eslint-config-typed 6.0.0 → 7.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.
@@ -5,7 +5,13 @@ import * as ts from 'typescript';
5
5
  *
6
6
  * `readCompilerOptions` は tsconfig の compilerOptions を返す関数で、既定では
7
7
  * カレントディレクトリの tsconfig.json を読む。テストが `typescript` を
8
- * モジュールごと差し替えずにすむよう引数にしている。
8
+ * モジュールごと差し替えずにすむよう引数にしている。返す `paths` の値は
9
+ * カレントディレクトリからの相対パスとして扱う。
9
10
  */
10
11
  export declare const resolveImportPath: (importPath: string, relativeFilePath: string | undefined, pathIndexMap: ReadonlyRecord<string, number>, readCompilerOptions?: () => ts.CompilerOptions | undefined) => string;
12
+ /**
13
+ * Reads the tsconfig.json found from `cwd` upward, with `paths` rewritten as
14
+ * relative to `cwd`.
15
+ */
16
+ export declare const readTsConfig: (cwd: string) => ts.CompilerOptions | undefined;
11
17
  //# sourceMappingURL=resolve-import-path.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-import-path.d.mts","sourceRoot":"","sources":["../../../../src/plugins/strict-dependencies/rules/resolve-import-path.mts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAIjC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,eAChB,MAAM,oBACA,MAAM,GAAG,SAAS,gBACtB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,wBACvB,MAAM,EAAE,CAAC,eAAe,GAAG,SAAS,KAExD,MA4DF,CAAC"}
1
+ {"version":3,"file":"resolve-import-path.d.mts","sourceRoot":"","sources":["../../../../src/plugins/strict-dependencies/rules/resolve-import-path.mts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAIjC;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,eAChB,MAAM,oBACA,MAAM,GAAG,SAAS,gBACtB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,wBACvB,MAAM,EAAE,CAAC,eAAe,GAAG,SAAS,KAExD,MAmDF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,EAAE,CAAC,eAAe,GAAG,SAoD/D,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import * as path from 'node:path';
2
- import { Arr, isNonEmptyString, mapNullable } from 'ts-data-forge';
2
+ import { Arr, isNonEmptyString, isString, mapNullable, Obj, } from 'ts-data-forge';
3
3
  import * as ts from 'typescript';
4
4
 
5
5
 
@@ -9,6 +9,7 @@ import * as ts from 'typescript';
9
9
 
10
10
 
11
11
 
12
+
12
13
  export const resolveImportPath = (importPath, relativeFilePath, pathIndexMap, readCompilerOptions = () => readTsConfig(process.cwd())) => {
13
14
 
14
15
  const mut_importAliasMap = {};
@@ -25,14 +26,8 @@ export const resolveImportPath = (importPath, relativeFilePath, pathIndexMap, re
25
26
  if (!Arr.isNonEmpty(value)) {
26
27
  continue;
27
28
  }
28
- const pathValue = mapNullable(pathIndex, (i) => value[i]) ?? value[0];
29
-
30
-
31
-
32
-
33
- const { baseUrl } = tsconfigOptions;
34
29
  mut_importAliasMap[key] =
35
- baseUrl !== undefined ? path.join(baseUrl, pathValue) : pathValue;
30
+ mapNullable(pathIndex, (i) => value[i]) ?? value[0];
36
31
  }
37
32
  }
38
33
  }
@@ -48,14 +43,12 @@ export const resolveImportPath = (importPath, relativeFilePath, pathIndexMap, re
48
43
  (resolvedImportPath, key) => resolvedImportPath.replace(key.replace('*', ''), mut_importAliasMap[key]?.replace('*', '') ?? ''), mut_importPath);
49
44
  return path.normalize(absolutePath);
50
45
  };
51
- const readTsConfig = (tsconfigPath) => {
52
-
53
- const basePath = ts.sys.directoryExists(tsconfigPath)
54
- ? tsconfigPath
55
- : path.dirname(tsconfigPath);
56
- const found = ts.findConfigFile(basePath, (filePath) => ts.sys.fileExists(filePath), ts.sys.directoryExists(tsconfigPath)
57
- ? 'tsconfig.json'
58
- : path.basename(tsconfigPath));
46
+
47
+
48
+
49
+
50
+ export const readTsConfig = (cwd) => {
51
+ const found = ts.findConfigFile(cwd, (filePath) => ts.sys.fileExists(filePath), 'tsconfig.json');
59
52
  if (found === undefined) {
60
53
 
61
54
  return undefined;
@@ -77,6 +70,24 @@ const readTsConfig = (tsconfigPath) => {
77
70
  });
78
71
 
79
72
 
80
- return result?.options;
73
+ if (result?.options.paths === undefined) {
74
+ return result?.options;
75
+ }
76
+
77
+
78
+
79
+ const pathsBasePath = result.options['pathsBasePath'];
80
+ const baseDir = isString(pathsBasePath) ? pathsBasePath : path.dirname(found);
81
+ return {
82
+ ...result.options,
83
+ paths: Obj.map(result.options.paths, (values) => values.map((value) => relativeTo(cwd, baseDir, value))),
84
+ };
85
+ };
86
+
87
+ const relativeTo = (cwd, baseDir, value) => {
88
+ const relative = path.relative(cwd, path.resolve(baseDir, value));
89
+ const nonEmpty = relative === '' ? '.' : relative;
90
+
91
+ return value.endsWith('/') ? `${nonEmpty}/` : nonEmpty;
81
92
  };
82
93
  //# sourceMappingURL=resolve-import-path.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-import-path.mjs","sourceRoot":"","sources":["../../../../src/plugins/strict-dependencies/rules/resolve-import-path.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve-import-path.mjs","sourceRoot":"","sources":["../../../../src/plugins/strict-dependencies/rules/resolve-import-path.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,GAAG,EACH,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,GAAG,GACJ,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,wIAAwI;AAExI;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,UAAkB,EAClB,gBAAoC,EACpC,YAA4C,EAC5C,mBAAmB,GAAyC,GAAG,EAAE,CAC/D,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EACrB,EAAE;IACV,mCAAmC;IACnC,MAAM,kBAAkB,GAAkC,EAAE,CAAC;IAE7D,IAAI,cAAc,GAAG,UAAU,CAAC;IAEhC,uBAAuB;IACvB,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,mBAAmB,EAAE,CAAC;QAE9C,yBAAyB;QACzB,IAAI,eAAe,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;YACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjE,MAAM,UAAU,GAAuB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CACnE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CACjB,CAAC;gBAEF,oEAAoE;gBACpE,MAAM,SAAS,GACb,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE1D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3B,SAAS;gBACX,CAAC;gBAED,kBAAkB,CAAC,GAAG,CAAC;oBACrB,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,aAAa;IACf,CAAC;IAED,IACE,gBAAgB,CAAC,gBAAgB,CAAC;QAClC,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EACrE,CAAC;QACD,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,cAAc,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM;IACzD,iDAAiD;IACjD,CAAC,kBAAkB,EAAE,GAAG,EAAE,EAAE,CAC1B,kBAAkB,CAAC,OAAO,CACxB,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,EACpB,kBAAkB,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,EAAE,CAChD,EACH,cAAc,CACf,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;AACtC,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAkC,EAAE;IAC1E,MAAM,KAAK,GAAG,EAAE,CAAC,cAAc,CAC7B,GAAG,EACH,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EACzC,eAAe,CAChB,CAAC;IAEF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,mCAAmC;QACnC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,yBAAyB;IACzB,MAAM,MAAM,GAAG,EAAE,CAAC,gCAAgC,CAChD,KAAK;IACL,mBAAmB,CAAC,EAAE,EACtB;QACE,GAAG,EAAE,CAAC,GAAG;QACT,mCAAmC,EAAE,CAAC,CAAC,EAAE,EAAE;YACzC,cAAc;YACd,MAAM,GAAG,GAAG,EAAE,CAAC,4BAA4B,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YAEjE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC;QACD,mBAAmB,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,mBAAmB,EAAE;QACvD,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAChE,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;QACtE,UAAU,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;QACrD,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACjD,yBAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,yBAAyB;KAC5D,CACF,CAAC;IAEF,yCAAyC;IACzC,yCAAyC;IACzC,IAAI,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACxC,OAAO,MAAM,EAAE,OAAO,CAAC;IACzB,CAAC;IAED,wEAAwE;IACxE,mEAAmE;IACnE,yEAAyE;IACzE,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE9E,OAAO;QACL,GAAG,MAAM,CAAC,OAAO;QACjB,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CACvD;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,OAAe,EAAE,KAAa,EAAU,EAAE;IACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IAElE,MAAM,QAAQ,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IAElD,4EAA4E;IAC5E,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AACzD,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-typed",
3
- "version": "6.0.0",
3
+ "version": "7.0.0",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript"
@@ -90,7 +90,7 @@
90
90
  "@vitest/ui": "5.0.5",
91
91
  "cspell": "10.4.0",
92
92
  "dedent": "1.7.2",
93
- "eslint-config-typed": "6.0.0",
93
+ "eslint-config-typed": "7.0.0",
94
94
  "eslint-plugin-ts-data-forge": "0.10.4",
95
95
  "eslint-plugin-ts-fortress": "1.3.9",
96
96
  "eslint-plugin-ts-type-forge": "0.8.14",
@@ -1,5 +1,11 @@
1
1
  import * as path from 'node:path';
2
- import { Arr, isNonEmptyString, mapNullable } from 'ts-data-forge';
2
+ import {
3
+ Arr,
4
+ isNonEmptyString,
5
+ isString,
6
+ mapNullable,
7
+ Obj,
8
+ } from 'ts-data-forge';
3
9
  import type { MutableRecord, ReadonlyRecord } from 'ts-type-forge';
4
10
  import * as ts from 'typescript';
5
11
 
@@ -10,7 +16,8 @@ import * as ts from 'typescript';
10
16
  *
11
17
  * `readCompilerOptions` は tsconfig の compilerOptions を返す関数で、既定では
12
18
  * カレントディレクトリの tsconfig.json を読む。テストが `typescript` を
13
- * モジュールごと差し替えずにすむよう引数にしている。
19
+ * モジュールごと差し替えずにすむよう引数にしている。返す `paths` の値は
20
+ * カレントディレクトリからの相対パスとして扱う。
14
21
  */
15
22
  export const resolveImportPath = (
16
23
  importPath: string,
@@ -43,17 +50,8 @@ export const resolveImportPath = (
43
50
  continue;
44
51
  }
45
52
 
46
- const pathValue: string =
47
- mapNullable(pathIndex, (i) => value[i]) ?? value[0];
48
-
49
- // `baseUrl` is deprecated in TypeScript 6.0, but this rule still
50
- // needs to read it (if present) to resolve legacy `baseUrl`-relative
51
- // `paths` entries the same way `tsc` does.
52
- // eslint-disable-next-line @typescript-eslint/no-deprecated
53
- const { baseUrl } = tsconfigOptions;
54
-
55
53
  mut_importAliasMap[key] =
56
- baseUrl !== undefined ? path.join(baseUrl, pathValue) : pathValue;
54
+ mapNullable(pathIndex, (i) => value[i]) ?? value[0];
57
55
  }
58
56
  }
59
57
  } catch {
@@ -80,22 +78,19 @@ export const resolveImportPath = (
80
78
  return path.normalize(absolutePath);
81
79
  };
82
80
 
83
- const readTsConfig = (tsconfigPath: string): ts.CompilerOptions | undefined => {
84
- // プロジェクトルート探索: tsconfigPath がディレクトリならその中を探す
85
- const basePath = ts.sys.directoryExists(tsconfigPath)
86
- ? tsconfigPath
87
- : path.dirname(tsconfigPath);
88
-
81
+ /**
82
+ * Reads the tsconfig.json found from `cwd` upward, with `paths` rewritten as
83
+ * relative to `cwd`.
84
+ */
85
+ export const readTsConfig = (cwd: string): ts.CompilerOptions | undefined => {
89
86
  const found = ts.findConfigFile(
90
- basePath,
87
+ cwd,
91
88
  (filePath) => ts.sys.fileExists(filePath),
92
- ts.sys.directoryExists(tsconfigPath)
93
- ? 'tsconfig.json'
94
- : path.basename(tsconfigPath),
89
+ 'tsconfig.json',
95
90
  );
96
91
 
97
92
  if (found === undefined) {
98
- // tsconfig not found under: ${tsconfigPath}
93
+ // tsconfig not found under: ${cwd}
99
94
  return undefined;
100
95
  }
101
96
 
@@ -122,5 +117,31 @@ const readTsConfig = (tsconfigPath: string): ts.CompilerOptions | undefined => {
122
117
 
123
118
  // undefined: 'Failed to parse tsconfig.'
124
119
  // result.options: 正規化済みの compilerOptions
125
- return result?.options;
120
+ if (result?.options.paths === undefined) {
121
+ return result?.options;
122
+ }
123
+
124
+ // `baseUrl` is not read: `paths` are relative to the tsconfig.json that
125
+ // declares them, as `tsc` resolves them without `baseUrl`. That is
126
+ // `pathsBasePath` (internal to TypeScript) when it is an `extends` base.
127
+ const pathsBasePath = result.options['pathsBasePath'];
128
+
129
+ const baseDir = isString(pathsBasePath) ? pathsBasePath : path.dirname(found);
130
+
131
+ return {
132
+ ...result.options,
133
+ paths: Obj.map(result.options.paths, (values) =>
134
+ values.map((value) => relativeTo(cwd, baseDir, value)),
135
+ ),
136
+ };
137
+ };
138
+
139
+ /** Rewrites `value`, relative to `baseDir`, as relative to `cwd`. */
140
+ const relativeTo = (cwd: string, baseDir: string, value: string): string => {
141
+ const relative = path.relative(cwd, path.resolve(baseDir, value));
142
+
143
+ const nonEmpty = relative === '' ? '.' : relative;
144
+
145
+ // `path.resolve` drops a trailing slash, which an alias with one relies on.
146
+ return value.endsWith('/') ? `${nonEmpty}/` : nonEmpty;
126
147
  };
@@ -1,12 +1,13 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
1
4
  import type { ReadonlyRecord } from 'ts-type-forge';
2
5
  import type * as ts from 'typescript';
3
- import { resolveImportPath } from './resolve-import-path.mjs';
6
+ import { readTsConfig, resolveImportPath } from './resolve-import-path.mjs';
4
7
 
5
8
  // FIXME: https://github.com/knowledge-work/eslint-plugin-strict-dependencies/tree/v1.3.27 のテストをコピーしてきて
6
9
  // Codex でテスト・型チェックが通るようにさせただけなので、意味の無いテストになっていないかチェックして修正する
7
10
 
8
- // `baseUrl` is deprecated in TypeScript 6.0, but the rule still resolves legacy
9
- // `baseUrl`-relative `paths`, so the fixtures below have to set it.
10
11
  const compilerOptionsByFixture = {
11
12
  'no-paths': {},
12
13
  'paths-basic': {
@@ -16,55 +17,14 @@ const compilerOptionsByFixture = {
16
17
  '@/components/*': ['components/*'],
17
18
  },
18
19
  },
19
- 'base-url-dot': {
20
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
21
- baseUrl: '.',
22
- paths: {
23
- '@/components/': ['components/'],
24
- },
25
- },
26
- 'base-url-dot-slash': {
27
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
28
- baseUrl: './',
29
- paths: {
30
- '@/components/': ['components/'],
31
- },
32
- },
33
- 'base-url-parent': {
34
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
35
- baseUrl: '../',
36
- paths: {
37
- '@/components/': ['components/'],
38
- },
39
- },
20
+ // `paths` are resolved from the tsconfig.json whatever `baseUrl` says.
40
21
  'base-url-src': {
41
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
22
+ // eslint-disable-next-line @typescript-eslint/no-deprecated -- the fixture is about the deprecated option
42
23
  baseUrl: 'src',
43
24
  paths: {
44
25
  '@/components/': ['components/'],
45
26
  },
46
27
  },
47
- 'base-url-dot-src': {
48
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
49
- baseUrl: './src',
50
- paths: {
51
- '@/components/': ['components/'],
52
- },
53
- },
54
- 'base-url-src-slash': {
55
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
56
- baseUrl: 'src/',
57
- paths: {
58
- '@/components/': ['components/'],
59
- },
60
- },
61
- 'base-url-dot-src-slash': {
62
- // eslint-disable-next-line @typescript-eslint/no-deprecated -- see the note above the table
63
- baseUrl: './src/',
64
- paths: {
65
- '@/components/': ['components/'],
66
- },
67
- },
68
28
  'paths-multiple': {
69
29
  paths: {
70
30
  '@/components/*': ['src/components/*', 'src/alternativeComponents/*'],
@@ -103,40 +63,6 @@ const aliasCases = [
103
63
  },
104
64
  ] as const;
105
65
 
106
- const baseUrlCases = [
107
- {
108
- fixtureName: 'base-url-dot',
109
- expected: 'components/aaa/bbb',
110
- },
111
- {
112
- fixtureName: 'base-url-dot-slash',
113
- expected: 'components/aaa/bbb',
114
- },
115
- {
116
- fixtureName: 'base-url-parent',
117
- expected: '../components/aaa/bbb',
118
- },
119
- {
120
- fixtureName: 'base-url-src',
121
- expected: 'src/components/aaa/bbb',
122
- },
123
- {
124
- fixtureName: 'base-url-dot-src',
125
- expected: 'src/components/aaa/bbb',
126
- },
127
- {
128
- fixtureName: 'base-url-src-slash',
129
- expected: 'src/components/aaa/bbb',
130
- },
131
- {
132
- fixtureName: 'base-url-dot-src-slash',
133
- expected: 'src/components/aaa/bbb',
134
- },
135
- ] as const satisfies readonly Readonly<{
136
- fixtureName: FixtureName;
137
- expected: string;
138
- }>[];
139
-
140
66
  describe(resolveImportPath, () => {
141
67
  test('should resolve relative path', () => {
142
68
  expect(
@@ -192,30 +118,16 @@ describe(resolveImportPath, () => {
192
118
  },
193
119
  );
194
120
 
195
- test.each(baseUrlCases)(
196
- 'baseUrl $fixtureName',
197
- ({ fixtureName, expected }: Readonly<(typeof baseUrlCases)[number]>) => {
198
- const readCompilerOptions = readFixture(fixtureName);
199
-
200
- expect(
201
- resolveImportPath(
202
- 'components/aaa/bbb',
203
- undefined,
204
- {},
205
- readCompilerOptions,
206
- ),
207
- ).toBe('components/aaa/bbb');
208
-
209
- expect(
210
- resolveImportPath(
211
- '@/components/aaa/bbb',
212
- undefined,
213
- {},
214
- readCompilerOptions,
215
- ),
216
- ).toBe(expected);
217
- },
218
- );
121
+ test('should ignore baseUrl', () => {
122
+ expect(
123
+ resolveImportPath(
124
+ '@/components/aaa/bbb',
125
+ undefined,
126
+ {},
127
+ readFixture('base-url-src'),
128
+ ),
129
+ ).toBe('components/aaa/bbb');
130
+ });
219
131
 
220
132
  test('should resolve path alias with specified index in pathIndexMap', () => {
221
133
  expect(
@@ -250,3 +162,120 @@ describe(resolveImportPath, () => {
250
162
  ).toBe('src/components/aaa/bbb');
251
163
  });
252
164
  });
165
+
166
+ describe(readTsConfig, () => {
167
+ test('should resolve paths from the directory of tsconfig.json', () => {
168
+ expect(
169
+ resolveWithTsconfig(
170
+ { paths: { '@/*': ['./src/*'] } },
171
+ '.',
172
+ '@/components/aaa',
173
+ ),
174
+ ).toBe('src/components/aaa');
175
+ });
176
+
177
+ test('should keep a trailing slash of a paths entry', () => {
178
+ expect(
179
+ resolveWithTsconfig(
180
+ { paths: { '@/components/': ['src/components/'] } },
181
+ '.',
182
+ '@/components/aaa',
183
+ ),
184
+ ).toBe('src/components/aaa');
185
+ });
186
+
187
+ test('should resolve a paths entry naming the directory of tsconfig.json', () => {
188
+ expect(
189
+ resolveWithTsconfig({ paths: { '@/': ['./'] } }, '.', '@/components/aaa'),
190
+ ).toBe('components/aaa');
191
+ });
192
+
193
+ test('should resolve paths from a tsconfig.json found above the working directory', () => {
194
+ expect(
195
+ resolveWithTsconfig(
196
+ { paths: { '@/*': ['./src/*'] } },
197
+ 'packages/a',
198
+ '@/components/aaa',
199
+ ),
200
+ ).toBe('../../src/components/aaa');
201
+ });
202
+
203
+ test('should resolve paths from the directory of the tsconfig.json declaring them', () => {
204
+ expect(
205
+ resolveWithFiles(
206
+ {
207
+ 'configs/tsconfig.base.json': {
208
+ compilerOptions: { paths: { '@/*': ['../src/*'] } },
209
+ },
210
+ 'tsconfig.json': {
211
+ extends: './configs/tsconfig.base.json',
212
+ files: [],
213
+ },
214
+ },
215
+ '.',
216
+ '@/components/aaa',
217
+ ),
218
+ ).toBe('src/components/aaa');
219
+ });
220
+
221
+ test('should ignore baseUrl', () => {
222
+ expect(
223
+ resolveWithTsconfig(
224
+ {
225
+ baseUrl: 'src',
226
+ ignoreDeprecations: '6.0',
227
+ paths: { '@/*': ['./lib/*'] },
228
+ },
229
+ '.',
230
+ '@/components/aaa',
231
+ ),
232
+ ).toBe('lib/components/aaa');
233
+ });
234
+ });
235
+
236
+ /**
237
+ * Writes `files` (JSON, by path) into a new directory, runs
238
+ * `resolveImportPath` with `readTsConfig` from `cwdSubdirectory` of it, and
239
+ * removes the directory.
240
+ */
241
+ const resolveWithFiles = (
242
+ files: ReadonlyRecord<string, unknown>,
243
+ cwdSubdirectory: string,
244
+ importPath: string,
245
+ ): string => {
246
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'resolve-import-path-'));
247
+
248
+ try {
249
+ for (const [filePath, content] of Object.entries(files)) {
250
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
251
+ fs.mkdirSync(path.dirname(path.join(root, filePath)), {
252
+ recursive: true,
253
+ });
254
+
255
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
256
+ fs.writeFileSync(path.join(root, filePath), JSON.stringify(content));
257
+ }
258
+
259
+ const cwd = path.join(root, cwdSubdirectory);
260
+
261
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
262
+ fs.mkdirSync(cwd, { recursive: true });
263
+
264
+ return resolveImportPath(importPath, undefined, {}, () =>
265
+ readTsConfig(cwd),
266
+ );
267
+ } finally {
268
+ fs.rmSync(root, { recursive: true, force: true });
269
+ }
270
+ };
271
+
272
+ const resolveWithTsconfig = (
273
+ compilerOptions: ReadonlyRecord<string, unknown>,
274
+ cwdSubdirectory: string,
275
+ importPath: string,
276
+ ): string =>
277
+ resolveWithFiles(
278
+ { 'tsconfig.json': { compilerOptions, files: [] } },
279
+ cwdSubdirectory,
280
+ importPath,
281
+ );