eslint-plugin-fast-import 2.2.1 → 2.2.2
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/.claude/settings.local.json +4 -4
- package/CHANGELOG.md +4 -0
- package/README.md +3 -0
- package/dist/module/computePackageInfo.d.ts +2 -0
- package/dist/module/computePackageInfo.js +4 -0
- package/dist/module/computePackageInfo.js.map +1 -0
- package/dist/module/computeRepoInfo.d.ts +5 -0
- package/dist/module/computeRepoInfo.js +100 -0
- package/dist/module/computeRepoInfo.js.map +1 -0
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.js +3 -0
- package/dist/plugin.js.map +1 -1
- package/dist/rules/alias/alias.d.ts +1 -1
- package/dist/rules/no-cycle/cycle.d.ts +4 -0
- package/dist/rules/no-cycle/cycle.js +140 -0
- package/dist/rules/no-cycle/cycle.js.map +1 -0
- package/dist/rules/no-cycle/rule.d.ts +4 -0
- package/dist/rules/no-cycle/rule.js +319 -0
- package/dist/rules/no-cycle/rule.js.map +1 -0
- package/dist/rules/no-empty-entry-points/rule.d.ts +3 -0
- package/dist/rules/no-empty-entry-points/rule.js +57 -0
- package/dist/rules/no-empty-entry-points/rule.js.map +1 -0
- package/dist/rules/no-entry-point-imports/entryPoint.d.ts +3 -0
- package/dist/rules/no-entry-point-imports/entryPoint.js +57 -0
- package/dist/rules/no-entry-point-imports/entryPoint.js.map +1 -0
- package/dist/rules/no-entry-point-imports/rule.d.ts +3 -0
- package/dist/rules/no-entry-point-imports/rule.js +60 -0
- package/dist/rules/no-entry-point-imports/rule.js.map +1 -0
- package/dist/rules/no-external-barrel-reexports/externalBarrelReexports.d.ts +3 -0
- package/dist/rules/no-external-barrel-reexports/externalBarrelReexports.js +42 -0
- package/dist/rules/no-external-barrel-reexports/externalBarrelReexports.js.map +1 -0
- package/dist/rules/no-external-barrel-reexports/rule.d.ts +3 -0
- package/dist/rules/no-external-barrel-reexports/rule.js +42 -0
- package/dist/rules/no-external-barrel-reexports/rule.js.map +1 -0
- package/dist/rules/no-named-as-default/namedAsDefault.d.ts +3 -0
- package/dist/rules/no-named-as-default/namedAsDefault.js +77 -0
- package/dist/rules/no-named-as-default/namedAsDefault.js.map +1 -0
- package/dist/rules/no-named-as-default/rule.d.ts +3 -0
- package/dist/rules/no-named-as-default/rule.js +79 -0
- package/dist/rules/no-named-as-default/rule.js.map +1 -0
- package/dist/rules/no-node-builtins/nodeBuiltins.d.ts +3 -0
- package/dist/rules/no-node-builtins/nodeBuiltins.js +48 -0
- package/dist/rules/no-node-builtins/nodeBuiltins.js.map +1 -0
- package/dist/rules/no-node-builtins/rule.d.ts +3 -0
- package/dist/rules/no-node-builtins/rule.js +49 -0
- package/dist/rules/no-node-builtins/rule.js.map +1 -0
- package/dist/rules/no-restricted-imports/restricted.d.ts +31 -0
- package/dist/rules/no-restricted-imports/restricted.js +196 -0
- package/dist/rules/no-restricted-imports/restricted.js.map +1 -0
- package/dist/rules/no-restricted-imports/rule.d.ts +31 -0
- package/dist/rules/no-restricted-imports/rule.js +204 -0
- package/dist/rules/no-restricted-imports/rule.js.map +1 -0
- package/dist/rules/no-test-imports-in-prod/rule.d.ts +3 -0
- package/dist/rules/no-test-imports-in-prod/rule.js +57 -0
- package/dist/rules/no-test-imports-in-prod/rule.js.map +1 -0
- package/dist/rules/no-test-imports-in-prod/testInProd.d.ts +3 -0
- package/dist/rules/no-test-imports-in-prod/testInProd.js +49 -0
- package/dist/rules/no-test-imports-in-prod/testInProd.js.map +1 -0
- package/dist/rules/no-test-only-imports/rule.d.ts +3 -0
- package/dist/rules/no-test-only-imports/rule.js +69 -0
- package/dist/rules/no-test-only-imports/rule.js.map +1 -0
- package/dist/rules/no-unnamed-entry-point-exports/rule.d.ts +3 -0
- package/dist/rules/no-unnamed-entry-point-exports/rule.js +41 -0
- package/dist/rules/no-unnamed-entry-point-exports/rule.js.map +1 -0
- package/dist/rules/no-unresolved-imports/rule.d.ts +3 -0
- package/dist/rules/no-unresolved-imports/rule.js +139 -0
- package/dist/rules/no-unresolved-imports/rule.js.map +1 -0
- package/dist/rules/no-unresolved-imports/unresolved.d.ts +3 -0
- package/dist/rules/no-unresolved-imports/unresolved.js +135 -0
- package/dist/rules/no-unresolved-imports/unresolved.js.map +1 -0
- package/dist/rules/no-unused-exports/rule.d.ts +3 -0
- package/dist/rules/no-unused-exports/rule.js +60 -0
- package/dist/rules/no-unused-exports/rule.js.map +1 -0
- package/dist/rules/no-unused-package-exports/rule.d.ts +3 -0
- package/dist/rules/no-unused-package-exports/rule.js +57 -0
- package/dist/rules/no-unused-package-exports/rule.js.map +1 -0
- package/dist/rules/prefer-alias-imports/alias.d.ts +6 -0
- package/dist/rules/prefer-alias-imports/alias.js +210 -0
- package/dist/rules/prefer-alias-imports/alias.js.map +1 -0
- package/dist/rules/prefer-alias-imports/rule.d.ts +6 -0
- package/dist/rules/prefer-alias-imports/rule.js +214 -0
- package/dist/rules/prefer-alias-imports/rule.js.map +1 -0
- package/dist/rules/require-node-prefix/nodePrefix.d.ts +3 -0
- package/dist/rules/require-node-prefix/nodePrefix.js +59 -0
- package/dist/rules/require-node-prefix/nodePrefix.js.map +1 -0
- package/dist/rules/require-node-prefix/rule.d.ts +3 -0
- package/dist/rules/require-node-prefix/rule.js +60 -0
- package/dist/rules/require-node-prefix/rule.js.map +1 -0
- package/dist/settings/framework.d.ts +3 -0
- package/dist/settings/framework.js +91 -0
- package/dist/settings/framework.js.map +1 -0
- package/dist/settings/package.d.ts +6 -0
- package/dist/settings/package.js +64 -0
- package/dist/settings/package.js.map +1 -0
- package/dist/settings/repo.d.ts +1 -0
- package/dist/settings/repo.js +6 -0
- package/dist/settings/repo.js.map +1 -0
- package/dist/settings/user.d.ts +1 -1
- package/dist/util/getSubpathEntry.d.ts +4 -0
- package/dist/util/getSubpathEntry.js +22 -0
- package/dist/util/getSubpathEntry.js.map +1 -0
- package/package.json +6 -8
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { createRule, getESMInfo, getLocFromRange } from '../util.js';
|
|
4
|
+
const firstPartyEntrySchema = z.strictObject({
|
|
5
|
+
type: z.enum(['first-party']),
|
|
6
|
+
filepath: z.union([z.string(), z.instanceof(RegExp)]),
|
|
7
|
+
allowed: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
|
|
8
|
+
denied: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
|
|
9
|
+
excludeTypeImports: z.boolean().optional(),
|
|
10
|
+
message: z.string().optional(),
|
|
11
|
+
});
|
|
12
|
+
const thirdPartyEntrySchema = z.strictObject({
|
|
13
|
+
type: z.enum(['third-party', 'built-in']),
|
|
14
|
+
moduleSpecifier: z.union([z.string(), z.instanceof(RegExp)]),
|
|
15
|
+
allowed: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
|
|
16
|
+
denied: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
|
|
17
|
+
excludeTypeImports: z.boolean().optional(),
|
|
18
|
+
message: z.string().optional(),
|
|
19
|
+
});
|
|
20
|
+
const entrySchema = z.union([firstPartyEntrySchema, thirdPartyEntrySchema]);
|
|
21
|
+
const schema = z.strictObject({
|
|
22
|
+
rules: z.array(entrySchema),
|
|
23
|
+
});
|
|
24
|
+
function replaceMatchesInRegex(regex, matches) {
|
|
25
|
+
if (!matches) {
|
|
26
|
+
return regex;
|
|
27
|
+
}
|
|
28
|
+
let source = regex.source;
|
|
29
|
+
for (let i = 0; i < matches.length; i++) {
|
|
30
|
+
source = source.replaceAll('$' + (i + 1).toString(), matches[i]);
|
|
31
|
+
}
|
|
32
|
+
return new RegExp(source, regex.flags);
|
|
33
|
+
}
|
|
34
|
+
export const noRestrictedImports = createRule({
|
|
35
|
+
name: 'no-restricted-imports',
|
|
36
|
+
meta: {
|
|
37
|
+
docs: {
|
|
38
|
+
description: 'Esnures restricted imports are only imported by allowed consumers',
|
|
39
|
+
},
|
|
40
|
+
schema: [schema.toJSONSchema({ unrepresentable: 'any' })],
|
|
41
|
+
fixable: undefined,
|
|
42
|
+
type: 'problem',
|
|
43
|
+
messages: {
|
|
44
|
+
restrictedImport: '{{message}}',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
defaultOptions: [{ rules: [] }],
|
|
48
|
+
create(context) {
|
|
49
|
+
const esmInfo = getESMInfo(context);
|
|
50
|
+
// No package info means this file wasn't found as part of the package, e.g.
|
|
51
|
+
// because it's ignored
|
|
52
|
+
/* istanbul ignore if */
|
|
53
|
+
if (!esmInfo) {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
56
|
+
const { fileInfo } = esmInfo;
|
|
57
|
+
/* istanbul ignore if */
|
|
58
|
+
if (fileInfo.fileType !== 'code') {
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
// Normalize allowed and denied string paths to absolute
|
|
62
|
+
const entries = [];
|
|
63
|
+
for (const originalEntry of context.options[0].rules) {
|
|
64
|
+
const entry = { ...originalEntry };
|
|
65
|
+
entries.push(entry);
|
|
66
|
+
if (entry.allowed) {
|
|
67
|
+
entry.allowed = entry.allowed.map((allowed) => {
|
|
68
|
+
if (typeof allowed === 'string' && !isAbsolute(allowed)) {
|
|
69
|
+
return resolve(esmInfo.packageInfo.packageRootDir, allowed);
|
|
70
|
+
}
|
|
71
|
+
return allowed;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (entry.denied) {
|
|
75
|
+
entry.denied = entry.denied.map((denied) => {
|
|
76
|
+
if (typeof denied === 'string' && !isAbsolute(denied)) {
|
|
77
|
+
return resolve(esmInfo.packageInfo.packageRootDir, denied);
|
|
78
|
+
}
|
|
79
|
+
return denied;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (entry.type === 'first-party') {
|
|
83
|
+
// Normalize string paths to absolute
|
|
84
|
+
if (typeof entry.filepath === 'string' && !isAbsolute(entry.filepath)) {
|
|
85
|
+
entry.filepath = resolve(esmInfo.packageInfo.packageRootDir, entry.filepath);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Check each import and reexport
|
|
90
|
+
for (const importEntry of [
|
|
91
|
+
...fileInfo.singleImports,
|
|
92
|
+
...fileInfo.barrelImports,
|
|
93
|
+
...fileInfo.dynamicImports,
|
|
94
|
+
...fileInfo.sideEffectImports,
|
|
95
|
+
...fileInfo.singleReexports,
|
|
96
|
+
...fileInfo.barrelReexports,
|
|
97
|
+
]) {
|
|
98
|
+
const { moduleSpecifier } = importEntry;
|
|
99
|
+
/* istanbul ignore if */
|
|
100
|
+
if (!moduleSpecifier) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
if ('isTypeImport' in importEntry &&
|
|
105
|
+
importEntry.isTypeImport &&
|
|
106
|
+
entry.excludeTypeImports) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
// Check if this import applies to this entry
|
|
110
|
+
let matches = null;
|
|
111
|
+
switch (entry.type) {
|
|
112
|
+
case 'third-party':
|
|
113
|
+
case 'built-in': {
|
|
114
|
+
// Check if the module specifier matches
|
|
115
|
+
if (typeof entry.moduleSpecifier === 'string') {
|
|
116
|
+
if (entry.moduleSpecifier !== moduleSpecifier) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else if (!entry.moduleSpecifier.test(moduleSpecifier)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'first-party': {
|
|
126
|
+
// First we have to make sure we could resolve the module specifier to
|
|
127
|
+
// a file path. Otherwise we ignore it, since this is either a broken
|
|
128
|
+
// import or a dynamic import
|
|
129
|
+
if (!importEntry.resolvedModulePath) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
// Check if the resolved module path matches
|
|
133
|
+
if (typeof entry.filepath === 'string') {
|
|
134
|
+
if (entry.filepath !== importEntry.resolvedModulePath) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
const match = entry.filepath.exec(importEntry.resolvedModulePath);
|
|
140
|
+
if (!match) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (match.length > 1) {
|
|
144
|
+
matches = match.slice(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Check if the module specifier is allowed
|
|
151
|
+
if (entry.allowed) {
|
|
152
|
+
let isAllowed = false;
|
|
153
|
+
for (const allowed of entry.allowed) {
|
|
154
|
+
if (typeof allowed === 'string') {
|
|
155
|
+
if (allowed === context.filename) {
|
|
156
|
+
isAllowed = true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else if (replaceMatchesInRegex(allowed, matches).test(context.filename)) {
|
|
160
|
+
isAllowed = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!isAllowed) {
|
|
164
|
+
context.report({
|
|
165
|
+
loc: getLocFromRange(context, importEntry.statementNodeRange),
|
|
166
|
+
messageId: 'restrictedImport',
|
|
167
|
+
data: {
|
|
168
|
+
message: entry.message ??
|
|
169
|
+
`${context.filename} is not allowed to import ${moduleSpecifier}`,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Check if the module specifier is denied
|
|
176
|
+
if (entry.denied) {
|
|
177
|
+
let isDenied = false;
|
|
178
|
+
for (const denied of entry.denied) {
|
|
179
|
+
if (typeof denied === 'string') {
|
|
180
|
+
if (denied === context.filename) {
|
|
181
|
+
isDenied = true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (replaceMatchesInRegex(denied, matches).test(context.filename)) {
|
|
185
|
+
isDenied = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (isDenied) {
|
|
189
|
+
context.report({
|
|
190
|
+
loc: getLocFromRange(context, importEntry.statementNodeRange),
|
|
191
|
+
messageId: 'restrictedImport',
|
|
192
|
+
data: {
|
|
193
|
+
message: entry.message ??
|
|
194
|
+
`${context.filename} is denied from importing ${moduleSpecifier}`,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {};
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/rules/no-restricted-imports/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGhD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,qBAAqB,GAAG,CAAC,CAAC,YAAY,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC;IAC7B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvE,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,CAAC,CAAC,YAAY,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACzC,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvE,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC,CAAC;AAC5E,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;CAC5B,CAAC,CAAC;AAMH,SAAS,qBAAqB,CAAC,KAAa,EAAE,OAAwB;IACpE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAG3C;IACA,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EACT,mEAAmE;SACtE;QACD,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,CAAgB,CAAC;QACxE,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,gBAAgB,EAAE,aAAa;SAChC;KACF;IACD,cAAc,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC/B,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,uBAAuB;QACvB,wBAAwB;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,wBAAwB;QACxB,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,wDAAwD;QACxD,MAAM,OAAO,GAAY,EAAE,CAAC;QAC5B,KAAK,MAAM,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;YACrD,MAAM,KAAK,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;oBAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;wBACxD,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;oBAC9D,CAAC;oBACD,OAAO,OAAO,CAAC;gBACjB,CAAC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjB,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBACzC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;wBACtD,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;oBAC7D,CAAC;oBACD,OAAO,MAAM,CAAC;gBAChB,CAAC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBACjC,qCAAqC;gBACrC,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACtE,KAAK,CAAC,QAAQ,GAAG,OAAO,CACtB,OAAO,CAAC,WAAW,CAAC,cAAc,EAClC,KAAK,CAAC,QAAQ,CACf,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,KAAK,MAAM,WAAW,IAAI;YACxB,GAAG,QAAQ,CAAC,aAAa;YACzB,GAAG,QAAQ,CAAC,aAAa;YACzB,GAAG,QAAQ,CAAC,cAAc;YAC1B,GAAG,QAAQ,CAAC,iBAAiB;YAC7B,GAAG,QAAQ,CAAC,eAAe;YAC3B,GAAG,QAAQ,CAAC,eAAe;SAC5B,EAAE,CAAC;YACF,MAAM,EAAE,eAAe,EAAE,GAAG,WAAW,CAAC;YACxC,wBAAwB;YACxB,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IACE,cAAc,IAAI,WAAW;oBAC7B,WAAW,CAAC,YAAY;oBACxB,KAAK,CAAC,kBAAkB,EACxB,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,6CAA6C;gBAC7C,IAAI,OAAO,GAAoB,IAAI,CAAC;gBACpC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;oBACnB,KAAK,aAAa,CAAC;oBACnB,KAAK,UAAU,CAAC,CAAC,CAAC;wBAChB,wCAAwC;wBACxC,IAAI,OAAO,KAAK,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;4BAC9C,IAAI,KAAK,CAAC,eAAe,KAAK,eAAe,EAAE,CAAC;gCAC9C,SAAS;4BACX,CAAC;wBACH,CAAC;6BAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;4BACxD,SAAS;wBACX,CAAC;wBACD,MAAM;oBACR,CAAC;oBACD,KAAK,aAAa,CAAC,CAAC,CAAC;wBACnB,sEAAsE;wBACtE,qEAAqE;wBACrE,6BAA6B;wBAC7B,IAAI,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC;4BACpC,SAAS;wBACX,CAAC;wBAED,4CAA4C;wBAC5C,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;4BACvC,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC,kBAAkB,EAAE,CAAC;gCACtD,SAAS;4BACX,CAAC;wBACH,CAAC;6BAAM,CAAC;4BACN,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;4BAClE,IAAI,CAAC,KAAK,EAAE,CAAC;gCACX,SAAS;4BACX,CAAC;4BACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gCACrB,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;4BAC3B,CAAC;wBACH,CAAC;wBACD,MAAM;oBACR,CAAC;gBACH,CAAC;gBAED,2CAA2C;gBAC3C,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClB,IAAI,SAAS,GAAG,KAAK,CAAC;oBACtB,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;wBACpC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;4BAChC,IAAI,OAAO,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;gCACjC,SAAS,GAAG,IAAI,CAAC;4BACnB,CAAC;wBACH,CAAC;6BAAM,IACL,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAC9D,CAAC;4BACD,SAAS,GAAG,IAAI,CAAC;wBACnB,CAAC;oBACH,CAAC;oBACD,IAAI,CAAC,SAAS,EAAE,CAAC;wBACf,OAAO,CAAC,MAAM,CAAC;4BACb,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,kBAAkB,CAAC;4BAC7D,SAAS,EAAE,kBAAkB;4BAC7B,IAAI,EAAE;gCACJ,OAAO,EACL,KAAK,CAAC,OAAO;oCACb,GAAG,OAAO,CAAC,QAAQ,6BAA6B,eAAe,EAAE;6BACpE;yBACF,CAAC,CAAC;wBACH,SAAS;oBACX,CAAC;gBACH,CAAC;gBAED,0CAA0C;gBAC1C,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;oBACjB,IAAI,QAAQ,GAAG,KAAK,CAAC;oBACrB,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;wBAClC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;4BAC/B,IAAI,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;gCAChC,QAAQ,GAAG,IAAI,CAAC;4BAClB,CAAC;wBACH,CAAC;6BAAM,IACL,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAC7D,CAAC;4BACD,QAAQ,GAAG,IAAI,CAAC;wBAClB,CAAC;oBACH,CAAC;oBACD,IAAI,QAAQ,EAAE,CAAC;wBACb,OAAO,CAAC,MAAM,CAAC;4BACb,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,kBAAkB,CAAC;4BAC7D,SAAS,EAAE,kBAAkB;4BAC7B,IAAI,EAAE;gCACJ,OAAO,EACL,KAAK,CAAC,OAAO;oCACb,GAAG,OAAO,CAAC,QAAQ,6BAA6B,eAAe,EAAE;6BACpE;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createRule, getESMInfo, getLocFromRange, isNonTestFile, } from '../util.js';
|
|
2
|
+
export const noTestImportsInProd = createRule({
|
|
3
|
+
name: 'no-test-imports-in-prod',
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Ensures that production code does not import test code',
|
|
7
|
+
},
|
|
8
|
+
schema: [],
|
|
9
|
+
fixable: undefined,
|
|
10
|
+
type: 'problem',
|
|
11
|
+
messages: {
|
|
12
|
+
noTestImports: 'Test code should not be imported in production code',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultOptions: [],
|
|
16
|
+
create(context) {
|
|
17
|
+
const esmInfo = getESMInfo(context);
|
|
18
|
+
// No package info means this file wasn't found as part of the package, e.g.
|
|
19
|
+
// because it's ignored
|
|
20
|
+
/* istanbul ignore if */
|
|
21
|
+
if (!esmInfo) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const { fileInfo } = esmInfo;
|
|
25
|
+
if (fileInfo.fileType !== 'code' || !isNonTestFile(context.filename)) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
for (const importEntry of [
|
|
29
|
+
...fileInfo.singleImports,
|
|
30
|
+
...fileInfo.barrelImports,
|
|
31
|
+
...fileInfo.dynamicImports,
|
|
32
|
+
...fileInfo.sideEffectImports,
|
|
33
|
+
...fileInfo.singleReexports,
|
|
34
|
+
...fileInfo.barrelReexports,
|
|
35
|
+
]) {
|
|
36
|
+
if (importEntry.resolvedModuleType !== 'firstPartyCode' &&
|
|
37
|
+
importEntry.resolvedModuleType !== 'firstPartyOther') {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (
|
|
41
|
+
// First check if the imported file is a test file
|
|
42
|
+
(importEntry.resolvedModulePath &&
|
|
43
|
+
!isNonTestFile(importEntry.resolvedModulePath)) ||
|
|
44
|
+
// Now check if the imported symbol is in production but intended to be
|
|
45
|
+
// test only
|
|
46
|
+
('importName' in importEntry &&
|
|
47
|
+
importEntry.importName.startsWith('_testOnly'))) {
|
|
48
|
+
context.report({
|
|
49
|
+
loc: getLocFromRange(context, importEntry.reportNodeRange),
|
|
50
|
+
messageId: 'noTestImports',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {};
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/rules/no-test-imports-in-prod/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EACV,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;IAC5C,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,wDAAwD;SACtE;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,aAAa,EAAE,qDAAqD;SACrE;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,uBAAuB;QACvB,wBAAwB;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,KAAK,MAAM,WAAW,IAAI;YACxB,GAAG,QAAQ,CAAC,aAAa;YACzB,GAAG,QAAQ,CAAC,aAAa;YACzB,GAAG,QAAQ,CAAC,cAAc;YAC1B,GAAG,QAAQ,CAAC,iBAAiB;YAC7B,GAAG,QAAQ,CAAC,eAAe;YAC3B,GAAG,QAAQ,CAAC,eAAe;SAC5B,EAAE,CAAC;YACF,IACE,WAAW,CAAC,kBAAkB,KAAK,gBAAgB;gBACnD,WAAW,CAAC,kBAAkB,KAAK,iBAAiB,EACpD,CAAC;gBACD,SAAS;YACX,CAAC;YACD;YACE,kDAAkD;YAClD,CAAC,WAAW,CAAC,kBAAkB;gBAC7B,CAAC,aAAa,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;gBACjD,uEAAuE;gBACvE,YAAY;gBACZ,CAAC,YAAY,IAAI,WAAW;oBAC1B,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,EACjD,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC;oBACb,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC;oBAC1D,SAAS,EAAE,eAAe;iBAC3B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createRule, getESMInfo, getLocFromRange, isNonTestFile } from '../util.js';
|
|
2
|
+
export const noTestImportsInProd = createRule({
|
|
3
|
+
name: 'no-test-imports-in-prod',
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Ensures that production code does not import test code',
|
|
7
|
+
},
|
|
8
|
+
schema: [],
|
|
9
|
+
fixable: undefined,
|
|
10
|
+
type: 'problem',
|
|
11
|
+
messages: {
|
|
12
|
+
noTestImports: 'Test code should not be imported in production code',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultOptions: [],
|
|
16
|
+
create(context) {
|
|
17
|
+
const esmInfo = getESMInfo(context);
|
|
18
|
+
// No project info means this file wasn't found as part of the project, e.g.
|
|
19
|
+
// because it's ignored
|
|
20
|
+
/* istanbul ignore if */
|
|
21
|
+
if (!esmInfo) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const { fileInfo } = esmInfo;
|
|
25
|
+
if (fileInfo.fileType !== 'code' || !isNonTestFile(context.filename)) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
for (const importEntry of [
|
|
29
|
+
...fileInfo.singleImports,
|
|
30
|
+
...fileInfo.barrelImports,
|
|
31
|
+
...fileInfo.dynamicImports,
|
|
32
|
+
...fileInfo.singleReexports,
|
|
33
|
+
...fileInfo.barrelReexports,
|
|
34
|
+
]) {
|
|
35
|
+
if (importEntry.resolvedModuleType !== 'firstPartyCode' &&
|
|
36
|
+
importEntry.resolvedModuleType !== 'firstPartyOther') {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (importEntry.resolvedModulePath && !isNonTestFile(importEntry.resolvedModulePath)) {
|
|
40
|
+
context.report({
|
|
41
|
+
loc: getLocFromRange(context, importEntry.reportNodeRange),
|
|
42
|
+
messageId: 'noTestImports',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {};
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=testInProd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testInProd.js","sourceRoot":"","sources":["../../../src/rules/no-test-imports-in-prod/testInProd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpF,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;IAC5C,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,wDAAwD;SACtE;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,aAAa,EAAE,qDAAqD;SACrE;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,uBAAuB;QACvB,wBAAwB;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,KAAK,MAAM,WAAW,IAAI;YACxB,GAAG,QAAQ,CAAC,aAAa;YACzB,GAAG,QAAQ,CAAC,aAAa;YACzB,GAAG,QAAQ,CAAC,cAAc;YAC1B,GAAG,QAAQ,CAAC,eAAe;YAC3B,GAAG,QAAQ,CAAC,eAAe;SAC5B,EAAE,CAAC;YACF,IACE,WAAW,CAAC,kBAAkB,KAAK,gBAAgB;gBACnD,WAAW,CAAC,kBAAkB,KAAK,iBAAiB,EACpD,CAAC;gBACD,SAAS;YACX,CAAC;YACD,IAAI,WAAW,CAAC,kBAAkB,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACrF,OAAO,CAAC,MAAM,CAAC;oBACb,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC;oBAC1D,SAAS,EAAE,eAAe;iBAC3B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createRule, getESMInfo, getLocFromRange, isNonTestFile, } from '../util.js';
|
|
2
|
+
export const noTestOnlyImports = createRule({
|
|
3
|
+
name: 'no-test-only-imports',
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Flags exports in production code that are only imported by test code',
|
|
7
|
+
},
|
|
8
|
+
schema: [],
|
|
9
|
+
fixable: undefined,
|
|
10
|
+
type: 'problem',
|
|
11
|
+
messages: {
|
|
12
|
+
noTestOnlyImports: 'Export "{{name}}" must be imported by non-test files',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultOptions: [],
|
|
16
|
+
create(context) {
|
|
17
|
+
// .d.ts files are not typically referenced directly, and instead are used
|
|
18
|
+
// to type ambient modules. Sometimes they are used directly though when
|
|
19
|
+
// paired with a neighboring vanilla JS file. Either way, we're making the
|
|
20
|
+
// tradeoff of potentially missing an unused type export for better DX.
|
|
21
|
+
if (context.filename.endsWith('.d.ts')) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const esmInfo = getESMInfo(context);
|
|
25
|
+
// No package info means this file wasn't found as part of the package, e.g.
|
|
26
|
+
// because it's ignored
|
|
27
|
+
/* istanbul ignore if */
|
|
28
|
+
if (!esmInfo) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
const { fileInfo } = esmInfo;
|
|
32
|
+
/* istanbul ignore if */
|
|
33
|
+
if (fileInfo.fileType !== 'code') {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
// Check each export and reexport to make sure it's being used
|
|
37
|
+
for (const exportEntry of [
|
|
38
|
+
...fileInfo.exports,
|
|
39
|
+
...fileInfo.singleReexports,
|
|
40
|
+
...fileInfo.barrelReexports,
|
|
41
|
+
]) {
|
|
42
|
+
// If this is an entry point, then it's being imported externally by definition
|
|
43
|
+
if (exportEntry.isEntryPoint || exportEntry.isExternallyImported) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// Check if there are no imports at all and bail, since this means it's
|
|
47
|
+
// by definition not imported by a test file. Otherwise, it trips our
|
|
48
|
+
// logic below
|
|
49
|
+
if (exportEntry.importedBy.length === 0) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (isNonTestFile(context.filename) &&
|
|
53
|
+
!exportEntry.importedBy.some((i) => isNonTestFile(i.filePath)) &&
|
|
54
|
+
!exportEntry.exportName?.startsWith('_testOnly')) {
|
|
55
|
+
if (!(`isTypeExport` in exportEntry) || !exportEntry.isTypeExport) {
|
|
56
|
+
context.report({
|
|
57
|
+
messageId: 'noTestOnlyImports',
|
|
58
|
+
loc: getLocFromRange(context, exportEntry.reportNodeRange),
|
|
59
|
+
data: {
|
|
60
|
+
name: exportEntry.exportName || '<unnamed>',
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {};
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/rules/no-test-only-imports/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EACV,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;IAC1C,IAAI,EAAE,sBAAsB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EACT,sEAAsE;SACzE;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,iBAAiB,EAAE,sDAAsD;SAC1E;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,uBAAuB;QACvB,wBAAwB;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,wBAAwB;QACxB,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,8DAA8D;QAC9D,KAAK,MAAM,WAAW,IAAI;YACxB,GAAG,QAAQ,CAAC,OAAO;YACnB,GAAG,QAAQ,CAAC,eAAe;YAC3B,GAAG,QAAQ,CAAC,eAAe;SAC5B,EAAE,CAAC;YACF,+EAA+E;YAC/E,IAAI,WAAW,CAAC,YAAY,IAAI,WAAW,CAAC,oBAAoB,EAAE,CAAC;gBACjE,SAAS;YACX,CAAC;YAED,uEAAuE;YACvE,qEAAqE;YACrE,cAAc;YACd,IAAI,WAAW,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxC,SAAS;YACX,CAAC;YAED,IACE,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC/B,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;gBAC9D,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,WAAW,CAAC,EAChD,CAAC;gBACD,IAAI,CAAC,CAAC,cAAc,IAAI,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;oBAClE,OAAO,CAAC,MAAM,CAAC;wBACb,SAAS,EAAE,mBAAmB;wBAC9B,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC;wBAC1D,IAAI,EAAE;4BACJ,IAAI,EAAE,WAAW,CAAC,UAAU,IAAI,WAAW;yBAC5C;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createRule, getESMInfo, getLocFromRange } from '../util.js';
|
|
2
|
+
export const noUnnamedEntryPointExports = createRule({
|
|
3
|
+
name: 'no-unnamed-entry-point-exports',
|
|
4
|
+
meta: {
|
|
5
|
+
docs: {
|
|
6
|
+
description: 'Ensures barrel reexports in entry points are named',
|
|
7
|
+
},
|
|
8
|
+
schema: [],
|
|
9
|
+
fixable: undefined,
|
|
10
|
+
type: 'problem',
|
|
11
|
+
messages: {
|
|
12
|
+
noUnnamedEntryPointExports: 'Barrel reexports in entry points must be named',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultOptions: [],
|
|
16
|
+
create(context) {
|
|
17
|
+
const esmInfo = getESMInfo(context);
|
|
18
|
+
// No package info means this file wasn't found as part of the package, e.g.
|
|
19
|
+
// because it's ignored
|
|
20
|
+
/* istanbul ignore if */
|
|
21
|
+
if (!esmInfo) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
const { fileInfo } = esmInfo;
|
|
25
|
+
/* istanbul ignore if */
|
|
26
|
+
if (fileInfo.fileType !== 'code' || !fileInfo.entryPointSpecifier) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
// Now check reexports
|
|
30
|
+
for (const reexportEntry of fileInfo.barrelReexports) {
|
|
31
|
+
if (!reexportEntry.exportName) {
|
|
32
|
+
context.report({
|
|
33
|
+
loc: getLocFromRange(context, reexportEntry.reportNodeRange),
|
|
34
|
+
messageId: 'noUnnamedEntryPointExports',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {};
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/rules/no-unnamed-entry-point-exports/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,CAAC,MAAM,0BAA0B,GAAG,UAAU,CAAC;IACnD,IAAI,EAAE,gCAAgC;IACtC,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,oDAAoD;SAClE;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,0BAA0B,EACxB,gDAAgD;SACnD;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,uBAAuB;QACvB,wBAAwB;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,wBAAwB;QACxB,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC;YAClE,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,sBAAsB;QACtB,KAAK,MAAM,aAAa,IAAI,QAAQ,CAAC,eAAe,EAAE,CAAC;YACrD,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC;oBACb,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC;oBAC5D,SAAS,EAAE,4BAA4B;iBACxC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { exitWithInternalError } from '../../util/error.js';
|
|
2
|
+
import { createRule, getESMInfo, getLocFromRange } from '../util.js';
|
|
3
|
+
export const noUnresolvedImports = createRule({
|
|
4
|
+
name: 'no-unresolved-imports',
|
|
5
|
+
meta: {
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Ensures that imports point to valid exports',
|
|
8
|
+
},
|
|
9
|
+
schema: [],
|
|
10
|
+
fixable: undefined,
|
|
11
|
+
type: 'problem',
|
|
12
|
+
messages: {
|
|
13
|
+
noUnresolvedImports: 'Import "{{name}}" does not point to a valid first party export',
|
|
14
|
+
noTransientDependencies: 'Third party module specifier "{{specifier}}" is not listed in package.json.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create(context) {
|
|
19
|
+
const esmInfo = getESMInfo(context);
|
|
20
|
+
// No package info means this file wasn't found as part of the package, e.g.
|
|
21
|
+
// because it's ignored
|
|
22
|
+
/* istanbul ignore if */
|
|
23
|
+
if (!esmInfo) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
const { fileInfo, packageInfo } = esmInfo;
|
|
27
|
+
/* istanbul ignore if */
|
|
28
|
+
if (fileInfo.fileType !== 'code') {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
// First check imports
|
|
32
|
+
outer: for (const importEntry of [
|
|
33
|
+
...fileInfo.singleImports,
|
|
34
|
+
...fileInfo.barrelImports,
|
|
35
|
+
...fileInfo.dynamicImports,
|
|
36
|
+
...fileInfo.sideEffectImports,
|
|
37
|
+
]) {
|
|
38
|
+
// First, check if this is a third party dependency, and ensure that the dependency is listed
|
|
39
|
+
// in a package.json
|
|
40
|
+
if (importEntry.resolvedModuleType === 'thirdParty') {
|
|
41
|
+
for (const [path, deps,] of packageInfo.availableThirdPartyDependencies) {
|
|
42
|
+
if (context.filename.startsWith(path) &&
|
|
43
|
+
deps.some((dep) =>
|
|
44
|
+
// Check if this is exactly the import specifier, e.g. 'react'
|
|
45
|
+
importEntry.moduleSpecifier === dep ||
|
|
46
|
+
// Check if this is a type import for a dep from DefinitelyTyped
|
|
47
|
+
// just in case someone is only using type imports w/o the
|
|
48
|
+
// implementation package installed
|
|
49
|
+
('isTypeImport' in importEntry &&
|
|
50
|
+
importEntry.isTypeImport &&
|
|
51
|
+
`@types/${importEntry.moduleSpecifier}` === dep) ||
|
|
52
|
+
// Check if this is reaching into the package, e.g. 'react/path'
|
|
53
|
+
importEntry.moduleSpecifier?.startsWith(dep + '/'))) {
|
|
54
|
+
continue outer;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Quick sanity check to see if there was a bug
|
|
58
|
+
/* istanbul ignore if */
|
|
59
|
+
if (importEntry.moduleSpecifier?.startsWith('.')) {
|
|
60
|
+
exitWithInternalError(`Module specifier ${importEntry.moduleSpecifier} was misclassified as a third party import`);
|
|
61
|
+
}
|
|
62
|
+
// If we got here, we couldn't find a match in package.json, so error
|
|
63
|
+
context.report({
|
|
64
|
+
messageId: 'noTransientDependencies',
|
|
65
|
+
loc: getLocFromRange(context, importEntry.statementNodeRange),
|
|
66
|
+
data: {
|
|
67
|
+
specifier: importEntry.moduleSpecifier,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Barrel/dynamic imports don't resolve to a single export, and can be
|
|
73
|
+
// spread across multiple files even. The specific items being imported
|
|
74
|
+
// isn't specified either in non-first party code, meaning the only way to
|
|
75
|
+
// know if an import is valid is to introspect how it's used at runtime.
|
|
76
|
+
// This isn't tractable, so we only validate that the module specifier
|
|
77
|
+
// could be resolved. If the module couldn't be resolved, we mark the file
|
|
78
|
+
// type as first party other, so we first have to check for that.
|
|
79
|
+
if (importEntry.resolvedModuleType === 'firstPartyOther' &&
|
|
80
|
+
importEntry.type === 'barrelImport') {
|
|
81
|
+
context.report({
|
|
82
|
+
loc: getLocFromRange(context, importEntry.reportNodeRange),
|
|
83
|
+
messageId: 'noUnresolvedImports',
|
|
84
|
+
data: {
|
|
85
|
+
name: importEntry.importAlias,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// Next, we check if the root export could be resolved, which is only
|
|
90
|
+
// available for single imports
|
|
91
|
+
if (importEntry.resolvedModuleType === 'firstPartyCode' &&
|
|
92
|
+
importEntry.type === 'singleImport' &&
|
|
93
|
+
importEntry.rootModuleType === undefined) {
|
|
94
|
+
context.report({
|
|
95
|
+
loc: getLocFromRange(context, importEntry.reportNodeRange),
|
|
96
|
+
messageId: 'noUnresolvedImports',
|
|
97
|
+
data: {
|
|
98
|
+
name: importEntry.importName,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Now check reexports
|
|
104
|
+
for (const reexportEntry of [
|
|
105
|
+
...fileInfo.singleReexports,
|
|
106
|
+
...fileInfo.barrelReexports,
|
|
107
|
+
]) {
|
|
108
|
+
// First check if we couldn't resolve the module specifier. If the module
|
|
109
|
+
// couldn't be resolved, we mark the file type as first party other, so
|
|
110
|
+
// we first have to check for that.
|
|
111
|
+
if (reexportEntry.resolvedModuleType === 'firstPartyOther' &&
|
|
112
|
+
reexportEntry.type === 'barrelReexport') {
|
|
113
|
+
context.report({
|
|
114
|
+
loc: getLocFromRange(context, reexportEntry.reportNodeRange),
|
|
115
|
+
messageId: 'noUnresolvedImports',
|
|
116
|
+
data: {
|
|
117
|
+
name: reexportEntry.exportName,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// Next, we check if the root export could be resolved, which is only
|
|
122
|
+
// available for single reexports if they are entry points
|
|
123
|
+
if (reexportEntry.resolvedModuleType === 'firstPartyCode' &&
|
|
124
|
+
reexportEntry.type === 'singleReexport' &&
|
|
125
|
+
reexportEntry.rootModuleType === undefined &&
|
|
126
|
+
(reexportEntry.isEntryPoint || reexportEntry.isExternallyImported)) {
|
|
127
|
+
context.report({
|
|
128
|
+
loc: getLocFromRange(context, reexportEntry.reportNodeRange),
|
|
129
|
+
messageId: 'noUnresolvedImports',
|
|
130
|
+
data: {
|
|
131
|
+
name: reexportEntry.exportName,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {};
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/rules/no-unresolved-imports/rule.ts"],"names":[],"mappings":"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"}
|