@the-stranger/eslint-plugin 2.0.2 → 2.1.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.
Files changed (79) hide show
  1. package/README.md +41 -29
  2. package/package.json +26 -72
  3. package/src/index.d.ts +1 -2
  4. package/src/index.js +1 -1
  5. package/src/lib/configs.d.ts +19 -0
  6. package/src/lib/configs.js +65 -0
  7. package/src/lib/disable-type-checked.d.ts +4 -0
  8. package/src/lib/disable-type-checked.js +8 -0
  9. package/src/lib/meta.d.ts +0 -1
  10. package/src/lib/namer.d.ts +3 -1
  11. package/src/lib/namer.js +2 -0
  12. package/src/lib/utils/get-module-root.d.ts +11 -0
  13. package/src/lib/utils/get-module-root.js +31 -0
  14. package/src/lib/utils/optional-import-resolver.d.ts +76 -0
  15. package/src/lib/utils/optional-import-resolver.js +168 -0
  16. package/src/lib/utils/optional-import.d.ts +47 -0
  17. package/src/lib/utils/optional-import.js +142 -0
  18. package/src/lib/utils/options.d.ts +3 -0
  19. package/src/lib/utils/options.js +24 -0
  20. package/src/utils.d.ts +2 -4
  21. package/src/utils.js +2 -3
  22. package/src/index.d.ts.map +0 -1
  23. package/src/lib/configs/index.d.ts +0 -17
  24. package/src/lib/configs/index.d.ts.map +0 -1
  25. package/src/lib/configs/index.js +0 -26
  26. package/src/lib/configs/jest.d.ts +0 -4
  27. package/src/lib/configs/jest.d.ts.map +0 -1
  28. package/src/lib/configs/jest.js +0 -27
  29. package/src/lib/configs/jsdoc.d.ts +0 -5
  30. package/src/lib/configs/jsdoc.d.ts.map +0 -1
  31. package/src/lib/configs/jsdoc.js +0 -44
  32. package/src/lib/configs/jsonc.d.ts +0 -4
  33. package/src/lib/configs/jsonc.d.ts.map +0 -1
  34. package/src/lib/configs/jsonc.js +0 -128
  35. package/src/lib/configs/n.d.ts +0 -4
  36. package/src/lib/configs/n.d.ts.map +0 -1
  37. package/src/lib/configs/n.js +0 -24
  38. package/src/lib/configs/nx.d.ts +0 -6
  39. package/src/lib/configs/nx.d.ts.map +0 -1
  40. package/src/lib/configs/nx.js +0 -45
  41. package/src/lib/configs/perfectionist.d.ts +0 -4
  42. package/src/lib/configs/perfectionist.d.ts.map +0 -1
  43. package/src/lib/configs/perfectionist.js +0 -129
  44. package/src/lib/configs/promise.d.ts +0 -4
  45. package/src/lib/configs/promise.d.ts.map +0 -1
  46. package/src/lib/configs/promise.js +0 -16
  47. package/src/lib/configs/regexp.d.ts +0 -4
  48. package/src/lib/configs/regexp.d.ts.map +0 -1
  49. package/src/lib/configs/regexp.js +0 -5
  50. package/src/lib/configs/toml.d.ts +0 -4
  51. package/src/lib/configs/toml.d.ts.map +0 -1
  52. package/src/lib/configs/toml.js +0 -35
  53. package/src/lib/configs/typescript-eslint.d.ts +0 -4
  54. package/src/lib/configs/typescript-eslint.d.ts.map +0 -1
  55. package/src/lib/configs/typescript-eslint.js +0 -26
  56. package/src/lib/configs/unicorn.d.ts +0 -4
  57. package/src/lib/configs/unicorn.d.ts.map +0 -1
  58. package/src/lib/configs/unicorn.js +0 -66
  59. package/src/lib/configs/vitest.d.ts +0 -4
  60. package/src/lib/configs/vitest.d.ts.map +0 -1
  61. package/src/lib/configs/vitest.js +0 -15
  62. package/src/lib/configs/yml.d.ts +0 -4
  63. package/src/lib/configs/yml.d.ts.map +0 -1
  64. package/src/lib/configs/yml.js +0 -127
  65. package/src/lib/extend-config.d.ts +0 -3
  66. package/src/lib/extend-config.d.ts.map +0 -1
  67. package/src/lib/extend-config.js +0 -22
  68. package/src/lib/meta.d.ts.map +0 -1
  69. package/src/lib/namer.d.ts.map +0 -1
  70. package/src/lib/patterns.d.ts +0 -82
  71. package/src/lib/patterns.d.ts.map +0 -1
  72. package/src/lib/patterns.js +0 -147
  73. package/src/lib/rule-levels.d.ts +0 -43
  74. package/src/lib/rule-levels.d.ts.map +0 -1
  75. package/src/lib/rule-levels.js +0 -71
  76. package/src/lib/severity.d.ts +0 -13
  77. package/src/lib/severity.d.ts.map +0 -1
  78. package/src/lib/severity.js +0 -34
  79. package/src/utils.d.ts.map +0 -1
package/README.md CHANGED
@@ -10,32 +10,20 @@ Requires Node.js 24+ and ESLint 9+.
10
10
  npm install --save-dev @the-stranger/eslint-plugin
11
11
  ```
12
12
 
13
- ## Optional peer dependencies
14
-
15
- Install only the peers you need for the conditional presets:
16
-
17
- - `eslint-plugin-jest@^29.12.1`
18
- - `@vitest/eslint-plugin@^1.6.6`
19
- - `eslint-plugin-toml@^0.12.0` and `toml-eslint-parser@^0.10.1`
20
- - `@nx/eslint-plugin@21`
21
-
22
13
  ## Usage
23
14
 
24
15
  In your `eslint.config.js`, extend the presets you want:
25
16
 
26
17
  ```javascript
27
18
  import le from '@the-stranger/eslint-plugin'
28
- import leJest from '@the-stranger/eslint-plugin/configs/jest'
29
- import leVitest from '@the-stranger/eslint-plugin/configs/vitest'
30
- import leToml from '@the-stranger/eslint-plugin/configs/toml'
31
19
  import leNx from '@the-stranger/eslint-plugin/configs/nx'
32
- import { objectNamer, setRuleLevel } from '@the-stranger/eslint-plugin/utils'
20
+ import { setRuleLevel } from '@the-stranger/eslint-plugin/utils'
33
21
  import { defineConfig } from 'eslint/config'
34
22
 
35
23
  export default defineConfig({
36
24
  extends: [
37
25
  // all-in-one
38
- le.configs.recommended,
26
+ le.configs.standard,
39
27
 
40
28
  // or pick and choose
41
29
  le.configs.jsdoc,
@@ -47,29 +35,54 @@ export default defineConfig({
47
35
  le.configs.ts,
48
36
  le.configs.unicorn,
49
37
  le.configs.yml,
50
-
51
- // conditional presets when peers are installed
52
- leJest,
53
- leVitest,
54
- leToml,
55
- leNx,
38
+ le.configs.vitest,
56
39
 
57
40
  // customization helpers
58
41
  setRuleLevel('error', le.configs.perfectionist),
59
- objectNamer(le.configs.ts, 'my-eslint-config'),
60
42
  ],
61
43
  })
62
44
  ```
63
45
 
46
+ ## Optional peer dependencies
47
+
48
+ Install [@nx/eslint-plugin] to enable the Nx preset:
49
+
50
+ ```bash
51
+ npm install --save-dev @nx/eslint-plugin@^21
52
+ ```
53
+
54
+ Then, in your ESLint config, extend the Nx preset:
55
+
56
+ ```javascript
57
+ import leNx from '@the-stranger/eslint-plugin/nx'
58
+ import { defineConfig } from 'eslint/config'
59
+
60
+ export default defineConfig({
61
+ extends: [leNx],
62
+ })
63
+ ```
64
+
64
65
  ## Configurations
65
66
 
66
- - **JSDoc**: Recommended config from [eslint-plugin-jsdoc] for both TypeScript and JavaScript files; allows the `@document` tag used by Docusaurus.
67
+ - **All**: Includes every available preset in this package.
68
+ - **Astro**: Uses [eslint-plugin-astro] with strict JSX accessibility checks.
69
+ - **Base**: Minimal baseline config with no additional presets.
70
+ - **Cypress**: Uses [eslint-plugin-cypress] recommended rules for Cypress tests.
71
+ - **Jest**: Uses [eslint-plugin-jest]; aligned with the Vitest config for consistency.
72
+ - **JSDoc**: Recommended config from [eslint-plugin-jsdoc] for both TypeScript and JavaScript files.
67
73
  - **JSONC**: Enables key and array sorting in JSON/JSONC documents using [eslint-plugin-jsonc].
68
74
  - **Node (n)**: Extends the recommended config from [eslint-plugin-n].
69
- - **Perfectionist**: Extends [eslint-plugin-perfectionist]; sorts all the things.
75
+ - **Perfectionist**: Extends [eslint-plugin-perfectionist]; sorts all the things. Rules in this preset are set to "warn" by default.
70
76
  - **Promise**: Recommended rules from [eslint-plugin-promise].
77
+ - **React**: Combines [@eslint-react/eslint-plugin], [eslint-plugin-react-hooks], [eslint-plugin-react-compiler], and [eslint-plugin-jsx-a11y].
78
+ - **React (type-checked)**: Extends the React preset with [eslint-react]'s strict type-checked config.
71
79
  - **Regexp**: Recommended rules from [eslint-plugin-regexp].
80
+ - **Standard**: Curated default preset (Vitest + core linting presets) for most projects.
81
+ - **TOML**: Uses [eslint-plugin-toml] and [toml-eslint-parser] to lint TOML files.
72
82
  - **TypeScript (ts)**: Sets up TypeScript linting via [typescript-eslint], disabling a few noisy rules; falls back when Nx is unavailable.
83
+ - **TypeScript (type-checked)**: Extends the TypeScript preset with rules that require type information.
84
+ - **TypeScript (type-checked strict)**: Extends the TypeScript preset with stricter rules.
85
+ - **Vitest**: Uses [@vitest/eslint-plugin] to keep test files readable.
73
86
  - **Unicorn**: Recommended rules from [eslint-plugin-unicorn] with customizations.
74
87
  - **YAML**: Recommended config from [eslint-plugin-yml], plus key and array sorting via [yaml-eslint-parser].
75
88
 
@@ -77,25 +90,24 @@ export default defineConfig({
77
90
 
78
91
  These presets load only when their peer dependencies are present:
79
92
 
80
- - **Jest**: Uses [eslint-plugin-jest]; aligned with the Vitest rules for consistency.
81
- - **Vitest**: Uses [@vitest/eslint-plugin] to keep test files readable.
82
- - **TOML**: Uses [eslint-plugin-toml] and [toml-eslint-parser] to lint TOML files.
83
93
  - **Nx**: Extends Nx's recommended monorepo config from [@nx/eslint-plugin].
84
94
 
85
95
  ## Utilities
86
96
 
87
97
  - **getFilePatterns**: Generates glob patterns.
88
- - **namer**: Simple helper for naming config blocks.
89
- - **objectNamer**: Wraps a config object and assigns it a friendly name for reports.
90
- - **setRuleLevel**: Sets the severity of some or all rules in a config, handling nested configs.
98
+ - **setRuleLevel**: Sets the severity of some or all rules in a config or an array of configs.
91
99
 
92
100
  <!-- Links -->
93
101
 
94
102
  [@nx/eslint-plugin]: https://nx.dev/docs/technologies/eslint/eslint-plugin/introduction
103
+ [@eslint-react/eslint-plugin]: https://eslint-react.xyz
95
104
  [@vitest/eslint-plugin]: https://github.com/vitest-dev/eslint-plugin-vitest
96
105
  [eslint-plugin-jest]: https://github.com/jest-community/eslint-plugin-jest
97
106
  [eslint-plugin-jsdoc]: https://github.com/gajus/eslint-plugin-jsdoc
98
107
  [eslint-plugin-jsonc]: https://ota-meshi.github.io/eslint-plugin-jsonc
108
+ [eslint-plugin-cypress]: https://github.com/cypress-io/eslint-plugin-cypress
109
+ [eslint-plugin-react-compiler]: https://www.npmjs.com/package/eslint-plugin-react-compiler
110
+ [eslint-plugin-react-hooks]: https://www.npmjs.com/package/eslint-plugin-react-hooks
99
111
  [eslint-plugin-n]: https://github.com/eslint-community/eslint-plugin-n
100
112
  [eslint-plugin-perfectionist]: https://perfectionist.dev
101
113
  [eslint-plugin-promise]: https://github.com/eslint-community/eslint-plugin-promise
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@the-stranger/eslint-plugin",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "repository": {
5
- "url": "git+https://github.com/the-chris-strange/the-stranger.git",
5
+ "type": "git",
6
+ "url": "https://github.com/the-chris-strange/the-stranger.git",
6
7
  "directory": "packages/eslint-plugin"
7
8
  },
8
9
  "type": "module",
9
10
  "exports": {
10
- "./package.json": "./package.json",
11
11
  ".": {
12
12
  "types": "./src/index.d.ts",
13
13
  "import": "./src/index.js"
@@ -16,85 +16,39 @@
16
16
  "types": "./src/utils.d.ts",
17
17
  "import": "./src/utils.js"
18
18
  },
19
- "./configs/jest": {
20
- "types": "./src/lib/configs/jest.d.ts",
21
- "import": "./src/lib/configs/jest.js"
22
- },
23
- "./configs/nx": {
24
- "types": "./src/lib/configs/nx.d.ts",
25
- "import": "./src/lib/configs/nx.js"
26
- },
27
- "./configs/toml": {
28
- "types": "./src/lib/configs/toml.d.ts",
29
- "import": "./src/lib/configs/toml.js"
30
- },
31
- "./configs/vitest": {
32
- "types": "./src/lib/configs/vitest.d.ts",
33
- "import": "./src/lib/configs/vitest.js"
34
- }
19
+ "./package.json": "./package.json"
35
20
  },
21
+ "main": "./src/index.js",
22
+ "module": "./src/index.js",
23
+ "types": "./src/types.d.ts",
36
24
  "dependencies": {
37
- "eslint-plugin-jsdoc": "^50.8.0",
38
- "eslint-plugin-jsonc": "^2.21.0",
39
- "eslint-plugin-n": "^17.23.2",
40
- "eslint-plugin-perfectionist": "^4.15.1",
41
- "eslint-plugin-promise": "^7.2.1",
42
- "eslint-plugin-regexp": "^2.10.0",
43
- "eslint-plugin-unicorn": "^59.0.1",
44
- "eslint-plugin-yml": "^1.19.1",
45
- "jsonc-eslint-parser": "^2.4.2",
46
- "tslib": "^2.8.1",
47
- "typescript-eslint": "^8.53.1",
48
- "yaml-eslint-parser": "^1.3.2"
25
+ "@the-stranger/eslint-config": "^1.0.0",
26
+ "@the-stranger/eslint-utils": "^1.0.0",
27
+ "tslib": "^2.8.1"
49
28
  },
50
29
  "devDependencies": {
51
- "@eslint/js": "^9.39.2",
52
- "@nx/eslint": "21.6.4",
53
- "@nx/eslint-plugin": "21.6.4",
54
- "@nx/vite": "21.6.4",
55
- "@types/node": "^24.10.9",
56
- "@typescript-eslint/parser": "^8.53.1",
57
- "@vitest/coverage-v8": "^3.2.4",
58
- "@vitest/eslint-plugin": "^1.3.16",
59
- "eslint": "^9.39.2",
30
+ "@nx/eslint": "22.5.2",
31
+ "@nx/eslint-plugin": "22.5.2",
32
+ "@nx/vitest": "22.5.2",
33
+ "@types/eslint-plugin-jsx-a11y": "^6.10.1",
34
+ "@types/node": "^24.12.2",
35
+ "@typescript-eslint/parser": "^8.58.2",
36
+ "@vitest/coverage-v8": "4.1.4",
37
+ "eslint": "^9.39.4",
60
38
  "eslint-config-prettier": "^10.1.8",
61
- "eslint-plugin-eslint-plugin": "^7.3.0",
62
- "eslint-plugin-jest": "^29.12.1",
63
- "eslint-plugin-toml": "^0.12.0",
64
- "nx": "21.6.4",
65
- "prettier": "^3.8.0",
66
- "prettier-plugin-packagejson": "^2.5.22",
67
- "toml-eslint-parser": "^0.10.1",
39
+ "eslint-plugin-eslint-plugin": "^7.3.2",
40
+ "nx": "22.5.2",
41
+ "prettier": "^3.8.3",
42
+ "prettier-plugin-packagejson": "^3.0.2",
68
43
  "typescript": "^5.9.3",
69
- "vite": "7.3.1",
70
- "vitest": "^3.2.4"
44
+ "vite": "7.3.2",
45
+ "vitest": "4.1.4"
71
46
  },
72
47
  "peerDependencies": {
73
- "@nx/eslint-plugin": "^21",
74
- "@vitest/eslint-plugin": "^1.6.6",
75
48
  "eslint": "^9",
76
- "eslint-plugin-jest": "^29.12.1",
77
- "eslint-plugin-toml": "^0.12.0",
78
- "toml-eslint-parser": "^0.10.1"
79
- },
80
- "peerDependenciesMeta": {
81
- "@nx/eslint-plugin": {
82
- "optional": true
83
- },
84
- "@vitest/eslint-plugin": {
85
- "optional": true
86
- },
87
- "eslint-plugin-jest": {
88
- "optional": true
89
- },
90
- "eslint-plugin-toml": {
91
- "optional": true
92
- },
93
- "toml-eslint-parser": {
94
- "optional": true
95
- }
49
+ "typescript-eslint": "^8"
96
50
  },
97
51
  "engines": {
98
52
  "node": "^24"
99
53
  }
100
- }
54
+ }
package/src/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export { configs } from './lib/configs/index.js';
1
+ export { configs } from './lib/configs.js';
2
2
  export { meta } from './lib/meta.js';
3
- //# sourceMappingURL=index.d.ts.map
package/src/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { configs } from './lib/configs/index.js';
1
+ export { configs } from './lib/configs.js';
2
2
  export { meta } from './lib/meta.js';
@@ -0,0 +1,19 @@
1
+ export declare const configs: {
2
+ readonly disableTypeChecked: {
3
+ name: string;
4
+ rules: {};
5
+ }[];
6
+ readonly json: import("eslint/config").Config[];
7
+ readonly recommended: import("eslint/config").Config[];
8
+ readonly 'recommended/astro': import("eslint/config").Config[];
9
+ readonly 'recommended/no-type-checked': import("eslint/config").Config[];
10
+ readonly 'recommended/react': import("eslint/config").Config[];
11
+ readonly 'recommended/strict': import("eslint/config").Config[];
12
+ readonly standard: import("eslint/config").Config[];
13
+ readonly 'standard/no-type-checked': import("eslint/config").Config[];
14
+ readonly 'standard/strict': import("eslint/config").Config[];
15
+ readonly 'tests/jest': import("eslint/config").Config[];
16
+ readonly 'tests/vitest': import("eslint/config").Config[];
17
+ readonly toml: import("eslint/config").Config[];
18
+ readonly yaml: import("eslint/config").Config[];
19
+ };
@@ -0,0 +1,65 @@
1
+ import { configure } from '@the-stranger/eslint-config';
2
+ import { disableTypeCheckedConfig } from './disable-type-checked.js';
3
+ import { disableExcept } from './utils/options.js';
4
+ const recommendedSourceOptions = {
5
+ agentSkills: true,
6
+ js: true,
7
+ jsdoc: true,
8
+ node: true,
9
+ promise: true,
10
+ react: false,
11
+ regexp: true,
12
+ sort: true,
13
+ ts: { strict: false, typeChecked: true },
14
+ unicorn: true,
15
+ };
16
+ const recommendedReactOptions = {
17
+ ...recommendedSourceOptions,
18
+ react: {
19
+ astro: true,
20
+ typeChecked: true,
21
+ typescript: true,
22
+ },
23
+ };
24
+ const recommendedOptions = {
25
+ json: { sort: true },
26
+ nx: true,
27
+ source: recommendedSourceOptions,
28
+ tests: { unitTestRunner: 'vitest' },
29
+ yaml: { sort: true },
30
+ };
31
+ export const configs = {
32
+ 'disableTypeChecked': disableTypeCheckedConfig,
33
+ 'json': disableExcept({}, 'json'),
34
+ 'recommended': configure(recommendedOptions),
35
+ 'recommended/astro': configure({
36
+ ...recommendedOptions,
37
+ source: {
38
+ ...recommendedSourceOptions,
39
+ react: { astro: true, typeChecked: true, typescript: true },
40
+ },
41
+ }),
42
+ 'recommended/no-type-checked': configure({
43
+ ...recommendedOptions,
44
+ source: { ...recommendedSourceOptions, ts: { strict: false, typeChecked: false } },
45
+ }),
46
+ 'recommended/react': configure({
47
+ ...recommendedOptions,
48
+ source: recommendedReactOptions,
49
+ }),
50
+ 'recommended/strict': configure({
51
+ ...recommendedOptions,
52
+ source: { ts: { strict: true, typeChecked: true } },
53
+ }),
54
+ 'standard': configure(),
55
+ 'standard/no-type-checked': configure({
56
+ source: { ts: { strict: false, typeChecked: false } },
57
+ }),
58
+ 'standard/strict': configure({
59
+ source: { ts: { strict: true, typeChecked: true } },
60
+ }),
61
+ 'tests/jest': disableExcept({ tests: { unitTestRunner: 'jest' } }, 'tests'),
62
+ 'tests/vitest': disableExcept({ tests: { unitTestRunner: 'vitest' } }, 'tests'),
63
+ 'toml': disableExcept({}, 'toml'),
64
+ 'yaml': disableExcept({}, 'yaml'),
65
+ };
@@ -0,0 +1,4 @@
1
+ export declare const disableTypeCheckedConfig: {
2
+ name: string;
3
+ rules: {};
4
+ }[];
@@ -0,0 +1,8 @@
1
+ import tseslint from 'typescript-eslint';
2
+ import { namer } from './namer.js';
3
+ export const disableTypeCheckedConfig = [
4
+ {
5
+ name: namer('disable-type-checked'),
6
+ rules: { ...tseslint.configs.disableTypeChecked.rules },
7
+ },
8
+ ];
package/src/lib/meta.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  import type { ESLint } from 'eslint';
2
2
  export declare const meta: ESLint.Plugin['meta'];
3
- //# sourceMappingURL=meta.d.ts.map
@@ -1,12 +1,14 @@
1
1
  import type { Linter } from 'eslint';
2
2
  /**
3
3
  * Prepend the workspace's namespace or full name to a string. Useful for naming eslint configuration objects.
4
+ * @internal
4
5
  * @param value the value to add to the name
5
6
  * @returns prefixed value
6
7
  */
7
8
  export declare function namer(value?: string): string;
8
9
  /**
9
10
  * Set the `name` property of an ESLint config.
11
+ * @internal
10
12
  * @param config the object
11
13
  * @param defaultName override the default behavior of this function
12
14
  * @returns the named config(s)
@@ -14,6 +16,7 @@ export declare function namer(value?: string): string;
14
16
  export declare function objectNamer(config: Config, defaultName?: string): Named<Config>;
15
17
  /**
16
18
  * Make the name property of an object required. Preserves JSDoc comments for objects that already have a name property.
19
+ * @internal
17
20
  */
18
21
  export type Named<T extends object> = Required<T extends N ? Pick<T, 'name'> : N> & T;
19
22
  type Config = Linter.Config;
@@ -21,4 +24,3 @@ type N = {
21
24
  name?: string;
22
25
  };
23
26
  export {};
24
- //# sourceMappingURL=namer.d.ts.map
package/src/lib/namer.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import pkg from '../../package.json' with { type: 'json' };
2
2
  /**
3
3
  * Prepend the workspace's namespace or full name to a string. Useful for naming eslint configuration objects.
4
+ * @internal
4
5
  * @param value the value to add to the name
5
6
  * @returns prefixed value
6
7
  */
@@ -13,6 +14,7 @@ export function namer(value) {
13
14
  }
14
15
  /**
15
16
  * Set the `name` property of an ESLint config.
17
+ * @internal
16
18
  * @param config the object
17
19
  * @param defaultName override the default behavior of this function
18
20
  * @returns the named config(s)
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Get the expected root of a module. For package specifiers, returns the package root; for non-package-like specifiers, returns the value as-is.
3
+ * @param specifier the module specifier
4
+ * @returns the root module specifier
5
+ * @example
6
+ * getModuleRoot('pg') // -> 'pg'
7
+ * getModuleRoot('lodash/fp') // -> 'lodash'
8
+ * getModuleRoot('@scope/pkg') // -> '@scope/pkg'
9
+ * getModuleRoot('@scope/pkg/subpath') // -> '@scope/pkg'
10
+ */
11
+ export declare function getModuleRoot(specifier: string): string;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Get the expected root of a module. For package specifiers, returns the package root; for non-package-like specifiers, returns the value as-is.
3
+ * @param specifier the module specifier
4
+ * @returns the root module specifier
5
+ * @example
6
+ * getModuleRoot('pg') // -> 'pg'
7
+ * getModuleRoot('lodash/fp') // -> 'lodash'
8
+ * getModuleRoot('@scope/pkg') // -> '@scope/pkg'
9
+ * getModuleRoot('@scope/pkg/subpath') // -> '@scope/pkg'
10
+ */
11
+ export function getModuleRoot(specifier) {
12
+ if (!specifier) {
13
+ return specifier;
14
+ }
15
+ if (specifier.startsWith('./') ||
16
+ specifier.startsWith('../') ||
17
+ specifier.startsWith('/') ||
18
+ specifier.startsWith('file:') ||
19
+ specifier.startsWith('node:')) {
20
+ return specifier;
21
+ }
22
+ if (specifier.startsWith('@')) {
23
+ const parts = specifier.split('/');
24
+ if (parts.length >= 2) {
25
+ return `${parts[0]}/${parts[1]}`;
26
+ }
27
+ return specifier;
28
+ }
29
+ const firstSlash = specifier.indexOf('/');
30
+ return firstSlash === -1 ? specifier : specifier.slice(0, firstSlash);
31
+ }
@@ -0,0 +1,76 @@
1
+ export declare class ImportResolver {
2
+ private allowSubpathMatch;
3
+ private cache;
4
+ private useCache;
5
+ constructor(options?: ImportResolverOptions);
6
+ clear(specifier?: string): void;
7
+ has(specifier: string): boolean;
8
+ import<T = unknown>(specifier: string): Promise<OptionalImportResult<T>>;
9
+ importDefault<T = unknown>(specifier: string): Promise<T | undefined>;
10
+ requireImport<T = unknown>(specifier: string): Promise<T | undefined>;
11
+ /**
12
+ * Narrow unknown to a Node-like error shape.
13
+ * @param value the value
14
+ * @returns the error-like object, or undefined if the value is not an object of the expected shape
15
+ */
16
+ private asNodeLikeError;
17
+ /**
18
+ * Extract the target from CommonJS-style error messages like:
19
+ * - Cannot find module 'pg'
20
+ * @param message the error message
21
+ * @returns the target, or undefined if the message doesn't match the expected pattern
22
+ */
23
+ private extractCannotFindModuleTarget;
24
+ /**
25
+ * Extract the quoted missing target from error messages like:
26
+ * - Cannot find package 'pg' imported from ...
27
+ * - Cannot find module 'pg' imported from ...
28
+ * @param message the error message
29
+ * @returns the target, or undefined if the message doesn't match the expected pattern
30
+ */
31
+ private extractQuotedMissingTarget;
32
+ /**
33
+ * Detect whether an import error means that the *requested* specifier is missing, as opposed to one of its transitive dependencies. This is necessarily heuristic because Node error shapes/messages vary by version.
34
+ * @param error the captured error
35
+ * @param specifier the value that was imported
36
+ * @returns true if the error is caused by the requested module; false otherwise
37
+ */
38
+ private isRequestedModuleMissing;
39
+ /**
40
+ * Determine whether the target is the requested module, or a subpath of it.
41
+ * @param target the identified target specifier
42
+ * @param requested the requested module specifier
43
+ * @returns true if {@link target} is a subpath of {@link requested}; false otherwise
44
+ * @example
45
+ * isSubpathOfModule('@scope/pkg/subpath', '@scope/pkg') // -> true
46
+ */
47
+ private isSameOrSubpath;
48
+ private loadModule;
49
+ }
50
+ export interface ImportResolverOptions {
51
+ /**
52
+ * Treat package subpaths as belonging to the same package.
53
+ * @default true
54
+ */
55
+ allowSubpathMatch?: boolean;
56
+ /**
57
+ * Cache resolved promises/results for each specifier.
58
+ * @default true
59
+ */
60
+ cache?: boolean;
61
+ }
62
+ export interface NodeLikeError {
63
+ code?: string;
64
+ message?: string;
65
+ }
66
+ /**
67
+ * The result of resolving an optional dependency.
68
+ * @template TModule the expected type of the imported module
69
+ */
70
+ export type OptionalImportResult<TModule> = {
71
+ module: TModule;
72
+ success: true;
73
+ } | {
74
+ module: undefined;
75
+ success: false;
76
+ };