@sanity/codegen 5.7.0-next.8 → 5.7.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/bin/run.js +31 -0
- package/dist/_exports/index.js +11 -0
- package/dist/_exports/index.js.map +1 -0
- package/dist/actions/generatedFileWarning.js +15 -0
- package/dist/actions/generatedFileWarning.js.map +1 -0
- package/dist/actions/typegenGenerate.worker.js +54 -0
- package/dist/actions/typegenGenerate.worker.js.map +1 -0
- package/dist/actions/types.js +3 -0
- package/dist/actions/types.js.map +1 -0
- package/dist/casing.js +27 -0
- package/dist/casing.js.map +1 -0
- package/dist/commands/typegen/generate.js +237 -0
- package/dist/commands/typegen/generate.js.map +1 -0
- package/dist/getBabelConfig.js +37 -0
- package/dist/getBabelConfig.js.map +1 -0
- package/dist/index.d.ts +459 -0
- package/dist/readConfig.js +38 -0
- package/dist/readConfig.js.map +1 -0
- package/dist/readSchema.js +14 -0
- package/dist/readSchema.js.map +1 -0
- package/dist/safeParseQuery.js +37 -0
- package/dist/safeParseQuery.js.map +1 -0
- package/dist/typeUtils.js +37 -0
- package/dist/typeUtils.js.map +1 -0
- package/dist/typescript/constants.js +12 -0
- package/dist/typescript/constants.js.map +1 -0
- package/dist/typescript/expressionResolvers.js +356 -0
- package/dist/typescript/expressionResolvers.js.map +1 -0
- package/dist/typescript/findQueriesInPath.js +69 -0
- package/dist/typescript/findQueriesInPath.js.map +1 -0
- package/dist/typescript/findQueriesInSource.js +175 -0
- package/dist/typescript/findQueriesInSource.js.map +1 -0
- package/dist/typescript/helpers.js +86 -0
- package/dist/typescript/helpers.js.map +1 -0
- package/dist/typescript/moduleResolver.js +33 -0
- package/dist/typescript/moduleResolver.js.map +1 -0
- package/dist/typescript/parseSource.js +75 -0
- package/dist/typescript/parseSource.js.map +1 -0
- package/dist/typescript/registerBabel.js +23 -0
- package/dist/typescript/registerBabel.js.map +1 -0
- package/dist/typescript/schemaTypeGenerator.js +323 -0
- package/dist/typescript/schemaTypeGenerator.js.map +1 -0
- package/dist/typescript/typeGenerator.js +240 -0
- package/dist/typescript/typeGenerator.js.map +1 -0
- package/dist/typescript/types.js +31 -0
- package/dist/typescript/types.js.map +1 -0
- package/dist/utils/count.js +6 -0
- package/dist/utils/count.js.map +1 -0
- package/dist/utils/formatPath.js +8 -0
- package/dist/utils/formatPath.js.map +1 -0
- package/dist/utils/getMessage.js +3 -0
- package/dist/utils/getMessage.js.map +1 -0
- package/dist/utils/percent.js +8 -0
- package/dist/utils/percent.js.map +1 -0
- package/oclif.manifest.json +39 -0
- package/package.json +49 -23
- package/lib/index.d.ts +0 -433
- package/lib/index.js +0 -1011
- package/lib/index.js.map +0 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { traverse } from '@babel/core';
|
|
4
|
+
import { Scope } from '@babel/traverse';
|
|
5
|
+
import * as babelTypes from '@babel/types';
|
|
6
|
+
import createDebug from 'debug';
|
|
7
|
+
import { formatPath } from '../utils/formatPath.js';
|
|
8
|
+
import { parseSourceFile } from './parseSource.js';
|
|
9
|
+
const debug = createDebug('sanity:codegen:findQueries:debug');
|
|
10
|
+
const TAGGED_TEMPLATE_ALLOW_LIST = new Set([
|
|
11
|
+
'groq'
|
|
12
|
+
]);
|
|
13
|
+
const FUNCTION_WRAPPER_ALLOW_LIST = new Set([
|
|
14
|
+
'defineQuery'
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* resolveExpression takes a node and returns the resolved value of the expression.
|
|
18
|
+
* @beta
|
|
19
|
+
* @internal
|
|
20
|
+
*/ export function resolveExpression({ babelConfig, file, filename, fnArguments = [], node, params = [], resolver, scope }) {
|
|
21
|
+
debug(`Resolving node ${node.type} in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`);
|
|
22
|
+
if (babelTypes.isTaggedTemplateExpression(node) && babelTypes.isIdentifier(node.tag) && TAGGED_TEMPLATE_ALLOW_LIST.has(node.tag.name)) {
|
|
23
|
+
return resolveExpression({
|
|
24
|
+
babelConfig,
|
|
25
|
+
file,
|
|
26
|
+
filename,
|
|
27
|
+
fnArguments,
|
|
28
|
+
node: node.quasi,
|
|
29
|
+
params,
|
|
30
|
+
resolver,
|
|
31
|
+
scope
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (babelTypes.isTemplateLiteral(node)) {
|
|
35
|
+
const resolvedExpressions = node.expressions.map((expression)=>resolveExpression({
|
|
36
|
+
babelConfig,
|
|
37
|
+
file,
|
|
38
|
+
filename,
|
|
39
|
+
fnArguments,
|
|
40
|
+
node: expression,
|
|
41
|
+
params,
|
|
42
|
+
resolver,
|
|
43
|
+
scope
|
|
44
|
+
}));
|
|
45
|
+
return node.quasis.map((quasi, idx)=>{
|
|
46
|
+
return (quasi.value.cooked || '') + (resolvedExpressions[idx] || '');
|
|
47
|
+
}).join('');
|
|
48
|
+
}
|
|
49
|
+
if (babelTypes.isLiteral(node)) {
|
|
50
|
+
if (node.type === 'NullLiteral' || node.type === 'RegExpLiteral') {
|
|
51
|
+
throw new Error(`Unsupported literal type: ${node.type}`);
|
|
52
|
+
}
|
|
53
|
+
return node.value.toString();
|
|
54
|
+
}
|
|
55
|
+
if (babelTypes.isIdentifier(node)) {
|
|
56
|
+
return resolveIdentifier({
|
|
57
|
+
babelConfig,
|
|
58
|
+
file,
|
|
59
|
+
filename,
|
|
60
|
+
fnArguments,
|
|
61
|
+
node,
|
|
62
|
+
params,
|
|
63
|
+
resolver,
|
|
64
|
+
scope
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (babelTypes.isVariableDeclarator(node)) {
|
|
68
|
+
const init = node.init ?? (babelTypes.isAssignmentPattern(node.id) && node.id.right);
|
|
69
|
+
if (!init) {
|
|
70
|
+
throw new Error(`Unsupported variable declarator`);
|
|
71
|
+
}
|
|
72
|
+
return resolveExpression({
|
|
73
|
+
babelConfig,
|
|
74
|
+
file,
|
|
75
|
+
filename,
|
|
76
|
+
fnArguments,
|
|
77
|
+
node: init,
|
|
78
|
+
resolver,
|
|
79
|
+
scope
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (babelTypes.isCallExpression(node) && babelTypes.isIdentifier(node.callee) && FUNCTION_WRAPPER_ALLOW_LIST.has(node.callee.name)) {
|
|
83
|
+
return resolveExpression({
|
|
84
|
+
babelConfig,
|
|
85
|
+
file,
|
|
86
|
+
filename,
|
|
87
|
+
node: node.arguments[0],
|
|
88
|
+
params,
|
|
89
|
+
resolver,
|
|
90
|
+
scope
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (babelTypes.isCallExpression(node)) {
|
|
94
|
+
return resolveCallExpression({
|
|
95
|
+
babelConfig,
|
|
96
|
+
file,
|
|
97
|
+
filename,
|
|
98
|
+
fnArguments,
|
|
99
|
+
node,
|
|
100
|
+
params,
|
|
101
|
+
resolver,
|
|
102
|
+
scope
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (babelTypes.isArrowFunctionExpression(node) || babelTypes.isFunctionDeclaration(node) || babelTypes.isFunctionExpression(node)) {
|
|
106
|
+
const newScope = new Scope(scope.path, scope);
|
|
107
|
+
for (const [i, param] of params.entries()){
|
|
108
|
+
newScope.push({
|
|
109
|
+
id: param,
|
|
110
|
+
init: fnArguments[i]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return resolveExpression({
|
|
114
|
+
babelConfig,
|
|
115
|
+
file,
|
|
116
|
+
filename,
|
|
117
|
+
fnArguments,
|
|
118
|
+
node: node.body,
|
|
119
|
+
params: node.params,
|
|
120
|
+
resolver,
|
|
121
|
+
scope: newScope
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (babelTypes.isNewExpression(node)) {
|
|
125
|
+
return resolveExpression({
|
|
126
|
+
babelConfig,
|
|
127
|
+
file,
|
|
128
|
+
filename,
|
|
129
|
+
node: node.callee,
|
|
130
|
+
resolver,
|
|
131
|
+
scope
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (babelTypes.isImportDefaultSpecifier(node) || babelTypes.isImportSpecifier(node)) {
|
|
135
|
+
return resolveImportSpecifier({
|
|
136
|
+
babelConfig,
|
|
137
|
+
file,
|
|
138
|
+
filename,
|
|
139
|
+
fnArguments,
|
|
140
|
+
node,
|
|
141
|
+
resolver,
|
|
142
|
+
scope
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (babelTypes.isAssignmentPattern(node)) {
|
|
146
|
+
return resolveExpression({
|
|
147
|
+
babelConfig,
|
|
148
|
+
file,
|
|
149
|
+
filename,
|
|
150
|
+
fnArguments,
|
|
151
|
+
node: node.right,
|
|
152
|
+
params,
|
|
153
|
+
resolver,
|
|
154
|
+
scope
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Handle TypeScript type assertions (e.g., `'foo' as string`)
|
|
158
|
+
if (babelTypes.isTSAsExpression(node)) {
|
|
159
|
+
return resolveExpression({
|
|
160
|
+
babelConfig,
|
|
161
|
+
file,
|
|
162
|
+
filename,
|
|
163
|
+
fnArguments,
|
|
164
|
+
node: node.expression,
|
|
165
|
+
params,
|
|
166
|
+
resolver,
|
|
167
|
+
scope
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
throw new Error(`Unsupported expression type: ${node.type} in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`);
|
|
171
|
+
}
|
|
172
|
+
function resolveIdentifier({ babelConfig, file, filename, fnArguments, node, params, resolver, scope }) {
|
|
173
|
+
const paramIndex = params.findIndex((param)=>babelTypes.isIdentifier(param) && node.name === param.name || babelTypes.isAssignmentPattern(param) && babelTypes.isIdentifier(param.left) && node.name === param.left.name);
|
|
174
|
+
let argument = fnArguments[paramIndex];
|
|
175
|
+
if (!argument && paramIndex !== -1 && babelTypes.isAssignmentPattern(params[paramIndex])) {
|
|
176
|
+
argument = params[paramIndex].right;
|
|
177
|
+
}
|
|
178
|
+
if (argument && babelTypes.isLiteral(argument)) {
|
|
179
|
+
return resolveExpression({
|
|
180
|
+
babelConfig,
|
|
181
|
+
file,
|
|
182
|
+
filename,
|
|
183
|
+
fnArguments,
|
|
184
|
+
node: argument,
|
|
185
|
+
params,
|
|
186
|
+
resolver,
|
|
187
|
+
scope
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const binding = scope.getBinding(node.name);
|
|
191
|
+
if (binding) {
|
|
192
|
+
if (babelTypes.isIdentifier(binding.path.node)) {
|
|
193
|
+
const isSame = binding.path.node.name === node.name;
|
|
194
|
+
if (isSame) {
|
|
195
|
+
throw new Error(`Could not resolve same identifier "${node.name}" in "${filename}:${node.loc?.start.line}:${node.loc?.start.column}"`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return resolveExpression({
|
|
199
|
+
babelConfig,
|
|
200
|
+
file,
|
|
201
|
+
filename,
|
|
202
|
+
fnArguments,
|
|
203
|
+
node: binding.path.node,
|
|
204
|
+
params,
|
|
205
|
+
resolver,
|
|
206
|
+
scope
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
throw new Error(`Could not find binding for node "${node.name}" in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`);
|
|
210
|
+
}
|
|
211
|
+
function resolveCallExpression({ babelConfig, file, filename, node, params, resolver, scope }) {
|
|
212
|
+
const { callee } = node;
|
|
213
|
+
return resolveExpression({
|
|
214
|
+
babelConfig,
|
|
215
|
+
file,
|
|
216
|
+
filename,
|
|
217
|
+
fnArguments: node.arguments,
|
|
218
|
+
node: callee,
|
|
219
|
+
params,
|
|
220
|
+
resolver,
|
|
221
|
+
scope
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function resolveImportSpecifier({ babelConfig, file, filename, fnArguments, node, resolver }) {
|
|
225
|
+
let importDeclaration;
|
|
226
|
+
traverse(file, {
|
|
227
|
+
ImportDeclaration (n) {
|
|
228
|
+
if (!babelTypes.isImportDeclaration(n.node)) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
for (const specifier of n.node.specifiers){
|
|
232
|
+
if (babelTypes.isImportDefaultSpecifier(specifier) && specifier.local.loc?.identifierName === node.local.name) {
|
|
233
|
+
importDeclaration = n.node;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
if (specifier.local.name === node.local.name) {
|
|
237
|
+
importDeclaration = n.node;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
if (!importDeclaration) {
|
|
243
|
+
throw new Error(`Could not find import declaration for ${node.local.name}`);
|
|
244
|
+
}
|
|
245
|
+
const importName = node.local.name // the name of the variable to import
|
|
246
|
+
;
|
|
247
|
+
const importFileName = importDeclaration.source.value // the file to import from
|
|
248
|
+
;
|
|
249
|
+
const importPath = importFileName.startsWith('./') || importFileName.startsWith('../') ? path.resolve(path.dirname(filename), importFileName) : importFileName;
|
|
250
|
+
const resolvedFile = resolver(formatPath(importPath));
|
|
251
|
+
const source = fs.readFileSync(resolvedFile);
|
|
252
|
+
const tree = parseSourceFile(source.toString(), resolvedFile, babelConfig);
|
|
253
|
+
let newScope;
|
|
254
|
+
traverse(tree, {
|
|
255
|
+
Program (p) {
|
|
256
|
+
newScope = p.scope;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
if (!newScope) {
|
|
260
|
+
throw new Error(`Could not find scope for ${filename}`);
|
|
261
|
+
}
|
|
262
|
+
const binding = newScope.getBinding(importName);
|
|
263
|
+
if (binding) {
|
|
264
|
+
return resolveExpression({
|
|
265
|
+
babelConfig,
|
|
266
|
+
file: tree,
|
|
267
|
+
filename: resolvedFile,
|
|
268
|
+
fnArguments,
|
|
269
|
+
node: binding.path.node,
|
|
270
|
+
resolver,
|
|
271
|
+
scope: newScope
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// It's not a global binding, but it might be a named export
|
|
275
|
+
let namedExport;
|
|
276
|
+
let newImportName;
|
|
277
|
+
traverse(tree, {
|
|
278
|
+
ExportDeclaration (p) {
|
|
279
|
+
if (p.node.type === 'ExportNamedDeclaration') {
|
|
280
|
+
for (const specifier of p.node.specifiers){
|
|
281
|
+
if (specifier.type === 'ExportSpecifier' && specifier.exported.type === 'Identifier' && specifier.exported.name === importName) {
|
|
282
|
+
namedExport = p.node;
|
|
283
|
+
newImportName = specifier.exported.name;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
if (namedExport && newImportName) {
|
|
290
|
+
return resolveExportSpecifier({
|
|
291
|
+
babelConfig,
|
|
292
|
+
filename: resolvedFile,
|
|
293
|
+
fnArguments,
|
|
294
|
+
importName: newImportName,
|
|
295
|
+
node: namedExport,
|
|
296
|
+
resolver
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
let result;
|
|
300
|
+
traverse(tree, {
|
|
301
|
+
ExportDeclaration (p) {
|
|
302
|
+
if (p.node.type === 'ExportAllDeclaration') {
|
|
303
|
+
try {
|
|
304
|
+
result = resolveExportSpecifier({
|
|
305
|
+
babelConfig,
|
|
306
|
+
filename: resolvedFile,
|
|
307
|
+
fnArguments,
|
|
308
|
+
importName,
|
|
309
|
+
node: p.node,
|
|
310
|
+
resolver
|
|
311
|
+
});
|
|
312
|
+
} catch (e) {
|
|
313
|
+
if (e.cause !== `noBinding:${importName}`) throw e;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
if (result) return result;
|
|
319
|
+
throw new Error(`Could not find binding for import "${importName}" in ${importFileName}`);
|
|
320
|
+
}
|
|
321
|
+
function resolveExportSpecifier({ babelConfig, filename, fnArguments, importName, node, resolver }) {
|
|
322
|
+
if (!node.source) {
|
|
323
|
+
throw new Error(`Could not find source for export "${importName}" in ${filename}`);
|
|
324
|
+
}
|
|
325
|
+
const importFileName = node.source.value;
|
|
326
|
+
const importPath = path.resolve(path.dirname(filename), importFileName);
|
|
327
|
+
const resolvedFile = resolver(formatPath(importPath));
|
|
328
|
+
const source = fs.readFileSync(resolvedFile);
|
|
329
|
+
const tree = parseSourceFile(source.toString(), resolvedFile, babelConfig);
|
|
330
|
+
let newScope;
|
|
331
|
+
traverse(tree, {
|
|
332
|
+
Program (p) {
|
|
333
|
+
newScope = p.scope;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
if (!newScope) {
|
|
337
|
+
throw new Error(`Could not find scope for ${filename}`);
|
|
338
|
+
}
|
|
339
|
+
const binding = newScope.getBinding(importName);
|
|
340
|
+
if (binding) {
|
|
341
|
+
return resolveExpression({
|
|
342
|
+
babelConfig,
|
|
343
|
+
file: tree,
|
|
344
|
+
filename: resolvedFile,
|
|
345
|
+
fnArguments,
|
|
346
|
+
node: binding.path.node,
|
|
347
|
+
resolver,
|
|
348
|
+
scope: newScope
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
throw new Error(`Could not find binding for export "${importName}" in ${importFileName}`, {
|
|
352
|
+
cause: `noBinding:${importName}`
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
//# sourceMappingURL=expressionResolvers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/typescript/expressionResolvers.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {type TransformOptions, traverse} from '@babel/core'\nimport {Scope} from '@babel/traverse'\nimport * as babelTypes from '@babel/types'\nimport createDebug from 'debug'\n\nimport {formatPath} from '../utils/formatPath.js'\nimport {parseSourceFile} from './parseSource.js'\n\nconst debug = createDebug('sanity:codegen:findQueries:debug')\n\ntype resolveExpressionReturnType = string\n\nconst TAGGED_TEMPLATE_ALLOW_LIST = new Set(['groq'])\nconst FUNCTION_WRAPPER_ALLOW_LIST = new Set(['defineQuery'])\n\n/**\n * resolveExpression takes a node and returns the resolved value of the expression.\n * @beta\n * @internal\n */\nexport function resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments = [],\n node,\n params = [],\n resolver,\n scope,\n}: {\n babelConfig: TransformOptions\n file: babelTypes.File\n filename: string\n fnArguments?: babelTypes.Node[]\n node: babelTypes.Node\n params?: babelTypes.Node[]\n resolver: NodeJS.RequireResolve\n scope: Scope\n}): resolveExpressionReturnType {\n debug(\n `Resolving node ${node.type} in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`,\n )\n if (\n babelTypes.isTaggedTemplateExpression(node) &&\n babelTypes.isIdentifier(node.tag) &&\n TAGGED_TEMPLATE_ALLOW_LIST.has(node.tag.name)\n ) {\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: node.quasi,\n params,\n resolver,\n scope,\n })\n }\n\n if (babelTypes.isTemplateLiteral(node)) {\n const resolvedExpressions = node.expressions.map((expression) =>\n resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: expression,\n params,\n resolver,\n scope,\n }),\n )\n return node.quasis\n .map((quasi, idx) => {\n return (quasi.value.cooked || '') + (resolvedExpressions[idx] || '')\n })\n .join('')\n }\n\n if (babelTypes.isLiteral(node)) {\n if (node.type === 'NullLiteral' || node.type === 'RegExpLiteral') {\n throw new Error(`Unsupported literal type: ${node.type}`)\n }\n\n return node.value.toString()\n }\n\n if (babelTypes.isIdentifier(node)) {\n return resolveIdentifier({\n babelConfig,\n file,\n filename,\n fnArguments,\n node,\n params,\n resolver,\n scope,\n })\n }\n\n if (babelTypes.isVariableDeclarator(node)) {\n const init = node.init ?? (babelTypes.isAssignmentPattern(node.id) && node.id.right)\n if (!init) {\n throw new Error(`Unsupported variable declarator`)\n }\n\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: init,\n resolver,\n scope,\n })\n }\n\n if (\n babelTypes.isCallExpression(node) &&\n babelTypes.isIdentifier(node.callee) &&\n FUNCTION_WRAPPER_ALLOW_LIST.has(node.callee.name)\n ) {\n return resolveExpression({\n babelConfig,\n file,\n filename,\n node: node.arguments[0]!,\n params,\n resolver,\n scope,\n })\n }\n\n if (babelTypes.isCallExpression(node)) {\n return resolveCallExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node,\n params,\n resolver,\n scope,\n })\n }\n\n if (\n babelTypes.isArrowFunctionExpression(node) ||\n babelTypes.isFunctionDeclaration(node) ||\n babelTypes.isFunctionExpression(node)\n ) {\n const newScope = new Scope(scope.path, scope)\n\n for (const [i, param] of params.entries()) {\n newScope.push({\n id: param as babelTypes.LVal,\n init: fnArguments[i] as babelTypes.Expression | undefined,\n })\n }\n\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: node.body,\n params: node.params,\n resolver,\n scope: newScope,\n })\n }\n\n if (babelTypes.isNewExpression(node)) {\n return resolveExpression({\n babelConfig,\n file,\n filename,\n node: node.callee,\n resolver,\n scope,\n })\n }\n\n if (babelTypes.isImportDefaultSpecifier(node) || babelTypes.isImportSpecifier(node)) {\n return resolveImportSpecifier({babelConfig, file, filename, fnArguments, node, resolver, scope})\n }\n\n if (babelTypes.isAssignmentPattern(node)) {\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: node.right,\n params,\n resolver,\n scope,\n })\n }\n\n // Handle TypeScript type assertions (e.g., `'foo' as string`)\n if (babelTypes.isTSAsExpression(node)) {\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: node.expression,\n params,\n resolver,\n scope,\n })\n }\n\n throw new Error(\n `Unsupported expression type: ${node.type} in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`,\n )\n}\n\nfunction resolveIdentifier({\n babelConfig,\n file,\n filename,\n fnArguments,\n node,\n params,\n resolver,\n scope,\n}: {\n babelConfig: TransformOptions\n file: babelTypes.File\n filename: string\n fnArguments: babelTypes.Node[]\n node: babelTypes.Identifier\n params: babelTypes.Node[]\n resolver: NodeJS.RequireResolve\n scope: Scope\n}): resolveExpressionReturnType {\n const paramIndex = params.findIndex(\n (param) =>\n (babelTypes.isIdentifier(param) && node.name === param.name) ||\n (babelTypes.isAssignmentPattern(param) &&\n babelTypes.isIdentifier(param.left) &&\n node.name === param.left.name),\n )\n let argument = fnArguments[paramIndex]\n if (!argument && paramIndex !== -1 && babelTypes.isAssignmentPattern(params[paramIndex])) {\n argument = params[paramIndex].right\n }\n if (argument && babelTypes.isLiteral(argument)) {\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: argument,\n params,\n resolver,\n scope,\n })\n }\n const binding = scope.getBinding(node.name)\n if (binding) {\n if (babelTypes.isIdentifier(binding.path.node)) {\n const isSame = binding.path.node.name === node.name\n if (isSame) {\n throw new Error(\n `Could not resolve same identifier \"${node.name}\" in \"${filename}:${node.loc?.start.line}:${node.loc?.start.column}\"`,\n )\n }\n }\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments,\n node: binding.path.node,\n params,\n resolver,\n scope,\n })\n }\n\n throw new Error(\n `Could not find binding for node \"${node.name}\" in ${filename}:${node.loc?.start.line}:${node.loc?.start.column}`,\n )\n}\n\nfunction resolveCallExpression({\n babelConfig,\n file,\n filename,\n node,\n params,\n resolver,\n scope,\n}: {\n babelConfig: TransformOptions\n file: babelTypes.File\n filename: string\n fnArguments: babelTypes.Node[]\n node: babelTypes.CallExpression\n params: babelTypes.Node[]\n resolver: NodeJS.RequireResolve\n scope: Scope\n}): resolveExpressionReturnType {\n const {callee} = node\n return resolveExpression({\n babelConfig,\n file,\n filename,\n fnArguments: node.arguments,\n node: callee,\n params,\n resolver,\n scope,\n })\n}\n\nfunction resolveImportSpecifier({\n babelConfig,\n file,\n filename,\n fnArguments,\n node,\n resolver,\n}: {\n babelConfig: TransformOptions\n file: babelTypes.File\n filename: string\n fnArguments: babelTypes.Node[]\n node: babelTypes.ExportSpecifier | babelTypes.ImportDefaultSpecifier | babelTypes.ImportSpecifier\n resolver: NodeJS.RequireResolve\n scope: Scope\n}): resolveExpressionReturnType {\n let importDeclaration: babelTypes.ImportDeclaration | undefined\n traverse(file, {\n ImportDeclaration(n) {\n if (!babelTypes.isImportDeclaration(n.node)) {\n return\n }\n for (const specifier of n.node.specifiers) {\n if (\n babelTypes.isImportDefaultSpecifier(specifier) &&\n specifier.local.loc?.identifierName === node.local.name\n ) {\n importDeclaration = n.node\n break\n }\n if (specifier.local.name === node.local.name) {\n importDeclaration = n.node\n }\n }\n },\n })\n\n if (!importDeclaration) {\n throw new Error(`Could not find import declaration for ${node.local.name}`)\n }\n\n const importName = node.local.name // the name of the variable to import\n const importFileName = importDeclaration.source.value // the file to import from\n\n const importPath =\n importFileName.startsWith('./') || importFileName.startsWith('../')\n ? path.resolve(path.dirname(filename), importFileName)\n : importFileName\n\n const resolvedFile = resolver(formatPath(importPath))\n const source = fs.readFileSync(resolvedFile)\n const tree = parseSourceFile(source.toString(), resolvedFile, babelConfig)\n\n let newScope: Scope | undefined\n traverse(tree, {\n Program(p) {\n newScope = p.scope\n },\n })\n if (!newScope) {\n throw new Error(`Could not find scope for ${filename}`)\n }\n\n const binding = newScope.getBinding(importName)\n if (binding) {\n return resolveExpression({\n babelConfig,\n file: tree,\n filename: resolvedFile,\n fnArguments,\n node: binding.path.node,\n resolver,\n scope: newScope,\n })\n }\n\n // It's not a global binding, but it might be a named export\n let namedExport: babelTypes.ExportNamedDeclaration | undefined\n let newImportName: string | undefined\n traverse(tree, {\n ExportDeclaration(p) {\n if (p.node.type === 'ExportNamedDeclaration') {\n for (const specifier of p.node.specifiers) {\n if (\n specifier.type === 'ExportSpecifier' &&\n specifier.exported.type === 'Identifier' &&\n specifier.exported.name === importName\n ) {\n namedExport = p.node\n newImportName = specifier.exported.name\n }\n }\n }\n },\n })\n\n if (namedExport && newImportName) {\n return resolveExportSpecifier({\n babelConfig,\n filename: resolvedFile,\n fnArguments,\n importName: newImportName,\n node: namedExport,\n resolver,\n })\n }\n\n let result: resolveExpressionReturnType | undefined\n traverse(tree, {\n ExportDeclaration(p) {\n if (p.node.type === 'ExportAllDeclaration') {\n try {\n result = resolveExportSpecifier({\n babelConfig,\n filename: resolvedFile,\n fnArguments,\n importName,\n node: p.node,\n resolver,\n })\n } catch (e) {\n if ((e as Error).cause !== `noBinding:${importName}`) throw e\n }\n }\n },\n })\n if (result) return result\n\n throw new Error(`Could not find binding for import \"${importName}\" in ${importFileName}`)\n}\n\nfunction resolveExportSpecifier({\n babelConfig,\n filename,\n fnArguments,\n importName,\n node,\n resolver,\n}: {\n babelConfig: TransformOptions\n filename: string\n fnArguments: babelTypes.Node[]\n importName: string\n node: babelTypes.ExportAllDeclaration | babelTypes.ExportNamedDeclaration\n resolver: NodeJS.RequireResolve\n}): resolveExpressionReturnType {\n if (!node.source) {\n throw new Error(`Could not find source for export \"${importName}\" in ${filename}`)\n }\n\n const importFileName = node.source.value\n const importPath = path.resolve(path.dirname(filename), importFileName)\n const resolvedFile = resolver(formatPath(importPath))\n const source = fs.readFileSync(resolvedFile)\n const tree = parseSourceFile(source.toString(), resolvedFile, babelConfig)\n\n let newScope: Scope | undefined\n traverse(tree, {\n Program(p) {\n newScope = p.scope\n },\n })\n if (!newScope) {\n throw new Error(`Could not find scope for ${filename}`)\n }\n\n const binding = newScope.getBinding(importName)\n if (binding) {\n return resolveExpression({\n babelConfig,\n file: tree,\n filename: resolvedFile,\n fnArguments,\n node: binding.path.node,\n resolver,\n scope: newScope,\n })\n }\n\n throw new Error(`Could not find binding for export \"${importName}\" in ${importFileName}`, {\n cause: `noBinding:${importName}`,\n })\n}\n"],"names":["fs","path","traverse","Scope","babelTypes","createDebug","formatPath","parseSourceFile","debug","TAGGED_TEMPLATE_ALLOW_LIST","Set","FUNCTION_WRAPPER_ALLOW_LIST","resolveExpression","babelConfig","file","filename","fnArguments","node","params","resolver","scope","type","loc","start","line","column","isTaggedTemplateExpression","isIdentifier","tag","has","name","quasi","isTemplateLiteral","resolvedExpressions","expressions","map","expression","quasis","idx","value","cooked","join","isLiteral","Error","toString","resolveIdentifier","isVariableDeclarator","init","isAssignmentPattern","id","right","isCallExpression","callee","arguments","resolveCallExpression","isArrowFunctionExpression","isFunctionDeclaration","isFunctionExpression","newScope","i","param","entries","push","body","isNewExpression","isImportDefaultSpecifier","isImportSpecifier","resolveImportSpecifier","isTSAsExpression","paramIndex","findIndex","left","argument","binding","getBinding","isSame","importDeclaration","ImportDeclaration","n","isImportDeclaration","specifier","specifiers","local","identifierName","importName","importFileName","source","importPath","startsWith","resolve","dirname","resolvedFile","readFileSync","tree","Program","p","namedExport","newImportName","ExportDeclaration","exported","resolveExportSpecifier","result","e","cause"],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import createDebug from 'debug';
|
|
3
|
+
import glob from 'globby';
|
|
4
|
+
import { getBabelConfig } from '../getBabelConfig.js';
|
|
5
|
+
import { findQueriesInSource } from './findQueriesInSource.js';
|
|
6
|
+
import { normalizeGlobPattern } from './helpers.js';
|
|
7
|
+
import { getResolver } from './moduleResolver.js';
|
|
8
|
+
import { QueryExtractionError } from './types.js';
|
|
9
|
+
const debug = createDebug('sanity:codegen:findQueries:debug');
|
|
10
|
+
/**
|
|
11
|
+
* findQueriesInPath takes a path or array of paths and returns all GROQ queries in the files.
|
|
12
|
+
* @param path - The path or array of paths to search for queries
|
|
13
|
+
* @param babelOptions - The babel configuration to use when parsing the source
|
|
14
|
+
* @param resolver - A resolver function to use when resolving module imports
|
|
15
|
+
* @returns An async generator that yields the results of the search
|
|
16
|
+
* @beta
|
|
17
|
+
* @internal
|
|
18
|
+
*/ export function findQueriesInPath({ babelOptions = getBabelConfig(), path, resolver = getResolver() }) {
|
|
19
|
+
const queryNames = new Set();
|
|
20
|
+
// Holds all query names found in the source files
|
|
21
|
+
debug(`Globing ${path}`);
|
|
22
|
+
// Normalize glob patterns to use forward slashes on all platforms
|
|
23
|
+
const normalizedPath = normalizeGlobPattern(path);
|
|
24
|
+
const files = glob.sync(normalizedPath, {
|
|
25
|
+
absolute: false,
|
|
26
|
+
ignore: [
|
|
27
|
+
'**/node_modules/**'
|
|
28
|
+
],
|
|
29
|
+
onlyFiles: true
|
|
30
|
+
}).toSorted();
|
|
31
|
+
async function* getQueries() {
|
|
32
|
+
for (const filename of files){
|
|
33
|
+
if (typeof filename !== 'string') {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
debug(`Found file "${filename}"`);
|
|
37
|
+
try {
|
|
38
|
+
const source = await fs.readFile(filename, 'utf8');
|
|
39
|
+
const pluckedModuleResult = findQueriesInSource(source, filename, babelOptions, resolver);
|
|
40
|
+
// Check and error on duplicate query names, because we can't generate types with the same name.
|
|
41
|
+
for (const { variable } of pluckedModuleResult.queries){
|
|
42
|
+
if (queryNames.has(variable.id.name)) {
|
|
43
|
+
throw new Error(`Duplicate query name found: "${variable.id.name}". Query names must be unique across all files.`);
|
|
44
|
+
}
|
|
45
|
+
queryNames.add(variable.id.name);
|
|
46
|
+
}
|
|
47
|
+
yield pluckedModuleResult;
|
|
48
|
+
} catch (cause) {
|
|
49
|
+
debug(`Error in file "${filename}"`, cause);
|
|
50
|
+
yield {
|
|
51
|
+
errors: [
|
|
52
|
+
new QueryExtractionError({
|
|
53
|
+
cause,
|
|
54
|
+
filename
|
|
55
|
+
})
|
|
56
|
+
],
|
|
57
|
+
filename,
|
|
58
|
+
queries: []
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
files,
|
|
65
|
+
queries: getQueries()
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=findQueriesInPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/typescript/findQueriesInPath.ts"],"sourcesContent":["import fs from 'node:fs/promises'\n\nimport {type TransformOptions} from '@babel/core'\nimport createDebug from 'debug'\nimport glob from 'globby'\n\nimport {getBabelConfig} from '../getBabelConfig.js'\nimport {findQueriesInSource} from './findQueriesInSource.js'\nimport {normalizeGlobPattern} from './helpers.js'\nimport {getResolver} from './moduleResolver.js'\nimport {type ExtractedModule, QueryExtractionError} from './types.js'\n\nconst debug = createDebug('sanity:codegen:findQueries:debug')\n\ninterface FindQueriesInPathOptions {\n path: string | string[]\n\n babelOptions?: TransformOptions\n resolver?: NodeJS.RequireResolve\n}\n\n/**\n * findQueriesInPath takes a path or array of paths and returns all GROQ queries in the files.\n * @param path - The path or array of paths to search for queries\n * @param babelOptions - The babel configuration to use when parsing the source\n * @param resolver - A resolver function to use when resolving module imports\n * @returns An async generator that yields the results of the search\n * @beta\n * @internal\n */\nexport function findQueriesInPath({\n babelOptions = getBabelConfig(),\n path,\n resolver = getResolver(),\n}: FindQueriesInPathOptions): {files: string[]; queries: AsyncIterable<ExtractedModule>} {\n const queryNames = new Set()\n // Holds all query names found in the source files\n debug(`Globing ${path}`)\n\n // Normalize glob patterns to use forward slashes on all platforms\n const normalizedPath = normalizeGlobPattern(path)\n\n const files = glob\n .sync(normalizedPath, {\n absolute: false,\n ignore: ['**/node_modules/**'], // we never want to look in node_modules\n onlyFiles: true,\n })\n .toSorted()\n\n async function* getQueries(): AsyncGenerator<ExtractedModule> {\n for (const filename of files) {\n if (typeof filename !== 'string') {\n continue\n }\n\n debug(`Found file \"${filename}\"`)\n try {\n const source = await fs.readFile(filename, 'utf8')\n const pluckedModuleResult = findQueriesInSource(source, filename, babelOptions, resolver)\n // Check and error on duplicate query names, because we can't generate types with the same name.\n for (const {variable} of pluckedModuleResult.queries) {\n if (queryNames.has(variable.id.name)) {\n throw new Error(\n `Duplicate query name found: \"${variable.id.name}\". Query names must be unique across all files.`,\n )\n }\n queryNames.add(variable.id.name)\n }\n\n yield pluckedModuleResult\n } catch (cause) {\n debug(`Error in file \"${filename}\"`, cause)\n\n yield {\n errors: [new QueryExtractionError({cause, filename})],\n filename,\n queries: [],\n }\n }\n }\n }\n\n return {files, queries: getQueries()}\n}\n"],"names":["fs","createDebug","glob","getBabelConfig","findQueriesInSource","normalizeGlobPattern","getResolver","QueryExtractionError","debug","findQueriesInPath","babelOptions","path","resolver","queryNames","Set","normalizedPath","files","sync","absolute","ignore","onlyFiles","toSorted","getQueries","filename","source","readFile","pluckedModuleResult","variable","queries","has","id","name","Error","add","cause","errors"],"mappings":"AAAA,OAAOA,QAAQ,mBAAkB;AAGjC,OAAOC,iBAAiB,QAAO;AAC/B,OAAOC,UAAU,SAAQ;AAEzB,SAAQC,cAAc,QAAO,uBAAsB;AACnD,SAAQC,mBAAmB,QAAO,2BAA0B;AAC5D,SAAQC,oBAAoB,QAAO,eAAc;AACjD,SAAQC,WAAW,QAAO,sBAAqB;AAC/C,SAA8BC,oBAAoB,QAAO,aAAY;AAErE,MAAMC,QAAQP,YAAY;AAS1B;;;;;;;;CAQC,GACD,OAAO,SAASQ,kBAAkB,EAChCC,eAAeP,gBAAgB,EAC/BQ,IAAI,EACJC,WAAWN,aAAa,EACC;IACzB,MAAMO,aAAa,IAAIC;IACvB,kDAAkD;IAClDN,MAAM,CAAC,QAAQ,EAAEG,MAAM;IAEvB,kEAAkE;IAClE,MAAMI,iBAAiBV,qBAAqBM;IAE5C,MAAMK,QAAQd,KACXe,IAAI,CAACF,gBAAgB;QACpBG,UAAU;QACVC,QAAQ;YAAC;SAAqB;QAC9BC,WAAW;IACb,GACCC,QAAQ;IAEX,gBAAgBC;QACd,KAAK,MAAMC,YAAYP,MAAO;YAC5B,IAAI,OAAOO,aAAa,UAAU;gBAChC;YACF;YAEAf,MAAM,CAAC,YAAY,EAAEe,SAAS,CAAC,CAAC;YAChC,IAAI;gBACF,MAAMC,SAAS,MAAMxB,GAAGyB,QAAQ,CAACF,UAAU;gBAC3C,MAAMG,sBAAsBtB,oBAAoBoB,QAAQD,UAAUb,cAAcE;gBAChF,gGAAgG;gBAChG,KAAK,MAAM,EAACe,QAAQ,EAAC,IAAID,oBAAoBE,OAAO,CAAE;oBACpD,IAAIf,WAAWgB,GAAG,CAACF,SAASG,EAAE,CAACC,IAAI,GAAG;wBACpC,MAAM,IAAIC,MACR,CAAC,6BAA6B,EAAEL,SAASG,EAAE,CAACC,IAAI,CAAC,+CAA+C,CAAC;oBAErG;oBACAlB,WAAWoB,GAAG,CAACN,SAASG,EAAE,CAACC,IAAI;gBACjC;gBAEA,MAAML;YACR,EAAE,OAAOQ,OAAO;gBACd1B,MAAM,CAAC,eAAe,EAAEe,SAAS,CAAC,CAAC,EAAEW;gBAErC,MAAM;oBACJC,QAAQ;wBAAC,IAAI5B,qBAAqB;4BAAC2B;4BAAOX;wBAAQ;qBAAG;oBACrDA;oBACAK,SAAS,EAAE;gBACb;YACF;QACF;IACF;IAEA,OAAO;QAACZ;QAAOY,SAASN;IAAY;AACtC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { traverse } from '@babel/core';
|
|
3
|
+
import * as babelTypes from '@babel/types';
|
|
4
|
+
import { getBabelConfig } from '../getBabelConfig.js';
|
|
5
|
+
import { resolveExpression } from './expressionResolvers.js';
|
|
6
|
+
import { parseSourceFile } from './parseSource.js';
|
|
7
|
+
import { QueryExtractionError } from './types.js';
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const groqTagName = 'groq';
|
|
10
|
+
const defineQueryFunctionName = 'defineQuery';
|
|
11
|
+
const groqModuleName = 'groq';
|
|
12
|
+
const nextSanityModuleName = 'next-sanity';
|
|
13
|
+
const sveltekitModuleName = '@sanity/sveltekit';
|
|
14
|
+
const ignoreValue = '@sanity-typegen-ignore';
|
|
15
|
+
/**
|
|
16
|
+
* findQueriesInSource takes a source string and returns all GROQ queries in it.
|
|
17
|
+
* @param source - The source code to search for queries
|
|
18
|
+
* @param filename - The filename of the source code
|
|
19
|
+
* @param babelConfig - The babel configuration to use when parsing the source
|
|
20
|
+
* @param resolver - A resolver function to use when resolving module imports
|
|
21
|
+
* @returns
|
|
22
|
+
* @beta
|
|
23
|
+
* @internal
|
|
24
|
+
*/ export function findQueriesInSource(source, filename, babelConfig = getBabelConfig(), resolver = require.resolve) {
|
|
25
|
+
const queries = [];
|
|
26
|
+
const errors = [];
|
|
27
|
+
const file = parseSourceFile(source, filename, babelConfig);
|
|
28
|
+
traverse(file, {
|
|
29
|
+
// Look for variable declarations, e.g. `const myQuery = groq`... and extract the query.
|
|
30
|
+
// The variable name is used as the name of the query result type
|
|
31
|
+
VariableDeclarator (path) {
|
|
32
|
+
const { node, scope } = path;
|
|
33
|
+
const init = node.init;
|
|
34
|
+
// Look for tagged template expressions that are called with the `groq` tag
|
|
35
|
+
const isGroqTemplateTag = babelTypes.isTaggedTemplateExpression(init) && babelTypes.isIdentifier(init.tag) && init.tag.name === groqTagName;
|
|
36
|
+
// Look for strings wrapped in a defineQuery function call
|
|
37
|
+
const isDefineQueryCall = babelTypes.isCallExpression(init) && (isImportFrom(groqModuleName, defineQueryFunctionName, scope, init.callee) || isImportFrom(nextSanityModuleName, defineQueryFunctionName, scope, init.callee) || isImportFrom(sveltekitModuleName, defineQueryFunctionName, scope, init.callee));
|
|
38
|
+
if (babelTypes.isIdentifier(node.id) && (isGroqTemplateTag || isDefineQueryCall)) {
|
|
39
|
+
// If we find a comment leading the decleration which macthes with ignoreValue we don't add
|
|
40
|
+
// the query
|
|
41
|
+
if (declarationLeadingCommentContains(path, ignoreValue)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const { end, id, start } = node;
|
|
45
|
+
const variable = {
|
|
46
|
+
id,
|
|
47
|
+
...start && {
|
|
48
|
+
start
|
|
49
|
+
},
|
|
50
|
+
...end && {
|
|
51
|
+
end
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
const query = resolveExpression({
|
|
56
|
+
babelConfig,
|
|
57
|
+
file,
|
|
58
|
+
filename,
|
|
59
|
+
node: init,
|
|
60
|
+
resolver,
|
|
61
|
+
scope
|
|
62
|
+
});
|
|
63
|
+
queries.push({
|
|
64
|
+
filename,
|
|
65
|
+
query,
|
|
66
|
+
variable
|
|
67
|
+
});
|
|
68
|
+
} catch (cause) {
|
|
69
|
+
errors.push(new QueryExtractionError({
|
|
70
|
+
cause,
|
|
71
|
+
filename,
|
|
72
|
+
variable
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
errors,
|
|
80
|
+
filename,
|
|
81
|
+
queries
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function declarationLeadingCommentContains(path, comment) {
|
|
85
|
+
/*
|
|
86
|
+
* We have to consider these cases:
|
|
87
|
+
*
|
|
88
|
+
* // @sanity-typegen-ignore
|
|
89
|
+
* const query = groq`...`
|
|
90
|
+
*
|
|
91
|
+
* // AST
|
|
92
|
+
* VariableDeclaration {
|
|
93
|
+
* declarations: [
|
|
94
|
+
* VariableDeclarator: {init: tag: {name: "groq"}}
|
|
95
|
+
* ],
|
|
96
|
+
* leadingComments: ...
|
|
97
|
+
* }
|
|
98
|
+
*
|
|
99
|
+
* // @sanity-typegen-ignore
|
|
100
|
+
* const query1 = groq`...`, query2 = groq`...`
|
|
101
|
+
*
|
|
102
|
+
* // AST
|
|
103
|
+
* VariableDeclaration {
|
|
104
|
+
* declarations: [
|
|
105
|
+
* VariableDeclarator: {init: tag: {name: "groq"}}
|
|
106
|
+
* VariableDeclarator: {init: tag: {name: "groq"}}
|
|
107
|
+
* ],
|
|
108
|
+
* leadingComments: ...
|
|
109
|
+
* }
|
|
110
|
+
*
|
|
111
|
+
* // @sanity-typegen-ignore
|
|
112
|
+
* export const query = groq`...`
|
|
113
|
+
*
|
|
114
|
+
* // AST
|
|
115
|
+
* ExportNamedDeclaration {
|
|
116
|
+
* declaration: VariableDeclaration {
|
|
117
|
+
* declarations: [
|
|
118
|
+
* VariableDeclarator: {init: tag: {name: "groq"}}
|
|
119
|
+
* VariableDeclarator: {init: tag: {name: "groq"}}
|
|
120
|
+
* ],
|
|
121
|
+
* },
|
|
122
|
+
* leadingComments: ...
|
|
123
|
+
* }
|
|
124
|
+
*
|
|
125
|
+
* In the case where multiple variables are under the same VariableDeclaration the leadingComments
|
|
126
|
+
* will still be on the VariableDeclaration
|
|
127
|
+
*
|
|
128
|
+
* In the case where the variable is exported, the leadingComments are on the
|
|
129
|
+
* ExportNamedDeclaration which includes the VariableDeclaration in its own declaration property
|
|
130
|
+
*/ const variableDeclaration = path.find((node)=>node.isVariableDeclaration());
|
|
131
|
+
if (!variableDeclaration) return false;
|
|
132
|
+
if (variableDeclaration.node.leadingComments?.find((commentItem)=>commentItem.value.trim() === comment)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
// If the declaration is exported, the comment lies on the parent of the export declaration
|
|
136
|
+
if (variableDeclaration.parent.leadingComments?.find((commentItem)=>commentItem.value.trim() === comment)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
function isImportFrom(moduleName, importName, scope, node) {
|
|
142
|
+
if (babelTypes.isIdentifier(node)) {
|
|
143
|
+
const binding = scope.getBinding(node.name);
|
|
144
|
+
if (!binding) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
const { path } = binding;
|
|
148
|
+
// import { foo } from 'groq'
|
|
149
|
+
if (babelTypes.isImportSpecifier(path.node)) {
|
|
150
|
+
return path.node.importKind === 'value' && path.parentPath && babelTypes.isImportDeclaration(path.parentPath.node) && path.parentPath.node.source.value === moduleName && babelTypes.isIdentifier(path.node.imported) && path.node.imported.name === importName;
|
|
151
|
+
}
|
|
152
|
+
// const { defineQuery } = require('groq')
|
|
153
|
+
if (babelTypes.isVariableDeclarator(path.node)) {
|
|
154
|
+
const { init } = path.node;
|
|
155
|
+
return babelTypes.isCallExpression(init) && babelTypes.isIdentifier(init.callee) && init.callee.name === 'require' && babelTypes.isStringLiteral(init.arguments[0]) && init.arguments[0].value === moduleName;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// import * as foo from 'groq'
|
|
159
|
+
// foo.defineQuery(...)
|
|
160
|
+
if (babelTypes.isMemberExpression(node)) {
|
|
161
|
+
const { object, property } = node;
|
|
162
|
+
if (!babelTypes.isIdentifier(object)) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
const binding = scope.getBinding(object.name);
|
|
166
|
+
if (!binding) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const { path } = binding;
|
|
170
|
+
return babelTypes.isIdentifier(object) && babelTypes.isIdentifier(property) && property.name === importName && babelTypes.isImportNamespaceSpecifier(path.node) && path.parentPath && babelTypes.isImportDeclaration(path.parentPath.node) && path.parentPath.node.source.value === moduleName;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
//# sourceMappingURL=findQueriesInSource.js.map
|