@ms-cloudpack/eslint-plugin 0.3.11 → 0.3.12
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.
- package/README.md +60 -2
- package/lib/rules/no-test-exports.d.ts +23 -0
- package/lib/rules/no-test-exports.d.ts.map +1 -0
- package/lib/rules/no-test-exports.js +129 -0
- package/lib/rules/no-test-exports.js.map +1 -0
- package/lib/rules/no-unsupported-imports.d.ts +0 -4
- package/lib/rules/no-unsupported-imports.d.ts.map +1 -1
- package/lib/rules/no-unsupported-imports.js +11 -5
- package/lib/rules/no-unsupported-imports.js.map +1 -1
- package/lib/utils/getPackageInfo.d.ts +1 -1
- package/lib/utils/getPackageInfo.d.ts.map +1 -1
- package/lib/utils/getPackageInfo.js +5 -1
- package/lib/utils/getPackageInfo.js.map +1 -1
- package/lib/utils/getRegexpsFromStrings.d.ts +6 -0
- package/lib/utils/getRegexpsFromStrings.d.ts.map +1 -0
- package/lib/utils/getRegexpsFromStrings.js +12 -0
- package/lib/utils/getRegexpsFromStrings.js.map +1 -0
- package/lib/utils/testExports/extractIdentifiersFromExport.d.ts +6 -0
- package/lib/utils/testExports/extractIdentifiersFromExport.d.ts.map +1 -0
- package/lib/utils/testExports/extractIdentifiersFromExport.js +58 -0
- package/lib/utils/testExports/extractIdentifiersFromExport.js.map +1 -0
- package/lib/utils/testExports/isIncludedIndexFile.d.ts +10 -0
- package/lib/utils/testExports/isIncludedIndexFile.d.ts.map +1 -0
- package/lib/utils/testExports/isIncludedIndexFile.js +28 -0
- package/lib/utils/testExports/isIncludedIndexFile.js.map +1 -0
- package/lib/utils/unsupportedImports/parseImportIfRelevant.d.ts.map +1 -0
- package/lib/utils/unsupportedImports/parseImportIfRelevant.js.map +1 -0
- package/lib/utils/{pathSatisfiesAnyExport.d.ts → unsupportedImports/pathSatisfiesAnyExport.d.ts} +1 -1
- package/lib/utils/unsupportedImports/pathSatisfiesAnyExport.d.ts.map +1 -0
- package/lib/utils/unsupportedImports/pathSatisfiesAnyExport.js.map +1 -0
- package/lib/utils/unsupportedImports/resolvePackageRoot.d.ts.map +1 -0
- package/lib/utils/unsupportedImports/resolvePackageRoot.js.map +1 -0
- package/package.json +3 -3
- package/lib/utils/parseImportIfRelevant.d.ts.map +0 -1
- package/lib/utils/parseImportIfRelevant.js.map +0 -1
- package/lib/utils/pathSatisfiesAnyExport.d.ts.map +0 -1
- package/lib/utils/pathSatisfiesAnyExport.js.map +0 -1
- package/lib/utils/resolvePackageRoot.d.ts.map +0 -1
- package/lib/utils/resolvePackageRoot.js.map +0 -1
- /package/lib/utils/{parseImportIfRelevant.d.ts → unsupportedImports/parseImportIfRelevant.d.ts} +0 -0
- /package/lib/utils/{parseImportIfRelevant.js → unsupportedImports/parseImportIfRelevant.js} +0 -0
- /package/lib/utils/{pathSatisfiesAnyExport.js → unsupportedImports/pathSatisfiesAnyExport.js} +0 -0
- /package/lib/utils/{resolvePackageRoot.d.ts → unsupportedImports/resolvePackageRoot.d.ts} +0 -0
- /package/lib/utils/{resolvePackageRoot.js → unsupportedImports/resolvePackageRoot.js} +0 -0
package/README.md
CHANGED
|
@@ -33,11 +33,11 @@ To enable, follow the instructions for [linting with type information](https://t
|
|
|
33
33
|
"extends": [
|
|
34
34
|
// Both of these should be included
|
|
35
35
|
"plugin:@ms-cloudpack/recommended",
|
|
36
|
-
"plugin:@ms-cloudpack/recommended-requiring-type-checking"
|
|
36
|
+
"plugin:@ms-cloudpack/recommended-requiring-type-checking",
|
|
37
37
|
],
|
|
38
38
|
"parserOptions": {
|
|
39
39
|
// `project` must be specified; see link above
|
|
40
|
-
}
|
|
40
|
+
},
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
@@ -61,8 +61,66 @@ The `@ms-cloudpack/onboarding-requiring-type-checking` config includes the same
|
|
|
61
61
|
|
|
62
62
|
| ✓ | 🔧 | Rule | Description |
|
|
63
63
|
| :-: | :-: | :------------------------------------- | :-------------------------------------------------------- |
|
|
64
|
+
| | | `@ms-cloudpack/no-test-exports` | Ban test, mock, and fixture exports from index files |
|
|
64
65
|
| ✓ | | `@ms-cloudpack/no-unsupported-imports` | Ban deep imports that are not defined in an `exports` map |
|
|
65
66
|
|
|
67
|
+
### `no-test-exports`
|
|
68
|
+
|
|
69
|
+
This rule bans exporting paths or names which appear to be test-related from index files (unless the index file is also under a test-related path).
|
|
70
|
+
|
|
71
|
+
Note that this rule checks the filename being linted and will **only** run on `index.*` files. Files under paths that appear test-related (based on the `testPathPatterns` setting) If you have the rule enabled for a whole repo, you'll need to disable it for any test-related packages.
|
|
72
|
+
|
|
73
|
+
Mixing test and "production" exports in a single package entry point is not recommended for several reasons:
|
|
74
|
+
|
|
75
|
+
- Especially if the package is published, it's not clear to consumers what should actually be considered part of the main public API.
|
|
76
|
+
- For Cloudpack, it will cause traversal of additional test-related dependencies such as `jest` and its dependency tree. These packages are often not intended for use in the browser and may fail to bundle, which causes time to be wasted debugging issues that won't be relevant at runtime.
|
|
77
|
+
- Even for other bundlers such as Webpack (or any tool that traverses code), traversing into test dependency code can cause a parse time penalty even if the exports are ultimately tree-shaken out.
|
|
78
|
+
|
|
79
|
+
The rule is unfortunately not auto-fixable because ESLint is designed to operate on single files. The fix is as follows:
|
|
80
|
+
|
|
81
|
+
- At the package source root, create a new file with a name such as `index.mock.ts` or `index.test.ts` and move all test, mock, and fixture exports into that file.
|
|
82
|
+
- If the packages uses an exports map, add this path to the exports map.
|
|
83
|
+
- Update consumers to import from the new path, e.g. `my-pkg/index.mock`.
|
|
84
|
+
|
|
85
|
+
#### Options
|
|
86
|
+
|
|
87
|
+
For any of the array options, a provided array overwrites the defaults. Include `...` in your custom array to also include the defaults.
|
|
88
|
+
|
|
89
|
+
- `testPathPatterns` (`string[]`): Ban importing or exporting from paths matching these regular expressions in index files. Also, index files underneath matching paths will be ignored. Default as of writing:
|
|
90
|
+
- File or directory starting with `mock|test|fixture` (optionally with `__` before)
|
|
91
|
+
- File or directory containing `Mock|Test|Fixture`
|
|
92
|
+
- File ending with `.(mock|test|fixture)` (optionally with extension)
|
|
93
|
+
- `testExportNamePatterns` (`string[]`): Ban exporting identifiers matching these regular expressions in index files. Default as of writing:
|
|
94
|
+
- Name starting with `mock|test|fixture`
|
|
95
|
+
- Name containing `Mock|Test|Fixture`
|
|
96
|
+
- `maxDepth` (`number`): Maximum depth of index files to check relative to the package root (zero-indexed). By default this is set to infinity in case of re-exports. Set to 0 to only check `<package root>/index.ts` or 1 to also check `src/index.ts`.
|
|
97
|
+
|
|
98
|
+
#### Examples
|
|
99
|
+
|
|
100
|
+
These examples applies to any `index.*` file which is within the configured `maxDepth` from the package root:
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
// ✅ OK
|
|
104
|
+
export { foo } from './foo';
|
|
105
|
+
// With testPathPatterns: []
|
|
106
|
+
export { foo } from './mocks/foo';
|
|
107
|
+
// With testExportNamePatterns: []
|
|
108
|
+
export { mockFoo } from './foo';
|
|
109
|
+
|
|
110
|
+
// ❌ Error
|
|
111
|
+
// These examples use "mock" to be concise, but the same rules apply by default to "test" and "fixture"
|
|
112
|
+
export { foo } from './foo.mock';
|
|
113
|
+
export { foo } from './mock-foo';
|
|
114
|
+
export { foo } from './mocks/foo';
|
|
115
|
+
export { foo } from './__mocks__/foo';
|
|
116
|
+
export * as foo from './foo.mock';
|
|
117
|
+
export { mockFoo, bar as mockBar } from './foo';
|
|
118
|
+
export const mockFoo = 'foo';
|
|
119
|
+
export { fooMock };
|
|
120
|
+
// Importing from test-related files in an index file is also banned
|
|
121
|
+
import { foo } from './foo.mock';
|
|
122
|
+
```
|
|
123
|
+
|
|
66
124
|
### `no-unsupported-imports`
|
|
67
125
|
|
|
68
126
|
This rule bans deep imports from paths which aren't defined in a package's [exports map](https://nodejs.org/api/packages.html#package-entry-points). It also bans **all** deep imports from packages which don't define exports maps.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
/** Processed rule options */
|
|
3
|
+
type RuleOptions = {
|
|
4
|
+
testPathPatterns: RegExp[];
|
|
5
|
+
testExportNamePatterns: RegExp[];
|
|
6
|
+
};
|
|
7
|
+
/** Rule options as specified in the config */
|
|
8
|
+
export type RawRuleOptions = Omit<Partial<RuleOptions>, 'testPathPatterns' | 'testExportNamePatterns'> & {
|
|
9
|
+
testPathPatterns?: string[];
|
|
10
|
+
testExportNamePatterns?: string[];
|
|
11
|
+
maxDepth?: number;
|
|
12
|
+
};
|
|
13
|
+
export declare const defaultTestPaths: RegExp[];
|
|
14
|
+
export declare const defaultMaxDepth: number;
|
|
15
|
+
export type MessageIds = 'invalidPath' | 'invalidName';
|
|
16
|
+
export type ErrorData = {
|
|
17
|
+
extension: string;
|
|
18
|
+
invalidPath?: string;
|
|
19
|
+
invalidName?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const rule: TSESLint.RuleModule<MessageIds, RawRuleOptions[]>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=no-test-exports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-test-exports.d.ts","sourceRoot":"","sources":["../../src/rules/no-test-exports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAOnE,6BAA6B;AAC7B,KAAK,WAAW,GAAG;IACjB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,kBAAkB,GAAG,wBAAwB,CAAC,GAAG;IACvG,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AASF,eAAO,MAAM,gBAAgB,EAAE,MAAM,EAKpC,CAAC;AAGF,eAAO,MAAM,eAAe,QAAW,CAAC;AAExC,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,aAAa,CAAC;AAEvD,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAaF,eAAO,MAAM,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,cAAc,EAAE,CA+ElE,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rule = exports.defaultMaxDepth = exports.defaultTestPaths = void 0;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const getImportPathLiteralNode_1 = require("../utils/getImportPathLiteralNode");
|
|
6
|
+
const extractIdentifiersFromExport_1 = require("../utils/testExports/extractIdentifiersFromExport");
|
|
7
|
+
const getRegexpsFromStrings_1 = require("../utils/getRegexpsFromStrings");
|
|
8
|
+
const isIncludedIndexFile_1 = require("../utils/testExports/isIncludedIndexFile");
|
|
9
|
+
exports.defaultTestPaths = [
|
|
10
|
+
// Only match lowercase mock|test|fixture at the beginning of an import path segment to avoid false positives
|
|
11
|
+
/\/(__)?(mock|test|fixture)/,
|
|
12
|
+
/\.(mock|test|fixture)s?(\.\w+)?$/,
|
|
13
|
+
/Mock|Test|Fixture/,
|
|
14
|
+
];
|
|
15
|
+
// Only match lowercase mock|test|fixture at the beginning of an export name to avoid false positives
|
|
16
|
+
const defaultTestExportNames = [/^(mock|test|fixture)/, /Mock|Test|Fixture/];
|
|
17
|
+
exports.defaultMaxDepth = Infinity;
|
|
18
|
+
const separateFileMessage = 'use a separate index.mock.{{extension}} file instead';
|
|
19
|
+
const messages = {
|
|
20
|
+
invalidPath: 'Contents of test-related path "{{invalidPath}}" should not be referenced from the index file; ' +
|
|
21
|
+
separateFileMessage,
|
|
22
|
+
invalidName: 'Export "{{invalidName}}" appears to be test-related and should not be exported from the index file; ' +
|
|
23
|
+
separateFileMessage,
|
|
24
|
+
};
|
|
25
|
+
exports.rule = {
|
|
26
|
+
defaultOptions: [],
|
|
27
|
+
meta: {
|
|
28
|
+
type: 'problem',
|
|
29
|
+
docs: {
|
|
30
|
+
description: 'ban test, mock, and fixture exports from index files',
|
|
31
|
+
recommended: 'recommended',
|
|
32
|
+
},
|
|
33
|
+
messages,
|
|
34
|
+
schema: [
|
|
35
|
+
{
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
testPathPatterns: {
|
|
39
|
+
type: 'array',
|
|
40
|
+
description: 'Ban exports from these paths (regex) from index files. Use "..." to include the default paths.',
|
|
41
|
+
items: { type: 'string' },
|
|
42
|
+
},
|
|
43
|
+
testExportNamePatterns: {
|
|
44
|
+
type: 'array',
|
|
45
|
+
description: 'Ban exports with these names (regex) from index files. Use "..." to include the default names.',
|
|
46
|
+
items: { type: 'string' },
|
|
47
|
+
},
|
|
48
|
+
maxDepth: {
|
|
49
|
+
type: 'number',
|
|
50
|
+
description: 'Maximum depth of index file (0-indexed; default Infinity)',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
create: (context) => {
|
|
58
|
+
const options = context.options?.[0] || {};
|
|
59
|
+
// eslint-disable-next-line etc/no-deprecated -- filename property may not exist yet?
|
|
60
|
+
const filename = context.filename || context.getFilename?.();
|
|
61
|
+
const testPathPatterns = (0, getRegexpsFromStrings_1.getRegexpsFromStrings)(options.testPathPatterns, exports.defaultTestPaths);
|
|
62
|
+
const testExportNamePatterns = (0, getRegexpsFromStrings_1.getRegexpsFromStrings)(options.testExportNamePatterns, defaultTestExportNames);
|
|
63
|
+
const maxDepth = options.maxDepth ?? exports.defaultMaxDepth;
|
|
64
|
+
if (!(0, isIncludedIndexFile_1.isIncludedIndexFile)({ filename, ignorePaths: testPathPatterns, maxDepth })) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
const ruleContext = {
|
|
68
|
+
...context,
|
|
69
|
+
options: { testExportNamePatterns, testPathPatterns },
|
|
70
|
+
filename,
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
// import foo from 'foo'
|
|
74
|
+
// import * as foo from 'foo'
|
|
75
|
+
// import { foo } from 'foo'
|
|
76
|
+
// import { foo as bar } from 'foo'
|
|
77
|
+
// import 'foo'
|
|
78
|
+
ImportDeclaration: (node) => checkNode(ruleContext, node),
|
|
79
|
+
// import foo = require('foo')
|
|
80
|
+
TSImportEqualsDeclaration: (node) => {
|
|
81
|
+
// Skip "export import foo = require('foo')" because that will be handled by ExportNamedDeclaration
|
|
82
|
+
if (node.parent.type !== 'ExportNamedDeclaration') {
|
|
83
|
+
checkNode(ruleContext, node);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
// export { foo }
|
|
87
|
+
ExportDeclaration: (node) => checkNode(ruleContext, node),
|
|
88
|
+
// export { foo } from 'foo'
|
|
89
|
+
// export { foo as bar } from 'foo'
|
|
90
|
+
// export import foo = require('foo')
|
|
91
|
+
// export const foo = 'foo';
|
|
92
|
+
// and other exported declarations
|
|
93
|
+
ExportNamedDeclaration: (node) => checkNode(ruleContext, node),
|
|
94
|
+
// export * from 'foo'
|
|
95
|
+
// export * as foo from 'foo'
|
|
96
|
+
ExportAllDeclaration: (node) => checkNode(ruleContext, node),
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
function checkNode(context, node) {
|
|
101
|
+
const extension = path.extname(context.filename).slice(1);
|
|
102
|
+
// If there's an import path, check it
|
|
103
|
+
const { importPath, pathNode } = (0, getImportPathLiteralNode_1.getImportPathLiteralNode)(node) || {};
|
|
104
|
+
if (importPath && pathNode && context.options.testPathPatterns.some((re) => re.test(importPath))) {
|
|
105
|
+
const data = { extension, invalidPath: importPath };
|
|
106
|
+
context.report({
|
|
107
|
+
node: pathNode,
|
|
108
|
+
messageId: 'invalidPath',
|
|
109
|
+
data,
|
|
110
|
+
});
|
|
111
|
+
// This takes precedence over export name checks
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Check exported names if relevant
|
|
115
|
+
if (node.type === 'ExportAllDeclaration' || node.type === 'ExportNamedDeclaration') {
|
|
116
|
+
const ids = (0, extractIdentifiersFromExport_1.extractIdentifiersFromExport)(node);
|
|
117
|
+
for (const id of ids) {
|
|
118
|
+
if (context.options.testExportNamePatterns.some((re) => re.test(id.name))) {
|
|
119
|
+
const data = { extension, invalidName: id.name };
|
|
120
|
+
context.report({
|
|
121
|
+
node: id,
|
|
122
|
+
messageId: 'invalidName',
|
|
123
|
+
data,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=no-test-exports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-test-exports.js","sourceRoot":"","sources":["../../src/rules/no-test-exports.ts"],"names":[],"mappings":";;;AACA,6BAA6B;AAC7B,gFAAkG;AAClG,oGAAiG;AACjG,0EAAuE;AACvE,kFAA+E;AAsBlE,QAAA,gBAAgB,GAAa;IACxC,6GAA6G;IAC7G,4BAA4B;IAC5B,kCAAkC;IAClC,mBAAmB;CACpB,CAAC;AACF,qGAAqG;AACrG,MAAM,sBAAsB,GAAa,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;AAC1E,QAAA,eAAe,GAAG,QAAQ,CAAC;AAUxC,MAAM,mBAAmB,GAAG,sDAAsD,CAAC;AAEnF,MAAM,QAAQ,GAA+B;IAC3C,WAAW,EACT,gGAAgG;QAChG,mBAAmB;IACrB,WAAW,EACT,sGAAsG;QACtG,mBAAmB;CACtB,CAAC;AAEW,QAAA,IAAI,GAAsD;IACrE,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,sDAAsD;YACnE,WAAW,EAAE,aAAa;SAC3B;QACD,QAAQ;QACR,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,gBAAgB,EAAE;wBAChB,IAAI,EAAE,OAAO;wBACb,WAAW,EACT,gGAAgG;wBAClG,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC1B;oBACD,sBAAsB,EAAE;wBACtB,IAAI,EAAE,OAAO;wBACb,WAAW,EACT,gGAAgG;wBAClG,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC1B;oBACD,QAAQ,EAAE;wBACR,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,2DAA2D;qBACzE;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IACD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,qFAAqF;QACrF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7D,MAAM,gBAAgB,GAAG,IAAA,6CAAqB,EAAC,OAAO,CAAC,gBAAgB,EAAE,wBAAgB,CAAC,CAAC;QAC3F,MAAM,sBAAsB,GAAG,IAAA,6CAAqB,EAAC,OAAO,CAAC,sBAAsB,EAAE,sBAAsB,CAAC,CAAC;QAC7G,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,uBAAe,CAAC;QAErD,IAAI,CAAC,IAAA,yCAAmB,EAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YAChF,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,WAAW,GAAgB;YAC/B,GAAG,OAAO;YACV,OAAO,EAAE,EAAE,sBAAsB,EAAE,gBAAgB,EAAE;YACrD,QAAQ;SACT,CAAC;QAEF,OAAO;YACL,wBAAwB;YACxB,6BAA6B;YAC7B,4BAA4B;YAC5B,mCAAmC;YACnC,eAAe;YACf,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC;YACzD,8BAA8B;YAC9B,yBAAyB,EAAE,CAAC,IAAI,EAAE,EAAE;gBAClC,mGAAmG;gBACnG,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;oBAClD,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;YACD,iBAAiB;YACjB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC;YACzD,4BAA4B;YAC5B,mCAAmC;YACnC,qCAAqC;YACrC,4BAA4B;YAC5B,kCAAkC;YAClC,sBAAsB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC;YAC9D,sBAAsB;YACtB,6BAA6B;YAC7B,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC;SAC7D,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,SAAS,SAAS,CAChB,OAAoB,EACpB,IAAkF;IAElF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE1D,sCAAsC;IACtC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAA,mDAAwB,EAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,UAAU,IAAI,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QACjG,MAAM,IAAI,GAAc,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;QAC/D,OAAO,CAAC,MAAM,CAAC;YACb,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,aAAa;YACxB,IAAI;SACL,CAAC,CAAC;QACH,gDAAgD;QAChD,OAAO;IACT,CAAC;IAED,mCAAmC;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAsB,IAAI,IAAI,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;QACnF,MAAM,GAAG,GAAG,IAAA,2DAA4B,EAAC,IAAI,CAAC,CAAC;QAC/C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC1E,MAAM,IAAI,GAAc,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;gBAC5D,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,EAAE;oBACR,SAAS,EAAE,aAAa;oBACxB,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import type { TSESLint, TSESTree } from '@typescript-eslint/utils';\nimport * as path from 'path';\nimport { getImportPathLiteralNode, type ImportLikeNode } from '../utils/getImportPathLiteralNode';\nimport { extractIdentifiersFromExport } from '../utils/testExports/extractIdentifiersFromExport';\nimport { getRegexpsFromStrings } from '../utils/getRegexpsFromStrings';\nimport { isIncludedIndexFile } from '../utils/testExports/isIncludedIndexFile';\n\n/** Processed rule options */\ntype RuleOptions = {\n testPathPatterns: RegExp[];\n testExportNamePatterns: RegExp[];\n};\n\n/** Rule options as specified in the config */\nexport type RawRuleOptions = Omit<Partial<RuleOptions>, 'testPathPatterns' | 'testExportNamePatterns'> & {\n testPathPatterns?: string[];\n testExportNamePatterns?: string[];\n maxDepth?: number;\n};\n\ntype RuleContext = Omit<RawRuleContext, 'options'> & {\n options: RuleOptions;\n filename: string;\n};\n\ntype RawRuleContext = TSESLint.RuleContext<MessageIds, RawRuleOptions[]>;\n\nexport const defaultTestPaths: RegExp[] = [\n // Only match lowercase mock|test|fixture at the beginning of an import path segment to avoid false positives\n /\\/(__)?(mock|test|fixture)/,\n /\\.(mock|test|fixture)s?(\\.\\w+)?$/,\n /Mock|Test|Fixture/,\n];\n// Only match lowercase mock|test|fixture at the beginning of an export name to avoid false positives\nconst defaultTestExportNames: RegExp[] = [/^(mock|test|fixture)/, /Mock|Test|Fixture/];\nexport const defaultMaxDepth = Infinity;\n\nexport type MessageIds = 'invalidPath' | 'invalidName';\n\nexport type ErrorData = {\n extension: string;\n invalidPath?: string;\n invalidName?: string;\n};\n\nconst separateFileMessage = 'use a separate index.mock.{{extension}} file instead';\n\nconst messages: Record<MessageIds, string> = {\n invalidPath:\n 'Contents of test-related path \"{{invalidPath}}\" should not be referenced from the index file; ' +\n separateFileMessage,\n invalidName:\n 'Export \"{{invalidName}}\" appears to be test-related and should not be exported from the index file; ' +\n separateFileMessage,\n};\n\nexport const rule: TSESLint.RuleModule<MessageIds, RawRuleOptions[]> = {\n defaultOptions: [],\n meta: {\n type: 'problem',\n docs: {\n description: 'ban test, mock, and fixture exports from index files',\n recommended: 'recommended',\n },\n messages,\n schema: [\n {\n type: 'object',\n properties: {\n testPathPatterns: {\n type: 'array',\n description:\n 'Ban exports from these paths (regex) from index files. Use \"...\" to include the default paths.',\n items: { type: 'string' },\n },\n testExportNamePatterns: {\n type: 'array',\n description:\n 'Ban exports with these names (regex) from index files. Use \"...\" to include the default names.',\n items: { type: 'string' },\n },\n maxDepth: {\n type: 'number',\n description: 'Maximum depth of index file (0-indexed; default Infinity)',\n },\n },\n additionalProperties: false,\n },\n ],\n },\n create: (context) => {\n const options = context.options?.[0] || {};\n // eslint-disable-next-line etc/no-deprecated -- filename property may not exist yet?\n const filename = context.filename || context.getFilename?.();\n const testPathPatterns = getRegexpsFromStrings(options.testPathPatterns, defaultTestPaths);\n const testExportNamePatterns = getRegexpsFromStrings(options.testExportNamePatterns, defaultTestExportNames);\n const maxDepth = options.maxDepth ?? defaultMaxDepth;\n\n if (!isIncludedIndexFile({ filename, ignorePaths: testPathPatterns, maxDepth })) {\n return {};\n }\n\n const ruleContext: RuleContext = {\n ...context,\n options: { testExportNamePatterns, testPathPatterns },\n filename,\n };\n\n return {\n // import foo from 'foo'\n // import * as foo from 'foo'\n // import { foo } from 'foo'\n // import { foo as bar } from 'foo'\n // import 'foo'\n ImportDeclaration: (node) => checkNode(ruleContext, node),\n // import foo = require('foo')\n TSImportEqualsDeclaration: (node) => {\n // Skip \"export import foo = require('foo')\" because that will be handled by ExportNamedDeclaration\n if (node.parent.type !== 'ExportNamedDeclaration') {\n checkNode(ruleContext, node);\n }\n },\n // export { foo }\n ExportDeclaration: (node) => checkNode(ruleContext, node),\n // export { foo } from 'foo'\n // export { foo as bar } from 'foo'\n // export import foo = require('foo')\n // export const foo = 'foo';\n // and other exported declarations\n ExportNamedDeclaration: (node) => checkNode(ruleContext, node),\n // export * from 'foo'\n // export * as foo from 'foo'\n ExportAllDeclaration: (node) => checkNode(ruleContext, node),\n };\n },\n};\n\nfunction checkNode(\n context: RuleContext,\n node: Exclude<ImportLikeNode, TSESTree.CallExpression | TSESTree.ImportExpression>,\n) {\n const extension = path.extname(context.filename).slice(1);\n\n // If there's an import path, check it\n const { importPath, pathNode } = getImportPathLiteralNode(node) || {};\n if (importPath && pathNode && context.options.testPathPatterns.some((re) => re.test(importPath))) {\n const data: ErrorData = { extension, invalidPath: importPath };\n context.report({\n node: pathNode,\n messageId: 'invalidPath',\n data,\n });\n // This takes precedence over export name checks\n return;\n }\n\n // Check exported names if relevant\n if (node.type === 'ExportAllDeclaration' || node.type === 'ExportNamedDeclaration') {\n const ids = extractIdentifiersFromExport(node);\n for (const id of ids) {\n if (context.options.testExportNamePatterns.some((re) => re.test(id.name))) {\n const data: ErrorData = { extension, invalidName: id.name };\n context.report({\n node: id,\n messageId: 'invalidName',\n data,\n });\n }\n }\n }\n}\n"]}
|
|
@@ -11,10 +11,6 @@ export type RawRuleOptions = Omit<Partial<RuleOptions>, 'ignorePatterns'> & {
|
|
|
11
11
|
export type ErrorMessageIds = 'noExports' | 'noExportsLocal' | 'notExported' | 'notExportedLocal';
|
|
12
12
|
export type SuggestMessageIds = 'useTopLevel';
|
|
13
13
|
export type MessageIds = ErrorMessageIds | SuggestMessageIds;
|
|
14
|
-
export type ErrorData = {
|
|
15
|
-
packageName: string;
|
|
16
|
-
subPath: string;
|
|
17
|
-
};
|
|
18
14
|
export declare const rule: TSESLint.RuleModule<MessageIds, RawRuleOptions[]>;
|
|
19
15
|
export {};
|
|
20
16
|
//# sourceMappingURL=no-unsupported-imports.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-unsupported-imports.d.ts","sourceRoot":"","sources":["../../src/rules/no-unsupported-imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"no-unsupported-imports.d.ts","sourceRoot":"","sources":["../../src/rules/no-unsupported-imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAQzD,6BAA6B;AAC7B,KAAK,WAAW,GAAG;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,GAAG;IAC1E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAOF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,gBAAgB,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAClG,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAC9C,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAoC7D,eAAO,MAAM,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,cAAc,EAAE,CAiElE,CAAC"}
|
|
@@ -3,9 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.rule = void 0;
|
|
4
4
|
const getImportPathLiteralNode_1 = require("../utils/getImportPathLiteralNode");
|
|
5
5
|
const getPackageInfo_1 = require("../utils/getPackageInfo");
|
|
6
|
-
const parseImportIfRelevant_1 = require("../utils/parseImportIfRelevant");
|
|
7
|
-
const pathSatisfiesAnyExport_1 = require("../utils/pathSatisfiesAnyExport");
|
|
8
|
-
const resolvePackageRoot_1 = require("../utils/resolvePackageRoot");
|
|
6
|
+
const parseImportIfRelevant_1 = require("../utils/unsupportedImports/parseImportIfRelevant");
|
|
7
|
+
const pathSatisfiesAnyExport_1 = require("../utils/unsupportedImports/pathSatisfiesAnyExport");
|
|
8
|
+
const resolvePackageRoot_1 = require("../utils/unsupportedImports/resolvePackageRoot");
|
|
9
|
+
const getRegexpsFromStrings_1 = require("../utils/getRegexpsFromStrings");
|
|
9
10
|
const defaultOptions = {
|
|
10
11
|
ignorePatterns: [],
|
|
11
12
|
debug: false,
|
|
@@ -55,7 +56,7 @@ exports.rule = {
|
|
|
55
56
|
options: {
|
|
56
57
|
debug: false,
|
|
57
58
|
...options,
|
|
58
|
-
ignorePatterns: (
|
|
59
|
+
ignorePatterns: (0, getRegexpsFromStrings_1.getRegexpsFromStrings)(options.ignorePatterns),
|
|
59
60
|
},
|
|
60
61
|
// eslint-disable-next-line etc/no-deprecated -- filename property doesn't appear to exist yet...?
|
|
61
62
|
filename: context.getFilename(),
|
|
@@ -70,7 +71,12 @@ exports.rule = {
|
|
|
70
71
|
// await import('foo')
|
|
71
72
|
ImportExpression: (node) => checkImportOrExport(ruleContext, node),
|
|
72
73
|
// import foo = require('foo')
|
|
73
|
-
TSImportEqualsDeclaration: (node) =>
|
|
74
|
+
TSImportEqualsDeclaration: (node) => {
|
|
75
|
+
// Skip "export import foo = require('foo')" because that will be handled by ExportNamedDeclaration
|
|
76
|
+
if (node.parent.type !== 'ExportNamedDeclaration') {
|
|
77
|
+
checkImportOrExport(ruleContext, node);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
74
80
|
// export { foo } from 'foo'
|
|
75
81
|
// export { foo as bar } from 'foo'
|
|
76
82
|
ExportNamedDeclaration: (node) => checkImportOrExport(ruleContext, node),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-unsupported-imports.js","sourceRoot":"","sources":["../../src/rules/no-unsupported-imports.ts"],"names":[],"mappings":";;;AACA,gFAAkG;AAClG,4DAAyD;AACzD,0EAAuE;AACvE,4EAAyE;AACzE,oEAAiE;AAiCjE,MAAM,cAAc,GAAmB;IACrC,cAAc,EAAE,EAAE;IAClB,KAAK,EAAE,KAAK;CACb,CAAC;AAEF,MAAM,cAAc,GAAG,8DAA8D,CAAC;AACtF,MAAM,SAAS,GAAG,mFAAmF,GAAG,cAAc,CAAC;AACvH,MAAM,WAAW,GACf,yFAAyF,GAAG,cAAc,CAAC;AAC7G,MAAM,YAAY,GAChB,mFAAmF;IACnF,iEAAiE,CAAC;AAEpE,MAAM,QAAQ,GAA+B;IAC3C,SAAS;IACT,cAAc,EAAE,GAAG,SAAS,KAAK,YAAY,EAAE;IAC/C,WAAW;IACX,gBAAgB,EAAE,GAAG,WAAW,KAAK,YAAY,EAAE;IACnD,WAAW,EAAE,qDAAqD;CACnE,CAAC;AAEF,MAAM,gBAAgB,GAAsB,aAAa,CAAC;AAE7C,QAAA,IAAI,GAAsD;IACrE,cAAc,EAAE,CAAC,cAAc,CAAC;IAChC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,uCAAuC;YACpD,WAAW,EAAE,aAAa;SAC3B;QACD,cAAc,EAAE,IAAI;QACpB,QAAQ;QACR,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,cAAc,EAAE;wBACd,IAAI,EAAE,OAAO;wBACb,WAAW,EAAE,4DAA4D;wBACzE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC1B;oBACD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC3B;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IACD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,WAAW,GAAgB;YAC/B,GAAG,OAAO;YACV,OAAO,EAAE;gBACP,KAAK,EAAE,KAAK;gBACZ,GAAG,OAAO;gBACV,cAAc,EAAE,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;aAC7E;YACD,kGAAkG;YAClG,QAAQ,EAAE,OAAO,CAAC,WAAW,EAAE;SAChC,CAAC;QAEF,OAAO;YACL,wBAAwB;YACxB,6BAA6B;YAC7B,4BAA4B;YAC5B,mCAAmC;YACnC,eAAe;YACf,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC;YACnE,sBAAsB;YACtB,gBAAgB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC;YAClE,8BAA8B;YAC9B,yBAAyB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC;YAC3E,4BAA4B;YAC5B,mCAAmC;YACnC,sBAAsB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC;YACxE,sBAAsB;YACtB,6BAA6B;YAC7B,oBAAoB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC;YACtE,iBAAiB;YACjB,yBAAyB;YACzB,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC;SACjE,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,SAAS,mBAAmB,CAAC,OAAoB,EAAE,IAAoB;IACrE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAA,mDAAwB,EAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,CAAC,CAAC,QAAQ,IAAI,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,iBAAiB;IAC3B,CAAC;IAED,+DAA+D;IAC/D,wFAAwF;IACxF,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,CAAC;IAEzC,kFAAkF;IAClF,yFAAyF;IACzF,mFAAmF;IACnF,+EAA+E;IAC/E,iEAAiE;IACjE,mBAAmB;IACnB,mEAAmE;IACnE,8EAA8E;IAC9E,4EAA4E;IAC5E,IAAI,UAAiF,CAAC;IACtF;IACE,gCAAgC;IAChC,CAAC,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,iBAAiB,CAAC;QACrF,iCAAiC;QACjC,CAAC,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,0BAA0B,CAAC;QAC9F,kCAAkC;QAClC,IAAI,CAAC,IAAI,KAAK,2BAA2B;QACzC,gCAAgC;QAChC,IAAI,CAAC,IAAI,KAAK,wBAAwB,EACtC,CAAC;QACD,UAAU,GAAG;YACX,SAAS,EAAE,gBAAgB;YAC3B,IAAI;YACJ,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CACb,KAAK,CAAC,gBAAgB;YACpB,kBAAkB;YAClB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAC9C,IAAI,CAAC,WAAW,CACjB;SACJ,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAM,CAAC;QACb,IAAI,EAAE,QAAQ;QACd,SAAS;QACT,IAAI;QACJ,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,OAAoB,EAAE,UAAkB;IAC/D,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAE3C,MAAM,WAAW,GAAG,IAAA,6CAAqB,EAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACtE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,sDAAsD;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;IAE7C,wEAAwE;IACxE,MAAM,UAAU,GAAG,IAAA,+BAAc,EAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3E,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACxD,mFAAmF;QACnF,6DAA6D;QAC7D,iDAAiD;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0EAA0E;IAC1E,gGAAgG;IAChG,4FAA4F;IAC5F,uCAAuC;IACvC,MAAM,eAAe,GAAG,IAAA,uCAAkB,EAAC,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChG,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,yBAAyB;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kCAAkC;IAClC,MAAM,SAAS,GAAG,IAAA,+BAAc,EAAC,eAAe,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,6DAA6D;QAC7D,OAAO;YACL,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW;YAC7D,OAAO,EAAE,OAAO;YAChB,WAAW;SACZ,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,IAAI,CAAC,IAAA,+CAAsB,EAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QAC7D,OAAO;YACL,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,aAAa;YACjE,OAAO,EAAE,OAAO;YAChB,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport { getImportPathLiteralNode, type ImportLikeNode } from '../utils/getImportPathLiteralNode';\nimport { getPackageInfo } from '../utils/getPackageInfo';\nimport { parseImportIfRelevant } from '../utils/parseImportIfRelevant';\nimport { pathSatisfiesAnyExport } from '../utils/pathSatisfiesAnyExport';\nimport { resolvePackageRoot } from '../utils/resolvePackageRoot';\n\n/** Processed rule options */\ntype RuleOptions = {\n ignorePatterns: RegExp[];\n debug: boolean;\n};\n\n/** Rule options as specified in the config */\nexport type RawRuleOptions = Omit<Partial<RuleOptions>, 'ignorePatterns'> & {\n ignorePatterns?: string[];\n};\n\ntype RuleContext = Omit<RawRuleContext, 'options'> & {\n options: RuleOptions;\n filename: string;\n};\n\nexport type ErrorMessageIds = 'noExports' | 'noExportsLocal' | 'notExported' | 'notExportedLocal';\nexport type SuggestMessageIds = 'useTopLevel';\nexport type MessageIds = ErrorMessageIds | SuggestMessageIds;\n\nexport type ErrorData = {\n packageName: string;\n subPath: string;\n};\n\ntype ErrorResult = ErrorData & {\n messageId: ErrorMessageIds;\n};\n\ntype RawRuleContext = TSESLint.RuleContext<MessageIds, RawRuleOptions[]>;\n\nconst defaultOptions: RawRuleOptions = {\n ignorePatterns: [],\n debug: false,\n};\n\nconst preferTopLevel = 'prefer importing directly from \"{{packageName}}\" if possible';\nconst noExports = '\"{{packageName}}\" doesn\\'t have an exports map, so deep imports aren\\'t allowed; ' + preferTopLevel;\nconst notExported =\n 'Path \"{{subPath}}\" is not exported by \"{{packageName}}\", according to its exports map; ' + preferTopLevel;\nconst localMessage =\n '(Consider updating \"{{packageName}}\" to export additional identifiers if needed, ' +\n 'or if deep imports are strictly necessary, add an exports map.)';\n\nconst messages: Record<MessageIds, string> = {\n noExports,\n noExportsLocal: `${noExports}. ${localMessage}`,\n notExported,\n notExportedLocal: `${notExported}. ${localMessage}`,\n useTopLevel: 'Import directly from \"{{packageName}}\", if possible',\n};\n\nconst suggestMessageId: SuggestMessageIds = 'useTopLevel';\n\nexport const rule: TSESLint.RuleModule<MessageIds, RawRuleOptions[]> = {\n defaultOptions: [defaultOptions],\n meta: {\n type: 'problem',\n docs: {\n description: 'ban importing from non-exported paths',\n recommended: 'recommended',\n },\n hasSuggestions: true,\n messages,\n schema: [\n {\n type: 'object',\n properties: {\n ignorePatterns: {\n type: 'array',\n description: 'Ignore imports matching these regular expression patterns.',\n items: { type: 'string' },\n },\n debug: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n ],\n },\n create: (context) => {\n const options = context.options?.[0] || {};\n const ruleContext: RuleContext = {\n ...context,\n options: {\n debug: false,\n ...options,\n ignorePatterns: (options.ignorePatterns || []).map((str) => new RegExp(str)),\n },\n // eslint-disable-next-line etc/no-deprecated -- filename property doesn't appear to exist yet...?\n filename: context.getFilename(),\n };\n\n return {\n // import foo from 'foo'\n // import * as foo from 'foo'\n // import { foo } from 'foo'\n // import { foo as bar } from 'foo'\n // import 'foo'\n ImportDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // await import('foo')\n ImportExpression: (node) => checkImportOrExport(ruleContext, node),\n // import foo = require('foo')\n TSImportEqualsDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // export { foo } from 'foo'\n // export { foo as bar } from 'foo'\n ExportNamedDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // export * from 'foo'\n // export * as foo from 'foo'\n ExportAllDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // require('foo')\n // require.resolve('foo')\n CallExpression: (node) => checkImportOrExport(ruleContext, node),\n };\n },\n};\n\nfunction checkImportOrExport(context: RuleContext, node: ImportLikeNode) {\n const { importPath, pathNode } = getImportPathLiteralNode(node) || {};\n if (!(pathNode && importPath)) {\n return;\n }\n\n const errorData = checkImportPath(context, importPath);\n if (!errorData) {\n return; // Import is fine\n }\n\n // At this point, the import is probably invalid, so report it.\n // (Might still be a false positive if it's a local package that hasn't been built yet.)\n const { messageId, ...data } = errorData;\n\n // For named imports/exports or import *, suggest importing from the package root.\n // This is just a suggestion, so it doesn't have to be correct, but we also want to avoid\n // suggesting when it's likely to be misleading or might cause issues; for example:\n // - Default imports may refer to an actual default export or the entire module\n // - Side effect imports are likely specific to a particular file\n // - Async import()\n // - export * from an entire package might export a lot more things\n // - require() could be used in many ways (would have to look at more context)\n // - require.resolve() is typically used to find the path to a specific file\n let suggestion: TSESLint.ReportSuggestionArray<SuggestMessageIds>[number] | undefined;\n if (\n // import { foo } from 'foo/bar'\n (node.type === 'ImportDeclaration' && node.specifiers[0]?.type === 'ImportSpecifier') ||\n // import * as foo from 'foo/bar'\n (node.type === 'ImportDeclaration' && node.specifiers[0]?.type === 'ImportNamespaceSpecifier') ||\n // import foo = require('foo/bar')\n node.type === 'TSImportEqualsDeclaration' ||\n // export { foo } from 'foo/bar'\n node.type === 'ExportNamedDeclaration'\n ) {\n suggestion = {\n messageId: suggestMessageId,\n data,\n fix: (fixer) =>\n fixer.replaceTextRange(\n // Keep the quotes\n [pathNode.range[0] + 1, pathNode.range[1] - 1],\n data.packageName,\n ),\n };\n }\n\n context.report({\n node: pathNode,\n messageId,\n data,\n suggest: suggestion ? [suggestion] : undefined,\n });\n}\n\nfunction checkImportPath(context: RuleContext, importPath: string): ErrorResult | null {\n const { ignorePatterns } = context.options;\n\n const importParts = parseImportIfRelevant(importPath, ignorePatterns);\n if (!importParts) {\n // Import is relative, top-level, built-in, or ignored\n return null;\n }\n const { packageName, subPath } = importParts;\n\n // Find the root of the current file's package and read its package.json\n const currentPkg = getPackageInfo(context.filename, context.options.debug);\n if (!currentPkg || currentPkg.json.name === packageName) {\n // - If package.json for the current file's package wasn't found, ignore the import\n // (getPackageInfo already logged a debug message about it)\n // - If the import is a self-reference, ignore it\n return null;\n }\n\n // Resolve packageName's top-level import so we can find the package.json.\n // (This resolution must be done in the context of the current package in case eslint is running\n // in a different directory, e.g. monorepo root, where the package may not be installed or a\n // different version may be installed.)\n const resolvedPkgRoot = resolvePackageRoot(currentPkg.path, packageName, context.options.debug);\n if (!resolvedPkgRoot) {\n // Maybe an optional dep?\n return null;\n }\n\n // Read packageName's package.json\n const importPkg = getPackageInfo(resolvedPkgRoot, context.options.debug);\n if (!importPkg) {\n return null;\n }\n\n if (!importPkg.json.exports) {\n // Deep imports are always an error if there's no exports map\n return {\n messageId: importPkg.isLocal ? 'noExportsLocal' : 'noExports',\n subPath: subPath,\n packageName,\n };\n }\n\n // Check if subPath matches any paths from exports (disregarding conditions)\n if (!pathSatisfiesAnyExport(importPkg.json.exports, subPath)) {\n return {\n messageId: importPkg.isLocal ? 'notExportedLocal' : 'notExported',\n subPath: subPath,\n packageName,\n };\n }\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"no-unsupported-imports.js","sourceRoot":"","sources":["../../src/rules/no-unsupported-imports.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TSESLint } from '@typescript-eslint/utils';\nimport { getImportPathLiteralNode, type ImportLikeNode } from '../utils/getImportPathLiteralNode';\nimport { getPackageInfo } from '../utils/getPackageInfo';\nimport { parseImportIfRelevant } from '../utils/unsupportedImports/parseImportIfRelevant';\nimport { pathSatisfiesAnyExport } from '../utils/unsupportedImports/pathSatisfiesAnyExport';\nimport { resolvePackageRoot } from '../utils/unsupportedImports/resolvePackageRoot';\nimport { getRegexpsFromStrings } from '../utils/getRegexpsFromStrings';\n\n/** Processed rule options */\ntype RuleOptions = {\n ignorePatterns: RegExp[];\n debug: boolean;\n};\n\n/** Rule options as specified in the config */\nexport type RawRuleOptions = Omit<Partial<RuleOptions>, 'ignorePatterns'> & {\n ignorePatterns?: string[];\n};\n\ntype RuleContext = Omit<RawRuleContext, 'options'> & {\n options: RuleOptions;\n filename: string;\n};\n\nexport type ErrorMessageIds = 'noExports' | 'noExportsLocal' | 'notExported' | 'notExportedLocal';\nexport type SuggestMessageIds = 'useTopLevel';\nexport type MessageIds = ErrorMessageIds | SuggestMessageIds;\n\ntype ErrorData = {\n packageName: string;\n subPath: string;\n};\n\ntype ErrorResult = ErrorData & {\n messageId: ErrorMessageIds;\n};\n\ntype RawRuleContext = TSESLint.RuleContext<MessageIds, RawRuleOptions[]>;\n\nconst defaultOptions: RawRuleOptions = {\n ignorePatterns: [],\n debug: false,\n};\n\nconst preferTopLevel = 'prefer importing directly from \"{{packageName}}\" if possible';\nconst noExports = '\"{{packageName}}\" doesn\\'t have an exports map, so deep imports aren\\'t allowed; ' + preferTopLevel;\nconst notExported =\n 'Path \"{{subPath}}\" is not exported by \"{{packageName}}\", according to its exports map; ' + preferTopLevel;\nconst localMessage =\n '(Consider updating \"{{packageName}}\" to export additional identifiers if needed, ' +\n 'or if deep imports are strictly necessary, add an exports map.)';\n\nconst messages: Record<MessageIds, string> = {\n noExports,\n noExportsLocal: `${noExports}. ${localMessage}`,\n notExported,\n notExportedLocal: `${notExported}. ${localMessage}`,\n useTopLevel: 'Import directly from \"{{packageName}}\", if possible',\n};\n\nconst suggestMessageId: SuggestMessageIds = 'useTopLevel';\n\nexport const rule: TSESLint.RuleModule<MessageIds, RawRuleOptions[]> = {\n defaultOptions: [defaultOptions],\n meta: {\n type: 'problem',\n docs: {\n description: 'ban importing from non-exported paths',\n recommended: 'recommended',\n },\n hasSuggestions: true,\n messages,\n schema: [\n {\n type: 'object',\n properties: {\n ignorePatterns: {\n type: 'array',\n description: 'Ignore imports matching these regular expression patterns.',\n items: { type: 'string' },\n },\n debug: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n ],\n },\n create: (context) => {\n const options = context.options?.[0] || {};\n const ruleContext: RuleContext = {\n ...context,\n options: {\n debug: false,\n ...options,\n ignorePatterns: getRegexpsFromStrings(options.ignorePatterns),\n },\n // eslint-disable-next-line etc/no-deprecated -- filename property doesn't appear to exist yet...?\n filename: context.getFilename(),\n };\n\n return {\n // import foo from 'foo'\n // import * as foo from 'foo'\n // import { foo } from 'foo'\n // import { foo as bar } from 'foo'\n // import 'foo'\n ImportDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // await import('foo')\n ImportExpression: (node) => checkImportOrExport(ruleContext, node),\n // import foo = require('foo')\n TSImportEqualsDeclaration: (node) => {\n // Skip \"export import foo = require('foo')\" because that will be handled by ExportNamedDeclaration\n if (node.parent.type !== 'ExportNamedDeclaration') {\n checkImportOrExport(ruleContext, node);\n }\n },\n // export { foo } from 'foo'\n // export { foo as bar } from 'foo'\n ExportNamedDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // export * from 'foo'\n // export * as foo from 'foo'\n ExportAllDeclaration: (node) => checkImportOrExport(ruleContext, node),\n // require('foo')\n // require.resolve('foo')\n CallExpression: (node) => checkImportOrExport(ruleContext, node),\n };\n },\n};\n\nfunction checkImportOrExport(context: RuleContext, node: ImportLikeNode) {\n const { importPath, pathNode } = getImportPathLiteralNode(node) || {};\n if (!(pathNode && importPath)) {\n return;\n }\n\n const errorData = checkImportPath(context, importPath);\n if (!errorData) {\n return; // Import is fine\n }\n\n // At this point, the import is probably invalid, so report it.\n // (Might still be a false positive if it's a local package that hasn't been built yet.)\n const { messageId, ...data } = errorData;\n\n // For named imports/exports or import *, suggest importing from the package root.\n // This is just a suggestion, so it doesn't have to be correct, but we also want to avoid\n // suggesting when it's likely to be misleading or might cause issues; for example:\n // - Default imports may refer to an actual default export or the entire module\n // - Side effect imports are likely specific to a particular file\n // - Async import()\n // - export * from an entire package might export a lot more things\n // - require() could be used in many ways (would have to look at more context)\n // - require.resolve() is typically used to find the path to a specific file\n let suggestion: TSESLint.ReportSuggestionArray<SuggestMessageIds>[number] | undefined;\n if (\n // import { foo } from 'foo/bar'\n (node.type === 'ImportDeclaration' && node.specifiers[0]?.type === 'ImportSpecifier') ||\n // import * as foo from 'foo/bar'\n (node.type === 'ImportDeclaration' && node.specifiers[0]?.type === 'ImportNamespaceSpecifier') ||\n // import foo = require('foo/bar')\n node.type === 'TSImportEqualsDeclaration' ||\n // export { foo } from 'foo/bar'\n node.type === 'ExportNamedDeclaration'\n ) {\n suggestion = {\n messageId: suggestMessageId,\n data,\n fix: (fixer) =>\n fixer.replaceTextRange(\n // Keep the quotes\n [pathNode.range[0] + 1, pathNode.range[1] - 1],\n data.packageName,\n ),\n };\n }\n\n context.report({\n node: pathNode,\n messageId,\n data,\n suggest: suggestion ? [suggestion] : undefined,\n });\n}\n\nfunction checkImportPath(context: RuleContext, importPath: string): ErrorResult | null {\n const { ignorePatterns } = context.options;\n\n const importParts = parseImportIfRelevant(importPath, ignorePatterns);\n if (!importParts) {\n // Import is relative, top-level, built-in, or ignored\n return null;\n }\n const { packageName, subPath } = importParts;\n\n // Find the root of the current file's package and read its package.json\n const currentPkg = getPackageInfo(context.filename, context.options.debug);\n if (!currentPkg || currentPkg.json.name === packageName) {\n // - If package.json for the current file's package wasn't found, ignore the import\n // (getPackageInfo already logged a debug message about it)\n // - If the import is a self-reference, ignore it\n return null;\n }\n\n // Resolve packageName's top-level import so we can find the package.json.\n // (This resolution must be done in the context of the current package in case eslint is running\n // in a different directory, e.g. monorepo root, where the package may not be installed or a\n // different version may be installed.)\n const resolvedPkgRoot = resolvePackageRoot(currentPkg.path, packageName, context.options.debug);\n if (!resolvedPkgRoot) {\n // Maybe an optional dep?\n return null;\n }\n\n // Read packageName's package.json\n const importPkg = getPackageInfo(resolvedPkgRoot, context.options.debug);\n if (!importPkg) {\n return null;\n }\n\n if (!importPkg.json.exports) {\n // Deep imports are always an error if there's no exports map\n return {\n messageId: importPkg.isLocal ? 'noExportsLocal' : 'noExports',\n subPath: subPath,\n packageName,\n };\n }\n\n // Check if subPath matches any paths from exports (disregarding conditions)\n if (!pathSatisfiesAnyExport(importPkg.json.exports, subPath)) {\n return {\n messageId: importPkg.isLocal ? 'notExportedLocal' : 'notExported',\n subPath: subPath,\n packageName,\n };\n }\n return null;\n}\n"]}
|
|
@@ -12,5 +12,5 @@ export type PackageInfo = {
|
|
|
12
12
|
* package.json file) and read the package.json.
|
|
13
13
|
* @param startPath Search up starting from this file or directory
|
|
14
14
|
*/
|
|
15
|
-
export declare function getPackageInfo(startPath: string, debug
|
|
15
|
+
export declare function getPackageInfo(startPath: string, debug?: boolean): PackageInfo | null;
|
|
16
16
|
//# sourceMappingURL=getPackageInfo.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPackageInfo.d.ts","sourceRoot":"","sources":["../../src/utils/getPackageInfo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"getPackageInfo.d.ts","sourceRoot":"","sources":["../../src/utils/getPackageInfo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAmDrF"}
|
|
@@ -10,10 +10,14 @@ const packageInfoCache = new Map();
|
|
|
10
10
|
* @param startPath Search up starting from this file or directory
|
|
11
11
|
*/
|
|
12
12
|
function getPackageInfo(startPath, debug) {
|
|
13
|
+
if (!path.isAbsolute(startPath) || !fs.existsSync(startPath)) {
|
|
14
|
+
// prevent unexpected results if a test or other code passes a relative or nonexistent path
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
13
17
|
// Use the realpath in case this is a linked package in a monorepo
|
|
14
18
|
startPath = fs.realpathSync(startPath);
|
|
15
19
|
const root = path.parse(startPath).root;
|
|
16
|
-
const startDir = fs.statSync(startPath).isDirectory() ? startPath : path.dirname(startPath);
|
|
20
|
+
const startDir = path.normalize(fs.statSync(startPath).isDirectory() ? startPath : path.dirname(startPath));
|
|
17
21
|
let dir = startDir;
|
|
18
22
|
let packageJsonPath = '';
|
|
19
23
|
let found = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPackageInfo.js","sourceRoot":"","sources":["../../src/utils/getPackageInfo.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AACzB,6BAA6B;AAY7B,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAC/D;;;;GAIG;AACH,SAAgB,cAAc,CAAC,SAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"getPackageInfo.js","sourceRoot":"","sources":["../../src/utils/getPackageInfo.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AACzB,6BAA6B;AAY7B,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAC/D;;;;GAIG;AACH,SAAgB,cAAc,CAAC,SAAiB,EAAE,KAAe;IAC/D,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7D,2FAA2F;QAC3F,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kEAAkE;IAClE,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;IAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAE5G,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,IAAI,eAAe,GAAG,EAAE,CAAC;IACzB,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,OAAO,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC3C,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QACjD,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACnC,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;QAC/E,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,WAAW,GAAuB,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAgB,CAAC;QACxF,WAAW,GAAG;YACZ,IAAI,EAAE,GAAG;YACT,iCAAiC;YACjC,OAAO,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5C,IAAI,EAAE,WAAW;SAClB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,4BAA4B,eAAe,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9E,CAAC;IACD,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACvC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC5C,OAAO,WAAW,CAAC;AACrB,CAAC;AAnDD,wCAmDC","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport type { PackageJson } from './PackageJson';\n\nexport type PackageInfo = {\n /** Path to the package root directory */\n path: string;\n /** Whether this is a package locally developed in the same monorepo */\n isLocal: boolean;\n /** package.json contents */\n json: PackageJson;\n};\n\nconst packageInfoCache = new Map<string, PackageInfo | null>();\n/**\n * Find the package root directory relative to the given file (based on the presence of a\n * package.json file) and read the package.json.\n * @param startPath Search up starting from this file or directory\n */\nexport function getPackageInfo(startPath: string, debug?: boolean): PackageInfo | null {\n if (!path.isAbsolute(startPath) || !fs.existsSync(startPath)) {\n // prevent unexpected results if a test or other code passes a relative or nonexistent path\n return null;\n }\n\n // Use the realpath in case this is a linked package in a monorepo\n startPath = fs.realpathSync(startPath);\n const root = path.parse(startPath).root;\n\n const startDir = path.normalize(fs.statSync(startPath).isDirectory() ? startPath : path.dirname(startPath));\n\n let dir = startDir;\n let packageJsonPath = '';\n let found = false;\n while (dir !== root && !found) {\n const cachedInfo = packageInfoCache.get(dir);\n if (cachedInfo !== undefined) {\n packageInfoCache.set(startDir, cachedInfo);\n return cachedInfo;\n }\n\n packageJsonPath = path.join(dir, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n found = true;\n } else {\n dir = path.dirname(dir);\n }\n }\n\n if (!found) {\n debug && console.error(`no package.json found searching up from ${startPath}`);\n packageInfoCache.set(startDir, null);\n return null;\n }\n\n let packageInfo: PackageInfo | null = null;\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as PackageJson;\n packageInfo = {\n path: dir,\n // TODO may not work with yarn 3?\n isLocal: !/[\\\\/]node_modules[\\\\/]/.test(dir),\n json: packageJson,\n };\n } catch (err) {\n debug && console.error(`error reading or parsing ${packageJsonPath}:`, err);\n }\n packageInfoCache.set(dir, packageInfo);\n packageInfoCache.set(startDir, packageInfo);\n return packageInfo;\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get an array of regular expressions from an array of strings, replacing the `...` string with
|
|
3
|
+
* the default values (if provided). If `strs` is undefined, returns `defaults` or an empty array.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getRegexpsFromStrings(strs: string[] | undefined, defaults?: RegExp[]): RegExp[];
|
|
6
|
+
//# sourceMappingURL=getRegexpsFromStrings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRegexpsFromStrings.d.ts","sourceRoot":"","sources":["../../src/utils/getRegexpsFromStrings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,QAAQ,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAEnG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRegexpsFromStrings = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Get an array of regular expressions from an array of strings, replacing the `...` string with
|
|
6
|
+
* the default values (if provided). If `strs` is undefined, returns `defaults` or an empty array.
|
|
7
|
+
*/
|
|
8
|
+
function getRegexpsFromStrings(strs, defaults = []) {
|
|
9
|
+
return strs?.map((str) => (str === '...' ? defaults : new RegExp(str))).flat() || defaults;
|
|
10
|
+
}
|
|
11
|
+
exports.getRegexpsFromStrings = getRegexpsFromStrings;
|
|
12
|
+
//# sourceMappingURL=getRegexpsFromStrings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRegexpsFromStrings.js","sourceRoot":"","sources":["../../src/utils/getRegexpsFromStrings.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,IAA0B,EAAE,WAAqB,EAAE;IACvF,OAAO,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC;AAC7F,CAAC;AAFD,sDAEC","sourcesContent":["/**\n * Get an array of regular expressions from an array of strings, replacing the `...` string with\n * the default values (if provided). If `strs` is undefined, returns `defaults` or an empty array.\n */\nexport function getRegexpsFromStrings(strs: string[] | undefined, defaults: RegExp[] = []): RegExp[] {\n return strs?.map((str) => (str === '...' ? defaults : new RegExp(str))).flat() || defaults;\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Extract identifiers from an export declaration.
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractIdentifiersFromExport(node: TSESTree.ExportAllDeclaration | TSESTree.ExportNamedDeclaration): TSESTree.Identifier[];
|
|
6
|
+
//# sourceMappingURL=extractIdentifiersFromExport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractIdentifiersFromExport.d.ts","sourceRoot":"","sources":["../../../src/utils/testExports/extractIdentifiersFromExport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,QAAQ,CAAC,oBAAoB,GAAG,QAAQ,CAAC,sBAAsB,GACpE,QAAQ,CAAC,UAAU,EAAE,CAkDvB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractIdentifiersFromExport = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Extract identifiers from an export declaration.
|
|
6
|
+
*/
|
|
7
|
+
function extractIdentifiersFromExport(node) {
|
|
8
|
+
if (node.type === 'ExportAllDeclaration') {
|
|
9
|
+
// export * as foo from 'foo'
|
|
10
|
+
return node.exported ? [node.exported] : [];
|
|
11
|
+
}
|
|
12
|
+
if (node.specifiers.length) {
|
|
13
|
+
// export { a, b }
|
|
14
|
+
// export { a, b } from 'foo'
|
|
15
|
+
return node.specifiers.map((s) => s.exported);
|
|
16
|
+
}
|
|
17
|
+
if (node.declaration && node.declaration?.type !== 'VariableDeclaration') {
|
|
18
|
+
// export import foo = require('foo')
|
|
19
|
+
// also class, function, type, interface...
|
|
20
|
+
return node.declaration.id?.type === 'Identifier' ? [node.declaration.id] : [];
|
|
21
|
+
}
|
|
22
|
+
const ids = [];
|
|
23
|
+
const declarations = node.declaration?.declarations || [];
|
|
24
|
+
for (const decl of declarations) {
|
|
25
|
+
if (decl.id.type === 'Identifier') {
|
|
26
|
+
// export const foo = 'foo'
|
|
27
|
+
ids.push(decl.id);
|
|
28
|
+
}
|
|
29
|
+
else if (decl.id.type === 'ArrayPattern') {
|
|
30
|
+
// Unlikely array destructuring export (ignore any nested variants)
|
|
31
|
+
// export const [foo, bar] = ['foo', 'bar']
|
|
32
|
+
for (const elem of decl.id.elements) {
|
|
33
|
+
if (elem?.type === 'Identifier') {
|
|
34
|
+
ids.push(elem);
|
|
35
|
+
}
|
|
36
|
+
else if (elem?.type === 'RestElement' && elem.argument.type === 'Identifier') {
|
|
37
|
+
ids.push(elem.argument);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Unlikely object destructuring export (ignore any nested variants)
|
|
43
|
+
// export const { foo, bar } = { foo: 'foo', bar: 'bar' }
|
|
44
|
+
for (const prop of decl.id.properties) {
|
|
45
|
+
if (prop.type === 'Property' && prop.value.type === 'Identifier') {
|
|
46
|
+
// .value instead of .key handles renaming and prevents including non-exported nested keys
|
|
47
|
+
ids.push(prop.value);
|
|
48
|
+
}
|
|
49
|
+
else if (prop.type === 'RestElement' && prop.argument.type === 'Identifier') {
|
|
50
|
+
ids.push(prop.argument);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return ids;
|
|
56
|
+
}
|
|
57
|
+
exports.extractIdentifiersFromExport = extractIdentifiersFromExport;
|
|
58
|
+
//# sourceMappingURL=extractIdentifiersFromExport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractIdentifiersFromExport.js","sourceRoot":"","sources":["../../../src/utils/testExports/extractIdentifiersFromExport.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,SAAgB,4BAA4B,CAC1C,IAAqE;IAErE,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;QACzC,6BAA6B;QAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QAC3B,kBAAkB;QAClB,6BAA6B;QAC7B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,KAAK,qBAAqB,EAAE,CAAC;QACzE,qCAAqC;QACrC,2CAA2C;QAC3C,OAAO,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,GAAG,GAA0B,EAAE,CAAC;IACtC,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,IAAI,EAAE,CAAC;IAE1D,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAClC,2BAA2B;YAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC3C,mEAAmE;YACnE,2CAA2C;YAC3C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;gBACpC,IAAI,IAAI,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;oBAChC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjB,CAAC;qBAAM,IAAI,IAAI,EAAE,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAC/E,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,oEAAoE;YACpE,yDAAyD;YACzD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;gBACtC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACjE,0FAA0F;oBAC1F,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACvB,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAC9E,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AApDD,oEAoDC","sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\n\n/**\n * Extract identifiers from an export declaration.\n */\nexport function extractIdentifiersFromExport(\n node: TSESTree.ExportAllDeclaration | TSESTree.ExportNamedDeclaration,\n): TSESTree.Identifier[] {\n if (node.type === 'ExportAllDeclaration') {\n // export * as foo from 'foo'\n return node.exported ? [node.exported] : [];\n }\n\n if (node.specifiers.length) {\n // export { a, b }\n // export { a, b } from 'foo'\n return node.specifiers.map((s) => s.exported);\n }\n\n if (node.declaration && node.declaration?.type !== 'VariableDeclaration') {\n // export import foo = require('foo')\n // also class, function, type, interface...\n return node.declaration.id?.type === 'Identifier' ? [node.declaration.id] : [];\n }\n\n const ids: TSESTree.Identifier[] = [];\n const declarations = node.declaration?.declarations || [];\n\n for (const decl of declarations) {\n if (decl.id.type === 'Identifier') {\n // export const foo = 'foo'\n ids.push(decl.id);\n } else if (decl.id.type === 'ArrayPattern') {\n // Unlikely array destructuring export (ignore any nested variants)\n // export const [foo, bar] = ['foo', 'bar']\n for (const elem of decl.id.elements) {\n if (elem?.type === 'Identifier') {\n ids.push(elem);\n } else if (elem?.type === 'RestElement' && elem.argument.type === 'Identifier') {\n ids.push(elem.argument);\n }\n }\n } else {\n // Unlikely object destructuring export (ignore any nested variants)\n // export const { foo, bar } = { foo: 'foo', bar: 'bar' }\n for (const prop of decl.id.properties) {\n if (prop.type === 'Property' && prop.value.type === 'Identifier') {\n // .value instead of .key handles renaming and prevents including non-exported nested keys\n ids.push(prop.value);\n } else if (prop.type === 'RestElement' && prop.argument.type === 'Identifier') {\n ids.push(prop.argument);\n }\n }\n }\n }\n\n return ids;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether the given file is an index file, is not under an ignored path, and is not
|
|
3
|
+
* nested too deep in the package.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isIncludedIndexFile(params: {
|
|
6
|
+
filename: string;
|
|
7
|
+
ignorePaths: RegExp[];
|
|
8
|
+
maxDepth: number;
|
|
9
|
+
}): boolean;
|
|
10
|
+
//# sourceMappingURL=isIncludedIndexFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isIncludedIndexFile.d.ts","sourceRoot":"","sources":["../../../src/utils/testExports/isIncludedIndexFile.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAoBlH"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isIncludedIndexFile = void 0;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const getPackageInfo_js_1 = require("../getPackageInfo.js");
|
|
6
|
+
/**
|
|
7
|
+
* Checks whether the given file is an index file, is not under an ignored path, and is not
|
|
8
|
+
* nested too deep in the package.
|
|
9
|
+
*/
|
|
10
|
+
function isIncludedIndexFile(params) {
|
|
11
|
+
const { filename, ignorePaths, maxDepth } = params;
|
|
12
|
+
// ignore non index files
|
|
13
|
+
if (!filename || !/^index\.[cm]?[jt]sx?$/.test(path.basename(filename))) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const packageInfo = (0, getPackageInfo_js_1.getPackageInfo)(filename);
|
|
17
|
+
if (packageInfo) {
|
|
18
|
+
const relativePath = path.normalize(filename).replace(packageInfo.path, '').slice(1).replace(/\\/g, '/');
|
|
19
|
+
// Ignore index files that are too deep, or if the relative path (within the package)
|
|
20
|
+
// matches an ignore path
|
|
21
|
+
if (relativePath.split('/').length > maxDepth + 1 || ignorePaths.some((re) => re.test('./' + relativePath))) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
exports.isIncludedIndexFile = isIncludedIndexFile;
|
|
28
|
+
//# sourceMappingURL=isIncludedIndexFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isIncludedIndexFile.js","sourceRoot":"","sources":["../../../src/utils/testExports/isIncludedIndexFile.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,4DAAsD;AAEtD;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,MAAqE;IACvG,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAEnD,yBAAyB;IACzB,IAAI,CAAC,QAAQ,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,IAAA,kCAAc,EAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAEzG,qFAAqF;QACrF,yBAAyB;QACzB,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,QAAQ,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,CAAC;YAC5G,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AApBD,kDAoBC","sourcesContent":["import * as path from 'path';\nimport { getPackageInfo } from '../getPackageInfo.js';\n\n/**\n * Checks whether the given file is an index file, is not under an ignored path, and is not\n * nested too deep in the package.\n */\nexport function isIncludedIndexFile(params: { filename: string; ignorePaths: RegExp[]; maxDepth: number }): boolean {\n const { filename, ignorePaths, maxDepth } = params;\n\n // ignore non index files\n if (!filename || !/^index\\.[cm]?[jt]sx?$/.test(path.basename(filename))) {\n return false;\n }\n\n const packageInfo = getPackageInfo(filename);\n if (packageInfo) {\n const relativePath = path.normalize(filename).replace(packageInfo.path, '').slice(1).replace(/\\\\/g, '/');\n\n // Ignore index files that are too deep, or if the relative path (within the package)\n // matches an ignore path\n if (relativePath.split('/').length > maxDepth + 1 || ignorePaths.some((re) => re.test('./' + relativePath))) {\n return false;\n }\n }\n\n return true;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseImportIfRelevant.d.ts","sourceRoot":"","sources":["../../../src/utils/unsupportedImports/parseImportIfRelevant.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBjD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM;;;EAO7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseImportIfRelevant.js","sourceRoot":"","sources":["../../../src/utils/unsupportedImports/parseImportIfRelevant.ts"],"names":[],"mappings":";;;AAAA,mCAAwC;AAExC;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,UAAkB,EAClB,cAAwB;IAExB,mCAAmC;IACnC,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEvD,qEAAqE;IACrE,+DAA+D;IAC/D,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,uBAAc,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAChG,8CAA8C;QAC9C,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;QAEjE,gEAAgE;QAChE,IAAI,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC;YACrE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AApBD,sDAoBC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,QAAgB;IAC5C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IAElE,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5D,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAPD,sCAOC","sourcesContent":["import { builtinModules } from 'module';\n\n/**\n * Verify that the import is relevant for the very specific purposes of the `no-unsupported-imports` rule,\n * and if so, find the package name and sub-path.\n */\nexport function parseImportIfRelevant(\n importPath: string,\n ignorePatterns: RegExp[],\n): { packageName: string; subPath: string } | null {\n // Remove any webpack loader prefix\n // (* is greedy, so it will work even if multiple loaders are specified)\n const normalizedImport = importPath.replace(/.*!/, '');\n\n // Ignore relative imports, internal imports, builtins, and data URLs\n // (builtinModules includes valid sub-paths like \"fs/promises\")\n if (!/^([.#]|node:|data:)/.test(normalizedImport) && !builtinModules.includes(normalizedImport)) {\n // Find the package name and sub-path (if any)\n const { packageName, subPath } = parseModuleId(normalizedImport);\n\n // Ignore top-level imports, or anything from an ignored package\n if (subPath && !ignorePatterns.some((r) => r.test(normalizedImport))) {\n return { packageName, subPath };\n }\n }\n return null;\n}\n\n/**\n * Parse a module ID which is assumed to point to an actual file in a package (no loader prefixes,\n * relative paths, node builtins, or data URIs).\n * @returns Package name and sub-path (if any). Sub-path does *not* include a leading `./`,\n * e.g. `@foo/bar/baz` returns `{ packageName: '@foo/bar', subPath: 'baz' }`.\n */\nexport function parseModuleId(moduleId: string) {\n const nameParts = moduleId.split('/');\n const hasScope = nameParts.length >= 2 && nameParts[0][0] === '@';\n\n const packageName = hasScope ? `${nameParts[0]}/${nameParts[1]}` : nameParts[0];\n const subPath = nameParts.slice(hasScope ? 2 : 1).join('/');\n return { packageName, subPath };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathSatisfiesAnyExport.d.ts","sourceRoot":"","sources":["../../../src/utils/unsupportedImports/pathSatisfiesAnyExport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,cAAc,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,WA8BnG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathSatisfiesAnyExport.js","sourceRoot":"","sources":["../../../src/utils/unsupportedImports/pathSatisfiesAnyExport.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACH,SAAgB,sBAAsB,CAAC,UAAsC,EAAE,aAAqB;IAClG,wEAAwE;IACxE,oEAAoE;IACpE,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,aAAa,GAAG,KAAK,aAAa,EAAE,CAAC;IAErC,OAAO;IACL,yFAAyF;IACzF,kFAAkF;IAClF,mDAAmD;IAClD,UAAsC,CAAC,aAAa,CAAC,KAAK,IAAI;QAC/D,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACnC,wCAAwC;YACxC,yEAAyE;YACzE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAClC,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC/F,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;YACD,oDAAoD;YACpD,OAAO,GAAG,KAAK,aAAa,CAAC;QAC/B,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AA9BD,wDA8BC","sourcesContent":["import type { PackageExports } from '../PackageJson.js';\n\n/**\n * Determine whether `importSubPath` might satisfy any sub-path from the exports map,\n * disregarding conditions and file existence.\n * @param importSubPath Sub-path such as `lib/foo`\n */\nexport function pathSatisfiesAnyExport(exportsMap: PackageExports | undefined, importSubPath: string) {\n // If the exports map is a string, it's a shorthand for a single export.\n // If it's an array, the contents are fallbacks for a single export.\n if (!exportsMap || typeof exportsMap === 'string' || Array.isArray(exportsMap)) {\n return false;\n }\n\n importSubPath = `./${importSubPath}`;\n\n return (\n // Check for very basic exclusions. (Technically a path could also be excluded by setting\n // a condition to null, or by setting a later wildcard to override an earlier one.\n // Handling for this can be added later if needed.)\n (exportsMap as Record<string, unknown>)[importSubPath] !== null &&\n Object.keys(exportsMap).some((key) => {\n // . is the root import, not a sub-path.\n // Starting character other than . means this is a condition, not a path.\n if (key === '.' || key[0] !== '.') {\n return false;\n }\n if (key.includes('*')) {\n return new RegExp(`^${key.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*')}$`).test(importSubPath);\n }\n if (key.endsWith('/')) {\n return importSubPath.startsWith(key);\n }\n // Check if the path is a literal match for this key\n return key === importSubPath;\n })\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePackageRoot.d.ts","sourceRoot":"","sources":["../../../src/utils/unsupportedImports/resolvePackageRoot.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyBtG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePackageRoot.js","sourceRoot":"","sources":["../../../src/utils/unsupportedImports/resolvePackageRoot.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,oCAAoC;AAEpC,sCAAsC;AACtC,0CAA0C;AAC1C,0CAA0C;AAC1C,8BAA8B;AAC9B,kGAAkG;AAClG,gGAAgG;AAChG,mFAAmF;AACnF,2BAA2B;AAC3B,MAAM,WAAW,GAAyB,QAAQ,CAAC,IAAI,IAAK,QAAgB,CAAC,OAAO,EAAE,IAAI,CAAC;AAE3F,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAE,EAAE,CAAC,GAAG,OAAO,KAAK,WAAW,EAAE,CAAC;AAC3F,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;AAEtD;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAAe,EAAE,WAAmB,EAAE,KAAc;IACrF,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,WAAW,GAAG,GAAG,WAAW,eAAe,CAAC;IAClD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACnG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,KAAK,EAAE,CAAC;YACV,2BAA2B;YAC3B,IAAK,GAAW,EAAE,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBAC9C,OAAO,CAAC,KAAK,CAAC,qBAAqB,WAAW,SAAS,OAAO,qBAAqB,CAAC,CAAC;YACvF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,qBAAqB,WAAW,SAAS,OAAO,KAAM,GAAa,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;YACtG,CAAC;QACH,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACrC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAzBD,gDAyBC","sourcesContent":["import * as path from 'path';\nimport * as _resolve from 'resolve';\n\n// 'resolve' index.js looks like this:\n// var async = require('./lib/async');\n// async.sync = require('./lib/sync');\n// module.exports = async;\n// This does not play nicely with at least one transpilation or interop step, possibly on specific\n// Node versions: `import * as resolve` *usually* gives the `resolve` function, but sometimes it\n// gives an object with property `default`... This is a workaround for either case.\n// eslint-disable-next-line\nconst resolveSync: typeof _resolve.sync = _resolve.sync || (_resolve as any).default?.sync;\n\nconst getCacheKey = (fromDir: string, packageName: string) => `${fromDir}::${packageName}`;\nconst resolveCache = new Map<string, string | null>();\n\n/**\n * Resolve the root directory of `packageName` starting from `fromDir`, with caching.\n * This uses the basic `resolve` package (which doesn't respect exports maps) to resolve\n * `${packageName}/package.json`, which should always exist.\n */\nexport function resolvePackageRoot(fromDir: string, packageName: string, debug: boolean): string | null {\n const cacheKey = getCacheKey(fromDir, packageName);\n const cached = resolveCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const resolvePath = `${packageName}/package.json`;\n let resolved: string | null = null;\n try {\n resolved = path.dirname(resolveSync(resolvePath, { basedir: fromDir, preserveSymlinks: false }));\n } catch (err) {\n if (debug) {\n // eslint-disable-next-line\n if ((err as any)?.code === 'MODULE_NOT_FOUND') {\n console.error(`Failed to resolve ${resolvePath} from ${fromDir} (module not found)`);\n } else {\n console.error(`Failed to resolve ${resolvePath} from ${fromDir}: ${(err as Error).message || err}`);\n }\n }\n }\n\n // Cache even if resolution failed so we don't waste time trying again\n resolveCache.set(cacheKey, resolved);\n return resolved;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ms-cloudpack/eslint-plugin",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"description": "A set of ESLint rules for Cloudpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@rnx-kit/eslint-plugin": "^0.6.0",
|
|
18
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
19
|
-
"@typescript-eslint/parser": "^6.
|
|
18
|
+
"@typescript-eslint/eslint-plugin": "^6.19.1",
|
|
19
|
+
"@typescript-eslint/parser": "^6.19.1",
|
|
20
20
|
"resolve": "^1.22.0"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseImportIfRelevant.d.ts","sourceRoot":"","sources":["../../src/utils/parseImportIfRelevant.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBjD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM;;;EAO7C"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseImportIfRelevant.js","sourceRoot":"","sources":["../../src/utils/parseImportIfRelevant.ts"],"names":[],"mappings":";;;AAAA,mCAAwC;AAExC;;;GAGG;AACH,SAAgB,qBAAqB,CACnC,UAAkB,EAClB,cAAwB;IAExB,mCAAmC;IACnC,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEvD,qEAAqE;IACrE,+DAA+D;IAC/D,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,uBAAc,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAChG,8CAA8C;QAC9C,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;QAEjE,gEAAgE;QAChE,IAAI,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC;YACrE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AApBD,sDAoBC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,QAAgB;IAC5C,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IAElE,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5D,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAPD,sCAOC","sourcesContent":["import { builtinModules } from 'module';\n\n/**\n * Verify that the import is relevant for the very specific purposes of the `no-unsupported-imports` rule,\n * and if so, find the package name and sub-path.\n */\nexport function parseImportIfRelevant(\n importPath: string,\n ignorePatterns: RegExp[],\n): { packageName: string; subPath: string } | null {\n // Remove any webpack loader prefix\n // (* is greedy, so it will work even if multiple loaders are specified)\n const normalizedImport = importPath.replace(/.*!/, '');\n\n // Ignore relative imports, internal imports, builtins, and data URLs\n // (builtinModules includes valid sub-paths like \"fs/promises\")\n if (!/^([.#]|node:|data:)/.test(normalizedImport) && !builtinModules.includes(normalizedImport)) {\n // Find the package name and sub-path (if any)\n const { packageName, subPath } = parseModuleId(normalizedImport);\n\n // Ignore top-level imports, or anything from an ignored package\n if (subPath && !ignorePatterns.some((r) => r.test(normalizedImport))) {\n return { packageName, subPath };\n }\n }\n return null;\n}\n\n/**\n * Parse a module ID which is assumed to point to an actual file in a package (no loader prefixes,\n * relative paths, node builtins, or data URIs).\n * @returns Package name and sub-path (if any). Sub-path does *not* include a leading `./`,\n * e.g. `@foo/bar/baz` returns `{ packageName: '@foo/bar', subPath: 'baz' }`.\n */\nexport function parseModuleId(moduleId: string) {\n const nameParts = moduleId.split('/');\n const hasScope = nameParts.length >= 2 && nameParts[0][0] === '@';\n\n const packageName = hasScope ? `${nameParts[0]}/${nameParts[1]}` : nameParts[0];\n const subPath = nameParts.slice(hasScope ? 2 : 1).join('/');\n return { packageName, subPath };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pathSatisfiesAnyExport.d.ts","sourceRoot":"","sources":["../../src/utils/pathSatisfiesAnyExport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,cAAc,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,WA8BnG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pathSatisfiesAnyExport.js","sourceRoot":"","sources":["../../src/utils/pathSatisfiesAnyExport.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACH,SAAgB,sBAAsB,CAAC,UAAsC,EAAE,aAAqB;IAClG,wEAAwE;IACxE,oEAAoE;IACpE,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,aAAa,GAAG,KAAK,aAAa,EAAE,CAAC;IAErC,OAAO;IACL,yFAAyF;IACzF,kFAAkF;IAClF,mDAAmD;IAClD,UAAsC,CAAC,aAAa,CAAC,KAAK,IAAI;QAC/D,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACnC,wCAAwC;YACxC,yEAAyE;YACzE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAClC,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC/F,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;YACD,oDAAoD;YACpD,OAAO,GAAG,KAAK,aAAa,CAAC;QAC/B,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AA9BD,wDA8BC","sourcesContent":["import type { PackageExports } from './PackageJson.js';\n\n/**\n * Determine whether `importSubPath` might satisfy any sub-path from the exports map,\n * disregarding conditions and file existence.\n * @param importSubPath Sub-path such as `lib/foo`\n */\nexport function pathSatisfiesAnyExport(exportsMap: PackageExports | undefined, importSubPath: string) {\n // If the exports map is a string, it's a shorthand for a single export.\n // If it's an array, the contents are fallbacks for a single export.\n if (!exportsMap || typeof exportsMap === 'string' || Array.isArray(exportsMap)) {\n return false;\n }\n\n importSubPath = `./${importSubPath}`;\n\n return (\n // Check for very basic exclusions. (Technically a path could also be excluded by setting\n // a condition to null, or by setting a later wildcard to override an earlier one.\n // Handling for this can be added later if needed.)\n (exportsMap as Record<string, unknown>)[importSubPath] !== null &&\n Object.keys(exportsMap).some((key) => {\n // . is the root import, not a sub-path.\n // Starting character other than . means this is a condition, not a path.\n if (key === '.' || key[0] !== '.') {\n return false;\n }\n if (key.includes('*')) {\n return new RegExp(`^${key.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*')}$`).test(importSubPath);\n }\n if (key.endsWith('/')) {\n return importSubPath.startsWith(key);\n }\n // Check if the path is a literal match for this key\n return key === importSubPath;\n })\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolvePackageRoot.d.ts","sourceRoot":"","sources":["../../src/utils/resolvePackageRoot.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyBtG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolvePackageRoot.js","sourceRoot":"","sources":["../../src/utils/resolvePackageRoot.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,oCAAoC;AAEpC,sCAAsC;AACtC,0CAA0C;AAC1C,0CAA0C;AAC1C,8BAA8B;AAC9B,kGAAkG;AAClG,gGAAgG;AAChG,mFAAmF;AACnF,2BAA2B;AAC3B,MAAM,WAAW,GAAyB,QAAQ,CAAC,IAAI,IAAK,QAAgB,CAAC,OAAO,EAAE,IAAI,CAAC;AAE3F,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAE,EAAE,CAAC,GAAG,OAAO,KAAK,WAAW,EAAE,CAAC;AAC3F,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;AAEtD;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAAe,EAAE,WAAmB,EAAE,KAAc;IACrF,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,WAAW,GAAG,GAAG,WAAW,eAAe,CAAC;IAClD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACnG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,KAAK,EAAE,CAAC;YACV,2BAA2B;YAC3B,IAAK,GAAW,EAAE,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBAC9C,OAAO,CAAC,KAAK,CAAC,qBAAqB,WAAW,SAAS,OAAO,qBAAqB,CAAC,CAAC;YACvF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,qBAAqB,WAAW,SAAS,OAAO,KAAM,GAAa,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;YACtG,CAAC;QACH,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACrC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAzBD,gDAyBC","sourcesContent":["import * as path from 'path';\nimport * as _resolve from 'resolve';\n\n// 'resolve' index.js looks like this:\n// var async = require('./lib/async');\n// async.sync = require('./lib/sync');\n// module.exports = async;\n// This does not play nicely with at least one transpilation or interop step, possibly on specific\n// Node versions: `import * as resolve` *usually* gives the `resolve` function, but sometimes it\n// gives an object with property `default`... This is a workaround for either case.\n// eslint-disable-next-line\nconst resolveSync: typeof _resolve.sync = _resolve.sync || (_resolve as any).default?.sync;\n\nconst getCacheKey = (fromDir: string, packageName: string) => `${fromDir}::${packageName}`;\nconst resolveCache = new Map<string, string | null>();\n\n/**\n * Resolve the root directory of `packageName` starting from `fromDir`, with caching.\n * This uses the basic `resolve` package (which doesn't respect exports maps) to resolve\n * `${packageName}/package.json`, which should always exist.\n */\nexport function resolvePackageRoot(fromDir: string, packageName: string, debug: boolean): string | null {\n const cacheKey = getCacheKey(fromDir, packageName);\n const cached = resolveCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const resolvePath = `${packageName}/package.json`;\n let resolved: string | null = null;\n try {\n resolved = path.dirname(resolveSync(resolvePath, { basedir: fromDir, preserveSymlinks: false }));\n } catch (err) {\n if (debug) {\n // eslint-disable-next-line\n if ((err as any)?.code === 'MODULE_NOT_FOUND') {\n console.error(`Failed to resolve ${resolvePath} from ${fromDir} (module not found)`);\n } else {\n console.error(`Failed to resolve ${resolvePath} from ${fromDir}: ${(err as Error).message || err}`);\n }\n }\n }\n\n // Cache even if resolution failed so we don't waste time trying again\n resolveCache.set(cacheKey, resolved);\n return resolved;\n}\n"]}
|
/package/lib/utils/{parseImportIfRelevant.d.ts → unsupportedImports/parseImportIfRelevant.d.ts}
RENAMED
|
File without changes
|
|
File without changes
|
/package/lib/utils/{pathSatisfiesAnyExport.js → unsupportedImports/pathSatisfiesAnyExport.js}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|