@ncukondo/slide-generation 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +248 -0
- package/README_ja.md +248 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +2994 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +999 -0
- package/dist/index.js +1469 -0
- package/dist/index.js.map +1 -0
- package/icons/custom/.gitkeep +3 -0
- package/icons/registry.yaml +77 -0
- package/package.json +84 -0
- package/templates/basic/bullet-list.yaml +39 -0
- package/templates/basic/numbered-list.yaml +39 -0
- package/templates/basic/section.yaml +26 -0
- package/templates/basic/title.yaml +46 -0
- package/templates/data/comparison-table.yaml +107 -0
- package/templates/data/table.yaml +94 -0
- package/templates/diagrams/cycle-diagram.yaml +71 -0
- package/templates/diagrams/flow-chart.yaml +141 -0
- package/templates/diagrams/hierarchy.yaml +117 -0
- package/templates/diagrams/matrix.yaml +163 -0
- package/templates/diagrams/timeline.yaml +167 -0
- package/templates/layouts/gallery.yaml +94 -0
- package/templates/layouts/image-text.yaml +105 -0
- package/templates/layouts/three-column.yaml +101 -0
- package/templates/layouts/two-column.yaml +85 -0
- package/templates/special/bibliography.yaml +132 -0
- package/templates/special/code-block.yaml +79 -0
- package/templates/special/custom.yaml +45 -0
- package/templates/special/quote.yaml +76 -0
- package/themes/default.css +122 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/parser.ts","../src/core/transformer.ts","../src/core/renderer.ts","../src/core/pipeline.ts","../src/templates/engine.ts","../src/templates/loader.ts","../src/templates/validators.ts","../src/icons/registry.ts","../src/icons/schema.ts","../src/icons/resolver.ts","../src/references/manager.ts","../src/references/extractor.ts","../src/references/formatter.ts","../src/index.ts"],"sourcesContent":["import { z } from 'zod';\nimport { parse as parseYaml } from 'yaml';\nimport { readFile } from 'fs/promises';\n\n// References config schema\nconst referencesConfigSchema = z.object({\n enabled: z.boolean().default(true),\n style: z.string().default('author-year-pmid'),\n});\n\n// Meta schema\nconst metaSchema = z.object({\n title: z.string(),\n author: z.string().optional(),\n date: z.string().optional(),\n theme: z.string().default('default'),\n references: referencesConfigSchema.optional(),\n});\n\n// Slide schema\nconst slideSchema = z.object({\n template: z.string(),\n content: z.record(z.unknown()).default({}),\n class: z.string().optional(),\n notes: z.string().optional(),\n raw: z.string().optional(),\n});\n\n// Presentation schema\nexport const presentationSchema = z.object({\n meta: metaSchema,\n slides: z.array(slideSchema).default([]),\n});\n\nexport type PresentationMeta = z.infer<typeof metaSchema>;\nexport type ParsedSlide = z.infer<typeof slideSchema>;\nexport type ParsedPresentation = z.infer<typeof presentationSchema>;\n\nexport class ParseError extends Error {\n constructor(\n message: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'ParseError';\n }\n}\n\nexport class ValidationError extends Error {\n constructor(\n message: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'ValidationError';\n }\n}\n\nexport class Parser {\n parse(yamlContent: string): ParsedPresentation {\n let rawData: unknown;\n\n try {\n rawData = parseYaml(yamlContent);\n } catch (error) {\n throw new ParseError('Failed to parse YAML', error);\n }\n\n const result = presentationSchema.safeParse(rawData);\n\n if (!result.success) {\n throw new ValidationError(\n 'Schema validation failed',\n result.error.format()\n );\n }\n\n return result.data;\n }\n\n async parseFile(filePath: string): Promise<ParsedPresentation> {\n let content: string;\n\n try {\n content = await readFile(filePath, 'utf-8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new ParseError(`File not found: ${filePath}`);\n }\n throw new ParseError(`Failed to read file: ${filePath}`, error);\n }\n\n return this.parse(content);\n }\n}\n","import type { TemplateEngine, IconsHelper, RefsHelper } from '../templates/engine';\nimport type { TemplateLoader } from '../templates/loader';\nimport type { IconResolver } from '../icons/resolver';\nimport type { CitationFormatter } from '../references/formatter';\nimport type { ParsedSlide, ParsedPresentation, PresentationMeta } from './parser';\n\n// Placeholder patterns for async resolution\nconst ICON_PLACEHOLDER_PREFIX = '___ICON_PLACEHOLDER_';\nconst ICON_PLACEHOLDER_SUFFIX = '___';\nconst REFS_CITE_PLACEHOLDER_PREFIX = '___REFS_CITE_PLACEHOLDER_';\nconst REFS_CITE_PLACEHOLDER_SUFFIX = '___';\nconst REFS_EXPAND_PLACEHOLDER_PREFIX = '___REFS_EXPAND_PLACEHOLDER_';\nconst REFS_EXPAND_PLACEHOLDER_SUFFIX = '___';\n\n/**\n * Context passed to each slide transformation\n */\nexport interface TransformContext {\n meta: PresentationMeta;\n slideIndex: number;\n totalSlides: number;\n}\n\n/**\n * Error thrown when transformation fails\n */\nexport class TransformError extends Error {\n constructor(\n message: string,\n public slide?: ParsedSlide,\n public details?: unknown\n ) {\n super(message);\n this.name = 'TransformError';\n }\n}\n\n/**\n * Pending async operations collected during template rendering\n */\ninterface PendingOperations {\n icons: Map<string, { name: string; options: Record<string, unknown> | undefined }>;\n cites: Map<string, string>;\n expands: Map<string, string>;\n}\n\n/**\n * Transformer applies templates to slides and generates HTML content\n */\nexport class Transformer {\n constructor(\n private templateEngine: TemplateEngine,\n private templateLoader: TemplateLoader,\n private iconResolver: IconResolver,\n private citationFormatter: CitationFormatter\n ) {}\n\n /**\n * Transform a single slide using its template\n */\n async transform(slide: ParsedSlide, context: TransformContext): Promise<string> {\n // Handle raw template - return raw content directly\n if (slide.template === 'raw') {\n return slide.raw ?? '';\n }\n\n // Get the template definition\n const template = this.templateLoader.get(slide.template);\n if (!template) {\n throw new TransformError(\n `Template \"${slide.template}\" not found`,\n slide\n );\n }\n\n // Validate content against template schema\n const validationResult = this.templateLoader.validateContent(\n slide.template,\n slide.content\n );\n if (!validationResult.valid) {\n throw new TransformError(\n `Slide content validation failed: ${validationResult.errors?.join(', ')}`,\n slide,\n validationResult.errors\n );\n }\n\n // Build template context with helpers that use placeholders\n const pending: PendingOperations = {\n icons: new Map(),\n cites: new Map(),\n expands: new Map(),\n };\n const templateContext = this.buildTemplateContext(slide, context, pending);\n\n // Render the template (synchronous, with placeholders)\n let output = this.templateEngine.render(template.output, templateContext);\n\n // Resolve all async operations and replace placeholders\n output = await this.resolvePlaceholders(output, pending);\n\n // Add CSS class directive if specified\n if (slide.class) {\n output = `<!-- _class: ${slide.class} -->\\n${output}`;\n }\n\n return output.trim();\n }\n\n /**\n * Transform all slides in a presentation\n */\n async transformAll(presentation: ParsedPresentation): Promise<string[]> {\n const results: string[] = [];\n const totalSlides = presentation.slides.length;\n\n for (let i = 0; i < presentation.slides.length; i++) {\n const slide = presentation.slides[i]!;\n const context: TransformContext = {\n meta: presentation.meta,\n slideIndex: i,\n totalSlides,\n };\n\n const transformed = await this.transform(slide, context);\n results.push(transformed);\n }\n\n return results;\n }\n\n /**\n * Build the full template context with helpers that collect async operations\n */\n private buildTemplateContext(\n slide: ParsedSlide,\n context: TransformContext,\n pending: PendingOperations\n ): Record<string, unknown> {\n let iconCounter = 0;\n let citeCounter = 0;\n let expandCounter = 0;\n\n // Create icons helper that returns placeholders\n const icons: IconsHelper = {\n render: (name: string, options?: Record<string, unknown>) => {\n const id = `${iconCounter++}`;\n const placeholder = `${ICON_PLACEHOLDER_PREFIX}${id}${ICON_PLACEHOLDER_SUFFIX}`;\n pending.icons.set(id, { name, options });\n return placeholder;\n },\n };\n\n // Create refs helper that returns placeholders\n const refs: RefsHelper = {\n cite: (id: string) => {\n const counterId = `${citeCounter++}`;\n const placeholder = `${REFS_CITE_PLACEHOLDER_PREFIX}${counterId}${REFS_CITE_PLACEHOLDER_SUFFIX}`;\n pending.cites.set(counterId, id);\n return placeholder;\n },\n expand: (text: string) => {\n const counterId = `${expandCounter++}`;\n const placeholder = `${REFS_EXPAND_PLACEHOLDER_PREFIX}${counterId}${REFS_EXPAND_PLACEHOLDER_SUFFIX}`;\n pending.expands.set(counterId, text);\n return placeholder;\n },\n };\n\n return {\n content: slide.content,\n meta: {\n title: context.meta.title,\n author: context.meta.author,\n theme: context.meta.theme,\n },\n slide: {\n index: context.slideIndex,\n total: context.totalSlides,\n },\n icons,\n refs,\n };\n }\n\n /**\n * Resolve all placeholders by executing async operations\n */\n private async resolvePlaceholders(\n output: string,\n pending: PendingOperations\n ): Promise<string> {\n // Resolve icons\n const iconResults = new Map<string, string>();\n for (const [id, { name, options }] of pending.icons) {\n const rendered = await this.iconResolver.render(\n name,\n options as { size?: string; color?: string; class?: string } | undefined\n );\n iconResults.set(id, rendered);\n }\n\n // Resolve citations\n const citeResults = new Map<string, string>();\n for (const [counterId, id] of pending.cites) {\n const formatted = await this.citationFormatter.formatInline(id);\n citeResults.set(counterId, formatted);\n }\n\n // Resolve citation expansions\n const expandResults = new Map<string, string>();\n for (const [counterId, text] of pending.expands) {\n const expanded = await this.citationFormatter.expandCitations(text);\n expandResults.set(counterId, expanded);\n }\n\n // Replace all placeholders\n let result = output;\n\n for (const [id, rendered] of iconResults) {\n const placeholder = `${ICON_PLACEHOLDER_PREFIX}${id}${ICON_PLACEHOLDER_SUFFIX}`;\n result = result.replace(placeholder, rendered);\n }\n\n for (const [counterId, formatted] of citeResults) {\n const placeholder = `${REFS_CITE_PLACEHOLDER_PREFIX}${counterId}${REFS_CITE_PLACEHOLDER_SUFFIX}`;\n result = result.replace(placeholder, formatted);\n }\n\n for (const [counterId, expanded] of expandResults) {\n const placeholder = `${REFS_EXPAND_PLACEHOLDER_PREFIX}${counterId}${REFS_EXPAND_PLACEHOLDER_SUFFIX}`;\n result = result.replace(placeholder, expanded);\n }\n\n return result;\n }\n}\n","import type { PresentationMeta } from './parser';\n\n/**\n * Options for rendering the final Marp markdown\n */\nexport interface RenderOptions {\n /** Include theme in front matter (default: true) */\n includeTheme?: boolean;\n /** Speaker notes for each slide (indexed by slide position) */\n notes?: (string | undefined)[];\n /** Additional front matter properties */\n additionalFrontMatter?: Record<string, unknown>;\n}\n\n/**\n * Renderer combines transformed slides into Marp-compatible Markdown\n */\nexport class Renderer {\n /**\n * Render slides and metadata into final Marp markdown\n */\n render(\n slides: string[],\n meta: PresentationMeta,\n options?: RenderOptions\n ): string {\n const frontMatter = this.renderFrontMatter(meta, options);\n const slidesContent = this.joinSlides(slides, options?.notes);\n\n if (slides.length === 0) {\n return frontMatter;\n }\n\n return `${frontMatter}\\n\\n${slidesContent}`;\n }\n\n /**\n * Render the YAML front matter block\n */\n private renderFrontMatter(\n meta: PresentationMeta,\n options?: RenderOptions\n ): string {\n const lines: string[] = ['---', 'marp: true'];\n\n // Add title\n lines.push(`title: ${meta.title}`);\n\n // Add author if present\n if (meta.author) {\n lines.push(`author: ${meta.author}`);\n }\n\n // Add date if present\n if (meta.date) {\n lines.push(`date: ${meta.date}`);\n }\n\n // Add theme if enabled (default: true)\n const includeTheme = options?.includeTheme ?? true;\n if (includeTheme && meta.theme) {\n lines.push(`theme: ${meta.theme}`);\n }\n\n // Add additional front matter properties\n if (options?.additionalFrontMatter) {\n for (const [key, value] of Object.entries(options.additionalFrontMatter)) {\n lines.push(`${key}: ${this.formatFrontMatterValue(value)}`);\n }\n }\n\n lines.push('---');\n\n return lines.join('\\n');\n }\n\n /**\n * Format a front matter value for YAML\n */\n private formatFrontMatterValue(value: unknown): string {\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false';\n }\n if (typeof value === 'number') {\n return String(value);\n }\n if (typeof value === 'string') {\n // Quote if contains special characters\n if (/[:#[\\]{}|>]/.test(value)) {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`;\n }\n return value;\n }\n return String(value);\n }\n\n /**\n * Join slides with Marp slide separator\n */\n private joinSlides(\n slides: string[],\n notes?: (string | undefined)[]\n ): string {\n const parts: string[] = [];\n\n for (let i = 0; i < slides.length; i++) {\n let slideContent = slides[i]!;\n\n // Add speaker notes if present\n const note = notes?.[i];\n if (note && note.trim()) {\n slideContent = `${slideContent}\\n\\n${this.renderSpeakerNotes(note)}`;\n }\n\n parts.push(slideContent);\n }\n\n // Join with Marp slide separator (---)\n return parts.map(slide => `---\\n\\n${slide}`).join('\\n\\n');\n }\n\n /**\n * Render speaker notes as HTML comment\n */\n private renderSpeakerNotes(notes: string): string {\n return `<!--\\n${notes}\\n-->`;\n }\n}\n","import { writeFile } from 'fs/promises';\nimport { Parser, type ParsedPresentation } from './parser';\nimport { Transformer } from './transformer';\nimport { Renderer, type RenderOptions } from './renderer';\nimport { TemplateEngine } from '../templates/engine';\nimport { TemplateLoader } from '../templates/loader';\nimport { IconRegistryLoader } from '../icons/registry';\nimport { IconResolver } from '../icons/resolver';\nimport { ReferenceManager, type CSLItem } from '../references/manager';\nimport { CitationExtractor } from '../references/extractor';\nimport { CitationFormatter } from '../references/formatter';\nimport type { Config } from '../config/schema';\n\n/**\n * Options for the Pipeline\n */\nexport interface PipelineOptions {\n /** Custom config path override */\n configPath?: string;\n /** Output file path (if not specified, returns string only) */\n outputPath?: string;\n /** Enable verbose/progress output */\n verbose?: boolean;\n}\n\n/**\n * Result of a pipeline run\n */\nexport interface PipelineResult {\n /** Generated Marp markdown */\n output: string;\n /** Citation IDs found in the presentation */\n citations: string[];\n /** Warnings generated during processing */\n warnings: string[];\n /** Number of slides processed */\n slideCount: number;\n}\n\n/**\n * Error thrown when pipeline processing fails\n */\nexport class PipelineError extends Error {\n constructor(\n message: string,\n public stage: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'PipelineError';\n }\n}\n\n/**\n * Pipeline orchestrates the full YAML to Marp markdown conversion\n *\n * Stages:\n * 1. Parse Source - Load and validate YAML\n * 2. Collect Citations - Extract citation IDs from all slides\n * 3. Resolve References - Fetch bibliography data\n * 4. Transform Slides - Apply templates and resolve icons/citations\n * 5. Render Output - Generate final Marp markdown\n */\nexport class Pipeline {\n private parser: Parser;\n private templateEngine: TemplateEngine;\n private templateLoader: TemplateLoader;\n private iconRegistry: IconRegistryLoader;\n private iconResolver: IconResolver;\n private referenceManager: ReferenceManager;\n private citationExtractor: CitationExtractor;\n private citationFormatter: CitationFormatter;\n private transformer: Transformer;\n private renderer: Renderer;\n private warnings: string[] = [];\n\n constructor(private config: Config) {\n // Initialize all components\n this.parser = new Parser();\n this.templateEngine = new TemplateEngine();\n this.templateLoader = new TemplateLoader();\n this.iconRegistry = new IconRegistryLoader();\n this.iconResolver = new IconResolver(this.iconRegistry);\n this.referenceManager = new ReferenceManager(\n config.references.connection.command\n );\n this.citationExtractor = new CitationExtractor();\n this.citationFormatter = new CitationFormatter(\n this.referenceManager,\n {\n author: {\n maxAuthors: config.references.format.maxAuthors,\n etAl: config.references.format.etAl,\n etAlJa: config.references.format.etAlJa,\n },\n inline: {\n authorSep: config.references.format.authorSep,\n identifierSep: config.references.format.identifierSep,\n },\n }\n );\n this.transformer = new Transformer(\n this.templateEngine,\n this.templateLoader,\n this.iconResolver,\n this.citationFormatter\n );\n this.renderer = new Renderer();\n }\n\n /**\n * Run the full conversion pipeline\n */\n async run(inputPath: string, options?: PipelineOptions): Promise<string> {\n this.warnings = [];\n\n try {\n // Stage 1: Parse Source\n const presentation = await this.parseSource(inputPath);\n\n // Stage 2: Collect Citations\n const citationIds = this.collectCitations(presentation);\n\n // Stage 3: Resolve References\n await this.resolveReferences(citationIds);\n\n // Stage 4: Transform Slides\n const transformedSlides = await this.transformSlides(presentation);\n\n // Stage 5: Render Output\n const output = this.render(transformedSlides, presentation);\n\n // Write output file if specified\n if (options?.outputPath) {\n await writeFile(options.outputPath, output, 'utf-8');\n }\n\n return output;\n } catch (error) {\n if (error instanceof PipelineError) {\n throw error;\n }\n throw new PipelineError(\n error instanceof Error ? error.message : 'Unknown error',\n 'unknown',\n error\n );\n }\n }\n\n /**\n * Run the full pipeline with detailed result\n */\n async runWithResult(\n inputPath: string,\n options?: PipelineOptions\n ): Promise<PipelineResult> {\n this.warnings = [];\n\n try {\n // Stage 1: Parse Source\n const presentation = await this.parseSource(inputPath);\n\n // Stage 2: Collect Citations\n const citationIds = this.collectCitations(presentation);\n\n // Stage 3: Resolve References\n await this.resolveReferences(citationIds);\n\n // Stage 4: Transform Slides\n const transformedSlides = await this.transformSlides(presentation);\n\n // Stage 5: Render Output\n const output = this.render(transformedSlides, presentation);\n\n // Write output file if specified\n if (options?.outputPath) {\n await writeFile(options.outputPath, output, 'utf-8');\n }\n\n return {\n output,\n citations: citationIds,\n warnings: this.warnings,\n slideCount: presentation.slides.length,\n };\n } catch (error) {\n if (error instanceof PipelineError) {\n throw error;\n }\n throw new PipelineError(\n error instanceof Error ? error.message : 'Unknown error',\n 'unknown',\n error\n );\n }\n }\n\n /**\n * Initialize the pipeline by loading templates and icon registry\n */\n async initialize(): Promise<void> {\n try {\n // Load built-in templates\n await this.templateLoader.loadBuiltIn(this.config.templates.builtin);\n\n // Load custom templates if specified\n if (this.config.templates.custom) {\n await this.templateLoader.loadCustom(this.config.templates.custom);\n }\n\n // Load icon registry\n await this.iconRegistry.load(this.config.icons.registry);\n } catch (error) {\n throw new PipelineError(\n `Failed to initialize pipeline: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'initialize',\n error\n );\n }\n }\n\n /**\n * Get collected warnings\n */\n getWarnings(): string[] {\n return [...this.warnings];\n }\n\n // --- Private Stage Methods ---\n\n /**\n * Stage 1: Parse the YAML source file\n */\n private async parseSource(inputPath: string): Promise<ParsedPresentation> {\n try {\n return await this.parser.parseFile(inputPath);\n } catch (error) {\n throw new PipelineError(\n `Failed to parse source file: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'parse',\n error\n );\n }\n }\n\n /**\n * Stage 2: Collect all citation IDs from the presentation\n */\n private collectCitations(presentation: ParsedPresentation): string[] {\n const citations = this.citationExtractor.extractFromPresentation(presentation);\n return this.citationExtractor.getUniqueIds(citations);\n }\n\n /**\n * Stage 3: Resolve references from the reference manager\n */\n private async resolveReferences(ids: string[]): Promise<Map<string, CSLItem>> {\n if (!this.config.references.enabled || ids.length === 0) {\n return new Map();\n }\n\n try {\n const items = await this.referenceManager.getByIds(ids);\n\n // Warn about missing references\n for (const id of ids) {\n if (!items.has(id)) {\n this.warnings.push(`Reference not found: ${id}`);\n }\n }\n\n return items;\n } catch (error) {\n // Non-fatal: log warning and continue\n this.warnings.push(\n `Failed to resolve references: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n return new Map();\n }\n }\n\n /**\n * Stage 4: Transform all slides using templates\n */\n private async transformSlides(\n presentation: ParsedPresentation\n ): Promise<string[]> {\n try {\n return await this.transformer.transformAll(presentation);\n } catch (error) {\n throw new PipelineError(\n `Failed to transform slides: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'transform',\n error\n );\n }\n }\n\n /**\n * Stage 5: Render the final Marp markdown\n */\n private render(\n slides: string[],\n presentation: ParsedPresentation\n ): string {\n try {\n // Collect notes from slides\n const notes = presentation.slides.map((slide) => slide.notes);\n\n const renderOptions: RenderOptions = {\n includeTheme: true,\n notes,\n };\n\n return this.renderer.render(slides, presentation.meta, renderOptions);\n } catch (error) {\n throw new PipelineError(\n `Failed to render output: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'render',\n error\n );\n }\n }\n}\n","import nunjucks from \"nunjucks\";\n\n/**\n * Icons helper interface for template rendering\n */\nexport interface IconsHelper {\n render: (name: string, options?: Record<string, unknown>) => string;\n}\n\n/**\n * References helper interface for citation handling\n */\nexport interface RefsHelper {\n cite: (id: string) => string;\n expand: (text: string) => string;\n}\n\n/**\n * Slide context passed to templates\n */\nexport interface SlideContext {\n index: number;\n total: number;\n}\n\n/**\n * Meta context for presentation metadata\n */\nexport interface MetaContext {\n title: string;\n author?: string;\n theme: string;\n [key: string]: unknown;\n}\n\n/**\n * Full template context interface\n */\nexport interface TemplateContext {\n content: Record<string, unknown>;\n meta: MetaContext;\n slide: SlideContext;\n icons: IconsHelper;\n refs: RefsHelper;\n [key: string]: unknown;\n}\n\nexport class TemplateEngine {\n private env: nunjucks.Environment;\n\n constructor() {\n this.env = new nunjucks.Environment(null, {\n autoescape: false, // HTML output for Marp\n throwOnUndefined: false,\n });\n this.registerFilters();\n this.registerGlobals();\n }\n\n render(template: string, context: Record<string, unknown>): string {\n return this.env.renderString(template, context);\n }\n\n private registerFilters(): void {\n // Will be extended in later steps\n }\n\n private registerGlobals(): void {\n // Icon helper stub - will be replaced with real implementation\n const icons = {\n render: (name: string, options?: Record<string, unknown>): string => {\n const size = (options?.[\"size\"] as string) ?? \"24px\";\n const color = (options?.[\"color\"] as string) ?? \"currentColor\";\n return `<span class=\"icon icon-${name}\" style=\"font-size: ${size}; color: ${color};\">[${name}]</span>`;\n },\n };\n\n this.env.addGlobal(\"icons\", icons);\n\n // Reference helper stub - will be replaced with real implementation\n const refs = {\n cite: (id: string): string => {\n const cleanId = id.replace(\"@\", \"\");\n return `(${cleanId})`;\n },\n expand: (text: string): string => {\n // Simple stub - replace [@id] with (id)\n return text.replace(/\\[@(\\w+)\\]/g, \"($1)\");\n },\n };\n\n this.env.addGlobal(\"refs\", refs);\n }\n}\n","import { z } from \"zod\";\nimport * as yaml from \"yaml\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport {\n validateWithJsonSchema,\n type JsonSchema,\n type ValidationResult,\n} from \"./validators\";\n\n/**\n * JSON Schema-like structure for template content validation\n */\nconst jsonSchemaSchema = z.record(z.unknown());\n\n/**\n * Template definition schema - validates YAML template definition files\n */\nexport const templateDefSchema = z.object({\n name: z.string().min(1, \"Template name is required\"),\n description: z.string(),\n category: z.string(),\n schema: jsonSchemaSchema,\n example: z.record(z.unknown()).optional(),\n output: z.string().min(1, \"Template output is required\"),\n css: z.string().optional(),\n});\n\n/**\n * Template definition type derived from schema\n */\nexport type TemplateDefinition = z.infer<typeof templateDefSchema>;\n\n/**\n * Loads and manages template definitions from YAML files\n */\nexport class TemplateLoader {\n private templates: Map<string, TemplateDefinition>;\n\n constructor() {\n this.templates = new Map();\n }\n\n /**\n * Load a template from a YAML string\n */\n async loadFromString(yamlContent: string): Promise<void> {\n const parsed = yaml.parse(yamlContent);\n const result = templateDefSchema.safeParse(parsed);\n\n if (!result.success) {\n const errors = result.error.errors\n .map(e => `${e.path.join(\".\")}: ${e.message}`)\n .join(\", \");\n throw new Error(`Invalid template definition: ${errors}`);\n }\n\n this.templates.set(result.data.name, result.data);\n }\n\n /**\n * Load a template from a file\n */\n async loadFromFile(filePath: string): Promise<void> {\n const content = await fs.readFile(filePath, \"utf-8\");\n await this.loadFromString(content);\n }\n\n /**\n * Load all templates from a directory (recursively)\n */\n async loadBuiltIn(directory: string): Promise<void> {\n await this.loadDirectory(directory);\n }\n\n /**\n * Load custom templates from a directory (can override built-in)\n */\n async loadCustom(directory: string): Promise<void> {\n await this.loadDirectory(directory);\n }\n\n /**\n * Internal method to load templates from a directory\n */\n private async loadDirectory(directory: string): Promise<void> {\n const entries = await fs.readdir(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(directory, entry.name);\n\n if (entry.isDirectory()) {\n await this.loadDirectory(fullPath);\n } else if (entry.isFile() && (entry.name.endsWith(\".yaml\") || entry.name.endsWith(\".yml\"))) {\n await this.loadFromFile(fullPath);\n }\n }\n }\n\n /**\n * Get a template by name\n */\n get(name: string): TemplateDefinition | undefined {\n return this.templates.get(name);\n }\n\n /**\n * List all loaded templates\n */\n list(): TemplateDefinition[] {\n return Array.from(this.templates.values());\n }\n\n /**\n * List templates filtered by category\n */\n listByCategory(category: string): TemplateDefinition[] {\n return this.list().filter(t => t.category === category);\n }\n\n /**\n * Validate content against a template's schema\n */\n validateContent(templateName: string, content: unknown): ValidationResult {\n const template = this.get(templateName);\n\n if (!template) {\n return {\n valid: false,\n errors: [`Template \"${templateName}\" not found`],\n };\n }\n\n return validateWithJsonSchema(template.schema as JsonSchema, content);\n }\n}\n\nexport type { ValidationResult };\n","import { z, type ZodTypeAny, type ZodIssue } from \"zod\";\n\n/**\n * JSON Schema type definition (subset used by templates)\n */\nexport interface JsonSchema {\n type?: string;\n required?: string[];\n properties?: Record<string, JsonSchema>;\n items?: JsonSchema;\n minItems?: number;\n maxItems?: number;\n pattern?: string;\n enum?: (string | number | boolean)[];\n default?: unknown;\n description?: string;\n oneOf?: JsonSchema[];\n}\n\n/**\n * Validation result for content against template schema\n */\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Convert a JSON Schema object to a Zod schema\n *\n * Supports a subset of JSON Schema used by template definitions:\n * - Basic types: string, number, boolean, array, object\n * - Required fields\n * - Nested objects and arrays\n * - Pattern validation for strings\n * - minItems/maxItems for arrays\n */\nexport function jsonSchemaToZod(schema: JsonSchema): ZodTypeAny {\n // Handle oneOf first (union type)\n if (schema.oneOf && schema.oneOf.length > 0) {\n const schemas = schema.oneOf.map((s) => jsonSchemaToZod(s));\n if (schemas.length === 1) {\n return schemas[0]!;\n }\n // z.union requires at least 2 schemas\n return z.union(schemas as [ZodTypeAny, ZodTypeAny, ...ZodTypeAny[]]);\n }\n\n const type = schema.type ?? \"object\";\n\n switch (type) {\n case \"string\": {\n // Handle enum first (enum values are always valid)\n if (schema.enum && schema.enum.length > 0) {\n const enumValues = schema.enum as [string, ...string[]];\n return z.enum(enumValues);\n }\n\n let zodSchema = z.string();\n if (schema.pattern) {\n zodSchema = zodSchema.regex(new RegExp(schema.pattern));\n }\n return zodSchema;\n }\n\n case \"number\":\n return z.number();\n\n case \"integer\":\n return z.number().int();\n\n case \"boolean\":\n return z.boolean();\n\n case \"array\": {\n const itemSchema = schema.items ? jsonSchemaToZod(schema.items) : z.unknown();\n let arraySchema = z.array(itemSchema);\n\n if (schema.minItems !== undefined) {\n arraySchema = arraySchema.min(schema.minItems);\n }\n if (schema.maxItems !== undefined) {\n arraySchema = arraySchema.max(schema.maxItems);\n }\n\n return arraySchema;\n }\n\n case \"object\": {\n if (!schema.properties) {\n return z.record(z.unknown());\n }\n\n const shape: Record<string, ZodTypeAny> = {};\n const required = new Set(schema.required ?? []);\n\n for (const [key, propSchema] of Object.entries(schema.properties)) {\n const propZod = jsonSchemaToZod(propSchema);\n shape[key] = required.has(key) ? propZod : propZod.optional();\n }\n\n return z.object(shape).passthrough();\n }\n\n default:\n return z.unknown();\n }\n}\n\n/**\n * Validate content against a JSON Schema\n */\nexport function validateWithJsonSchema(\n schema: JsonSchema,\n content: unknown\n): ValidationResult {\n const zodSchema = jsonSchemaToZod(schema);\n const result = zodSchema.safeParse(content);\n\n if (result.success) {\n return { valid: true, errors: [] };\n }\n\n const errors = result.error.errors.map((issue: ZodIssue) => {\n const path = issue.path.join(\".\");\n return path ? `${path}: ${issue.message}` : issue.message;\n });\n\n return { valid: false, errors };\n}\n","import * as fs from \"node:fs/promises\";\nimport { parse as parseYaml } from \"yaml\";\nimport {\n iconRegistrySchema,\n type IconRegistry,\n type IconSource,\n type IconDefaults,\n} from \"./schema.js\";\n\n/**\n * Parsed icon reference with prefix and name\n */\nexport interface ParsedIconReference {\n prefix: string;\n name: string;\n}\n\n/**\n * Icon Registry Loader - loads and manages icon registry configuration\n */\nexport class IconRegistryLoader {\n private registry: IconRegistry | null = null;\n private sourcesByPrefix: Map<string, IconSource> = new Map();\n private aliasMap: Map<string, string> = new Map();\n private colorMap: Map<string, string> = new Map();\n\n /**\n * Load registry from YAML file\n */\n async load(configPath: string): Promise<IconRegistry> {\n const content = await fs.readFile(configPath, \"utf-8\");\n const parsed = parseYaml(content);\n const validated = iconRegistrySchema.parse(parsed);\n\n this.registry = validated;\n this.buildMaps();\n\n return validated;\n }\n\n /**\n * Resolve an alias to its icon reference\n * @returns The resolved icon reference or the original name if not an alias\n */\n resolveAlias(nameOrAlias: string): string {\n return this.aliasMap.get(nameOrAlias) ?? nameOrAlias;\n }\n\n /**\n * Get icon source by prefix\n */\n getSource(prefix: string): IconSource | undefined {\n return this.sourcesByPrefix.get(prefix);\n }\n\n /**\n * Parse an icon reference string (e.g., \"mi:home\" or \"iconify:mdi:account\")\n * @returns Parsed reference or null if invalid format\n */\n parseIconReference(reference: string): ParsedIconReference | null {\n const colonIndex = reference.indexOf(\":\");\n if (colonIndex === -1) {\n return null;\n }\n\n const prefix = reference.substring(0, colonIndex);\n const name = reference.substring(colonIndex + 1);\n\n return { prefix, name };\n }\n\n /**\n * Get registry defaults\n */\n getDefaults(): IconDefaults {\n if (!this.registry) {\n return { size: \"24px\", color: \"currentColor\" };\n }\n return this.registry.defaults;\n }\n\n /**\n * Get color by name from color palette\n */\n getColor(name: string): string | undefined {\n return this.colorMap.get(name);\n }\n\n /**\n * Get all sources\n */\n getSources(): IconSource[] {\n return this.registry?.sources ?? [];\n }\n\n /**\n * Get all aliases\n */\n getAliases(): Record<string, string> {\n return this.registry?.aliases ?? {};\n }\n\n /**\n * Check if registry is loaded\n */\n isLoaded(): boolean {\n return this.registry !== null;\n }\n\n /**\n * Build internal lookup maps from registry\n */\n private buildMaps(): void {\n this.sourcesByPrefix.clear();\n this.aliasMap.clear();\n this.colorMap.clear();\n\n if (!this.registry) {\n return;\n }\n\n // Build sources map\n for (const source of this.registry.sources) {\n this.sourcesByPrefix.set(source.prefix, source);\n }\n\n // Build aliases map\n for (const [alias, target] of Object.entries(this.registry.aliases)) {\n this.aliasMap.set(alias, target);\n }\n\n // Build colors map\n if (this.registry.colors) {\n for (const [name, color] of Object.entries(this.registry.colors)) {\n this.colorMap.set(name, color);\n }\n }\n }\n}\n","import { z } from \"zod\";\n\n/**\n * Schema for icon source types\n */\nexport const iconSourceTypeSchema = z.enum([\n \"web-font\",\n \"svg-inline\",\n \"svg-sprite\",\n \"local-svg\",\n]);\n\nexport type IconSourceType = z.infer<typeof iconSourceTypeSchema>;\n\n/**\n * Schema for individual icon source definition\n */\nexport const iconSourceSchema = z.object({\n name: z.string(),\n type: iconSourceTypeSchema,\n prefix: z.string(),\n url: z.string().optional(),\n path: z.string().optional(),\n render: z.string().optional(),\n});\n\nexport type IconSource = z.infer<typeof iconSourceSchema>;\n\n/**\n * Schema for icon defaults\n */\nexport const iconDefaultsSchema = z.object({\n size: z.string().default(\"24px\"),\n color: z.string().default(\"currentColor\"),\n});\n\nexport type IconDefaults = z.infer<typeof iconDefaultsSchema>;\n\n/**\n * Schema for the full icon registry configuration\n */\nexport const iconRegistrySchema = z.object({\n sources: z.array(iconSourceSchema),\n aliases: z.record(z.string()).default({}),\n colors: z.record(z.string()).optional(),\n defaults: iconDefaultsSchema.default({}),\n});\n\nexport type IconRegistry = z.infer<typeof iconRegistrySchema>;\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport nunjucks from \"nunjucks\";\nimport { IconRegistryLoader } from \"./registry.js\";\nimport type { IconSource } from \"./schema.js\";\n\n/**\n * Options for rendering an icon\n */\nexport interface IconOptions {\n size?: string;\n color?: string;\n class?: string;\n}\n\n/**\n * Icon Resolver - renders icons from various sources\n */\nexport class IconResolver {\n private nunjucksEnv: nunjucks.Environment;\n\n constructor(private registry: IconRegistryLoader) {\n this.nunjucksEnv = new nunjucks.Environment(null, {\n autoescape: false,\n });\n }\n\n /**\n * Render an icon by name or alias\n */\n async render(nameOrAlias: string, options?: IconOptions): Promise<string> {\n // Resolve alias if needed\n const resolved = this.registry.resolveAlias(nameOrAlias);\n\n // Parse the icon reference\n const parsed = this.registry.parseIconReference(resolved);\n if (!parsed) {\n throw new Error(\n `Invalid icon reference format: \"${resolved}\". Expected format: \"prefix:name\"`\n );\n }\n\n // Get the source for this prefix\n const source = this.registry.getSource(parsed.prefix);\n if (!source) {\n throw new Error(`Unknown icon source prefix: \"${parsed.prefix}\"`);\n }\n\n // Get defaults and merge options\n const defaults = this.registry.getDefaults();\n const mergedOptions: Required<Omit<IconOptions, \"class\">> & Pick<IconOptions, \"class\"> = {\n size: options?.size ?? defaults.size,\n color: options?.color ?? defaults.color,\n ...(options?.class !== undefined ? { class: options.class } : {}),\n };\n\n // Render based on source type\n switch (source.type) {\n case \"web-font\":\n return this.renderWebFont(source, parsed.name, mergedOptions);\n case \"local-svg\":\n return await this.renderLocalSvg(source, parsed.name, mergedOptions);\n case \"svg-inline\":\n return await this.renderSvgInline(source, parsed.name, mergedOptions);\n case \"svg-sprite\":\n return this.renderSvgSprite(source, parsed.name, mergedOptions);\n default:\n throw new Error(`Unsupported icon source type: \"${source.type}\"`);\n }\n }\n\n /**\n * Render a web-font icon\n */\n private renderWebFont(\n source: IconSource,\n name: string,\n options: IconOptions\n ): string {\n const style = this.buildStyle(options);\n const className = this.buildClassName(name, options);\n\n if (source.render) {\n // Use custom render template\n return this.nunjucksEnv.renderString(source.render, {\n name,\n style,\n class: className,\n size: options.size,\n color: options.color,\n });\n }\n\n // Default web-font render\n return `<span class=\"${className}\" style=\"${style}\">${name}</span>`;\n }\n\n /**\n * Render a local SVG icon\n */\n private async renderLocalSvg(\n source: IconSource,\n name: string,\n options: IconOptions\n ): Promise<string> {\n if (!source.path) {\n throw new Error(`Local SVG source \"${source.name}\" has no path defined`);\n }\n\n const svgPath = path.join(source.path, `${name}.svg`);\n\n try {\n const svgContent = await fs.readFile(svgPath, \"utf-8\");\n return this.processSvg(svgContent, name, options);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new Error(`Icon file not found: ${svgPath}`);\n }\n throw error;\n }\n }\n\n /**\n * Render an SVG from external URL (placeholder without cache)\n */\n private async renderSvgInline(\n source: IconSource,\n name: string,\n options: IconOptions\n ): Promise<string> {\n // Without cache implementation, return a placeholder\n // Cache will be integrated in Step 4\n const className = this.buildClassName(name, options);\n const style = this.buildStyle(options);\n\n return `<span class=\"${className}\" style=\"${style}\" data-icon-source=\"${source.name}\" data-icon-name=\"${name}\">[${name}]</span>`;\n }\n\n /**\n * Render an SVG sprite reference\n */\n private renderSvgSprite(\n source: IconSource,\n name: string,\n options: IconOptions\n ): string {\n const className = this.buildClassName(name, options);\n const size = options.size ?? \"24px\";\n const color = options.color ?? \"currentColor\";\n\n const spriteUrl = source.url ?? \"\";\n\n return `<svg class=\"${className}\" width=\"${size}\" height=\"${size}\" fill=\"${color}\">\n <use xlink:href=\"${spriteUrl}#${name}\"/>\n</svg>`;\n }\n\n /**\n * Process SVG content and apply options\n */\n private processSvg(\n svgContent: string,\n name: string,\n options: IconOptions\n ): string {\n const className = this.buildClassName(name, options);\n const size = options.size ?? \"24px\";\n const color = options.color ?? \"currentColor\";\n\n // Parse and modify SVG attributes\n let processed = svgContent.trim();\n\n // Add/replace class attribute\n if (processed.includes(\"class=\")) {\n processed = processed.replace(/class=\"[^\"]*\"/, `class=\"${className}\"`);\n } else {\n processed = processed.replace(\"<svg\", `<svg class=\"${className}\"`);\n }\n\n // Add/replace width and height\n if (processed.includes(\"width=\")) {\n processed = processed.replace(/width=\"[^\"]*\"/, `width=\"${size}\"`);\n } else {\n processed = processed.replace(\"<svg\", `<svg width=\"${size}\"`);\n }\n\n if (processed.includes(\"height=\")) {\n processed = processed.replace(/height=\"[^\"]*\"/, `height=\"${size}\"`);\n } else {\n processed = processed.replace(\"<svg\", `<svg height=\"${size}\"`);\n }\n\n // Replace fill=\"currentColor\" with actual color\n if (color !== \"currentColor\") {\n processed = processed.replace(/fill=\"currentColor\"/g, `fill=\"${color}\"`);\n }\n\n return processed;\n }\n\n /**\n * Build CSS style string\n */\n private buildStyle(options: IconOptions): string {\n const styles: string[] = [];\n\n if (options.size) {\n styles.push(`font-size: ${options.size}`);\n }\n\n if (options.color) {\n styles.push(`color: ${options.color}`);\n }\n\n return styles.join(\"; \");\n }\n\n /**\n * Build class name string\n */\n private buildClassName(name: string, options: IconOptions): string {\n const classes = [\"icon\", `icon-${name}`];\n\n if (options.class) {\n classes.push(options.class);\n }\n\n return classes.join(\" \");\n }\n}\n","import { exec } from 'child_process';\n\nexport interface CSLAuthor {\n family: string;\n given?: string;\n}\n\nexport interface CSLItem {\n id: string;\n author?: CSLAuthor[];\n issued?: { 'date-parts': number[][] };\n title?: string;\n DOI?: string;\n PMID?: string;\n 'container-title'?: string;\n volume?: string;\n issue?: string;\n page?: string;\n URL?: string;\n type?: string;\n}\n\nexport class ReferenceManagerError extends Error {\n constructor(\n message: string,\n public cause?: unknown\n ) {\n super(message);\n this.name = 'ReferenceManagerError';\n }\n}\n\n/**\n * Client for reference-manager CLI\n */\nexport class ReferenceManager {\n constructor(private command: string = 'ref') {}\n\n /**\n * Check if reference-manager CLI is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n await this.execCommand(`${this.command} --version`);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get all references from the library\n */\n async getAll(): Promise<CSLItem[]> {\n const result = await this.execCommand(`${this.command} list --format json`);\n return this.parseJSON(result);\n }\n\n /**\n * Get a single reference by ID\n */\n async getById(id: string): Promise<CSLItem | null> {\n const result = await this.execCommand(\n `${this.command} list --id ${id} --format json`\n );\n const items = this.parseJSON(result);\n return items[0] || null;\n }\n\n /**\n * Get multiple references by IDs\n */\n async getByIds(ids: string[]): Promise<Map<string, CSLItem>> {\n if (ids.length === 0) {\n return new Map();\n }\n\n const result = await this.execCommand(`${this.command} list --format json`);\n const allItems = this.parseJSON(result);\n\n const idSet = new Set(ids);\n const map = new Map<string, CSLItem>();\n\n for (const item of allItems) {\n if (idSet.has(item.id)) {\n map.set(item.id, item);\n }\n }\n\n return map;\n }\n\n private execCommand(cmd: string): Promise<string> {\n return new Promise((resolve, reject) => {\n exec(cmd, (error, stdout) => {\n if (error) {\n reject(\n new ReferenceManagerError(`Failed to execute: ${cmd}`, error)\n );\n return;\n }\n resolve(stdout.toString());\n });\n });\n }\n\n private parseJSON(data: string): CSLItem[] {\n try {\n return JSON.parse(data) as CSLItem[];\n } catch (error) {\n throw new ReferenceManagerError(\n 'Failed to parse reference-manager output as JSON',\n error\n );\n }\n }\n}\n","import type { ParsedSlide, ParsedPresentation } from '../core/parser';\n\nexport interface ExtractedCitation {\n id: string;\n locator?: string | undefined;\n position: { start: number; end: number };\n}\n\n// Pattern to match citations like [@id], [@id, p.42], [@id1; @id2]\n// Matches: [@word-chars] or [@word-chars, locator]\nconst SINGLE_CITATION_PATTERN = /@([\\w-]+)(?:,\\s*([^;\\]]+))?/g;\nconst CITATION_BRACKET_PATTERN = /\\[(@[\\w-]+(?:,\\s*[^;\\]]+)?(?:;\\s*@[\\w-]+(?:,\\s*[^;\\]]+)?)*)\\]/g;\n\n// Pattern to extract @id from source field in structured citations\nconst SOURCE_CITATION_PATTERN = /^@([\\w-]+)$/;\n\nexport class CitationExtractor {\n /**\n * Extract citations from a text string\n */\n extract(text: string): ExtractedCitation[] {\n const citations: ExtractedCitation[] = [];\n\n // Find all bracketed citation groups\n let bracketMatch: RegExpExecArray | null;\n CITATION_BRACKET_PATTERN.lastIndex = 0;\n\n while ((bracketMatch = CITATION_BRACKET_PATTERN.exec(text)) !== null) {\n const bracketStart = bracketMatch.index;\n const bracketContent = bracketMatch[1];\n\n // Parse individual citations within the bracket\n SINGLE_CITATION_PATTERN.lastIndex = 0;\n let singleMatch: RegExpExecArray | null;\n\n while ((singleMatch = SINGLE_CITATION_PATTERN.exec(bracketContent!)) !== null) {\n const id = singleMatch[1]!;\n const locator = singleMatch[2]?.trim();\n\n citations.push({\n id,\n locator: locator ?? undefined,\n position: {\n start: bracketStart,\n end: bracketStart + bracketMatch[0].length,\n },\n });\n }\n }\n\n return citations;\n }\n\n /**\n * Extract citations from a slide's content\n */\n extractFromSlide(slide: ParsedSlide): ExtractedCitation[] {\n const allCitations: ExtractedCitation[] = [];\n const seenIds = new Set<string>();\n\n // Extract from content recursively\n const extractFromValue = (value: unknown): void => {\n if (typeof value === 'string') {\n // Check for structured source citation (e.g., source: \"@smith2024\")\n const sourceMatch = SOURCE_CITATION_PATTERN.exec(value);\n if (sourceMatch && sourceMatch[1]) {\n const id = sourceMatch[1];\n if (!seenIds.has(id)) {\n seenIds.add(id);\n allCitations.push({\n id,\n locator: undefined,\n position: { start: 0, end: value.length },\n });\n }\n return;\n }\n\n // Regular citation extraction\n const citations = this.extract(value);\n for (const citation of citations) {\n if (!seenIds.has(citation.id)) {\n seenIds.add(citation.id);\n allCitations.push(citation);\n }\n }\n } else if (Array.isArray(value)) {\n for (const item of value) {\n extractFromValue(item);\n }\n } else if (value && typeof value === 'object') {\n for (const v of Object.values(value)) {\n extractFromValue(v);\n }\n }\n };\n\n // Extract from content\n extractFromValue(slide.content);\n\n // Extract from notes if present\n if (slide.notes) {\n const notesCitations = this.extract(slide.notes);\n for (const citation of notesCitations) {\n if (!seenIds.has(citation.id)) {\n seenIds.add(citation.id);\n allCitations.push(citation);\n }\n }\n }\n\n return allCitations;\n }\n\n /**\n * Extract citations from all slides in a presentation\n */\n extractFromPresentation(presentation: ParsedPresentation): ExtractedCitation[] {\n const allCitations: ExtractedCitation[] = [];\n const seenIds = new Set<string>();\n\n for (const slide of presentation.slides) {\n const slideCitations = this.extractFromSlide(slide);\n for (const citation of slideCitations) {\n if (!seenIds.has(citation.id)) {\n seenIds.add(citation.id);\n allCitations.push(citation);\n }\n }\n }\n\n return allCitations;\n }\n\n /**\n * Get unique citation IDs in order of first appearance\n */\n getUniqueIds(citations: ExtractedCitation[]): string[] {\n const seen = new Set<string>();\n const uniqueIds: string[] = [];\n\n for (const citation of citations) {\n if (!seen.has(citation.id)) {\n seen.add(citation.id);\n uniqueIds.push(citation.id);\n }\n }\n\n return uniqueIds;\n }\n}\n","import type { ReferenceManager, CSLItem, CSLAuthor } from './manager';\n\nexport interface FormatterConfig {\n author?: {\n maxAuthors?: number;\n etAl?: string;\n etAlJa?: string;\n separatorJa?: string;\n };\n inline?: {\n authorSep?: string;\n identifierSep?: string;\n multiSep?: string;\n };\n}\n\nconst DEFAULT_CONFIG: Required<FormatterConfig> = {\n author: {\n maxAuthors: 2,\n etAl: 'et al.',\n etAlJa: 'ほか',\n separatorJa: '・',\n },\n inline: {\n authorSep: ', ',\n identifierSep: '; ',\n multiSep: '), (',\n },\n};\n\n// Pattern to detect Japanese characters\nconst JAPANESE_PATTERN = /[\\u3040-\\u309F\\u30A0-\\u30FF\\u4E00-\\u9FAF]/;\n\n// Citation patterns for expansion\nconst CITATION_BRACKET_PATTERN =\n /\\[(@[\\w-]+(?:,\\s*[^;\\]]+)?(?:;\\s*@[\\w-]+(?:,\\s*[^;\\]]+)?)*)\\]/g;\nconst SINGLE_CITATION_PATTERN = /@([\\w-]+)(?:,\\s*([^;\\]]+))?/g;\n\n/**\n * Formats citations for inline display and bibliography generation\n */\nexport class CitationFormatter {\n private config: Required<FormatterConfig>;\n\n constructor(\n private manager: ReferenceManager,\n config?: FormatterConfig\n ) {\n this.config = {\n author: { ...DEFAULT_CONFIG.author, ...config?.author },\n inline: { ...DEFAULT_CONFIG.inline, ...config?.inline },\n };\n }\n\n /**\n * Format an inline citation\n * e.g., \"(Smith et al., 2024; PMID: 12345678)\"\n */\n async formatInline(id: string): Promise<string> {\n const item = await this.manager.getById(id);\n if (!item) {\n return `[${id}]`;\n }\n\n return this.formatInlineItem(item);\n }\n\n /**\n * Format a full bibliography citation\n */\n async formatFull(id: string): Promise<string> {\n const item = await this.manager.getById(id);\n if (!item) {\n return `[${id}]`;\n }\n\n return this.formatFullItem(item);\n }\n\n /**\n * Expand all citations in text\n * e.g., \"[@smith2024]\" -> \"(Smith et al., 2024; PMID: 12345678)\"\n */\n async expandCitations(text: string): Promise<string> {\n // First, collect all citation IDs\n const ids = new Set<string>();\n CITATION_BRACKET_PATTERN.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = CITATION_BRACKET_PATTERN.exec(text)) !== null) {\n const content = match[1];\n SINGLE_CITATION_PATTERN.lastIndex = 0;\n\n let singleMatch: RegExpExecArray | null;\n while ((singleMatch = SINGLE_CITATION_PATTERN.exec(content!)) !== null) {\n ids.add(singleMatch[1]!);\n }\n }\n\n // Fetch all items at once\n const items = await this.manager.getByIds([...ids]);\n\n // Replace citations\n CITATION_BRACKET_PATTERN.lastIndex = 0;\n let result = text;\n\n // Reset and iterate again for replacement\n const matches: Array<{\n start: number;\n end: number;\n replacement: string;\n }> = [];\n\n CITATION_BRACKET_PATTERN.lastIndex = 0;\n while ((match = CITATION_BRACKET_PATTERN.exec(text)) !== null) {\n const content = match[1];\n const replacements: string[] = [];\n\n SINGLE_CITATION_PATTERN.lastIndex = 0;\n let singleMatch: RegExpExecArray | null;\n while ((singleMatch = SINGLE_CITATION_PATTERN.exec(content!)) !== null) {\n const id = singleMatch[1]!;\n const item = items.get(id);\n if (item) {\n replacements.push(this.formatInlineItem(item));\n } else {\n replacements.push(`[${id}]`);\n }\n }\n\n matches.push({\n start: match.index,\n end: match.index + match[0].length,\n replacement: replacements.join(', '),\n });\n }\n\n // Apply replacements from end to start to maintain positions\n for (const m of [...matches].reverse()) {\n result = result.slice(0, m.start) + m.replacement + result.slice(m.end);\n }\n\n return result;\n }\n\n /**\n * Generate bibliography entries\n */\n async generateBibliography(\n ids: string[],\n sort: 'author' | 'year' | 'citation-order' = 'citation-order'\n ): Promise<string[]> {\n if (ids.length === 0) {\n return [];\n }\n\n const items = await this.manager.getByIds(ids);\n let sortedItems: CSLItem[];\n\n if (sort === 'citation-order') {\n // Keep order of ids, filtering out non-existent\n sortedItems = ids\n .map((id) => items.get(id))\n .filter((item): item is CSLItem => item !== undefined);\n } else if (sort === 'author') {\n sortedItems = [...items.values()].sort((a, b) => {\n const authorA = this.getFirstAuthorFamily(a);\n const authorB = this.getFirstAuthorFamily(b);\n return authorA.localeCompare(authorB);\n });\n } else {\n // sort by year\n sortedItems = [...items.values()].sort((a, b) => {\n const yearA = this.getYear(a);\n const yearB = this.getYear(b);\n return yearA - yearB;\n });\n }\n\n return sortedItems.map((item) => this.formatFullItem(item));\n }\n\n private formatInlineItem(item: CSLItem): string {\n const author = this.formatAuthorInline(item.author);\n const year = this.getYear(item);\n const identifier = this.getIdentifier(item);\n\n if (identifier) {\n return `(${author}, ${year}; ${identifier})`;\n }\n return `(${author}, ${year})`;\n }\n\n private formatFullItem(item: CSLItem): string {\n const parts: string[] = [];\n\n // Authors\n const isJapanese = this.isJapaneseAuthors(item.author);\n const authors = this.formatAuthorsFull(item.author, isJapanese);\n parts.push(authors);\n\n // Year\n const year = this.getYear(item);\n parts.push(`(${year}).`);\n\n // Title\n if (item.title) {\n parts.push(`${item.title}.`);\n }\n\n // Container (journal)\n if (item['container-title']) {\n const journal = isJapanese\n ? item['container-title']\n : `*${item['container-title']}*`;\n\n // Volume, issue, pages\n let location = '';\n if (item.volume) {\n location = item.issue\n ? `${item.volume}(${item.issue})`\n : item.volume;\n }\n if (item.page) {\n location = location ? `${location}, ${item.page}` : item.page;\n }\n\n parts.push(location ? `${journal}, ${location}.` : `${journal}.`);\n }\n\n // Identifier\n const identifier = this.getIdentifier(item);\n if (identifier) {\n parts.push(identifier);\n }\n\n return parts.join(' ');\n }\n\n private formatAuthorInline(authors: CSLAuthor[] | undefined): string {\n if (!authors || authors.length === 0) {\n return 'Unknown';\n }\n\n const isJapanese = this.isJapaneseAuthors(authors);\n const { etAl, etAlJa, separatorJa } = this.config.author;\n const firstAuthor = authors[0]!;\n\n if (authors.length === 1) {\n return firstAuthor.family;\n }\n\n if (authors.length === 2) {\n const separator = isJapanese ? separatorJa : ' & ';\n return `${firstAuthor.family}${separator}${authors[1]!.family}`;\n }\n\n // 3+ authors\n const suffix = isJapanese ? etAlJa : ` ${etAl}`;\n return `${firstAuthor.family}${suffix}`;\n }\n\n private formatAuthorsFull(\n authors: CSLAuthor[] | undefined,\n isJapanese: boolean\n ): string {\n if (!authors || authors.length === 0) {\n return 'Unknown';\n }\n\n if (isJapanese) {\n // Japanese: 田中太郎, 山田花子\n return authors.map((a) => `${a.family}${a.given || ''}`).join(', ');\n }\n\n // English: Smith, J., Johnson, A., & Williams, B.\n if (authors.length === 1) {\n const a = authors[0]!;\n const initial = a.given ? `${a.given.charAt(0)}.` : '';\n return `${a.family}, ${initial}`;\n }\n\n const formatted = authors.map((a, i) => {\n const initial = a.given ? `${a.given.charAt(0)}.` : '';\n if (i === authors.length - 1) {\n return `& ${a.family}, ${initial}`;\n }\n return `${a.family}, ${initial}`;\n });\n\n // Join with \", \" for 3+ authors, or \", \" for 2 authors\n return formatted.join(', ').replace(', &', ', &');\n }\n\n private isJapaneseAuthors(authors: CSLAuthor[] | undefined): boolean {\n if (!authors || authors.length === 0) {\n return false;\n }\n // Check first author's family name for Japanese characters\n return JAPANESE_PATTERN.test(authors[0]!.family);\n }\n\n private getFirstAuthorFamily(item: CSLItem): string {\n return item.author?.[0]?.family || '';\n }\n\n private getYear(item: CSLItem): number {\n const dateParts = item.issued?.['date-parts'];\n if (dateParts && dateParts[0] && dateParts[0][0]) {\n return dateParts[0][0];\n }\n return 0;\n }\n\n private getIdentifier(item: CSLItem): string | null {\n if (item.PMID) {\n return `PMID: ${item.PMID}`;\n }\n if (item.DOI) {\n return `DOI: ${item.DOI}`;\n }\n return null;\n }\n}\n","/**\n * slide-generation - A CLI tool to generate Marp-compatible Markdown from YAML source files\n */\n\nexport const VERSION = \"0.1.0\";\n\n// Core modules\nexport * from './core';\n// export * from './core/transformer';\n// export * from './core/renderer';\n// export * from './core/pipeline';\n\n// Template system\nexport * from './templates';\n"],"mappings":"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","names":["z","z","path","z","fs","parseYaml","z","parseYaml","fs","path","nunjucks","CITATION_BRACKET_PATTERN","SINGLE_CITATION_PATTERN"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Icon Registry Configuration
|
|
2
|
+
# This file defines icon sources, aliases, and defaults for the slide generation system.
|
|
3
|
+
|
|
4
|
+
# Icon source definitions
|
|
5
|
+
sources:
|
|
6
|
+
# Material Icons (Web Font)
|
|
7
|
+
- name: material-icons
|
|
8
|
+
type: web-font
|
|
9
|
+
prefix: mi
|
|
10
|
+
url: "https://fonts.googleapis.com/icon?family=Material+Icons"
|
|
11
|
+
render: '<span class="material-icons" style="{{ style }}">{{ name }}</span>'
|
|
12
|
+
|
|
13
|
+
# Heroicons (SVG CDN)
|
|
14
|
+
- name: heroicons
|
|
15
|
+
type: svg-inline
|
|
16
|
+
prefix: hero
|
|
17
|
+
url: "https://unpkg.com/heroicons@2.0.0/24/outline/{name}.svg"
|
|
18
|
+
|
|
19
|
+
# Iconify (Universal SVG CDN)
|
|
20
|
+
- name: iconify
|
|
21
|
+
type: svg-inline
|
|
22
|
+
prefix: iconify
|
|
23
|
+
url: "https://api.iconify.design/{set}/{name}.svg"
|
|
24
|
+
|
|
25
|
+
# Custom local SVG icons
|
|
26
|
+
- name: custom
|
|
27
|
+
type: local-svg
|
|
28
|
+
prefix: custom
|
|
29
|
+
path: "./icons/custom/"
|
|
30
|
+
|
|
31
|
+
# Semantic aliases - map meaningful names to actual icons
|
|
32
|
+
aliases:
|
|
33
|
+
# Actions
|
|
34
|
+
planning: "mi:event_note"
|
|
35
|
+
action: "mi:play_arrow"
|
|
36
|
+
analysis: "mi:analytics"
|
|
37
|
+
improvement: "mi:trending_up"
|
|
38
|
+
|
|
39
|
+
# Status
|
|
40
|
+
success: "mi:check_circle"
|
|
41
|
+
warning: "mi:warning"
|
|
42
|
+
error: "mi:error"
|
|
43
|
+
info: "mi:info"
|
|
44
|
+
|
|
45
|
+
# Objects
|
|
46
|
+
document: "mi:description"
|
|
47
|
+
folder: "mi:folder"
|
|
48
|
+
database: "mi:storage"
|
|
49
|
+
settings: "mi:settings"
|
|
50
|
+
|
|
51
|
+
# Navigation
|
|
52
|
+
home: "mi:home"
|
|
53
|
+
back: "mi:arrow_back"
|
|
54
|
+
forward: "mi:arrow_forward"
|
|
55
|
+
up: "mi:arrow_upward"
|
|
56
|
+
down: "mi:arrow_downward"
|
|
57
|
+
|
|
58
|
+
# Communication
|
|
59
|
+
email: "mi:email"
|
|
60
|
+
phone: "mi:phone"
|
|
61
|
+
chat: "mi:chat"
|
|
62
|
+
notification: "mi:notifications"
|
|
63
|
+
|
|
64
|
+
# Color palette for icons
|
|
65
|
+
colors:
|
|
66
|
+
primary: "#1976D2"
|
|
67
|
+
secondary: "#424242"
|
|
68
|
+
accent: "#FF4081"
|
|
69
|
+
success: "#4CAF50"
|
|
70
|
+
warning: "#FF9800"
|
|
71
|
+
danger: "#F44336"
|
|
72
|
+
info: "#2196F3"
|
|
73
|
+
|
|
74
|
+
# Default icon settings
|
|
75
|
+
defaults:
|
|
76
|
+
size: "24px"
|
|
77
|
+
color: "currentColor"
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ncukondo/slide-generation",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A CLI tool to generate Marp-compatible Markdown from YAML source files",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"slide-gen": "./dist/cli/index.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"templates",
|
|
20
|
+
"themes",
|
|
21
|
+
"icons",
|
|
22
|
+
"README.md",
|
|
23
|
+
"README_ja.md",
|
|
24
|
+
"CHANGELOG.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"lint": "oxlint",
|
|
34
|
+
"format": "oxfmt write src",
|
|
35
|
+
"format:check": "oxfmt check src",
|
|
36
|
+
"prepublishOnly": "pnpm build && pnpm test && pnpm lint && pnpm typecheck"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"marp",
|
|
40
|
+
"slides",
|
|
41
|
+
"markdown",
|
|
42
|
+
"yaml",
|
|
43
|
+
"presentation",
|
|
44
|
+
"cli",
|
|
45
|
+
"slide-generation",
|
|
46
|
+
"template"
|
|
47
|
+
],
|
|
48
|
+
"author": "ncukondo",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/ncukondo/slide-generation.git"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/ncukondo/slide-generation/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/ncukondo/slide-generation#readme",
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=22.0.0"
|
|
63
|
+
},
|
|
64
|
+
"packageManager": "pnpm@9.15.4",
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"chalk": "^5.4.1",
|
|
67
|
+
"chokidar": "^4.0.3",
|
|
68
|
+
"commander": "^13.1.0",
|
|
69
|
+
"globby": "^14.0.2",
|
|
70
|
+
"nunjucks": "^3.2.4",
|
|
71
|
+
"ora": "^8.1.1",
|
|
72
|
+
"yaml": "^2.7.0",
|
|
73
|
+
"zod": "^3.24.1"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/node": "^22.10.7",
|
|
77
|
+
"@types/nunjucks": "^3.2.6",
|
|
78
|
+
"oxfmt": "^0.23.0",
|
|
79
|
+
"oxlint": "^0.16.6",
|
|
80
|
+
"tsup": "^8.3.5",
|
|
81
|
+
"typescript": "^5.7.3",
|
|
82
|
+
"vitest": "^3.0.4"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: bullet-list
|
|
2
|
+
description: "箇条書きリスト"
|
|
3
|
+
category: basic
|
|
4
|
+
|
|
5
|
+
schema:
|
|
6
|
+
type: object
|
|
7
|
+
required:
|
|
8
|
+
- title
|
|
9
|
+
- items
|
|
10
|
+
properties:
|
|
11
|
+
title:
|
|
12
|
+
type: string
|
|
13
|
+
description: "スライドタイトル"
|
|
14
|
+
items:
|
|
15
|
+
type: array
|
|
16
|
+
description: "リスト項目(文字列またはネスト構造)"
|
|
17
|
+
|
|
18
|
+
example:
|
|
19
|
+
title: "主なポイント"
|
|
20
|
+
items:
|
|
21
|
+
- "項目1"
|
|
22
|
+
- "項目2"
|
|
23
|
+
- "項目3"
|
|
24
|
+
|
|
25
|
+
output: |
|
|
26
|
+
# {{ content.title }}
|
|
27
|
+
|
|
28
|
+
{% macro indent(n) %}{% for i in range(n) %} {% endfor %}{% endmacro %}
|
|
29
|
+
{% macro renderItems(items, depth) %}
|
|
30
|
+
{% for item in items %}
|
|
31
|
+
{% if item is string %}
|
|
32
|
+
{{ indent(depth) }}- {{ refs.expand(item) }}
|
|
33
|
+
{% elif item.nested %}
|
|
34
|
+
{{ indent(depth) }}- {{ item.nested.title }}
|
|
35
|
+
{{ renderItems(item.nested.items, depth + 1) }}
|
|
36
|
+
{% endif %}
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endmacro %}
|
|
39
|
+
{{ renderItems(content.items, 0) }}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: numbered-list
|
|
2
|
+
description: "番号付きリスト"
|
|
3
|
+
category: basic
|
|
4
|
+
|
|
5
|
+
schema:
|
|
6
|
+
type: object
|
|
7
|
+
required:
|
|
8
|
+
- title
|
|
9
|
+
- items
|
|
10
|
+
properties:
|
|
11
|
+
title:
|
|
12
|
+
type: string
|
|
13
|
+
description: "スライドタイトル"
|
|
14
|
+
items:
|
|
15
|
+
type: array
|
|
16
|
+
description: "リスト項目(文字列またはネスト構造)"
|
|
17
|
+
|
|
18
|
+
example:
|
|
19
|
+
title: "手順"
|
|
20
|
+
items:
|
|
21
|
+
- "最初のステップ"
|
|
22
|
+
- "次のステップ"
|
|
23
|
+
- "最後のステップ"
|
|
24
|
+
|
|
25
|
+
output: |
|
|
26
|
+
# {{ content.title }}
|
|
27
|
+
|
|
28
|
+
{% macro indent(n) %}{% for i in range(n) %} {% endfor %}{% endmacro %}
|
|
29
|
+
{% macro renderItems(items, depth) %}
|
|
30
|
+
{% for item in items %}
|
|
31
|
+
{% if item is string %}
|
|
32
|
+
{{ indent(depth) }}{{ loop.index }}. {{ refs.expand(item) }}
|
|
33
|
+
{% elif item.nested %}
|
|
34
|
+
{{ indent(depth) }}{{ loop.index }}. {{ item.nested.title }}
|
|
35
|
+
{{ renderItems(item.nested.items, depth + 1) }}
|
|
36
|
+
{% endif %}
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endmacro %}
|
|
39
|
+
{{ renderItems(content.items, 0) }}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: section
|
|
2
|
+
description: "セクション区切り"
|
|
3
|
+
category: basic
|
|
4
|
+
|
|
5
|
+
schema:
|
|
6
|
+
type: object
|
|
7
|
+
required:
|
|
8
|
+
- title
|
|
9
|
+
properties:
|
|
10
|
+
title:
|
|
11
|
+
type: string
|
|
12
|
+
description: "セクションタイトル"
|
|
13
|
+
subtitle:
|
|
14
|
+
type: string
|
|
15
|
+
description: "サブタイトル(オプション)"
|
|
16
|
+
|
|
17
|
+
example:
|
|
18
|
+
title: "第1章"
|
|
19
|
+
subtitle: "はじめに"
|
|
20
|
+
|
|
21
|
+
output: |
|
|
22
|
+
<!-- _class: section -->
|
|
23
|
+
|
|
24
|
+
# {{ content.title }}
|
|
25
|
+
|
|
26
|
+
{% if content.subtitle %}{{ content.subtitle }}{% endif %}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: title
|
|
2
|
+
description: "タイトルスライド"
|
|
3
|
+
category: basic
|
|
4
|
+
|
|
5
|
+
schema:
|
|
6
|
+
type: object
|
|
7
|
+
required:
|
|
8
|
+
- title
|
|
9
|
+
properties:
|
|
10
|
+
title:
|
|
11
|
+
type: string
|
|
12
|
+
description: "メインタイトル"
|
|
13
|
+
subtitle:
|
|
14
|
+
type: string
|
|
15
|
+
description: "サブタイトル"
|
|
16
|
+
author:
|
|
17
|
+
type: string
|
|
18
|
+
description: "著者名"
|
|
19
|
+
date:
|
|
20
|
+
type: string
|
|
21
|
+
description: "日付"
|
|
22
|
+
affiliation:
|
|
23
|
+
type: string
|
|
24
|
+
description: "所属"
|
|
25
|
+
|
|
26
|
+
example:
|
|
27
|
+
title: "プレゼンテーションタイトル"
|
|
28
|
+
subtitle: "サブタイトル"
|
|
29
|
+
author: "著者名"
|
|
30
|
+
date: "2024-01-15"
|
|
31
|
+
affiliation: "所属組織"
|
|
32
|
+
|
|
33
|
+
output: |
|
|
34
|
+
<!-- _class: title -->
|
|
35
|
+
|
|
36
|
+
# {{ content.title }}
|
|
37
|
+
|
|
38
|
+
{% if content.subtitle %}## {{ content.subtitle }}{% endif %}
|
|
39
|
+
|
|
40
|
+
{% if content.author or content.affiliation or content.date %}
|
|
41
|
+
<div class="title-meta">
|
|
42
|
+
{% if content.author %}<span class="author">{{ content.author }}</span>{% endif %}
|
|
43
|
+
{% if content.affiliation %}<span class="affiliation">{{ content.affiliation }}</span>{% endif %}
|
|
44
|
+
{% if content.date %}<span class="date">{{ content.date }}</span>{% endif %}
|
|
45
|
+
</div>
|
|
46
|
+
{% endif %}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
name: comparison-table
|
|
2
|
+
description: "比較表(強調付き)"
|
|
3
|
+
category: data
|
|
4
|
+
|
|
5
|
+
schema:
|
|
6
|
+
type: object
|
|
7
|
+
required:
|
|
8
|
+
- title
|
|
9
|
+
- items
|
|
10
|
+
- criteria
|
|
11
|
+
properties:
|
|
12
|
+
title:
|
|
13
|
+
type: string
|
|
14
|
+
description: "スライドタイトル"
|
|
15
|
+
items:
|
|
16
|
+
type: array
|
|
17
|
+
minItems: 2
|
|
18
|
+
description: "比較対象の項目(2つ以上)"
|
|
19
|
+
items:
|
|
20
|
+
type: string
|
|
21
|
+
highlightColumn:
|
|
22
|
+
type: integer
|
|
23
|
+
description: "強調する列のインデックス(0始まり)"
|
|
24
|
+
criteria:
|
|
25
|
+
type: array
|
|
26
|
+
minItems: 1
|
|
27
|
+
description: "比較基準"
|
|
28
|
+
items:
|
|
29
|
+
type: object
|
|
30
|
+
required:
|
|
31
|
+
- label
|
|
32
|
+
- values
|
|
33
|
+
properties:
|
|
34
|
+
label:
|
|
35
|
+
type: string
|
|
36
|
+
description: "基準のラベル"
|
|
37
|
+
description:
|
|
38
|
+
type: string
|
|
39
|
+
description: "基準の説明(オプション)"
|
|
40
|
+
values:
|
|
41
|
+
type: array
|
|
42
|
+
description: "各項目に対する値"
|
|
43
|
+
items:
|
|
44
|
+
type: string
|
|
45
|
+
|
|
46
|
+
example:
|
|
47
|
+
title: "プラン比較"
|
|
48
|
+
items: ["Free", "Pro", "Enterprise"]
|
|
49
|
+
highlightColumn: 1
|
|
50
|
+
criteria:
|
|
51
|
+
- label: "ストレージ"
|
|
52
|
+
values: ["5GB", "100GB", "無制限"]
|
|
53
|
+
- label: "サポート"
|
|
54
|
+
description: "カスタマーサポートの種類"
|
|
55
|
+
values: ["メール", "24時間チャット", "専属担当"]
|
|
56
|
+
- label: "API"
|
|
57
|
+
values: ["no", "yes", "yes"]
|
|
58
|
+
- label: "カスタムドメイン"
|
|
59
|
+
values: ["no", "partial", "yes"]
|
|
60
|
+
|
|
61
|
+
output: |
|
|
62
|
+
<!-- _class: data-slide comparison-slide -->
|
|
63
|
+
|
|
64
|
+
# {{ content.title }}
|
|
65
|
+
|
|
66
|
+
{% macro escape_pipe(text) %}{{ text | replace("|", "\\|") }}{% endmacro %}
|
|
67
|
+
{% macro eval_mark(value) %}{% if value == 'yes' or value == 'YES' or value == 'true' %}✓{% elif value == 'no' or value == 'NO' or value == 'false' %}✗{% elif value == 'partial' or value == 'PARTIAL' %}△{% else %}{{ value }}{% endif %}{% endmacro %}
|
|
68
|
+
{% macro highlight_class(index) %}{% if content.highlightColumn is defined and content.highlightColumn == index %} **{% endif %}{% endmacro %}
|
|
69
|
+
{% macro highlight_end(index) %}{% if content.highlightColumn is defined and content.highlightColumn == index %}** {% endif %}{% endmacro %}
|
|
70
|
+
<div class="comparison-container">
|
|
71
|
+
|
|
72
|
+
| 比較項目 | {% for item in content.items %}{{ highlight_class(loop.index0) }}{{ escape_pipe(item) }}{{ highlight_end(loop.index0) }} | {% endfor %}
|
|
73
|
+
|
|
74
|
+
| --- |{% for item in content.items %} --- |{% endfor %}
|
|
75
|
+
|
|
76
|
+
{% for criterion in content.criteria %}| **{{ escape_pipe(criterion.label) }}**{% if criterion.description %} <br><small>{{ escape_pipe(criterion.description) }}</small>{% endif %} | {% for value in criterion.values %}{{ highlight_class(loop.index0) }}{{ eval_mark(value) }}{{ highlight_end(loop.index0) }} | {% endfor %}
|
|
77
|
+
|
|
78
|
+
{% endfor %}
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
css: |
|
|
82
|
+
.comparison-slide table {
|
|
83
|
+
width: 100%;
|
|
84
|
+
border-collapse: collapse;
|
|
85
|
+
}
|
|
86
|
+
.comparison-slide th,
|
|
87
|
+
.comparison-slide td {
|
|
88
|
+
border: 1px solid #ddd;
|
|
89
|
+
padding: 0.75em;
|
|
90
|
+
text-align: center;
|
|
91
|
+
}
|
|
92
|
+
.comparison-slide th:first-child,
|
|
93
|
+
.comparison-slide td:first-child {
|
|
94
|
+
text-align: left;
|
|
95
|
+
}
|
|
96
|
+
.comparison-slide thead th {
|
|
97
|
+
background-color: #f5f5f5;
|
|
98
|
+
font-weight: bold;
|
|
99
|
+
}
|
|
100
|
+
.comparison-slide .highlight {
|
|
101
|
+
background-color: #E3F2FD;
|
|
102
|
+
font-weight: bold;
|
|
103
|
+
}
|
|
104
|
+
.comparison-slide small {
|
|
105
|
+
font-size: 0.8em;
|
|
106
|
+
color: #666;
|
|
107
|
+
}
|