node-type-registry 0.4.0 → 0.5.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.
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ // GENERATED FILE — DO NOT EDIT
3
+ //
4
+ // Regenerate with:
5
+ // cd graphile/node-type-registry && pnpm generate:types
6
+ //
7
+ // These types match the JSONB shape expected by construct_blueprint().
8
+ // All field names are snake_case to match the SQL convention.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ /**
11
+ * ===========================================================================
12
+ * Data node type parameters
13
+ * ===========================================================================
14
+ */
15
+ ;
16
+ /**
17
+ * ===========================================================================
18
+ * Authz node type parameters
19
+ * ===========================================================================
20
+ */
21
+ ;
22
+ /**
23
+ * ===========================================================================
24
+ * Relation node type parameters
25
+ * ===========================================================================
26
+ */
27
+ ;
28
+ /**
29
+ * ===========================================================================
30
+ * View node type parameters
31
+ * ===========================================================================
32
+ */
33
+ ;
34
+ /**
35
+ * ===========================================================================
36
+ * Static structural types
37
+ * ===========================================================================
38
+ */
39
+ ;
40
+ /**
41
+ * ===========================================================================
42
+ * Node types -- discriminated union for nodes[] entries
43
+ * ===========================================================================
44
+ */
45
+ ;
46
+ /**
47
+ * ===========================================================================
48
+ * Relation types
49
+ * ===========================================================================
50
+ */
51
+ ;
52
+ /**
53
+ * ===========================================================================
54
+ * Blueprint table and definition
55
+ * ===========================================================================
56
+ */
57
+ ;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Generate TypeScript types for blueprint definitions from node type registry.
3
+ *
4
+ * Uses @babel/types AST nodes + schema-typescript for JSON Schema -> TS
5
+ * conversion. Produces a `blueprint-types.generated.ts` file with:
6
+ *
7
+ * - Per-node-type parameter interfaces (via schema-typescript)
8
+ * - BlueprintNode -- discriminated union of all non-relation node types
9
+ * - BlueprintRelation -- typed relation entries with $type, source_ref, target_ref
10
+ * - BlueprintTable, BlueprintField, BlueprintPolicy, BlueprintIndex, etc.
11
+ * - BlueprintDefinition -- the top-level type matching the JSONB shape
12
+ *
13
+ * These types are client-side only -- they provide autocomplete and type safety
14
+ * when building blueprint JSON. The API itself accepts plain JSONB.
15
+ *
16
+ * Usage:
17
+ * npx ts-node src/codegen/generate-types.ts [--outdir <dir>]
18
+ */
19
+ export {};
@@ -0,0 +1,373 @@
1
+ "use strict";
2
+ /**
3
+ * Generate TypeScript types for blueprint definitions from node type registry.
4
+ *
5
+ * Uses @babel/types AST nodes + schema-typescript for JSON Schema -> TS
6
+ * conversion. Produces a `blueprint-types.generated.ts` file with:
7
+ *
8
+ * - Per-node-type parameter interfaces (via schema-typescript)
9
+ * - BlueprintNode -- discriminated union of all non-relation node types
10
+ * - BlueprintRelation -- typed relation entries with $type, source_ref, target_ref
11
+ * - BlueprintTable, BlueprintField, BlueprintPolicy, BlueprintIndex, etc.
12
+ * - BlueprintDefinition -- the top-level type matching the JSONB shape
13
+ *
14
+ * These types are client-side only -- they provide autocomplete and type safety
15
+ * when building blueprint JSON. The API itself accepts plain JSONB.
16
+ *
17
+ * Usage:
18
+ * npx ts-node src/codegen/generate-types.ts [--outdir <dir>]
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
55
+ const generate = require('@babel/generator').default ?? require('@babel/generator');
56
+ const t = __importStar(require("@babel/types"));
57
+ const fs_1 = require("fs");
58
+ const path_1 = require("path");
59
+ const schema_typescript_1 = require("schema-typescript");
60
+ const index_1 = require("../index");
61
+ // ---------------------------------------------------------------------------
62
+ // Helpers
63
+ // ---------------------------------------------------------------------------
64
+ /** Attach a JSDoc-style leading comment to an AST node. */
65
+ function addJSDoc(node, description) {
66
+ node.leadingComments = [
67
+ { type: 'CommentBlock', value: `* ${description} ` },
68
+ ];
69
+ return node;
70
+ }
71
+ /** Create an optional TSPropertySignature. */
72
+ function optionalProp(name, typeAnnotation) {
73
+ const prop = t.tsPropertySignature(t.identifier(name), t.tsTypeAnnotation(typeAnnotation));
74
+ prop.optional = true;
75
+ return prop;
76
+ }
77
+ /** Create a required TSPropertySignature. */
78
+ function requiredProp(name, typeAnnotation) {
79
+ return t.tsPropertySignature(t.identifier(name), t.tsTypeAnnotation(typeAnnotation));
80
+ }
81
+ /** Create an exported interface declaration. */
82
+ function exportInterface(name, members) {
83
+ return t.exportNamedDeclaration(t.tsInterfaceDeclaration(t.identifier(name), null, [], t.tsInterfaceBody(members)));
84
+ }
85
+ /** Create an exported type alias. */
86
+ function exportTypeAlias(name, type) {
87
+ return t.exportNamedDeclaration(t.tsTypeAliasDeclaration(t.identifier(name), null, type));
88
+ }
89
+ /** Create a string literal type. */
90
+ function strLit(value) {
91
+ return t.tsLiteralType(t.stringLiteral(value));
92
+ }
93
+ /** Create a union of string literals. */
94
+ function strUnion(values) {
95
+ if (values.length === 1)
96
+ return strLit(values[0]);
97
+ return t.tsUnionType(values.map(strLit));
98
+ }
99
+ /** Create Record<K, V> type reference. */
100
+ function recordType(keyType, valueType) {
101
+ return t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([keyType, valueType]));
102
+ }
103
+ /** Create Partial<T> type reference. */
104
+ function partialOf(inner) {
105
+ return t.tsTypeReference(t.identifier('Partial'), t.tsTypeParameterInstantiation([inner]));
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Schema sanitizer — ensures array types have an items spec (schema-typescript
109
+ // throws without one). Numeric/boolean enum handling is fixed upstream as of
110
+ // schema-typescript@0.14.2.
111
+ // ---------------------------------------------------------------------------
112
+ function ensureArrayItems(schema) {
113
+ const out = { ...schema };
114
+ // Ensure arrays have an items spec (schema-typescript throws without one)
115
+ if (out.type === 'array' && !out.items) {
116
+ out.items = { type: 'string' };
117
+ }
118
+ // Recurse into properties
119
+ if (out.properties && typeof out.properties === 'object') {
120
+ const props = {};
121
+ for (const [k, v] of Object.entries(out.properties)) {
122
+ props[k] = v && typeof v === 'object' ? ensureArrayItems(v) : v;
123
+ }
124
+ out.properties = props;
125
+ }
126
+ // Recurse into items
127
+ if (out.items && typeof out.items === 'object') {
128
+ out.items = ensureArrayItems(out.items);
129
+ }
130
+ // Recurse into composition keywords
131
+ for (const keyword of ['oneOf', 'anyOf', 'allOf']) {
132
+ if (Array.isArray(out[keyword])) {
133
+ out[keyword] = out[keyword].map((s) => s && typeof s === 'object' ? ensureArrayItems(s) : s);
134
+ }
135
+ }
136
+ return out;
137
+ }
138
+ // ---------------------------------------------------------------------------
139
+ // Generate per-node-type parameter interfaces via schema-typescript
140
+ // ---------------------------------------------------------------------------
141
+ function generateParamsInterfaces(nodeTypes) {
142
+ const results = [];
143
+ for (const nt of nodeTypes) {
144
+ const schema = nt.parameter_schema;
145
+ const typeName = `${nt.name}Params`;
146
+ const sanitized = ensureArrayItems({ ...schema, title: typeName });
147
+ const astNodes = (0, schema_typescript_1.generateTypeScriptTypes)(sanitized, {
148
+ includePropertyComments: true,
149
+ includeTypeComments: false,
150
+ strictTypeSafety: true,
151
+ });
152
+ if (astNodes.length > 0) {
153
+ // The last node is the main interface for the title
154
+ const mainNode = astNodes[astNodes.length - 1];
155
+ addJSDoc(mainNode, nt.description);
156
+ for (const node of astNodes) {
157
+ results.push(node);
158
+ }
159
+ }
160
+ else {
161
+ // Fallback: empty interface for node types with no properties
162
+ results.push(addJSDoc(exportInterface(typeName, []), nt.description));
163
+ }
164
+ }
165
+ return results;
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // Static structural types (BlueprintField, BlueprintPolicy, etc.)
169
+ // ---------------------------------------------------------------------------
170
+ function buildBlueprintField() {
171
+ return addJSDoc(exportInterface('BlueprintField', [
172
+ addJSDoc(requiredProp('name', t.tsStringKeyword()), 'The column name.'),
173
+ addJSDoc(requiredProp('type', t.tsStringKeyword()), 'The PostgreSQL type (e.g., "text", "integer", "boolean", "uuid").'),
174
+ addJSDoc(optionalProp('is_required', t.tsBooleanKeyword()), 'Whether the column has a NOT NULL constraint.'),
175
+ addJSDoc(optionalProp('default_value', t.tsStringKeyword()), 'SQL default value expression (e.g., "true", "now()").'),
176
+ addJSDoc(optionalProp('description', t.tsStringKeyword()), 'Comment/description for this field.'),
177
+ ]), 'A custom field (column) to add to a blueprint table.');
178
+ }
179
+ function buildBlueprintPolicy(authzNodes) {
180
+ const policyTypeAnnotation = authzNodes.length > 0
181
+ ? strUnion(authzNodes.map((nt) => nt.name))
182
+ : t.tsStringKeyword();
183
+ return addJSDoc(exportInterface('BlueprintPolicy', [
184
+ addJSDoc(requiredProp('$type', policyTypeAnnotation), 'Authz* policy type name (e.g., "AuthzDirectOwner", "AuthzAllowAll").'),
185
+ addJSDoc(optionalProp('policy_role', t.tsStringKeyword()), 'Role for this policy. Defaults to "authenticated".'),
186
+ addJSDoc(optionalProp('permissive', t.tsBooleanKeyword()), 'Whether this policy is permissive (true) or restrictive (false).'),
187
+ addJSDoc(optionalProp('policy_name', t.tsStringKeyword()), 'Optional custom name for this policy.'),
188
+ addJSDoc(optionalProp('privileges', t.tsArrayType(t.tsStringKeyword())), 'Privileges this policy applies to.'),
189
+ addJSDoc(optionalProp('data', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Policy-specific data (structure varies by policy type).'),
190
+ ]), 'An RLS policy entry for a blueprint table.');
191
+ }
192
+ function buildBlueprintFtsSource() {
193
+ return addJSDoc(exportInterface('BlueprintFtsSource', [
194
+ addJSDoc(requiredProp('field', t.tsStringKeyword()), 'Column name of the source field.'),
195
+ addJSDoc(requiredProp('weight', t.tsStringKeyword()), 'TSVector weight: "A", "B", "C", or "D".'),
196
+ addJSDoc(optionalProp('lang', t.tsStringKeyword()), 'Language for text search. Defaults to "english".'),
197
+ ]), 'A source field contributing to a full-text search tsvector column.');
198
+ }
199
+ function buildBlueprintFullTextSearch() {
200
+ return addJSDoc(exportInterface('BlueprintFullTextSearch', [
201
+ addJSDoc(requiredProp('table_ref', t.tsStringKeyword()), 'Reference key of the table this full-text search belongs to.'),
202
+ addJSDoc(requiredProp('field', t.tsStringKeyword()), 'Name of the tsvector field on the table.'),
203
+ addJSDoc(requiredProp('sources', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFtsSource')))), 'Source fields that feed into this tsvector.'),
204
+ ]), 'A full-text search configuration for a blueprint table.');
205
+ }
206
+ function buildBlueprintIndex() {
207
+ return addJSDoc(exportInterface('BlueprintIndex', [
208
+ addJSDoc(requiredProp('table_ref', t.tsStringKeyword()), 'Reference key of the table this index belongs to.'),
209
+ addJSDoc(optionalProp('column', t.tsStringKeyword()), 'Single column name for the index. Mutually exclusive with "columns".'),
210
+ addJSDoc(optionalProp('columns', t.tsArrayType(t.tsStringKeyword())), 'Array of column names for a multi-column index. Mutually exclusive with "column".'),
211
+ addJSDoc(requiredProp('access_method', t.tsStringKeyword()), 'Index access method (e.g., "BTREE", "GIN", "GIST", "HNSW", "BM25").'),
212
+ addJSDoc(optionalProp('is_unique', t.tsBooleanKeyword()), 'Whether this is a unique index.'),
213
+ addJSDoc(optionalProp('name', t.tsStringKeyword()), 'Optional custom name for the index.'),
214
+ addJSDoc(optionalProp('op_classes', t.tsArrayType(t.tsStringKeyword())), 'Operator classes for the index columns.'),
215
+ addJSDoc(optionalProp('options', recordType(t.tsStringKeyword(), t.tsUnknownKeyword())), 'Additional index-specific options.'),
216
+ ]), 'An index definition within a blueprint.');
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // Node type discriminated unions
220
+ // ---------------------------------------------------------------------------
221
+ function buildNodeTypes(dataNodes) {
222
+ const results = [];
223
+ // BlueprintNodeShorthand -- union of string literals
224
+ results.push(addJSDoc(exportTypeAlias('BlueprintNodeShorthand', strUnion(dataNodes.map((nt) => nt.name))), 'String shorthand -- just the node type name.'));
225
+ // BlueprintNodeObject -- discriminated union of { $type, data } objects
226
+ const objectMembers = dataNodes.map((nt) => {
227
+ const hasParams = nt.parameter_schema.properties &&
228
+ Object.keys(nt.parameter_schema.properties).length > 0;
229
+ const dataType = hasParams
230
+ ? t.tsTypeReference(t.identifier(`${nt.name}Params`))
231
+ : recordType(t.tsStringKeyword(), t.tsNeverKeyword());
232
+ const dataProp = hasParams
233
+ ? requiredProp('data', dataType)
234
+ : optionalProp('data', dataType);
235
+ return t.tsTypeLiteral([requiredProp('$type', strLit(nt.name)), dataProp]);
236
+ });
237
+ results.push(addJSDoc(exportTypeAlias('BlueprintNodeObject', t.tsUnionType(objectMembers)), 'Object form -- { $type, data } with typed parameters.'));
238
+ // BlueprintNode -- shorthand | object
239
+ results.push(addJSDoc(exportTypeAlias('BlueprintNode', t.tsUnionType([
240
+ t.tsTypeReference(t.identifier('BlueprintNodeShorthand')),
241
+ t.tsTypeReference(t.identifier('BlueprintNodeObject')),
242
+ ])), 'A node entry in a blueprint table. Either a string shorthand or a typed object.'));
243
+ return results;
244
+ }
245
+ // ---------------------------------------------------------------------------
246
+ // Relation types
247
+ // ---------------------------------------------------------------------------
248
+ function buildRelationTypes(relationNodes) {
249
+ const relationMembers = relationNodes.map((nt) => {
250
+ const baseType = t.tsTypeLiteral([
251
+ requiredProp('$type', strLit(nt.name)),
252
+ requiredProp('source_ref', t.tsStringKeyword()),
253
+ requiredProp('target_ref', t.tsStringKeyword()),
254
+ ]);
255
+ return t.tsIntersectionType([
256
+ baseType,
257
+ partialOf(t.tsTypeReference(t.identifier(`${nt.name}Params`))),
258
+ ]);
259
+ });
260
+ return [
261
+ addJSDoc(exportTypeAlias('BlueprintRelation', t.tsUnionType(relationMembers)), 'A relation entry in a blueprint definition.'),
262
+ ];
263
+ }
264
+ // ---------------------------------------------------------------------------
265
+ // BlueprintTable and BlueprintDefinition
266
+ // ---------------------------------------------------------------------------
267
+ function buildBlueprintTable() {
268
+ return addJSDoc(exportInterface('BlueprintTable', [
269
+ addJSDoc(requiredProp('ref', t.tsStringKeyword()), 'Local reference key for this table (used by relations, indexes, fts).'),
270
+ addJSDoc(requiredProp('table_name', t.tsStringKeyword()), 'The PostgreSQL table name to create.'),
271
+ addJSDoc(requiredProp('nodes', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintNode')))), "Array of node type entries that define the table's behavior."),
272
+ addJSDoc(optionalProp('fields', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintField')))), 'Custom fields (columns) to add to the table.'),
273
+ addJSDoc(optionalProp('policies', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintPolicy')))), 'RLS policies for this table.'),
274
+ addJSDoc(optionalProp('grant_roles', t.tsArrayType(t.tsStringKeyword())), 'Database roles to grant privileges to. Defaults to ["authenticated"].'),
275
+ addJSDoc(optionalProp('grants', t.tsArrayType(t.tsUnknownKeyword())), 'Privilege grants as [verb, column] tuples or objects.'),
276
+ addJSDoc(optionalProp('use_rls', t.tsBooleanKeyword()), 'Whether to enable RLS on this table. Defaults to true.'),
277
+ ]), 'A table definition within a blueprint.');
278
+ }
279
+ function buildBlueprintDefinition() {
280
+ return addJSDoc(exportInterface('BlueprintDefinition', [
281
+ addJSDoc(requiredProp('tables', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintTable')))), 'Tables to create.'),
282
+ addJSDoc(optionalProp('relations', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintRelation')))), 'Relations between tables.'),
283
+ addJSDoc(optionalProp('indexes', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintIndex')))), 'Indexes on table columns.'),
284
+ addJSDoc(optionalProp('full_text_searches', t.tsArrayType(t.tsTypeReference(t.identifier('BlueprintFullTextSearch')))), 'Full-text search configurations.'),
285
+ ]), 'The complete blueprint definition -- the JSONB shape accepted by construct_blueprint().');
286
+ }
287
+ // ---------------------------------------------------------------------------
288
+ // Section comment helper
289
+ // ---------------------------------------------------------------------------
290
+ function sectionComment(title) {
291
+ const empty = t.emptyStatement();
292
+ empty.leadingComments = [
293
+ {
294
+ type: 'CommentBlock',
295
+ value: `*\n * ===========================================================================\n * ${title}\n * ===========================================================================\n `,
296
+ },
297
+ ];
298
+ return empty;
299
+ }
300
+ // ---------------------------------------------------------------------------
301
+ // Main generator
302
+ // ---------------------------------------------------------------------------
303
+ function buildProgram() {
304
+ const statements = [];
305
+ // Group node types by category
306
+ const categories = new Map();
307
+ for (const nt of index_1.allNodeTypes) {
308
+ const list = categories.get(nt.category) ?? [];
309
+ list.push(nt);
310
+ categories.set(nt.category, list);
311
+ }
312
+ const dataNodes = index_1.allNodeTypes.filter((nt) => nt.category !== 'relation' && nt.category !== 'view');
313
+ const relationNodes = index_1.allNodeTypes.filter((nt) => nt.category === 'relation');
314
+ const authzNodes = index_1.allNodeTypes.filter((nt) => nt.category === 'authz');
315
+ // -- Parameter interfaces grouped by category --
316
+ const categoryOrder = ['data', 'authz', 'relation', 'view'];
317
+ for (const cat of categoryOrder) {
318
+ const nts = categories.get(cat);
319
+ if (!nts || nts.length === 0)
320
+ continue;
321
+ statements.push(sectionComment(`${cat.charAt(0).toUpperCase() + cat.slice(1)} node type parameters`));
322
+ statements.push(...generateParamsInterfaces(nts));
323
+ }
324
+ // -- Static structural types --
325
+ statements.push(sectionComment('Static structural types'));
326
+ statements.push(buildBlueprintField());
327
+ statements.push(buildBlueprintPolicy(authzNodes));
328
+ statements.push(buildBlueprintFtsSource());
329
+ statements.push(buildBlueprintFullTextSearch());
330
+ statements.push(buildBlueprintIndex());
331
+ // -- Node types discriminated union --
332
+ statements.push(sectionComment('Node types -- discriminated union for nodes[] entries'));
333
+ statements.push(...buildNodeTypes(dataNodes));
334
+ // -- Relation types --
335
+ statements.push(sectionComment('Relation types'));
336
+ statements.push(...buildRelationTypes(relationNodes));
337
+ // -- Blueprint table and definition --
338
+ statements.push(sectionComment('Blueprint table and definition'));
339
+ statements.push(buildBlueprintTable());
340
+ statements.push(buildBlueprintDefinition());
341
+ // Build the full AST and render to code
342
+ const program = t.program(statements);
343
+ const file = t.file(program);
344
+ const header = [
345
+ '// GENERATED FILE \u2014 DO NOT EDIT',
346
+ '//',
347
+ '// Regenerate with:',
348
+ '// cd graphile/node-type-registry && pnpm generate:types',
349
+ '//',
350
+ '// These types match the JSONB shape expected by construct_blueprint().',
351
+ '// All field names are snake_case to match the SQL convention.',
352
+ '',
353
+ '',
354
+ ].join('\n');
355
+ const output = generate(file, { comments: true });
356
+ return header + output.code + '\n';
357
+ }
358
+ // ---------------------------------------------------------------------------
359
+ // CLI
360
+ // ---------------------------------------------------------------------------
361
+ function main() {
362
+ const args = process.argv.slice(2);
363
+ const outdirIdx = args.indexOf('--outdir');
364
+ const outdir = outdirIdx !== -1 ? args[outdirIdx + 1] : (0, path_1.join)(__dirname, '..');
365
+ const content = buildProgram();
366
+ const filename = 'blueprint-types.generated.ts';
367
+ const filepath = (0, path_1.join)(outdir, filename);
368
+ if (!(0, fs_1.existsSync)(outdir))
369
+ (0, fs_1.mkdirSync)(outdir, { recursive: true });
370
+ (0, fs_1.writeFileSync)(filepath, content);
371
+ console.log(`Generated ${filepath} (${index_1.allNodeTypes.length} node types)`);
372
+ }
373
+ main();