@khanacademy/graphql-flow 3.4.2 → 4.0.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.
@@ -36,7 +36,7 @@ jobs:
36
36
  runs-on: ubuntu-latest
37
37
  steps:
38
38
  - uses: actions/checkout@v4
39
- - uses: Khan/actions@shared-node-cache-v2
39
+ - uses: Khan/actions@shared-node-cache-v3
40
40
  with:
41
41
  node-version: 20.x
42
42
 
@@ -17,7 +17,7 @@ jobs:
17
17
  node-version: [20.x]
18
18
  steps:
19
19
  - uses: actions/checkout@v4
20
- - uses: Khan/actions@shared-node-cache-v2
20
+ - uses: Khan/actions@shared-node-cache-v3
21
21
  with:
22
22
  node-version: ${{ matrix.node-version }}
23
23
 
@@ -34,7 +34,7 @@ jobs:
34
34
 
35
35
  - name: Run TypeScript
36
36
  if: steps.ts-files.outputs.filtered != '[]'
37
- run: yarn typecheck
37
+ run: pnpm typecheck
38
38
 
39
39
  - id: eslint-reset
40
40
  uses: Khan/actions@filter-files-v1
@@ -47,9 +47,9 @@ jobs:
47
47
  uses: Khan/actions@full-or-limited-v0
48
48
  with:
49
49
  full-trigger: ${{ steps.eslint-reset.outputs.filtered }}
50
- full: yarn eslint src/**/*.ts
50
+ full: pnpm eslint src/**/*.ts
51
51
  limited-trigger: ${{ steps.ts-files.outputs.filtered }}
52
- limited: yarn eslint {}
52
+ limited: pnpm eslint {}
53
53
 
54
54
  - id: jest-reset
55
55
  uses: Khan/actions@filter-files-v1
@@ -62,6 +62,6 @@ jobs:
62
62
  uses: Khan/actions@full-or-limited-v0
63
63
  with:
64
64
  full-trigger: ${{ steps.jest-reset.outputs.filtered }}
65
- full: yarn jest
65
+ full: pnpm jest
66
66
  limited-trigger: ${{ steps.ts-files.outputs.filtered }}
67
- limited: yarn jest --findRelatedTests {}
67
+ limited: pnpm jest --findRelatedTests {}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @khanacademy/graphql-flow
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 9d96c11: Overhaul import resolution, relying on tsconfig for import aliases, and rspack-resolver for package imports. This removes the `alias` config option, instead requiring that aliases be defined in a `tsconfig.json`.
8
+
9
+ ### Minor Changes
10
+
11
+ - a27caca: Support "export \* from" for fragments
12
+
3
13
  ## 3.4.2
4
14
 
5
15
  ### Patch Changes
package/dist/cli/run.js CHANGED
@@ -40,7 +40,7 @@ const inputFiles = (0, _config.getInputFiles)(options, config);
40
40
  /** Step (2) */
41
41
 
42
42
  const files = (0, _parse.processFiles)(inputFiles, config, f => {
43
- const resolvedPath = (0, _utils.getPathWithExtension)(f, config);
43
+ const resolvedPath = (0, _utils.getPathWithExtension)(f);
44
44
  if (!resolvedPath) {
45
45
  throw new Error(`Unable to find ${f}`);
46
46
  }
@@ -8,6 +8,7 @@ var _wonderStuffCore = require("@khanacademy/wonder-stuff-core");
8
8
  var _parser = require("@babel/parser");
9
9
  var _traverse = _interopRequireDefault(require("@babel/traverse"));
10
10
  var _path = _interopRequireDefault(require("path"));
11
+ var _resolveImport = require("./resolveImport");
11
12
  var _utils = require("./utils");
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
14
  /**
@@ -47,12 +48,12 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
47
48
  * potentially relevant, and of course any values referenced
48
49
  * from a graphql template are treated as relevant.
49
50
  */
50
- const listExternalReferences = (file, config) => {
51
+ const listExternalReferences = file => {
51
52
  const paths = {};
52
53
  const add = (v, followImports) => {
53
54
  if (v.type === "import") {
54
55
  if (followImports) {
55
- const absPath = (0, _utils.getPathWithExtension)(v.path, config);
56
+ const absPath = (0, _utils.getPathWithExtension)(v.path);
56
57
  if (absPath) {
57
58
  paths[absPath] = true;
58
59
  }
@@ -71,14 +72,15 @@ const listExternalReferences = (file, config) => {
71
72
  file.operations.forEach(op => op.source.expressions.forEach(expr => add(expr,
72
73
  // Imports that are used in graphql expressions definitely need to be followed.
73
74
  true)));
75
+ file.exportAlls.forEach(expr => add(expr, true));
74
76
  return Object.keys(paths);
75
77
  };
76
78
  const processFile = (filePath, contents, config) => {
77
- const dir = _path.default.dirname(filePath);
78
79
  const result = {
79
80
  path: filePath,
80
81
  operations: [],
81
82
  exports: {},
83
+ exportAlls: [],
82
84
  locals: {},
83
85
  errors: []
84
86
  };
@@ -94,14 +96,16 @@ const processFile = (filePath, contents, config) => {
94
96
  ast.program.body.forEach(toplevel => {
95
97
  var _toplevel$declaration;
96
98
  if (toplevel.type === "ImportDeclaration") {
97
- const newLocals = getLocals(dir, toplevel, filePath, config);
99
+ const newLocals = getLocals(toplevel, filePath);
98
100
  if (newLocals) {
99
101
  Object.keys(newLocals).forEach(k => {
102
+ var _local$resolvedPath$i, _local$resolvedPath;
100
103
  const local = newLocals[k];
101
- if (local.path.startsWith("/")) {
104
+ const isGraphqlTagImport = local.rawPath === "graphql-tag" || ((_local$resolvedPath$i = (_local$resolvedPath = local.resolvedPath) === null || _local$resolvedPath === void 0 ? void 0 : _local$resolvedPath.includes(`${_path.default.sep}node_modules${_path.default.sep}graphql-tag`)) !== null && _local$resolvedPath$i !== void 0 ? _local$resolvedPath$i : false);
105
+ if (_path.default.isAbsolute(local.path)) {
102
106
  result.locals[k] = local;
103
107
  }
104
- if (local.path === "graphql-tag" && local.name === "default") {
108
+ if (isGraphqlTagImport && local.name === "default") {
105
109
  gqlTagNames.push(k);
106
110
  }
107
111
  });
@@ -111,7 +115,8 @@ const processFile = (filePath, contents, config) => {
111
115
  if (toplevel.source) {
112
116
  var _toplevel$specifiers;
113
117
  const source = toplevel.source;
114
- const importPath = source.value.startsWith(".") ? _path.default.resolve(_path.default.join(dir, source.value)) : source.value;
118
+ const resolvedPath = (0, _resolveImport.resolveImportPath)(filePath, source.value);
119
+ const importPath = resolvedPath !== null && resolvedPath !== void 0 ? resolvedPath : source.value;
115
120
  (_toplevel$specifiers = toplevel.specifiers) === null || _toplevel$specifiers === void 0 || _toplevel$specifiers.forEach(spec => {
116
121
  if (spec.type === "ExportSpecifier" && spec.exported.type === "Identifier") {
117
122
  var _spec$start, _spec$end, _spec$loc$start$line, _spec$loc;
@@ -140,6 +145,22 @@ const processFile = (filePath, contents, config) => {
140
145
  });
141
146
  }
142
147
  }
148
+ if (toplevel.type === "ExportAllDeclaration" && toplevel.source) {
149
+ var _toplevel$start, _toplevel$end, _toplevel$loc$start$l, _toplevel$loc;
150
+ const source = toplevel.source;
151
+ const importPath = source.value.startsWith(".") ? _path.default.resolve(_path.default.join(_path.default.dirname(filePath), source.value)) : source.value;
152
+ result.exportAlls.push({
153
+ type: "import",
154
+ name: "*",
155
+ path: importPath,
156
+ loc: {
157
+ start: (_toplevel$start = toplevel.start) !== null && _toplevel$start !== void 0 ? _toplevel$start : -1,
158
+ end: (_toplevel$end = toplevel.end) !== null && _toplevel$end !== void 0 ? _toplevel$end : -1,
159
+ line: (_toplevel$loc$start$l = (_toplevel$loc = toplevel.loc) === null || _toplevel$loc === void 0 ? void 0 : _toplevel$loc.start.line) !== null && _toplevel$loc$start$l !== void 0 ? _toplevel$loc$start$l : -1,
160
+ path: filePath
161
+ }
162
+ });
163
+ }
143
164
  const processDeclarator = (decl, isExported) => {
144
165
  if (decl.id.type !== "Identifier" || !decl.init) {
145
166
  return;
@@ -210,7 +231,8 @@ const processFile = (filePath, contents, config) => {
210
231
  };
211
232
  (0, _traverse.default)(ast, {
212
233
  TaggedTemplateExpression(path) {
213
- visitTpl(path.node, name => {
234
+ const node = path.node;
235
+ visitTpl(node, name => {
214
236
  const binding = path.scope.getBinding(name);
215
237
  if (!binding) {
216
238
  return null;
@@ -273,12 +295,12 @@ const processTemplate = (tpl, result, getTemplate) => {
273
295
  }
274
296
  };
275
297
  };
276
- const getLocals = (dir, toplevel, myPath, config) => {
298
+ const getLocals = (toplevel, myPath) => {
277
299
  if (toplevel.importKind === "type") {
278
300
  return null;
279
301
  }
280
- const fixedPath = (0, _utils.fixPathResolution)(toplevel.source.value, config);
281
- const importPath = fixedPath.startsWith(".") ? _path.default.resolve(_path.default.join(dir, fixedPath)) : fixedPath;
302
+ const resolvedPath = (0, _resolveImport.resolveImportPath)(myPath, toplevel.source.value);
303
+ const importPath = resolvedPath !== null && resolvedPath !== void 0 ? resolvedPath : toplevel.source.value;
282
304
  const locals = {};
283
305
  toplevel.specifiers.forEach(spec => {
284
306
  if (spec.type === "ImportDefaultSpecifier") {
@@ -286,6 +308,8 @@ const getLocals = (dir, toplevel, myPath, config) => {
286
308
  type: "import",
287
309
  name: "default",
288
310
  path: importPath,
311
+ rawPath: toplevel.source.value,
312
+ resolvedPath,
289
313
  loc: {
290
314
  start: spec.start,
291
315
  end: spec.end,
@@ -297,6 +321,8 @@ const getLocals = (dir, toplevel, myPath, config) => {
297
321
  type: "import",
298
322
  name: spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value,
299
323
  path: importPath,
324
+ rawPath: toplevel.source.value,
325
+ resolvedPath,
300
326
  loc: {
301
327
  start: spec.start,
302
328
  end: spec.end,
@@ -321,7 +347,7 @@ const processFiles = (filePaths, config, getFileSource) => {
321
347
  }
322
348
  const result = processFile(next, source, config);
323
349
  files[next] = result;
324
- listExternalReferences(result, config).forEach(path => {
350
+ listExternalReferences(result).forEach(path => {
325
351
  if (!files[path] && !toProcess.includes(path)) {
326
352
  toProcess.push(path);
327
353
  }
@@ -29,7 +29,7 @@ const resolveDocuments = (files, config) => {
29
29
  };
30
30
  exports.resolveDocuments = resolveDocuments;
31
31
  const resolveImport = (expr, files, errors, seen, config) => {
32
- const absPath = (0, _utils.getPathWithExtension)(expr.path, config);
32
+ const absPath = (0, _utils.getPathWithExtension)(expr.path);
33
33
  if (!absPath) {
34
34
  return null;
35
35
  }
@@ -50,6 +50,19 @@ const resolveImport = (expr, files, errors, seen, config) => {
50
50
  return null;
51
51
  }
52
52
  if (!res.exports[expr.name]) {
53
+ if (expr.name !== "*" && res.exportAlls.length) {
54
+ for (const exportAll of res.exportAlls) {
55
+ const value = resolveImport({
56
+ ...exportAll,
57
+ name: expr.name
58
+ }, files, errors, {
59
+ ...seen
60
+ }, config);
61
+ if (value) {
62
+ return value;
63
+ }
64
+ }
65
+ }
53
66
  errors.push({
54
67
  loc: expr.loc,
55
68
  message: `${absPath} has no valid gql export ${expr.name}`
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.resetImportCache = resetImportCache;
7
+ exports.resolveImportPath = resolveImportPath;
8
+ var _nodePath = _interopRequireDefault(require("node:path"));
9
+ var _rspackResolver = require("rspack-resolver");
10
+ var _tsconfigPaths = require("tsconfig-paths");
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ // Copied from https://github.com/Khan/frontend/blob/main/libs/node/resolve-import/src/resolve-import.ts
13
+ // In future it would be cool to publish @khan/node-resolve-import as a public library so we
14
+ // could consume it here.
15
+
16
+ const CONDITION_NAMES = ["import"];
17
+ const matchPathCache = new Map();
18
+ let esmResolver = getEsmResolver();
19
+ function getEsmResolver() {
20
+ return new _rspackResolver.ResolverFactory({
21
+ conditionNames: CONDITION_NAMES,
22
+ mainFields: ["module", "main"],
23
+ extensions: [".mjs", ".js", ".jsx", ".ts", ".tsx"]
24
+ });
25
+ }
26
+ function resetImportCache() {
27
+ matchPathCache.clear();
28
+ esmResolver = getEsmResolver();
29
+ }
30
+
31
+ /**
32
+ * Resolves an import path using tsconfig and the rspack resolver.
33
+ *
34
+ * @param sourceFile - The file that is importing the path.
35
+ * @param importPath - The path to resolve.
36
+ * @returns The fully resolved path.
37
+ */
38
+ function resolveImportPath(sourceFile, importPath) {
39
+ const dir = _nodePath.default.dirname(sourceFile);
40
+ let matchPath = matchPathCache.get(dir);
41
+ if (!matchPath) {
42
+ const foundConfig = (0, _tsconfigPaths.loadConfig)(dir);
43
+ if (foundConfig.resultType !== "success") {
44
+ throw new Error("Failed to load tsconfig");
45
+ }
46
+ matchPath = (0, _tsconfigPaths.createMatchPath)(foundConfig.absoluteBaseUrl, foundConfig.paths, CONDITION_NAMES);
47
+ matchPathCache.set(dir, matchPath);
48
+ }
49
+
50
+ // See if we can resolve the import path using the tsconfig.
51
+ const resolvedPath = matchPath(importPath);
52
+
53
+ // Get the directory of the source file to resolve against.
54
+ const sourceFileDir = _nodePath.default.dirname(sourceFile);
55
+
56
+ // Get the fully resolved path.
57
+ return esmResolver.sync(sourceFileDir, resolvedPath !== null && resolvedPath !== void 0 ? resolvedPath : importPath).path;
58
+ }
@@ -3,23 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getPathWithExtension = exports.fixPathResolution = void 0;
6
+ exports.getPathWithExtension = void 0;
7
7
  var _fs = _interopRequireDefault(require("fs"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
- const fixPathResolution = (path, config) => {
10
- if (config.alias) {
11
- for (const {
12
- find,
13
- replacement
14
- } of config.alias) {
15
- path = path.replace(find, replacement);
16
- }
17
- }
18
- return path;
19
- };
20
- exports.fixPathResolution = fixPathResolution;
21
- const getPathWithExtension = (pathWithoutExtension, config) => {
22
- pathWithoutExtension = fixPathResolution(pathWithoutExtension, config);
9
+ const getPathWithExtension = pathWithoutExtension => {
23
10
  if (/\.(less|css|png|gif|jpg|jpeg|js|jsx|ts|tsx|mjs)$/.test(pathWithoutExtension)) {
24
11
  return pathWithoutExtension;
25
12
  }
package/package.json CHANGED
@@ -1,66 +1,72 @@
1
1
  {
2
- "name": "@khanacademy/graphql-flow",
3
- "version": "3.4.2",
4
- "repository": {
5
- "type": "git",
6
- "url": "https://github.com/Khan/graphql-flow.git"
7
- },
8
- "bugs": {
9
- "url": "https://github.com/Khan/graphql-flow/issues"
10
- },
11
- "publishConfig": {
12
- "access": "public",
13
- "provenance": true
14
- },
15
- "bin": {
16
- "graphql-flow": "dist/cli/run.js"
17
- },
18
- "jest": {
19
- "testPathIgnorePatterns": [
20
- "dist"
21
- ]
22
- },
23
- "scripts": {
24
- "test": "jest",
25
- "typecheck": "tsc --noEmit",
26
- "publish:ci": "yarn run build && changeset publish",
27
- "build": "babel src --extensions '.ts, .tsx' --out-dir dist --ignore 'src/**/*.spec.ts','src/**/*.test.ts' && chmod 755 dist/cli/run.js"
28
- },
29
- "main": "dist/index.js",
30
- "devDependencies": {
31
- "@babel/cli": "^7.17.6",
32
- "@babel/eslint-parser": "^7.17.0",
33
- "@babel/polyfill": "^7.0.0",
34
- "@babel/preset-env": "^7.24.5",
35
- "@babel/preset-typescript": "^7.24.1",
36
- "@changesets/cli": "^2.21.1",
37
- "@khanacademy/eslint-config": "^4.0.0",
38
- "@types/jest": "^29.5.3",
39
- "@types/prop-types": "^15.7.12",
40
- "@types/react": "^18.3.3",
41
- "@typescript-eslint/eslint-plugin": "^7.17.0",
42
- "@typescript-eslint/parser": "^7.17.0",
43
- "babel-jest": "23.4.2",
44
- "eslint": "^8.57.0",
45
- "eslint-config-prettier": "7.0.0",
46
- "eslint-plugin-jest": "^28.6.0",
47
- "eslint-plugin-prettier": "^4.0.0",
48
- "graphql-tag": "2.10.1",
49
- "jest": "^27.5.1",
50
- "prettier": "^2.5.1",
51
- "prettier-eslint": "^13.0.0",
52
- "typescript": "^5.1.6"
53
- },
54
- "dependencies": {
55
- "@babel/core": "^7.24.5",
56
- "@babel/generator": "^7.24.5",
57
- "@babel/parser": "^7.24.5",
58
- "@babel/traverse": "^7.24.5",
59
- "@babel/types": "^7.24.5",
60
- "@khanacademy/wonder-stuff-core": "^1.5.1",
61
- "apollo-utilities": "^1.3.4",
62
- "graphql": "^16.9.0",
63
- "jsonschema": "^1.4.1",
64
- "minimist": "^1.2.8"
65
- }
66
- }
2
+ "name": "@khanacademy/graphql-flow",
3
+ "version": "4.0.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/Khan/graphql-flow.git"
7
+ },
8
+ "bugs": {
9
+ "url": "https://github.com/Khan/graphql-flow/issues"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "provenance": true
14
+ },
15
+ "bin": {
16
+ "graphql-flow": "dist/cli/run.js"
17
+ },
18
+ "jest": {
19
+ "testPathIgnorePatterns": [
20
+ "dist"
21
+ ]
22
+ },
23
+ "main": "dist/index.js",
24
+ "devDependencies": {
25
+ "@babel/cli": "^7.17.6",
26
+ "@babel/eslint-parser": "^7.17.0",
27
+ "@babel/polyfill": "^7.0.0",
28
+ "@babel/preset-env": "^7.24.5",
29
+ "@babel/preset-typescript": "^7.24.1",
30
+ "@changesets/cli": "^2.21.1",
31
+ "@jest/globals": "^30.2.0",
32
+ "@khanacademy/eslint-config": "^4.0.0",
33
+ "@types/babel__generator": "^7.27.0",
34
+ "@types/babel__traverse": "^7.28.0",
35
+ "@types/jest": "^29.5.3",
36
+ "@types/minimist": "^1.2.5",
37
+ "@types/prop-types": "^15.7.12",
38
+ "@types/react": "^18.3.3",
39
+ "@typescript-eslint/eslint-plugin": "^7.17.0",
40
+ "@typescript-eslint/parser": "^7.17.0",
41
+ "babel-jest": "23.4.2",
42
+ "eslint": "^8.57.0",
43
+ "eslint-config-prettier": "7.0.0",
44
+ "eslint-plugin-jest": "^28.6.0",
45
+ "eslint-plugin-prettier": "^4.0.0",
46
+ "graphql-tag": "2.10.1",
47
+ "jest": "^27.5.1",
48
+ "prettier": "^2.5.1",
49
+ "prettier-eslint": "^13.0.0",
50
+ "typescript": "^5.1.6"
51
+ },
52
+ "dependencies": {
53
+ "@babel/core": "^7.24.5",
54
+ "@babel/generator": "^7.24.5",
55
+ "@babel/parser": "^7.24.5",
56
+ "@babel/traverse": "^7.24.5",
57
+ "@babel/types": "^7.24.5",
58
+ "@khanacademy/wonder-stuff-core": "^1.5.1",
59
+ "apollo-utilities": "^1.3.4",
60
+ "graphql": "^16.9.0",
61
+ "jsonschema": "^1.4.1",
62
+ "minimist": "^1.2.8",
63
+ "rspack-resolver": "^1.3.0",
64
+ "tsconfig-paths": "^4.2.0"
65
+ },
66
+ "scripts": {
67
+ "test": "jest",
68
+ "typecheck": "tsc --noEmit",
69
+ "publish:ci": "pnpm build && changeset publish",
70
+ "build": "babel src --extensions '.ts, .tsx' --out-dir dist --ignore 'src/**/*.spec.ts','src/**/*.test.ts' && chmod 755 dist/cli/run.js"
71
+ }
72
+ }
package/schema.json CHANGED
@@ -94,23 +94,7 @@
94
94
  "generate": {"oneOf": [
95
95
  {"$ref": "#/definitions/GenerateConfig"},
96
96
  {"type": "array", "items": {"$ref": "#/definitions/GenerateConfig"}}
97
- ]},
98
- "alias": {
99
- "type": "array",
100
- "items": {
101
- "type": "object",
102
- "additionalProperties": false,
103
- "properties": {
104
- "find": {
105
- "type": ["string", "object"]
106
- },
107
- "replacement": {
108
- "type": "string"
109
- }
110
- },
111
- "required": [ "find", "replacement" ]
112
- }
113
- }
97
+ ]}
114
98
  },
115
99
  "required": [ "crawl", "generate" ]
116
100
  }
package/src/cli/run.ts CHANGED
@@ -56,7 +56,7 @@ const inputFiles = getInputFiles(options, config);
56
56
  /** Step (2) */
57
57
 
58
58
  const files = processFiles(inputFiles, config, (f) => {
59
- const resolvedPath = getPathWithExtension(f, config);
59
+ const resolvedPath = getPathWithExtension(f);
60
60
  if (!resolvedPath) {
61
61
  throw new Error(`Unable to find ${f}`);
62
62
  }
@@ -1,4 +1,7 @@
1
- import {describe, it, expect} from "@jest/globals";
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+ import {describe, it, expect, afterEach} from "@jest/globals";
2
5
 
3
6
  import {Config} from "../../types";
4
7
  import {processFiles} from "../parse";
@@ -6,6 +9,32 @@ import {resolveDocuments} from "../resolve";
6
9
 
7
10
  import {print} from "graphql/language/printer";
8
11
 
12
+ jest.mock("../resolveImport", () => ({
13
+ resetImportCache: jest.fn(),
14
+ resolveImportPath: jest
15
+ .fn()
16
+ .mockImplementation((sourceFile: string, importPath: string) => {
17
+ const path = require("path");
18
+ if (importPath === "graphql-tag") {
19
+ return "/repo/node_modules/graphql-tag/index.js";
20
+ }
21
+ if (importPath === "monorepo-package/fragment") {
22
+ return "/repo/node_modules/monorepo-package/fragment.js";
23
+ }
24
+ if (importPath.startsWith(".")) {
25
+ return path.resolve(path.dirname(sourceFile), importPath);
26
+ }
27
+ if (path.isAbsolute(importPath)) {
28
+ return importPath;
29
+ }
30
+ return null;
31
+ }),
32
+ }));
33
+
34
+ afterEach(() => {
35
+ jest.clearAllMocks();
36
+ });
37
+
9
38
  const fixtureFiles: {
10
39
  [key: string]:
11
40
  | string
@@ -14,6 +43,27 @@ const fixtureFiles: {
14
43
  resolvedPath: string;
15
44
  };
16
45
  } = {
46
+ "/repo/node_modules/monorepo-package/fragment.js": `
47
+ import gql from 'graphql-tag';
48
+
49
+ export const sharedFragment = gql\`
50
+ fragment SharedFields on Something {
51
+ id
52
+ }
53
+ \`;
54
+ `,
55
+ "/repo/packages/app/App.js": `
56
+ import gql from 'graphql-tag';
57
+ import {sharedFragment} from 'monorepo-package/fragment';
58
+ export const appQuery = gql\`
59
+ query AppQuery {
60
+ viewer {
61
+ ...SharedFields
62
+ }
63
+ }
64
+ \${sharedFragment}
65
+ \`;
66
+ `,
17
67
  "/firstFile.js": `
18
68
  // Note that you can import graphql-tag as
19
69
  // something other than gql.
@@ -57,6 +107,31 @@ const fixtureFiles: {
57
107
  \`;
58
108
  export {secondFragment};`,
59
109
 
110
+ "/starExportSource.js": `
111
+ import gql from 'graphql-tag';
112
+ export const starFragment = gql\`
113
+ fragment StarFragment on Star {
114
+ id
115
+ }
116
+ \`;
117
+ `,
118
+ "/starExportReexport.js": `
119
+ export * from './starExportSource.js';
120
+ `,
121
+ "/starExportConsumer.js": `
122
+ import gql from 'graphql-tag';
123
+ import {starFragment} from './starExportReexport.js';
124
+
125
+ export const starQuery = gql\`
126
+ query StarQuery {
127
+ stars {
128
+ ...StarFragment
129
+ }
130
+ }
131
+ \${starFragment}
132
+ \`;
133
+ `,
134
+
60
135
  "/thirdFile.js": `
61
136
  import {fromFirstFile, alsoFirst, secondFragment} from './secondFile.js';
62
137
  import gql from 'graphql-tag';
@@ -338,4 +413,123 @@ describe("processing fragments in various ways", () => {
338
413
  );
339
414
  expect(printed).toMatchInlineSnapshot(`Object {}`);
340
415
  });
416
+
417
+ it("should resolve fragments re-exported via export all", () => {
418
+ // Arrange
419
+ const config: Config = {
420
+ crawl: {
421
+ root: "/here/we/crawl",
422
+ },
423
+ generate: {
424
+ match: [/\.fixture\.js$/],
425
+ exclude: [
426
+ "_test\\.js$",
427
+ "\\bcourse-editor-package\\b",
428
+ "\\.fixture\\.js$",
429
+ "\\b__flowtests__\\b",
430
+ "\\bcourse-editor\\b",
431
+ ],
432
+ readOnlyArray: false,
433
+ regenerateCommand: "make gqlflow",
434
+ scalars: {
435
+ JSONString: "string",
436
+ KALocale: "string",
437
+ NaiveDateTime: "string",
438
+ },
439
+ splitTypes: true,
440
+ generatedDirectory: "__graphql-types__",
441
+ exportAllObjectTypes: true,
442
+ schemaFilePath: "./composed_schema.graphql",
443
+ },
444
+ };
445
+ // Act
446
+ const files = processFiles(
447
+ ["/starExportConsumer.js"],
448
+ config,
449
+ getFileSource,
450
+ );
451
+ const {resolved} = resolveDocuments(files, config);
452
+ const printed: Record<string, any> = {};
453
+ Object.keys(resolved).map(
454
+ (k: any) => (printed[k] = print(resolved[k].document).trim()),
455
+ );
456
+
457
+ // Assert
458
+ expect(printed).toMatchInlineSnapshot(`
459
+ Object {
460
+ "/starExportConsumer.js:5": "query StarQuery {
461
+ stars {
462
+ ...StarFragment
463
+ }
464
+ }
465
+
466
+ fragment StarFragment on Star {
467
+ id
468
+ }",
469
+ "/starExportSource.js:3": "fragment StarFragment on Star {
470
+ id
471
+ }",
472
+ }
473
+ `);
474
+ });
475
+
476
+ it("should resolve fragments imported from monorepo packages", () => {
477
+ // Arrange
478
+ const config: Config = {
479
+ crawl: {
480
+ root: "/here/we/crawl",
481
+ },
482
+ generate: {
483
+ match: [/\.fixture\.js$/],
484
+ exclude: [
485
+ "_test\\.js$",
486
+ "\\bcourse-editor-package\\b",
487
+ "\\.fixture\\.js$",
488
+ "\\b__flowtests__\\b",
489
+ "\\bcourse-editor\\b",
490
+ ],
491
+ readOnlyArray: false,
492
+ regenerateCommand: "make gqlflow",
493
+ scalars: {
494
+ JSONString: "string",
495
+ KALocale: "string",
496
+ NaiveDateTime: "string",
497
+ },
498
+ splitTypes: true,
499
+ generatedDirectory: "__graphql-types__",
500
+ exportAllObjectTypes: true,
501
+ schemaFilePath: "./composed_schema.graphql",
502
+ },
503
+ };
504
+
505
+ // Act
506
+ const files = processFiles(
507
+ ["/repo/packages/app/App.js"],
508
+ config,
509
+ getFileSource,
510
+ );
511
+ const {resolved} = resolveDocuments(files, config);
512
+ const printed: Record<string, any> = {};
513
+ Object.keys(resolved).map(
514
+ (k: any) => (printed[k] = print(resolved[k].document).trim()),
515
+ );
516
+
517
+ // Assert
518
+ expect(printed).toMatchInlineSnapshot(`
519
+ Object {
520
+ "/repo/node_modules/monorepo-package/fragment.js:4": "fragment SharedFields on Something {
521
+ id
522
+ }",
523
+ "/repo/packages/app/App.js:4": "query AppQuery {
524
+ viewer {
525
+ ...SharedFields
526
+ }
527
+ }
528
+
529
+ fragment SharedFields on Something {
530
+ id
531
+ }",
532
+ }
533
+ `);
534
+ });
341
535
  });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+ import {afterEach, beforeEach, describe, expect, it} from "@jest/globals";
5
+ import {resolveImportPath, resetImportCache} from "../resolveImport";
6
+ import {ResolverFactory} from "rspack-resolver";
7
+
8
+ const mockSync = jest.fn();
9
+ const mockCreateMatchPath = jest.fn();
10
+ const mockLoadConfig = jest.fn();
11
+
12
+ jest.mock("rspack-resolver", () => ({
13
+ ResolverFactory: jest.fn().mockImplementation(() => ({
14
+ sync: (...args: Array<unknown>) => mockSync(...args),
15
+ })),
16
+ }));
17
+
18
+ jest.mock("tsconfig-paths", () => ({
19
+ createMatchPath: jest
20
+ .fn()
21
+ .mockImplementation((...args: Array<unknown>) =>
22
+ mockCreateMatchPath(...args),
23
+ ),
24
+ loadConfig: jest
25
+ .fn()
26
+ .mockImplementation((...args: Array<unknown>) =>
27
+ mockLoadConfig(...args),
28
+ ),
29
+ }));
30
+
31
+ describe("resolveImportPath", () => {
32
+ beforeEach(() => {
33
+ mockSync.mockReset();
34
+ mockCreateMatchPath.mockReset();
35
+ mockLoadConfig.mockReset();
36
+ (ResolverFactory as unknown as jest.Mock).mockClear();
37
+ resetImportCache();
38
+ });
39
+
40
+ afterEach(() => {
41
+ jest.clearAllMocks();
42
+ });
43
+
44
+ it("returns the resolved path from the resolver", () => {
45
+ // Arrange
46
+ const matchPath = jest.fn().mockReturnValue("/repo/src/alias/thing.ts");
47
+ mockLoadConfig.mockReturnValue({
48
+ resultType: "success",
49
+ absoluteBaseUrl: "/repo",
50
+ paths: {"@/*": ["src/*"]},
51
+ });
52
+ mockCreateMatchPath.mockReturnValue(matchPath);
53
+ mockSync.mockReturnValue({path: "/repo/src/alias/thing.ts"});
54
+
55
+ // Act
56
+ const result = resolveImportPath("/repo/src/file.ts", "@/alias/thing");
57
+
58
+ // Assert
59
+ expect(result).toBe("/repo/src/alias/thing.ts");
60
+ });
61
+
62
+ it("loads tsconfig from the source file directory", () => {
63
+ // Arrange
64
+ const matchPath = jest.fn().mockReturnValue("/repo/src/alias/thing.ts");
65
+ mockLoadConfig.mockReturnValue({
66
+ resultType: "success",
67
+ absoluteBaseUrl: "/repo",
68
+ paths: {"@/*": ["src/*"]},
69
+ });
70
+ mockCreateMatchPath.mockReturnValue(matchPath);
71
+ mockSync.mockReturnValue({path: "/repo/src/alias/thing.ts"});
72
+
73
+ // Act
74
+ resolveImportPath("/repo/src/file.ts", "@/alias/thing");
75
+
76
+ // Assert
77
+ expect(mockLoadConfig).toHaveBeenCalledWith("/repo/src");
78
+ });
79
+
80
+ it("caches tsconfig matchPath per source directory", () => {
81
+ // Arrange
82
+ const matchPath = jest.fn().mockReturnValue(undefined);
83
+ mockLoadConfig.mockReturnValue({
84
+ resultType: "success",
85
+ absoluteBaseUrl: "/repo",
86
+ paths: {},
87
+ });
88
+ mockCreateMatchPath.mockReturnValue(matchPath);
89
+ mockSync.mockReturnValue({path: "/repo/node_modules/pkg/index.js"});
90
+
91
+ // Act
92
+ resolveImportPath("/repo/src/a.ts", "pkg");
93
+ resolveImportPath("/repo/src/b.ts", "pkg");
94
+
95
+ // Assert
96
+ expect(mockLoadConfig).toHaveBeenCalledTimes(1);
97
+ });
98
+ });
@@ -1,41 +1,10 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
1
4
  import fs from "fs";
2
- import {describe, it, expect, jest} from "@jest/globals";
3
- import type {Config} from "../../types";
4
-
5
+ import {describe, it, expect} from "@jest/globals";
5
6
  import {getPathWithExtension} from "../utils";
6
7
 
7
- const generate = {
8
- match: [/\.fixture\.js$/],
9
- exclude: [
10
- "_test\\.js$",
11
- "\\bcourse-editor-package\\b",
12
- "\\.fixture\\.js$",
13
- "\\b__flowtests__\\b",
14
- "\\bcourse-editor\\b",
15
- ],
16
- readOnlyArray: false,
17
- regenerateCommand: "make gqlflow",
18
- scalars: {
19
- JSONString: "string",
20
- KALocale: "string",
21
- NaiveDateTime: "string",
22
- },
23
- splitTypes: true,
24
- generatedDirectory: "__graphql-types__",
25
- exportAllObjectTypes: true,
26
- schemaFilePath: "./composed_schema.graphql",
27
- } as const;
28
-
29
- const config: Config = {
30
- crawl: {
31
- root: "/here/we/crawl",
32
- },
33
- generate: [
34
- {...generate, match: [/^static/], exportAllObjectTypes: false},
35
- generate,
36
- ],
37
- };
38
-
39
8
  describe("getPathWithExtension", () => {
40
9
  it("should handle a basic missing extension", () => {
41
10
  // Arrange
@@ -44,7 +13,7 @@ describe("getPathWithExtension", () => {
44
13
  );
45
14
 
46
15
  // Act
47
- const result = getPathWithExtension("/path/to/file", config);
16
+ const result = getPathWithExtension("/path/to/file");
48
17
 
49
18
  // Assert
50
19
  expect(result).toBe("/path/to/file.js");
@@ -55,26 +24,20 @@ describe("getPathWithExtension", () => {
55
24
  jest.spyOn(fs, "existsSync").mockImplementation((path) => false);
56
25
 
57
26
  // Act
58
- const result = getPathWithExtension("/path/to/file", config);
27
+ const result = getPathWithExtension("/path/to/file");
59
28
 
60
29
  // Assert
61
30
  expect(result).toBe(null);
62
31
  });
63
32
 
64
- it("maps aliases to their correct value", () => {
33
+ it("returns the original path when an extension is already present", () => {
65
34
  // Arrange
66
- jest.spyOn(fs, "existsSync").mockImplementation((path) =>
67
- typeof path === "string" ? path.endsWith(".js") : false,
68
- );
69
- const tmpConfig: Config = {
70
- ...config,
71
- alias: [{find: "~", replacement: "../../some/prefix"}],
72
- };
35
+ const input = "/dir/file.tsx";
73
36
 
74
37
  // Act
75
- const result = getPathWithExtension("~/dir/file", tmpConfig);
38
+ const result = getPathWithExtension(input);
76
39
 
77
40
  // Assert
78
- expect(result).toBe("../../some/prefix/dir/file.js");
41
+ expect(result).toBe(input);
79
42
  });
80
43
  });
@@ -8,10 +8,12 @@ import type {
8
8
 
9
9
  import {parse, ParserPlugin} from "@babel/parser";
10
10
  import traverse from "@babel/traverse";
11
+ import type {NodePath} from "@babel/traverse";
11
12
 
12
13
  import path from "path";
13
14
 
14
- import {fixPathResolution, getPathWithExtension} from "./utils";
15
+ import {resolveImportPath} from "./resolveImport";
16
+ import {getPathWithExtension} from "./utils";
15
17
  import {Config} from "../types";
16
18
 
17
19
  /**
@@ -63,6 +65,8 @@ export type Import = {
63
65
  type: "import";
64
66
  name: string;
65
67
  path: string;
68
+ rawPath?: string;
69
+ resolvedPath?: string | null;
66
70
  loc: Loc;
67
71
  };
68
72
 
@@ -79,6 +83,7 @@ export type FileResult = {
79
83
  exports: {
80
84
  [key: string]: Document | Import;
81
85
  };
86
+ exportAlls: Array<Import>;
82
87
  locals: {
83
88
  [key: string]: Document | Import;
84
89
  };
@@ -100,15 +105,12 @@ export type Files = {
100
105
  * potentially relevant, and of course any values referenced
101
106
  * from a graphql template are treated as relevant.
102
107
  */
103
- const listExternalReferences = (
104
- file: FileResult,
105
- config: Config,
106
- ): Array<string> => {
108
+ const listExternalReferences = (file: FileResult): Array<string> => {
107
109
  const paths: Record<string, any> = {};
108
110
  const add = (v: Document | Import, followImports: boolean) => {
109
111
  if (v.type === "import") {
110
112
  if (followImports) {
111
- const absPath = getPathWithExtension(v.path, config);
113
+ const absPath = getPathWithExtension(v.path);
112
114
  if (absPath) {
113
115
  paths[absPath] = true;
114
116
  }
@@ -141,6 +143,7 @@ const listExternalReferences = (
141
143
  ),
142
144
  ),
143
145
  );
146
+ file.exportAlls.forEach((expr) => add(expr, true));
144
147
  return Object.keys(paths);
145
148
  };
146
149
 
@@ -154,11 +157,11 @@ export const processFile = (
154
157
  },
155
158
  config: Config,
156
159
  ): FileResult => {
157
- const dir = path.dirname(filePath);
158
160
  const result: FileResult = {
159
161
  path: filePath,
160
162
  operations: [],
161
163
  exports: {},
164
+ exportAlls: [],
162
165
  locals: {},
163
166
  errors: [],
164
167
  };
@@ -178,17 +181,20 @@ export const processFile = (
178
181
 
179
182
  ast.program.body.forEach((toplevel) => {
180
183
  if (toplevel.type === "ImportDeclaration") {
181
- const newLocals = getLocals(dir, toplevel, filePath, config);
184
+ const newLocals = getLocals(toplevel, filePath);
182
185
  if (newLocals) {
183
186
  Object.keys(newLocals).forEach((k) => {
184
187
  const local = newLocals[k];
185
- if (local.path.startsWith("/")) {
188
+ const isGraphqlTagImport =
189
+ local.rawPath === "graphql-tag" ||
190
+ (local.resolvedPath?.includes(
191
+ `${path.sep}node_modules${path.sep}graphql-tag`,
192
+ ) ??
193
+ false);
194
+ if (path.isAbsolute(local.path)) {
186
195
  result.locals[k] = local;
187
196
  }
188
- if (
189
- local.path === "graphql-tag" &&
190
- local.name === "default"
191
- ) {
197
+ if (isGraphqlTagImport && local.name === "default") {
192
198
  gqlTagNames.push(k);
193
199
  }
194
200
  });
@@ -197,9 +203,8 @@ export const processFile = (
197
203
  if (toplevel.type === "ExportNamedDeclaration") {
198
204
  if (toplevel.source) {
199
205
  const source = toplevel.source;
200
- const importPath = source.value.startsWith(".")
201
- ? path.resolve(path.join(dir, source.value))
202
- : source.value;
206
+ const resolvedPath = resolveImportPath(filePath, source.value);
207
+ const importPath = resolvedPath ?? source.value;
203
208
  toplevel.specifiers?.forEach((spec) => {
204
209
  if (
205
210
  spec.type === "ExportSpecifier" &&
@@ -229,6 +234,23 @@ export const processFile = (
229
234
  });
230
235
  }
231
236
  }
237
+ if (toplevel.type === "ExportAllDeclaration" && toplevel.source) {
238
+ const source = toplevel.source;
239
+ const importPath = source.value.startsWith(".")
240
+ ? path.resolve(path.join(path.dirname(filePath), source.value))
241
+ : source.value;
242
+ result.exportAlls.push({
243
+ type: "import",
244
+ name: "*",
245
+ path: importPath,
246
+ loc: {
247
+ start: toplevel.start ?? -1,
248
+ end: toplevel.end ?? -1,
249
+ line: toplevel.loc?.start.line ?? -1,
250
+ path: filePath,
251
+ },
252
+ });
253
+ }
232
254
 
233
255
  const processDeclarator = (
234
256
  decl: VariableDeclarator,
@@ -308,8 +330,9 @@ export const processFile = (
308
330
  };
309
331
 
310
332
  traverse(ast as any, {
311
- TaggedTemplateExpression(path) {
312
- visitTpl(path.node as any, (name) => {
333
+ TaggedTemplateExpression(path: NodePath) {
334
+ const node = path.node as TaggedTemplateExpression;
335
+ visitTpl(node, (name) => {
313
336
  const binding = path.scope.getBinding(name);
314
337
  if (!binding) {
315
338
  return null;
@@ -384,10 +407,8 @@ const processTemplate = (
384
407
  };
385
408
 
386
409
  const getLocals = (
387
- dir: string,
388
410
  toplevel: ImportDeclaration,
389
411
  myPath: string,
390
- config: Config,
391
412
  ):
392
413
  | {
393
414
  [key: string]: Import;
@@ -397,10 +418,8 @@ const getLocals = (
397
418
  if (toplevel.importKind === "type") {
398
419
  return null;
399
420
  }
400
- const fixedPath = fixPathResolution(toplevel.source.value, config);
401
- const importPath = fixedPath.startsWith(".")
402
- ? path.resolve(path.join(dir, fixedPath))
403
- : fixedPath;
421
+ const resolvedPath = resolveImportPath(myPath, toplevel.source.value);
422
+ const importPath = resolvedPath ?? toplevel.source.value;
404
423
  const locals: Record<string, any> = {};
405
424
  toplevel.specifiers.forEach((spec) => {
406
425
  if (spec.type === "ImportDefaultSpecifier") {
@@ -408,6 +427,8 @@ const getLocals = (
408
427
  type: "import",
409
428
  name: "default",
410
429
  path: importPath,
430
+ rawPath: toplevel.source.value,
431
+ resolvedPath,
411
432
  loc: {start: spec.start, end: spec.end, path: myPath},
412
433
  };
413
434
  } else if (spec.type === "ImportSpecifier") {
@@ -418,6 +439,8 @@ const getLocals = (
418
439
  ? spec.imported.name
419
440
  : spec.imported.value,
420
441
  path: importPath,
442
+ rawPath: toplevel.source.value,
443
+ resolvedPath,
421
444
  loc: {start: spec.start, end: spec.end, path: myPath},
422
445
  };
423
446
  }
@@ -449,7 +472,7 @@ export const processFiles = (
449
472
  }
450
473
  const result = processFile(next, source, config);
451
474
  files[next] = result;
452
- listExternalReferences(result, config).forEach((path) => {
475
+ listExternalReferences(result).forEach((path) => {
453
476
  if (!files[path] && !toProcess.includes(path)) {
454
477
  toProcess.push(path);
455
478
  }
@@ -51,7 +51,7 @@ const resolveImport = (
51
51
  },
52
52
  config: Config,
53
53
  ): Document | null | undefined => {
54
- const absPath = getPathWithExtension(expr.path, config);
54
+ const absPath = getPathWithExtension(expr.path);
55
55
  if (!absPath) {
56
56
  return null;
57
57
  }
@@ -71,6 +71,23 @@ const resolveImport = (
71
71
  return null;
72
72
  }
73
73
  if (!res.exports[expr.name]) {
74
+ if (expr.name !== "*" && res.exportAlls.length) {
75
+ for (const exportAll of res.exportAlls) {
76
+ const value = resolveImport(
77
+ {
78
+ ...exportAll,
79
+ name: expr.name,
80
+ },
81
+ files,
82
+ errors,
83
+ {...seen},
84
+ config,
85
+ );
86
+ if (value) {
87
+ return value;
88
+ }
89
+ }
90
+ }
74
91
  errors.push({
75
92
  loc: expr.loc,
76
93
  message: `${absPath} has no valid gql export ${expr.name}`,
@@ -0,0 +1,65 @@
1
+ // Copied from https://github.com/Khan/frontend/blob/main/libs/node/resolve-import/src/resolve-import.ts
2
+ // In future it would be cool to publish @khan/node-resolve-import as a public library so we
3
+ // could consume it here.
4
+ import path from "node:path";
5
+
6
+ import {ResolverFactory} from "rspack-resolver";
7
+ import {createMatchPath, loadConfig} from "tsconfig-paths";
8
+
9
+ const CONDITION_NAMES = ["import"];
10
+
11
+ const matchPathCache = new Map<
12
+ string,
13
+ (importPath: string) => string | undefined
14
+ >();
15
+
16
+ let esmResolver = getEsmResolver();
17
+
18
+ function getEsmResolver() {
19
+ return new ResolverFactory({
20
+ conditionNames: CONDITION_NAMES,
21
+ mainFields: ["module", "main"],
22
+ extensions: [".mjs", ".js", ".jsx", ".ts", ".tsx"],
23
+ });
24
+ }
25
+
26
+ export function resetImportCache() {
27
+ matchPathCache.clear();
28
+ esmResolver = getEsmResolver();
29
+ }
30
+
31
+ /**
32
+ * Resolves an import path using tsconfig and the rspack resolver.
33
+ *
34
+ * @param sourceFile - The file that is importing the path.
35
+ * @param importPath - The path to resolve.
36
+ * @returns The fully resolved path.
37
+ */
38
+ export function resolveImportPath(sourceFile: string, importPath: string) {
39
+ const dir = path.dirname(sourceFile);
40
+ let matchPath = matchPathCache.get(dir);
41
+
42
+ if (!matchPath) {
43
+ const foundConfig = loadConfig(dir);
44
+
45
+ if (foundConfig.resultType !== "success") {
46
+ throw new Error("Failed to load tsconfig");
47
+ }
48
+
49
+ matchPath = createMatchPath(
50
+ foundConfig.absoluteBaseUrl,
51
+ foundConfig.paths,
52
+ CONDITION_NAMES,
53
+ );
54
+ matchPathCache.set(dir, matchPath);
55
+ }
56
+
57
+ // See if we can resolve the import path using the tsconfig.
58
+ const resolvedPath = matchPath(importPath);
59
+
60
+ // Get the directory of the source file to resolve against.
61
+ const sourceFileDir = path.dirname(sourceFile);
62
+
63
+ // Get the fully resolved path.
64
+ return esmResolver.sync(sourceFileDir, resolvedPath ?? importPath).path;
65
+ }
@@ -1,20 +1,6 @@
1
1
  import fs from "fs";
2
- import {Config} from "../types";
3
2
 
4
- export const fixPathResolution = (path: string, config: Config) => {
5
- if (config.alias) {
6
- for (const {find, replacement} of config.alias) {
7
- path = path.replace(find, replacement);
8
- }
9
- }
10
- return path;
11
- };
12
-
13
- export const getPathWithExtension = (
14
- pathWithoutExtension: string,
15
- config: Config,
16
- ) => {
17
- pathWithoutExtension = fixPathResolution(pathWithoutExtension, config);
3
+ export const getPathWithExtension = (pathWithoutExtension: string) => {
18
4
  if (
19
5
  /\.(less|css|png|gif|jpg|jpeg|js|jsx|ts|tsx|mjs)$/.test(
20
6
  pathWithoutExtension,
package/src/types.ts CHANGED
@@ -50,10 +50,6 @@ export type CrawlConfig = {
50
50
  export type Config = {
51
51
  crawl: CrawlConfig;
52
52
  generate: GenerateConfig | Array<GenerateConfig>;
53
- alias?: Array<{
54
- find: RegExp | string;
55
- replacement: string;
56
- }>;
57
53
  };
58
54
 
59
55
  export type Schema = {