Skip to content

Commit 45f09ef

Browse files
authored
[🔥AUDIT🔥] Fix up some more alias resolution in graphql-flow. (#70)
🖍 _This is an audit!_ 🖍 ## Summary: Missed some other edge cases from my previous PR, this should fix that! Issue: FEI-5745 ## Test plan: I updated the graphql-flow dep in the static service with a link: and confirmed that this new command works as expected. Author: jeresig Auditors: #frontend-infra-web Required Reviewers: Approved By: Checks: ✅ Lint & Test (ubuntu-latest, 20.x) Pull Request URL: #70
1 parent b0ea7e8 commit 45f09ef

File tree

7 files changed

+54
-40
lines changed

7 files changed

+54
-40
lines changed

.changeset/forty-pens-sip.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@khanacademy/graphql-flow": patch
3+
---
4+
5+
Fix up some more alias resolution in graphql-flow.

schema.json

+18-2
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,23 @@
9191
"generate": {"oneOf": [
9292
{"$ref": "#/definitions/GenerateConfig"},
9393
{"type": "array", "items": {"$ref": "#/definitions/GenerateConfig"}}
94-
]}
94+
]},
95+
"alias": {
96+
"type": "array",
97+
"items": {
98+
"type": "object",
99+
"additionalProperties": false,
100+
"properties": {
101+
"find": {
102+
"type": ["string", "object"]
103+
},
104+
"replacement": {
105+
"type": "string"
106+
}
107+
},
108+
"required": [ "find", "replacement" ]
109+
}
110+
}
95111
},
96112
"required": [ "crawl", "generate" ]
97-
}
113+
}

src/cli/run.ts

+5-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {GraphQLSchema} from "graphql/type/schema";
66
import {generateTypeFiles, processPragmas} from "../generateTypeFiles";
77
import {processFiles} from "../parser/parse";
88
import {resolveDocuments} from "../parser/resolve";
9+
import {getPathWithExtension} from "../parser/utils";
910
import {findApplicableConfig, getSchemas, loadConfigFile} from "./config";
1011

1112
import {addTypenameToDocument} from "apollo-utilities";
@@ -81,22 +82,11 @@ const inputFiles = cliFiles.length
8182
/** Step (2) */
8283

8384
const files = processFiles(inputFiles, config, (f) => {
84-
if (existsSync(f)) {
85-
return readFileSync(f, "utf8");
85+
const resolvedPath = getPathWithExtension(f, config);
86+
if (!resolvedPath) {
87+
throw new Error(`Unable to find ${f}`);
8688
}
87-
if (existsSync(f + ".js")) {
88-
return {text: readFileSync(f + ".js", "utf8"), resolvedPath: f + ".js"};
89-
}
90-
if (existsSync(f + ".ts")) {
91-
return {text: readFileSync(f + ".ts", "utf8"), resolvedPath: f + ".ts"};
92-
}
93-
if (existsSync(f + ".tsx")) {
94-
return {
95-
text: readFileSync(f + ".tsx", "utf8"),
96-
resolvedPath: f + ".tsx",
97-
};
98-
}
99-
throw new Error(`Unable to find ${f}`);
89+
return {text: readFileSync(resolvedPath, "utf8"), resolvedPath};
10090
});
10191

10292
let filesHadErrors = false;

src/parser/__test__/utils.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ describe("getPathWithExtension", () => {
5050
expect(result).toBe("/path/to/file.js");
5151
});
5252

53-
it("returns an empty string if no file is found", () => {
53+
it("returns null if no file is found", () => {
5454
// Arrange
5555
jest.spyOn(fs, "existsSync").mockImplementation((path) => false);
5656

5757
// Act
5858
const result = getPathWithExtension("/path/to/file", config);
5959

6060
// Assert
61-
expect(result).toBe("");
61+
expect(result).toBe(null);
6262
});
6363

6464
it("maps aliases to their correct value", () => {

src/parser/parse.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import traverse from "@babel/traverse";
1111

1212
import path from "path";
1313

14-
import {getPathWithExtension} from "./utils";
14+
import {fixPathResolution, getPathWithExtension} from "./utils";
1515
import {Config} from "../types";
1616

1717
/**
@@ -152,6 +152,7 @@ export const processFile = (
152152
text: string;
153153
resolvedPath: string;
154154
},
155+
config: Config,
155156
): FileResult => {
156157
const dir = path.dirname(filePath);
157158
const result: FileResult = {
@@ -177,7 +178,7 @@ export const processFile = (
177178

178179
ast.program.body.forEach((toplevel) => {
179180
if (toplevel.type === "ImportDeclaration") {
180-
const newLocals = getLocals(dir, toplevel, filePath);
181+
const newLocals = getLocals(dir, toplevel, filePath, config);
181182
if (newLocals) {
182183
Object.keys(newLocals).forEach((k) => {
183184
const local = newLocals[k];
@@ -386,6 +387,7 @@ const getLocals = (
386387
dir: string,
387388
toplevel: ImportDeclaration,
388389
myPath: string,
390+
config: Config,
389391
):
390392
| {
391393
[key: string]: Import;
@@ -395,9 +397,10 @@ const getLocals = (
395397
if (toplevel.importKind === "type") {
396398
return null;
397399
}
398-
const importPath = toplevel.source.value.startsWith(".")
399-
? path.resolve(path.join(dir, toplevel.source.value))
400-
: toplevel.source.value;
400+
const fixedPath = fixPathResolution(toplevel.source.value, config);
401+
const importPath = fixedPath.startsWith(".")
402+
? path.resolve(path.join(dir, fixedPath))
403+
: fixedPath;
401404
const locals: Record<string, any> = {};
402405
toplevel.specifiers.forEach((spec) => {
403406
if (spec.type === "ImportDefaultSpecifier") {
@@ -439,7 +442,7 @@ export const processFiles = (
439442
if (!next || files[next]) {
440443
continue;
441444
}
442-
const result = processFile(next, getFileSource(next));
445+
const result = processFile(next, getFileSource(next), config);
443446
files[next] = result;
444447
listExternalReferences(result, config).forEach((path) => {
445448
if (!files[path] && !toProcess.includes(path)) {

src/parser/resolve.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ const resolveImport = (
5151
},
5252
config: Config,
5353
): Document | null | undefined => {
54-
const absPath: string = getPathWithExtension(expr.path, config);
54+
const absPath = getPathWithExtension(expr.path, config);
55+
if (!absPath) {
56+
return null;
57+
}
5558
if (seen[absPath]) {
5659
errors.push({
5760
loc: expr.loc,

src/parser/utils.ts

+11-14
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import fs from "fs";
22
import {Config} from "../types";
33

4-
export const getPathWithExtension = (
5-
pathWithoutExtension: string,
6-
config: Config,
7-
): string => {
8-
// Process the path so that we can handle aliases.
4+
export const fixPathResolution = (path: string, config: Config) => {
95
if (config.alias) {
106
for (const {find, replacement} of config.alias) {
11-
pathWithoutExtension = pathWithoutExtension.replace(
12-
find,
13-
replacement,
14-
);
7+
path = path.replace(find, replacement);
158
}
169
}
10+
return path;
11+
};
12+
13+
export const getPathWithExtension = (
14+
pathWithoutExtension: string,
15+
config: Config,
16+
) => {
17+
pathWithoutExtension = fixPathResolution(pathWithoutExtension, config);
1718
if (
1819
/\.(less|css|png|gif|jpg|jpeg|js|jsx|ts|tsx|mjs)$/.test(
1920
pathWithoutExtension,
@@ -33,9 +34,5 @@ export const getPathWithExtension = (
3334
if (fs.existsSync(pathWithoutExtension + ".ts")) {
3435
return pathWithoutExtension + ".ts";
3536
}
36-
// NOTE(john): This is a bit of a hack, but it's necessary for when we
37-
// have a file that doesn't exist. This will happen when we delete all of
38-
// the type files before re-running graphql-flow again. We want to ensure
39-
// that we don't error out in this case.
40-
return "";
37+
return null;
4138
};

0 commit comments

Comments
 (0)