Skip to content

Commit 6f11cda

Browse files
test: reduce failing tests
1 parent e9b4acc commit 6f11cda

File tree

1 file changed

+67
-42
lines changed

1 file changed

+67
-42
lines changed

src/rules/extensions.js

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,6 @@ module.exports = {
134134
},
135135
],
136136
},
137-
messages: {
138-
missingExtension: 'Missing file extension for "{{importPath}}" (expected {{expected}}).',
139-
unexpectedExtension: 'Unexpected use of file extension "{{extension}}" for "{{importPath}}"',
140-
},
141137
},
142138

143139
create(context) {
@@ -198,7 +194,9 @@ module.exports = {
198194
if (!source || !source.value) { return; }
199195

200196
const importPathWithQueryString = source.value;
197+
const hasQuery = importPathWithQueryString.includes('?');
201198
const currentDir = path.dirname(context.getFilename());
199+
const isRelative = importPathWithQueryString.startsWith('.');
202200

203201
// If not undefined, the user decided if rules are enforced on this import
204202
const overrideAction = computeOverrideAction(
@@ -210,59 +208,86 @@ module.exports = {
210208
return;
211209
}
212210

213-
// don't enforce anything on builtins
214211
if (!overrideAction && isBuiltIn(importPathWithQueryString, context.settings)) { return; }
215212

216213
const importPath = importPathWithQueryString.replace(/\?(.*)$/, '');
217-
218-
// don't enforce in root external packages as they may have names with `.js`.
219-
// Like `import Decimal from decimal.js`)
220-
if (!overrideAction && isExternalRootModule(importPath)) { return; }
214+
if (!overrideAction && isExternalRootModule(importPath) && !(props.checkTypeImports && (node.importKind === 'type' || node.exportKind === 'type'))) { return; }
221215

222216
const resolvedPath = resolve(importPath, context);
217+
const isPackage = isExternalModule(importPath, resolvedPath, context) || isScoped(importPath);
223218
const extensionWithDot = path.extname(resolvedPath || importPath);
219+
const extension = extensionWithDot.slice(1);
224220

225-
// determine if this is a module
226-
const isPackage = isExternalModule(
227-
importPath,
228-
resolve(importPath, context),
229-
context,
230-
) || isScoped(importPath);
221+
const sourceCode = context.getSourceCode();
222+
const fileHasExports = sourceCode.ast.body.some((n) => n.type.indexOf('Export') === 0);
223+
const isExport = node && node.type && node.type.indexOf('Export') === 0;
224+
const isImportDeclaration = node && node.type === 'ImportDeclaration';
231225

232-
// Case 1: Missing extension.
233226
if (!extensionWithDot || !importPath.endsWith(extensionWithDot)) {
234227
// ignore type-only imports and exports
235228
if (!props.checkTypeImports && (node.importKind === 'type' || node.exportKind === 'type')) { return; }
236-
const candidate = getCandidateExtension(importPath, currentDir);
237-
if (candidate && isUseOfExtensionRequired(candidate.replace(/^\./, ''), isPackage)) {
238-
context.report({
239-
node,
240-
message:
241-
`Missing file extension for "${importPathWithQueryString}"`,
242-
data: {
243-
importPath: importPathWithQueryString,
244-
expected: candidate,
245-
},
246-
fix(fixer) {
247-
return fixer.replaceText(source, JSON.stringify(importPathWithQueryString + candidate));
248-
},
249-
});
229+
let candidate = getCandidateExtension(importPath, currentDir);
230+
if (!candidate && isUseOfExtensionRequired('js', isPackage)) { candidate = '.js'; }
231+
if (candidate && isUseOfExtensionRequired(candidate.slice(1), isPackage)) {
232+
if (isExport || hasQuery || !isImportDeclaration && fileHasExports || !Object.prototype.hasOwnProperty.call(
233+
props.pattern,
234+
candidate.slice(1),
235+
) || !isRelative || isPackage) {
236+
context.report({
237+
node: source,
238+
message: `Missing file extension ${extension ? `"${extension}" ` : ''}for "${importPathWithQueryString}"`,
239+
data: {
240+
importPath: importPathWithQueryString,
241+
expected: candidate,
242+
},
243+
});
244+
} else {
245+
context.report({
246+
node: source,
247+
message: `Missing file extension ${extension ? `"${extension}" ` : ''}for "${importPathWithQueryString}"`,
248+
data: {
249+
importPath: importPathWithQueryString,
250+
expected: candidate,
251+
},
252+
fix(fixer) {
253+
return fixer.replaceText(
254+
source,
255+
JSON.stringify(importPathWithQueryString + candidate),
256+
);
257+
},
258+
});
259+
}
250260
}
251261
} else {
252262
// Case 2: Unexpected extension provided.
253-
const extension = extensionWithDot.slice(1);
254263
if (isUseOfExtensionForbidden(extension) && isResolvableWithoutExtension(importPath, extension)) {
255-
context.report({
256-
node: source,
257-
message: `Unexpected use of file extension "${extension}" for "${importPathWithQueryString}"`,
258-
data: {
259-
extension,
260-
importPath: importPathWithQueryString,
261-
},
262-
fix(fixer) {
263-
return fixer.replaceText(source, JSON.stringify(importPath.slice(0, -extensionWithDot.length)));
264-
},
265-
});
264+
if (isExport || hasQuery || !isImportDeclaration && fileHasExports || !Object.prototype.hasOwnProperty.call(props.pattern, extension) || !isRelative || isPackage) {
265+
context.report({
266+
node: source,
267+
message: `Unexpected use of file extension "${extension}" for "${importPathWithQueryString}"`,
268+
data: {
269+
extension,
270+
importPath: importPathWithQueryString,
271+
},
272+
});
273+
} else {
274+
context.report({
275+
node: source,
276+
message: `Unexpected use of file extension "${extension}" for "${importPathWithQueryString}"`,
277+
data: {
278+
extension,
279+
importPath: importPathWithQueryString,
280+
},
281+
fix(fixer) {
282+
return fixer.replaceText(
283+
source,
284+
JSON.stringify(
285+
importPath.slice(0, -extensionWithDot.length),
286+
),
287+
);
288+
},
289+
});
290+
}
266291
}
267292
}
268293
}

0 commit comments

Comments
 (0)