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.
- package/LICENSE +21 -0
- package/README.md +941 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +337 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/dependency.d.ts +59 -0
- package/dist/core/dependency.d.ts.map +1 -0
- package/dist/core/dependency.js +209 -0
- package/dist/core/dependency.js.map +1 -0
- package/dist/core/generator.d.ts +23 -0
- package/dist/core/generator.d.ts.map +1 -0
- package/dist/core/generator.js +211 -0
- package/dist/core/generator.js.map +1 -0
- package/dist/core/inline-datasource.d.ts +117 -0
- package/dist/core/inline-datasource.d.ts.map +1 -0
- package/dist/core/inline-datasource.js +346 -0
- package/dist/core/inline-datasource.js.map +1 -0
- package/dist/core/parser.d.ts +41 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +250 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/processor.d.ts +18 -0
- package/dist/core/processor.d.ts.map +1 -0
- package/dist/core/processor.js +219 -0
- package/dist/core/processor.js.map +1 -0
- package/dist/datasources/csv.d.ts +17 -0
- package/dist/datasources/csv.d.ts.map +1 -0
- package/dist/datasources/csv.js +54 -0
- package/dist/datasources/csv.js.map +1 -0
- package/dist/datasources/glob.d.ts +17 -0
- package/dist/datasources/glob.d.ts.map +1 -0
- package/dist/datasources/glob.js +72 -0
- package/dist/datasources/glob.js.map +1 -0
- package/dist/datasources/index.d.ts +22 -0
- package/dist/datasources/index.d.ts.map +1 -0
- package/dist/datasources/index.js +53 -0
- package/dist/datasources/index.js.map +1 -0
- package/dist/datasources/json.d.ts +16 -0
- package/dist/datasources/json.d.ts.map +1 -0
- package/dist/datasources/json.js +59 -0
- package/dist/datasources/json.js.map +1 -0
- package/dist/datasources/sqlite.d.ts +15 -0
- package/dist/datasources/sqlite.d.ts.map +1 -0
- package/dist/datasources/sqlite.js +40 -0
- package/dist/datasources/sqlite.js.map +1 -0
- package/dist/datasources/yaml.d.ts +16 -0
- package/dist/datasources/yaml.d.ts.map +1 -0
- package/dist/datasources/yaml.js +60 -0
- package/dist/datasources/yaml.js.map +1 -0
- package/dist/helpers/markdown.d.ts +10 -0
- package/dist/helpers/markdown.d.ts.map +1 -0
- package/dist/helpers/markdown.js +93 -0
- package/dist/helpers/markdown.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +254 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,941 @@
|
|
|
1
|
+
# embedoc
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/embedoc) [](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
|
+
|