embedoc 0.9.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +941 -0
  3. package/dist/cli.d.ts +6 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +337 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/dependency.d.ts +59 -0
  8. package/dist/core/dependency.d.ts.map +1 -0
  9. package/dist/core/dependency.js +209 -0
  10. package/dist/core/dependency.js.map +1 -0
  11. package/dist/core/generator.d.ts +23 -0
  12. package/dist/core/generator.d.ts.map +1 -0
  13. package/dist/core/generator.js +211 -0
  14. package/dist/core/generator.js.map +1 -0
  15. package/dist/core/inline-datasource.d.ts +117 -0
  16. package/dist/core/inline-datasource.d.ts.map +1 -0
  17. package/dist/core/inline-datasource.js +346 -0
  18. package/dist/core/inline-datasource.js.map +1 -0
  19. package/dist/core/parser.d.ts +41 -0
  20. package/dist/core/parser.d.ts.map +1 -0
  21. package/dist/core/parser.js +250 -0
  22. package/dist/core/parser.js.map +1 -0
  23. package/dist/core/processor.d.ts +18 -0
  24. package/dist/core/processor.d.ts.map +1 -0
  25. package/dist/core/processor.js +219 -0
  26. package/dist/core/processor.js.map +1 -0
  27. package/dist/datasources/csv.d.ts +17 -0
  28. package/dist/datasources/csv.d.ts.map +1 -0
  29. package/dist/datasources/csv.js +54 -0
  30. package/dist/datasources/csv.js.map +1 -0
  31. package/dist/datasources/glob.d.ts +17 -0
  32. package/dist/datasources/glob.d.ts.map +1 -0
  33. package/dist/datasources/glob.js +72 -0
  34. package/dist/datasources/glob.js.map +1 -0
  35. package/dist/datasources/index.d.ts +22 -0
  36. package/dist/datasources/index.d.ts.map +1 -0
  37. package/dist/datasources/index.js +53 -0
  38. package/dist/datasources/index.js.map +1 -0
  39. package/dist/datasources/json.d.ts +16 -0
  40. package/dist/datasources/json.d.ts.map +1 -0
  41. package/dist/datasources/json.js +59 -0
  42. package/dist/datasources/json.js.map +1 -0
  43. package/dist/datasources/sqlite.d.ts +15 -0
  44. package/dist/datasources/sqlite.d.ts.map +1 -0
  45. package/dist/datasources/sqlite.js +40 -0
  46. package/dist/datasources/sqlite.js.map +1 -0
  47. package/dist/datasources/yaml.d.ts +16 -0
  48. package/dist/datasources/yaml.d.ts.map +1 -0
  49. package/dist/datasources/yaml.js +60 -0
  50. package/dist/datasources/yaml.js.map +1 -0
  51. package/dist/helpers/markdown.d.ts +10 -0
  52. package/dist/helpers/markdown.d.ts.map +1 -0
  53. package/dist/helpers/markdown.js +93 -0
  54. package/dist/helpers/markdown.js.map +1 -0
  55. package/dist/index.d.ts +50 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +51 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/types/index.d.ts +254 -0
  60. package/dist/types/index.d.ts.map +1 -0
  61. package/dist/types/index.js +5 -0
  62. package/dist/types/index.js.map +1 -0
  63. package/package.json +88 -0
package/README.md ADDED
@@ -0,0 +1,941 @@
1
+ # embedoc
2
+
3
+ [![npm version](https://badge.fury.io/js/embedoc.svg)](https://www.npmjs.com/package/embedoc) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+
5
+ **In-Place Document Generator** - A tool that auto-updates marker blocks in documents and source code while preserving manually edited sections.
6
+
7
+
8
+ ## Overview
9
+
10
+ embedoc provides "In-Place template update" functionality that auto-updates specific blocks (regions enclosed by markers) within documents or source code while preserving manually edited sections.
11
+
12
+ ```markdown
13
+ # Manually written heading
14
+
15
+ This part can be manually edited.
16
+
17
+ <!--@embedoc:table_columns id="users"-->
18
+ (This content is auto-generated)
19
+ <!--@embedoc:end-->
20
+
21
+ This part can also be manually edited.
22
+ ```
23
+
24
+ **Auto-generated and manually edited sections coexist in the same file** without separating source and built files.
25
+
26
+ ## Features
27
+
28
+ - **In-Place Updates**: Auto-generated and manually edited sections coexist in the same file
29
+ - **Multiple Comment Formats**: Supports HTML, block, line, hash, SQL comment formats
30
+ - **Programmable Embeds**: Write marker embedding logic in TypeScript (no compilation required)
31
+ - **Multiple Datasources**: SQLite, CSV, JSON, YAML, and glob support
32
+ - **Inline Datasources**: Define data directly in documents with `@embedoc-data` markers
33
+ - **File Generation**: Generate new files in bulk using Handlebars templates
34
+ - **Watch Mode**: Monitor file changes and auto-rebuild with incremental builds
35
+ - **Dependency Tracking**: Automatic dependency graph analysis for efficient rebuilds
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ npm install embedoc
41
+ # or
42
+ pnpm add embedoc
43
+ # or
44
+ yarn add embedoc
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ### 1. Create Configuration File
50
+
51
+ ```yaml
52
+ # embedoc.config.yaml
53
+ version: "1.0"
54
+
55
+ targets:
56
+ - pattern: "./docs/**/*.md"
57
+ comment_style: html
58
+ exclude:
59
+ - "**/node_modules/**"
60
+
61
+ datasources:
62
+ metadata_db:
63
+ type: sqlite
64
+ path: "./data/metadata.db"
65
+
66
+ embeds_dir: "./embeds"
67
+ templates_dir: "./templates"
68
+ ```
69
+
70
+ ### 2. Create an Embed
71
+
72
+ ```typescript
73
+ // embeds/table_columns.ts
74
+ import { defineEmbed } from 'embedoc';
75
+
76
+ export default defineEmbed({
77
+ dependsOn: ['metadata_db'],
78
+
79
+ async render(ctx) {
80
+ const { id } = ctx.params;
81
+
82
+ if (!id) {
83
+ return { content: '❌ Error: id parameter is required' };
84
+ }
85
+
86
+ const columns = await ctx.datasources['metadata_db']!.query(
87
+ `SELECT * FROM columns WHERE table_name = ? ORDER BY ordinal_position`,
88
+ [id]
89
+ );
90
+
91
+ const markdown = ctx.markdown.table(
92
+ ['Column', 'Type', 'NOT NULL', 'Default', 'Comment'],
93
+ columns.map((col) => [
94
+ col['column_name'],
95
+ col['data_type'],
96
+ col['not_null'] ? '✔' : '',
97
+ col['default_value'] ?? 'NULL',
98
+ col['column_comment'] ?? '',
99
+ ])
100
+ );
101
+
102
+ return { content: markdown };
103
+ },
104
+ });
105
+ ```
106
+
107
+ Register your embed in `embeds/index.ts`:
108
+
109
+ ```typescript
110
+ // embeds/index.ts
111
+ import tableColumns from './table_columns.ts';
112
+
113
+ export const embeds = {
114
+ table_columns: tableColumns,
115
+ };
116
+ ```
117
+
118
+ > **Note**: embedoc can directly import TypeScript files, so **no compilation is required**.
119
+
120
+ ### 3. Add Markers to Your Document
121
+
122
+ ```markdown
123
+ # Users Table
124
+
125
+ <!--@embedoc:table_columns id="users"-->
126
+ <!--@embedoc:end-->
127
+ ```
128
+
129
+ ### 4. Run Build
130
+
131
+ ```bash
132
+ npx embedoc build
133
+ ```
134
+
135
+ ---
136
+
137
+ ## CLI Commands
138
+
139
+ ```bash
140
+ # Build all files
141
+ embedoc build --config embedoc.config.yaml
142
+
143
+ # Build specific files only
144
+ embedoc build ./path/to/file.md
145
+
146
+ # Generate new files (specific datasource)
147
+ embedoc generate --datasource tables
148
+
149
+ # Run all datasource generators
150
+ embedoc generate --all
151
+
152
+ # Watch mode (incremental build)
153
+ embedoc watch --config embedoc.config.yaml
154
+
155
+ # Debug dependency graph
156
+ embedoc watch --debug-deps
157
+
158
+ # Dry run (no file writes)
159
+ embedoc build --dry-run
160
+
161
+ # Verbose output
162
+ embedoc build --verbose
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Configuration File
168
+
169
+ ### Full Configuration Reference
170
+
171
+ ```yaml
172
+ # embedoc.config.yaml
173
+ version: "1.0"
174
+
175
+ # Target files
176
+ targets:
177
+ - pattern: "./docs/**/*.md"
178
+ comment_style: html
179
+ exclude:
180
+ - "**/node_modules/**"
181
+ - "**/.git/**"
182
+ - pattern: "./src/**/*.ts"
183
+ comment_style: block
184
+ - pattern: "./scripts/**/*.py"
185
+ comment_style: hash
186
+ - pattern: "./db/**/*.sql"
187
+ comment_style: sql
188
+
189
+ # Custom comment style definitions (optional)
190
+ comment_styles:
191
+ html:
192
+ start: "<!--"
193
+ end: "-->"
194
+ block:
195
+ start: "/*"
196
+ end: "*/"
197
+ line:
198
+ start: "//"
199
+ end: ""
200
+ hash:
201
+ start: "#"
202
+ end: ""
203
+ sql:
204
+ start: "--"
205
+ end: ""
206
+ # Custom formats
207
+ lua:
208
+ start: "--[["
209
+ end: "]]"
210
+
211
+ # Datasource definitions
212
+ datasources:
213
+ # Schema datasource with generators
214
+ tables:
215
+ type: sqlite
216
+ path: "./data/metadata.db"
217
+ query: "SELECT * FROM tables"
218
+ generators:
219
+ - output_path: "./docs/tables/{table_name}.md"
220
+ template: table_doc.hbs
221
+ overwrite: false
222
+
223
+ # Connection datasource (for queries from embeds)
224
+ metadata_db:
225
+ type: sqlite
226
+ path: "./data/metadata.db"
227
+
228
+ # CSV datasource
229
+ api_endpoints:
230
+ type: csv
231
+ path: "./data/endpoints.csv"
232
+ encoding: utf-8
233
+
234
+ # JSON datasource
235
+ config:
236
+ type: json
237
+ path: "./data/config.json"
238
+
239
+ # YAML datasource
240
+ settings:
241
+ type: yaml
242
+ path: "./data/settings.yaml"
243
+
244
+ # Glob datasource
245
+ doc_files:
246
+ type: glob
247
+ pattern: "./docs/**/*.md"
248
+
249
+ # Embed directory (TypeScript)
250
+ embeds_dir: "./embeds"
251
+
252
+ # Template directory (Handlebars)
253
+ templates_dir: "./templates"
254
+
255
+ # Output settings
256
+ output:
257
+ encoding: utf-8
258
+ line_ending: lf # or "crlf"
259
+
260
+ # Inline datasource configuration
261
+ inline_datasource:
262
+ enabled: true
263
+ maxBytes: 10240 # Max size per inline block (default: 10KB)
264
+ allowedFormats: # Allowed formats (default: all)
265
+ - yaml
266
+ - json
267
+ - csv
268
+ - table
269
+ - text
270
+ conflictPolicy: warn # warn | error | prefer_external
271
+ stripCodeFences: true # Auto-strip ```yaml ... ``` fences
272
+ stripPatterns: # Custom patterns to strip (regex)
273
+ - '^```\w*\s*\n?'
274
+ - '\n?```\s*$'
275
+
276
+ # GitHub integration
277
+ # Used as base URL when generating repository links in embeds
278
+ # (e.g., ctx.markdown.link('file.ts', github.base_url + 'src/file.ts'))
279
+ github:
280
+ base_url: "https://github.com/owner/repo/blob/main/"
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Marker Syntax
286
+
287
+ ### Basic Syntax
288
+
289
+ ```
290
+ {comment_start}@embedoc:{embed_name} {attr1}="{value1}" {attr2}="{value2}"{comment_end}
291
+ (auto-generated content)
292
+ {comment_start}@embedoc:end{comment_end}
293
+ ```
294
+
295
+ ### Supported Comment Formats
296
+
297
+ | Format | Start Marker | End Marker | Target Files |
298
+ |--------|-------------|------------|--------------|
299
+ | `html` | `<!--` | `-->` | `.md`, `.html`, `.xml` |
300
+ | `block` | `/*` | `*/` | `.js`, `.ts`, `.css`, `.java`, `.c` |
301
+ | `line` | `//` | (newline) | `.js`, `.ts`, `.java`, `.c`, `.go` |
302
+ | `hash` | `#` | (newline) | `.py`, `.rb`, `.sh`, `.yaml` |
303
+ | `sql` | `--` | (newline) | `.sql` |
304
+
305
+ ### Examples by Format
306
+
307
+ **Markdown / HTML**
308
+ ```markdown
309
+ <!--@embedoc:table_columns id="users"-->
310
+ | Column | Type | Comment |
311
+ | --- | --- | --- |
312
+ | id | integer | User ID |
313
+ <!--@embedoc:end-->
314
+ ```
315
+
316
+ **TypeScript / JavaScript (block)**
317
+ ```typescript
318
+ /*@embedoc:type_definition id="User"*/
319
+ export interface User {
320
+ id: number;
321
+ name: string;
322
+ }
323
+ /*@embedoc:end*/
324
+ ```
325
+
326
+ **TypeScript / JavaScript (line)**
327
+ ```typescript
328
+ //@embedoc:imports id="api-client"
329
+ import { ApiClient } from './api';
330
+ import { UserService } from './services/user';
331
+ //@embedoc:end
332
+ ```
333
+
334
+ **Python**
335
+ ```python
336
+ #@embedoc:constants id="config"
337
+ API_URL = "https://api.example.com"
338
+ TIMEOUT = 30
339
+ #@embedoc:end
340
+ ```
341
+
342
+ **SQL**
343
+ ```sql
344
+ --@embedoc:view_definition id="active_users"
345
+ CREATE VIEW active_users AS
346
+ SELECT * FROM users WHERE status = 'active';
347
+ --@embedoc:end
348
+ ```
349
+
350
+ ### Variable References in Attributes
351
+
352
+ Use `${...}` syntax in attribute values to reference Frontmatter properties or inline datasources.
353
+
354
+ ```yaml
355
+ ---
356
+ doc_id: "users"
357
+ schema: "public"
358
+ ---
359
+ ```
360
+
361
+ ```markdown
362
+ <!--@embedoc:table_columns id="${doc_id}"-->
363
+ <!--@embedoc:end-->
364
+
365
+ <!--@embedoc:table_info id="${schema}.${doc_id}"-->
366
+ <!--@embedoc:end-->
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Embed API
372
+
373
+ ### Basic Structure
374
+
375
+ ```typescript
376
+ import { defineEmbed } from 'embedoc';
377
+
378
+ export default defineEmbed({
379
+ // Datasources this embed depends on (for dependency tracking)
380
+ dependsOn: ['metadata_db'],
381
+
382
+ // Render function
383
+ async render(ctx) {
384
+ // ctx.params: Marker attribute values
385
+ // ctx.frontmatter: Frontmatter YAML data
386
+ // ctx.datasources: Access to datasources
387
+ // ctx.markdown: Markdown helpers
388
+ // ctx.filePath: Current file path being processed
389
+
390
+ return { content: 'Generated content' };
391
+ }
392
+ });
393
+ ```
394
+
395
+ ### Context Object
396
+
397
+ | Property | Type | Description |
398
+ |----------|------|-------------|
399
+ | `ctx.params` | `Record<string, string>` | Marker attribute values |
400
+ | `ctx.frontmatter` | `Record<string, unknown>` | Document frontmatter data |
401
+ | `ctx.datasources` | `Record<string, Datasource>` | Available datasources |
402
+ | `ctx.markdown` | `MarkdownHelper` | Markdown generation helpers |
403
+ | `ctx.filePath` | `string` | Current file path |
404
+
405
+ ### Markdown Helpers
406
+
407
+ ```typescript
408
+ // Table
409
+ ctx.markdown.table(
410
+ ['Column', 'Type', 'Description'],
411
+ [
412
+ ['id', 'integer', 'Primary key'],
413
+ ['name', 'varchar', 'User name'],
414
+ ]
415
+ );
416
+
417
+ // List
418
+ ctx.markdown.list(['Item 1', 'Item 2', 'Item 3'], false); // unordered
419
+ ctx.markdown.list(['First', 'Second', 'Third'], true); // ordered
420
+
421
+ // Code block
422
+ ctx.markdown.codeBlock('const x = 1;', 'typescript');
423
+
424
+ // Link
425
+ ctx.markdown.link('Click here', 'https://example.com');
426
+
427
+ // Heading
428
+ ctx.markdown.heading('Section Title', 2); // ## Section Title
429
+
430
+ // Inline formatting
431
+ ctx.markdown.bold('Important'); // **Important**
432
+ ctx.markdown.italic('Emphasis'); // *Emphasis*
433
+ ctx.markdown.checkbox(true); // [x]
434
+ ctx.markdown.checkbox(false); // [ ]
435
+ ```
436
+
437
+ ---
438
+
439
+ ## Datasources
440
+
441
+ ### SQLite
442
+
443
+ ```yaml
444
+ datasources:
445
+ metadata_db:
446
+ type: sqlite
447
+ path: "./data/metadata.db"
448
+ # Optional: predefined query for generators
449
+ query: "SELECT * FROM tables"
450
+ ```
451
+
452
+ Usage in embed:
453
+ ```typescript
454
+ const rows = await ctx.datasources['metadata_db'].query(
455
+ 'SELECT * FROM users WHERE id = ?',
456
+ [userId]
457
+ );
458
+ ```
459
+
460
+ ### CSV
461
+
462
+ ```yaml
463
+ datasources:
464
+ endpoints:
465
+ type: csv
466
+ path: "./data/endpoints.csv"
467
+ encoding: utf-8 # optional, default: utf-8
468
+ ```
469
+
470
+ ### JSON
471
+
472
+ ```yaml
473
+ datasources:
474
+ config:
475
+ type: json
476
+ path: "./data/config.json"
477
+ ```
478
+
479
+ ### YAML
480
+
481
+ ```yaml
482
+ datasources:
483
+ settings:
484
+ type: yaml
485
+ path: "./data/settings.yaml"
486
+ ```
487
+
488
+ ### Glob (File Listings)
489
+
490
+ ```yaml
491
+ datasources:
492
+ doc_files:
493
+ type: glob
494
+ pattern: "./docs/**/*.md"
495
+ ```
496
+
497
+ Returns array of file info objects with `path`, `name`, `ext`, etc.
498
+
499
+ ---
500
+
501
+ ## Inline Datasources
502
+
503
+ Define data directly in documents using `@embedoc-data` markers.
504
+
505
+ ### Basic Syntax
506
+
507
+ ```markdown
508
+ <!--@embedoc-data:datasource_name format="yaml"-->
509
+ - name: Alice
510
+ age: 25
511
+ - name: Bob
512
+ age: 30
513
+ <!--@embedoc-data:end-->
514
+ ```
515
+
516
+ ### Supported Formats
517
+
518
+ | Format | Description |
519
+ |--------|-------------|
520
+ | `yaml` | YAML array or object (default) |
521
+ | `json` | JSON array or object |
522
+ | `csv` | CSV with header row |
523
+ | `table` | Markdown table |
524
+ | `text` | Plain text |
525
+
526
+ ### Format Examples
527
+
528
+ **YAML (default)**
529
+ ```markdown
530
+ <!--@embedoc-data:users format="yaml"-->
531
+ - id: 1
532
+ name: Alice
533
+ email: alice@example.com
534
+ - id: 2
535
+ name: Bob
536
+ email: bob@example.com
537
+ <!--@embedoc-data:end-->
538
+ ```
539
+
540
+ **JSON**
541
+ ```markdown
542
+ <!--@embedoc-data:config format="json"-->
543
+ {
544
+ "api_url": "https://api.example.com",
545
+ "timeout": 30
546
+ }
547
+ <!--@embedoc-data:end-->
548
+ ```
549
+
550
+ **CSV**
551
+ ```markdown
552
+ <!--@embedoc-data:endpoints format="csv"-->
553
+ method,path,description
554
+ GET,/users,List all users
555
+ POST,/users,Create user
556
+ <!--@embedoc-data:end-->
557
+ ```
558
+
559
+ **Markdown Table**
560
+ ```markdown
561
+ <!--@embedoc-data:features format="table"-->
562
+ | Feature | Status | Priority |
563
+ |---------|--------|----------|
564
+ | Auth | Done | High |
565
+ | API | WIP | High |
566
+ <!--@embedoc-data:end-->
567
+ ```
568
+
569
+ ### Code Fence Support
570
+
571
+ For better readability in editors, you can wrap data in code fences:
572
+
573
+ ````markdown
574
+ <!--@embedoc-data:config format="yaml"-->
575
+ ```yaml
576
+ api_url: https://api.example.com
577
+ timeout: 30
578
+ features:
579
+ - auth
580
+ - logging
581
+ ```
582
+ <!--@embedoc-data:end-->
583
+ ````
584
+
585
+ Code fences are automatically stripped during parsing.
586
+
587
+ ### Dot-Path Access for Nested Data
588
+
589
+ Access nested properties using dot notation:
590
+
591
+ ```markdown
592
+ <!--@embedoc-data:project format="yaml"-->
593
+ name: embedoc
594
+ version: 1.0.0
595
+ author:
596
+ name: Jane Developer
597
+ email: jane@example.com
598
+ repository:
599
+ url: https://github.com/janedev/embedoc
600
+ <!--@embedoc-data:end-->
601
+
602
+ Project: ${project.name} v${project.version}
603
+ Author: ${project.author.name} (${project.author.email})
604
+ ```
605
+
606
+ ### Distributed Definition Style
607
+
608
+ Define data inline where it's contextually relevant:
609
+
610
+ ```markdown
611
+ # Project Documentation
612
+
613
+ This project, <!--@embedoc-data:project.name-->embedoc<!--@embedoc-data:end-->,
614
+ version <!--@embedoc-data:project.version-->1.0.0<!--@embedoc-data:end-->,
615
+ provides in-place document generation.
616
+
617
+ ## Author
618
+
619
+ Maintained by <!--@embedoc-data:project.author.name-->Jane Developer<!--@embedoc-data:end-->
620
+ (<!--@embedoc-data:project.author.email-->jane@example.com<!--@embedoc-data:end-->).
621
+
622
+ ## Summary
623
+
624
+ | Property | Value |
625
+ |----------|-------|
626
+ | Name | ${project.name} |
627
+ | Version | ${project.version} |
628
+ | Author | ${project.author.name} |
629
+ ```
630
+
631
+ Both YAML blocks and dot-path definitions produce the same structure and can be mixed.
632
+
633
+ > **Note**: If the same dot-path is defined multiple times within a document, the **last definition wins** (values are overwritten in document order).
634
+
635
+ ### Using Inline Datasources in Embeds
636
+
637
+ ```typescript
638
+ export default defineEmbed({
639
+ async render(ctx) {
640
+ const datasourceName = ctx.params['datasource'];
641
+ const ds = ctx.datasources[datasourceName];
642
+
643
+ // Get all data
644
+ const data = await ds.getAll();
645
+
646
+ // Get nested value (for object datasources)
647
+ const authorName = await ds.get('author.name');
648
+
649
+ return { content: ctx.markdown.table(/* ... */) };
650
+ }
651
+ });
652
+ ```
653
+
654
+ ### Inline Datasource Configuration
655
+
656
+ ```yaml
657
+ # embedoc.config.yaml
658
+ inline_datasource:
659
+ enabled: true # Enable/disable (default: true)
660
+ maxBytes: 10240 # Max size per block (default: 10KB)
661
+ allowedFormats: # Restrict formats
662
+ - yaml
663
+ - json
664
+ conflictPolicy: warn # warn | error | prefer_external
665
+ stripCodeFences: true # Auto-strip code fences (default: true)
666
+ stripPatterns: # Custom strip patterns (regex)
667
+ - '^```\w*\s*\n?'
668
+ - '\n?```\s*$'
669
+ ```
670
+
671
+ ---
672
+
673
+ ## File Generation
674
+
675
+ Generate new files in bulk using Handlebars templates based on datasource records.
676
+
677
+ ### Configuration
678
+
679
+ ```yaml
680
+ datasources:
681
+ tables:
682
+ type: sqlite
683
+ path: "./data/metadata.db"
684
+ query: "SELECT * FROM tables"
685
+ generators:
686
+ - output_path: "./docs/tables/{table_name}.md"
687
+ template: table_doc.hbs
688
+ overwrite: false # Don't overwrite existing files
689
+ ```
690
+
691
+ ### Template (Handlebars)
692
+
693
+ ```handlebars
694
+ {{!-- templates/table_doc.hbs --}}
695
+ ---
696
+ doc_id: "{{table_name}}"
697
+ embeds:
698
+ - table_columns
699
+ - table_relations
700
+ ---
701
+ # Table: {{table_name}}
702
+
703
+ ## Columns
704
+
705
+ <!--@embedoc:table_columns id="{{table_name}}"-->
706
+ <!--@embedoc:end-->
707
+
708
+ ## Relations
709
+
710
+ <!--@embedoc:table_relations id="{{table_name}}"-->
711
+ <!--@embedoc:end-->
712
+
713
+ Created: {{today}}
714
+ ```
715
+
716
+ ### Built-in Handlebars Helpers
717
+
718
+ | Helper | Description | Example Output |
719
+ |--------|-------------|----------------|
720
+ | `{{today}}` | Today's date (YYYY-MM-DD) | `YYYY-MM-DD` |
721
+ | `{{datetime}}` | Current datetime (ISO 8601) | `YYYY-MM-DDTHH:mm:ss.sssZ` |
722
+ | `{{#if condition}}` | Conditional | `{{#if is_primary}}✔{{/if}}` |
723
+ | `{{#each items}}` | Loop | `{{#each columns}}{{name}}{{/each}}` |
724
+ | `{{#unless condition}}` | Negation | `{{#unless nullable}}NOT NULL{{/unless}}` |
725
+
726
+ ### Run Generation
727
+
728
+ ```bash
729
+ # Generate for specific datasource
730
+ embedoc generate --datasource tables
731
+
732
+ # Generate for all datasources with generators
733
+ embedoc generate --all
734
+ ```
735
+
736
+ ---
737
+
738
+ ## Incremental Build & Dependency Tracking
739
+
740
+ ### Dependency Chain
741
+
742
+ ```
743
+ Document (.md) → Embed (.ts) → Datasource (.db, .csv, .json)
744
+ ```
745
+
746
+ - **Document changed**: Rebuild that document only
747
+ - **Embed changed**: Rebuild all documents using that embed
748
+ - **Datasource changed**: Rebuild all documents using embeds that depend on that datasource
749
+
750
+ ### Watch Mode
751
+
752
+ ```bash
753
+ embedoc watch --config embedoc.config.yaml
754
+ ```
755
+
756
+ ### Debug Dependency Graph
757
+
758
+ ```bash
759
+ embedoc watch --debug-deps
760
+ ```
761
+
762
+ Example output:
763
+ ```
764
+ === Dependency Graph ===
765
+
766
+ [document] docs/tables/users.md
767
+ depends on:
768
+ - embed:table_columns
769
+ - embed:table_relations
770
+
771
+ [embed] embed:table_columns
772
+ depends on:
773
+ - data/sample.db
774
+ depended by:
775
+ - docs/tables/users.md
776
+ - docs/tables/orders.md
777
+
778
+ [datasource] data/sample.db
779
+ depended by:
780
+ - embed:table_columns
781
+ - embed:table_relations
782
+ ```
783
+
784
+ ---
785
+
786
+ ## Frontmatter
787
+
788
+ Documents can include YAML frontmatter for metadata and configuration:
789
+
790
+ ```yaml
791
+ ---
792
+ doc_id: "users"
793
+ doc_type: "table"
794
+ schema: "public"
795
+ embeds:
796
+ - table_columns
797
+ - table_relations
798
+ ---
799
+ ```
800
+
801
+ Frontmatter values can be referenced in marker attributes using `${...}` syntax.
802
+
803
+ ---
804
+
805
+ ## Directory Structure
806
+
807
+ ### Recommended Project Structure
808
+
809
+ ```
810
+ your-project/
811
+ ├── embedoc.config.yaml # Configuration file
812
+ ├── embeds/ # Embed definitions (TypeScript)
813
+ │ ├── table_columns.ts
814
+ │ ├── table_relations.ts
815
+ │ └── index.ts # Export all embeds
816
+ ├── templates/ # File generation templates (Handlebars)
817
+ │ ├── table_doc.hbs
818
+ │ └── view_doc.hbs
819
+ ├── data/ # Datasources
820
+ │ ├── metadata.db
821
+ │ └── endpoints.csv
822
+ └── docs/ # Target documents
823
+ └── tables/
824
+ └── users.md
825
+ ```
826
+
827
+ ### Embed Registration
828
+
829
+ ```typescript
830
+ // embeds/index.ts
831
+ import tableColumns from './table_columns.ts';
832
+ import tableRelations from './table_relations.ts';
833
+ import customEmbed from './custom_embed.ts';
834
+
835
+ export const embeds = {
836
+ table_columns: tableColumns,
837
+ table_relations: tableRelations,
838
+ custom_embed: customEmbed,
839
+ };
840
+ ```
841
+
842
+ ---
843
+
844
+ ## Development
845
+
846
+ ### Building from Source
847
+
848
+ ```bash
849
+ # Clone repository
850
+ git clone https://github.com/user/embedoc.git
851
+ cd embedoc
852
+
853
+ # Install dependencies
854
+ npm install
855
+
856
+ # Build
857
+ npm run build
858
+
859
+ # Development mode (watch)
860
+ npm run dev
861
+
862
+ # Run tests
863
+ npm test
864
+ ```
865
+
866
+ ### Requirements
867
+
868
+ - Node.js 18+
869
+ - npm / pnpm / yarn
870
+
871
+ ---
872
+
873
+ ## API Reference
874
+
875
+ ### Exported Functions
876
+
877
+ ```typescript
878
+ import {
879
+ // Core
880
+ defineEmbed,
881
+ build,
882
+ processFile,
883
+
884
+ // Parser
885
+ parseMarkers,
886
+ parseFrontmatter,
887
+ parseInlineDataMarkers,
888
+
889
+ // Datasource utilities
890
+ InlineDatasource,
891
+ buildInlineDatasources,
892
+ parseDotPath,
893
+ resolveDotPath,
894
+
895
+ // Helpers
896
+ createMarkdownHelper,
897
+
898
+ // Constants
899
+ DEFAULT_COMMENT_STYLES,
900
+ } from 'embedoc';
901
+ ```
902
+
903
+ ### Type Definitions
904
+
905
+ ```typescript
906
+ interface EmbedDefinition {
907
+ dependsOn?: string[];
908
+ render: (ctx: EmbedContext) => Promise<{ content: string }>;
909
+ }
910
+
911
+ interface EmbedContext {
912
+ params: Record<string, string>;
913
+ frontmatter: Record<string, unknown>;
914
+ datasources: Record<string, Datasource>;
915
+ markdown: MarkdownHelper;
916
+ filePath: string;
917
+ }
918
+
919
+ interface Datasource {
920
+ query(sql: string, params?: unknown[]): Promise<QueryResult>;
921
+ getAll(): Promise<QueryResult>;
922
+ get?(path: string): Promise<unknown>; // For inline datasources
923
+ close(): Promise<void>;
924
+ }
925
+
926
+ interface InlineDatasourceConfig {
927
+ enabled?: boolean;
928
+ maxBytes?: number;
929
+ allowedFormats?: string[];
930
+ conflictPolicy?: 'warn' | 'error' | 'prefer_external';
931
+ stripCodeFences?: boolean;
932
+ stripPatterns?: string[];
933
+ }
934
+ ```
935
+
936
+ ---
937
+
938
+ ## License
939
+
940
+ MIT
941
+