@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,544 +0,0 @@
|
|
|
1
|
-
import { readdirSync, lstatSync } from 'node:fs';
|
|
2
|
-
import { join, extname, relative, sep } from 'node:path';
|
|
3
|
-
import { Node, SyntaxKind } from 'ts-morph';
|
|
4
|
-
import { a as parseObjectShape } from './parse-validator-BDGV8iue.mjs';
|
|
5
|
-
import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
|
|
6
|
-
|
|
7
|
-
const FUNCTION_KINDS = /* @__PURE__ */ new Set(["action", "mutation", "query", "stream"]);
|
|
8
|
-
const ANY_TOKEN_RE = /\bany\b(?!\s*(?:\?\s*)?:)/u;
|
|
9
|
-
const STRING_LITERAL_SPAN_RE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`/gu;
|
|
10
|
-
const IDENTIFIER_RE = /^[A-Za-z_$][\w$]*$/u;
|
|
11
|
-
const renderExpandedPropertyKey = (propertyName) => IDENTIFIER_RE.test(propertyName) ? propertyName : JSON.stringify(propertyName);
|
|
12
|
-
const TS_EXTENSION_RE = /\.ts$/u;
|
|
13
|
-
const lunoraRelativePath = (lunoraDirectory, filePath) => relative(lunoraDirectory, filePath).split(sep).join("/").replace(TS_EXTENSION_RE, "");
|
|
14
|
-
const INTERNAL_FACTORIES = {
|
|
15
|
-
internalAction: "action",
|
|
16
|
-
internalMutation: "mutation",
|
|
17
|
-
internalQuery: "query"
|
|
18
|
-
};
|
|
19
|
-
const LIFECYCLE_FACTORIES = {
|
|
20
|
-
onConnect: "connect",
|
|
21
|
-
onDisconnect: "disconnect"
|
|
22
|
-
};
|
|
23
|
-
const GENERATED_SERVER_RE = /(?:^|\/)_generated\/server(?:\.js)?$/u;
|
|
24
|
-
const isLunoraSurfaceModule = (moduleSpecifier) => moduleSpecifier === "@lunora/server" || GENERATED_SERVER_RE.test(moduleSpecifier);
|
|
25
|
-
const resolveCalleeKind = (identifier) => {
|
|
26
|
-
const symbol = identifier.getSymbol();
|
|
27
|
-
if (!symbol) {
|
|
28
|
-
return identifier.getText();
|
|
29
|
-
}
|
|
30
|
-
const declarations = symbol.getDeclarations();
|
|
31
|
-
for (const declaration of declarations) {
|
|
32
|
-
if (!Node.isImportSpecifier(declaration)) {
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const importDeclaration = declaration.getImportDeclaration();
|
|
36
|
-
const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
|
|
37
|
-
if (!isLunoraSurfaceModule(moduleSpecifier)) {
|
|
38
|
-
return void 0;
|
|
39
|
-
}
|
|
40
|
-
return declaration.getNameNode().getText();
|
|
41
|
-
}
|
|
42
|
-
return void 0;
|
|
43
|
-
};
|
|
44
|
-
const resolveBuilderRootKind = (receiver, followedLocal = false) => {
|
|
45
|
-
let current = receiver;
|
|
46
|
-
while (Node.isCallExpression(current)) {
|
|
47
|
-
const inner = current.getExpression();
|
|
48
|
-
if (!Node.isPropertyAccessExpression(inner)) {
|
|
49
|
-
return void 0;
|
|
50
|
-
}
|
|
51
|
-
current = inner.getExpression();
|
|
52
|
-
}
|
|
53
|
-
if (!Node.isIdentifier(current)) {
|
|
54
|
-
return void 0;
|
|
55
|
-
}
|
|
56
|
-
const rootName = resolveCalleeKind(current);
|
|
57
|
-
if (rootName === void 0) {
|
|
58
|
-
if (followedLocal) {
|
|
59
|
-
return void 0;
|
|
60
|
-
}
|
|
61
|
-
const declaration = current.getSymbol()?.getValueDeclaration();
|
|
62
|
-
if (declaration && Node.isVariableDeclaration(declaration)) {
|
|
63
|
-
const initializer = declaration.getInitializer();
|
|
64
|
-
return initializer ? resolveBuilderRootKind(initializer, true) : void 0;
|
|
65
|
-
}
|
|
66
|
-
return void 0;
|
|
67
|
-
}
|
|
68
|
-
if (FUNCTION_KINDS.has(rootName)) {
|
|
69
|
-
return "public";
|
|
70
|
-
}
|
|
71
|
-
return INTERNAL_FACTORIES[rootName] ? "internal" : void 0;
|
|
72
|
-
};
|
|
73
|
-
const exposeFromBuilderChain = (receiver) => {
|
|
74
|
-
let current = receiver;
|
|
75
|
-
while (Node.isCallExpression(current)) {
|
|
76
|
-
const inner = current.getExpression();
|
|
77
|
-
if (!Node.isPropertyAccessExpression(inner)) {
|
|
78
|
-
return void 0;
|
|
79
|
-
}
|
|
80
|
-
if (inner.getName() === "expose") {
|
|
81
|
-
const argument = current.getArguments()[0];
|
|
82
|
-
if (argument !== void 0 && Node.isObjectLiteralExpression(argument)) {
|
|
83
|
-
const restProperty = argument.getProperty("rest");
|
|
84
|
-
if (restProperty !== void 0 && Node.isPropertyAssignment(restProperty)) {
|
|
85
|
-
const initializer = restProperty.getInitializer();
|
|
86
|
-
const rest = initializer?.getText() === "true";
|
|
87
|
-
return { rest };
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return {};
|
|
91
|
-
}
|
|
92
|
-
current = inner.getExpression();
|
|
93
|
-
}
|
|
94
|
-
return void 0;
|
|
95
|
-
};
|
|
96
|
-
const argsFromCall = (call) => {
|
|
97
|
-
const first = call.getArguments()[0];
|
|
98
|
-
if (!first || !Node.isObjectLiteralExpression(first)) {
|
|
99
|
-
return {};
|
|
100
|
-
}
|
|
101
|
-
const argsProperty = first.getProperty("args");
|
|
102
|
-
if (!argsProperty || !Node.isPropertyAssignment(argsProperty)) {
|
|
103
|
-
return {};
|
|
104
|
-
}
|
|
105
|
-
const initializer = argsProperty.getInitializer();
|
|
106
|
-
if (!initializer || !Node.isObjectLiteralExpression(initializer)) {
|
|
107
|
-
return {};
|
|
108
|
-
}
|
|
109
|
-
return parseObjectShape(initializer);
|
|
110
|
-
};
|
|
111
|
-
const symbolDeclaredUnreachable = (type, handlerFilePath) => {
|
|
112
|
-
for (const candidate of [type.getSymbol(), type.getAliasSymbol()]) {
|
|
113
|
-
if (!candidate) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
for (const declaration of candidate.getDeclarations()) {
|
|
117
|
-
const declarationFile = declaration.getSourceFile();
|
|
118
|
-
if (declarationFile.isInNodeModules() || declarationFile.isDeclarationFile()) {
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
if (declarationFile.getFilePath() !== handlerFilePath) {
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
if ((Node.isInterfaceDeclaration(declaration) || Node.isTypeAliasDeclaration(declaration)) && !declaration.isExported()) {
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
};
|
|
131
|
-
const childTypes = (type) => {
|
|
132
|
-
const children = [...type.getTypeArguments()];
|
|
133
|
-
if (type.isUnion()) {
|
|
134
|
-
children.push(...type.getUnionTypes());
|
|
135
|
-
}
|
|
136
|
-
if (type.isIntersection()) {
|
|
137
|
-
children.push(...type.getIntersectionTypes());
|
|
138
|
-
}
|
|
139
|
-
return children;
|
|
140
|
-
};
|
|
141
|
-
const isExpandableObject = (type) => {
|
|
142
|
-
if (!type.isObject() || type.isArray() || type.isTuple()) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
if (type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
return type.getStringIndexType() === void 0 && type.getNumberIndexType() === void 0;
|
|
149
|
-
};
|
|
150
|
-
const referencesUnreachableLocalType = (type, node, handlerFilePath, seen = /* @__PURE__ */ new Set()) => {
|
|
151
|
-
if (seen.has(type)) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
seen.add(type);
|
|
155
|
-
if (symbolDeclaredUnreachable(type, handlerFilePath)) {
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
if (childTypes(type).some((child) => referencesUnreachableLocalType(child, node, handlerFilePath, seen))) {
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
if (!isExpandableObject(type)) {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
return type.getProperties().some((property) => referencesUnreachableLocalType(property.getTypeAtLocation(node), node, handlerFilePath, seen));
|
|
165
|
-
};
|
|
166
|
-
const isOptionalProperty = (property, propertyType) => {
|
|
167
|
-
const declaration = property.getValueDeclaration() ?? property.getDeclarations()[0];
|
|
168
|
-
if (declaration && (Node.isPropertySignature(declaration) || Node.isPropertyDeclaration(declaration)) && declaration.hasQuestionToken()) {
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
return propertyType.isUnion() && propertyType.getUnionTypes().some((member) => member.isUndefined());
|
|
172
|
-
};
|
|
173
|
-
const MAX_EXPANSION_DEPTH = 8;
|
|
174
|
-
const expandArrayType = (type, node, handlerFilePath, depth, nextSeen, expand) => {
|
|
175
|
-
const element = type.getArrayElementType();
|
|
176
|
-
const rendered = element ? expand(element, node, handlerFilePath, depth, nextSeen) : void 0;
|
|
177
|
-
if (rendered === void 0) {
|
|
178
|
-
return void 0;
|
|
179
|
-
}
|
|
180
|
-
return element?.isUnion() ? `(${rendered})[]` : `${rendered}[]`;
|
|
181
|
-
};
|
|
182
|
-
const expandUnionType = (type, node, handlerFilePath, depth, nextSeen, expand) => {
|
|
183
|
-
const parts = [];
|
|
184
|
-
for (const member of type.getUnionTypes()) {
|
|
185
|
-
const rendered = expand(member, node, handlerFilePath, depth, nextSeen);
|
|
186
|
-
if (rendered === void 0) {
|
|
187
|
-
return void 0;
|
|
188
|
-
}
|
|
189
|
-
parts.push(rendered);
|
|
190
|
-
}
|
|
191
|
-
return parts.join(" | ");
|
|
192
|
-
};
|
|
193
|
-
const expandObjectType = (type, node, handlerFilePath, depth, nextSeen, expand) => {
|
|
194
|
-
if (!isExpandableObject(type)) {
|
|
195
|
-
return void 0;
|
|
196
|
-
}
|
|
197
|
-
const parts = [];
|
|
198
|
-
for (const property of type.getProperties()) {
|
|
199
|
-
const propertyType = property.getTypeAtLocation(node);
|
|
200
|
-
const optional = isOptionalProperty(property, propertyType);
|
|
201
|
-
const valueMembers = optional && propertyType.isUnion() ? propertyType.getUnionTypes().filter((member) => !member.isUndefined()) : [propertyType];
|
|
202
|
-
const rendered = [];
|
|
203
|
-
for (const member of valueMembers) {
|
|
204
|
-
const text = expand(member, node, handlerFilePath, depth + 1, nextSeen);
|
|
205
|
-
if (text === void 0) {
|
|
206
|
-
return void 0;
|
|
207
|
-
}
|
|
208
|
-
rendered.push(text);
|
|
209
|
-
}
|
|
210
|
-
parts.push(`${renderExpandedPropertyKey(property.getName())}${optional ? "?" : ""}: ${rendered.join(" | ")}`);
|
|
211
|
-
}
|
|
212
|
-
return parts.length > 0 ? `{ ${parts.join("; ")} }` : "{}";
|
|
213
|
-
};
|
|
214
|
-
const expandUnreachableType = (type, node, handlerFilePath, depth, seen) => {
|
|
215
|
-
if (depth > MAX_EXPANSION_DEPTH || seen.has(type)) {
|
|
216
|
-
return void 0;
|
|
217
|
-
}
|
|
218
|
-
if (!referencesUnreachableLocalType(type, node, handlerFilePath)) {
|
|
219
|
-
return type.getText(node);
|
|
220
|
-
}
|
|
221
|
-
const nextSeen = new Set(seen).add(type);
|
|
222
|
-
if (type.isArray()) {
|
|
223
|
-
return expandArrayType(type, node, handlerFilePath, depth, nextSeen, expandUnreachableType);
|
|
224
|
-
}
|
|
225
|
-
if (type.isUnion()) {
|
|
226
|
-
return expandUnionType(type, node, handlerFilePath, depth, nextSeen, expandUnreachableType);
|
|
227
|
-
}
|
|
228
|
-
return expandObjectType(type, node, handlerFilePath, depth, nextSeen, expandUnreachableType);
|
|
229
|
-
};
|
|
230
|
-
const unwrapHandlerReturn = (handler) => {
|
|
231
|
-
const signature = handler.getType().getCallSignatures()[0];
|
|
232
|
-
if (!signature) {
|
|
233
|
-
return "unknown";
|
|
234
|
-
}
|
|
235
|
-
let returnType = signature.getReturnType();
|
|
236
|
-
const symbol = returnType.getSymbol() ?? returnType.getAliasSymbol();
|
|
237
|
-
const wrapperName = symbol?.getName();
|
|
238
|
-
if (wrapperName === "Promise" || wrapperName === "AsyncIterable" || wrapperName === "AsyncIterableIterator" || wrapperName === "AsyncGenerator") {
|
|
239
|
-
const innerTypeArgument = returnType.getTypeArguments()[0];
|
|
240
|
-
if (innerTypeArgument) {
|
|
241
|
-
returnType = innerTypeArgument;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
const rendered = returnType.getText(handler);
|
|
245
|
-
if (!rendered || rendered === "any" || rendered === "never") {
|
|
246
|
-
return "unknown";
|
|
247
|
-
}
|
|
248
|
-
if (ANY_TOKEN_RE.test(rendered.replaceAll(STRING_LITERAL_SPAN_RE, ""))) {
|
|
249
|
-
return "unknown";
|
|
250
|
-
}
|
|
251
|
-
const handlerFilePath = handler.getSourceFile().getFilePath();
|
|
252
|
-
if (referencesUnreachableLocalType(returnType, handler, handlerFilePath)) {
|
|
253
|
-
return expandUnreachableType(returnType, handler, handlerFilePath, 0, /* @__PURE__ */ new Set()) ?? "unknown";
|
|
254
|
-
}
|
|
255
|
-
return rendered;
|
|
256
|
-
};
|
|
257
|
-
const returnTypeFromCall = (call) => {
|
|
258
|
-
const first = call.getArguments()[0];
|
|
259
|
-
if (!first || !Node.isObjectLiteralExpression(first)) {
|
|
260
|
-
return "unknown";
|
|
261
|
-
}
|
|
262
|
-
const handlerProperty = first.getProperty("handler");
|
|
263
|
-
if (!handlerProperty || !Node.isPropertyAssignment(handlerProperty)) {
|
|
264
|
-
return "unknown";
|
|
265
|
-
}
|
|
266
|
-
const initializer = handlerProperty.getInitializer();
|
|
267
|
-
if (!initializer || !(Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer))) {
|
|
268
|
-
return "unknown";
|
|
269
|
-
}
|
|
270
|
-
return unwrapHandlerReturn(initializer);
|
|
271
|
-
};
|
|
272
|
-
const returnTypeFromBuilderCall = (call) => {
|
|
273
|
-
const handler = call.getArguments()[0];
|
|
274
|
-
if (!handler || !(Node.isArrowFunction(handler) || Node.isFunctionExpression(handler))) {
|
|
275
|
-
return "unknown";
|
|
276
|
-
}
|
|
277
|
-
return unwrapHandlerReturn(handler);
|
|
278
|
-
};
|
|
279
|
-
const argsFromBuilderChain = (receiver) => {
|
|
280
|
-
let merged = {};
|
|
281
|
-
let node = receiver;
|
|
282
|
-
while (Node.isCallExpression(node)) {
|
|
283
|
-
const chainCallee = node.getExpression();
|
|
284
|
-
if (!Node.isPropertyAccessExpression(chainCallee)) {
|
|
285
|
-
break;
|
|
286
|
-
}
|
|
287
|
-
if (chainCallee.getName() === "input") {
|
|
288
|
-
const argument = node.getArguments()[0];
|
|
289
|
-
if (argument && Node.isObjectLiteralExpression(argument)) {
|
|
290
|
-
merged = { ...parseObjectShape(argument), ...merged };
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
node = chainCallee.getExpression();
|
|
294
|
-
}
|
|
295
|
-
return merged;
|
|
296
|
-
};
|
|
297
|
-
const classifyProcedureCall = (call) => {
|
|
298
|
-
const callee = call.getExpression();
|
|
299
|
-
if (Node.isPropertyAccessExpression(callee)) {
|
|
300
|
-
const method = callee.getName();
|
|
301
|
-
if (!FUNCTION_KINDS.has(method)) {
|
|
302
|
-
return void 0;
|
|
303
|
-
}
|
|
304
|
-
const receiver = callee.getExpression();
|
|
305
|
-
if (receiver.getType().getProperty("__lunoraProcedure")) {
|
|
306
|
-
return { kind: method, receiver, visibility: receiver.getType().getProperty("__lunoraVisibility") ? "internal" : "public" };
|
|
307
|
-
}
|
|
308
|
-
const rootKind = resolveBuilderRootKind(receiver);
|
|
309
|
-
if (rootKind) {
|
|
310
|
-
return { kind: method, receiver, visibility: rootKind };
|
|
311
|
-
}
|
|
312
|
-
return void 0;
|
|
313
|
-
}
|
|
314
|
-
if (!Node.isIdentifier(callee)) {
|
|
315
|
-
return void 0;
|
|
316
|
-
}
|
|
317
|
-
const calleeName2 = resolveCalleeKind(callee);
|
|
318
|
-
if (!calleeName2) {
|
|
319
|
-
return void 0;
|
|
320
|
-
}
|
|
321
|
-
if (FUNCTION_KINDS.has(calleeName2)) {
|
|
322
|
-
return { kind: calleeName2, visibility: "public" };
|
|
323
|
-
}
|
|
324
|
-
const internalKind = INTERNAL_FACTORIES[calleeName2];
|
|
325
|
-
if (internalKind) {
|
|
326
|
-
return { kind: internalKind, visibility: "internal" };
|
|
327
|
-
}
|
|
328
|
-
const lifecycle = LIFECYCLE_FACTORIES[calleeName2];
|
|
329
|
-
if (lifecycle) {
|
|
330
|
-
return { kind: "mutation", lifecycle, visibility: "internal" };
|
|
331
|
-
}
|
|
332
|
-
return void 0;
|
|
333
|
-
};
|
|
334
|
-
const inlineHandler = (argument) => argument !== void 0 && (Node.isArrowFunction(argument) || Node.isFunctionExpression(argument)) ? argument : void 0;
|
|
335
|
-
const isDatabaseAccessor = (receiver) => Node.isPropertyAccessExpression(receiver) && receiver.getName() === "db" || Node.isIdentifier(receiver) && receiver.getText() === "db";
|
|
336
|
-
const procedureHandler = (initializer) => {
|
|
337
|
-
const argument = initializer.getArguments()[0];
|
|
338
|
-
const direct = inlineHandler(argument);
|
|
339
|
-
if (direct !== void 0) {
|
|
340
|
-
return direct;
|
|
341
|
-
}
|
|
342
|
-
if (argument === void 0 || !Node.isObjectLiteralExpression(argument)) {
|
|
343
|
-
return void 0;
|
|
344
|
-
}
|
|
345
|
-
const property = argument.getProperty("handler");
|
|
346
|
-
return property !== void 0 && Node.isPropertyAssignment(property) ? inlineHandler(property.getInitializer()) : void 0;
|
|
347
|
-
};
|
|
348
|
-
const calleeName = (callee) => {
|
|
349
|
-
if (Node.isIdentifier(callee)) {
|
|
350
|
-
return callee.getText();
|
|
351
|
-
}
|
|
352
|
-
return Node.isPropertyAccessExpression(callee) ? callee.getName() : "";
|
|
353
|
-
};
|
|
354
|
-
const chainHasStep = (receiver, method) => {
|
|
355
|
-
let node = receiver;
|
|
356
|
-
while (Node.isCallExpression(node)) {
|
|
357
|
-
const callee = node.getExpression();
|
|
358
|
-
if (!Node.isPropertyAccessExpression(callee)) {
|
|
359
|
-
break;
|
|
360
|
-
}
|
|
361
|
-
if (callee.getName() === method) {
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
node = callee.getExpression();
|
|
365
|
-
}
|
|
366
|
-
return false;
|
|
367
|
-
};
|
|
368
|
-
const chainUsesWrappedCall = (receiver, method, wrappedCallee) => {
|
|
369
|
-
let node = receiver;
|
|
370
|
-
while (Node.isCallExpression(node)) {
|
|
371
|
-
const callee = node.getExpression();
|
|
372
|
-
if (!Node.isPropertyAccessExpression(callee)) {
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
const argument = node.getArguments()[0];
|
|
376
|
-
if (callee.getName() === method && argument !== void 0 && Node.isCallExpression(argument) && calleeName(argument.getExpression()) === wrappedCallee) {
|
|
377
|
-
return true;
|
|
378
|
-
}
|
|
379
|
-
node = callee.getExpression();
|
|
380
|
-
}
|
|
381
|
-
return false;
|
|
382
|
-
};
|
|
383
|
-
const listLunoraSourceFiles = (directory, accumulator = [], root = directory) => {
|
|
384
|
-
let entries;
|
|
385
|
-
try {
|
|
386
|
-
entries = readdirSync(directory);
|
|
387
|
-
} catch {
|
|
388
|
-
return accumulator;
|
|
389
|
-
}
|
|
390
|
-
for (const entry of entries) {
|
|
391
|
-
const full = join(directory, entry);
|
|
392
|
-
const info = lstatSync(full);
|
|
393
|
-
if (info.isDirectory()) {
|
|
394
|
-
if (entry === "_generated" || entry === "node_modules") {
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
listLunoraSourceFiles(full, accumulator, root);
|
|
398
|
-
} else if (info.isFile() && extname(entry) === ".ts") {
|
|
399
|
-
if (entry === "schema.ts" && directory === root) {
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
accumulator.push(full);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return accumulator;
|
|
406
|
-
};
|
|
407
|
-
const discoverFromCall = (call) => {
|
|
408
|
-
const classified = classifyProcedureCall(call);
|
|
409
|
-
if (!classified) {
|
|
410
|
-
return void 0;
|
|
411
|
-
}
|
|
412
|
-
if (classified.receiver) {
|
|
413
|
-
const expose = exposeFromBuilderChain(classified.receiver);
|
|
414
|
-
return {
|
|
415
|
-
args: argsFromBuilderChain(classified.receiver),
|
|
416
|
-
...expose ? { expose } : {},
|
|
417
|
-
kind: classified.kind,
|
|
418
|
-
returnType: returnTypeFromBuilderCall(call),
|
|
419
|
-
visibility: classified.visibility
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
if (classified.lifecycle) {
|
|
423
|
-
return { args: {}, kind: classified.kind, lifecycle: classified.lifecycle, returnType: "void", visibility: classified.visibility };
|
|
424
|
-
}
|
|
425
|
-
return {
|
|
426
|
-
args: argsFromCall(call),
|
|
427
|
-
kind: classified.kind,
|
|
428
|
-
returnType: returnTypeFromCall(call),
|
|
429
|
-
visibility: classified.visibility
|
|
430
|
-
};
|
|
431
|
-
};
|
|
432
|
-
const RE_EXPORT_RESOLVE_LIMIT = 8;
|
|
433
|
-
const resolveExpressionToCall = (node, depth = 0) => {
|
|
434
|
-
if (depth > RE_EXPORT_RESOLVE_LIMIT) {
|
|
435
|
-
return void 0;
|
|
436
|
-
}
|
|
437
|
-
if (Node.isCallExpression(node)) {
|
|
438
|
-
return node;
|
|
439
|
-
}
|
|
440
|
-
if (Node.isParenthesizedExpression(node) || Node.isAsExpression(node) || Node.isSatisfiesExpression(node) || Node.isNonNullExpression(node)) {
|
|
441
|
-
return resolveExpressionToCall(node.getExpression(), depth + 1);
|
|
442
|
-
}
|
|
443
|
-
if (!Node.isIdentifier(node) && !Node.isPropertyAccessExpression(node)) {
|
|
444
|
-
return void 0;
|
|
445
|
-
}
|
|
446
|
-
const declaration = node.getSymbol()?.getValueDeclaration();
|
|
447
|
-
return declaration ? resolveDeclarationToCall(declaration, depth + 1) : void 0;
|
|
448
|
-
};
|
|
449
|
-
const resolveDeclarationToCall = (declaration, depth) => {
|
|
450
|
-
if (Node.isVariableDeclaration(declaration) || Node.isPropertyAssignment(declaration)) {
|
|
451
|
-
const initializer = declaration.getInitializer();
|
|
452
|
-
return initializer ? resolveExpressionToCall(initializer, depth) : void 0;
|
|
453
|
-
}
|
|
454
|
-
if (Node.isShorthandPropertyAssignment(declaration)) {
|
|
455
|
-
return resolveExpressionToCall(declaration.getNameNode(), depth);
|
|
456
|
-
}
|
|
457
|
-
if (Node.isBindingElement(declaration)) {
|
|
458
|
-
const propertyName = declaration.getPropertyNameNode()?.getText() ?? declaration.getName();
|
|
459
|
-
const variableDeclaration = declaration.getFirstAncestorByKind(SyntaxKind.VariableDeclaration);
|
|
460
|
-
const rightHandSide = variableDeclaration?.getInitializer();
|
|
461
|
-
const propertyDeclaration = rightHandSide?.getType().getProperty(propertyName)?.getValueDeclaration();
|
|
462
|
-
return propertyDeclaration ? resolveDeclarationToCall(propertyDeclaration, depth + 1) : void 0;
|
|
463
|
-
}
|
|
464
|
-
return void 0;
|
|
465
|
-
};
|
|
466
|
-
const exportCallsOfDeclaration = (declaration) => {
|
|
467
|
-
const nameNode = declaration.getNameNode();
|
|
468
|
-
if (Node.isObjectBindingPattern(nameNode)) {
|
|
469
|
-
const pairs = [];
|
|
470
|
-
for (const element of nameNode.getElements()) {
|
|
471
|
-
const call2 = resolveExpressionToCall(element.getNameNode());
|
|
472
|
-
if (call2) {
|
|
473
|
-
pairs.push([element.getName(), call2]);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
return pairs;
|
|
477
|
-
}
|
|
478
|
-
const initializer = declaration.getInitializer();
|
|
479
|
-
const call = initializer && (Node.isCallExpression(initializer) ? initializer : resolveExpressionToCall(initializer));
|
|
480
|
-
return call ? [[declaration.getName(), call]] : [];
|
|
481
|
-
};
|
|
482
|
-
const functionIrFromCall = (call, exportName, relativePath) => {
|
|
483
|
-
const discovered = discoverFromCall(call);
|
|
484
|
-
if (!discovered) {
|
|
485
|
-
return void 0;
|
|
486
|
-
}
|
|
487
|
-
return {
|
|
488
|
-
args: discovered.args,
|
|
489
|
-
exportName,
|
|
490
|
-
filePath: relativePath,
|
|
491
|
-
kind: discovered.kind,
|
|
492
|
-
returnType: discovered.returnType,
|
|
493
|
-
visibility: discovered.visibility,
|
|
494
|
-
...discovered.expose ? { expose: discovered.expose } : {},
|
|
495
|
-
...discovered.lifecycle ? { lifecycle: discovered.lifecycle } : {}
|
|
496
|
-
};
|
|
497
|
-
};
|
|
498
|
-
const discoverFileFunctions = (source, relativePath) => {
|
|
499
|
-
const found = [];
|
|
500
|
-
for (const statement of source.getVariableStatements()) {
|
|
501
|
-
if (!statement.isExported()) {
|
|
502
|
-
continue;
|
|
503
|
-
}
|
|
504
|
-
for (const declaration of statement.getDeclarations()) {
|
|
505
|
-
for (const [exportName, call] of exportCallsOfDeclaration(declaration)) {
|
|
506
|
-
const entry = functionIrFromCall(call, exportName, relativePath);
|
|
507
|
-
if (entry) {
|
|
508
|
-
found.push(entry);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
return found;
|
|
514
|
-
};
|
|
515
|
-
const assertNoNamespaceCollision = (functions) => {
|
|
516
|
-
const namespaceOrigins = /* @__PURE__ */ new Map();
|
|
517
|
-
for (const entry of functions) {
|
|
518
|
-
const namespace = sanitizeNamespace(entry.filePath);
|
|
519
|
-
const prior = namespaceOrigins.get(namespace);
|
|
520
|
-
if (prior && prior !== entry.filePath) {
|
|
521
|
-
throw Object.assign(
|
|
522
|
-
new Error(
|
|
523
|
-
`Namespace collision: "${prior}" and "${entry.filePath}" both resolve to "${namespace}". Rename one of the files so the JS-identifier-sanitized names differ. (note: case-insensitive filesystems may also cause this — \`foo\` and \`FOO\` map to the same identifier)`
|
|
524
|
-
),
|
|
525
|
-
{ code: "NAMESPACE_COLLISION", name: "LunoraError", paths: [prior, entry.filePath], status: 500 }
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
namespaceOrigins.set(namespace, entry.filePath);
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
const discoverFunctions = (project, lunoraDirectory) => {
|
|
532
|
-
const filePaths = listLunoraSourceFiles(lunoraDirectory);
|
|
533
|
-
const functions = [];
|
|
534
|
-
for (const filePath of filePaths) {
|
|
535
|
-
const source = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
|
|
536
|
-
const relativePath = lunoraRelativePath(lunoraDirectory, filePath);
|
|
537
|
-
functions.push(...discoverFileFunctions(source, relativePath));
|
|
538
|
-
}
|
|
539
|
-
functions.sort((a, b) => `${a.filePath}:${a.exportName}`.localeCompare(`${b.filePath}:${b.exportName}`));
|
|
540
|
-
assertNoNamespaceCollision(functions);
|
|
541
|
-
return functions;
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
export { chainHasStep, chainUsesWrappedCall, classifyProcedureCall, discoverFunctions, inlineHandler, isDatabaseAccessor, listLunoraSourceFiles, lunoraRelativePath, procedureHandler, unwrapHandlerReturn };
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { relative, sep } from 'node:path';
|
|
2
|
-
import { Node } from 'ts-morph';
|
|
3
|
-
import { listLunoraSourceFiles, unwrapHandlerReturn } from './discoverFunctions-COG_Xkyz.mjs';
|
|
4
|
-
import { p as parseValidator, a as parseObjectShape } from './parse-validator-BDGV8iue.mjs';
|
|
5
|
-
|
|
6
|
-
const TS_EXTENSION_RE = /\.ts$/u;
|
|
7
|
-
const HTTP_VERBS = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
|
|
8
|
-
const MAP_STEPS = /* @__PURE__ */ new Set(["body", "params", "searchParams"]);
|
|
9
|
-
const TERMINAL_STEPS = /* @__PURE__ */ new Set(["handler", "stream"]);
|
|
10
|
-
const readPathLiteral = (call) => {
|
|
11
|
-
const first = call.getArguments()[0];
|
|
12
|
-
if (first && Node.isStringLiteral(first)) {
|
|
13
|
-
return first.getLiteralValue();
|
|
14
|
-
}
|
|
15
|
-
return void 0;
|
|
16
|
-
};
|
|
17
|
-
const readMapArgument = (call) => {
|
|
18
|
-
const first = call.getArguments()[0];
|
|
19
|
-
return first && Node.isObjectLiteralExpression(first) ? parseObjectShape(first) : {};
|
|
20
|
-
};
|
|
21
|
-
const readRootVerb = (node) => {
|
|
22
|
-
if (!Node.isCallExpression(node)) {
|
|
23
|
-
return void 0;
|
|
24
|
-
}
|
|
25
|
-
const callee = node.getExpression();
|
|
26
|
-
if (!Node.isPropertyAccessExpression(callee)) {
|
|
27
|
-
return void 0;
|
|
28
|
-
}
|
|
29
|
-
const verb = callee.getName();
|
|
30
|
-
if (!HTTP_VERBS.has(verb)) {
|
|
31
|
-
return void 0;
|
|
32
|
-
}
|
|
33
|
-
const receiver = callee.getExpression();
|
|
34
|
-
if (!Node.isIdentifier(receiver) || receiver.getText() !== "httpRoute") {
|
|
35
|
-
return void 0;
|
|
36
|
-
}
|
|
37
|
-
const path = readPathLiteral(node);
|
|
38
|
-
return path === void 0 ? void 0 : { method: verb.toUpperCase(), path };
|
|
39
|
-
};
|
|
40
|
-
const walkRouteChain = (terminalCall, terminalStep) => {
|
|
41
|
-
const state = { body: {}, params: {}, searchParams: {}, stream: terminalStep === "stream" };
|
|
42
|
-
const terminalCallee = terminalCall.getExpression();
|
|
43
|
-
if (!Node.isPropertyAccessExpression(terminalCallee)) {
|
|
44
|
-
return void 0;
|
|
45
|
-
}
|
|
46
|
-
let node = terminalCallee.getExpression();
|
|
47
|
-
while (Node.isCallExpression(node)) {
|
|
48
|
-
const callee = node.getExpression();
|
|
49
|
-
if (!Node.isPropertyAccessExpression(callee)) {
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
const step = callee.getName();
|
|
53
|
-
if (HTTP_VERBS.has(step)) {
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
if (MAP_STEPS.has(step)) {
|
|
57
|
-
const map = readMapArgument(node);
|
|
58
|
-
state[step] = { ...map, ...state[step] };
|
|
59
|
-
} else if (step === "output" && state.output === void 0) {
|
|
60
|
-
const argument = node.getArguments()[0];
|
|
61
|
-
if (argument && Node.isExpression(argument)) {
|
|
62
|
-
state.output = parseValidator(argument);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
node = callee.getExpression();
|
|
66
|
-
}
|
|
67
|
-
const root = readRootVerb(node);
|
|
68
|
-
if (!root) {
|
|
69
|
-
return void 0;
|
|
70
|
-
}
|
|
71
|
-
state.method = root.method;
|
|
72
|
-
state.path = root.path;
|
|
73
|
-
return state;
|
|
74
|
-
};
|
|
75
|
-
const chunkTypeFromStreamTerminal = (call) => {
|
|
76
|
-
const handler = call.getArguments()[0];
|
|
77
|
-
if (!handler || !(Node.isArrowFunction(handler) || Node.isFunctionExpression(handler))) {
|
|
78
|
-
return "unknown";
|
|
79
|
-
}
|
|
80
|
-
return unwrapHandlerReturn(handler);
|
|
81
|
-
};
|
|
82
|
-
const routeFromTerminal = (call, callee, exportName, filePath) => {
|
|
83
|
-
const step = callee.getName();
|
|
84
|
-
if (!TERMINAL_STEPS.has(step)) {
|
|
85
|
-
return void 0;
|
|
86
|
-
}
|
|
87
|
-
const state = walkRouteChain(call, step);
|
|
88
|
-
if (state?.method === void 0 || state.path === void 0) {
|
|
89
|
-
return void 0;
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
body: state.body,
|
|
93
|
-
exportName,
|
|
94
|
-
filePath,
|
|
95
|
-
method: state.method,
|
|
96
|
-
params: state.params,
|
|
97
|
-
path: state.path,
|
|
98
|
-
searchParams: state.searchParams,
|
|
99
|
-
stream: state.stream,
|
|
100
|
-
...state.stream ? { chunkType: chunkTypeFromStreamTerminal(call) } : {},
|
|
101
|
-
...state.output ? { output: state.output } : {}
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
const discoverFileRoutes = (source, relativePath) => {
|
|
105
|
-
const found = [];
|
|
106
|
-
for (const statement of source.getVariableStatements()) {
|
|
107
|
-
if (!statement.isExported()) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
for (const declaration of statement.getDeclarations()) {
|
|
111
|
-
const initializer = declaration.getInitializer();
|
|
112
|
-
if (!initializer || !Node.isCallExpression(initializer)) {
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
const callee = initializer.getExpression();
|
|
116
|
-
if (!Node.isPropertyAccessExpression(callee)) {
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
const route = routeFromTerminal(initializer, callee, declaration.getName(), relativePath);
|
|
120
|
-
if (route) {
|
|
121
|
-
found.push(route);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return found;
|
|
126
|
-
};
|
|
127
|
-
const discoverHttpRoutes = (project, lunoraDirectory) => {
|
|
128
|
-
const filePaths = listLunoraSourceFiles(lunoraDirectory);
|
|
129
|
-
const routes = [];
|
|
130
|
-
for (const filePath of filePaths) {
|
|
131
|
-
const source = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
|
|
132
|
-
const relativePath = relative(lunoraDirectory, filePath).split(sep).join("/").replace(TS_EXTENSION_RE, "");
|
|
133
|
-
routes.push(...discoverFileRoutes(source, relativePath));
|
|
134
|
-
}
|
|
135
|
-
routes.sort((a, b) => `${a.method} ${a.path}`.localeCompare(`${b.method} ${b.path}`) || a.filePath.localeCompare(b.filePath));
|
|
136
|
-
return routes;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
export { discoverHttpRoutes as default };
|