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