diff --git a/.changeset/forty-pens-sip.md b/.changeset/forty-pens-sip.md new file mode 100644 index 0000000..2b3ab8f --- /dev/null +++ b/.changeset/forty-pens-sip.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/graphql-flow": patch +--- + +Fix up some more alias resolution in graphql-flow. diff --git a/schema.json b/schema.json index 7c8df45..70d0b29 100644 --- a/schema.json +++ b/schema.json @@ -91,7 +91,23 @@ "generate": {"oneOf": [ {"$ref": "#/definitions/GenerateConfig"}, {"type": "array", "items": {"$ref": "#/definitions/GenerateConfig"}} - ]} + ]}, + "alias": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "find": { + "type": ["string", "object"] + }, + "replacement": { + "type": "string" + } + }, + "required": [ "find", "replacement" ] + } + } }, "required": [ "crawl", "generate" ] -} \ No newline at end of file +} diff --git a/src/cli/run.ts b/src/cli/run.ts index f56d0ce..9c1190f 100644 --- a/src/cli/run.ts +++ b/src/cli/run.ts @@ -6,6 +6,7 @@ import type {GraphQLSchema} from "graphql/type/schema"; import {generateTypeFiles, processPragmas} from "../generateTypeFiles"; import {processFiles} from "../parser/parse"; import {resolveDocuments} from "../parser/resolve"; +import {getPathWithExtension} from "../parser/utils"; import {findApplicableConfig, getSchemas, loadConfigFile} from "./config"; import {addTypenameToDocument} from "apollo-utilities"; @@ -81,22 +82,11 @@ const inputFiles = cliFiles.length /** Step (2) */ const files = processFiles(inputFiles, config, (f) => { - if (existsSync(f)) { - return readFileSync(f, "utf8"); + const resolvedPath = getPathWithExtension(f, config); + if (!resolvedPath) { + throw new Error(`Unable to find ${f}`); } - if (existsSync(f + ".js")) { - return {text: readFileSync(f + ".js", "utf8"), resolvedPath: f + ".js"}; - } - if (existsSync(f + ".ts")) { - return {text: readFileSync(f + ".ts", "utf8"), resolvedPath: f + ".ts"}; - } - if (existsSync(f + ".tsx")) { - return { - text: readFileSync(f + ".tsx", "utf8"), - resolvedPath: f + ".tsx", - }; - } - throw new Error(`Unable to find ${f}`); + return {text: readFileSync(resolvedPath, "utf8"), resolvedPath}; }); let filesHadErrors = false; diff --git a/src/parser/__test__/utils.test.ts b/src/parser/__test__/utils.test.ts index 607d972..a8da61d 100644 --- a/src/parser/__test__/utils.test.ts +++ b/src/parser/__test__/utils.test.ts @@ -50,7 +50,7 @@ describe("getPathWithExtension", () => { expect(result).toBe("/path/to/file.js"); }); - it("returns an empty string if no file is found", () => { + it("returns null if no file is found", () => { // Arrange jest.spyOn(fs, "existsSync").mockImplementation((path) => false); @@ -58,7 +58,7 @@ describe("getPathWithExtension", () => { const result = getPathWithExtension("/path/to/file", config); // Assert - expect(result).toBe(""); + expect(result).toBe(null); }); it("maps aliases to their correct value", () => { diff --git a/src/parser/parse.ts b/src/parser/parse.ts index da6e439..eac9e1b 100644 --- a/src/parser/parse.ts +++ b/src/parser/parse.ts @@ -11,7 +11,7 @@ import traverse from "@babel/traverse"; import path from "path"; -import {getPathWithExtension} from "./utils"; +import {fixPathResolution, getPathWithExtension} from "./utils"; import {Config} from "../types"; /** @@ -152,6 +152,7 @@ export const processFile = ( text: string; resolvedPath: string; }, + config: Config, ): FileResult => { const dir = path.dirname(filePath); const result: FileResult = { @@ -177,7 +178,7 @@ export const processFile = ( ast.program.body.forEach((toplevel) => { if (toplevel.type === "ImportDeclaration") { - const newLocals = getLocals(dir, toplevel, filePath); + const newLocals = getLocals(dir, toplevel, filePath, config); if (newLocals) { Object.keys(newLocals).forEach((k) => { const local = newLocals[k]; @@ -386,6 +387,7 @@ const getLocals = ( dir: string, toplevel: ImportDeclaration, myPath: string, + config: Config, ): | { [key: string]: Import; @@ -395,9 +397,10 @@ const getLocals = ( if (toplevel.importKind === "type") { return null; } - const importPath = toplevel.source.value.startsWith(".") - ? path.resolve(path.join(dir, toplevel.source.value)) - : toplevel.source.value; + const fixedPath = fixPathResolution(toplevel.source.value, config); + const importPath = fixedPath.startsWith(".") + ? path.resolve(path.join(dir, fixedPath)) + : fixedPath; const locals: Record = {}; toplevel.specifiers.forEach((spec) => { if (spec.type === "ImportDefaultSpecifier") { @@ -439,7 +442,7 @@ export const processFiles = ( if (!next || files[next]) { continue; } - const result = processFile(next, getFileSource(next)); + const result = processFile(next, getFileSource(next), config); files[next] = result; listExternalReferences(result, config).forEach((path) => { if (!files[path] && !toProcess.includes(path)) { diff --git a/src/parser/resolve.ts b/src/parser/resolve.ts index 03df2cb..f530a3d 100644 --- a/src/parser/resolve.ts +++ b/src/parser/resolve.ts @@ -51,7 +51,10 @@ const resolveImport = ( }, config: Config, ): Document | null | undefined => { - const absPath: string = getPathWithExtension(expr.path, config); + const absPath = getPathWithExtension(expr.path, config); + if (!absPath) { + return null; + } if (seen[absPath]) { errors.push({ loc: expr.loc, diff --git a/src/parser/utils.ts b/src/parser/utils.ts index d0c7eb0..620157c 100644 --- a/src/parser/utils.ts +++ b/src/parser/utils.ts @@ -1,19 +1,20 @@ import fs from "fs"; import {Config} from "../types"; -export const getPathWithExtension = ( - pathWithoutExtension: string, - config: Config, -): string => { - // Process the path so that we can handle aliases. +export const fixPathResolution = (path: string, config: Config) => { if (config.alias) { for (const {find, replacement} of config.alias) { - pathWithoutExtension = pathWithoutExtension.replace( - find, - replacement, - ); + path = path.replace(find, replacement); } } + return path; +}; + +export const getPathWithExtension = ( + pathWithoutExtension: string, + config: Config, +) => { + pathWithoutExtension = fixPathResolution(pathWithoutExtension, config); if ( /\.(less|css|png|gif|jpg|jpeg|js|jsx|ts|tsx|mjs)$/.test( pathWithoutExtension, @@ -33,9 +34,5 @@ export const getPathWithExtension = ( if (fs.existsSync(pathWithoutExtension + ".ts")) { return pathWithoutExtension + ".ts"; } - // NOTE(john): This is a bit of a hack, but it's necessary for when we - // have a file that doesn't exist. This will happen when we delete all of - // the type files before re-running graphql-flow again. We want to ensure - // that we don't error out in this case. - return ""; + return null; };