@soda-gql/babel-plugin 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -14
- package/dist/index.cjs +4 -610
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -580
- package/dist/index.mjs.map +1 -1
- package/package.json +29 -11
package/dist/index.mjs
CHANGED
|
@@ -1,580 +1,7 @@
|
|
|
1
1
|
import { types } from "@babel/core";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { err, ok } from "neverthrow";
|
|
5
|
-
import * as t from "@babel/types";
|
|
2
|
+
import { createTransformer } from "@soda-gql/babel-transformer";
|
|
3
|
+
import { createPluginSession } from "@soda-gql/plugin-common";
|
|
6
4
|
|
|
7
|
-
//#region packages/babel-plugin/src/ast/imports.ts
|
|
8
|
-
const RUNTIME_MODULE = "@soda-gql/runtime";
|
|
9
|
-
/**
|
|
10
|
-
* Ensure that the gqlRuntime import exists in the program.
|
|
11
|
-
* gqlRuntime is always imported from @soda-gql/runtime.
|
|
12
|
-
*/
|
|
13
|
-
const ensureGqlRuntimeImport = (programPath) => {
|
|
14
|
-
const existing = programPath.node.body.find((statement) => statement.type === "ImportDeclaration" && statement.source.value === RUNTIME_MODULE);
|
|
15
|
-
if (existing && types.isImportDeclaration(existing)) {
|
|
16
|
-
if (!existing.specifiers.some((specifier) => specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && specifier.imported.name === "gqlRuntime")) existing.specifiers = [...existing.specifiers, types.importSpecifier(types.identifier("gqlRuntime"), types.identifier("gqlRuntime"))];
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
programPath.node.body.unshift(types.importDeclaration([types.importSpecifier(types.identifier("gqlRuntime"), types.identifier("gqlRuntime"))], types.stringLiteral(RUNTIME_MODULE)));
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Remove the graphql-system import (runtimeModule) and gql-related exports from the program.
|
|
23
|
-
* After transformation, gqlRuntime is imported from @soda-gql/runtime instead,
|
|
24
|
-
* so the original graphql-system import should be completely removed.
|
|
25
|
-
*
|
|
26
|
-
* This handles both ESM imports and CommonJS require() statements.
|
|
27
|
-
*/
|
|
28
|
-
const removeGraphqlSystemImports = (programPath, graphqlSystemIdentifyHelper, filename) => {
|
|
29
|
-
const toRemove = [];
|
|
30
|
-
programPath.traverse({
|
|
31
|
-
ImportDeclaration(path) {
|
|
32
|
-
if (types.isStringLiteral(path.node.source)) {
|
|
33
|
-
if (graphqlSystemIdentifyHelper.isGraphqlSystemImportSpecifier({
|
|
34
|
-
filePath: filename,
|
|
35
|
-
specifier: path.node.source.value
|
|
36
|
-
})) toRemove.push(path);
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
VariableDeclaration(path) {
|
|
40
|
-
if (path.node.declarations.every((decl) => {
|
|
41
|
-
const specifier = extractRequireTargetSpecifier(decl.init);
|
|
42
|
-
if (!specifier) return false;
|
|
43
|
-
return graphqlSystemIdentifyHelper.isGraphqlSystemImportSpecifier({
|
|
44
|
-
filePath: filename,
|
|
45
|
-
specifier
|
|
46
|
-
});
|
|
47
|
-
})) toRemove.push(path);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
for (const path of toRemove) path.remove();
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Check if an expression is a require() call and extract its target specifier.
|
|
54
|
-
* Handles multiple patterns:
|
|
55
|
-
* - require("@/graphql-system")
|
|
56
|
-
* - Object(require("@/graphql-system")) (interop helper pattern)
|
|
57
|
-
*/
|
|
58
|
-
const extractRequireTargetSpecifier = (expr) => {
|
|
59
|
-
if (!expr) return;
|
|
60
|
-
if (types.isCallExpression(expr)) {
|
|
61
|
-
if (types.isIdentifier(expr.callee) && expr.callee.name === "require") {
|
|
62
|
-
const arg = expr.arguments[0];
|
|
63
|
-
if (arg && types.isStringLiteral(arg)) return arg.value;
|
|
64
|
-
}
|
|
65
|
-
if (types.isIdentifier(expr.callee) && (expr.callee.name === "Object" || expr.callee.name.startsWith("__import"))) {
|
|
66
|
-
const arg = expr.arguments[0];
|
|
67
|
-
if (arg && types.isCallExpression(arg)) {
|
|
68
|
-
if (types.isIdentifier(arg.callee) && arg.callee.name === "require") {
|
|
69
|
-
const requireArg = arg.arguments[0];
|
|
70
|
-
if (requireArg && types.isStringLiteral(requireArg)) return requireArg.value;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
//#endregion
|
|
78
|
-
//#region packages/babel-plugin/src/ast/metadata.ts
|
|
79
|
-
const collectGqlDefinitionMetadata = ({ programPath, filename, createTracker }) => {
|
|
80
|
-
const exportBindings = collectExportBindings(programPath.node);
|
|
81
|
-
const tracker = (createTracker ?? createCanonicalTracker)({
|
|
82
|
-
filePath: filename,
|
|
83
|
-
getExportName: (localName) => exportBindings.get(localName)
|
|
84
|
-
});
|
|
85
|
-
const getAnonymousName = createAnonymousNameFactory();
|
|
86
|
-
const scopeHandles = /* @__PURE__ */ new WeakMap();
|
|
87
|
-
const metadata = /* @__PURE__ */ new WeakMap();
|
|
88
|
-
programPath.traverse({
|
|
89
|
-
enter(path) {
|
|
90
|
-
if (path.isCallExpression() && isGqlDefinitionCall(path.node)) {
|
|
91
|
-
const depthBeforeRegister = tracker.currentDepth();
|
|
92
|
-
const { astPath } = tracker.registerDefinition();
|
|
93
|
-
const isTopLevel = depthBeforeRegister <= 1;
|
|
94
|
-
const exportInfo = isTopLevel ? resolveTopLevelExport(path, exportBindings) : null;
|
|
95
|
-
metadata.set(path.node, {
|
|
96
|
-
astPath,
|
|
97
|
-
isTopLevel,
|
|
98
|
-
isExported: exportInfo?.isExported ?? false,
|
|
99
|
-
exportBinding: exportInfo?.exportBinding
|
|
100
|
-
});
|
|
101
|
-
path.skip();
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const handle = maybeEnterScope(path, tracker, getAnonymousName);
|
|
105
|
-
if (handle) scopeHandles.set(path, handle);
|
|
106
|
-
},
|
|
107
|
-
exit(path) {
|
|
108
|
-
const handle = scopeHandles.get(path);
|
|
109
|
-
if (handle) {
|
|
110
|
-
tracker.exitScope(handle);
|
|
111
|
-
scopeHandles.delete(path);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
return metadata;
|
|
116
|
-
};
|
|
117
|
-
const collectExportBindings = (program) => {
|
|
118
|
-
const bindings = /* @__PURE__ */ new Map();
|
|
119
|
-
for (const statement of program.body) {
|
|
120
|
-
if (types.isExportNamedDeclaration(statement) && statement.declaration) {
|
|
121
|
-
const { declaration } = statement;
|
|
122
|
-
if (types.isVariableDeclaration(declaration)) {
|
|
123
|
-
for (const declarator of declaration.declarations) if (types.isIdentifier(declarator.id)) bindings.set(declarator.id.name, declarator.id.name);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if ((types.isFunctionDeclaration(declaration) || types.isClassDeclaration(declaration)) && declaration.id) bindings.set(declaration.id.name, declaration.id.name);
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
if (types.isExpressionStatement(statement) && types.isAssignmentExpression(statement.expression)) {
|
|
130
|
-
const exportName = getCommonJsExportName(statement.expression.left);
|
|
131
|
-
if (exportName) bindings.set(exportName, exportName);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return bindings;
|
|
135
|
-
};
|
|
136
|
-
const getCommonJsExportName = (node) => {
|
|
137
|
-
if (!types.isMemberExpression(node) || node.computed) return null;
|
|
138
|
-
const isExports = types.isIdentifier(node.object, { name: "exports" });
|
|
139
|
-
const isModuleExports = types.isMemberExpression(node.object) && types.isIdentifier(node.object.object, { name: "module" }) && types.isIdentifier(node.object.property, { name: "exports" });
|
|
140
|
-
if (!isExports && !isModuleExports) return null;
|
|
141
|
-
if (types.isIdentifier(node.property)) return node.property.name;
|
|
142
|
-
if (types.isStringLiteral(node.property)) return node.property.value;
|
|
143
|
-
return null;
|
|
144
|
-
};
|
|
145
|
-
const createAnonymousNameFactory = () => {
|
|
146
|
-
const counters = /* @__PURE__ */ new Map();
|
|
147
|
-
return (kind) => {
|
|
148
|
-
const count = counters.get(kind) ?? 0;
|
|
149
|
-
counters.set(kind, count + 1);
|
|
150
|
-
return `${kind}#${count}`;
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
const isGqlDefinitionCall = (node) => types.isCallExpression(node) && types.isMemberExpression(node.callee) && isGqlReference$1(node.callee.object) && node.arguments.length > 0 && types.isArrowFunctionExpression(node.arguments[0]);
|
|
154
|
-
const isGqlReference$1 = (expr) => {
|
|
155
|
-
if (types.isIdentifier(expr, { name: "gql" })) return true;
|
|
156
|
-
if (!types.isMemberExpression(expr) || expr.computed) return false;
|
|
157
|
-
if (types.isIdentifier(expr.property) && expr.property.name === "gql" || types.isStringLiteral(expr.property) && expr.property.value === "gql") return true;
|
|
158
|
-
return isGqlReference$1(expr.object);
|
|
159
|
-
};
|
|
160
|
-
const resolveTopLevelExport = (callPath, exportBindings) => {
|
|
161
|
-
const declarator = callPath.parentPath;
|
|
162
|
-
if (declarator?.isVariableDeclarator()) {
|
|
163
|
-
const { id } = declarator.node;
|
|
164
|
-
if (types.isIdentifier(id)) {
|
|
165
|
-
const exportBinding = exportBindings.get(id.name);
|
|
166
|
-
if (exportBinding) return {
|
|
167
|
-
isExported: true,
|
|
168
|
-
exportBinding
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
const assignment = callPath.parentPath;
|
|
173
|
-
if (assignment?.isAssignmentExpression()) {
|
|
174
|
-
const exportName = getCommonJsExportName(assignment.node.left);
|
|
175
|
-
if (exportName && exportBindings.has(exportName)) return {
|
|
176
|
-
isExported: true,
|
|
177
|
-
exportBinding: exportName
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
return null;
|
|
181
|
-
};
|
|
182
|
-
const maybeEnterScope = (path, tracker, getAnonymousName) => {
|
|
183
|
-
if (path.isAssignmentExpression()) {
|
|
184
|
-
const exportName = getCommonJsExportName(path.node.left);
|
|
185
|
-
if (exportName) return tracker.enterScope({
|
|
186
|
-
segment: exportName,
|
|
187
|
-
kind: "variable",
|
|
188
|
-
stableKey: `var:${exportName}`
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
if (path.isVariableDeclarator() && types.isIdentifier(path.node.id)) {
|
|
192
|
-
const name = path.node.id.name;
|
|
193
|
-
return tracker.enterScope({
|
|
194
|
-
segment: name,
|
|
195
|
-
kind: "variable",
|
|
196
|
-
stableKey: `var:${name}`
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
if (path.isArrowFunctionExpression()) {
|
|
200
|
-
const name = getAnonymousName("arrow");
|
|
201
|
-
return tracker.enterScope({
|
|
202
|
-
segment: name,
|
|
203
|
-
kind: "function",
|
|
204
|
-
stableKey: "arrow"
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
if (path.isFunctionDeclaration() || path.isFunctionExpression()) {
|
|
208
|
-
const name = path.node.id?.name ?? getAnonymousName("function");
|
|
209
|
-
return tracker.enterScope({
|
|
210
|
-
segment: name,
|
|
211
|
-
kind: "function",
|
|
212
|
-
stableKey: `func:${name}`
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
if (path.isClassDeclaration()) {
|
|
216
|
-
const name = path.node.id?.name ?? getAnonymousName("class");
|
|
217
|
-
return tracker.enterScope({
|
|
218
|
-
segment: name,
|
|
219
|
-
kind: "class",
|
|
220
|
-
stableKey: `class:${name}`
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
if (path.isClassMethod() && types.isIdentifier(path.node.key)) {
|
|
224
|
-
const name = path.node.key.name;
|
|
225
|
-
return tracker.enterScope({
|
|
226
|
-
segment: name,
|
|
227
|
-
kind: "method",
|
|
228
|
-
stableKey: `member:${name}`
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
if (path.isClassProperty() && types.isIdentifier(path.node.key)) {
|
|
232
|
-
const name = path.node.key.name;
|
|
233
|
-
return tracker.enterScope({
|
|
234
|
-
segment: name,
|
|
235
|
-
kind: "property",
|
|
236
|
-
stableKey: `member:${name}`
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
if (path.isObjectProperty()) {
|
|
240
|
-
const key = path.node.key;
|
|
241
|
-
const name = types.isIdentifier(key) ? key.name : types.isStringLiteral(key) ? key.value : null;
|
|
242
|
-
if (name) return tracker.enterScope({
|
|
243
|
-
segment: name,
|
|
244
|
-
kind: "property",
|
|
245
|
-
stableKey: `prop:${name}`
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
return null;
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
//#endregion
|
|
252
|
-
//#region packages/babel-plugin/src/ast/analysis.ts
|
|
253
|
-
const extractGqlCall = ({ nodePath, filename, metadata, builderCall, getArtifact }) => {
|
|
254
|
-
const callExpression = nodePath.node;
|
|
255
|
-
const meta = metadata.get(callExpression);
|
|
256
|
-
if (!meta) return err(createMetadataMissingError({ filename }));
|
|
257
|
-
const canonicalId = resolveCanonicalId(filename, meta.astPath);
|
|
258
|
-
const artifact = getArtifact(canonicalId);
|
|
259
|
-
if (!artifact) return err(createArtifactMissingError({
|
|
260
|
-
filename,
|
|
261
|
-
canonicalId
|
|
262
|
-
}));
|
|
263
|
-
if (artifact.type === "model") return ok({
|
|
264
|
-
nodePath,
|
|
265
|
-
canonicalId,
|
|
266
|
-
builderCall,
|
|
267
|
-
type: "model",
|
|
268
|
-
artifact
|
|
269
|
-
});
|
|
270
|
-
if (artifact.type === "slice") return ok({
|
|
271
|
-
nodePath,
|
|
272
|
-
canonicalId,
|
|
273
|
-
builderCall,
|
|
274
|
-
type: "slice",
|
|
275
|
-
artifact
|
|
276
|
-
});
|
|
277
|
-
if (artifact.type === "operation") return ok({
|
|
278
|
-
nodePath,
|
|
279
|
-
canonicalId,
|
|
280
|
-
builderCall,
|
|
281
|
-
type: "operation",
|
|
282
|
-
artifact
|
|
283
|
-
});
|
|
284
|
-
if (artifact.type === "inlineOperation") return ok({
|
|
285
|
-
nodePath,
|
|
286
|
-
canonicalId,
|
|
287
|
-
builderCall,
|
|
288
|
-
type: "inlineOperation",
|
|
289
|
-
artifact
|
|
290
|
-
});
|
|
291
|
-
return err(createUnsupportedArtifactTypeError({
|
|
292
|
-
filename,
|
|
293
|
-
canonicalId,
|
|
294
|
-
artifactType: artifact.type
|
|
295
|
-
}));
|
|
296
|
-
};
|
|
297
|
-
const createMetadataMissingError = ({ filename }) => ({
|
|
298
|
-
type: "PluginError",
|
|
299
|
-
stage: "analysis",
|
|
300
|
-
code: "SODA_GQL_METADATA_NOT_FOUND",
|
|
301
|
-
message: `No GraphQL metadata found for ${filename}`,
|
|
302
|
-
cause: { filename },
|
|
303
|
-
filename
|
|
304
|
-
});
|
|
305
|
-
const createArtifactMissingError = ({ filename, canonicalId }) => ({
|
|
306
|
-
type: "PluginError",
|
|
307
|
-
stage: "analysis",
|
|
308
|
-
code: "SODA_GQL_ANALYSIS_ARTIFACT_NOT_FOUND",
|
|
309
|
-
message: `No builder artifact found for canonical ID ${canonicalId}`,
|
|
310
|
-
cause: {
|
|
311
|
-
filename,
|
|
312
|
-
canonicalId
|
|
313
|
-
},
|
|
314
|
-
filename,
|
|
315
|
-
canonicalId
|
|
316
|
-
});
|
|
317
|
-
const createUnsupportedArtifactTypeError = ({ filename, canonicalId, artifactType }) => ({
|
|
318
|
-
type: "PluginError",
|
|
319
|
-
stage: "analysis",
|
|
320
|
-
code: "SODA_GQL_UNSUPPORTED_ARTIFACT_TYPE",
|
|
321
|
-
message: `Unsupported builder artifact type "${artifactType}" for canonical ID ${canonicalId}`,
|
|
322
|
-
cause: {
|
|
323
|
-
filename,
|
|
324
|
-
canonicalId,
|
|
325
|
-
artifactType
|
|
326
|
-
},
|
|
327
|
-
filename,
|
|
328
|
-
canonicalId,
|
|
329
|
-
artifactType
|
|
330
|
-
});
|
|
331
|
-
const findGqlBuilderCall = (callPath) => resolveBuilderCall(callPath.node);
|
|
332
|
-
const resolveBuilderCall = (call) => {
|
|
333
|
-
if (!isGqlMemberExpression(call.callee)) return null;
|
|
334
|
-
if (call.arguments.length !== 1) return null;
|
|
335
|
-
const factoryArg = call.arguments[0];
|
|
336
|
-
if (!types.isArrowFunctionExpression(factoryArg)) return null;
|
|
337
|
-
return extractBuilderCall(factoryArg);
|
|
338
|
-
};
|
|
339
|
-
const isGqlMemberExpression = (callee) => {
|
|
340
|
-
return types.isMemberExpression(callee) && isSimpleProperty(callee.property) && isGqlReference(callee.object);
|
|
341
|
-
};
|
|
342
|
-
const isSimpleProperty = (property) => types.isIdentifier(property) || types.isStringLiteral(property) && property.value.length > 0;
|
|
343
|
-
const isGqlReference = (expr) => {
|
|
344
|
-
if (types.isIdentifier(expr, { name: "gql" })) return true;
|
|
345
|
-
if (!types.isMemberExpression(expr) || expr.computed) return false;
|
|
346
|
-
if (types.isIdentifier(expr.property) && expr.property.name === "gql" || types.isStringLiteral(expr.property) && expr.property.value === "gql") return true;
|
|
347
|
-
return isGqlReference(expr.object);
|
|
348
|
-
};
|
|
349
|
-
const extractBuilderCall = (factory) => {
|
|
350
|
-
if (types.isCallExpression(factory.body)) return factory.body;
|
|
351
|
-
if (!types.isBlockStatement(factory.body)) return null;
|
|
352
|
-
for (const statement of factory.body.body) if (types.isReturnStatement(statement) && statement.argument && types.isCallExpression(statement.argument)) return statement.argument;
|
|
353
|
-
return null;
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
//#endregion
|
|
357
|
-
//#region packages/babel-plugin/src/ast/ast.ts
|
|
358
|
-
const clone = (node) => t.cloneNode(node, true);
|
|
359
|
-
const buildObjectExpression = (properties) => t.objectExpression(Object.entries(properties).map(([key, value]) => t.objectProperty(t.identifier(key), value)));
|
|
360
|
-
|
|
361
|
-
//#endregion
|
|
362
|
-
//#region packages/babel-plugin/src/ast/runtime.ts
|
|
363
|
-
const createMissingBuilderArgError = ({ filename, builderType, argName }) => ({
|
|
364
|
-
type: "PluginError",
|
|
365
|
-
stage: "transform",
|
|
366
|
-
code: "SODA_GQL_TRANSFORM_MISSING_BUILDER_ARG",
|
|
367
|
-
message: `${builderType} requires a ${argName} argument`,
|
|
368
|
-
cause: {
|
|
369
|
-
filename,
|
|
370
|
-
builderType,
|
|
371
|
-
argName
|
|
372
|
-
},
|
|
373
|
-
filename,
|
|
374
|
-
builderType,
|
|
375
|
-
argName
|
|
376
|
-
});
|
|
377
|
-
const buildModelRuntimeCall = ({ artifact, builderCall, filename }) => {
|
|
378
|
-
const [, , normalize] = builderCall.arguments;
|
|
379
|
-
if (!normalize || !types.isExpression(normalize)) return err(createMissingBuilderArgError({
|
|
380
|
-
filename,
|
|
381
|
-
builderType: "model",
|
|
382
|
-
argName: "normalize"
|
|
383
|
-
}));
|
|
384
|
-
return ok(types.callExpression(types.memberExpression(types.identifier("gqlRuntime"), types.identifier("model")), [buildObjectExpression({
|
|
385
|
-
prebuild: buildObjectExpression({ typename: types.stringLiteral(artifact.prebuild.typename) }),
|
|
386
|
-
runtime: buildObjectExpression({ normalize: clone(normalize) })
|
|
387
|
-
})]));
|
|
388
|
-
};
|
|
389
|
-
const buildSliceRuntimeCall = ({ artifact, builderCall, filename }) => {
|
|
390
|
-
const [, , projectionBuilder] = builderCall.arguments;
|
|
391
|
-
if (!projectionBuilder || !types.isExpression(projectionBuilder)) return err(createMissingBuilderArgError({
|
|
392
|
-
filename,
|
|
393
|
-
builderType: "slice",
|
|
394
|
-
argName: "projectionBuilder"
|
|
395
|
-
}));
|
|
396
|
-
return ok(types.callExpression(types.memberExpression(types.identifier("gqlRuntime"), types.identifier("slice")), [buildObjectExpression({
|
|
397
|
-
prebuild: buildObjectExpression({ operationType: types.stringLiteral(artifact.prebuild.operationType) }),
|
|
398
|
-
runtime: buildObjectExpression({ buildProjection: clone(projectionBuilder) })
|
|
399
|
-
})]));
|
|
400
|
-
};
|
|
401
|
-
const buildComposedOperationRuntimeComponents = ({ artifact, builderCall, filename }) => {
|
|
402
|
-
const [, slicesBuilder] = builderCall.arguments;
|
|
403
|
-
if (!slicesBuilder || !types.isExpression(slicesBuilder)) return err(createMissingBuilderArgError({
|
|
404
|
-
filename,
|
|
405
|
-
builderType: "composed operation",
|
|
406
|
-
argName: "slicesBuilder"
|
|
407
|
-
}));
|
|
408
|
-
const runtimeCall = types.callExpression(types.memberExpression(types.identifier("gqlRuntime"), types.identifier("composedOperation")), [buildObjectExpression({
|
|
409
|
-
prebuild: types.callExpression(types.memberExpression(types.identifier("JSON"), types.identifier("parse")), [types.stringLiteral(JSON.stringify(artifact.prebuild))]),
|
|
410
|
-
runtime: buildObjectExpression({ getSlices: clone(slicesBuilder) })
|
|
411
|
-
})]);
|
|
412
|
-
return ok({
|
|
413
|
-
referenceCall: types.callExpression(types.memberExpression(types.identifier("gqlRuntime"), types.identifier("getComposedOperation")), [types.stringLiteral(artifact.prebuild.operationName)]),
|
|
414
|
-
runtimeCall
|
|
415
|
-
});
|
|
416
|
-
};
|
|
417
|
-
const buildInlineOperationRuntimeComponents = ({ artifact }) => {
|
|
418
|
-
const runtimeCall = types.callExpression(types.memberExpression(types.identifier("gqlRuntime"), types.identifier("inlineOperation")), [buildObjectExpression({
|
|
419
|
-
prebuild: types.callExpression(types.memberExpression(types.identifier("JSON"), types.identifier("parse")), [types.stringLiteral(JSON.stringify(artifact.prebuild))]),
|
|
420
|
-
runtime: buildObjectExpression({})
|
|
421
|
-
})]);
|
|
422
|
-
return ok({
|
|
423
|
-
referenceCall: types.callExpression(types.memberExpression(types.identifier("gqlRuntime"), types.identifier("getInlineOperation")), [types.stringLiteral(artifact.prebuild.operationName)]),
|
|
424
|
-
runtimeCall
|
|
425
|
-
});
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
//#endregion
|
|
429
|
-
//#region packages/babel-plugin/src/ast/transformer.ts
|
|
430
|
-
const transformCallExpression = ({ callPath, filename, metadata, getArtifact }) => {
|
|
431
|
-
const builderCall = findGqlBuilderCall(callPath);
|
|
432
|
-
if (!builderCall) return ok({ transformed: false });
|
|
433
|
-
const gqlCallResult = extractGqlCall({
|
|
434
|
-
nodePath: callPath,
|
|
435
|
-
filename,
|
|
436
|
-
metadata,
|
|
437
|
-
builderCall,
|
|
438
|
-
getArtifact
|
|
439
|
-
});
|
|
440
|
-
if (gqlCallResult.isErr()) return err(gqlCallResult.error);
|
|
441
|
-
const gqlCall = gqlCallResult.value;
|
|
442
|
-
return replaceWithRuntimeCall(callPath, gqlCall, filename);
|
|
443
|
-
};
|
|
444
|
-
const replaceWithRuntimeCall = (callPath, gqlCall, filename) => {
|
|
445
|
-
if (gqlCall.type === "model") {
|
|
446
|
-
const result = buildModelRuntimeCall({
|
|
447
|
-
...gqlCall,
|
|
448
|
-
filename
|
|
449
|
-
});
|
|
450
|
-
if (result.isErr()) return err(result.error);
|
|
451
|
-
callPath.replaceWith(result.value);
|
|
452
|
-
return ok({ transformed: true });
|
|
453
|
-
}
|
|
454
|
-
if (gqlCall.type === "slice") {
|
|
455
|
-
const result = buildSliceRuntimeCall({
|
|
456
|
-
...gqlCall,
|
|
457
|
-
filename
|
|
458
|
-
});
|
|
459
|
-
if (result.isErr()) return err(result.error);
|
|
460
|
-
callPath.replaceWith(result.value);
|
|
461
|
-
return ok({ transformed: true });
|
|
462
|
-
}
|
|
463
|
-
if (gqlCall.type === "operation") {
|
|
464
|
-
const result = buildComposedOperationRuntimeComponents({
|
|
465
|
-
...gqlCall,
|
|
466
|
-
filename
|
|
467
|
-
});
|
|
468
|
-
if (result.isErr()) return err(result.error);
|
|
469
|
-
const { referenceCall, runtimeCall } = result.value;
|
|
470
|
-
callPath.replaceWith(referenceCall);
|
|
471
|
-
return ok({
|
|
472
|
-
transformed: true,
|
|
473
|
-
runtimeCall
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
if (gqlCall.type === "inlineOperation") {
|
|
477
|
-
const result = buildInlineOperationRuntimeComponents({
|
|
478
|
-
...gqlCall,
|
|
479
|
-
filename
|
|
480
|
-
});
|
|
481
|
-
if (result.isErr()) return err(result.error);
|
|
482
|
-
const { referenceCall, runtimeCall } = result.value;
|
|
483
|
-
callPath.replaceWith(referenceCall);
|
|
484
|
-
return ok({
|
|
485
|
-
transformed: true,
|
|
486
|
-
runtimeCall
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
return ok({ transformed: false });
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
//#endregion
|
|
493
|
-
//#region packages/babel-plugin/src/transformer.ts
|
|
494
|
-
/**
|
|
495
|
-
* Creates a Babel transformer with a single transform() method.
|
|
496
|
-
* This matches the pattern used in the TypeScript plugin.
|
|
497
|
-
*/
|
|
498
|
-
const createTransformer = ({ programPath, types: types$1, config }) => {
|
|
499
|
-
const graphqlSystemIdentifyHelper = createGraphqlSystemIdentifyHelper(config);
|
|
500
|
-
/**
|
|
501
|
-
* Check if a node is a require() or __webpack_require__() call.
|
|
502
|
-
*/
|
|
503
|
-
const isRequireCall = (node) => {
|
|
504
|
-
if (!types$1.isCallExpression(node)) return false;
|
|
505
|
-
const callee = node.callee;
|
|
506
|
-
return types$1.isIdentifier(callee) && (callee.name === "require" || callee.name === "__webpack_require__");
|
|
507
|
-
};
|
|
508
|
-
/**
|
|
509
|
-
* Find the last statement that loads a module (import or require).
|
|
510
|
-
* Handles both ESM imports and CommonJS require() calls.
|
|
511
|
-
*/
|
|
512
|
-
const findLastModuleLoader = () => {
|
|
513
|
-
const bodyPaths = programPath.get("body");
|
|
514
|
-
let lastLoader = null;
|
|
515
|
-
for (const path of bodyPaths) {
|
|
516
|
-
if (path.isImportDeclaration()) {
|
|
517
|
-
lastLoader = path;
|
|
518
|
-
continue;
|
|
519
|
-
}
|
|
520
|
-
if (path.isVariableDeclaration()) {
|
|
521
|
-
for (const declarator of path.node.declarations) if (declarator.init && isRequireCall(declarator.init)) {
|
|
522
|
-
lastLoader = path;
|
|
523
|
-
break;
|
|
524
|
-
}
|
|
525
|
-
continue;
|
|
526
|
-
}
|
|
527
|
-
if (path.isExpressionStatement()) {
|
|
528
|
-
if (isRequireCall(path.node.expression)) lastLoader = path;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
return lastLoader;
|
|
532
|
-
};
|
|
533
|
-
return { transform: (context) => {
|
|
534
|
-
const metadata = collectGqlDefinitionMetadata({
|
|
535
|
-
programPath,
|
|
536
|
-
filename: context.filename
|
|
537
|
-
});
|
|
538
|
-
const runtimeCalls = [];
|
|
539
|
-
let transformed = false;
|
|
540
|
-
programPath.traverse({ CallExpression: (callPath) => {
|
|
541
|
-
const result = transformCallExpression({
|
|
542
|
-
callPath,
|
|
543
|
-
filename: context.filename,
|
|
544
|
-
metadata,
|
|
545
|
-
getArtifact: context.artifactLookup
|
|
546
|
-
});
|
|
547
|
-
if (result.isErr()) {
|
|
548
|
-
console.error(`[@soda-gql/babel-plugin] ${formatPluginError(result.error)}`);
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
const transformResult = result.value;
|
|
552
|
-
if (transformResult.transformed) {
|
|
553
|
-
transformed = true;
|
|
554
|
-
if (transformResult.runtimeCall) runtimeCalls.push(transformResult.runtimeCall);
|
|
555
|
-
}
|
|
556
|
-
} });
|
|
557
|
-
if (!transformed) return {
|
|
558
|
-
transformed: false,
|
|
559
|
-
runtimeArtifacts: void 0
|
|
560
|
-
};
|
|
561
|
-
ensureGqlRuntimeImport(programPath);
|
|
562
|
-
if (runtimeCalls.length > 0) {
|
|
563
|
-
const statements = runtimeCalls.map((expr) => types$1.expressionStatement(expr));
|
|
564
|
-
const lastLoaderPath = findLastModuleLoader();
|
|
565
|
-
if (lastLoaderPath) lastLoaderPath.insertAfter(statements);
|
|
566
|
-
else programPath.unshiftContainer("body", statements);
|
|
567
|
-
}
|
|
568
|
-
programPath.scope.crawl();
|
|
569
|
-
removeGraphqlSystemImports(programPath, graphqlSystemIdentifyHelper, context.filename);
|
|
570
|
-
return {
|
|
571
|
-
transformed: true,
|
|
572
|
-
runtimeArtifacts: void 0
|
|
573
|
-
};
|
|
574
|
-
} };
|
|
575
|
-
};
|
|
576
|
-
|
|
577
|
-
//#endregion
|
|
578
5
|
//#region packages/babel-plugin/src/plugin.ts
|
|
579
6
|
const fallbackPlugin = () => ({
|
|
580
7
|
name: "@soda-gql/babel-plugin",
|
|
@@ -625,9 +52,5 @@ const createPluginWithArtifact = ({ artifact, config }) => ({
|
|
|
625
52
|
});
|
|
626
53
|
|
|
627
54
|
//#endregion
|
|
628
|
-
|
|
629
|
-
var src_default = createSodaGqlPlugin;
|
|
630
|
-
|
|
631
|
-
//#endregion
|
|
632
|
-
export { createPlugin, createPluginWithArtifact, createSodaGqlPlugin, src_default as default };
|
|
55
|
+
export { createPlugin, createPluginWithArtifact, createSodaGqlPlugin };
|
|
633
56
|
//# sourceMappingURL=index.mjs.map
|