@lunora/codegen 1.0.0-alpha.55 → 1.0.0-alpha.57
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/dist/index.d.mts +59 -5
- package/dist/index.d.ts +59 -5
- package/dist/index.mjs +1 -38
- package/dist/packem_shared/AGENTS_FILENAME-BesaDYkL.mjs +1 -0
- package/dist/packem_shared/CONTAINERS_FILENAME-CFwdyaCI.mjs +1 -0
- package/dist/packem_shared/CodegenDiagnosticError-DPezpZTz.mjs +1 -0
- package/dist/packem_shared/FLAGS_FILENAME-DW5oGq1q.mjs +1 -0
- package/dist/packem_shared/GENERATED_HEADER-hlHbtIBb.mjs +1 -0
- package/dist/packem_shared/LUNORA_ERROR_CODES-Um9hC1gr.mjs +1 -0
- package/dist/packem_shared/MUTATORS_FILENAME-BKKPROzu.mjs +1 -0
- package/dist/packem_shared/NOTIFY_FILENAME-C-c7Lg-U.mjs +1 -0
- package/dist/packem_shared/OPENRPC_VERSION-DWoqALFJ.mjs +3 -0
- package/dist/packem_shared/QUEUES_FILENAME-CSE6i-ld.mjs +1 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Cuf8KyVF.mjs +3 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-Bpf1FGMG.mjs +15 -0
- package/dist/packem_shared/SHAPES_FILENAME-DTkSJSsg.mjs +1 -0
- package/dist/packem_shared/WORKFLOWS_FILENAME-Bk5upkGM.mjs +1 -0
- package/dist/packem_shared/buildOpenApiDocument-BRCc5AIx.mjs +3 -0
- package/dist/packem_shared/discover-ast-CezKqEhE.mjs +1 -0
- package/dist/packem_shared/discoverAuthApiCalls-DOfSQqVK.mjs +1 -0
- package/dist/packem_shared/discoverCrons-B09_uEuL.mjs +1 -0
- package/dist/packem_shared/discoverFunctions-BdibLQmc.mjs +1 -0
- package/dist/packem_shared/discoverHttpRoutes-BOWz6y_n.mjs +1 -0
- package/dist/packem_shared/discoverInserts-BtteTyNy.mjs +1 -0
- package/dist/packem_shared/discoverMaskProcedures-COPmwMBm.mjs +1 -0
- package/dist/packem_shared/discoverMigrations-iGMlp9YJ.mjs +1 -0
- package/dist/packem_shared/discoverNondeterministicCalls-Dmgc4QBx.mjs +1 -0
- package/dist/packem_shared/discoverQueries-CcfuGKHh.mjs +1 -0
- package/dist/packem_shared/discoverR2sqlCalls-CjZKvg-N.mjs +1 -0
- package/dist/packem_shared/discoverRlsMetadata-BXmNOgry.mjs +1 -0
- package/dist/packem_shared/discoverSandboxUsage-CDdBqWcM.mjs +1 -0
- package/dist/packem_shared/discoverSchema-m2voTncu.mjs +1 -0
- package/dist/packem_shared/discoverStorageRulesMetadata-b71cJJHz.mjs +1 -0
- package/dist/packem_shared/emit-BYVxPDqO.mjs +2127 -0
- package/dist/packem_shared/emitApp-CHCOfQer.mjs +413 -0
- package/dist/packem_shared/formatAdvisories-DZvv-0MG.mjs +2 -0
- package/dist/packem_shared/parse-validator-CSDlMEvE.mjs +1 -0
- package/dist/packem_shared/paths-BmX5O1sG.mjs +1 -0
- package/dist/packem_shared/redact-CQ8-to6l.mjs +1 -0
- package/dist/packem_shared/schemaFromIr-R1ZFzVyy.mjs +1 -0
- package/package.json +3 -3
- package/dist/packem_shared/AGENTS_FILENAME-Cxx7wiSs.mjs +0 -158
- package/dist/packem_shared/CONTAINERS_FILENAME-DjpXMqhp.mjs +0 -224
- package/dist/packem_shared/CodegenDiagnosticError-DyQ5FwkM.mjs +0 -24
- package/dist/packem_shared/FLAGS_FILENAME-D5igzqwR.mjs +0 -139
- package/dist/packem_shared/GENERATED_HEADER-C8tAvxqP.mjs +0 -4
- package/dist/packem_shared/LUNORA_ERROR_CODES-DvTLozCu.mjs +0 -68
- package/dist/packem_shared/MUTATORS_FILENAME-BZOfUhlY.mjs +0 -81
- package/dist/packem_shared/NOTIFY_FILENAME-CK2IrsrP.mjs +0 -152
- package/dist/packem_shared/OPENRPC_VERSION-DvDChMhC.mjs +0 -60
- package/dist/packem_shared/QUEUES_FILENAME-Xv6Vy-Ku.mjs +0 -145
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-YAL6GrxI.mjs +0 -3597
- package/dist/packem_shared/SCHEMA_SNAPSHOT_VERSION-DGD73E_n.mjs +0 -252
- package/dist/packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs +0 -94
- package/dist/packem_shared/WORKFLOWS_FILENAME-Dtuzvluc.mjs +0 -158
- package/dist/packem_shared/buildOpenApiDocument-DCQSLuFc.mjs +0 -262
- package/dist/packem_shared/discover-ast-CT6BgBr4.mjs +0 -13
- package/dist/packem_shared/discoverAuthApiCalls-Dhwgf4J4.mjs +0 -62
- package/dist/packem_shared/discoverCrons-UbQLLmMS.mjs +0 -286
- package/dist/packem_shared/discoverFunctions-COG_Xkyz.mjs +0 -544
- package/dist/packem_shared/discoverHttpRoutes-CVXWZkzo.mjs +0 -139
- package/dist/packem_shared/discoverInserts-DdWnXmLS.mjs +0 -61
- package/dist/packem_shared/discoverMaskProcedures-BG58_fw3.mjs +0 -273
- package/dist/packem_shared/discoverMigrations-Bw1U01zr.mjs +0 -97
- package/dist/packem_shared/discoverNondeterministicCalls-BbXEFZUT.mjs +0 -122
- package/dist/packem_shared/discoverQueries-CDmxu2ET.mjs +0 -62
- package/dist/packem_shared/discoverR2sqlCalls-Bn7QVv7J.mjs +0 -80
- package/dist/packem_shared/discoverRlsMetadata-D9uN35no.mjs +0 -280
- package/dist/packem_shared/discoverSandboxUsage-B5jDU6Bt.mjs +0 -38
- package/dist/packem_shared/discoverSchema-BJp5_T4o.mjs +0 -906
- package/dist/packem_shared/discoverStorageRulesMetadata-BqMhuEjo.mjs +0 -97
- package/dist/packem_shared/emit-DIbr7U31.mjs +0 -3884
- package/dist/packem_shared/emitApp-DbMM8iHe.mjs +0 -706
- package/dist/packem_shared/formatAdvisories-Cans5TWS.mjs +0 -131
- package/dist/packem_shared/parse-validator-BDGV8iue.mjs +0 -144
- package/dist/packem_shared/paths-BRd6JHuF.mjs +0 -11
- package/dist/packem_shared/redact-oTmsol5A.mjs +0 -33
- package/dist/packem_shared/schemaFromIr-DTYsLBaA.mjs +0 -57
|
@@ -1,906 +0,0 @@
|
|
|
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-BDGV8iue.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
|
-
geoIndexes: [],
|
|
113
|
-
indexes,
|
|
114
|
-
name: bareName,
|
|
115
|
-
rankIndexes: [],
|
|
116
|
-
relations: [],
|
|
117
|
-
searchIndexes: (builder.searchIndexes ?? []).map((index) => {
|
|
118
|
-
return {
|
|
119
|
-
field: index.field,
|
|
120
|
-
...index.filterFields ? { filterFields: index.filterFields } : {},
|
|
121
|
-
name: index.name
|
|
122
|
-
};
|
|
123
|
-
}),
|
|
124
|
-
shape: Object.fromEntries(Object.entries(shape).map(([name, validator]) => [name, runtimeValidatorToIR(validator)])),
|
|
125
|
-
shardMode: shardModeToIR(builder.shardMode),
|
|
126
|
-
// Inline vector/rank indexes and relations are not yet introspected from a
|
|
127
|
-
// package extension; their presence is surfaced via `warnDroppedTableFeatures`.
|
|
128
|
-
vectorIndexes: []
|
|
129
|
-
};
|
|
130
|
-
};
|
|
131
|
-
const resolvedExtensionToIR = (value) => {
|
|
132
|
-
const { key, tables } = value;
|
|
133
|
-
if (typeof key !== "string" || typeof tables !== "object" || tables === null) {
|
|
134
|
-
return void 0;
|
|
135
|
-
}
|
|
136
|
-
const bareTables = Object.entries(tables).map(([bareName, builder]) => runtimeTableToIR(builder, bareName));
|
|
137
|
-
const vectorIndexes = value["vectorIndexes"] ?? {};
|
|
138
|
-
const bareVectorIndexes = Object.entries(vectorIndexes ?? {}).map(([name, index]) => {
|
|
139
|
-
return {
|
|
140
|
-
...index.dimensions === void 0 ? {} : { dimensions: index.dimensions },
|
|
141
|
-
...index.field === void 0 ? {} : { field: index.field },
|
|
142
|
-
...index.metadata === void 0 ? {} : { metadata: index.metadata },
|
|
143
|
-
...index.metric === void 0 ? {} : { metric: index.metric },
|
|
144
|
-
name,
|
|
145
|
-
table: index.table ?? ""
|
|
146
|
-
};
|
|
147
|
-
});
|
|
148
|
-
return { bareTables, bareVectorIndexes, key };
|
|
149
|
-
};
|
|
150
|
-
const receiverIdentifierText = (argument) => {
|
|
151
|
-
if (Node.isIdentifier(argument)) {
|
|
152
|
-
return argument.getText();
|
|
153
|
-
}
|
|
154
|
-
if (Node.isPropertyAccessExpression(argument)) {
|
|
155
|
-
const receiver = argument.getExpression();
|
|
156
|
-
return Node.isIdentifier(receiver) ? receiver.getText() : void 0;
|
|
157
|
-
}
|
|
158
|
-
return void 0;
|
|
159
|
-
};
|
|
160
|
-
const accessPathOf = (argument) => {
|
|
161
|
-
const receiverName = receiverIdentifierText(argument);
|
|
162
|
-
if (receiverName === void 0) {
|
|
163
|
-
return void 0;
|
|
164
|
-
}
|
|
165
|
-
const property = Node.isPropertyAccessExpression(argument) ? argument.getName() : void 0;
|
|
166
|
-
const propertyPath = property === void 0 ? [] : [property];
|
|
167
|
-
for (const declaration of argument.getSourceFile().getImportDeclarations()) {
|
|
168
|
-
const moduleSpecifier = declaration.getModuleSpecifierValue();
|
|
169
|
-
for (const named of declaration.getNamedImports()) {
|
|
170
|
-
const localName = named.getAliasNode()?.getText() ?? named.getName();
|
|
171
|
-
if (localName === receiverName) {
|
|
172
|
-
return { importedName: named.getName(), moduleSpecifier, propertyPath };
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (declaration.getDefaultImport()?.getText() === receiverName) {
|
|
176
|
-
return { importedName: "default", moduleSpecifier, propertyPath };
|
|
177
|
-
}
|
|
178
|
-
if (declaration.getNamespaceImport()?.getText() === receiverName && property !== void 0) {
|
|
179
|
-
return { importedName: property, moduleSpecifier, propertyPath: [] };
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return void 0;
|
|
183
|
-
};
|
|
184
|
-
const readExtensionValue = (module_, access) => {
|
|
185
|
-
let current = module_[access.importedName];
|
|
186
|
-
for (const segment of access.propertyPath) {
|
|
187
|
-
if (typeof current !== "object" || current === null) {
|
|
188
|
-
return void 0;
|
|
189
|
-
}
|
|
190
|
-
current = current[segment];
|
|
191
|
-
}
|
|
192
|
-
return current;
|
|
193
|
-
};
|
|
194
|
-
const resolvePackageExtension = (argument, projectRoot) => {
|
|
195
|
-
const access = accessPathOf(argument);
|
|
196
|
-
if (!access) {
|
|
197
|
-
return void 0;
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
const projectRequire = createRequire(join(projectRoot, "noop.cjs"));
|
|
201
|
-
const resolved = projectRequire.resolve(access.moduleSpecifier);
|
|
202
|
-
const loadedModule = projectRequire(resolved);
|
|
203
|
-
const value = readExtensionValue(loadedModule, access);
|
|
204
|
-
if (typeof value !== "object" || value === null) {
|
|
205
|
-
return void 0;
|
|
206
|
-
}
|
|
207
|
-
return resolvedExtensionToIR(value);
|
|
208
|
-
} catch {
|
|
209
|
-
return void 0;
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const VECTOR_METRICS = /* @__PURE__ */ new Set(["cosine", "dot-product", "euclidean"]);
|
|
214
|
-
const ON_DELETE_ACTIONS = /* @__PURE__ */ new Set(["cascade", "restrict", "set null"]);
|
|
215
|
-
const RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set(["delete", "get", "insert", "normalizeId", "patch", "query", "replace", "system"]);
|
|
216
|
-
const assertTableNameAllowed = (name, node) => {
|
|
217
|
-
if (RESERVED_TABLE_NAMES.has(name)) {
|
|
218
|
-
throw diagnosticAt(
|
|
219
|
-
node,
|
|
220
|
-
`table name "${name}" is reserved — it collides with a \`ctx.db\` member (one of ${[...RESERVED_TABLE_NAMES].map((reserved) => `"${reserved}"`).join(", ")}). Rename the table.`
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
const getStringProperty = (object, key) => {
|
|
225
|
-
const property = object.getProperty(key);
|
|
226
|
-
if (property && Node.isPropertyAssignment(property)) {
|
|
227
|
-
const initializer = property.getInitializer();
|
|
228
|
-
if (initializer && Node.isStringLiteral(initializer)) {
|
|
229
|
-
return initializer.getLiteralText();
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return void 0;
|
|
233
|
-
};
|
|
234
|
-
const getNumberProperty = (object, key) => {
|
|
235
|
-
const property = object.getProperty(key);
|
|
236
|
-
if (property && Node.isPropertyAssignment(property)) {
|
|
237
|
-
const initializer = property.getInitializer();
|
|
238
|
-
if (initializer && Node.isNumericLiteral(initializer)) {
|
|
239
|
-
return Number(initializer.getLiteralText());
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return void 0;
|
|
243
|
-
};
|
|
244
|
-
const getStringArrayProperty = (object, key) => {
|
|
245
|
-
const property = object.getProperty(key);
|
|
246
|
-
if (property && Node.isPropertyAssignment(property)) {
|
|
247
|
-
const initializer = property.getInitializer();
|
|
248
|
-
if (initializer && Node.isArrayLiteralExpression(initializer)) {
|
|
249
|
-
return initializer.getElements().filter((element) => Node.isStringLiteral(element)).map((element) => element.getLiteralText());
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return void 0;
|
|
253
|
-
};
|
|
254
|
-
const asMetric = (value) => value && VECTOR_METRICS.has(value) ? value : void 0;
|
|
255
|
-
const asOnDelete = (value) => value && ON_DELETE_ACTIONS.has(value) ? value : void 0;
|
|
256
|
-
const relationsObjectBody = (argument) => {
|
|
257
|
-
if (!Node.isArrowFunction(argument)) {
|
|
258
|
-
return void 0;
|
|
259
|
-
}
|
|
260
|
-
let body = argument.getBody();
|
|
261
|
-
if (Node.isParenthesizedExpression(body)) {
|
|
262
|
-
body = body.getExpression();
|
|
263
|
-
} else if (Node.isBlock(body)) {
|
|
264
|
-
const returnStatement = body.getStatements().find((statement) => Node.isReturnStatement(statement));
|
|
265
|
-
body = returnStatement && Node.isReturnStatement(returnStatement) ? returnStatement.getExpression() ?? body : body;
|
|
266
|
-
}
|
|
267
|
-
return Node.isObjectLiteralExpression(body) ? body : void 0;
|
|
268
|
-
};
|
|
269
|
-
const relationFromProperty = (property) => {
|
|
270
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
271
|
-
return void 0;
|
|
272
|
-
}
|
|
273
|
-
const initializer = property.getInitializer();
|
|
274
|
-
if (!initializer || !Node.isCallExpression(initializer)) {
|
|
275
|
-
return void 0;
|
|
276
|
-
}
|
|
277
|
-
const callee = initializer.getExpression();
|
|
278
|
-
if (!Node.isPropertyAccessExpression(callee)) {
|
|
279
|
-
return void 0;
|
|
280
|
-
}
|
|
281
|
-
const method = callee.getName();
|
|
282
|
-
if (method !== "one" && method !== "many") {
|
|
283
|
-
return void 0;
|
|
284
|
-
}
|
|
285
|
-
const [tableArgument, optionsExpression] = initializer.getArguments();
|
|
286
|
-
const table = tableArgument && Node.isStringLiteral(tableArgument) ? tableArgument.getLiteralText() : "_unknown_";
|
|
287
|
-
let field = "_unknown_";
|
|
288
|
-
let references = "_id";
|
|
289
|
-
let onDelete;
|
|
290
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
291
|
-
field = getStringProperty(optionsExpression, "field") ?? field;
|
|
292
|
-
references = getStringProperty(optionsExpression, "references") ?? references;
|
|
293
|
-
onDelete = method === "one" ? asOnDelete(getStringProperty(optionsExpression, "onDelete")) : void 0;
|
|
294
|
-
}
|
|
295
|
-
return { field, kind: method, name: property.getName(), onDelete, references, table };
|
|
296
|
-
};
|
|
297
|
-
const parseRelations = (argument) => {
|
|
298
|
-
const body = relationsObjectBody(argument);
|
|
299
|
-
if (!body) {
|
|
300
|
-
return [];
|
|
301
|
-
}
|
|
302
|
-
const relations = [];
|
|
303
|
-
for (const property of body.getProperties()) {
|
|
304
|
-
const relation = relationFromProperty(property);
|
|
305
|
-
if (relation) {
|
|
306
|
-
relations.push(relation);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
return relations;
|
|
310
|
-
};
|
|
311
|
-
const indexNameOf = (nameArgument) => nameArgument && Node.isStringLiteral(nameArgument) ? nameArgument.getLiteralText() : "_unnamed_";
|
|
312
|
-
const parseIndexCall = (args) => {
|
|
313
|
-
const [indexName, fieldsExpression, optionsExpression] = args;
|
|
314
|
-
let unique = false;
|
|
315
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
316
|
-
const property = optionsExpression.getProperty("unique");
|
|
317
|
-
if (property && Node.isPropertyAssignment(property)) {
|
|
318
|
-
const initializer = property.getInitializer();
|
|
319
|
-
if (initializer && !Node.isTrueLiteral(initializer) && !Node.isFalseLiteral(initializer)) {
|
|
320
|
-
throw diagnosticAt(initializer, `\`unique\` must be a literal \`true\` or \`false\`, got ${JSON.stringify(initializer.getText())}`);
|
|
321
|
-
}
|
|
322
|
-
unique = initializer ? Node.isTrueLiteral(initializer) : false;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
const fields = fieldsExpression && Node.isArrayLiteralExpression(fieldsExpression) ? fieldsExpression.getElements().filter((element) => Node.isStringLiteral(element)).map((element) => element.getLiteralText()) : [];
|
|
326
|
-
return { fields, name: indexNameOf(indexName), unique };
|
|
327
|
-
};
|
|
328
|
-
const parseSearchIndexCall = (args) => {
|
|
329
|
-
const [indexName, optionsExpression] = args;
|
|
330
|
-
let field = "_unknown_";
|
|
331
|
-
let filterFields;
|
|
332
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
333
|
-
field = getStringProperty(optionsExpression, "field") ?? field;
|
|
334
|
-
filterFields = getStringArrayProperty(optionsExpression, "filterFields");
|
|
335
|
-
}
|
|
336
|
-
return { field, filterFields, name: indexNameOf(indexName) };
|
|
337
|
-
};
|
|
338
|
-
const parseGeoIndexCall = (args) => {
|
|
339
|
-
const [indexName, optionsExpression] = args;
|
|
340
|
-
let field = "_unknown_";
|
|
341
|
-
let precision;
|
|
342
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
343
|
-
field = getStringProperty(optionsExpression, "field") ?? field;
|
|
344
|
-
precision = getNumberProperty(optionsExpression, "precision");
|
|
345
|
-
}
|
|
346
|
-
return { field, name: indexNameOf(indexName), precision };
|
|
347
|
-
};
|
|
348
|
-
const parseTtlCall = (args) => {
|
|
349
|
-
const [fieldArgument, optionsExpression] = args;
|
|
350
|
-
const field = fieldArgument && Node.isStringLiteral(fieldArgument) ? fieldArgument.getLiteralText() : "_unknown_";
|
|
351
|
-
let after;
|
|
352
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
353
|
-
after = getNumberProperty(optionsExpression, "after");
|
|
354
|
-
}
|
|
355
|
-
return { after, field };
|
|
356
|
-
};
|
|
357
|
-
const rankSortKeyFromElement = (element) => {
|
|
358
|
-
if (!Node.isObjectLiteralExpression(element)) {
|
|
359
|
-
return void 0;
|
|
360
|
-
}
|
|
361
|
-
const field = getStringProperty(element, "field");
|
|
362
|
-
if (field === void 0) {
|
|
363
|
-
return void 0;
|
|
364
|
-
}
|
|
365
|
-
const direction = getStringProperty(element, "direction");
|
|
366
|
-
return { direction: direction === "desc" ? "desc" : "asc", field };
|
|
367
|
-
};
|
|
368
|
-
const parseRankIndexCall = (args) => {
|
|
369
|
-
const [indexName, optionsExpression] = args;
|
|
370
|
-
let sortBy = [];
|
|
371
|
-
let partitionBy;
|
|
372
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
373
|
-
const sortByProperty = optionsExpression.getProperty("sortBy");
|
|
374
|
-
if (sortByProperty && Node.isPropertyAssignment(sortByProperty)) {
|
|
375
|
-
const initializer = sortByProperty.getInitializer();
|
|
376
|
-
if (initializer && Node.isArrayLiteralExpression(initializer)) {
|
|
377
|
-
sortBy = initializer.getElements().map((element) => rankSortKeyFromElement(element)).filter((key) => key !== void 0);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
partitionBy = getStringArrayProperty(optionsExpression, "partitionBy");
|
|
381
|
-
}
|
|
382
|
-
return { name: indexNameOf(indexName), partitionBy, sortBy };
|
|
383
|
-
};
|
|
384
|
-
const parseVectorizeCall = (args, table) => {
|
|
385
|
-
const [fieldArgument, optionsExpression] = args;
|
|
386
|
-
const field = fieldArgument && Node.isStringLiteral(fieldArgument) ? fieldArgument.getLiteralText() : "_unknown_";
|
|
387
|
-
if (!optionsExpression || !Node.isObjectLiteralExpression(optionsExpression)) {
|
|
388
|
-
return void 0;
|
|
389
|
-
}
|
|
390
|
-
return {
|
|
391
|
-
dimensions: getNumberProperty(optionsExpression, "dimensions"),
|
|
392
|
-
field,
|
|
393
|
-
metadata: getStringArrayProperty(optionsExpression, "metadata"),
|
|
394
|
-
metric: asMetric(getStringProperty(optionsExpression, "metric")),
|
|
395
|
-
name: getStringProperty(optionsExpression, "index") ?? "_unnamed_",
|
|
396
|
-
table
|
|
397
|
-
};
|
|
398
|
-
};
|
|
399
|
-
const parseGlobalBackend = (args) => {
|
|
400
|
-
const optionsExpression = args[0];
|
|
401
|
-
if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
|
|
402
|
-
const backend = getStringProperty(optionsExpression, "backend");
|
|
403
|
-
if (backend === "hyperdrive") {
|
|
404
|
-
return "hyperdrive";
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return "d1";
|
|
408
|
-
};
|
|
409
|
-
const softDeleteFieldOf = (optionsArgument) => {
|
|
410
|
-
if (optionsArgument && Node.isObjectLiteralExpression(optionsArgument)) {
|
|
411
|
-
const fieldProperty = optionsArgument.getProperty("field");
|
|
412
|
-
if (fieldProperty && Node.isPropertyAssignment(fieldProperty)) {
|
|
413
|
-
const initializer = fieldProperty.getInitializer();
|
|
414
|
-
if (initializer && Node.isStringLiteral(initializer)) {
|
|
415
|
-
return initializer.getLiteralText();
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return "deletedAt";
|
|
420
|
-
};
|
|
421
|
-
const stringPropertyOf = (object, property) => {
|
|
422
|
-
const node = object.getProperty(property);
|
|
423
|
-
if (node && Node.isPropertyAssignment(node)) {
|
|
424
|
-
const initializer = node.getInitializer();
|
|
425
|
-
if (initializer && Node.isStringLiteral(initializer)) {
|
|
426
|
-
return initializer.getLiteralText();
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
return void 0;
|
|
430
|
-
};
|
|
431
|
-
const stringArrayPropertyOf = (object, property) => {
|
|
432
|
-
const node = object.getProperty(property);
|
|
433
|
-
if (node && Node.isPropertyAssignment(node)) {
|
|
434
|
-
const initializer = node.getInitializer();
|
|
435
|
-
if (initializer && Node.isArrayLiteralExpression(initializer)) {
|
|
436
|
-
const items = initializer.getElements().filter((element) => Node.isStringLiteral(element)).map((element) => element.getLiteralText());
|
|
437
|
-
return items.length > 0 ? items : void 0;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
return void 0;
|
|
441
|
-
};
|
|
442
|
-
const parseSourceCall = (args) => {
|
|
443
|
-
const first = args[0];
|
|
444
|
-
if (!first || !Node.isObjectLiteralExpression(first)) {
|
|
445
|
-
return { binding: "", hasTenantBy: false, unanalyzable: true };
|
|
446
|
-
}
|
|
447
|
-
return {
|
|
448
|
-
binding: stringPropertyOf(first, "binding") ?? "",
|
|
449
|
-
columns: stringArrayPropertyOf(first, "columns"),
|
|
450
|
-
hasReconcile: first.getProperty("reconcileEveryMs") !== void 0,
|
|
451
|
-
hasSoftDelete: first.getProperty("softDeleteColumn") !== void 0,
|
|
452
|
-
hasTenantBy: first.getProperty("tenantBy") !== void 0,
|
|
453
|
-
idColumn: stringPropertyOf(first, "idColumn"),
|
|
454
|
-
mode: stringPropertyOf(first, "mode"),
|
|
455
|
-
query: stringPropertyOf(first, "query")
|
|
456
|
-
};
|
|
457
|
-
};
|
|
458
|
-
const applyTableMethod = (accumulator, method, args, name) => {
|
|
459
|
-
switch (method) {
|
|
460
|
-
case "externallyManaged": {
|
|
461
|
-
accumulator.externallyManaged = true;
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
case "geoIndex": {
|
|
465
|
-
accumulator.geoIndexes.push(parseGeoIndexCall(args));
|
|
466
|
-
break;
|
|
467
|
-
}
|
|
468
|
-
case "global": {
|
|
469
|
-
accumulator.shardMode = "global";
|
|
470
|
-
accumulator.globalBackend = parseGlobalBackend(args);
|
|
471
|
-
break;
|
|
472
|
-
}
|
|
473
|
-
case "index": {
|
|
474
|
-
accumulator.indexes.push(parseIndexCall(args));
|
|
475
|
-
break;
|
|
476
|
-
}
|
|
477
|
-
case "public": {
|
|
478
|
-
accumulator.isPublic = true;
|
|
479
|
-
break;
|
|
480
|
-
}
|
|
481
|
-
case "rankIndex": {
|
|
482
|
-
accumulator.rankIndexes.push(parseRankIndexCall(args));
|
|
483
|
-
break;
|
|
484
|
-
}
|
|
485
|
-
case "relations": {
|
|
486
|
-
const builder = args[0];
|
|
487
|
-
if (builder) {
|
|
488
|
-
accumulator.relations.push(...parseRelations(builder));
|
|
489
|
-
}
|
|
490
|
-
break;
|
|
491
|
-
}
|
|
492
|
-
case "searchIndex": {
|
|
493
|
-
accumulator.searchIndexes.push(parseSearchIndexCall(args));
|
|
494
|
-
break;
|
|
495
|
-
}
|
|
496
|
-
case "shardBy": {
|
|
497
|
-
const field = args[0];
|
|
498
|
-
accumulator.shardMode = { field: field && Node.isStringLiteral(field) ? field.getLiteralText() : "_unknown_", kind: "shardBy" };
|
|
499
|
-
break;
|
|
500
|
-
}
|
|
501
|
-
case "softDelete": {
|
|
502
|
-
accumulator.softDelete = { field: softDeleteFieldOf(args[0]) };
|
|
503
|
-
break;
|
|
504
|
-
}
|
|
505
|
-
case "source": {
|
|
506
|
-
accumulator.externalSource = parseSourceCall(args);
|
|
507
|
-
accumulator.externallyManaged = true;
|
|
508
|
-
break;
|
|
509
|
-
}
|
|
510
|
-
case "ttl": {
|
|
511
|
-
accumulator.ttl = parseTtlCall(args);
|
|
512
|
-
break;
|
|
513
|
-
}
|
|
514
|
-
case "vectorize": {
|
|
515
|
-
const vectorIndex = parseVectorizeCall(args, name);
|
|
516
|
-
if (vectorIndex) {
|
|
517
|
-
accumulator.vectorIndexes.push(vectorIndex);
|
|
518
|
-
}
|
|
519
|
-
break;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
};
|
|
523
|
-
const parseTableBuilder = (expression, name) => {
|
|
524
|
-
const accumulator = {
|
|
525
|
-
externallyManaged: false,
|
|
526
|
-
geoIndexes: [],
|
|
527
|
-
indexes: [],
|
|
528
|
-
isPublic: false,
|
|
529
|
-
rankIndexes: [],
|
|
530
|
-
relations: [],
|
|
531
|
-
searchIndexes: [],
|
|
532
|
-
shardMode: "root",
|
|
533
|
-
vectorIndexes: []
|
|
534
|
-
};
|
|
535
|
-
let shape = {};
|
|
536
|
-
let current = expression;
|
|
537
|
-
while (Node.isCallExpression(current)) {
|
|
538
|
-
const callee = current.getExpression();
|
|
539
|
-
const args = current.getArguments();
|
|
540
|
-
if (Node.isPropertyAccessExpression(callee)) {
|
|
541
|
-
applyTableMethod(accumulator, callee.getName(), args, name);
|
|
542
|
-
current = callee.getExpression();
|
|
543
|
-
} else if (Node.isIdentifier(callee) && callee.getText() === "defineTable") {
|
|
544
|
-
const first = args[0];
|
|
545
|
-
if (first && Node.isObjectLiteralExpression(first)) {
|
|
546
|
-
shape = parseObjectShape(first);
|
|
547
|
-
}
|
|
548
|
-
break;
|
|
549
|
-
} else {
|
|
550
|
-
break;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
if (accumulator.softDelete && !(accumulator.softDelete.field in shape)) {
|
|
554
|
-
shape = { ...shape, [accumulator.softDelete.field]: { inner: { kind: "number" }, kind: "optional" } };
|
|
555
|
-
}
|
|
556
|
-
return {
|
|
557
|
-
externallyManaged: accumulator.externallyManaged,
|
|
558
|
-
externalSource: accumulator.externalSource,
|
|
559
|
-
geoIndexes: accumulator.geoIndexes,
|
|
560
|
-
globalBackend: accumulator.shardMode === "global" ? accumulator.globalBackend ?? "d1" : void 0,
|
|
561
|
-
indexes: accumulator.indexes,
|
|
562
|
-
isPublic: accumulator.isPublic,
|
|
563
|
-
name,
|
|
564
|
-
rankIndexes: accumulator.rankIndexes,
|
|
565
|
-
relations: accumulator.relations,
|
|
566
|
-
searchIndexes: accumulator.searchIndexes,
|
|
567
|
-
shape,
|
|
568
|
-
shardMode: accumulator.shardMode,
|
|
569
|
-
softDelete: accumulator.softDelete,
|
|
570
|
-
ttl: accumulator.ttl,
|
|
571
|
-
vectorIndexes: accumulator.vectorIndexes
|
|
572
|
-
};
|
|
573
|
-
};
|
|
574
|
-
const sourceTableOf = (optionsExpression) => {
|
|
575
|
-
const sourceProperty = optionsExpression.getProperty("source");
|
|
576
|
-
if (sourceProperty && Node.isPropertyAssignment(sourceProperty)) {
|
|
577
|
-
const sourceInitializer = sourceProperty.getInitializer();
|
|
578
|
-
if (sourceInitializer && Node.isObjectLiteralExpression(sourceInitializer)) {
|
|
579
|
-
return getStringProperty(sourceInitializer, "table") ?? "_unknown_";
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return "_unknown_";
|
|
583
|
-
};
|
|
584
|
-
const standaloneVectorIndexFromProperty = (property) => {
|
|
585
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
586
|
-
return void 0;
|
|
587
|
-
}
|
|
588
|
-
const initializer = property.getInitializer();
|
|
589
|
-
if (!initializer || !Node.isCallExpression(initializer)) {
|
|
590
|
-
return void 0;
|
|
591
|
-
}
|
|
592
|
-
const callee = initializer.getExpression();
|
|
593
|
-
if (!Node.isIdentifier(callee) || callee.getText() !== "defineVectorIndex") {
|
|
594
|
-
return void 0;
|
|
595
|
-
}
|
|
596
|
-
const optionsExpression = initializer.getArguments()[0];
|
|
597
|
-
if (!optionsExpression || !Node.isObjectLiteralExpression(optionsExpression)) {
|
|
598
|
-
return void 0;
|
|
599
|
-
}
|
|
600
|
-
const nameNode = property.getNameNode();
|
|
601
|
-
const indexName = Node.isStringLiteral(nameNode) ? nameNode.getLiteralText() : nameNode.getText();
|
|
602
|
-
return {
|
|
603
|
-
dimensions: getNumberProperty(optionsExpression, "dimensions"),
|
|
604
|
-
metric: asMetric(getStringProperty(optionsExpression, "metric")),
|
|
605
|
-
name: indexName,
|
|
606
|
-
table: sourceTableOf(optionsExpression)
|
|
607
|
-
};
|
|
608
|
-
};
|
|
609
|
-
const parseStandaloneVectorIndexes = (object) => {
|
|
610
|
-
const result = [];
|
|
611
|
-
for (const property of object.getProperties()) {
|
|
612
|
-
const index = standaloneVectorIndexFromProperty(property);
|
|
613
|
-
if (index) {
|
|
614
|
-
result.push(index);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
return result;
|
|
618
|
-
};
|
|
619
|
-
const prefixTableName = (key, bareName) => `${key}_${bareName}`;
|
|
620
|
-
const rewriteReference = (target, key, bareNames) => bareNames.has(target) ? prefixTableName(key, target) : target;
|
|
621
|
-
const namespaceExtensionTable = (table, key, bareNames) => {
|
|
622
|
-
const ownPrefixed = prefixTableName(key, table.name);
|
|
623
|
-
return {
|
|
624
|
-
...table,
|
|
625
|
-
name: ownPrefixed,
|
|
626
|
-
relations: table.relations.map((relation) => {
|
|
627
|
-
return { ...relation, table: rewriteReference(relation.table, key, bareNames) };
|
|
628
|
-
}),
|
|
629
|
-
// Inline `.vectorize()` stamps `table` with the bare owner name, so it
|
|
630
|
-
// is always one of `bareNames` and resolves to `ownPrefixed`.
|
|
631
|
-
vectorIndexes: table.vectorIndexes.map((index) => {
|
|
632
|
-
return { ...index, table: rewriteReference(index.table, key, bareNames) };
|
|
633
|
-
})
|
|
634
|
-
};
|
|
635
|
-
};
|
|
636
|
-
const declarationInitializer = (declaration) => {
|
|
637
|
-
if (Node.isVariableDeclaration(declaration) || Node.isPropertyAssignment(declaration)) {
|
|
638
|
-
return declaration.getInitializer();
|
|
639
|
-
}
|
|
640
|
-
if (Node.isShorthandPropertyAssignment(declaration)) {
|
|
641
|
-
return declaration.getNameNode();
|
|
642
|
-
}
|
|
643
|
-
return void 0;
|
|
644
|
-
};
|
|
645
|
-
const objectPropertyInitializer = (objectLiteral, name) => {
|
|
646
|
-
const property = objectLiteral.getProperty(name);
|
|
647
|
-
if (property && Node.isPropertyAssignment(property)) {
|
|
648
|
-
return property.getInitializer();
|
|
649
|
-
}
|
|
650
|
-
return void 0;
|
|
651
|
-
};
|
|
652
|
-
const isInlineExtensionCall = (argument) => {
|
|
653
|
-
if (!Node.isCallExpression(argument)) {
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
|
-
const callee = argument.getExpression();
|
|
657
|
-
return Node.isIdentifier(callee) && callee.getText() === "defineSchemaExtension";
|
|
658
|
-
};
|
|
659
|
-
const extensionTargetIdentifier = (argument) => {
|
|
660
|
-
if (Node.isIdentifier(argument)) {
|
|
661
|
-
return argument;
|
|
662
|
-
}
|
|
663
|
-
if (Node.isPropertyAccessExpression(argument)) {
|
|
664
|
-
const receiver = argument.getExpression();
|
|
665
|
-
return Node.isIdentifier(receiver) ? receiver : void 0;
|
|
666
|
-
}
|
|
667
|
-
return void 0;
|
|
668
|
-
};
|
|
669
|
-
const pluginConfigObject = (expression) => {
|
|
670
|
-
if (Node.isObjectLiteralExpression(expression)) {
|
|
671
|
-
return expression;
|
|
672
|
-
}
|
|
673
|
-
if (Node.isCallExpression(expression)) {
|
|
674
|
-
const callee = expression.getExpression();
|
|
675
|
-
let name;
|
|
676
|
-
if (Node.isIdentifier(callee)) {
|
|
677
|
-
name = callee.getText();
|
|
678
|
-
} else if (Node.isPropertyAccessExpression(callee)) {
|
|
679
|
-
name = callee.getName();
|
|
680
|
-
}
|
|
681
|
-
if (name === "definePlugin") {
|
|
682
|
-
const configArgument = expression.getArguments()[1];
|
|
683
|
-
return configArgument && Node.isObjectLiteralExpression(configArgument) ? configArgument : void 0;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return void 0;
|
|
687
|
-
};
|
|
688
|
-
const nextExpressionFromDeclaration = (declaration, argument) => {
|
|
689
|
-
const initializer = declarationInitializer(declaration);
|
|
690
|
-
if (!initializer) {
|
|
691
|
-
return void 0;
|
|
692
|
-
}
|
|
693
|
-
if (Node.isPropertyAccessExpression(argument)) {
|
|
694
|
-
const configObject = pluginConfigObject(initializer);
|
|
695
|
-
return configObject ? objectPropertyInitializer(configObject, argument.getName()) : void 0;
|
|
696
|
-
}
|
|
697
|
-
return initializer;
|
|
698
|
-
};
|
|
699
|
-
const resolveSchemaExtensionCall = (argument) => {
|
|
700
|
-
let current = argument;
|
|
701
|
-
let hops = 0;
|
|
702
|
-
while (current && hops < 32) {
|
|
703
|
-
hops += 1;
|
|
704
|
-
if (isInlineExtensionCall(current)) {
|
|
705
|
-
return current;
|
|
706
|
-
}
|
|
707
|
-
const target = extensionTargetIdentifier(current);
|
|
708
|
-
const symbol = target && Node.isIdentifier(target) ? target.getSymbol() : void 0;
|
|
709
|
-
const declarations = symbol?.getAliasedSymbol()?.getDeclarations() ?? symbol?.getDeclarations() ?? [];
|
|
710
|
-
const first = declarations[0];
|
|
711
|
-
if (!first) {
|
|
712
|
-
return void 0;
|
|
713
|
-
}
|
|
714
|
-
const declarationFile = first.getSourceFile();
|
|
715
|
-
if (declarationFile.isInNodeModules() || declarationFile.isDeclarationFile()) {
|
|
716
|
-
return void 0;
|
|
717
|
-
}
|
|
718
|
-
current = nextExpressionFromDeclaration(first, current);
|
|
719
|
-
}
|
|
720
|
-
return void 0;
|
|
721
|
-
};
|
|
722
|
-
const extensionPartsOf = (call) => {
|
|
723
|
-
const [keyArgument, optionsArgument] = call.getArguments();
|
|
724
|
-
if (!keyArgument || !Node.isStringLiteral(keyArgument)) {
|
|
725
|
-
return void 0;
|
|
726
|
-
}
|
|
727
|
-
if (!optionsArgument || !Node.isObjectLiteralExpression(optionsArgument)) {
|
|
728
|
-
return void 0;
|
|
729
|
-
}
|
|
730
|
-
return { key: keyArgument.getLiteralText(), options: optionsArgument };
|
|
731
|
-
};
|
|
732
|
-
const parseExtensionTables = (options) => {
|
|
733
|
-
const tablesProperty = options.getProperty("tables");
|
|
734
|
-
if (!tablesProperty || !Node.isPropertyAssignment(tablesProperty)) {
|
|
735
|
-
return [];
|
|
736
|
-
}
|
|
737
|
-
const tablesObject = tablesProperty.getInitializer();
|
|
738
|
-
if (!tablesObject || !Node.isObjectLiteralExpression(tablesObject)) {
|
|
739
|
-
return [];
|
|
740
|
-
}
|
|
741
|
-
const tables = [];
|
|
742
|
-
for (const property of tablesObject.getProperties()) {
|
|
743
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
744
|
-
continue;
|
|
745
|
-
}
|
|
746
|
-
const initializer = property.getInitializer();
|
|
747
|
-
if (!initializer) {
|
|
748
|
-
continue;
|
|
749
|
-
}
|
|
750
|
-
tables.push(parseTableBuilder(initializer, property.getName()));
|
|
751
|
-
}
|
|
752
|
-
return tables;
|
|
753
|
-
};
|
|
754
|
-
const parseExtensionVectorIndexes = (options) => {
|
|
755
|
-
const property = options.getProperty("vectorIndexes");
|
|
756
|
-
if (!property || !Node.isPropertyAssignment(property)) {
|
|
757
|
-
return [];
|
|
758
|
-
}
|
|
759
|
-
const object = property.getInitializer();
|
|
760
|
-
if (!object || !Node.isObjectLiteralExpression(object)) {
|
|
761
|
-
return [];
|
|
762
|
-
}
|
|
763
|
-
return parseStandaloneVectorIndexes(object);
|
|
764
|
-
};
|
|
765
|
-
const namespaceExtension = (key, bareTables, bareVectorIndexes) => {
|
|
766
|
-
const bareNames = new Set(bareTables.map((table) => table.name));
|
|
767
|
-
const tables = bareTables.map((table) => namespaceExtensionTable(table, key, bareNames));
|
|
768
|
-
const vectorIndexes = bareVectorIndexes.map((index) => {
|
|
769
|
-
return { ...index, name: prefixTableName(key, index.name), table: rewriteReference(index.table, key, bareNames) };
|
|
770
|
-
});
|
|
771
|
-
return { tables, vectorIndexes };
|
|
772
|
-
};
|
|
773
|
-
const mergeExtension = (key, options) => namespaceExtension(key, parseExtensionTables(options), parseExtensionVectorIndexes(options));
|
|
774
|
-
const mergeExtendCall = (extendCall, projectRoot) => {
|
|
775
|
-
const extendArgument = extendCall.getArguments()[0];
|
|
776
|
-
if (!extendArgument) {
|
|
777
|
-
return void 0;
|
|
778
|
-
}
|
|
779
|
-
const resolved = resolveSchemaExtensionCall(extendArgument);
|
|
780
|
-
if (!resolved) {
|
|
781
|
-
if (projectRoot !== void 0) {
|
|
782
|
-
const fromPackage = resolvePackageExtension(extendArgument, projectRoot);
|
|
783
|
-
if (fromPackage) {
|
|
784
|
-
return namespaceExtension(fromPackage.key, fromPackage.bareTables, fromPackage.bareVectorIndexes);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
console.warn(
|
|
788
|
-
`@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.`
|
|
789
|
-
);
|
|
790
|
-
return void 0;
|
|
791
|
-
}
|
|
792
|
-
const parts = extensionPartsOf(resolved);
|
|
793
|
-
if (!parts) {
|
|
794
|
-
console.warn(`@lunora/codegen: skipping \`.extend(...)\` — \`defineSchemaExtension\` requires a string \`key\` and an options object literal.`);
|
|
795
|
-
return void 0;
|
|
796
|
-
}
|
|
797
|
-
return mergeExtension(parts.key, parts.options);
|
|
798
|
-
};
|
|
799
|
-
const extendCallsOf = (defineSchemaCall) => {
|
|
800
|
-
const calls = [];
|
|
801
|
-
let current = defineSchemaCall;
|
|
802
|
-
for (; ; ) {
|
|
803
|
-
const parent = current.getParent();
|
|
804
|
-
if (!parent || !Node.isPropertyAccessExpression(parent)) {
|
|
805
|
-
break;
|
|
806
|
-
}
|
|
807
|
-
const callParent = parent.getParent();
|
|
808
|
-
if (!callParent || !Node.isCallExpression(callParent)) {
|
|
809
|
-
break;
|
|
810
|
-
}
|
|
811
|
-
if (parent.getName() === "extend") {
|
|
812
|
-
calls.push(callParent);
|
|
813
|
-
}
|
|
814
|
-
current = callParent;
|
|
815
|
-
}
|
|
816
|
-
return calls;
|
|
817
|
-
};
|
|
818
|
-
const chainedStringLiteralArgument = (defineSchemaCall, methodName, noun, allowed, expected) => {
|
|
819
|
-
let current = defineSchemaCall;
|
|
820
|
-
for (; ; ) {
|
|
821
|
-
const parent = current.getParent();
|
|
822
|
-
if (!parent || !Node.isPropertyAccessExpression(parent)) {
|
|
823
|
-
break;
|
|
824
|
-
}
|
|
825
|
-
const callParent = parent.getParent();
|
|
826
|
-
if (!callParent || !Node.isCallExpression(callParent)) {
|
|
827
|
-
break;
|
|
828
|
-
}
|
|
829
|
-
if (parent.getName() === methodName) {
|
|
830
|
-
const argument = callParent.getArguments()[0];
|
|
831
|
-
if (!argument || !Node.isStringLiteral(argument)) {
|
|
832
|
-
throw diagnosticAt(callParent, `\`.${methodName}(...)\` expects a string literal (${expected})`);
|
|
833
|
-
}
|
|
834
|
-
const value = argument.getLiteralText();
|
|
835
|
-
if (!allowed.has(value)) {
|
|
836
|
-
throw diagnosticAt(argument, `unknown ${noun} ${JSON.stringify(value)} — expected ${expected}`);
|
|
837
|
-
}
|
|
838
|
-
return value;
|
|
839
|
-
}
|
|
840
|
-
current = callParent;
|
|
841
|
-
}
|
|
842
|
-
return void 0;
|
|
843
|
-
};
|
|
844
|
-
const JURISDICTIONS = /* @__PURE__ */ new Set(["eu", "fedramp", "us"]);
|
|
845
|
-
const jurisdictionOf = (defineSchemaCall) => chainedStringLiteralArgument(defineSchemaCall, "jurisdiction", "jurisdiction", JURISDICTIONS, '"eu", "us", or "fedramp"');
|
|
846
|
-
const RLS_MODES = /* @__PURE__ */ new Set(["required"]);
|
|
847
|
-
const rlsModeOf = (defineSchemaCall) => chainedStringLiteralArgument(defineSchemaCall, "rls", "rls mode", RLS_MODES, '"required"');
|
|
848
|
-
const parseBaseTables = (object) => {
|
|
849
|
-
const tables = [];
|
|
850
|
-
for (const property of object.getProperties()) {
|
|
851
|
-
if (!Node.isPropertyAssignment(property)) {
|
|
852
|
-
continue;
|
|
853
|
-
}
|
|
854
|
-
const initializer = property.getInitializer();
|
|
855
|
-
if (initializer) {
|
|
856
|
-
const name = property.getName();
|
|
857
|
-
assertTableNameAllowed(name, property.getNameNode());
|
|
858
|
-
tables.push(parseTableBuilder(initializer, name));
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
return tables;
|
|
862
|
-
};
|
|
863
|
-
const applyExtensions = (defineSchemaCall, tables, projectRoot) => {
|
|
864
|
-
const existingTableNames = new Set(tables.map((table) => table.name));
|
|
865
|
-
const vectorIndexes = [];
|
|
866
|
-
for (const extendCall of extendCallsOf(defineSchemaCall)) {
|
|
867
|
-
const merged = mergeExtendCall(extendCall, projectRoot);
|
|
868
|
-
if (!merged) {
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
871
|
-
for (const table of merged.tables) {
|
|
872
|
-
if (existingTableNames.has(table.name)) {
|
|
873
|
-
throw diagnosticAt(
|
|
874
|
-
extendCall,
|
|
875
|
-
`defineSchema(...).extend(...): table "${table.name}" already exists — another extension with the same key already contributed it.`
|
|
876
|
-
);
|
|
877
|
-
}
|
|
878
|
-
existingTableNames.add(table.name);
|
|
879
|
-
tables.push(table);
|
|
880
|
-
}
|
|
881
|
-
vectorIndexes.push(...merged.vectorIndexes);
|
|
882
|
-
}
|
|
883
|
-
return vectorIndexes;
|
|
884
|
-
};
|
|
885
|
-
const discoverSchema = (project, schemaPath, projectRoot) => {
|
|
886
|
-
const file = project.addSourceFileAtPath(schemaPath);
|
|
887
|
-
const defineSchemaCall = file.getDescendantsOfKind(SyntaxKind.CallExpression).find((call) => {
|
|
888
|
-
const callee = call.getExpression();
|
|
889
|
-
return Node.isIdentifier(callee) && callee.getText() === "defineSchema";
|
|
890
|
-
});
|
|
891
|
-
if (!defineSchemaCall) {
|
|
892
|
-
throw new LunoraError("INTERNAL", `defineSchema() not found in ${schemaPath}`);
|
|
893
|
-
}
|
|
894
|
-
const argument = defineSchemaCall.getArguments()[0];
|
|
895
|
-
if (!argument || !Node.isObjectLiteralExpression(argument)) {
|
|
896
|
-
throw diagnosticAt(defineSchemaCall, "defineSchema() expects an object literal");
|
|
897
|
-
}
|
|
898
|
-
const tables = parseBaseTables(argument);
|
|
899
|
-
const standaloneArgument = defineSchemaCall.getArguments()[1];
|
|
900
|
-
const standaloneVectorIndexes = standaloneArgument && Node.isObjectLiteralExpression(standaloneArgument) ? parseStandaloneVectorIndexes(standaloneArgument) : [];
|
|
901
|
-
const extensionStandaloneVectorIndexes = applyExtensions(defineSchemaCall, tables, projectRoot);
|
|
902
|
-
const vectorIndexes = [...tables.flatMap((table) => table.vectorIndexes), ...standaloneVectorIndexes, ...extensionStandaloneVectorIndexes];
|
|
903
|
-
return { jurisdiction: jurisdictionOf(defineSchemaCall), rlsMode: rlsModeOf(defineSchemaCall), tables, vectorIndexes };
|
|
904
|
-
};
|
|
905
|
-
|
|
906
|
-
export { discoverSchema as default };
|