@lunora/codegen 1.0.0-alpha.5 → 1.0.0-alpha.50
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.md +6 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +1950 -734
- package/dist/index.d.ts +1950 -734
- package/dist/index.mjs +32 -24
- package/dist/packem_shared/AGENTS_FILENAME-Cxx7wiSs.mjs +158 -0
- package/dist/packem_shared/{CONTAINERS_FILENAME-0K-pjNb8.mjs → CONTAINERS_FILENAME-DjpXMqhp.mjs} +1 -1
- package/dist/packem_shared/{CodegenDiagnosticError-54jWDxA9.mjs → CodegenDiagnosticError-DyQ5FwkM.mjs} +7 -5
- package/dist/packem_shared/FLAGS_FILENAME-Dg4mKUuz.mjs +139 -0
- package/dist/packem_shared/GENERATED_HEADER-C5paWNYO.mjs +4 -0
- package/dist/packem_shared/{LUNORA_ERROR_CODES-CySpQPD3.mjs → LUNORA_ERROR_CODES-DvTLozCu.mjs} +8 -1
- package/dist/packem_shared/MUTATORS_FILENAME-BZOfUhlY.mjs +81 -0
- package/dist/packem_shared/{OPENRPC_VERSION-C7zKVeKi.mjs → OPENRPC_VERSION-7A2weq2u.mjs} +2 -2
- package/dist/packem_shared/QUEUES_FILENAME-Xv6Vy-Ku.mjs +145 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-G5dkcxPR.mjs +3502 -0
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_VERSION-DzLDbWk3.mjs → SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs} +18 -2
- package/dist/packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs +94 -0
- package/dist/packem_shared/WORKFLOWS_FILENAME-Dtuzvluc.mjs +158 -0
- package/dist/packem_shared/{buildOpenApiDocument-Cns1EkCQ.mjs → buildOpenApiDocument-B7mEdzA2.mjs} +2 -2
- package/dist/packem_shared/{discoverAuthApiCalls-C35R6z0T.mjs → discoverAuthApiCalls-Dx3K42rk.mjs} +1 -1
- package/dist/packem_shared/{discoverCrons-BL6iGuJ3.mjs → discoverCrons-DvqkEWdx.mjs} +68 -36
- package/dist/packem_shared/{discoverFunctions-DEgAcRuD.mjs → discoverFunctions-BJ-qR7Rg.mjs} +72 -14
- package/dist/packem_shared/{discoverHttpRoutes-C978pBiG.mjs → discoverHttpRoutes-daCzuTe8.mjs} +10 -2
- package/dist/packem_shared/{discoverInserts-CRQdXvHO.mjs → discoverInserts-DI4q5NxE.mjs} +24 -2
- package/dist/packem_shared/{discoverMaskProcedures-B64zA740.mjs → discoverMaskProcedures-BcTOEKNU.mjs} +58 -2
- package/dist/packem_shared/{discoverMigrations-Doj_-BAA.mjs → discoverMigrations-VNUFvCwr.mjs} +10 -4
- package/dist/packem_shared/{discoverNondeterministicCalls-4KiPQxQU.mjs → discoverNondeterministicCalls-S0N2xLCq.mjs} +1 -1
- package/dist/packem_shared/{discoverQueries-BkIi0dBD.mjs → discoverQueries-CJnnnLpd.mjs} +1 -1
- package/dist/packem_shared/{discoverR2sqlCalls-BpDqvcUn.mjs → discoverR2sqlCalls-pnpicWfz.mjs} +1 -1
- package/dist/packem_shared/{discoverRlsMetadata-DpRB1HMe.mjs → discoverRlsMetadata-DppniPUH.mjs} +1 -1
- package/dist/packem_shared/discoverSandboxUsage-BUM2r90k.mjs +38 -0
- package/dist/packem_shared/{discoverSchema-DB_QrIQe.mjs → discoverSchema-BaSAvooG.mjs} +326 -14
- package/dist/packem_shared/{discoverStorageRulesMetadata-DAqJUxUv.mjs → discoverStorageRulesMetadata-CnHl2rXD.mjs} +1 -1
- package/dist/packem_shared/{GENERATED_HEADER-DF1hQcix.mjs → emit-ClTbCLy4.mjs} +1458 -154
- package/dist/packem_shared/{emitApp-Ci_hcJNO.mjs → emitApp-CzzrjVqH.mjs} +129 -31
- package/dist/packem_shared/formatAdvisories-BmF7Mplc.mjs +115 -0
- package/dist/packem_shared/{parse-validator-tuQtHrsr.mjs → parse-validator-BSJo1HGP.mjs} +18 -6
- package/dist/packem_shared/redact-oTmsol5A.mjs +33 -0
- package/package.json +10 -7
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-BqOtU2lC.mjs +0 -922
- package/dist/packem_shared/WORKFLOWS_FILENAME-DRDQdhfq.mjs +0 -84
- package/dist/packem_shared/formatAdvisories-8NIv1k0I.mjs +0 -69
|
@@ -1,6 +1,213 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { Node, SyntaxKind } from 'ts-morph';
|
|
3
|
+
import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
|
|
4
|
+
import { a as parseObjectShape } from './parse-validator-BSJo1HGP.mjs';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
|
|
8
|
+
const renderLiteralValue = (value) => {
|
|
9
|
+
switch (typeof value) {
|
|
10
|
+
case "bigint": {
|
|
11
|
+
return value.toString();
|
|
12
|
+
}
|
|
13
|
+
case "boolean":
|
|
14
|
+
case "number": {
|
|
15
|
+
return String(value);
|
|
16
|
+
}
|
|
17
|
+
case "string": {
|
|
18
|
+
return JSON.stringify(value);
|
|
19
|
+
}
|
|
20
|
+
default: {
|
|
21
|
+
return value === null ? "null" : void 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const columnMetaToIR = (column) => {
|
|
26
|
+
const hasDefault = column?.["defaultValue"] !== void 0 || column?.["defaultFn"] !== void 0 || column?.["serverDefault"] !== void 0;
|
|
27
|
+
return {
|
|
28
|
+
...hasDefault ? { hasDefault: true } : {},
|
|
29
|
+
...column?.["onUpdateFn"] === void 0 ? {} : { hasOnUpdate: true },
|
|
30
|
+
notNull: column?.["notNull"] ?? true,
|
|
31
|
+
...column?.["unique"] === true ? { unique: true } : {}
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const runtimeValidatorToIR = (validator) => {
|
|
35
|
+
const meta = validator?._meta ?? {};
|
|
36
|
+
const kind = validator?.kind ?? "unknown";
|
|
37
|
+
const ir = { column: columnMetaToIR(meta["column"]), kind };
|
|
38
|
+
switch (kind) {
|
|
39
|
+
case "array":
|
|
40
|
+
case "optional": {
|
|
41
|
+
ir.inner = runtimeValidatorToIR(meta["inner"]);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "id": {
|
|
45
|
+
ir.tableName = meta["tableName"];
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case "literal": {
|
|
49
|
+
ir.literalValue = renderLiteralValue(meta["value"]);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case "object": {
|
|
53
|
+
const shape = meta["shape"] ?? {};
|
|
54
|
+
ir.shape = Object.fromEntries(Object.entries(shape).map(([name, child]) => [name, runtimeValidatorToIR(child)]));
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case "record": {
|
|
58
|
+
ir.valueType = runtimeValidatorToIR(meta["valueValidator"]);
|
|
59
|
+
if (meta["keyValidator"] !== void 0) {
|
|
60
|
+
ir.keyType = runtimeValidatorToIR(meta["keyValidator"]);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "storage": {
|
|
65
|
+
if (typeof meta["bucket"] === "string") {
|
|
66
|
+
ir.bucket = meta["bucket"];
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "union": {
|
|
71
|
+
const members = meta["members"] ?? [];
|
|
72
|
+
ir.members = members.map((member) => runtimeValidatorToIR(member));
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return ir;
|
|
77
|
+
};
|
|
78
|
+
const shardModeToIR = (shardMode) => {
|
|
79
|
+
if (shardMode?.kind === "global") {
|
|
80
|
+
return "global";
|
|
81
|
+
}
|
|
82
|
+
if (shardMode?.kind === "shardBy" && typeof shardMode.field === "string") {
|
|
83
|
+
return { field: shardMode.field, kind: "shardBy" };
|
|
84
|
+
}
|
|
85
|
+
return "root";
|
|
86
|
+
};
|
|
87
|
+
const warnDroppedTableFeatures = (builder, bareName) => {
|
|
88
|
+
const dropped = [];
|
|
89
|
+
if (builder.relationMap && Object.keys(builder.relationMap).length > 0) {
|
|
90
|
+
dropped.push("relations");
|
|
91
|
+
}
|
|
92
|
+
if (builder.rankIndexes && builder.rankIndexes.length > 0) {
|
|
93
|
+
dropped.push("rank indexes");
|
|
94
|
+
}
|
|
95
|
+
if (builder.vectorIndexes && builder.vectorIndexes.length > 0) {
|
|
96
|
+
dropped.push("vector indexes");
|
|
97
|
+
}
|
|
98
|
+
if (dropped.length > 0) {
|
|
99
|
+
console.warn(
|
|
100
|
+
`@lunora/codegen: package schema-extension table "${bareName}" declares ${dropped.join(" + ")}, which are not yet introspected from a node_modules extension — they will be absent from the generated types.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const runtimeTableToIR = (builder, bareName) => {
|
|
105
|
+
const shape = builder.shape ?? {};
|
|
106
|
+
const indexes = (builder.indexes ?? []).map((index) => {
|
|
107
|
+
return { fields: index.fields, name: index.name, ...index.unique ? { unique: true } : {} };
|
|
108
|
+
});
|
|
109
|
+
warnDroppedTableFeatures(builder, bareName);
|
|
110
|
+
return {
|
|
111
|
+
...builder.isExternallyManaged ? { externallyManaged: true } : {},
|
|
112
|
+
indexes,
|
|
113
|
+
name: bareName,
|
|
114
|
+
rankIndexes: [],
|
|
115
|
+
relations: [],
|
|
116
|
+
searchIndexes: (builder.searchIndexes ?? []).map((index) => {
|
|
117
|
+
return {
|
|
118
|
+
field: index.field,
|
|
119
|
+
...index.filterFields ? { filterFields: index.filterFields } : {},
|
|
120
|
+
name: index.name
|
|
121
|
+
};
|
|
122
|
+
}),
|
|
123
|
+
shape: Object.fromEntries(Object.entries(shape).map(([name, validator]) => [name, runtimeValidatorToIR(validator)])),
|
|
124
|
+
shardMode: shardModeToIR(builder.shardMode),
|
|
125
|
+
// Inline vector/rank indexes and relations are not yet introspected from a
|
|
126
|
+
// package extension; their presence is surfaced via `warnDroppedTableFeatures`.
|
|
127
|
+
vectorIndexes: []
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
const resolvedExtensionToIR = (value) => {
|
|
131
|
+
const { key, tables } = value;
|
|
132
|
+
if (typeof key !== "string" || typeof tables !== "object" || tables === null) {
|
|
133
|
+
return void 0;
|
|
134
|
+
}
|
|
135
|
+
const bareTables = Object.entries(tables).map(([bareName, builder]) => runtimeTableToIR(builder, bareName));
|
|
136
|
+
const vectorIndexes = value["vectorIndexes"] ?? {};
|
|
137
|
+
const bareVectorIndexes = Object.entries(vectorIndexes ?? {}).map(([name, index]) => {
|
|
138
|
+
return {
|
|
139
|
+
...index.dimensions === void 0 ? {} : { dimensions: index.dimensions },
|
|
140
|
+
...index.field === void 0 ? {} : { field: index.field },
|
|
141
|
+
...index.metadata === void 0 ? {} : { metadata: index.metadata },
|
|
142
|
+
...index.metric === void 0 ? {} : { metric: index.metric },
|
|
143
|
+
name,
|
|
144
|
+
table: index.table ?? ""
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
return { bareTables, bareVectorIndexes, key };
|
|
148
|
+
};
|
|
149
|
+
const receiverIdentifierText = (argument) => {
|
|
150
|
+
if (Node.isIdentifier(argument)) {
|
|
151
|
+
return argument.getText();
|
|
152
|
+
}
|
|
153
|
+
if (Node.isPropertyAccessExpression(argument)) {
|
|
154
|
+
const receiver = argument.getExpression();
|
|
155
|
+
return Node.isIdentifier(receiver) ? receiver.getText() : void 0;
|
|
156
|
+
}
|
|
157
|
+
return void 0;
|
|
158
|
+
};
|
|
159
|
+
const accessPathOf = (argument) => {
|
|
160
|
+
const receiverName = receiverIdentifierText(argument);
|
|
161
|
+
if (receiverName === void 0) {
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
const property = Node.isPropertyAccessExpression(argument) ? argument.getName() : void 0;
|
|
165
|
+
const propertyPath = property === void 0 ? [] : [property];
|
|
166
|
+
for (const declaration of argument.getSourceFile().getImportDeclarations()) {
|
|
167
|
+
const moduleSpecifier = declaration.getModuleSpecifierValue();
|
|
168
|
+
for (const named of declaration.getNamedImports()) {
|
|
169
|
+
const localName = named.getAliasNode()?.getText() ?? named.getName();
|
|
170
|
+
if (localName === receiverName) {
|
|
171
|
+
return { importedName: named.getName(), moduleSpecifier, propertyPath };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (declaration.getDefaultImport()?.getText() === receiverName) {
|
|
175
|
+
return { importedName: "default", moduleSpecifier, propertyPath };
|
|
176
|
+
}
|
|
177
|
+
if (declaration.getNamespaceImport()?.getText() === receiverName && property !== void 0) {
|
|
178
|
+
return { importedName: property, moduleSpecifier, propertyPath: [] };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return void 0;
|
|
182
|
+
};
|
|
183
|
+
const readExtensionValue = (module_, access) => {
|
|
184
|
+
let current = module_[access.importedName];
|
|
185
|
+
for (const segment of access.propertyPath) {
|
|
186
|
+
if (typeof current !== "object" || current === null) {
|
|
187
|
+
return void 0;
|
|
188
|
+
}
|
|
189
|
+
current = current[segment];
|
|
190
|
+
}
|
|
191
|
+
return current;
|
|
192
|
+
};
|
|
193
|
+
const resolvePackageExtension = (argument, projectRoot) => {
|
|
194
|
+
const access = accessPathOf(argument);
|
|
195
|
+
if (!access) {
|
|
196
|
+
return void 0;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const projectRequire = createRequire(join(projectRoot, "noop.cjs"));
|
|
200
|
+
const resolved = projectRequire.resolve(access.moduleSpecifier);
|
|
201
|
+
const loadedModule = projectRequire(resolved);
|
|
202
|
+
const value = readExtensionValue(loadedModule, access);
|
|
203
|
+
if (typeof value !== "object" || value === null) {
|
|
204
|
+
return void 0;
|
|
205
|
+
}
|
|
206
|
+
return resolvedExtensionToIR(value);
|
|
207
|
+
} catch {
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
4
211
|
|
|
5
212
|
const VECTOR_METRICS = /* @__PURE__ */ new Set(["cosine", "dot-product", "euclidean"]);
|
|
6
213
|
const ON_DELETE_ACTIONS = /* @__PURE__ */ new Set(["cascade", "restrict", "set null"]);
|
|
@@ -179,6 +386,55 @@ const parseGlobalBackend = (args) => {
|
|
|
179
386
|
}
|
|
180
387
|
return "d1";
|
|
181
388
|
};
|
|
389
|
+
const softDeleteFieldOf = (optionsArgument) => {
|
|
390
|
+
if (optionsArgument && Node.isObjectLiteralExpression(optionsArgument)) {
|
|
391
|
+
const fieldProperty = optionsArgument.getProperty("field");
|
|
392
|
+
if (fieldProperty && Node.isPropertyAssignment(fieldProperty)) {
|
|
393
|
+
const initializer = fieldProperty.getInitializer();
|
|
394
|
+
if (initializer && Node.isStringLiteral(initializer)) {
|
|
395
|
+
return initializer.getLiteralText();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return "deletedAt";
|
|
400
|
+
};
|
|
401
|
+
const stringPropertyOf = (object, property) => {
|
|
402
|
+
const node = object.getProperty(property);
|
|
403
|
+
if (node && Node.isPropertyAssignment(node)) {
|
|
404
|
+
const initializer = node.getInitializer();
|
|
405
|
+
if (initializer && Node.isStringLiteral(initializer)) {
|
|
406
|
+
return initializer.getLiteralText();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return void 0;
|
|
410
|
+
};
|
|
411
|
+
const stringArrayPropertyOf = (object, property) => {
|
|
412
|
+
const node = object.getProperty(property);
|
|
413
|
+
if (node && Node.isPropertyAssignment(node)) {
|
|
414
|
+
const initializer = node.getInitializer();
|
|
415
|
+
if (initializer && Node.isArrayLiteralExpression(initializer)) {
|
|
416
|
+
const items = initializer.getElements().filter((element) => Node.isStringLiteral(element)).map((element) => element.getLiteralText());
|
|
417
|
+
return items.length > 0 ? items : void 0;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return void 0;
|
|
421
|
+
};
|
|
422
|
+
const parseSourceCall = (args) => {
|
|
423
|
+
const first = args[0];
|
|
424
|
+
if (!first || !Node.isObjectLiteralExpression(first)) {
|
|
425
|
+
return { binding: "", hasTenantBy: false, unanalyzable: true };
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
binding: stringPropertyOf(first, "binding") ?? "",
|
|
429
|
+
columns: stringArrayPropertyOf(first, "columns"),
|
|
430
|
+
hasReconcile: first.getProperty("reconcileEveryMs") !== void 0,
|
|
431
|
+
hasSoftDelete: first.getProperty("softDeleteColumn") !== void 0,
|
|
432
|
+
hasTenantBy: first.getProperty("tenantBy") !== void 0,
|
|
433
|
+
idColumn: stringPropertyOf(first, "idColumn"),
|
|
434
|
+
mode: stringPropertyOf(first, "mode"),
|
|
435
|
+
query: stringPropertyOf(first, "query")
|
|
436
|
+
};
|
|
437
|
+
};
|
|
182
438
|
const applyTableMethod = (accumulator, method, args, name) => {
|
|
183
439
|
switch (method) {
|
|
184
440
|
case "externallyManaged": {
|
|
@@ -194,6 +450,10 @@ const applyTableMethod = (accumulator, method, args, name) => {
|
|
|
194
450
|
accumulator.indexes.push(parseIndexCall(args));
|
|
195
451
|
break;
|
|
196
452
|
}
|
|
453
|
+
case "public": {
|
|
454
|
+
accumulator.isPublic = true;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
197
457
|
case "rankIndex": {
|
|
198
458
|
accumulator.rankIndexes.push(parseRankIndexCall(args));
|
|
199
459
|
break;
|
|
@@ -214,6 +474,15 @@ const applyTableMethod = (accumulator, method, args, name) => {
|
|
|
214
474
|
accumulator.shardMode = { field: field && Node.isStringLiteral(field) ? field.getLiteralText() : "_unknown_", kind: "shardBy" };
|
|
215
475
|
break;
|
|
216
476
|
}
|
|
477
|
+
case "softDelete": {
|
|
478
|
+
accumulator.softDelete = { field: softDeleteFieldOf(args[0]) };
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
case "source": {
|
|
482
|
+
accumulator.externalSource = parseSourceCall(args);
|
|
483
|
+
accumulator.externallyManaged = true;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
217
486
|
case "vectorize": {
|
|
218
487
|
const vectorIndex = parseVectorizeCall(args, name);
|
|
219
488
|
if (vectorIndex) {
|
|
@@ -227,6 +496,7 @@ const parseTableBuilder = (expression, name) => {
|
|
|
227
496
|
const accumulator = {
|
|
228
497
|
externallyManaged: false,
|
|
229
498
|
indexes: [],
|
|
499
|
+
isPublic: false,
|
|
230
500
|
rankIndexes: [],
|
|
231
501
|
relations: [],
|
|
232
502
|
searchIndexes: [],
|
|
@@ -251,16 +521,22 @@ const parseTableBuilder = (expression, name) => {
|
|
|
251
521
|
break;
|
|
252
522
|
}
|
|
253
523
|
}
|
|
524
|
+
if (accumulator.softDelete && !(accumulator.softDelete.field in shape)) {
|
|
525
|
+
shape = { ...shape, [accumulator.softDelete.field]: { inner: { kind: "number" }, kind: "optional" } };
|
|
526
|
+
}
|
|
254
527
|
return {
|
|
255
528
|
externallyManaged: accumulator.externallyManaged,
|
|
529
|
+
externalSource: accumulator.externalSource,
|
|
256
530
|
globalBackend: accumulator.shardMode === "global" ? accumulator.globalBackend ?? "d1" : void 0,
|
|
257
531
|
indexes: accumulator.indexes,
|
|
532
|
+
isPublic: accumulator.isPublic,
|
|
258
533
|
name,
|
|
259
534
|
rankIndexes: accumulator.rankIndexes,
|
|
260
535
|
relations: accumulator.relations,
|
|
261
536
|
searchIndexes: accumulator.searchIndexes,
|
|
262
537
|
shape,
|
|
263
538
|
shardMode: accumulator.shardMode,
|
|
539
|
+
softDelete: accumulator.softDelete,
|
|
264
540
|
vectorIndexes: accumulator.vectorIndexes
|
|
265
541
|
};
|
|
266
542
|
};
|
|
@@ -455,24 +731,30 @@ const parseExtensionVectorIndexes = (options) => {
|
|
|
455
731
|
}
|
|
456
732
|
return parseStandaloneVectorIndexes(object);
|
|
457
733
|
};
|
|
458
|
-
const
|
|
459
|
-
const bareTables = parseExtensionTables(options);
|
|
734
|
+
const namespaceExtension = (key, bareTables, bareVectorIndexes) => {
|
|
460
735
|
const bareNames = new Set(bareTables.map((table) => table.name));
|
|
461
736
|
const tables = bareTables.map((table) => namespaceExtensionTable(table, key, bareNames));
|
|
462
|
-
const vectorIndexes =
|
|
737
|
+
const vectorIndexes = bareVectorIndexes.map((index) => {
|
|
463
738
|
return { ...index, name: prefixTableName(key, index.name), table: rewriteReference(index.table, key, bareNames) };
|
|
464
739
|
});
|
|
465
740
|
return { tables, vectorIndexes };
|
|
466
741
|
};
|
|
467
|
-
const
|
|
742
|
+
const mergeExtension = (key, options) => namespaceExtension(key, parseExtensionTables(options), parseExtensionVectorIndexes(options));
|
|
743
|
+
const mergeExtendCall = (extendCall, projectRoot) => {
|
|
468
744
|
const extendArgument = extendCall.getArguments()[0];
|
|
469
745
|
if (!extendArgument) {
|
|
470
746
|
return void 0;
|
|
471
747
|
}
|
|
472
748
|
const resolved = resolveSchemaExtensionCall(extendArgument);
|
|
473
749
|
if (!resolved) {
|
|
750
|
+
if (projectRoot !== void 0) {
|
|
751
|
+
const fromPackage = resolvePackageExtension(extendArgument, projectRoot);
|
|
752
|
+
if (fromPackage) {
|
|
753
|
+
return namespaceExtension(fromPackage.key, fromPackage.bareTables, fromPackage.bareVectorIndexes);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
474
756
|
console.warn(
|
|
475
|
-
`@lunora/codegen: skipping \`.extend(${extendArgument.getText()})\` — its \`defineSchemaExtension(...)\`
|
|
757
|
+
`@lunora/codegen: skipping \`.extend(${extendArgument.getText()})\` — its \`defineSchemaExtension(...)\` could not be resolved from local sources, and ${projectRoot === void 0 ? "no project root was available to resolve the package" : "the package could not be imported/introspected"}. Extension tables will be absent from the generated types.`
|
|
476
758
|
);
|
|
477
759
|
return void 0;
|
|
478
760
|
}
|
|
@@ -502,6 +784,36 @@ const extendCallsOf = (defineSchemaCall) => {
|
|
|
502
784
|
}
|
|
503
785
|
return calls;
|
|
504
786
|
};
|
|
787
|
+
const chainedStringLiteralArgument = (defineSchemaCall, methodName, noun, allowed, expected) => {
|
|
788
|
+
let current = defineSchemaCall;
|
|
789
|
+
for (; ; ) {
|
|
790
|
+
const parent = current.getParent();
|
|
791
|
+
if (!parent || !Node.isPropertyAccessExpression(parent)) {
|
|
792
|
+
break;
|
|
793
|
+
}
|
|
794
|
+
const callParent = parent.getParent();
|
|
795
|
+
if (!callParent || !Node.isCallExpression(callParent)) {
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
if (parent.getName() === methodName) {
|
|
799
|
+
const argument = callParent.getArguments()[0];
|
|
800
|
+
if (!argument || !Node.isStringLiteral(argument)) {
|
|
801
|
+
throw diagnosticAt(callParent, `\`.${methodName}(...)\` expects a string literal (${expected})`);
|
|
802
|
+
}
|
|
803
|
+
const value = argument.getLiteralText();
|
|
804
|
+
if (!allowed.has(value)) {
|
|
805
|
+
throw diagnosticAt(argument, `unknown ${noun} ${JSON.stringify(value)} — expected ${expected}`);
|
|
806
|
+
}
|
|
807
|
+
return value;
|
|
808
|
+
}
|
|
809
|
+
current = callParent;
|
|
810
|
+
}
|
|
811
|
+
return void 0;
|
|
812
|
+
};
|
|
813
|
+
const JURISDICTIONS = /* @__PURE__ */ new Set(["eu", "fedramp", "us"]);
|
|
814
|
+
const jurisdictionOf = (defineSchemaCall) => chainedStringLiteralArgument(defineSchemaCall, "jurisdiction", "jurisdiction", JURISDICTIONS, '"eu", "us", or "fedramp"');
|
|
815
|
+
const RLS_MODES = /* @__PURE__ */ new Set(["required"]);
|
|
816
|
+
const rlsModeOf = (defineSchemaCall) => chainedStringLiteralArgument(defineSchemaCall, "rls", "rls mode", RLS_MODES, '"required"');
|
|
505
817
|
const parseBaseTables = (object) => {
|
|
506
818
|
const tables = [];
|
|
507
819
|
for (const property of object.getProperties()) {
|
|
@@ -517,11 +829,11 @@ const parseBaseTables = (object) => {
|
|
|
517
829
|
}
|
|
518
830
|
return tables;
|
|
519
831
|
};
|
|
520
|
-
const applyExtensions = (defineSchemaCall, tables) => {
|
|
832
|
+
const applyExtensions = (defineSchemaCall, tables, projectRoot) => {
|
|
521
833
|
const existingTableNames = new Set(tables.map((table) => table.name));
|
|
522
834
|
const vectorIndexes = [];
|
|
523
835
|
for (const extendCall of extendCallsOf(defineSchemaCall)) {
|
|
524
|
-
const merged = mergeExtendCall(extendCall);
|
|
836
|
+
const merged = mergeExtendCall(extendCall, projectRoot);
|
|
525
837
|
if (!merged) {
|
|
526
838
|
continue;
|
|
527
839
|
}
|
|
@@ -539,14 +851,14 @@ const applyExtensions = (defineSchemaCall, tables) => {
|
|
|
539
851
|
}
|
|
540
852
|
return vectorIndexes;
|
|
541
853
|
};
|
|
542
|
-
const discoverSchema = (project, schemaPath) => {
|
|
854
|
+
const discoverSchema = (project, schemaPath, projectRoot) => {
|
|
543
855
|
const file = project.addSourceFileAtPath(schemaPath);
|
|
544
856
|
const defineSchemaCall = file.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
|
|
545
857
|
const callee = call.getExpression();
|
|
546
858
|
return Node.isIdentifier(callee) && callee.getText() === "defineSchema";
|
|
547
859
|
});
|
|
548
860
|
if (!defineSchemaCall) {
|
|
549
|
-
throw new
|
|
861
|
+
throw new LunoraError("INTERNAL", `defineSchema() not found in ${schemaPath}`);
|
|
550
862
|
}
|
|
551
863
|
const argument = defineSchemaCall.getArguments()[0];
|
|
552
864
|
if (!argument || !Node.isObjectLiteralExpression(argument)) {
|
|
@@ -555,9 +867,9 @@ const discoverSchema = (project, schemaPath) => {
|
|
|
555
867
|
const tables = parseBaseTables(argument);
|
|
556
868
|
const standaloneArgument = defineSchemaCall.getArguments()[1];
|
|
557
869
|
const standaloneVectorIndexes = standaloneArgument && Node.isObjectLiteralExpression(standaloneArgument) ? parseStandaloneVectorIndexes(standaloneArgument) : [];
|
|
558
|
-
const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables);
|
|
870
|
+
const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables, projectRoot);
|
|
559
871
|
const vectorIndexes = [...tables.flatMap((table) => table.vectorIndexes), ...standaloneVectorIndexes, ...extensionStandaloneVectorIndexes];
|
|
560
|
-
return { tables, vectorIndexes };
|
|
872
|
+
return { jurisdiction: jurisdictionOf(defineSchemaCall), rlsMode: rlsModeOf(defineSchemaCall), tables, vectorIndexes };
|
|
561
873
|
};
|
|
562
874
|
|
|
563
875
|
export { discoverSchema as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Node } from 'ts-morph';
|
|
2
|
-
import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-
|
|
2
|
+
import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJ-qR7Rg.mjs';
|
|
3
3
|
|
|
4
4
|
const STORAGE_OPERATIONS = /* @__PURE__ */ new Set(["delete", "list", "read", "write"]);
|
|
5
5
|
const isStorageRulesCall = (node) => {
|