massive lint

This commit is contained in:
Adam Matthiesen 2024-03-03 08:49:15 -08:00
parent 3192714355
commit 5f7ac8e4a6
54 changed files with 1005 additions and 797 deletions

View File

@ -5,7 +5,11 @@ import { TSGhostContentAPI } from "@ts-ghost/content-api";
describe("content-api", () => { describe("content-api", () => {
let api: TSGhostContentAPI; let api: TSGhostContentAPI;
beforeEach(() => { beforeEach(() => {
api = new TSGhostContentAPI("https://ghost.org", "59d4bf56c73c04a18c867dc3ba", "v5.0"); api = new TSGhostContentAPI(
"https://ghost.org",
"59d4bf56c73c04a18c867dc3ba",
"v5.0",
);
}); });
test("content-api", () => { test("content-api", () => {
@ -14,7 +18,11 @@ describe("content-api", () => {
test("content-api shouldn't instantiate with an incorrect url", () => { test("content-api shouldn't instantiate with an incorrect url", () => {
assert.throws(() => { assert.throws(() => {
const api = new TSGhostContentAPI("ghost.org", "59d4bf56c73c04a18c867dc3ba", "v5.0"); const api = new TSGhostContentAPI(
"ghost.org",
"59d4bf56c73c04a18c867dc3ba",
"v5.0",
);
api.settings; api.settings;
}); });
}); });

View File

@ -4,10 +4,7 @@ import type { Page, Post } from "../schemas/api";
// LOAD ENVIRONMENT VARIABLES // LOAD ENVIRONMENT VARIABLES
import { loadEnv } from "vite"; import { loadEnv } from "vite";
const { const { CONTENT_API_KEY, CONTENT_API_URL } = loadEnv(
CONTENT_API_KEY,
CONTENT_API_URL
} = loadEnv(
"all", "all",
process.cwd(), process.cwd(),
"CONTENT_", "CONTENT_",

View File

@ -1,22 +1,22 @@
import { createResolver, defineIntegration } from "astro-integration-kit";
import { corePlugins } from "astro-integration-kit/plugins";
import { GhostUserConfigSchema } from "./schemas/userconfig";
import { loadEnv } from "vite";
import { AstroError } from "astro/errors";
import c from "picocolors";
import path from "node:path"; import path from "node:path";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { createResolver, defineIntegration } from "astro-integration-kit";
import { corePlugins } from "astro-integration-kit/plugins";
import { AstroError } from "astro/errors";
import fse from "fs-extra"; import fse from "fs-extra";
import c from "picocolors";
import { loadEnv } from "vite";
import { GhostUserConfigSchema } from "./schemas/userconfig";
import latestVersion from "./utils/latestVersion"; import latestVersion from "./utils/latestVersion";
// Import External Integrations // Import External Integrations
import sitemap from "@astrojs/sitemap"; import sitemap from "@astrojs/sitemap";
import robotsTxt from "astro-robots-txt"; import robotsTxt from "astro-robots-txt";
import ghostRSS from "./integrations/rssfeed";
// Import Internal Integrations // Import Internal Integrations
import ghostOGImages from "./integrations/satoriog" import ghostOGImages from "./integrations/satoriog";
import ghostRSS from "./integrations/rssfeed" import ghostThemeProvider from "./integrations/themeprovider";
import ghostThemeProvider from "./integrations/themeprovider"
// Load environment variables // Load environment variables
const ENV = loadEnv("all", process.cwd(), "CONTENT_API"); const ENV = loadEnv("all", process.cwd(), "CONTENT_API");
@ -40,112 +40,184 @@ export default defineIntegration({
addVirtualImports, addVirtualImports,
addDts, addDts,
injectRoute, injectRoute,
logger logger,
}) => { }) => {
const GhostLogger = logger.fork(c.bold(c.blue('👻 Astro-GhostCMS'))); const GhostLogger = logger.fork(c.bold(c.blue("👻 Astro-GhostCMS")));
const GhostENVLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('ENV Check')}`); const GhostENVLogger = logger.fork(
const GhostIntegrationLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('Integrations')}`); `${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
const GhostRouteLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('Router')}`); "ENV Check",
)}`,
);
const GhostIntegrationLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"Integrations",
)}`,
);
const GhostRouteLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"Router",
)}`,
);
watchIntegration(resolve()) watchIntegration(resolve());
GhostLogger.info('Initializing @matthiesenxyz/astro-ghostcms...') GhostLogger.info("Initializing @matthiesenxyz/astro-ghostcms...");
const verbose = options.fullConsoleLogs; const verbose = options.fullConsoleLogs;
// Check for GhostCMS environment variables // Check for GhostCMS environment variables
GhostENVLogger.info(c.bold(c.yellow('Checking for GhostCMS environment variables & user configuration'))) GhostENVLogger.info(
c.bold(
c.yellow(
"Checking for GhostCMS environment variables & user configuration",
),
),
);
if (ENV.CONTENT_API_KEY === undefined) { if (ENV.CONTENT_API_KEY === undefined) {
GhostENVLogger.error(c.bgRed(c.bold(c.white('CONTENT_API_KEY is not set in environment variables')))) GhostENVLogger.error(
throw new AstroError(`${name} CONTENT_API_KEY is not set in environment variables`) c.bgRed(
c.bold(
c.white("CONTENT_API_KEY is not set in environment variables"),
),
),
);
throw new AstroError(
`${name} CONTENT_API_KEY is not set in environment variables`,
);
} }
if (options.ghostURL === undefined) { if (options.ghostURL === undefined) {
GhostENVLogger.warn(c.bgYellow(c.bold(c.black('ghostURL is not set in user configuration falling back to environment variable')))) GhostENVLogger.warn(
c.bgYellow(
c.bold(
c.black(
"ghostURL is not set in user configuration falling back to environment variable",
),
),
),
);
if (ENV.CONTENT_API_URL === undefined) { if (ENV.CONTENT_API_URL === undefined) {
GhostENVLogger.error(c.bgRed(c.bold(c.white('CONTENT_API_URL is not set in environment variables')))) GhostENVLogger.error(
throw new AstroError(`${name} CONTENT_API_URL is not set in environment variables`) c.bgRed(
c.bold(
c.white(
"CONTENT_API_URL is not set in environment variables",
),
),
),
);
throw new AstroError(
`${name} CONTENT_API_URL is not set in environment variables`,
);
} }
} }
GhostENVLogger.info(c.bold(c.green('GhostCMS environment variables are set'))) GhostENVLogger.info(
c.bold(c.green("GhostCMS environment variables are set")),
);
// Set up Astro-GhostCMS Integrations // Set up Astro-GhostCMS Integrations
GhostIntegrationLogger.info(c.bold(c.magenta('Configuring Enabled Integrations'))) GhostIntegrationLogger.info(
c.bold(c.magenta("Configuring Enabled Integrations")),
);
// Theme Provider // Theme Provider
if (!options.disableThemeProvider) { if (!options.disableThemeProvider) {
addIntegration( addIntegration(
ghostThemeProvider({ ghostThemeProvider({
theme: options.ThemeProvider?.theme, theme: options.ThemeProvider?.theme,
verbose verbose,
}) }),
) );
} else { } else {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.gray('Theme Provider is disabled')) GhostIntegrationLogger.info(c.gray("Theme Provider is disabled"));
} }
} }
// Satori OG Images // Satori OG Images
if (options.enableOGImages) { if (options.enableOGImages) {
addIntegration(ghostOGImages({ verbose })) addIntegration(ghostOGImages({ verbose }));
} else { } else {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.gray('OG Image Provider is disabled')) GhostIntegrationLogger.info(
c.gray("OG Image Provider is disabled"),
);
} }
} }
// RSS Feed // RSS Feed
if (options.enableRSSFeed) { if (options.enableRSSFeed) {
addIntegration(ghostRSS({ verbose })) addIntegration(ghostRSS({ verbose }));
} else { } else {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.gray('RSS Feed is disabled')) GhostIntegrationLogger.info(c.gray("RSS Feed is disabled"));
} }
} }
// @ASTROJS/SITEMAP // @ASTROJS/SITEMAP
if (!hasIntegration("@astrojs/sitemap")) { if (!hasIntegration("@astrojs/sitemap")) {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.bold(c.magenta(`Adding ${c.blue("@astrojs/sitemap")} integration`))) GhostIntegrationLogger.info(
c.bold(
c.magenta(`Adding ${c.blue("@astrojs/sitemap")} integration`),
),
);
} }
addIntegration(sitemap()) addIntegration(sitemap());
} else { } else {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.gray('@astrojs/sitemap integration already exists, skipping...')) GhostIntegrationLogger.info(
c.gray(
"@astrojs/sitemap integration already exists, skipping...",
),
);
} }
} }
// ASTRO-ROBOTS-TXT // ASTRO-ROBOTS-TXT
if (!hasIntegration("@astro-robots-txt")) { if (!hasIntegration("@astro-robots-txt")) {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.bold(c.magenta(`Adding ${c.blue("astro-robots-txt")} integration`))) GhostIntegrationLogger.info(
c.bold(
c.magenta(`Adding ${c.blue("astro-robots-txt")} integration`),
),
);
} }
addIntegration(robotsTxt()) addIntegration(robotsTxt());
} else { } else {
if (verbose) { if (verbose) {
GhostIntegrationLogger.info(c.gray('astro-robots-txt integration already exists, skipping...')) GhostIntegrationLogger.info(
c.gray(
"astro-robots-txt integration already exists, skipping...",
),
);
} }
} }
// Set up default 404 page // Set up default 404 page
if (!options.disableDefault404) { if (!options.disableDefault404) {
if (verbose) { if (verbose) {
GhostRouteLogger.info(c.bold(c.cyan('Setting up default 404 page'))) GhostRouteLogger.info(
c.bold(c.cyan("Setting up default 404 page")),
);
} }
injectRoute({ injectRoute({
pattern: "/404", pattern: "/404",
entrypoint: `${name}/404.astro`, entrypoint: `${name}/404.astro`,
prerender: true prerender: true,
}) });
} else { } else {
if (verbose) { if (verbose) {
GhostRouteLogger.info(c.gray('Default 404 page is disabled, Skipping...')) GhostRouteLogger.info(
c.gray("Default 404 page is disabled, Skipping..."),
);
} }
} }
// Add virtual imports for user configuration // Add virtual imports for user configuration
addVirtualImports({ addVirtualImports({
'virtual:@matthiesenxyz/astro-ghostcms/config': `export default ${JSON.stringify(options)}`, "virtual:@matthiesenxyz/astro-ghostcms/config": `export default ${JSON.stringify(
}) options,
)}`,
});
// Add types for user configuration // Add types for user configuration
addDts({ addDts({
@ -153,37 +225,82 @@ export default defineIntegration({
content: `declare module "virtual:@matthiesenxyz/astro-ghostcms/config" { content: `declare module "virtual:@matthiesenxyz/astro-ghostcms/config" {
const Config: import("../schemas/userconfig").GhostUserConfig; const Config: import("../schemas/userconfig").GhostUserConfig;
export default Config; export default Config;
}` }`,
}) });
}, },
"astro:config:done": ({ logger }) => { "astro:config:done": ({ logger }) => {
const GhostLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.green('CONFIG')}`); const GhostLogger = logger.fork(
GhostLogger.info(c.bold(c.green('Integration Setup & Configuration Complete'))) `${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.green(
"CONFIG",
)}`,
);
GhostLogger.info(
c.bold(c.green("Integration Setup & Configuration Complete")),
);
}, },
"astro:server:start": async ({ logger }) => { "astro:server:start": async ({ logger }) => {
const GhostLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.bold(c.green('DEV'))}`); const GhostLogger = logger.fork(
const GhostUpdateLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.bold(c.green('VERSION CHECK'))}`); `${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.bold(
c.green("DEV"),
)}`,
);
const GhostUpdateLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.bold(
c.green("VERSION CHECK"),
)}`,
);
// Start the DEV server // Start the DEV server
GhostLogger.info(c.bold(c.magenta('Running Astro-GhostCMS in Deveopment mode 🚀'))) GhostLogger.info(
c.bold(c.magenta("Running Astro-GhostCMS in Deveopment mode 🚀")),
);
// Check for updates // Check for updates
const currentNPMVersion = await latestVersion("@matthiesenxyz/astro-ghostcms"); const currentNPMVersion = await latestVersion(
const packageJson = await fse.readJson(path.resolve(fileURLToPath(import.meta.url), "../../package.json")); "@matthiesenxyz/astro-ghostcms",
);
const packageJson = await fse.readJson(
path.resolve(fileURLToPath(import.meta.url), "../../package.json"),
);
const localVersion = packageJson.version; const localVersion = packageJson.version;
if (currentNPMVersion !== localVersion) { if (currentNPMVersion !== localVersion) {
GhostUpdateLogger.warn(`\n${c.bgYellow(c.bold(c.black(" There is a new version of Astro-GhostCMS available! ")))}\n${c.bold(c.white(" Current Installed Version: ")) + c.bold(c.red(`${localVersion} `))} \n ${c.bold(c.white("New Available Version: "))} ${c.green(currentNPMVersion)} \n ${c.bold(c.white("Please consider updating to the latest version by running: "))} ${c.bold(c.green("npm i @matthiesenxyz/astro-ghostcms@latest"))} \n`) GhostUpdateLogger.warn(
`\n${c.bgYellow(
c.bold(
c.black(
" There is a new version of Astro-GhostCMS available! ",
),
),
)}\n${
c.bold(c.white(" Current Installed Version: ")) +
c.bold(c.red(`${localVersion} `))
} \n ${c.bold(c.white("New Available Version: "))} ${c.green(
currentNPMVersion,
)} \n ${c.bold(
c.white(
"Please consider updating to the latest version by running: ",
),
)} ${c.bold(
c.green("npm i @matthiesenxyz/astro-ghostcms@latest"),
)} \n`,
);
} else { } else {
GhostUpdateLogger.info(c.bold(c.green(`Astro-GhostCMS is up to date! v${localVersion}`))) GhostUpdateLogger.info(
c.bold(c.green(`Astro-GhostCMS is up to date! v${localVersion}`)),
);
} }
}, },
"astro:build:done": ({ logger }) => { "astro:build:done": ({ logger }) => {
const GhostLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.bold(c.green('BUILD'))}`); const GhostLogger = logger.fork(
GhostLogger.info(c.bold(c.magenta('Running Astro-GhostCMS in Production mode 🚀'))) `${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.bold(
} c.green("BUILD"),
} )}`,
} );
}) GhostLogger.info(
c.bold(c.magenta("Running Astro-GhostCMS in Production mode 🚀")),
);
},
};
},
});

View File

@ -1,3 +1,3 @@
import astroghostcms from './astro-ghostcms.js'; import astroghostcms from "./astro-ghostcms.js";
export default astroghostcms; export default astroghostcms;

View File

@ -1,7 +1,7 @@
import { createResolver, defineIntegration } from "astro-integration-kit"; import { createResolver, defineIntegration } from "astro-integration-kit";
import { corePlugins } from "astro-integration-kit/plugins"; import { corePlugins } from "astro-integration-kit/plugins";
import c from "picocolors";
import { z } from "astro/zod"; import { z } from "astro/zod";
import c from "picocolors";
export default defineIntegration({ export default defineIntegration({
name: "@matthiesenxyz/astro-ghostcms-rss", name: "@matthiesenxyz/astro-ghostcms-rss",
@ -13,17 +13,17 @@ export default defineIntegration({
const { resolve } = createResolver(import.meta.url); const { resolve } = createResolver(import.meta.url);
return { return {
"astro:config:setup": ({ "astro:config:setup": ({ watchIntegration, injectRoute, logger }) => {
watchIntegration, watchIntegration(resolve());
injectRoute, const RSSLogger = logger.fork(
logger `${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
}) => { "RSSGenerator",
watchIntegration(resolve()) )}`,
const RSSLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('RSSGenerator')}`); );
RSSLogger.info(c.bold(c.magenta('RSS Feed Enabled. Setting up...'))) RSSLogger.info(c.bold(c.magenta("RSS Feed Enabled. Setting up...")));
const rssRoute = "@matthiesenxyz/astro-ghostcms/rss-routes" const rssRoute = "@matthiesenxyz/astro-ghostcms/rss-routes";
injectRoute({ injectRoute({
pattern: "/rss-style.xsl", pattern: "/rss-style.xsl",
@ -34,15 +34,18 @@ export default defineIntegration({
pattern: "/rss.xml", pattern: "/rss.xml",
entrypoint: `${rssRoute}/rss.xml.ts`, entrypoint: `${rssRoute}/rss.xml.ts`,
}); });
}, },
"astro:config:done": ({ logger }) => { "astro:config:done": ({ logger }) => {
const RSSLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('RSSGenerator')}`); const RSSLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"RSSGenerator",
)}`,
);
if (options.verbose) { if (options.verbose) {
RSSLogger.info(c.bold(c.green('RSS Feed Setup Complete'))) RSSLogger.info(c.bold(c.green("RSS Feed Setup Complete")));
} }
} },
} };
} },
}) });

View File

@ -1,7 +1,7 @@
import { createResolver, defineIntegration } from "astro-integration-kit"; import { createResolver, defineIntegration } from "astro-integration-kit";
import { corePlugins } from "astro-integration-kit/plugins"; import { corePlugins } from "astro-integration-kit/plugins";
import c from "picocolors";
import { z } from "astro/zod"; import { z } from "astro/zod";
import c from "picocolors";
export default defineIntegration({ export default defineIntegration({
name: "@matthiesenxyz/astro-ghostcms-satoriog", name: "@matthiesenxyz/astro-ghostcms-satoriog",
@ -17,15 +17,21 @@ export default defineIntegration({
watchIntegration, watchIntegration,
updateConfig, updateConfig,
injectRoute, injectRoute,
logger logger,
}) => { }) => {
watchIntegration(resolve()) watchIntegration(resolve());
const SatoriLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('SatoriOG')}`); const SatoriLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"SatoriOG",
)}`,
);
SatoriLogger.info(c.bold(c.magenta('OG Image Integration Enabled. Setting up...'))) SatoriLogger.info(
c.bold(c.magenta("OG Image Integration Enabled. Setting up...")),
);
const pkgname = "@matthiesenxyz/astro-ghostcms/open-graph" const pkgname = "@matthiesenxyz/astro-ghostcms/open-graph";
injectRoute({ injectRoute({
pattern: "/open-graph/[slug].png", pattern: "/open-graph/[slug].png",
@ -58,16 +64,22 @@ export default defineIntegration({
}); });
updateConfig({ updateConfig({
vite: { optimizeDeps: { exclude: ["@resvg/resvg-js"] } } vite: { optimizeDeps: { exclude: ["@resvg/resvg-js"] } },
}) });
}, },
"astro:config:done": ({ logger }) => { "astro:config:done": ({ logger }) => {
const SatoriLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('SatoriOG')}`); const SatoriLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"SatoriOG",
)}`,
);
if (options.verbose) { if (options.verbose) {
SatoriLogger.info(c.bold(c.green('OG Image Integration Setup Complete'))) SatoriLogger.info(
c.bold(c.green("OG Image Integration Setup Complete")),
);
} }
} },
} };
} },
}) });

View File

@ -5,12 +5,7 @@ import type {
InferGetStaticPropsType, InferGetStaticPropsType,
} from "astro"; } from "astro";
import { html } from "satori-html"; import { html } from "satori-html";
import { import { getAllPages, getAllPosts, getSettings, invariant } from "../../../api";
getAllPages,
getAllPosts,
getSettings,
invariant,
} from "../../../api";
import satoriOG from "../satori"; import satoriOG from "../satori";
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {

View File

@ -5,12 +5,7 @@ import type {
InferGetStaticPropsType, InferGetStaticPropsType,
} from "astro"; } from "astro";
import { html } from "satori-html"; import { html } from "satori-html";
import { import { getAllPages, getAllPosts, getSettings, invariant } from "../../../api";
getAllPages,
getAllPosts,
getSettings,
invariant,
} from "../../../api";
import satoriOG from "../satori"; import satoriOG from "../satori";
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {

View File

@ -5,12 +5,7 @@ import type {
InferGetStaticPropsType, InferGetStaticPropsType,
} from "astro"; } from "astro";
import { html } from "satori-html"; import { html } from "satori-html";
import { import { getAllPages, getAllPosts, getSettings, invariant } from "../../../api";
getAllPages,
getAllPosts,
getSettings,
invariant,
} from "../../../api";
import satoriOG from "../satori"; import satoriOG from "../satori";
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {

View File

@ -5,12 +5,7 @@ import type {
InferGetStaticPropsType, InferGetStaticPropsType,
} from "astro"; } from "astro";
import { html } from "satori-html"; import { html } from "satori-html";
import { import { getAllPages, getAllPosts, getSettings, invariant } from "../../../api";
getAllPages,
getAllPosts,
getSettings,
invariant,
} from "../../../api";
import satoriOG from "../satori"; import satoriOG from "../satori";
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => {

View File

@ -6,7 +6,10 @@ import c from "picocolors";
export default defineIntegration({ export default defineIntegration({
name: "@matthiesenxyz/astro-ghostcms-themeprovider", name: "@matthiesenxyz/astro-ghostcms-themeprovider",
optionsSchema: z.object({ optionsSchema: z.object({
theme: z.string().optional().default("@matthiesenxyz/astro-ghostcms-theme-default"), theme: z
.string()
.optional()
.default("@matthiesenxyz/astro-ghostcms-theme-default"),
verbose: z.boolean().optional().default(false), verbose: z.boolean().optional().default(false),
}), }),
plugins: [...corePlugins], plugins: [...corePlugins],
@ -14,22 +17,30 @@ export default defineIntegration({
const { resolve } = createResolver(import.meta.url); const { resolve } = createResolver(import.meta.url);
return { return {
"astro:config:setup": ({ "astro:config:setup": ({ watchIntegration, injectRoute, logger }) => {
watchIntegration, watchIntegration(resolve());
injectRoute,
logger
}) => {
watchIntegration(resolve())
const themeLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('Theme Provider')}`); const themeLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"Theme Provider",
)}`,
);
themeLogger.info(c.bold(c.magenta('Theme Provider enabled. Setting up...'))) themeLogger.info(
c.bold(c.magenta("Theme Provider enabled. Setting up...")),
);
if (options.verbose) { if (options.verbose) {
if (options.theme === "@matthiesenxyz/astro-ghostcms-theme-default") { if (options.theme === "@matthiesenxyz/astro-ghostcms-theme-default") {
themeLogger.info(c.blue('No theme is set, injecting default theme')) themeLogger.info(
c.blue("No theme is set, injecting default theme"),
);
} else { } else {
themeLogger.info(`${c.bold(c.cyan("Injecting Theme:"))} ${c.bold(c.underline(c.magenta(options.theme)))}`) themeLogger.info(
`${c.bold(c.cyan("Injecting Theme:"))} ${c.bold(
c.underline(c.magenta(options.theme)),
)}`,
);
} }
} }
@ -67,15 +78,18 @@ export default defineIntegration({
pattern: "/archives/[...page]", pattern: "/archives/[...page]",
entrypoint: `${options.theme}/archives/[...page].astro`, entrypoint: `${options.theme}/archives/[...page].astro`,
}); });
}, },
"astro:config:done": ({ logger }) => { "astro:config:done": ({ logger }) => {
const themeLogger = logger.fork(`${c.bold(c.blue('👻 Astro-GhostCMS'))}${c.gray("/")}${c.blue('Theme Provider')}`); const themeLogger = logger.fork(
`${c.bold(c.blue("👻 Astro-GhostCMS"))}${c.gray("/")}${c.blue(
"Theme Provider",
)}`,
);
if (options.verbose) { if (options.verbose) {
themeLogger.info(c.bold(c.green('Provider Setup Complete'))) themeLogger.info(c.bold(c.green("Provider Setup Complete")));
} }
} },
} };
} },
}) });

View File

@ -1,5 +1,5 @@
import createFetchMock from "vitest-fetch-mock";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import createFetchMock from "vitest-fetch-mock";
import { TSGhostContentAPI } from "@ts-ghost/content-api"; import { TSGhostContentAPI } from "@ts-ghost/content-api";
@ -7,7 +7,8 @@ const fetchMocker = createFetchMock(vi);
describe("authors api .browse() Args Type-safety", () => { describe("authors api .browse() Args Type-safety", () => {
const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com"; const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com";
const key = process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba"; const key =
process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba";
const api = new TSGhostContentAPI(url, key, "v5.0"); const api = new TSGhostContentAPI(url, key, "v5.0");
test(".browse() params shouldnt accept invalid params", () => { test(".browse() params shouldnt accept invalid params", () => {
// @ts-expect-error - shouldnt accept invalid params // @ts-expect-error - shouldnt accept invalid params
@ -19,19 +20,28 @@ describe("authors api .browse() Args Type-safety", () => {
// @ts-expect-error - order should ony contain field // @ts-expect-error - order should ony contain field
expect(() => api.authors.browse({ order: "foo ASC" })).toThrow(); expect(() => api.authors.browse({ order: "foo ASC" })).toThrow();
// valid // valid
expect(api.authors.browse({ order: "name ASC" }).getParams().browseParams).toStrictEqual({ expect(
api.authors.browse({ order: "name ASC" }).getParams().browseParams,
).toStrictEqual({
order: "name ASC", order: "name ASC",
}); });
expect(api.authors.browse({ order: "name ASC,slug DESC" }).getParams().browseParams).toStrictEqual({ expect(
api.authors.browse({ order: "name ASC,slug DESC" }).getParams()
.browseParams,
).toStrictEqual({
order: "name ASC,slug DESC", order: "name ASC,slug DESC",
}); });
expect( expect(
api.authors.browse({ order: "name ASC,slug DESC,location ASC" }).getParams().browseParams api.authors
.browse({ order: "name ASC,slug DESC,location ASC" })
.getParams().browseParams,
).toStrictEqual({ ).toStrictEqual({
order: "name ASC,slug DESC,location ASC", order: "name ASC,slug DESC,location ASC",
}); });
// @ts-expect-error - order should ony contain field (There is a typo in location) // @ts-expect-error - order should ony contain field (There is a typo in location)
expect(() => api.authors.browse({ order: "name ASC,slug DESC,locaton ASC" })).toThrow(); expect(() =>
api.authors.browse({ order: "name ASC,slug DESC,locaton ASC" }),
).toThrow();
}); });
test(".browse() 'filter' params should ony accept valid field", () => { test(".browse() 'filter' params should ony accept valid field", () => {
@ -39,14 +49,14 @@ describe("authors api .browse() Args Type-safety", () => {
api.authors.browse({ api.authors.browse({
// @ts-expect-error - order should ony contain field // @ts-expect-error - order should ony contain field
filter: "foo:bar", filter: "foo:bar",
}) }),
).toThrow(); ).toThrow();
expect( expect(
api.authors api.authors
.browse({ .browse({
filter: "name:bar", filter: "name:bar",
}) })
.getParams().browseParams .getParams().browseParams,
).toStrictEqual({ ).toStrictEqual({
filter: "name:bar", filter: "name:bar",
}); });
@ -55,7 +65,7 @@ describe("authors api .browse() Args Type-safety", () => {
.browse({ .browse({
filter: "name:bar+slug:-test", filter: "name:bar+slug:-test",
}) })
.getParams().browseParams .getParams().browseParams,
).toStrictEqual({ ).toStrictEqual({
filter: "name:bar+slug:-test", filter: "name:bar+slug:-test",
}); });
@ -69,14 +79,18 @@ describe("authors api .browse() Args Type-safety", () => {
// @ts-expect-error - order should ony contain field // @ts-expect-error - order should ony contain field
foo: true, foo: true,
}) })
.getOutputFields() .getOutputFields(),
).toEqual([]); ).toEqual([]);
expect(api.authors.browse().fields({ location: true }).getOutputFields()).toEqual(["location"]); expect(
expect(api.authors.browse().fields({ name: true, website: true }).getOutputFields()).toEqual([ api.authors.browse().fields({ location: true }).getOutputFields(),
"name", ).toEqual(["location"]);
"website", expect(
]); api.authors
.browse()
.fields({ name: true, website: true })
.getOutputFields(),
).toEqual(["name", "website"]);
}); });
}); });
@ -84,7 +98,11 @@ describe("authors resource mocked", () => {
let api: TSGhostContentAPI; let api: TSGhostContentAPI;
beforeEach(() => { beforeEach(() => {
api = new TSGhostContentAPI("https://my-ghost-blog.com", "59d4bf56c73c04a18c867dc3ba", "v5.0"); api = new TSGhostContentAPI(
"https://my-ghost-blog.com",
"59d4bf56c73c04a18c867dc3ba",
"v5.0",
);
fetchMocker.enableMocks(); fetchMocker.enableMocks();
}); });
afterEach(() => { afterEach(() => {
@ -123,7 +141,7 @@ describe("authors resource mocked", () => {
prev: null, prev: null,
}, },
}, },
}) }),
); );
const result = await browseQuery.fetch(); const result = await browseQuery.fetch();
expect(fetchMocker).toHaveBeenCalledTimes(1); expect(fetchMocker).toHaveBeenCalledTimes(1);
@ -134,7 +152,7 @@ describe("authors resource mocked", () => {
"Content-Type": "application/json", "Content-Type": "application/json",
"Accept-Version": "v5.0", "Accept-Version": "v5.0",
}, },
} },
); );
expect(result).not.toBeUndefined(); expect(result).not.toBeUndefined();
if (result.success) { if (result.success) {

View File

@ -4,7 +4,8 @@ import { TSGhostContentAPI } from "@ts-ghost/content-api";
import type { Post } from "./index"; import type { Post } from "./index";
const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com"; const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com";
const key = process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba"; const key =
process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba";
describe("posts api .browse() Args Type-safety", () => { describe("posts api .browse() Args Type-safety", () => {
const api = new TSGhostContentAPI(url, key, "v5.0"); const api = new TSGhostContentAPI(url, key, "v5.0");
@ -27,10 +28,13 @@ describe("posts api .browse() Args Type-safety", () => {
expect(test.getOutputFields()).toEqual(["slug", "title"]); expect(test.getOutputFields()).toEqual(["slug", "title"]);
const fields = ["slug", "title", "foo"] as const; const fields = ["slug", "title", "foo"] as const;
const unknownOriginFields = fields.reduce((acc, k) => { const unknownOriginFields = fields.reduce(
(acc, k) => {
acc[k as keyof Post] = true; acc[k as keyof Post] = true;
return acc; return acc;
}, {} as { [k in keyof Post]?: true | undefined }); },
{} as { [k in keyof Post]?: true | undefined },
);
const result = api.posts.browse().fields(unknownOriginFields); const result = api.posts.browse().fields(unknownOriginFields);
expect(result.getOutputFields()).toEqual(["slug", "title"]); expect(result.getOutputFields()).toEqual(["slug", "title"]);
}); });
@ -46,10 +50,18 @@ describe("posts api .browse() Args Type-safety", () => {
// @ts-expect-error - shouldnt accept invalid params // @ts-expect-error - shouldnt accept invalid params
expect(() => api.posts.browse({ filter: "slugg:test" })).toThrow(); expect(() => api.posts.browse({ filter: "slugg:test" })).toThrow();
// @ts-expect-error - shouldnt accept invalid params // @ts-expect-error - shouldnt accept invalid params
expect(() => api.posts.browse({ filter: "slug:test,foo:-[bar,baz]" })).toThrow(); expect(() =>
expect(api.posts.browse({ filter: "slug:test,tags:-[bar,baz]" })).toBeDefined(); api.posts.browse({ filter: "slug:test,foo:-[bar,baz]" }),
expect(api.posts.browse({ filter: "slug:test,tags:[bar,baz]" })).toBeDefined(); ).toThrow();
expect(
api.posts.browse({ filter: "slug:test,tags:-[bar,baz]" }),
).toBeDefined();
expect(
api.posts.browse({ filter: "slug:test,tags:[bar,baz]" }),
).toBeDefined();
// @ts-expect-error - shouldnt accept invalid params // @ts-expect-error - shouldnt accept invalid params
expect(() => api.posts.browse({ filter: "slug:test,food:-[bar,baz]" })).toThrow(); expect(() =>
api.posts.browse({ filter: "slug:test,food:-[bar,baz]" }),
).toThrow();
}); });
}); });

View File

@ -3,7 +3,8 @@ import { beforeEach, describe, expect, test } from "vitest";
import { TSGhostContentAPI } from "@ts-ghost/content-api"; import { TSGhostContentAPI } from "@ts-ghost/content-api";
const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com"; const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com";
const key = process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba"; const key =
process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba";
describe("settings integration tests browse", () => { describe("settings integration tests browse", () => {
let api: TSGhostContentAPI; let api: TSGhostContentAPI;
@ -24,7 +25,9 @@ describe("settings integration tests browse", () => {
expect(settings.title).toBe("Astro Starter"); expect(settings.title).toBe("Astro Starter");
expect(settings.description).toBe("Thoughts, stories and ideas."); expect(settings.description).toBe("Thoughts, stories and ideas.");
expect(settings.logo).toBeNull(); expect(settings.logo).toBeNull();
expect(settings.cover_image).toBe("https://static.ghost.org/v4.0.0/images/publication-cover.jpg"); expect(settings.cover_image).toBe(
"https://static.ghost.org/v4.0.0/images/publication-cover.jpg",
);
expect(settings.icon).toBeNull(); expect(settings.icon).toBeNull();
expect(settings.lang).toBe("en"); expect(settings.lang).toBe("en");
expect(settings.timezone).toBe("Etc/UTC"); expect(settings.timezone).toBe("Etc/UTC");

View File

@ -1,4 +1,4 @@
import { expect, describe, it } from "vitest"; import { describe, expect, it } from "vitest";
import { GhostUserConfigSchema } from "./userconfig"; import { GhostUserConfigSchema } from "./userconfig";
describe("GhostUserConfigSchema", () => { describe("GhostUserConfigSchema", () => {

View File

@ -18,12 +18,17 @@ export const GhostUserConfigSchema = z.object({
* @default false * @default false
*/ */
disableThemeProvider: z.boolean().optional().default(false), disableThemeProvider: z.boolean().optional().default(false),
ThemeProvider: z.object({ ThemeProvider: z
.object({
/** OPTIONAL - Set the theme you want to use /** OPTIONAL - Set the theme you want to use
* @default "@matthiesenxyz/astro-ghostcms-theme-default" * @default "@matthiesenxyz/astro-ghostcms-theme-default"
*/ */
theme: z.string().optional().default("@matthiesenxyz/astro-ghostcms-theme-default"), theme: z
}).optional(), .string()
.optional()
.default("@matthiesenxyz/astro-ghostcms-theme-default"),
})
.optional(),
/** Allows the user to disable the provided 404 page */ /** Allows the user to disable the provided 404 page */
disableDefault404: z.boolean().optional().default(false), disableDefault404: z.boolean().optional().default(false),
/** Allows the user to disable the provided RSS Feed */ /** Allows the user to disable the provided RSS Feed */

View File

@ -1,6 +1,6 @@
/// <reference types="vitest" /> /// <reference types="vitest" />
/// <reference types="vite/client" /> /// <reference types="vite/client" />
import { defineProject } from 'vitest/config' import { defineProject } from "vitest/config";
export default defineProject({ export default defineProject({
test: { test: {
@ -9,4 +9,4 @@ export default defineProject({
watchExclude: [".*\\/node_modules\\/.*", ".*\\/build\\/.*"], watchExclude: [".*\\/node_modules\\/.*", ".*\\/build\\/.*"],
exclude: ["node_modules", "dist", ".idea", ".git", ".cache"], exclude: ["node_modules", "dist", ".idea", ".git", ".cache"],
}, },
}) });

View File

@ -1,16 +1,16 @@
import { defineConfig } from "astro/config";
import ghostcms from "@matthiesenxyz/astro-ghostcms"; import ghostcms from "@matthiesenxyz/astro-ghostcms";
import UnoCSS from 'unocss/astro'; import { defineConfig } from "astro/config";
import UnoCSS from "unocss/astro";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
site: "https://example.xyz/", site: "https://example.xyz/",
trailingSlash: 'ignore', trailingSlash: "ignore",
integrations: [ integrations: [
UnoCSS({ injectReset: true }), UnoCSS({ injectReset: true }),
ghostcms({ ghostcms({
theme: "@matthiesenxyz/astro-ghostcms-brutalbyelian", theme: "@matthiesenxyz/astro-ghostcms-brutalbyelian",
ghostURL: "https://ghostdemo.matthiesen.xyz", ghostURL: "https://ghostdemo.matthiesen.xyz",
}) }),
], ],
}); });

View File

@ -1,7 +1,7 @@
/// <reference types="astro/client" /> /// <reference types="astro/client" />
interface ImportMetaEnv { interface ImportMetaEnv {
readonly CONTENT_API_KEY: string readonly CONTENT_API_KEY: string;
readonly CONTENT_API_URL: string readonly CONTENT_API_URL: string;
} }
interface ImportMeta { interface ImportMeta {

View File

@ -1,5 +1,5 @@
import brutalTheme from '@matthiesenxyz/astro-ghostcms-brutalbyelian'; import brutalTheme from "@matthiesenxyz/astro-ghostcms-brutalbyelian";
import { defineConfig } from 'unocss'; import { defineConfig } from "unocss";
export default defineConfig({ export default defineConfig({
presets: [brutalTheme()], presets: [brutalTheme()],

View File

@ -1,21 +1,35 @@
import type { StarlightPlugin, StarlightUserConfig } from '@astrojs/starlight/types' import type {
import type { AstroIntegrationLogger } from 'astro' StarlightPlugin,
import { type StarlightGhostConfig, validateConfig } from './src/schemas/config' StarlightUserConfig,
import { vitePluginStarlightGhostConfig } from './src/integrations/vite' } from "@astrojs/starlight/types";
import { facebook, getSettings, invariant, twitter } from './src/utils/api' import type { AstroIntegrationLogger } from "astro";
import { vitePluginStarlightGhostConfig } from "./src/integrations/vite";
import {
type StarlightGhostConfig,
validateConfig,
} from "./src/schemas/config";
import { facebook, getSettings, invariant, twitter } from "./src/utils/api";
const settings = await getSettings() const settings = await getSettings();
export type { StarlightGhostConfig } export type { StarlightGhostConfig };
export default function starlightGhostCMS(userConfig?: StarlightGhostConfig): StarlightPlugin { export default function starlightGhostCMS(
const config: StarlightGhostConfig = validateConfig(userConfig) userConfig?: StarlightGhostConfig,
invariant(settings, "Settings not available... check your api key/url") ): StarlightPlugin {
const config: StarlightGhostConfig = validateConfig(userConfig);
invariant(settings, "Settings not available... check your api key/url");
return { return {
name: '@matthiesenxyz/starlight-ghostcms-plugin', name: "@matthiesenxyz/starlight-ghostcms-plugin",
hooks: { hooks: {
setup({ astroConfig, addIntegration, config: starlightConfig, logger, updateConfig: updateStarlightConfig }) { setup({
astroConfig,
addIntegration,
config: starlightConfig,
logger,
updateConfig: updateStarlightConfig,
}) {
updateStarlightConfig({ updateStarlightConfig({
social: { social: {
...starlightConfig.social, ...starlightConfig.social,
@ -25,67 +39,88 @@ export default function starlightGhostCMS(userConfig?: StarlightGhostConfig): St
}, },
components: { components: {
...starlightConfig.components, ...starlightConfig.components,
...overrideStarlightComponent(starlightConfig.components, logger, 'MarkdownContent'), ...overrideStarlightComponent(
...overrideStarlightComponent(starlightConfig.components, logger, 'Sidebar'), starlightConfig.components,
...overrideStarlightComponent(starlightConfig.components, logger, "SiteTitle"), logger,
} "MarkdownContent",
}) ),
...overrideStarlightComponent(
starlightConfig.components,
logger,
"Sidebar",
),
...overrideStarlightComponent(
starlightConfig.components,
logger,
"SiteTitle",
),
},
});
addIntegration({ addIntegration({
name: '@matthiesenxyz/starlight-ghostcms', name: "@matthiesenxyz/starlight-ghostcms",
hooks: { hooks: {
'astro:config:setup': ({ injectRoute, updateConfig }) => { "astro:config:setup": ({ injectRoute, updateConfig }) => {
injectRoute({ injectRoute({
pattern: '/blog', pattern: "/blog",
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/index.astro', entrypoint:
"@matthiesenxyz/starlight-ghostcms/routes/index.astro",
prerender: true, prerender: true,
}) });
injectRoute({ injectRoute({
pattern: '/blog/[slug]', pattern: "/blog/[slug]",
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/[slug].astro', entrypoint:
"@matthiesenxyz/starlight-ghostcms/routes/[slug].astro",
prerender: true, prerender: true,
}) });
injectRoute({ injectRoute({
pattern: '/blog/about', pattern: "/blog/about",
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/about.astro', entrypoint:
"@matthiesenxyz/starlight-ghostcms/routes/about.astro",
prerender: true, prerender: true,
}) });
injectRoute({ injectRoute({
pattern: '/blog/authors', pattern: "/blog/authors",
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/authors.astro', entrypoint:
}) "@matthiesenxyz/starlight-ghostcms/routes/authors.astro",
});
injectRoute({ injectRoute({
pattern: '/rss.xml', pattern: "/rss.xml",
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/rss.xml.ts' entrypoint:
}) "@matthiesenxyz/starlight-ghostcms/routes/rss.xml.ts",
});
updateConfig({ updateConfig({
vite: { vite: {
plugins: [vitePluginStarlightGhostConfig(config)], plugins: [vitePluginStarlightGhostConfig(config)],
}, },
}) });
}
}
})
}
}, },
} },
});
},
},
};
} }
function overrideStarlightComponent( function overrideStarlightComponent(
components: StarlightUserConfig['components'], components: StarlightUserConfig["components"],
logger: AstroIntegrationLogger, logger: AstroIntegrationLogger,
component: keyof NonNullable<StarlightUserConfig['components']>, component: keyof NonNullable<StarlightUserConfig["components"]>,
) { ) {
if (components?.[component]) { if (components?.[component]) {
logger.warn(`It looks like you already have a \`${component}\` component override in your Starlight configuration.`) logger.warn(
logger.warn(`To use \`starlight-ghostcms\`, remove the override for the \`${component}\` component.\n`) `It looks like you already have a \`${component}\` component override in your Starlight configuration.`,
logger.warn("This Warning can be ignored if you know what your doing ;)") );
logger.warn(
`To use \`starlight-ghostcms\`, remove the override for the \`${component}\` component.\n`,
);
logger.warn("This Warning can be ignored if you know what your doing ;)");
return {} return {};
} }
return { return {
[component]: `@matthiesenxyz/starlight-ghostcms/overrides/${component}.astro`, [component]: `@matthiesenxyz/starlight-ghostcms/overrides/${component}.astro`,
} };
} }

View File

@ -1,22 +1,24 @@
import type { ViteUserConfig } from 'astro' import type { ViteUserConfig } from "astro";
import type { StarlightGhostConfig } from '../schemas/config.ts' import type { StarlightGhostConfig } from "../schemas/config.ts";
// Expose the starlight-blog plugin configuration. // Expose the starlight-blog plugin configuration.
export function vitePluginStarlightGhostConfig(config: StarlightGhostConfig): VitePlugin { export function vitePluginStarlightGhostConfig(
const moduleId = 'virtual:starlight-ghost-config' config: StarlightGhostConfig,
const resolvedModuleId = `\0${moduleId}` ): VitePlugin {
const moduleContent = `export default ${JSON.stringify(config)}` const moduleId = "virtual:starlight-ghost-config";
const resolvedModuleId = `\0${moduleId}`;
const moduleContent = `export default ${JSON.stringify(config)}`;
return { return {
name: 'vite-plugin-starlight-ghost-config', name: "vite-plugin-starlight-ghost-config",
load(id) { load(id) {
return id === resolvedModuleId ? moduleContent : undefined return id === resolvedModuleId ? moduleContent : undefined;
}, },
resolveId(id) { resolveId(id) {
return id === moduleId ? resolvedModuleId : undefined return id === moduleId ? resolvedModuleId : undefined;
}, },
} };
} }
type VitePlugin = NonNullable<ViteUserConfig['plugins']>[number] type VitePlugin = NonNullable<ViteUserConfig["plugins"]>[number];

View File

@ -1,15 +1,19 @@
import { z } from 'astro/zod'; import type { AstroBuiltinAttributes } from "astro";
import type { AstroBuiltinAttributes } from 'astro'; import type { HTMLAttributes } from "astro/types";
import type { HTMLAttributes } from 'astro/types'; import { z } from "astro/zod";
const linkHTMLAttributesSchema = z.record( const linkHTMLAttributesSchema = z.record(
z.union([z.string(), z.number(), z.boolean(), z.undefined()]) z.union([z.string(), z.number(), z.boolean(), z.undefined()]),
) as z.Schema<Omit<HTMLAttributes<'a'>, keyof AstroBuiltinAttributes | 'children'>>; ) as z.Schema<
Omit<HTMLAttributes<"a">, keyof AstroBuiltinAttributes | "children">
>;
export type LinkHTMLAttributes = z.infer<typeof linkHTMLAttributesSchema>; export type LinkHTMLAttributes = z.infer<typeof linkHTMLAttributesSchema>;
const badgeSchema = () => const badgeSchema = () =>
z.object({ z.object({
variant: z.enum(['note', 'danger', 'success', 'caution', 'tip', 'default']).default('default'), variant: z
.enum(["note", "danger", "success", "caution", "tip", "default"])
.default("default"),
text: z.string(), text: z.string(),
}); });
@ -17,8 +21,8 @@ export const BadgeConfigSchema = () =>
z z
.union([z.string(), badgeSchema()]) .union([z.string(), badgeSchema()])
.transform((badge) => { .transform((badge) => {
if (typeof badge === 'string') { if (typeof badge === "string") {
return { variant: 'default' as const, text: badge }; return { variant: "default" as const, text: badge };
} }
return badge; return badge;
}) })
@ -27,7 +31,7 @@ export const BadgeConfigSchema = () =>
export type Badge = z.output<ReturnType<typeof badgeSchema>>; export type Badge = z.output<ReturnType<typeof badgeSchema>>;
export interface Link { export interface Link {
type: 'link'; type: "link";
label: string; label: string;
href: string; href: string;
isCurrent: boolean; isCurrent: boolean;
@ -36,7 +40,7 @@ export interface Link {
} }
interface Group { interface Group {
type: 'group'; type: "group";
label: string; label: string;
entries: (Link | Group)[]; entries: (Link | Group)[];
collapsed: boolean; collapsed: boolean;

View File

@ -5,13 +5,13 @@ import { getAllPosts, getSettings, invariant } from "../utils/api";
const posts = await getAllPosts(); const posts = await getAllPosts();
const settings = await getSettings(); const settings = await getSettings();
import config from 'virtual:starlight-ghost-config'; import config from "virtual:starlight-ghost-config";
export async function GET({ site }: APIContext) { export async function GET({ site }: APIContext) {
invariant(settings,"Settings is not defined") invariant(settings, "Settings is not defined");
const title = config.title; const title = config.title;
const description = config.rssDescription; const description = config.rssDescription;
const ghostSite = settings.url const ghostSite = settings.url;
return rss({ return rss({
title: title, title: title,
description: description, description: description,

View File

@ -1,5 +1,5 @@
import { AstroError } from 'astro/errors' import { AstroError } from "astro/errors";
import { z } from 'astro/zod' import { z } from "astro/zod";
const configSchema = z const configSchema = z
.object({ .object({
@ -14,37 +14,39 @@ const configSchema = z
/** /**
* The title of the blog. * The title of the blog.
*/ */
title: z.string().default('Blog'), title: z.string().default("Blog"),
/** /**
* The description of the blog on the RSS Feed. * The description of the blog on the RSS Feed.
*/ */
rssDescription: z.string().default('My Awesome Starlight-GhostCMS Blog'), rssDescription: z.string().default("My Awesome Starlight-GhostCMS Blog"),
/** /**
* Turn on and off "Powered by Ghost" * Turn on and off "Powered by Ghost"
*/ */
supportGhost: z.boolean().default(true), supportGhost: z.boolean().default(true),
}) })
.default({}) .default({});
export function validateConfig(userConfig: unknown): StarlightGhostConfig { export function validateConfig(userConfig: unknown): StarlightGhostConfig {
const config = configSchema.safeParse(userConfig) const config = configSchema.safeParse(userConfig);
if (!config.success) { if (!config.success) {
const errors = config.error.flatten() const errors = config.error.flatten();
throw new AstroError( throw new AstroError(
`Invalid starlight-GhostCMS configuration: `Invalid starlight-GhostCMS configuration:
${errors.formErrors.map((formError) => ` - ${formError}`).join('\n')} ${errors.formErrors.map((formError) => ` - ${formError}`).join("\n")}
${Object.entries(errors.fieldErrors) ${Object.entries(errors.fieldErrors)
.map(([fieldName, fieldErrors]) => ` - ${fieldName}: ${fieldErrors.join(' - ')}`) .map(
.join('\n')} ([fieldName, fieldErrors]) => ` - ${fieldName}: ${fieldErrors.join(" - ")}`,
)
.join("\n")}
`, `,
"See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/matthiesenxyz/astro-ghostcms/issues/new/choose", "See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/matthiesenxyz/astro-ghostcms/issues/new/choose",
) );
} }
return config.data return config.data;
} }
export type StarlightGhostConfig = z.infer<typeof configSchema> export type StarlightGhostConfig = z.infer<typeof configSchema>;

View File

@ -1,8 +1,8 @@
import { TS_API } from "./content-api";
import type { Page, Post } from "./content-api/schemas";
import type { ContentAPICredentials } from './content-api/content-api'
// LOAD ENVIRONMENT VARIABLES // LOAD ENVIRONMENT VARIABLES
import { loadEnv } from "vite"; import { loadEnv } from "vite";
import { TS_API } from "./content-api";
import type { ContentAPICredentials } from "./content-api/content-api";
import type { Page, Post } from "./content-api/schemas";
import { invariant } from "./invariant.js"; import { invariant } from "./invariant.js";
const { CONTENT_API_KEY, CONTENT_API_URL } = loadEnv( const { CONTENT_API_KEY, CONTENT_API_URL } = loadEnv(
@ -11,14 +11,8 @@ const { CONTENT_API_KEY, CONTENT_API_URL } = loadEnv(
"CONTENT_", "CONTENT_",
); );
invariant( invariant(CONTENT_API_KEY, "CONTENT_API_KEY Missing from .env");
CONTENT_API_KEY, invariant(CONTENT_API_URL, "CONTENT_API_URL Missing from .env");
"CONTENT_API_KEY Missing from .env"
)
invariant(
CONTENT_API_URL,
"CONTENT_API_URL Missing from .env"
)
const key: ContentAPICredentials["key"] = CONTENT_API_KEY; const key: ContentAPICredentials["key"] = CONTENT_API_KEY;
const url: ContentAPICredentials["url"] = CONTENT_API_URL; const url: ContentAPICredentials["url"] = CONTENT_API_URL;
@ -79,7 +73,8 @@ export const getSluggedPost = async (slug:string) => {
.include({ .include({
authors: true, authors: true,
tags: true, tags: true,
}).fetch() })
.fetch();
if (!results.success) { if (!results.success) {
throw new Error(results.errors.map((e) => e.message).join(", ")); throw new Error(results.errors.map((e) => e.message).join(", "));
@ -112,7 +107,8 @@ export const getSluggedPage = async (slug:string) => {
.include({ .include({
authors: true, authors: true,
tags: true, tags: true,
}).fetch() })
.fetch();
if (!results.success) { if (!results.success) {
throw new Error(results.errors.map((e) => e.message).join(", ")); throw new Error(results.errors.map((e) => e.message).join(", "));

View File

@ -1,21 +1,21 @@
export function isAnyBlogPage(slug: string) { export function isAnyBlogPage(slug: string) {
return slug.match(/^blog(\/?$|\/.+\/?$)/) !== null return slug.match(/^blog(\/?$|\/.+\/?$)/) !== null;
} }
export function isBlogRoot(slug: string) { export function isBlogRoot(slug: string) {
return slug === 'blog' return slug === "blog";
} }
export function isAnyBlogPostPage(slug: string) { export function isAnyBlogPostPage(slug: string) {
return slug.match(/^blog\/(?!(\d+\/?|tags\/.+)$).+$/) !== null return slug.match(/^blog\/(?!(\d+\/?|tags\/.+)$).+$/) !== null;
} }
export function isBlogPostPage(slug: string, postSlug: string) { export function isBlogPostPage(slug: string, postSlug: string) {
return slug === postSlug return slug === postSlug;
} }
export function isBlogTagsPage(slug: string, tag: string) { export function isBlogTagsPage(slug: string, tag: string) {
return slug === `blog/tags/${tag}` return slug === `blog/tags/${tag}`;
} }
export function getPageProps(title: string): StarlightPageProps { export function getPageProps(title: string): StarlightPageProps {
@ -23,11 +23,11 @@ export function getPageProps(title: string): StarlightPageProps {
frontmatter: { frontmatter: {
title, title,
}, },
} };
} }
interface StarlightPageProps { interface StarlightPageProps {
frontmatter: { frontmatter: {
title: string title: string;
} };
} }

View File

@ -1,5 +1,5 @@
declare module 'virtual:starlight/user-config' { declare module "virtual:starlight/user-config" {
const Config: import('@astrojs/starlight/types').StarlightConfig const Config: import("@astrojs/starlight/types").StarlightConfig;
export default Config export default Config;
} }

View File

@ -1,5 +1,5 @@
declare module 'virtual:starlight-ghost-config' { declare module "virtual:starlight-ghost-config" {
const StarlightGhostConfig: import('./src/schemas/config').StarlightGhostConfig const StarlightGhostConfig: import("./src/schemas/config").StarlightGhostConfig;
export default StarlightGhostConfig export default StarlightGhostConfig;
} }

View File

@ -12,7 +12,7 @@ export default defineConfig({
ghostcms({ ghostcms({
ghostURL: "https://ghostdemo.matthiesen.xyz", ghostURL: "https://ghostdemo.matthiesen.xyz",
ThemeProvider: { ThemeProvider: {
theme: '@matthiesenxyz/astro-ghostcms-brutalbyelian', theme: "@matthiesenxyz/astro-ghostcms-brutalbyelian",
}, },
}), }),
], ],

View File

@ -1,33 +1,33 @@
import { defineConfig } from 'astro/config'; import starlight from "@astrojs/starlight";
import starlight from '@astrojs/starlight'; import starlightGhostCMS from "@matthiesenxyz/starlight-ghostcms";
import starlightGhostCMS from '@matthiesenxyz/starlight-ghostcms'; import { defineConfig } from "astro/config";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
site: "http://localhost:4321", site: "http://localhost:4321",
integrations: [ integrations: [
starlight({ starlight({
title: 'My Docs', title: "My Docs",
plugins: [ plugins: [
starlightGhostCMS({ starlightGhostCMS({
title: "Demo Blog", title: "Demo Blog",
rssDescription: "Starlight Playground" rssDescription: "Starlight Playground",
}) }),
], ],
social: { social: {
github: 'https://github.com/withastro/starlight', github: "https://github.com/withastro/starlight",
}, },
sidebar: [ sidebar: [
{ {
label: 'Guides', label: "Guides",
items: [ items: [
// Each item here is one entry in the navigation menu. // Each item here is one entry in the navigation menu.
{ label: 'Example Guide', link: '/guides/example/' }, { label: "Example Guide", link: "/guides/example/" },
], ],
}, },
{ {
label: 'Reference', label: "Reference",
autogenerate: { directory: 'reference' }, autogenerate: { directory: "reference" },
}, },
], ],
}), }),

View File

@ -1,5 +1,5 @@
import { defineCollection } from 'astro:content'; import { docsSchema } from "@astrojs/starlight/schema";
import { docsSchema } from '@astrojs/starlight/schema'; import { defineCollection } from "astro:content";
export const collections = { export const collections = {
docs: defineCollection({ schema: docsSchema() }), docs: defineCollection({ schema: docsSchema() }),