embedoc 0.10.1 → 0.11.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/README.md +159 -27
- package/dist/cli.js +212 -32
- package/dist/cli.js.map +1 -1
- package/dist/core/dependency.d.ts +3 -3
- package/dist/core/dependency.d.ts.map +1 -1
- package/dist/core/dependency.js +4 -4
- package/dist/core/dependency.js.map +1 -1
- package/dist/core/generator.d.ts +3 -3
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +1 -1
- package/dist/core/generator.js.map +1 -1
- package/dist/core/inline-datasource.d.ts +4 -4
- package/dist/core/inline-datasource.d.ts.map +1 -1
- package/dist/core/inline-datasource.js +20 -9
- package/dist/core/inline-datasource.js.map +1 -1
- package/dist/core/processor.d.ts +4 -3
- package/dist/core/processor.d.ts.map +1 -1
- package/dist/core/processor.js +3 -3
- package/dist/core/processor.js.map +1 -1
- package/dist/datasources/index.d.ts +5 -4
- package/dist/datasources/index.d.ts.map +1 -1
- package/dist/datasources/index.js +9 -5
- package/dist/datasources/index.js.map +1 -1
- package/dist/embed-api.d.ts +14 -2
- package/dist/embed-api.d.ts.map +1 -1
- package/dist/embed-api.js +2 -2
- package/dist/embed-api.js.map +1 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +45 -3
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,26 @@ yarn add embedoc
|
|
|
46
46
|
|
|
47
47
|
## Quick Start
|
|
48
48
|
|
|
49
|
-
### 1.
|
|
49
|
+
### 1. Initialize Project
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx embedoc init
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This creates:
|
|
56
|
+
- `embedoc.config.yaml` - configuration file
|
|
57
|
+
- `.embedoc/renderers/index.ts` - renderer registration
|
|
58
|
+
- `.embedoc/datasources/index.ts` - custom datasource registration
|
|
59
|
+
- `.embedoc/templates/` - Handlebars templates directory
|
|
60
|
+
|
|
61
|
+
If `package.json` exists, npm scripts are also added:
|
|
62
|
+
- `npm run embedoc:build` - build documents
|
|
63
|
+
- `npm run embedoc:watch` - watch mode
|
|
64
|
+
- `npm run embedoc:generate` - run generators
|
|
65
|
+
|
|
66
|
+
### 2. Configure
|
|
67
|
+
|
|
68
|
+
Edit `embedoc.config.yaml` to set your targets and datasources:
|
|
50
69
|
|
|
51
70
|
```yaml
|
|
52
71
|
# embedoc.config.yaml
|
|
@@ -62,15 +81,12 @@ datasources:
|
|
|
62
81
|
metadata_db:
|
|
63
82
|
type: sqlite
|
|
64
83
|
path: "./data/metadata.db"
|
|
65
|
-
|
|
66
|
-
embeds_dir: "./embeds"
|
|
67
|
-
templates_dir: "./templates"
|
|
68
84
|
```
|
|
69
85
|
|
|
70
|
-
###
|
|
86
|
+
### 3. Create a Renderer
|
|
71
87
|
|
|
72
88
|
```typescript
|
|
73
|
-
//
|
|
89
|
+
// .embedoc/renderers/table_columns.ts
|
|
74
90
|
import { defineEmbed } from 'embedoc';
|
|
75
91
|
|
|
76
92
|
export default defineEmbed({
|
|
@@ -104,10 +120,10 @@ export default defineEmbed({
|
|
|
104
120
|
});
|
|
105
121
|
```
|
|
106
122
|
|
|
107
|
-
Register your
|
|
123
|
+
Register your renderer in `.embedoc/renderers/index.ts`:
|
|
108
124
|
|
|
109
125
|
```typescript
|
|
110
|
-
//
|
|
126
|
+
// .embedoc/renderers/index.ts
|
|
111
127
|
import tableColumns from './table_columns.ts';
|
|
112
128
|
|
|
113
129
|
export const embeds = {
|
|
@@ -117,7 +133,7 @@ export const embeds = {
|
|
|
117
133
|
|
|
118
134
|
> **Note**: embedoc can directly import TypeScript files, so **no compilation is required**.
|
|
119
135
|
|
|
120
|
-
###
|
|
136
|
+
### 4. Add Markers to Your Document
|
|
121
137
|
|
|
122
138
|
```markdown
|
|
123
139
|
# Users Table
|
|
@@ -126,10 +142,12 @@ export const embeds = {
|
|
|
126
142
|
<!--@embedoc:end-->
|
|
127
143
|
```
|
|
128
144
|
|
|
129
|
-
###
|
|
145
|
+
### 5. Run Build
|
|
130
146
|
|
|
131
147
|
```bash
|
|
132
148
|
npx embedoc build
|
|
149
|
+
# or, if scripts were added to package.json:
|
|
150
|
+
npm run embedoc:build
|
|
133
151
|
```
|
|
134
152
|
|
|
135
153
|
---
|
|
@@ -137,7 +155,12 @@ npx embedoc build
|
|
|
137
155
|
## CLI Commands
|
|
138
156
|
|
|
139
157
|
```bash
|
|
158
|
+
# Initialize project (creates config, .embedoc/ directory, updates package.json)
|
|
159
|
+
embedoc init
|
|
160
|
+
embedoc init --force # overwrite existing files
|
|
161
|
+
|
|
140
162
|
# Build all files
|
|
163
|
+
embedoc build
|
|
141
164
|
embedoc build --config embedoc.config.yaml
|
|
142
165
|
|
|
143
166
|
# Build specific files only
|
|
@@ -150,6 +173,7 @@ embedoc generate --datasource tables
|
|
|
150
173
|
embedoc generate --all
|
|
151
174
|
|
|
152
175
|
# Watch mode (incremental build)
|
|
176
|
+
embedoc watch
|
|
153
177
|
embedoc watch --config embedoc.config.yaml
|
|
154
178
|
|
|
155
179
|
# Debug dependency graph
|
|
@@ -162,6 +186,8 @@ embedoc build --dry-run
|
|
|
162
186
|
embedoc build --verbose
|
|
163
187
|
```
|
|
164
188
|
|
|
189
|
+
All commands can be run directly with `npx embedoc <command>` or via package.json scripts after `embedoc init`.
|
|
190
|
+
|
|
165
191
|
---
|
|
166
192
|
|
|
167
193
|
## Configuration File
|
|
@@ -246,11 +272,14 @@ datasources:
|
|
|
246
272
|
type: glob
|
|
247
273
|
pattern: "./docs/**/*.md"
|
|
248
274
|
|
|
249
|
-
#
|
|
250
|
-
|
|
275
|
+
# Renderer directory (TypeScript) - default: ".embedoc/renderers"
|
|
276
|
+
renderers_dir: ".embedoc/renderers"
|
|
277
|
+
|
|
278
|
+
# Custom datasource types directory - default: ".embedoc/datasources"
|
|
279
|
+
datasources_dir: ".embedoc/datasources"
|
|
251
280
|
|
|
252
|
-
# Template directory (Handlebars)
|
|
253
|
-
templates_dir: "
|
|
281
|
+
# Template directory (Handlebars) - default: ".embedoc/templates"
|
|
282
|
+
templates_dir: ".embedoc/templates"
|
|
254
283
|
|
|
255
284
|
# Output settings
|
|
256
285
|
output:
|
|
@@ -713,6 +742,97 @@ inline_datasource:
|
|
|
713
742
|
|
|
714
743
|
---
|
|
715
744
|
|
|
745
|
+
## Custom Datasources
|
|
746
|
+
|
|
747
|
+
Define custom datasource types in TypeScript to connect to any data source (APIs, databases, custom file formats, etc.).
|
|
748
|
+
|
|
749
|
+
### Defining a Custom Datasource Type
|
|
750
|
+
|
|
751
|
+
```typescript
|
|
752
|
+
// .embedoc/datasources/github.ts
|
|
753
|
+
import { defineDatasource } from 'embedoc';
|
|
754
|
+
|
|
755
|
+
export default defineDatasource({
|
|
756
|
+
async create(config) {
|
|
757
|
+
const owner = config['owner'] as string;
|
|
758
|
+
const repo = config['repo'] as string;
|
|
759
|
+
const response = await fetch(
|
|
760
|
+
`https://api.github.com/repos/${owner}/${repo}/issues`
|
|
761
|
+
);
|
|
762
|
+
const issues = await response.json();
|
|
763
|
+
|
|
764
|
+
return {
|
|
765
|
+
async query() { return issues; },
|
|
766
|
+
async getAll() { return issues; },
|
|
767
|
+
async close() {},
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
### Registering Custom Datasource Types
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
// .embedoc/datasources/index.ts
|
|
777
|
+
import github from './github.ts';
|
|
778
|
+
|
|
779
|
+
export const datasourceTypes = {
|
|
780
|
+
github,
|
|
781
|
+
};
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
### Using in Configuration
|
|
785
|
+
|
|
786
|
+
```yaml
|
|
787
|
+
# embedoc.config.yaml
|
|
788
|
+
datasources:
|
|
789
|
+
my_issues:
|
|
790
|
+
type: github # matches key in datasourceTypes
|
|
791
|
+
owner: "myorg"
|
|
792
|
+
repo: "myrepo"
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
All config properties are passed to the `create()` method, so custom datasources can accept any configuration.
|
|
796
|
+
|
|
797
|
+
### Custom Inline Format Parsers
|
|
798
|
+
|
|
799
|
+
Register custom format parsers for `@embedoc-data` inline markers by exporting `inlineFormats` alongside `datasourceTypes`:
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
// .embedoc/datasources/index.ts
|
|
803
|
+
import github from './github.ts';
|
|
804
|
+
|
|
805
|
+
export const datasourceTypes = {
|
|
806
|
+
github,
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
export const inlineFormats = {
|
|
810
|
+
toml: (content: string) => parseToml(content),
|
|
811
|
+
ini: (content: string) => {
|
|
812
|
+
const result: Record<string, string> = {};
|
|
813
|
+
for (const line of content.split('\n')) {
|
|
814
|
+
const [key, ...rest] = line.split('=');
|
|
815
|
+
if (key && rest.length > 0) {
|
|
816
|
+
result[key.trim()] = rest.join('=').trim();
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return result;
|
|
820
|
+
},
|
|
821
|
+
};
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
Custom formats can then be used in documents:
|
|
825
|
+
|
|
826
|
+
```markdown
|
|
827
|
+
<!--@embedoc-data:config format="ini"-->
|
|
828
|
+
host=localhost
|
|
829
|
+
port=5432
|
|
830
|
+
database=myapp
|
|
831
|
+
<!--@embedoc-data:end-->
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
716
836
|
## File Generation
|
|
717
837
|
|
|
718
838
|
Generate new files in bulk using Handlebars templates based on datasource records.
|
|
@@ -734,7 +854,7 @@ datasources:
|
|
|
734
854
|
### Template (Handlebars)
|
|
735
855
|
|
|
736
856
|
```handlebars
|
|
737
|
-
{{!-- templates/table_doc.hbs --}}
|
|
857
|
+
{{!-- .embedoc/templates/table_doc.hbs --}}
|
|
738
858
|
---
|
|
739
859
|
doc_id: "{{table_name}}"
|
|
740
860
|
embeds:
|
|
@@ -851,26 +971,31 @@ Frontmatter values can be referenced in marker attributes using `${...}` syntax.
|
|
|
851
971
|
|
|
852
972
|
```
|
|
853
973
|
your-project/
|
|
854
|
-
├── embedoc.config.yaml
|
|
855
|
-
├──
|
|
856
|
-
│ ├──
|
|
857
|
-
│ ├──
|
|
858
|
-
│
|
|
859
|
-
|
|
860
|
-
│ ├──
|
|
861
|
-
│
|
|
862
|
-
|
|
974
|
+
├── embedoc.config.yaml # Configuration file
|
|
975
|
+
├── .embedoc/ # All embedoc custom code
|
|
976
|
+
│ ├── renderers/ # Renderer definitions (TypeScript)
|
|
977
|
+
│ │ ├── index.ts # Export all renderers
|
|
978
|
+
│ │ ├── table_columns.ts
|
|
979
|
+
│ │ └── table_relations.ts
|
|
980
|
+
│ ├── datasources/ # Custom datasource types (TypeScript)
|
|
981
|
+
│ │ ├── index.ts # Export datasourceTypes and inlineFormats
|
|
982
|
+
│ │ └── github.ts
|
|
983
|
+
│ ├── templates/ # File generation templates (Handlebars)
|
|
984
|
+
│ │ ├── table_doc.hbs
|
|
985
|
+
│ │ └── view_doc.hbs
|
|
986
|
+
│ └── package.json # Optional: dependencies for custom code
|
|
987
|
+
├── data/ # Datasource files
|
|
863
988
|
│ ├── metadata.db
|
|
864
989
|
│ └── endpoints.csv
|
|
865
|
-
└── docs/
|
|
990
|
+
└── docs/ # Target documents
|
|
866
991
|
└── tables/
|
|
867
992
|
└── users.md
|
|
868
993
|
```
|
|
869
994
|
|
|
870
|
-
###
|
|
995
|
+
### Renderer Registration
|
|
871
996
|
|
|
872
997
|
```typescript
|
|
873
|
-
//
|
|
998
|
+
// .embedoc/renderers/index.ts
|
|
874
999
|
import tableColumns from './table_columns.ts';
|
|
875
1000
|
import tableRelations from './table_relations.ts';
|
|
876
1001
|
import customEmbed from './custom_embed.ts';
|
|
@@ -923,6 +1048,7 @@ npm test
|
|
|
923
1048
|
import {
|
|
924
1049
|
// Core
|
|
925
1050
|
defineEmbed,
|
|
1051
|
+
defineDatasource,
|
|
926
1052
|
build,
|
|
927
1053
|
processFile,
|
|
928
1054
|
|
|
@@ -1002,6 +1128,12 @@ interface InlineDatasourceConfig {
|
|
|
1002
1128
|
stripCodeFences?: boolean;
|
|
1003
1129
|
stripPatterns?: string[];
|
|
1004
1130
|
}
|
|
1131
|
+
|
|
1132
|
+
interface CustomDatasourceDefinition {
|
|
1133
|
+
create(config: DatasourceConfig): Promise<Datasource>;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
type InlineFormatParser = (content: string) => unknown;
|
|
1005
1137
|
```
|
|
1006
1138
|
|
|
1007
1139
|
---
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* embedoc CLI
|
|
4
4
|
*/
|
|
5
5
|
import { Command } from 'commander';
|
|
6
|
-
import { readFile, access } from 'node:fs/promises';
|
|
6
|
+
import { readFile, writeFile, access, mkdir } from 'node:fs/promises';
|
|
7
7
|
import { resolve, relative } from 'node:path';
|
|
8
8
|
import { pathToFileURL } from 'node:url';
|
|
9
9
|
import yaml from 'js-yaml';
|
|
@@ -18,7 +18,7 @@ const program = new Command();
|
|
|
18
18
|
program
|
|
19
19
|
.name('embedoc')
|
|
20
20
|
.description('In-Place Document Generator')
|
|
21
|
-
.version('0.
|
|
21
|
+
.version('0.11.0');
|
|
22
22
|
/**
|
|
23
23
|
* Load configuration file
|
|
24
24
|
*/
|
|
@@ -43,34 +43,208 @@ async function fileExists(filePath) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
46
|
+
* Resolve renderers_dir from config, with embeds_dir as deprecated fallback
|
|
47
47
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
function resolveRenderersDir(config) {
|
|
49
|
+
if (config.renderers_dir) {
|
|
50
|
+
return config.renderers_dir;
|
|
51
|
+
}
|
|
52
|
+
if (config.embeds_dir) {
|
|
53
|
+
console.warn(pc.yellow('Warning: "embeds_dir" is deprecated. Use "renderers_dir" instead.'));
|
|
54
|
+
return config.embeds_dir;
|
|
55
|
+
}
|
|
56
|
+
return '.embedoc/renderers';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Load renderers (supports both TypeScript and JavaScript)
|
|
60
|
+
*/
|
|
61
|
+
async function loadRenderers(renderersDir) {
|
|
62
|
+
const tsIndexPath = resolve(renderersDir, 'index.ts');
|
|
63
|
+
const jsIndexPath = resolve(renderersDir, 'index.js');
|
|
51
64
|
try {
|
|
52
|
-
// First try TypeScript file
|
|
53
65
|
if (await fileExists(tsIndexPath)) {
|
|
54
|
-
// Use tsx to directly import TypeScript
|
|
55
|
-
// tsImport may return { default: { embeds: ... } } or { embeds: ... }
|
|
56
66
|
const module = await tsImport(tsIndexPath, import.meta.url);
|
|
57
67
|
return module.embeds ?? module.default?.embeds ?? {};
|
|
58
68
|
}
|
|
59
|
-
// Fall back to JavaScript
|
|
60
69
|
if (await fileExists(jsIndexPath)) {
|
|
61
70
|
const moduleUrl = pathToFileURL(jsIndexPath).href;
|
|
62
71
|
const module = (await import(moduleUrl));
|
|
63
72
|
return module.embeds ?? {};
|
|
64
73
|
}
|
|
65
|
-
console.warn(pc.yellow(`Warning: No embeds found in ${embedsDir} (index.ts or index.js)`));
|
|
66
74
|
return {};
|
|
67
75
|
}
|
|
68
76
|
catch (error) {
|
|
69
77
|
const message = error instanceof Error ? error.message : String(error);
|
|
70
|
-
console.warn(pc.yellow(`Warning: Could not load
|
|
78
|
+
console.warn(pc.yellow(`Warning: Could not load renderers from ${renderersDir}: ${message}`));
|
|
71
79
|
return {};
|
|
72
80
|
}
|
|
73
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Load custom datasource types and inline format parsers from datasources_dir
|
|
84
|
+
*/
|
|
85
|
+
async function loadCustomDatasources(datasourcesDir) {
|
|
86
|
+
const tsIndexPath = resolve(datasourcesDir, 'index.ts');
|
|
87
|
+
const jsIndexPath = resolve(datasourcesDir, 'index.js');
|
|
88
|
+
const empty = { datasourceTypes: {}, inlineFormats: {} };
|
|
89
|
+
try {
|
|
90
|
+
let module;
|
|
91
|
+
if (await fileExists(tsIndexPath)) {
|
|
92
|
+
module = await tsImport(tsIndexPath, import.meta.url);
|
|
93
|
+
}
|
|
94
|
+
else if (await fileExists(jsIndexPath)) {
|
|
95
|
+
const moduleUrl = pathToFileURL(jsIndexPath).href;
|
|
96
|
+
module = (await import(moduleUrl));
|
|
97
|
+
}
|
|
98
|
+
if (!module) {
|
|
99
|
+
return empty;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
datasourceTypes: module.datasourceTypes ?? module.default?.datasourceTypes ?? {},
|
|
103
|
+
inlineFormats: module.inlineFormats ?? module.default?.inlineFormats ?? {},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
108
|
+
console.warn(pc.yellow(`Warning: Could not load custom datasources from ${datasourcesDir}: ${message}`));
|
|
109
|
+
return empty;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* init command
|
|
114
|
+
*/
|
|
115
|
+
program
|
|
116
|
+
.command('init')
|
|
117
|
+
.description('Initialize embedoc in the current project')
|
|
118
|
+
.option('-f, --force', 'Overwrite existing files')
|
|
119
|
+
.action(async (options) => {
|
|
120
|
+
try {
|
|
121
|
+
console.log(pc.cyan('📁 Initializing embedoc...\n'));
|
|
122
|
+
const created = [];
|
|
123
|
+
const skipped = [];
|
|
124
|
+
const writeIfNotExists = async (filePath, content) => {
|
|
125
|
+
const absPath = resolve(filePath);
|
|
126
|
+
if (!options.force && await fileExists(absPath)) {
|
|
127
|
+
skipped.push(filePath);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const dir = absPath.substring(0, absPath.lastIndexOf('/'));
|
|
131
|
+
await mkdir(dir, { recursive: true });
|
|
132
|
+
await writeFile(absPath, content, { encoding: 'utf-8' });
|
|
133
|
+
created.push(filePath);
|
|
134
|
+
};
|
|
135
|
+
// embedoc.config.yaml
|
|
136
|
+
const configContent = `version: "1.0"
|
|
137
|
+
|
|
138
|
+
targets:
|
|
139
|
+
- pattern: "./docs/**/*.md"
|
|
140
|
+
comment_style: html
|
|
141
|
+
exclude:
|
|
142
|
+
- "**/node_modules/**"
|
|
143
|
+
- "**/.git/**"
|
|
144
|
+
|
|
145
|
+
datasources: {}
|
|
146
|
+
# example_db:
|
|
147
|
+
# type: sqlite
|
|
148
|
+
# path: "./data/example.db"
|
|
149
|
+
# example_csv:
|
|
150
|
+
# type: csv
|
|
151
|
+
# path: "./data/example.csv"
|
|
152
|
+
`;
|
|
153
|
+
await writeIfNotExists('embedoc.config.yaml', configContent);
|
|
154
|
+
// .embedoc/renderers/index.ts
|
|
155
|
+
const renderersIndexContent = `/**
|
|
156
|
+
* embedoc renderers
|
|
157
|
+
*
|
|
158
|
+
* Export your custom renderers here.
|
|
159
|
+
* Each key becomes a marker name: <!--@embedoc:key_name ...-->
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
// import myRenderer from './my_renderer.ts';
|
|
163
|
+
|
|
164
|
+
export const embeds = {
|
|
165
|
+
// my_renderer: myRenderer,
|
|
166
|
+
};
|
|
167
|
+
`;
|
|
168
|
+
await writeIfNotExists('.embedoc/renderers/index.ts', renderersIndexContent);
|
|
169
|
+
// .embedoc/datasources/index.ts
|
|
170
|
+
const datasourcesIndexContent = `/**
|
|
171
|
+
* embedoc custom datasources and inline format parsers
|
|
172
|
+
*
|
|
173
|
+
* datasourceTypes: register custom datasource types usable in embedoc.config.yaml
|
|
174
|
+
* inlineFormats: register custom parsers for @embedoc-data format="xxx" markers
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
// import type { CustomDatasourceDefinition, InlineFormatParser } from 'embedoc';
|
|
178
|
+
// import myDatasource from './my_datasource.ts';
|
|
179
|
+
|
|
180
|
+
export const datasourceTypes = {
|
|
181
|
+
// my_datasource: myDatasource,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const inlineFormats = {
|
|
185
|
+
// toml: (content: string) => parseToml(content),
|
|
186
|
+
};
|
|
187
|
+
`;
|
|
188
|
+
await writeIfNotExists('.embedoc/datasources/index.ts', datasourcesIndexContent);
|
|
189
|
+
// .embedoc/templates/ (create directory only via a .gitkeep)
|
|
190
|
+
await writeIfNotExists('.embedoc/templates/.gitkeep', '');
|
|
191
|
+
// Update package.json if it exists
|
|
192
|
+
const pkgPath = resolve('package.json');
|
|
193
|
+
if (await fileExists(pkgPath)) {
|
|
194
|
+
const pkgRaw = await readFile(pkgPath, { encoding: 'utf-8' });
|
|
195
|
+
const pkg = JSON.parse(pkgRaw);
|
|
196
|
+
const scripts = (pkg['scripts'] ?? {});
|
|
197
|
+
let scriptsUpdated = false;
|
|
198
|
+
const scriptEntries = [
|
|
199
|
+
['embedoc:build', 'embedoc build'],
|
|
200
|
+
['embedoc:watch', 'embedoc watch'],
|
|
201
|
+
['embedoc:generate', 'embedoc generate --all'],
|
|
202
|
+
];
|
|
203
|
+
for (const [key, value] of scriptEntries) {
|
|
204
|
+
if (!(key in scripts)) {
|
|
205
|
+
scripts[key] = value;
|
|
206
|
+
scriptsUpdated = true;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (scriptsUpdated) {
|
|
210
|
+
pkg['scripts'] = scripts;
|
|
211
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', { encoding: 'utf-8' });
|
|
212
|
+
console.log(pc.green(' Updated package.json scripts:'));
|
|
213
|
+
for (const [key, value] of scriptEntries) {
|
|
214
|
+
if (!((pkgRaw.includes(`"${key}"`)))) {
|
|
215
|
+
console.log(pc.gray(` "${key}": "${value}"`));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
console.log('');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Summary
|
|
222
|
+
if (created.length > 0) {
|
|
223
|
+
console.log(pc.green(' Created:'));
|
|
224
|
+
for (const f of created) {
|
|
225
|
+
console.log(pc.gray(` ${f}`));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (skipped.length > 0) {
|
|
229
|
+
console.log(pc.yellow(' Skipped (already exists):'));
|
|
230
|
+
for (const f of skipped) {
|
|
231
|
+
console.log(pc.gray(` ${f}`));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
console.log('');
|
|
235
|
+
console.log(pc.green('✅ embedoc initialized!'));
|
|
236
|
+
console.log('');
|
|
237
|
+
console.log(' Next steps:');
|
|
238
|
+
console.log(pc.cyan(' 1. Edit embedoc.config.yaml to configure targets and datasources'));
|
|
239
|
+
console.log(pc.cyan(' 2. Add renderers in .embedoc/renderers/'));
|
|
240
|
+
console.log(pc.cyan(' 3. Run: npx embedoc build'));
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
console.error(pc.red('❌ Init failed:'));
|
|
244
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
74
248
|
/**
|
|
75
249
|
* build command
|
|
76
250
|
*/
|
|
@@ -85,16 +259,19 @@ program
|
|
|
85
259
|
try {
|
|
86
260
|
console.log(pc.cyan('🔧 Loading configuration...'));
|
|
87
261
|
const config = await loadConfig(options.config);
|
|
262
|
+
const datasourcesDir = config.datasources_dir ?? '.embedoc/datasources';
|
|
263
|
+
const customModules = await loadCustomDatasources(datasourcesDir);
|
|
88
264
|
console.log(pc.cyan('📦 Initializing datasources...'));
|
|
89
|
-
const datasources = initializeDatasources(config);
|
|
90
|
-
console.log(pc.cyan('📝 Loading
|
|
91
|
-
const
|
|
92
|
-
const embeds = await
|
|
265
|
+
const datasources = await initializeDatasources(config, customModules.datasourceTypes);
|
|
266
|
+
console.log(pc.cyan('📝 Loading renderers...'));
|
|
267
|
+
const renderersDir = resolveRenderersDir(config);
|
|
268
|
+
const embeds = await loadRenderers(renderersDir);
|
|
93
269
|
console.log(pc.cyan('🔄 Processing files...'));
|
|
94
270
|
const result = await build(config, embeds, datasources, {
|
|
95
271
|
dryRun: options.dryRun,
|
|
96
272
|
verbose: options.verbose,
|
|
97
273
|
specificFiles: files.length > 0 ? files : undefined,
|
|
274
|
+
customInlineFormats: customModules.inlineFormats,
|
|
98
275
|
});
|
|
99
276
|
// Cleanup
|
|
100
277
|
await closeDatasources(datasources);
|
|
@@ -148,8 +325,10 @@ program
|
|
|
148
325
|
}
|
|
149
326
|
console.log(pc.cyan('🔧 Loading configuration...'));
|
|
150
327
|
const config = await loadConfig(options.config);
|
|
328
|
+
const datasourcesDir = config.datasources_dir ?? '.embedoc/datasources';
|
|
329
|
+
const customModules = await loadCustomDatasources(datasourcesDir);
|
|
151
330
|
console.log(pc.cyan('📦 Initializing datasources...'));
|
|
152
|
-
const datasources = initializeDatasources(config);
|
|
331
|
+
const datasources = await initializeDatasources(config, customModules.datasourceTypes);
|
|
153
332
|
console.log(pc.cyan('📄 Generating files...'));
|
|
154
333
|
const results = await generateAll(config, datasources, {
|
|
155
334
|
dryRun: options.dryRun,
|
|
@@ -203,11 +382,13 @@ program
|
|
|
203
382
|
try {
|
|
204
383
|
console.log(pc.cyan('🔧 Loading configuration...'));
|
|
205
384
|
const config = await loadConfig(options.config);
|
|
385
|
+
const datasourcesDir = config.datasources_dir ?? '.embedoc/datasources';
|
|
386
|
+
const customModules = await loadCustomDatasources(datasourcesDir);
|
|
206
387
|
console.log(pc.cyan('📦 Initializing datasources...'));
|
|
207
|
-
let datasources = initializeDatasources(config);
|
|
208
|
-
console.log(pc.cyan('📝 Loading
|
|
209
|
-
const
|
|
210
|
-
let embeds = await
|
|
388
|
+
let datasources = await initializeDatasources(config, customModules.datasourceTypes);
|
|
389
|
+
console.log(pc.cyan('📝 Loading renderers...'));
|
|
390
|
+
const renderersDir = resolve(resolveRenderersDir(config));
|
|
391
|
+
let embeds = await loadRenderers(renderersDir);
|
|
211
392
|
// Build dependency graph
|
|
212
393
|
console.log(pc.cyan('🔗 Building dependency graph...'));
|
|
213
394
|
let depGraph = new DependencyGraph(config, embeds);
|
|
@@ -234,25 +415,23 @@ program
|
|
|
234
415
|
const processChanges = async () => {
|
|
235
416
|
const changes = new Map(pendingChanges);
|
|
236
417
|
pendingChanges.clear();
|
|
237
|
-
|
|
238
|
-
let embedsReloaded = false;
|
|
418
|
+
let renderersReloaded = false;
|
|
239
419
|
for (const [filePath] of changes) {
|
|
240
|
-
if (filePath.startsWith(
|
|
241
|
-
console.log(pc.yellow(`\n🔄
|
|
242
|
-
console.log(pc.cyan(' Reloading
|
|
420
|
+
if (filePath.startsWith(renderersDir) && filePath.endsWith('.ts')) {
|
|
421
|
+
console.log(pc.yellow(`\n🔄 Renderer changed: ${relative(process.cwd(), filePath)}`));
|
|
422
|
+
console.log(pc.cyan(' Reloading renderers...'));
|
|
243
423
|
try {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
embedsReloaded = true;
|
|
424
|
+
embeds = await loadRenderers(renderersDir);
|
|
425
|
+
renderersReloaded = true;
|
|
247
426
|
}
|
|
248
427
|
catch (error) {
|
|
249
|
-
console.error(pc.red(' Failed to reload
|
|
428
|
+
console.error(pc.red(' Failed to reload renderers:'), error);
|
|
250
429
|
return;
|
|
251
430
|
}
|
|
252
431
|
}
|
|
253
432
|
}
|
|
254
433
|
// Rebuild dependency graph if embeds were reloaded
|
|
255
|
-
if (
|
|
434
|
+
if (renderersReloaded) {
|
|
256
435
|
console.log(pc.cyan(' Rebuilding dependency graph...'));
|
|
257
436
|
depGraph = new DependencyGraph(config, embeds);
|
|
258
437
|
await depGraph.build();
|
|
@@ -291,10 +470,11 @@ program
|
|
|
291
470
|
try {
|
|
292
471
|
// Re-initialize datasources (especially for SQLite)
|
|
293
472
|
await closeDatasources(datasources);
|
|
294
|
-
datasources = initializeDatasources(config);
|
|
473
|
+
datasources = await initializeDatasources(config, customModules.datasourceTypes);
|
|
295
474
|
const result = await build(config, embeds, datasources, {
|
|
296
475
|
verbose: options.verbose,
|
|
297
476
|
specificFiles: Array.from(affectedDocs),
|
|
477
|
+
customInlineFormats: customModules.inlineFormats,
|
|
298
478
|
});
|
|
299
479
|
if (result.totalMarkersUpdated > 0) {
|
|
300
480
|
console.log(pc.green(` ✅ Updated ${result.totalMarkersUpdated} marker(s)`));
|