Skip to content

Commit

Permalink
feat(linter): add internal rule to prevent deep import from plugins/js
Browse files Browse the repository at this point in the history
  • Loading branch information
meeroslav committed Apr 12, 2023
1 parent 3eede1c commit f0b0d1d
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"rules": {
"@nrwl/nx/workspace/valid-schema-description": "error"
}
},
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {
"@nrwl/nx/workspace/restrict-js-plugin-deep-import": "error"
}
}
]
}
2 changes: 1 addition & 1 deletion packages/nx/src/plugins/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { projectGraphCacheDirectory } from '../../utils/cache-directory';
import { readFileSync, writeFileSync } from 'fs';
import { workspaceRoot } from '../../utils/workspace-root';
import { ensureDirSync } from 'fs-extra';
import { removeNpmNodes } from 'nx/src/plugins/js/lock-file/remove-npm-nodes';
import { removeNpmNodes } from './lock-file/remove-npm-nodes';

export const processProjectGraph: ProjectGraphProcessor = async (
graph,
Expand Down
9 changes: 8 additions & 1 deletion tools/eslint-rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
RULE_NAME as restrictJsPluginDeepImportName,
rule as restrictJsPluginDeepImport,
} from './rules/restrict-js-plugin-deep-import';
import {
RULE_NAME as validSchemaDescriptionName,
rule as validSchemaDescription,
Expand Down Expand Up @@ -27,5 +31,8 @@ module.exports = {
* [myCustomRuleName]: myCustomRule
* }
*/
rules: { [validSchemaDescriptionName]: validSchemaDescription },
rules: {
[validSchemaDescriptionName]: validSchemaDescription,
[restrictJsPluginDeepImportName]: restrictJsPluginDeepImport,
},
};
11 changes: 11 additions & 0 deletions tools/eslint-rules/rules/restrict-js-plugin-deep-import.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { TSESLint } from '@typescript-eslint/utils';
import { rule, RULE_NAME } from './restrict-js-plugin-deep-import';

const ruleTester = new TSESLint.RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
});

ruleTester.run(RULE_NAME, rule, {
valid: [`const example = true;`],
invalid: [],
});
104 changes: 104 additions & 0 deletions tools/eslint-rules/rules/restrict-js-plugin-deep-import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* This file sets you up with structure needed for an ESLint rule.
*
* It leverages utilities from @typescript-eslint to allow TypeScript to
* provide autocompletions etc for the configuration.
*
* Your rule's custom logic will live within the create() method below
* and you can learn more about writing ESLint rules on the official guide:
*
* https://eslint.org/docs/developer-guide/working-with-rules
*
* You can also view many examples of existing rules here:
*
* https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/src/rules
*/

import { normalizePath, workspaceRoot } from '@nrwl/devkit';
import {
ESLintUtils,
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/utils';

// NOTE: The rule will be available in ESLint configs as "@nrwl/nx/workspace/restrict-js-plugin-deep-import"
export const RULE_NAME = 'restrict-js-plugin-deep-import';

export const rule = ESLintUtils.RuleCreator(() => __filename)({
name: RULE_NAME,
meta: {
type: 'problem',
docs: {
description: `Ensure that there are no deep imports from nx/src/plugins/js`,
recommended: 'error',
},
schema: [],
messages: {
noDeepImport:
'Functions from "nx/src/plugins/js" should be imported via barrel import. Deep import found: {{imp}}',
noDeepRelativeImport:
'Functions from "./plugins/js" should be imported via relative barrel import. Deep import found: {{imp}}',
},
},
defaultOptions: [],
create(context) {
function run(
node:
| TSESTree.ImportDeclaration
| TSESTree.ImportExpression
| TSESTree.ExportAllDeclaration
| TSESTree.ExportNamedDeclaration
) {
// Ignoring ExportNamedDeclarations like:
// export class Foo {}
if (!node.source) {
return;
}

// accept only literals because template literals have no value
if (node.source.type !== AST_NODE_TYPES.Literal) {
return;
}
const imp = node.source.value as string;
if (imp.includes('nx/src/plugins/js/')) {
context.report({
node,
messageId: 'noDeepImport',
data: {
imp,
},
});
}
const fileName = normalizePath(context.getFilename()).slice(
workspaceRoot.length + 1
);
if (
imp.includes('./plugins/js/') &&
fileName.startsWith('packages/nx/')
) {
context.report({
node,
messageId: 'noDeepRelativeImport',
data: {
imp,
},
});
}
}

return {
ImportDeclaration(node: TSESTree.ImportDeclaration) {
run(node);
},
ImportExpression(node: TSESTree.ImportExpression) {
run(node);
},
ExportAllDeclaration(node: TSESTree.ExportAllDeclaration) {
run(node);
},
ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration) {
run(node);
},
};
},
});

0 comments on commit f0b0d1d

Please sign in to comment.