quartz/quartz/plugins/test-helpers.ts
Copilot 06c8ff10f1
refactor: implement plugin decoupling foundation (Phases 1-5) (#3)
* 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>
2025-11-16 16:16:52 +01:00

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)};`),
},
}
}