@functional-examples/documentation 0.0.0-alpha.1

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.
Files changed (61) hide show
  1. package/dist/commands/generate.d.ts +21 -0
  2. package/dist/commands/generate.d.ts.map +1 -0
  3. package/dist/commands/generate.js +243 -0
  4. package/dist/commands/generate.js.map +1 -0
  5. package/dist/commands/index.d.ts +21 -0
  6. package/dist/commands/index.d.ts.map +1 -0
  7. package/dist/commands/index.js +5 -0
  8. package/dist/commands/index.js.map +1 -0
  9. package/dist/extractor/extractor.d.ts +9 -0
  10. package/dist/extractor/extractor.d.ts.map +1 -0
  11. package/dist/extractor/extractor.js +95 -0
  12. package/dist/extractor/extractor.js.map +1 -0
  13. package/dist/index.d.ts +32 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +46 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/renderers/markdoc.d.ts +13 -0
  18. package/dist/renderers/markdoc.d.ts.map +1 -0
  19. package/dist/renderers/markdoc.js +42 -0
  20. package/dist/renderers/markdoc.js.map +1 -0
  21. package/dist/renderers/markdown.d.ts +6 -0
  22. package/dist/renderers/markdown.d.ts.map +1 -0
  23. package/dist/renderers/markdown.js +12 -0
  24. package/dist/renderers/markdown.js.map +1 -0
  25. package/dist/renderers/types.d.ts +14 -0
  26. package/dist/renderers/types.d.ts.map +1 -0
  27. package/dist/renderers/types.js +2 -0
  28. package/dist/renderers/types.js.map +1 -0
  29. package/dist/schema.d.ts +63 -0
  30. package/dist/schema.d.ts.map +1 -0
  31. package/dist/schema.js +49 -0
  32. package/dist/schema.js.map +1 -0
  33. package/dist/templates/consumption-tracker.d.ts +16 -0
  34. package/dist/templates/consumption-tracker.d.ts.map +1 -0
  35. package/dist/templates/consumption-tracker.js +21 -0
  36. package/dist/templates/consumption-tracker.js.map +1 -0
  37. package/dist/templates/engine.d.ts +123 -0
  38. package/dist/templates/engine.d.ts.map +1 -0
  39. package/dist/templates/engine.js +212 -0
  40. package/dist/templates/engine.js.map +1 -0
  41. package/dist/templates/guide-renderer.d.ts +59 -0
  42. package/dist/templates/guide-renderer.d.ts.map +1 -0
  43. package/dist/templates/guide-renderer.js +93 -0
  44. package/dist/templates/guide-renderer.js.map +1 -0
  45. package/dist/templates/helpers.d.ts +45 -0
  46. package/dist/templates/helpers.d.ts.map +1 -0
  47. package/dist/templates/helpers.js +104 -0
  48. package/dist/templates/helpers.js.map +1 -0
  49. package/dist/templates/prose-helpers.d.ts +26 -0
  50. package/dist/templates/prose-helpers.d.ts.map +1 -0
  51. package/dist/templates/prose-helpers.js +39 -0
  52. package/dist/templates/prose-helpers.js.map +1 -0
  53. package/dist/types.d.ts +48 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +20 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +62 -0
  58. package/templates/@slug.md.template +40 -0
  59. package/templates/@slug.mdoc.template +40 -0
  60. package/templates/index.md.template +9 -0
  61. package/templates/index.mdoc.template +9 -0
@@ -0,0 +1,21 @@
1
+ import type { ResolvedConfig } from '@functional-examples/devkit';
2
+ import type { ResolvedDocumentationPluginOptions } from '../schema.js';
3
+ export declare function createGenerateCommand(config: ResolvedConfig, pluginOpts: ResolvedDocumentationPluginOptions): import("cli-forge").CLI<{
4
+ unmatched: string[];
5
+ '--'?: string[];
6
+ } & {
7
+ output?: string;
8
+ } & {} & {
9
+ format?: string;
10
+ } & {} & {
11
+ templates?: string;
12
+ } & {} & {
13
+ filter?: string;
14
+ } & {} & {
15
+ "dry-run"?: boolean;
16
+ } & {} & {
17
+ clean?: boolean;
18
+ } & {} & {
19
+ check?: boolean;
20
+ } & {}, Promise<void>, {}, undefined>;
21
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAK3E,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,cAAc,CAAC;AA6CvE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,kCAAkC;;;;;;;;;;;;;;;;;sCAiP/C"}
@@ -0,0 +1,243 @@
1
+ import { cli } from 'cli-forge';
2
+ import { scanExamples } from 'functional-examples';
3
+ import * as fs from 'node:fs/promises';
4
+ import * as path from 'node:path';
5
+ import { docsMetadataSchema } from '../schema.js';
6
+ import { loadTemplates, renderIndexTemplate, renderItemTemplate, renderTemplate, } from '../templates/engine.js';
7
+ function shouldSkip(example) {
8
+ const result = docsMetadataSchema.safeParse(example.metadata);
9
+ if (result.success && result.data.docs?.skip) {
10
+ return true;
11
+ }
12
+ return false;
13
+ }
14
+ function getOutputName(example) {
15
+ const result = docsMetadataSchema.safeParse(example.metadata);
16
+ if (result.success) {
17
+ return result.data.docs?.outputName;
18
+ }
19
+ return undefined;
20
+ }
21
+ function getPerExampleTemplate(example) {
22
+ const result = docsMetadataSchema.safeParse(example.metadata);
23
+ if (result.success) {
24
+ return result.data.docs?.template;
25
+ }
26
+ return undefined;
27
+ }
28
+ /** Ensure the parent directory of a file path exists. */
29
+ async function ensureParentDir(filePath) {
30
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
31
+ }
32
+ /** Map CLI format names to template file extensions. */
33
+ const FORMAT_TO_EXT = {
34
+ markdown: '.md',
35
+ mdoc: '.mdoc',
36
+ };
37
+ export function createGenerateCommand(config, pluginOpts) {
38
+ return cli('$0', {
39
+ description: 'Generate documentation from functional examples',
40
+ builder: (cmd) => cmd
41
+ .option('output', {
42
+ type: 'string',
43
+ alias: ['o'],
44
+ description: 'Output directory',
45
+ default: pluginOpts.outputDir,
46
+ })
47
+ .option('format', {
48
+ type: 'string',
49
+ alias: ['f'],
50
+ description: 'Output format: markdown | mdoc',
51
+ default: pluginOpts.format,
52
+ })
53
+ .option('templates', {
54
+ type: 'string',
55
+ alias: ['t'],
56
+ description: 'Path to custom templates directory',
57
+ })
58
+ .option('filter', {
59
+ type: 'string',
60
+ description: 'Filter examples by id pattern',
61
+ })
62
+ .option('dry-run', {
63
+ type: 'boolean',
64
+ description: 'Show what would be generated without writing files',
65
+ default: false,
66
+ })
67
+ .option('clean', {
68
+ type: 'boolean',
69
+ description: 'Remove output directory before generating',
70
+ default: false,
71
+ })
72
+ .option('check', {
73
+ type: 'boolean',
74
+ description: 'Verify generated docs are up-to-date (exit code 1 if stale)',
75
+ default: false,
76
+ }),
77
+ handler: async (args) => {
78
+ const format = (args.format === 'mdoc' ? 'mdoc' : 'markdown');
79
+ const outputDir = path.resolve(args.output);
80
+ const customTemplatesDir = args.templates ?? pluginOpts.templates;
81
+ // Load templates — custom directory or built-in filtered by format
82
+ let templates;
83
+ if (customTemplatesDir) {
84
+ templates = await loadTemplates(path.resolve(customTemplatesDir));
85
+ }
86
+ else {
87
+ const all = await loadTemplates();
88
+ const ext = FORMAT_TO_EXT[format] ?? '.md';
89
+ templates = all.filter((t) => t.format === ext);
90
+ }
91
+ // Scan for examples
92
+ const { examples, errors } = await scanExamples(config);
93
+ if (errors.length) {
94
+ for (const error of errors) {
95
+ console.error(`Error: ${error.message}`);
96
+ }
97
+ process.exit(1);
98
+ }
99
+ // Filter out skipped examples
100
+ let docsExamples = examples.filter((e) => !shouldSkip(e));
101
+ // Apply filter pattern
102
+ if (args.filter) {
103
+ const pattern = args.filter.toLowerCase();
104
+ docsExamples = docsExamples.filter((e) => e.id.toLowerCase().includes(pattern) ||
105
+ e.rootPath.toLowerCase().includes(pattern));
106
+ }
107
+ if (docsExamples.length === 0) {
108
+ console.log('No examples found for documentation generation');
109
+ return;
110
+ }
111
+ // ── --check mode: compare rendered output against existing files ──
112
+ if (args.check) {
113
+ const staleFiles = [];
114
+ for (const template of templates) {
115
+ if (template.perItem) {
116
+ for (const example of docsExamples) {
117
+ const perExampleTemplate = getPerExampleTemplate(example);
118
+ if (perExampleTemplate) {
119
+ // Per-example override: use custom template file directly
120
+ const outputName = getOutputName(example) ?? example.id;
121
+ const ext = template.format;
122
+ const outputFile = path.join(outputDir, `${outputName}${ext}`);
123
+ const rendered = await renderTemplate(example, perExampleTemplate);
124
+ let existing;
125
+ try {
126
+ existing = await fs.readFile(outputFile, 'utf-8');
127
+ }
128
+ catch {
129
+ // file doesn't exist yet
130
+ }
131
+ if (existing !== rendered) {
132
+ staleFiles.push(outputFile);
133
+ }
134
+ }
135
+ else {
136
+ const result = await renderItemTemplate(template, example);
137
+ const outputName = getOutputName(example);
138
+ const relativePath = outputName
139
+ ? `${outputName}${template.format}`
140
+ : result.relativePath;
141
+ const outputFile = path.join(outputDir, relativePath);
142
+ let existing;
143
+ try {
144
+ existing = await fs.readFile(outputFile, 'utf-8');
145
+ }
146
+ catch {
147
+ // file doesn't exist yet
148
+ }
149
+ if (existing !== result.content) {
150
+ staleFiles.push(outputFile);
151
+ }
152
+ }
153
+ }
154
+ }
155
+ else {
156
+ const result = await renderIndexTemplate(template, docsExamples);
157
+ const outputFile = path.join(outputDir, result.relativePath);
158
+ let existing;
159
+ try {
160
+ existing = await fs.readFile(outputFile, 'utf-8');
161
+ }
162
+ catch {
163
+ // file doesn't exist yet
164
+ }
165
+ if (existing !== result.content) {
166
+ staleFiles.push(outputFile);
167
+ }
168
+ }
169
+ }
170
+ if (staleFiles.length > 0) {
171
+ console.error(`Documentation is out of date. ${staleFiles.length} file(s) would change:`);
172
+ for (const f of staleFiles) {
173
+ console.error(` ${f}`);
174
+ }
175
+ process.exit(1);
176
+ }
177
+ console.log('Documentation is up to date.');
178
+ return;
179
+ }
180
+ // ── --dry-run / normal write mode ──
181
+ // Clean output directory if requested
182
+ if (args.clean && !args['dry-run']) {
183
+ await fs.rm(outputDir, { recursive: true, force: true });
184
+ }
185
+ // Ensure output directory exists
186
+ if (!args['dry-run']) {
187
+ await fs.mkdir(outputDir, { recursive: true });
188
+ }
189
+ console.log(`Generating ${format} documentation for ${docsExamples.length} example(s)...`);
190
+ for (const template of templates) {
191
+ if (template.perItem) {
192
+ for (const example of docsExamples) {
193
+ const perExampleTemplate = getPerExampleTemplate(example);
194
+ if (perExampleTemplate) {
195
+ // Per-example template override
196
+ const outputName = getOutputName(example) ?? example.id;
197
+ const ext = template.format;
198
+ const outputFile = path.join(outputDir, `${outputName}${ext}`);
199
+ if (args['dry-run']) {
200
+ console.log(` [dry-run] ${outputFile}`);
201
+ continue;
202
+ }
203
+ const rendered = await renderTemplate(example, perExampleTemplate);
204
+ await ensureParentDir(outputFile);
205
+ await fs.writeFile(outputFile, rendered, 'utf-8');
206
+ console.log(` ${outputFile}`);
207
+ }
208
+ else {
209
+ const result = await renderItemTemplate(template, example);
210
+ const outputName = getOutputName(example);
211
+ const relativePath = outputName
212
+ ? `${outputName}${template.format}`
213
+ : result.relativePath;
214
+ const outputFile = path.join(outputDir, relativePath);
215
+ if (args['dry-run']) {
216
+ console.log(` [dry-run] ${outputFile}`);
217
+ continue;
218
+ }
219
+ await ensureParentDir(outputFile);
220
+ await fs.writeFile(outputFile, result.content, 'utf-8');
221
+ console.log(` ${outputFile}`);
222
+ }
223
+ }
224
+ }
225
+ else {
226
+ const result = await renderIndexTemplate(template, docsExamples);
227
+ const outputFile = path.join(outputDir, result.relativePath);
228
+ if (args['dry-run']) {
229
+ console.log(` [dry-run] ${outputFile}`);
230
+ continue;
231
+ }
232
+ await ensureParentDir(outputFile);
233
+ await fs.writeFile(outputFile, result.content, 'utf-8');
234
+ console.log(` ${outputFile}`);
235
+ }
236
+ }
237
+ if (!args['dry-run']) {
238
+ console.log(`\nDone. ${docsExamples.length} example(s) documented.`);
239
+ }
240
+ },
241
+ });
242
+ }
243
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ResolvedConfig } from '@functional-examples/devkit';
2
+ import type { ResolvedDocumentationPluginOptions } from '../schema.js';
3
+ export declare function createDocumentationCommands(config: ResolvedConfig, pluginOpts: ResolvedDocumentationPluginOptions): import("cli-forge").CLI<{
4
+ unmatched: string[];
5
+ '--'?: string[];
6
+ } & {
7
+ output?: string;
8
+ } & {} & {
9
+ format?: string;
10
+ } & {} & {
11
+ templates?: string;
12
+ } & {} & {
13
+ filter?: string;
14
+ } & {} & {
15
+ "dry-run"?: boolean;
16
+ } & {} & {
17
+ clean?: boolean;
18
+ } & {} & {
19
+ check?: boolean;
20
+ } & {}, Promise<void>, {}, undefined>[];
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,cAAc,CAAC;AAGvE,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,kCAAkC;;;;;;;;;;;;;;;;;wCAG/C"}
@@ -0,0 +1,5 @@
1
+ import { createGenerateCommand } from './generate.js';
2
+ export function createDocumentationCommands(config, pluginOpts) {
3
+ return [createGenerateCommand(config, pluginOpts)];
4
+ }
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,UAAU,2BAA2B,CACzC,MAAsB,EACtB,UAA8C;IAE9C,OAAO,CAAC,qBAAqB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Extractor } from '@functional-examples/devkit';
2
+ /**
3
+ * Create a markdown frontmatter extractor.
4
+ *
5
+ * Scans for .md files with YAML frontmatter containing at least `id` and `title`.
6
+ * Treats each matching file as a single-file example.
7
+ */
8
+ export declare function createMarkdownExtractor(): Extractor;
9
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor/extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EAIV,MAAM,6BAA6B,CAAC;AA+CrC;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,SAAS,CAyEnD"}
@@ -0,0 +1,95 @@
1
+ import { parseYaml } from '@functional-examples/devkit';
2
+ import * as fs from 'node:fs/promises';
3
+ import * as path from 'node:path';
4
+ const EXTRACTOR_NAME = 'markdown-frontmatter-extractor';
5
+ /** Pattern matching YAML frontmatter delimiters. */
6
+ const FRONTMATTER_FENCE = /^---\s*$/;
7
+ /**
8
+ * Parse YAML frontmatter from a Markdown file.
9
+ * Returns null if no valid frontmatter is found.
10
+ */
11
+ async function parseFrontmatter(content) {
12
+ const lines = content.split('\n');
13
+ if (lines.length < 2 || !FRONTMATTER_FENCE.test(lines[0])) {
14
+ return null;
15
+ }
16
+ let endIdx = -1;
17
+ for (let i = 1; i < lines.length; i++) {
18
+ if (FRONTMATTER_FENCE.test(lines[i])) {
19
+ endIdx = i;
20
+ break;
21
+ }
22
+ }
23
+ if (endIdx === -1)
24
+ return null;
25
+ const yamlStr = lines.slice(1, endIdx).join('\n');
26
+ const metadata = (await parseYaml(yamlStr));
27
+ if (typeof metadata !== 'object' || metadata === null) {
28
+ return null;
29
+ }
30
+ const body = lines.slice(endIdx + 1).join('\n').trimStart();
31
+ return { metadata, body };
32
+ }
33
+ /**
34
+ * Create a markdown frontmatter extractor.
35
+ *
36
+ * Scans for .md files with YAML frontmatter containing at least `id` and `title`.
37
+ * Treats each matching file as a single-file example.
38
+ */
39
+ export function createMarkdownExtractor() {
40
+ return {
41
+ name: EXTRACTOR_NAME,
42
+ async extract(candidates, _options) {
43
+ const examples = [];
44
+ const errors = [];
45
+ const claimedFiles = new Set();
46
+ const mdCandidates = candidates.filter((c) => c.isFile() && c.name.endsWith('.md'));
47
+ for (const candidate of mdCandidates) {
48
+ const parentPath = 'parentPath' in candidate && typeof candidate.parentPath === 'string'
49
+ ? candidate.parentPath
50
+ : candidate.path ?? '';
51
+ const absPath = path.join(parentPath, candidate.name);
52
+ try {
53
+ const content = await fs.readFile(absPath, 'utf-8');
54
+ const parsed = await parseFrontmatter(content);
55
+ if (!parsed)
56
+ continue;
57
+ const { metadata, body } = parsed;
58
+ // Must have id and title to be treated as an example
59
+ if (typeof metadata.id !== 'string' ||
60
+ typeof metadata.title !== 'string') {
61
+ continue;
62
+ }
63
+ examples.push({
64
+ id: metadata.id,
65
+ title: metadata.title,
66
+ description: typeof metadata.description === 'string'
67
+ ? metadata.description
68
+ : undefined,
69
+ rootPath: path.dirname(absPath),
70
+ files: [
71
+ {
72
+ absolutePath: absPath,
73
+ relativePath: candidate.name,
74
+ raw: content,
75
+ parsed: body,
76
+ },
77
+ ],
78
+ metadata,
79
+ extractorName: EXTRACTOR_NAME,
80
+ });
81
+ claimedFiles.add(absPath);
82
+ }
83
+ catch (err) {
84
+ errors.push({
85
+ path: absPath,
86
+ message: err instanceof Error ? err.message : `Failed to read ${absPath}`,
87
+ cause: err instanceof Error ? err : undefined,
88
+ });
89
+ }
90
+ }
91
+ return { examples, errors, claimedFiles };
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/extractor/extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Plugin } from '@functional-examples/devkit';
2
+ import type { DocsMetadataSchemaType, DocumentationPluginOptions } from './schema.js';
3
+ /**
4
+ * Create the documentation plugin.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createDocumentationPlugin } from '@functional-examples/documentation';
9
+ *
10
+ * const config = {
11
+ * plugins: [
12
+ * createDocumentationPlugin({
13
+ * outputDir: './docs',
14
+ * format: 'markdown',
15
+ * }),
16
+ * ],
17
+ * };
18
+ * ```
19
+ */
20
+ export declare function createDocumentationPlugin(options?: DocumentationPluginOptions): Plugin<DocsMetadataSchemaType>;
21
+ export type { DocumentationPluginOptions, DocsMetadata, ResolvedDocumentationPluginOptions, DocsMetadataSchemaType, } from './schema.js';
22
+ export type { TemplateData, TemplateDescriptor, RenderedFile, IndexTemplateData, ProseRenderResult, } from './templates/engine.js';
23
+ export type { TemplateHelpers } from './templates/helpers.js';
24
+ export type { ProseHelpers } from './templates/prose-helpers.js';
25
+ export { createMarkdownExtractor } from './extractor/extractor.js';
26
+ export { renderTemplate, buildTemplateData, renderProseFiles, loadTemplates, parseTemplateName, substituteVars, renderItemTemplate, renderIndexTemplate, getBuiltinTemplatesDir, } from './templates/engine.js';
27
+ export { templateHelpers } from './templates/helpers.js';
28
+ export { ConsumptionTracker } from './templates/consumption-tracker.js';
29
+ export { createProseHelpers, fencedBlock } from './templates/prose-helpers.js';
30
+ export { createGuideRenderer } from './templates/guide-renderer.js';
31
+ export type { GuideRenderer, ExampleAccessor } from './templates/guide-renderer.js';
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAoB,MAAM,6BAA6B,CAAC;AAG5E,OAAO,KAAK,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAQtF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,0BAA+B,GACvC,MAAM,CAAC,sBAAsB,CAAC,CAkBhC;AAGD,YAAY,EACV,0BAA0B,EAC1B,YAAY,EACZ,kCAAkC,EAClC,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,46 @@
1
+ import { createDocumentationCommands } from './commands/index.js';
2
+ import { createMarkdownExtractor } from './extractor/extractor.js';
3
+ import { DOCS_METADATA_JSON_SCHEMA, DOCS_OPTIONS_JSON_SCHEMA, docsOptionsSchema, validateDocsMetadata, } from './schema.js';
4
+ /**
5
+ * Create the documentation plugin.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { createDocumentationPlugin } from '@functional-examples/documentation';
10
+ *
11
+ * const config = {
12
+ * plugins: [
13
+ * createDocumentationPlugin({
14
+ * outputDir: './docs',
15
+ * format: 'markdown',
16
+ * }),
17
+ * ],
18
+ * };
19
+ * ```
20
+ */
21
+ export function createDocumentationPlugin(options = {}) {
22
+ return {
23
+ name: '@functional-examples/documentation',
24
+ extensions: options.enableExtractor ? ['.md'] : undefined,
25
+ extractor: options.enableExtractor ? createMarkdownExtractor() : undefined,
26
+ schemas: {
27
+ metadata: JSON.stringify(DOCS_METADATA_JSON_SCHEMA),
28
+ options: JSON.stringify(DOCS_OPTIONS_JSON_SCHEMA),
29
+ },
30
+ validators: {
31
+ metadata: validateDocsMetadata,
32
+ },
33
+ commands: async (config) => {
34
+ const resolved = docsOptionsSchema.parse(options);
35
+ return createDocumentationCommands(config, resolved);
36
+ },
37
+ _options: options,
38
+ };
39
+ }
40
+ export { createMarkdownExtractor } from './extractor/extractor.js';
41
+ export { renderTemplate, buildTemplateData, renderProseFiles, loadTemplates, parseTemplateName, substituteVars, renderItemTemplate, renderIndexTemplate, getBuiltinTemplatesDir, } from './templates/engine.js';
42
+ export { templateHelpers } from './templates/helpers.js';
43
+ export { ConsumptionTracker } from './templates/consumption-tracker.js';
44
+ export { createProseHelpers, fencedBlock } from './templates/prose-helpers.js';
45
+ export { createGuideRenderer } from './templates/guide-renderer.js';
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAsC,EAAE;IAExC,OAAO;QACL,IAAI,EAAE,oCAAoC;QAC1C,UAAU,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;QACzD,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC,SAAS;QAC1E,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC;YACnD,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC;SAClD;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,oBAA+D;SAC1E;QACD,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACzB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAClD,OAAO,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAU,CAAC;QAChE,CAAC;QACD,QAAQ,EAAE,OAAO;KAClB,CAAC;AACJ,CAAC;AAkBD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Renderer } from './types.js';
2
+ /**
3
+ * Markdoc renderer — wraps code blocks with Markdoc-style fence annotations.
4
+ *
5
+ * Converts standard Markdown code fences into Markdoc-annotated fences:
6
+ * ```typescript → ```typescript {% process=true %}
7
+ * code code
8
+ * ``` ```
9
+ *
10
+ * Also converts headings to Markdoc-annotated headings with auto-generated IDs.
11
+ */
12
+ export declare function createMarkdocRenderer(): Renderer;
13
+ //# sourceMappingURL=markdoc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdoc.d.ts","sourceRoot":"","sources":["../../src/renderers/markdoc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,IAAI,QAAQ,CAkChD"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Markdoc renderer — wraps code blocks with Markdoc-style fence annotations.
3
+ *
4
+ * Converts standard Markdown code fences into Markdoc-annotated fences:
5
+ * ```typescript → ```typescript {% process=true %}
6
+ * code code
7
+ * ``` ```
8
+ *
9
+ * Also converts headings to Markdoc-annotated headings with auto-generated IDs.
10
+ */
11
+ export function createMarkdocRenderer() {
12
+ return {
13
+ extension: '.mdoc',
14
+ render(content) {
15
+ const lines = content.split('\n');
16
+ const result = [];
17
+ for (const line of lines) {
18
+ // Annotate code fences with Markdoc attributes
19
+ const fenceMatch = line.match(/^(```\w+)\s*$/);
20
+ if (fenceMatch) {
21
+ result.push(`${fenceMatch[1]} {% process=true %}`);
22
+ continue;
23
+ }
24
+ // Annotate headings with auto-generated IDs
25
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
26
+ if (headingMatch) {
27
+ const [, hashes, text] = headingMatch;
28
+ const id = text
29
+ .replace(/`/g, '')
30
+ .toLowerCase()
31
+ .replace(/[^a-z0-9]+/g, '-')
32
+ .replace(/^-|-$/g, '');
33
+ result.push(`${hashes} ${text} {% #${id} %}`);
34
+ continue;
35
+ }
36
+ result.push(line);
37
+ }
38
+ return result.join('\n');
39
+ },
40
+ };
41
+ }
42
+ //# sourceMappingURL=markdoc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdoc.js","sourceRoot":"","sources":["../../src/renderers/markdoc.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,SAAS,EAAE,OAAO;QAClB,MAAM,CAAC,OAAe;YACpB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,MAAM,GAAa,EAAE,CAAC;YAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,+CAA+C;gBAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;gBAC/C,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;oBACnD,SAAS;gBACX,CAAC;gBAED,4CAA4C;gBAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACrD,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,YAAY,CAAC;oBACtC,MAAM,EAAE,GAAG,IAAI;yBACZ,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;yBACjB,WAAW,EAAE;yBACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;yBAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,QAAQ,EAAE,KAAK,CAAC,CAAC;oBAC9C,SAAS;gBACX,CAAC;gBAED,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;YAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Renderer } from './types.js';
2
+ /**
3
+ * Markdown renderer — passes template output through as-is.
4
+ */
5
+ export declare function createMarkdownRenderer(): Renderer;
6
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/renderers/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,QAAQ,CAOjD"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Markdown renderer — passes template output through as-is.
3
+ */
4
+ export function createMarkdownRenderer() {
5
+ return {
6
+ extension: '.md',
7
+ render(content) {
8
+ return content;
9
+ },
10
+ };
11
+ }
12
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/renderers/markdown.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,SAAS,EAAE,KAAK;QAChB,MAAM,CAAC,OAAe;YACpB,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Renderer interface for post-processing template output.
3
+ */
4
+ export interface Renderer {
5
+ /** File extension produced by this renderer (e.g., '.md', '.mdoc') */
6
+ readonly extension: string;
7
+ /**
8
+ * Process template output into final file content.
9
+ * @param content - Raw rendered template output (Markdown)
10
+ * @returns Processed content ready to write to disk
11
+ */
12
+ render(content: string): string;
13
+ }
14
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/renderers/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,sEAAsE;IACtE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC"}