@khanacademy/graphql-flow 4.0.0 → 4.0.1
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/CHANGELOG.md +6 -0
- package/dist/parser/parse.js +36 -9
- package/package.json +1 -1
- package/src/parser/__test__/parse.test.ts +1 -1
- package/src/parser/parse.ts +41 -4
package/CHANGELOG.md
CHANGED
package/dist/parser/parse.js
CHANGED
|
@@ -82,7 +82,8 @@ const processFile = (filePath, contents, config) => {
|
|
|
82
82
|
exports: {},
|
|
83
83
|
exportAlls: [],
|
|
84
84
|
locals: {},
|
|
85
|
-
errors: []
|
|
85
|
+
errors: [],
|
|
86
|
+
unresolvedImports: {}
|
|
86
87
|
};
|
|
87
88
|
const text = typeof contents === "string" ? contents : contents.text;
|
|
88
89
|
const plugins = filePath.endsWith("x") ? ["typescript", "jsx"] : ["typescript"];
|
|
@@ -96,6 +97,23 @@ const processFile = (filePath, contents, config) => {
|
|
|
96
97
|
ast.program.body.forEach(toplevel => {
|
|
97
98
|
var _toplevel$declaration;
|
|
98
99
|
if (toplevel.type === "ImportDeclaration") {
|
|
100
|
+
const isUnresolvedModule = !toplevel.source.value.startsWith(".") && !_path.default.isAbsolute(toplevel.source.value) && toplevel.source.value !== "graphql-tag";
|
|
101
|
+
if (isUnresolvedModule) {
|
|
102
|
+
toplevel.specifiers.forEach(spec => {
|
|
103
|
+
if (spec.type === "ImportSpecifier" || spec.type === "ImportDefaultSpecifier") {
|
|
104
|
+
var _spec$start, _spec$end, _spec$loc$start$line, _spec$loc;
|
|
105
|
+
result.unresolvedImports[spec.local.name] = {
|
|
106
|
+
source: toplevel.source.value,
|
|
107
|
+
loc: {
|
|
108
|
+
start: (_spec$start = spec.start) !== null && _spec$start !== void 0 ? _spec$start : -1,
|
|
109
|
+
end: (_spec$end = spec.end) !== null && _spec$end !== void 0 ? _spec$end : -1,
|
|
110
|
+
line: (_spec$loc$start$line = (_spec$loc = spec.loc) === null || _spec$loc === void 0 ? void 0 : _spec$loc.start.line) !== null && _spec$loc$start$line !== void 0 ? _spec$loc$start$line : -1,
|
|
111
|
+
path: filePath
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
99
117
|
const newLocals = getLocals(toplevel, filePath);
|
|
100
118
|
if (newLocals) {
|
|
101
119
|
Object.keys(newLocals).forEach(k => {
|
|
@@ -119,15 +137,15 @@ const processFile = (filePath, contents, config) => {
|
|
|
119
137
|
const importPath = resolvedPath !== null && resolvedPath !== void 0 ? resolvedPath : source.value;
|
|
120
138
|
(_toplevel$specifiers = toplevel.specifiers) === null || _toplevel$specifiers === void 0 || _toplevel$specifiers.forEach(spec => {
|
|
121
139
|
if (spec.type === "ExportSpecifier" && spec.exported.type === "Identifier") {
|
|
122
|
-
var _spec$
|
|
140
|
+
var _spec$start2, _spec$end2, _spec$loc$start$line2, _spec$loc2;
|
|
123
141
|
result.exports[spec.exported.name] = {
|
|
124
142
|
type: "import",
|
|
125
143
|
name: spec.local.name,
|
|
126
144
|
path: importPath,
|
|
127
145
|
loc: {
|
|
128
|
-
start: (_spec$
|
|
129
|
-
end: (_spec$
|
|
130
|
-
line: (_spec$loc$start$
|
|
146
|
+
start: (_spec$start2 = spec.start) !== null && _spec$start2 !== void 0 ? _spec$start2 : -1,
|
|
147
|
+
end: (_spec$end2 = spec.end) !== null && _spec$end2 !== void 0 ? _spec$end2 : -1,
|
|
148
|
+
line: (_spec$loc$start$line2 = (_spec$loc2 = spec.loc) === null || _spec$loc2 === void 0 ? void 0 : _spec$loc2.start.line) !== null && _spec$loc$start$line2 !== void 0 ? _spec$loc$start$line2 : -1,
|
|
131
149
|
path: filePath
|
|
132
150
|
}
|
|
133
151
|
};
|
|
@@ -268,14 +286,23 @@ const processTemplate = (tpl, result, getTemplate) => {
|
|
|
268
286
|
return null;
|
|
269
287
|
}
|
|
270
288
|
if (!result.locals[expr.name]) {
|
|
289
|
+
var _result$unresolvedImp;
|
|
271
290
|
if (getTemplate) {
|
|
272
291
|
const found = getTemplate(expr.name);
|
|
273
292
|
return found;
|
|
274
293
|
}
|
|
275
|
-
result.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
294
|
+
const unresolved = (_result$unresolvedImp = result.unresolvedImports) === null || _result$unresolvedImp === void 0 ? void 0 : _result$unresolvedImp[expr.name];
|
|
295
|
+
if (unresolved) {
|
|
296
|
+
result.errors.push({
|
|
297
|
+
loc: unresolved.loc,
|
|
298
|
+
message: `Unable to resolve import ${expr.name} from "${unresolved.source}" at ${unresolved.loc.path}:${unresolved.loc.line}.`
|
|
299
|
+
});
|
|
300
|
+
} else {
|
|
301
|
+
result.errors.push({
|
|
302
|
+
loc,
|
|
303
|
+
message: `Unable to resolve ${expr.name}`
|
|
304
|
+
});
|
|
305
|
+
}
|
|
279
306
|
return null;
|
|
280
307
|
}
|
|
281
308
|
return result.locals[expr.name];
|
package/package.json
CHANGED
|
@@ -356,7 +356,7 @@ describe("processing fragments in various ways", () => {
|
|
|
356
356
|
expect(files["/invalidThings.js"].errors.map((m: any) => m.message))
|
|
357
357
|
.toMatchInlineSnapshot(`
|
|
358
358
|
Array [
|
|
359
|
-
"Unable to resolve someExternalFragment",
|
|
359
|
+
"Unable to resolve import someExternalFragment from \\"somewhere\\" at /invalidThings.js:4.",
|
|
360
360
|
"Unable to resolve someUndefinedFragment",
|
|
361
361
|
"Template literal interpolation must be an identifier",
|
|
362
362
|
]
|
package/src/parser/parse.ts
CHANGED
|
@@ -91,6 +91,12 @@ export type FileResult = {
|
|
|
91
91
|
loc: Loc;
|
|
92
92
|
message: string;
|
|
93
93
|
}>;
|
|
94
|
+
unresolvedImports?: {
|
|
95
|
+
[key: string]: {
|
|
96
|
+
source: string;
|
|
97
|
+
loc: Loc;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
94
100
|
};
|
|
95
101
|
|
|
96
102
|
export type Files = {
|
|
@@ -164,6 +170,7 @@ export const processFile = (
|
|
|
164
170
|
exportAlls: [],
|
|
165
171
|
locals: {},
|
|
166
172
|
errors: [],
|
|
173
|
+
unresolvedImports: {},
|
|
167
174
|
};
|
|
168
175
|
const text = typeof contents === "string" ? contents : contents.text;
|
|
169
176
|
const plugins: Array<ParserPlugin> = filePath.endsWith("x")
|
|
@@ -181,6 +188,28 @@ export const processFile = (
|
|
|
181
188
|
|
|
182
189
|
ast.program.body.forEach((toplevel) => {
|
|
183
190
|
if (toplevel.type === "ImportDeclaration") {
|
|
191
|
+
const isUnresolvedModule =
|
|
192
|
+
!toplevel.source.value.startsWith(".") &&
|
|
193
|
+
!path.isAbsolute(toplevel.source.value) &&
|
|
194
|
+
toplevel.source.value !== "graphql-tag";
|
|
195
|
+
if (isUnresolvedModule) {
|
|
196
|
+
toplevel.specifiers.forEach((spec) => {
|
|
197
|
+
if (
|
|
198
|
+
spec.type === "ImportSpecifier" ||
|
|
199
|
+
spec.type === "ImportDefaultSpecifier"
|
|
200
|
+
) {
|
|
201
|
+
result.unresolvedImports![spec.local.name] = {
|
|
202
|
+
source: toplevel.source.value,
|
|
203
|
+
loc: {
|
|
204
|
+
start: spec.start ?? -1,
|
|
205
|
+
end: spec.end ?? -1,
|
|
206
|
+
line: spec.loc?.start.line ?? -1,
|
|
207
|
+
path: filePath,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
184
213
|
const newLocals = getLocals(toplevel, filePath);
|
|
185
214
|
if (newLocals) {
|
|
186
215
|
Object.keys(newLocals).forEach((k) => {
|
|
@@ -381,10 +410,18 @@ const processTemplate = (
|
|
|
381
410
|
const found = getTemplate(expr.name);
|
|
382
411
|
return found;
|
|
383
412
|
}
|
|
384
|
-
result.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
413
|
+
const unresolved = result.unresolvedImports?.[expr.name];
|
|
414
|
+
if (unresolved) {
|
|
415
|
+
result.errors.push({
|
|
416
|
+
loc: unresolved.loc,
|
|
417
|
+
message: `Unable to resolve import ${expr.name} from "${unresolved.source}" at ${unresolved.loc.path}:${unresolved.loc.line}.`,
|
|
418
|
+
});
|
|
419
|
+
} else {
|
|
420
|
+
result.errors.push({
|
|
421
|
+
loc,
|
|
422
|
+
message: `Unable to resolve ${expr.name}`,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
388
425
|
return null;
|
|
389
426
|
}
|
|
390
427
|
return result.locals[expr.name];
|