Skip to content

Commit

Permalink
feat(linter): support path wildcards in enforce-module-boundaries aut…
Browse files Browse the repository at this point in the history
…ofix (#18316)
  • Loading branch information
dearlordylord committed Jul 31, 2023
1 parent dcefa4a commit 9c7ded0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 6 deletions.
17 changes: 13 additions & 4 deletions packages/eslint-plugin/src/rules/enforce-module-boundaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ export default createESLintRule<Options, MessageIds>({
fix(fixer) {
// imp has form of @myorg/someproject/some/path
const indexTsPaths = getBarrelEntryPointByImportScope(imp);
if (indexTsPaths && indexTsPaths.length > 0) {
if (indexTsPaths.length > 0) {
const specifiers = (node as any).specifiers;
if (!specifiers || specifiers.length === 0) {
return;
Expand All @@ -359,13 +359,22 @@ export default createESLintRule<Options, MessageIds>({
dirname(importPath)
);

// the string we receive from elsewhere might not have a leading './' here despite still being a relative path
// we'd like to ensure it's a normalized relative form starting from ./ or ../
const ensureRelativeForm = (path: string): string =>
path.startsWith('./') || path.startsWith('../')
? path
: `./${path}`;

// if the string is empty, it's the current file
const importPathResolved =
relativePath === ''
? `./${basename(importPath)}`
: joinPathFragments(
relativePath,
basename(importPath)
: ensureRelativeForm(
joinPathFragments(
relativePath,
basename(importPath)
)
);

importsToRemap.push({
Expand Down
46 changes: 44 additions & 2 deletions packages/eslint-plugin/src/utils/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,38 @@ function tryReadBaseJson() {
*/
export function getBarrelEntryPointByImportScope(
importScope: string
): string[] | null {
): string[] {
const tryPaths = (
paths: Record<string, string[]>,
importScope: string
): string[] => {
// TODO check and warn that the entries of paths[importScope] have no wildcards; that'd be user misconfiguration
if (paths[importScope]) return paths[importScope];

// accommodate wildcards (it's not glob) https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
const result = new Set<string>(); // set ensures there are no duplicates

for (const [alias, targets] of Object.entries(paths)) {
if (!alias.endsWith('*')) {
continue;
}
const strippedAlias = alias.slice(0, -1); // remove asterisk
if (!importScope.startsWith(strippedAlias)) {
continue;
}
const dynamicPart = importScope.slice(strippedAlias.length);
targets.forEach((target) => {
result.add(target.replace('*', dynamicPart)); // add interpolated value
});
// we found the entry for importScope; an import scope not supposed and has no sense having > 1 Aliases; TODO warn on duplicated entries
break;
}

return Array.from(result);
};
const tsConfigBase = tryReadBaseJson();
return tsConfigBase?.compilerOptions?.paths[importScope] || null;
if (!tsConfigBase?.compilerOptions?.paths) return [];
return tryPaths(tsConfigBase.compilerOptions.paths, importScope);
}

export function getBarrelEntryPointProjectNode(
Expand Down Expand Up @@ -90,7 +119,20 @@ export function getRelativeImportPath(exportedMember, filePath, basePath) {
} else {
return;
}
} else if (
!lstatSync(filePath, {
throwIfNoEntry: false,
}) /*not folder, but probably not full file with an extension either*/
) {
// try to find an extension that exists
const ext = ['.ts', '.tsx', '.js', '.jsx'].find((ext) =>
lstatSync(filePath + ext, { throwIfNoEntry: false })
);
if (ext) {
filePath += ext;
}
}

const fileContent = readFileSync(filePath, 'utf8');

// use the TypeScript AST to find the path to the file where exportedMember is defined
Expand Down

1 comment on commit 9c7ded0

@vercel
Copy link

@vercel vercel bot commented on 9c7ded0 Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app
nx.dev
nx-five.vercel.app

Please sign in to comment.