mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-19 10:54:06 -06:00
* Initial plan * docs: format design document for decoupling strategy Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com> * feat: implement Phase 1-4 of plugin decoupling strategy - Created centralized vfile-schema.ts with all VFile data type definitions - Created plugin-context.ts with PluginUtilities abstraction layer - Created test-helpers.ts for plugin testing utilities - Made BuildCtx readonly to prevent plugin mutations - Added MutableBuildCtx for build orchestration layer - Updated components to not mutate ctx.trie - Updated FrontMatter plugin with temporary cast for backward compatibility - Updated TransformOptions to accept ReadonlyArray Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com> * feat: add plugin utilities to BuildCtx and document plugin decoupling - Added utils property to BuildCtx with createPluginUtilities() - Documented plugin data dependencies with JSDoc comments on transformers and filters - Created comprehensive plugin migration guide in docs/PLUGIN_MIGRATION.md - Updated plugin types.ts with guidance on using PluginContext - All plugins now have access to ctx.utils for path, resource, and escape utilities Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com> * docs: add implementation and security summaries - Created IMPLEMENTATION_SUMMARY.md documenting all phases completed - Created SECURITY_SUMMARY.md with CodeQL scan results - All security checks passed with 0 vulnerabilities - Complete documentation of changes, decisions, and impact Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com> * docs: add guidance for custom plugins extending vfile data - Added section "Adding Custom VFile Fields" to PLUGIN_MIGRATION.md - Demonstrates TypeScript module augmentation for custom fields - Shows best practices for extending vfile data in third-party plugins - Clarifies that centralized schema doesn't prevent custom extensions Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com> * refactor: address code review feedback - Remove `any` type annotations from component map callbacks (Breadcrumbs, FolderContent) - Fix test-helpers: change `config` to `cfg` to match BuildCtx interface - Add `trie: undefined` to mock context for completeness - Add missing vfile fields to schema: text, blocks, htmlAst, hasMermaidDiagram - Make Argv properties truly readonly with ReadonlyArgv type - Add documentation explaining module augmentation pattern is intentional - Document FrontMatter mutation as known technical debt with timeline Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: saberzero1 <8161064+saberzero1@users.noreply.github.com>
133 lines
3.6 KiB
TypeScript
133 lines
3.6 KiB
TypeScript
import { VFile } from "vfile"
|
|
import { QuartzVFileData } from "./vfile-schema"
|
|
import { FullSlug, FilePath, SimpleSlug, RelativeURL, TransformOptions } from "../util/path"
|
|
import { QuartzConfig } from "../cfg"
|
|
import { Argv } from "../util/ctx"
|
|
import { CSSResource } from "../util/resources"
|
|
import { PluginContext, PluginUtilities } from "./plugin-context"
|
|
|
|
/**
|
|
* Create a mock plugin context for testing
|
|
*/
|
|
export function createMockPluginContext(overrides?: Partial<PluginContext>): PluginContext {
|
|
return {
|
|
cfg: createMockConfig(),
|
|
buildId: "test-build",
|
|
argv: createMockArgv(),
|
|
allSlugs: [],
|
|
allFiles: [],
|
|
incremental: false,
|
|
utils: createMockUtilities(),
|
|
trie: undefined,
|
|
...overrides,
|
|
} as PluginContext
|
|
}
|
|
|
|
/**
|
|
* Create a mock VFile for testing
|
|
*/
|
|
export function createMockVFile(data?: Partial<QuartzVFileData>): VFile {
|
|
const file = new VFile("")
|
|
file.data = {
|
|
slug: "test" as FullSlug,
|
|
filePath: "test.md" as FilePath,
|
|
relativePath: "test.md" as FilePath,
|
|
...data,
|
|
} as Partial<QuartzVFileData>
|
|
return file
|
|
}
|
|
|
|
function createMockConfig(): QuartzConfig {
|
|
return {
|
|
configuration: {
|
|
pageTitle: "Test Site",
|
|
baseUrl: "test.com",
|
|
locale: "en-US",
|
|
enableSPA: true,
|
|
enablePopovers: true,
|
|
analytics: null,
|
|
ignorePatterns: [],
|
|
defaultDateType: "created",
|
|
theme: {
|
|
typography: {
|
|
header: "Schibsted Grotesk",
|
|
body: "Source Sans Pro",
|
|
code: "IBM Plex Mono",
|
|
},
|
|
colors: {
|
|
lightMode: {
|
|
light: "#faf8f8",
|
|
lightgray: "#e5e5e5",
|
|
gray: "#b8b8b8",
|
|
darkgray: "#4e4e4e",
|
|
dark: "#2b2b2b",
|
|
secondary: "#284b63",
|
|
tertiary: "#84a59d",
|
|
highlight: "rgba(143, 159, 169, 0.15)",
|
|
textHighlight: "#fff23688",
|
|
},
|
|
darkMode: {
|
|
light: "#161618",
|
|
lightgray: "#393639",
|
|
gray: "#646464",
|
|
darkgray: "#d4d4d4",
|
|
dark: "#ebebec",
|
|
secondary: "#7b97aa",
|
|
tertiary: "#84a59d",
|
|
highlight: "rgba(143, 159, 169, 0.15)",
|
|
textHighlight: "#b3aa0288",
|
|
},
|
|
},
|
|
fontOrigin: "googleFonts",
|
|
cdnCaching: true,
|
|
},
|
|
},
|
|
plugins: {
|
|
transformers: [],
|
|
filters: [],
|
|
emitters: [],
|
|
},
|
|
} as QuartzConfig
|
|
}
|
|
|
|
function createMockArgv(): Argv {
|
|
return {
|
|
directory: "content",
|
|
verbose: false,
|
|
output: "public",
|
|
serve: false,
|
|
watch: false,
|
|
port: 8080,
|
|
wsPort: 3001,
|
|
}
|
|
}
|
|
|
|
function createMockUtilities(): PluginUtilities {
|
|
return {
|
|
path: {
|
|
slugify: (path: FilePath) => path as unknown as FullSlug,
|
|
simplify: (slug: FullSlug) => slug as unknown as SimpleSlug,
|
|
transform: (_from: FullSlug, to: string, _opts: TransformOptions) => to as RelativeURL,
|
|
toRoot: (_slug: FullSlug) => "/" as RelativeURL,
|
|
split: (slug: FullSlug) => [slug, ""],
|
|
join: (...segments: string[]) => segments.join("/") as FilePath,
|
|
},
|
|
resources: {
|
|
createExternalJS: (src: string, loadTime?: "beforeDOMReady" | "afterDOMReady") => ({
|
|
src,
|
|
contentType: "external" as const,
|
|
loadTime: loadTime ?? "afterDOMReady",
|
|
}),
|
|
createInlineJS: (script: string, loadTime?: "beforeDOMReady" | "afterDOMReady") => ({
|
|
script,
|
|
contentType: "inline" as const,
|
|
loadTime: loadTime ?? "afterDOMReady",
|
|
}),
|
|
createCSS: (resource: CSSResource) => resource,
|
|
},
|
|
escape: {
|
|
html: (text: string) => text.replace(/[&<>"']/g, (m) => `&#${m.charCodeAt(0)};`),
|
|
},
|
|
}
|
|
}
|