From 4c20628d0c4e722f6aa35f295a3af97d613faa57 Mon Sep 17 00:00:00 2001 From: Miroslav Jonas Date: Tue, 5 Sep 2023 15:25:21 +0200 Subject: [PATCH] feat(linter): remove tslint logic --- docs/generated/manifests/menus.json | 16 - docs/generated/manifests/nx-api.json | 18 - docs/generated/packages-metadata.json | 18 - .../generators/convert-tslint-to-eslint.json | 64 - .../packages/linter/documents/overview.md | 1 - .../generators/convert-tslint-to-eslint.json | 54 - docs/packages.json | 2 - docs/shared/mental-model/large-tasks.json | 115 -- docs/shared/packages/linter/linter-plugin.md | 1 - docs/shared/reference/sitemap.md | 2 - nx-dev/nx-dev-e2e/src/packages.spec.ts | 8 - nx-dev/nx-dev/redirect-rules.js | 4 - package.json | 1 - packages/angular/generators.json | 12 - packages/angular/generators.ts | 1 - .../convert-tslint-to-eslint.spec.ts.snap | 1248 ----------------- .../convert-tslint-to-eslint/compat.ts | 10 - .../convert-tslint-to-eslint.spec.ts | 368 ----- .../convert-tslint-to-eslint.ts | 206 --- .../convert-tslint-to-eslint/schema.json | 55 - .../src/generators/library/library.spec.ts | 1 - packages/cypress/index.ts | 2 - .../convert-tslint-to-eslint.spec.ts.snap | 274 ---- .../convert-tslint-to-eslint.spec.ts | 178 --- .../convert-tslint-to-eslint.ts | 134 -- .../convert-tslint-to-eslint/schema.json | 45 - .../configuration/configuration.spec.ts | 9 +- .../configuration/lib/update-workspace.ts | 16 - packages/linter/.eslintrc.json | 1 - packages/linter/index.ts | 2 - packages/linter/package.json | 1 - .../convert-to-eslint-config.spec.ts.snap | 244 ---- .../project-converter.spec.ts.snap | 351 ----- ...-nx-enforce-module-boundaries-rule.spec.ts | 166 --- ...nvert-nx-enforce-module-boundaries-rule.ts | 82 -- .../convert-to-eslint-config.spec.ts | 169 --- .../convert-to-eslint-config.ts | 230 --- .../example-tslint-configs.ts | 324 ----- .../utils/convert-tslint-to-eslint/index.ts | 7 - .../project-converter.spec.ts | 417 ------ .../project-converter.ts | 565 -------- .../convert-tslint-to-eslint/utils.spec.ts | 58 - .../utils/convert-tslint-to-eslint/utils.ts | 143 -- packages/linter/src/utils/versions.ts | 2 - packages/nest/generators.json | 12 - packages/nest/index.ts | 2 - .../convert-tslint-to-eslint.spec.ts.snap | 571 -------- .../convert-tslint-to-eslint.spec.ts | 246 ---- .../convert-tslint-to-eslint.ts | 156 --- .../convert-tslint-to-eslint/schema.json | 45 - .../configuration/lib/util-functions.ts | 17 +- .../src/plugins/write-index-html-plugin.ts | 1 - .../webpack/plugins/postcss-cli-resources.ts | 1 - ...t-configuration-in-new-destination.spec.ts | 19 +- packages/workspace/src/utils/testing-utils.ts | 78 +- packages/workspace/testing.ts | 6 +- pnpm-lock.yaml | 87 -- 57 files changed, 18 insertions(+), 6848 deletions(-) delete mode 100644 docs/generated/packages/angular/generators/convert-tslint-to-eslint.json delete mode 100644 docs/generated/packages/nest/generators/convert-tslint-to-eslint.json delete mode 100644 packages/angular/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap delete mode 100644 packages/angular/src/generators/convert-tslint-to-eslint/compat.ts delete mode 100644 packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts delete mode 100755 packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts delete mode 100644 packages/angular/src/generators/convert-tslint-to-eslint/schema.json delete mode 100644 packages/cypress/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap delete mode 100644 packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts delete mode 100755 packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts delete mode 100644 packages/cypress/src/generators/convert-tslint-to-eslint/schema.json delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/convert-to-eslint-config.spec.ts.snap delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/project-converter.spec.ts.snap delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.spec.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.spec.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/example-tslint-configs.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/index.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/project-converter.spec.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/project-converter.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/utils.spec.ts delete mode 100644 packages/linter/src/utils/convert-tslint-to-eslint/utils.ts delete mode 100644 packages/nest/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap delete mode 100644 packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts delete mode 100755 packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts delete mode 100644 packages/nest/src/generators/convert-tslint-to-eslint/schema.json diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 6d6acf28bab71..9f0939cf841d3 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -6031,14 +6031,6 @@ "isExternal": false, "disableCollapsible": false }, - { - "id": "convert-tslint-to-eslint", - "path": "/nx-api/angular/generators/convert-tslint-to-eslint", - "name": "convert-tslint-to-eslint", - "children": [], - "isExternal": false, - "disableCollapsible": false - }, { "id": "directive", "path": "/nx-api/angular/generators/directive", @@ -7101,14 +7093,6 @@ "isExternal": false, "disableCollapsible": false }, - { - "id": "convert-tslint-to-eslint", - "path": "/nx-api/nest/generators/convert-tslint-to-eslint", - "name": "convert-tslint-to-eslint", - "children": [], - "isExternal": false, - "disableCollapsible": false - }, { "id": "init", "path": "/nx-api/nest/generators/init", diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index 65548e9928ede..4db7c83acf990 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -168,15 +168,6 @@ "path": "/nx-api/angular/generators/component-test", "type": "generator" }, - "/nx-api/angular/generators/convert-tslint-to-eslint": { - "description": "Converts a project from TSLint to ESLint.", - "file": "generated/packages/angular/generators/convert-tslint-to-eslint.json", - "hidden": false, - "name": "convert-tslint-to-eslint", - "originalFilePath": "/packages/angular/src/generators/convert-tslint-to-eslint/schema.json", - "path": "/nx-api/angular/generators/convert-tslint-to-eslint", - "type": "generator" - }, "/nx-api/angular/generators/directive": { "description": "Generate an Angular directive.", "file": "generated/packages/angular/generators/directive.json", @@ -1180,15 +1171,6 @@ "path": "/nx-api/nest/generators/application", "type": "generator" }, - "/nx-api/nest/generators/convert-tslint-to-eslint": { - "description": "Convert a project from TSLint to ESLint.", - "file": "generated/packages/nest/generators/convert-tslint-to-eslint.json", - "hidden": false, - "name": "convert-tslint-to-eslint", - "originalFilePath": "/packages/nest/src/generators/convert-tslint-to-eslint/schema.json", - "path": "/nx-api/nest/generators/convert-tslint-to-eslint", - "type": "generator" - }, "/nx-api/nest/generators/init": { "description": "Initialize the `@nrwl/nest` plugin.", "file": "generated/packages/nest/generators/init.json", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 3075e1de3e993..1429c5cc8270c 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -163,15 +163,6 @@ "path": "angular/generators/component-test", "type": "generator" }, - { - "description": "Converts a project from TSLint to ESLint.", - "file": "generated/packages/angular/generators/convert-tslint-to-eslint.json", - "hidden": false, - "name": "convert-tslint-to-eslint", - "originalFilePath": "/packages/angular/src/generators/convert-tslint-to-eslint/schema.json", - "path": "angular/generators/convert-tslint-to-eslint", - "type": "generator" - }, { "description": "Generate an Angular directive.", "file": "generated/packages/angular/generators/directive.json", @@ -1162,15 +1153,6 @@ "path": "nest/generators/application", "type": "generator" }, - { - "description": "Convert a project from TSLint to ESLint.", - "file": "generated/packages/nest/generators/convert-tslint-to-eslint.json", - "hidden": false, - "name": "convert-tslint-to-eslint", - "originalFilePath": "/packages/nest/src/generators/convert-tslint-to-eslint/schema.json", - "path": "nest/generators/convert-tslint-to-eslint", - "type": "generator" - }, { "description": "Initialize the `@nrwl/nest` plugin.", "file": "generated/packages/nest/generators/init.json", diff --git a/docs/generated/packages/angular/generators/convert-tslint-to-eslint.json b/docs/generated/packages/angular/generators/convert-tslint-to-eslint.json deleted file mode 100644 index cd5f0ee01d690..0000000000000 --- a/docs/generated/packages/angular/generators/convert-tslint-to-eslint.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "convert-tslint-to-eslint", - "factory": "./src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionGenerator", - "schema": { - "$schema": "http://json-schema.org/schema", - "$id": "NxAngularConvertTSLintToESLintGenerator", - "cli": "nx", - "title": "Convert an Angular project from TSLint to ESLint", - "description": "Convert an Angular project from TSLint to ESLint. NOTE: Does not work in `--dry-run mode`.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "examples": [ - { - "command": "nx g convert-tslint-to-eslint myapp", - "description": "The following will first configure the project, `myapp`, the same way a _new_ project is configured i.e. It will use Nx's new recommended ESLint config. By default, this also adds the existing TSLint configuration on top of the default ESLint config from Nx to continue checking what it checks today. This is done by migrating TSLint rules to their equivalent ESLint rules to the best of its abilities. Some TSLint rules may not have ESLint equivalents and will be reported during the conversion" - }, - { - "command": "nx g convert-tslint-to-eslint myapp --ignoreExistingTslintConfig=true", - "description": "If your TSLint config isn't extremely important to you, ignoring it makes this process more deterministic. Unlike the prior example, this will discard the existing TSLint configuration, meaning that the project will only have the Nx's latest recommended ESLint configuration which may be good enough for some workspaces" - }, - { - "command": "nx g convert-tslint-to-eslint myapp --removeTSLintIfNoMoreTSLintTargets=false", - "description": "By default, this process removes the TSLint related dependencies and configuration once no more projects use TSLint. This can be disabled with the following flag to keep TSLint related dependencies and configuration in the repo" - } - ], - "type": "object", - "properties": { - "project": { - "description": "The name of the Angular project to convert. Please note, if the project is an Angular app with an associated Cypress e2e project, it will also attempt to convert that.", - "type": "string", - "$default": { "$source": "argv", "index": 0 }, - "x-prompt": "Which Angular project would you like to convert from TSLint to ESLint?", - "x-priority": "important" - }, - "ignoreExistingTslintConfig": { - "type": "boolean", - "description": "If true, it will not use existing TSLint config as a reference, it will just reset the project with the latest recommended ESLint config.", - "default": false, - "x-prompt": "Would you like to ignore the existing TSLint config? Recommended if the TSLint config has not been altered much as it makes the new ESLint config cleaner." - }, - "removeTSLintIfNoMoreTSLintTargets": { - "type": "boolean", - "description": "If this conversion leaves no more TSLint usage in the workspace, it will remove TSLint and related dependencies and configuration.", - "default": true, - "x-prompt": "Would you like to remove TSLint and its related config if there are no TSLint projects remaining after this conversion?" - }, - "skipFormat": { - "type": "boolean", - "description": "Skip formatting files.", - "default": false, - "x-priority": "internal" - } - }, - "additionalProperties": false, - "required": ["project"], - "presets": [] - }, - "description": "Converts a project from TSLint to ESLint.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "implementation": "/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionGenerator.ts", - "aliases": [], - "hidden": false, - "path": "/packages/angular/src/generators/convert-tslint-to-eslint/schema.json", - "type": "generator" -} diff --git a/docs/generated/packages/linter/documents/overview.md b/docs/generated/packages/linter/documents/overview.md index 30f9e8745c015..f987ba1a7cb9c 100644 --- a/docs/generated/packages/linter/documents/overview.md +++ b/docs/generated/packages/linter/documents/overview.md @@ -33,7 +33,6 @@ nx lint my-lib ## Utils - [convert-to-flat-config](/nx-api/linter/generators/convert-to-flat-config) - Converts the workspace's [ESLint](https://eslint.org/) configs to the new [Flat Config](https://eslint.org/blog/2022/08/new-config-system-part-2) -- **Deprecated** [convert-tslint-to-eslint](/nx-api/angular/generators/convert-tslint-to-eslint) - Converts a project linter from [TSLint](https://palantir.github.io/tslint/) to [ESLint](https://eslint.org/) ## ESLint plugin diff --git a/docs/generated/packages/nest/generators/convert-tslint-to-eslint.json b/docs/generated/packages/nest/generators/convert-tslint-to-eslint.json deleted file mode 100644 index a9459ede5db58..0000000000000 --- a/docs/generated/packages/nest/generators/convert-tslint-to-eslint.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "convert-tslint-to-eslint", - "factory": "./src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionGenerator", - "schema": { - "$schema": "http://json-schema.org/schema", - "$id": "nest-convert-tslint-to-eslint", - "cli": "nx", - "title": "Convert a NestJS project from TSLint to ESLint", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "description": "Convert a NestJS project from TSLint to ESLint. \n_NOTE: Does not work in `--dry-run` mode_.", - "examples": [ - { - "command": "nx g convert-tslint-to-eslint myapp", - "description": "Convert the NestJS project `myapp` from TSLint to ESLint" - } - ], - "type": "object", - "properties": { - "project": { - "description": "The name of the NestJS project to convert.", - "type": "string", - "$default": { "$source": "argv", "index": 0 }, - "x-prompt": "Which NestJS project would you like to convert from TSLint to ESLint?" - }, - "ignoreExistingTslintConfig": { - "description": "If true we will not use existing TSLint config as a reference, we will just reset the project with the latest recommended ESLint config.", - "type": "boolean", - "default": false, - "x-prompt": "Would you like to ignore the existing TSLint config? Recommended if the TSLint config has not been altered much as it makes the new ESLint config cleaner." - }, - "removeTSLintIfNoMoreTSLintTargets": { - "description": "If this conversion leaves no more TSLint usage in the workspace, it will remove TSLint and related dependencies and configuration.", - "type": "boolean", - "default": true, - "x-prompt": "Would you like to remove TSLint and its related config if there are no TSLint projects remaining after this conversion?" - }, - "skipFormat": { - "type": "boolean", - "description": "Skip formatting files.", - "default": false, - "x-priority": "internal" - } - }, - "required": ["project"], - "presets": [] - }, - "description": "Convert a project from TSLint to ESLint.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "implementation": "/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionGenerator.ts", - "aliases": [], - "hidden": false, - "path": "/packages/nest/src/generators/convert-tslint-to-eslint/schema.json", - "type": "generator" -} diff --git a/docs/packages.json b/docs/packages.json index 11483d176b7ab..940b5fa37d70e 100644 --- a/docs/packages.json +++ b/docs/packages.json @@ -22,7 +22,6 @@ "component-cypress-spec", "component-story", "component-test", - "convert-tslint-to-eslint", "downgrade-module", "init", "karma", @@ -186,7 +185,6 @@ "executors": [], "generators": [ "application", - "convert-tslint-to-eslint", "init", "library", "class", diff --git a/docs/shared/mental-model/large-tasks.json b/docs/shared/mental-model/large-tasks.json index f1a3377ff5807..f2c8e8328986d 100644 --- a/docs/shared/mental-model/large-tasks.json +++ b/docs/shared/mental-model/large-tasks.json @@ -8188,24 +8188,6 @@ "file": "packages/angular/src/generators/convert-to-with-mf/schema.json", "hash": "ce0a0a44c5560369c7eccc27cb3397bec7044b84" }, - { - "file": "packages/angular/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap", - "hash": "88a46d8d249b5e8cacbcee62b34eaafa179fe072" - }, - { - "file": "packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts", - "hash": "d9ef5aa20defb703c8cd0d007141e973c15ece74", - "deps": ["devkit", "linter"] - }, - { - "file": "packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts", - "hash": "cbbde4fcdf3983aafd4d3ec1a7f50cf4b90e22a2", - "deps": ["cypress", "devkit", "linter", "npm:eslint"] - }, - { - "file": "packages/angular/src/generators/convert-tslint-to-eslint/schema.json", - "hash": "c3b47a2dee7b256b9d74c6ae11a24f7fe31bcf18" - }, { "file": "packages/angular/src/generators/cypress-component-configuration/__snapshots__/cypress-component-configuration.spec.ts.snap", "hash": "cde7951d23c9c688fae6926d6c72eaeabb30b0f1" @@ -10642,24 +10624,6 @@ "file": "packages/cypress/src/executors/cypress/schema.json", "hash": "1e62f9dc2fb140c35dd41cde710ecbe39bedb0ea" }, - { - "file": "packages/cypress/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap", - "hash": "9eae619b87c6e22815cde69073bc0bb1471355da" - }, - { - "file": "packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts", - "hash": "6748869ec5c7c6f4e794d75b43308125c364ca2c", - "deps": ["devkit", "linter"] - }, - { - "file": "packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts", - "hash": "da0dd512554fc7ac8e0119675af3093a1e7db20c", - "deps": ["devkit", "linter", "npm:eslint"] - }, - { - "file": "packages/cypress/src/generators/convert-tslint-to-eslint/schema.json", - "hash": "a17853c7974502253b2d0c70644281b896396924" - }, { "file": "packages/cypress/src/generators/cypress-component-project/__snapshots__/cypress-component-project.spec.ts.snap", "hash": "36e5eec5d8f46d596590918a7285b17baaa7491b" @@ -12905,66 +12869,6 @@ "hash": "c40a4057d319e764fe1036ee11340ab8dc0913c4", "deps": ["devkit", "workspace"] }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/convert-to-eslint-config.spec.ts.snap", - "hash": "a2c28519469336f0570d45d89e19b45bb21a246c" - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/project-converter.spec.ts.snap", - "hash": "2977c64472b0117a1dfe68578a364c1e9dd62c25" - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.spec.ts", - "hash": "044ca66897f1760b5880dbd919f6cb03eea3997a" - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.ts", - "hash": "fcc7325c70e5f771bbaf57fd941323cdb500191e", - "deps": ["npm:tslint-to-eslint-config"] - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.spec.ts", - "hash": "673ab6bce04f69e7a83c3e61f396f6737f29a04a", - "deps": ["devkit"] - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.ts", - "hash": "3c72b9cba9d5239bd29d85b3558db71c940fe1fb", - "deps": [ - "devkit", - "npm:eslint", - "npm:tmp", - "npm:tslint-to-eslint-config" - ] - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/example-tslint-configs.ts", - "hash": "2c4123c381aaa6c18eebb53871e346600247d198" - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/index.ts", - "hash": "cc95094649634a3a38643aef1808f95c7b1ec24f" - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/project-converter.spec.ts", - "hash": "b38af0e8a1a5c83d1bd4938d132b4d1159796471", - "deps": ["devkit"] - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/project-converter.ts", - "hash": "fb446fabddcfbc205ffd21b879d465f4b966a235", - "deps": ["devkit", "npm:eslint"] - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/utils.spec.ts", - "hash": "6b1b4492c31d634d109988e63140add48db58ba0", - "deps": ["npm:eslint"] - }, - { - "file": "packages/linter/src/utils/convert-tslint-to-eslint/utils.ts", - "hash": "cbb058ac8381c33b77e769a258d6bdbdb7142e26", - "deps": ["devkit", "npm:eslint", "npm:tslint-to-eslint-config"] - }, { "file": "packages/linter/src/utils/rules-requiring-type-checking.ts", "hash": "a5bb99e79b0d1b5b736419bcc42157197179cd66", @@ -18074,24 +17978,6 @@ "file": "packages/nest/src/generators/controller/schema.json", "hash": "a93969679f0b96aaaf2f59207e2c602bfb8df262" }, - { - "file": "packages/nest/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap", - "hash": "39896d5381137e79eb91c543f9a68e2458e174b3" - }, - { - "file": "packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts", - "hash": "e3aa199189251121c4ddf3a103f9f75339320279", - "deps": ["devkit", "linter"] - }, - { - "file": "packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts", - "hash": "a1751f46b20f03f5bb0c31c8ca03fcbc4eecfe16", - "deps": ["devkit", "linter", "node", "workspace", "npm:eslint"] - }, - { - "file": "packages/nest/src/generators/convert-tslint-to-eslint/schema.json", - "hash": "b728083f6ebb1ea27b7c055df547bebafcbbd8f9" - }, { "file": "packages/nest/src/generators/decorator/decorator.spec.ts", "hash": "a734ede264980d9035148aabd78c127c7aee856b", @@ -27184,7 +27070,6 @@ "npm:ts-node", "npm:tsconfig-paths", "npm:tsconfig-paths-webpack-plugin", - "npm:tslint-to-eslint-config", "npm:typedoc", "npm:typedoc-plugin-markdown", "npm:typescript", diff --git a/docs/shared/packages/linter/linter-plugin.md b/docs/shared/packages/linter/linter-plugin.md index 30f9e8745c015..f987ba1a7cb9c 100644 --- a/docs/shared/packages/linter/linter-plugin.md +++ b/docs/shared/packages/linter/linter-plugin.md @@ -33,7 +33,6 @@ nx lint my-lib ## Utils - [convert-to-flat-config](/nx-api/linter/generators/convert-to-flat-config) - Converts the workspace's [ESLint](https://eslint.org/) configs to the new [Flat Config](https://eslint.org/blog/2022/08/new-config-system-part-2) -- **Deprecated** [convert-tslint-to-eslint](/nx-api/angular/generators/convert-tslint-to-eslint) - Converts a project linter from [TSLint](https://palantir.github.io/tslint/) to [ESLint](https://eslint.org/) ## ESLint plugin diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index d77d28bddedca..d797ae385fc40 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -312,7 +312,6 @@ - [component-cypress-spec](/nx-api/angular/generators/component-cypress-spec) - [component-story](/nx-api/angular/generators/component-story) - [component-test](/nx-api/angular/generators/component-test) - - [convert-tslint-to-eslint](/nx-api/angular/generators/convert-tslint-to-eslint) - [directive](/nx-api/angular/generators/directive) - [init](/nx-api/angular/generators/init) - [library](/nx-api/angular/generators/library) @@ -441,7 +440,6 @@ - [Overview](/nx-api/nest/documents/overview) - [generators](/nx-api/nest/generators) - [application](/nx-api/nest/generators/application) - - [convert-tslint-to-eslint](/nx-api/nest/generators/convert-tslint-to-eslint) - [init](/nx-api/nest/generators/init) - [library](/nx-api/nest/generators/library) - [class](/nx-api/nest/generators/class) diff --git a/nx-dev/nx-dev-e2e/src/packages.spec.ts b/nx-dev/nx-dev-e2e/src/packages.spec.ts index 811de2229340a..91f4e89fe38d1 100644 --- a/nx-dev/nx-dev-e2e/src/packages.spec.ts +++ b/nx-dev/nx-dev-e2e/src/packages.spec.ts @@ -23,10 +23,6 @@ const pages: Array<{ title: string; path: string }> = [ title: '@nx/angular:component-story', path: '/packages/angular/generators/component-story', }, - { - title: '@nx/angular:convert-tslint-to-eslint', - path: '/packages/angular/generators/convert-tslint-to-eslint', - }, { title: '@nx/angular:init', path: '/packages/angular/generators/init' }, { title: '@nx/angular:library', @@ -188,10 +184,6 @@ const pages: Array<{ title: string; path: string }> = [ title: '@nx/nest:application', path: '/packages/nest/generators/application', }, - { - title: '@nx/nest:convert-tslint-to-eslint', - path: '/packages/nest/generators/convert-tslint-to-eslint', - }, { title: '@nx/nest:init', path: '/packages/nest/generators/init' }, { title: '@nx/nest:library', path: '/packages/nest/generators/library' }, { title: '@nx/nest:class', path: '/packages/nest/generators/class' }, diff --git a/nx-dev/nx-dev/redirect-rules.js b/nx-dev/nx-dev/redirect-rules.js index 33c3d15c917e1..a4855abced767 100644 --- a/nx-dev/nx-dev/redirect-rules.js +++ b/nx-dev/nx-dev/redirect-rules.js @@ -30,8 +30,6 @@ const schemaUrls = { '/web/file-server': '/packages/web/executors/file-server', '/web/package': '/packages/web/executors/rollup', '/angular/application': '/packages/angular/generators/application', - '/angular/convert-tslint-to-eslint': - '/packages/angular/generators/convert-tslint-to-eslint', '/angular/downgrade-module': '/packages/angular/generators/downgrade-module', '/angular/karma': '/packages/angular/generators/karma', '/angular/karma-project': '/packages/angular/generators/karma-project', @@ -115,8 +113,6 @@ const schemaUrls = { '/nest/resolver': '/packages/nest/generators/resolver', '/nest/resource': '/packages/nest/generators/resource', '/nest/service': '/packages/nest/generators/service', - '/nest/convert-tslint-to-eslint': - '/packages/nest/generators/convert-tslint-to-eslint', '/next/application': '/packages/next/generators/application', '/next/component': '/packages/next/generators/component', '/next/page': '/packages/next/generators/page', diff --git a/package.json b/package.json index b8d3d60a533a7..51bf31f848ed9 100644 --- a/package.json +++ b/package.json @@ -278,7 +278,6 @@ "ts-node": "10.9.1", "tsconfig-paths": "^4.1.2", "tsconfig-paths-webpack-plugin": "4.0.0", - "tslint-to-eslint-config": "^2.14.0", "typedoc": "0.24.8", "typedoc-plugin-markdown": "3.15.3", "typescript": "~5.1.3", diff --git a/packages/angular/generators.json b/packages/angular/generators.json index 9102c2499f10c..1f4ffbe4ea583 100644 --- a/packages/angular/generators.json +++ b/packages/angular/generators.json @@ -39,12 +39,6 @@ "schema": "./src/generators/component-test/schema.json", "description": "Creates a cypress component test file for a component." }, - "convert-tslint-to-eslint": { - "factory": "./src/generators/convert-tslint-to-eslint/compat", - "schema": "./src/generators/convert-tslint-to-eslint/schema.json", - "description": "Converts a project from TSLint to ESLint.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint." - }, "init": { "factory": "./src/generators/init/init.compat#initSchematic", "schema": "./src/generators/init/schema.json", @@ -193,12 +187,6 @@ "schema": "./src/generators/component-test/schema.json", "description": "Creates a cypress component test file for a component." }, - "convert-tslint-to-eslint": { - "factory": "./src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionGenerator", - "schema": "./src/generators/convert-tslint-to-eslint/schema.json", - "description": "Converts a project from TSLint to ESLint.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint." - }, "directive": { "factory": "./src/generators/directive/directive", "schema": "./src/generators/directive/schema.json", diff --git a/packages/angular/generators.ts b/packages/angular/generators.ts index f8a41e3493b42..b86fb43f9aa24 100644 --- a/packages/angular/generators.ts +++ b/packages/angular/generators.ts @@ -3,7 +3,6 @@ export * from './src/generators/application/application'; export * from './src/generators/component-cypress-spec/component-cypress-spec'; export * from './src/generators/component-story/component-story'; export * from './src/generators/component/component'; -export * from './src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint'; export * from './src/generators/directive/directive'; export * from './src/generators/host/host'; export * from './src/generators/init/init'; diff --git a/packages/angular/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap b/packages/angular/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap deleted file mode 100644 index 793af59f669d0..0000000000000 --- a/packages/angular/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap +++ /dev/null @@ -1,1248 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`convert-tslint-to-eslint should not override .eslint config if migration in progress 1`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": true, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@angular-eslint/no-conflicting-lifecycle": "error", - "@angular-eslint/no-host-metadata-property": "error", - "@angular-eslint/no-input-rename": "error", - "@angular-eslint/no-inputs-metadata-property": "error", - "@angular-eslint/no-output-native": "error", - "@angular-eslint/no-output-on-prefix": "error", - "@angular-eslint/no-output-rename": "error", - "@angular-eslint/no-outputs-metadata-property": "error", - "@angular-eslint/use-lifecycle-interface": "error", - "@angular-eslint/use-pipe-transform-interface": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - { - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - "@angular-eslint/template/eqeqeq": "error", - "@angular-eslint/template/no-negated-async": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should not override .eslint config if migration in progress 2`] = ` -{ - "extends": [ - "../../.eslintrc.json", - ], - "ignorePatterns": [ - "!**/*", - ], - "overrides": [ - { - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates", - ], - "files": [ - "*.ts", - ], - "plugins": [ - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "angular-app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "angular-app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@typescript-eslint/no-empty-interface": "error", - }, - }, - { - "extends": [ - "plugin:@nx/angular-template", - ], - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - }, - }, - ], -} -`; - -exports[`convert-tslint-to-eslint should not override .eslint config if migration in progress 3`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": false, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@angular-eslint/no-conflicting-lifecycle": "error", - "@angular-eslint/no-host-metadata-property": "error", - "@angular-eslint/no-input-rename": "error", - "@angular-eslint/no-inputs-metadata-property": "error", - "@angular-eslint/no-output-native": "error", - "@angular-eslint/no-output-on-prefix": "error", - "@angular-eslint/no-output-rename": "error", - "@angular-eslint/no-outputs-metadata-property": "error", - "@angular-eslint/use-lifecycle-interface": "error", - "@angular-eslint/use-pipe-transform-interface": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - { - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - "@angular-eslint/template/eqeqeq": "error", - "@angular-eslint/template/no-negated-async": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should work for Angular applications 1`] = ` -{ - "dependencies": {}, - "devDependencies": { - "@angular-eslint/eslint-plugin": "~16.0.0", - "@angular-eslint/eslint-plugin-template": "~16.0.0", - "@angular-eslint/template-parser": "~16.0.0", - "@nx/eslint-plugin": "0.0.1", - "@nx/linter": "0.0.1", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "eslint": "~8.46.0", - "eslint-config-prettier": "8.1.0", - "eslint-plugin-import": "latest", - "jsonc-eslint-parser": "^2.1.0", - }, - "name": "test-name", -} -`; - -exports[`convert-tslint-to-eslint should work for Angular applications 2`] = ` -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "name": "angular-app-1", - "prefix": "angular-app", - "projectType": "application", - "root": "apps/angular-app-1", - "targets": { - "lint": { - "executor": "@nx/linter:eslint", - "options": { - "lintFilePatterns": [ - "apps/angular-app-1/**/*.ts", - "apps/angular-app-1/**/*.html", - ], - }, - "outputs": [ - "{options.outputFile}", - ], - }, - }, -} -`; - -exports[`convert-tslint-to-eslint should work for Angular applications 3`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": true, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@angular-eslint/no-conflicting-lifecycle": "error", - "@angular-eslint/no-host-metadata-property": "error", - "@angular-eslint/no-input-rename": "error", - "@angular-eslint/no-inputs-metadata-property": "error", - "@angular-eslint/no-output-native": "error", - "@angular-eslint/no-output-on-prefix": "error", - "@angular-eslint/no-output-rename": "error", - "@angular-eslint/no-outputs-metadata-property": "error", - "@angular-eslint/use-lifecycle-interface": "error", - "@angular-eslint/use-pipe-transform-interface": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - { - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - "@angular-eslint/template/eqeqeq": "error", - "@angular-eslint/template/no-negated-async": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should work for Angular applications 4`] = ` -{ - "extends": [ - "../../.eslintrc.json", - ], - "ignorePatterns": [ - "!**/*", - ], - "overrides": [ - { - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates", - ], - "files": [ - "*.ts", - ], - "parserOptions": { - "project": [ - "apps/angular-app-1/tsconfig.*?.json", - ], - }, - "plugins": [ - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "angular-app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "angular-app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/no-empty-interface": "error", - }, - }, - { - "extends": [ - "plugin:@nx/angular-template", - ], - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - }, - }, - ], -} -`; - -exports[`convert-tslint-to-eslint should work for Angular libraries 1`] = ` -{ - "dependencies": {}, - "devDependencies": { - "@angular-eslint/eslint-plugin": "~16.0.0", - "@angular-eslint/eslint-plugin-template": "~16.0.0", - "@angular-eslint/template-parser": "~16.0.0", - "@nx/eslint-plugin": "0.0.1", - "@nx/linter": "0.0.1", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "eslint": "~8.46.0", - "eslint-config-prettier": "8.1.0", - "eslint-plugin-import": "latest", - "jsonc-eslint-parser": "^2.1.0", - }, - "name": "test-name", -} -`; - -exports[`convert-tslint-to-eslint should work for Angular libraries 2`] = ` -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "name": "angular-lib-1", - "prefix": "angular-app", - "projectType": "library", - "root": "libs/angular-lib-1", - "targets": { - "lint": { - "executor": "@nx/linter:eslint", - "options": { - "lintFilePatterns": [ - "libs/angular-lib-1/**/*.ts", - "libs/angular-lib-1/**/*.html", - ], - }, - "outputs": [ - "{options.outputFile}", - ], - }, - }, -} -`; - -exports[`convert-tslint-to-eslint should work for Angular libraries 3`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": true, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@angular-eslint/no-conflicting-lifecycle": "error", - "@angular-eslint/no-host-metadata-property": "error", - "@angular-eslint/no-input-rename": "error", - "@angular-eslint/no-inputs-metadata-property": "error", - "@angular-eslint/no-output-native": "error", - "@angular-eslint/no-output-on-prefix": "error", - "@angular-eslint/no-output-rename": "error", - "@angular-eslint/no-outputs-metadata-property": "error", - "@angular-eslint/use-lifecycle-interface": "error", - "@angular-eslint/use-pipe-transform-interface": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - { - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - "@angular-eslint/template/eqeqeq": "error", - "@angular-eslint/template/no-negated-async": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should work for Angular libraries 4`] = ` -{ - "extends": [ - "../../.eslintrc.json", - ], - "ignorePatterns": [ - "!**/*", - ], - "overrides": [ - { - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates", - ], - "files": [ - "*.ts", - ], - "plugins": [ - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "angular-app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "angular-app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@typescript-eslint/no-empty-interface": "error", - }, - }, - { - "extends": [ - "plugin:@nx/angular-template", - ], - "files": [ - "*.html", - ], - "plugins": [ - "@angular-eslint/eslint-plugin-template", - ], - "rules": { - "@angular-eslint/template/banana-in-box": "error", - }, - }, - ], -} -`; diff --git a/packages/angular/src/generators/convert-tslint-to-eslint/compat.ts b/packages/angular/src/generators/convert-tslint-to-eslint/compat.ts deleted file mode 100644 index 83a7ea48db5f9..0000000000000 --- a/packages/angular/src/generators/convert-tslint-to-eslint/compat.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { convertNxGenerator } from '@nx/devkit'; -import { warnForSchematicUsage } from '../utils/warn-for-schematic-usage'; -import { conversionGenerator } from './convert-tslint-to-eslint'; - -/** - * @deprecated This generator will be removed in v17 - */ -export const conversionSchematic = warnForSchematicUsage( - convertNxGenerator(conversionGenerator) -); diff --git a/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts b/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts deleted file mode 100644 index cf2c2412c76ef..0000000000000 --- a/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts +++ /dev/null @@ -1,368 +0,0 @@ -import { - addProjectConfiguration, - joinPathFragments, - ProjectConfiguration, - readJson, - readProjectConfiguration, - Tree, - writeJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { exampleRootTslintJson } from '@nx/linter'; -import { conversionGenerator } from './convert-tslint-to-eslint'; - -/** - * Don't run actual child_process implementation of installPackagesTask() - */ -jest.mock('child_process', () => { - return { - ...jest.requireActual('child_process'), - execSync: jest.fn((command: string) => { - if (command.includes('pnpm --version')) { - return '8.2.0'; - } - return; - }), - }; -}); - -const appProjectName = 'angular-app-1'; -const appProjectRoot = `apps/${appProjectName}`; -const appProjectTSLintJsonPath = joinPathFragments( - appProjectRoot, - 'tslint.json' -); -const projectPrefix = 'angular-app'; -const libProjectName = 'angular-lib-1'; -const libProjectRoot = `libs/${libProjectName}`; -const libProjectTSLintJsonPath = joinPathFragments( - libProjectRoot, - 'tslint.json' -); -// Used to configure the test Tree and stub the response from tslint-to-eslint-config util findReportedConfiguration() -const projectTslintJsonData = { - raw: { - extends: '../../tslint.json', - rules: { - // Standard Nx/Angular CLI generated rules - 'directive-selector': [true, 'attribute', projectPrefix, 'camelCase'], - 'component-selector': [true, 'element', projectPrefix, 'kebab-case'], - // User custom TS rule - 'no-empty-interface': true, - // User custom template/HTML rule - 'template-banana-in-box': true, - // User custom rule with no known automated converter - 'some-super-custom-rule-with-no-converter': true, - }, - linterOptions: { - exclude: ['!**/*'], - }, - }, - tslintPrintConfigResult: { - rules: { - 'directive-selector': { - ruleArguments: ['attribute', projectPrefix, 'camelCase'], - ruleSeverity: 'error', - }, - 'component-selector': { - ruleArguments: ['element', projectPrefix, 'kebab-case'], - ruleSeverity: 'error', - }, - 'no-empty-interface': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'template-banana-in-box': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'some-super-custom-rule-with-no-converter': { - ruleArguments: [], - ruleSeverity: 'error', - }, - }, - }, -}; - -function mockFindReportedConfiguration(_, pathToTslintJson) { - switch (pathToTslintJson) { - case 'tslint.json': - return exampleRootTslintJson.tslintPrintConfigResult; - case appProjectTSLintJsonPath: - return { - /** - * Add in an example of rule which requires type-checking so we can test - * that parserOptions.project is appropriately preserved in the final - * config in this case. - */ - rules: { - ...projectTslintJsonData.tslintPrintConfigResult.rules, - 'await-promise': { - ruleArguments: [], - ruleSeverity: 'error', - }, - }, - }; - case libProjectTSLintJsonPath: - return projectTslintJsonData.tslintPrintConfigResult; - default: - throw new Error( - `mockFindReportedConfiguration - Did not recognize path ${pathToTslintJson}` - ); - } -} - -/** - * See ./mock-tslint-to-eslint-config.ts for why this is needed - */ -jest.mock('tslint-to-eslint-config', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('tslint-to-eslint-config'), - findReportedConfiguration: jest.fn(mockFindReportedConfiguration), - }; -}); - -/** - * Mock the the mutating fs utilities used within the conversion logic, they are not - * needed because of our stubbed response for findReportedConfiguration() above, and - * they would cause noise in the git data of the actual Nx repo when the tests run. - */ -jest.mock('fs', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('fs'), - writeFileSync: jest.fn(), - mkdirSync: jest.fn(), - }; -}); - -describe('convert-tslint-to-eslint', () => { - let host: Tree; - - beforeEach(async () => { - host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - - writeJson(host, 'tslint.json', exampleRootTslintJson.raw); - - addProjectConfiguration(host, appProjectName, { - root: appProjectRoot, - prefix: projectPrefix, - projectType: 'application', - targets: { - /** - * LINT TARGET CONFIG - BEFORE CONVERSION - * - * TSLint executor configured for the project - */ - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', '!apps/angular-app-1/**/*'], - tsConfig: ['apps/angular-app-1/tsconfig.app.json'], - }, - }, - }, - } as ProjectConfiguration); - - addProjectConfiguration(host, libProjectName, { - root: libProjectRoot, - prefix: projectPrefix, - projectType: 'library', - targets: { - /** - * LINT TARGET CONFIG - BEFORE CONVERSION - * - * TSLint executor configured for the project - */ - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', '!libs/angular-lib-1/**/*'], - tsConfig: ['libs/angular-lib-1/tsconfig.app.json'], - }, - }, - }, - } as ProjectConfiguration); - - /** - * Existing tslint.json file for the app project - */ - writeJson(host, 'apps/angular-app-1/tslint.json', { - ...projectTslintJsonData.raw, - rules: { - ...projectTslintJsonData.raw.rules, - /** - * Add in an example of rule which requires type-checking so we can test - * that parserOptions.project is appropriately preserved in the final - * config in this case. - */ - 'await-promise': true, - }, - }); - /** - * Existing tslint.json file for the lib project - */ - writeJson( - host, - 'libs/angular-lib-1/tslint.json', - projectTslintJsonData.raw - ); - }); - - it('should work for Angular applications', async () => { - await conversionGenerator(host, { - project: appProjectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: false, - }); - - /** - * It should ensure the required Nx packages are installed and available - * - * NOTE: tslint-to-eslint-config should NOT be present - */ - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - /** - * LINT TARGET CONFIG - AFTER CONVERSION - * - * It should replace the TSLint executor with the ESLint one - */ - expect(readProjectConfiguration(host, appProjectName)).toMatchSnapshot(); - - /** - * The root level .eslintrc.json should now have been generated - */ - const eslintJson = readJson(host, '.eslintrc.json'); - expect(eslintJson.overrides[3].rules['no-console'][1].allow).toContain( - 'log' - ); - // Remove no-console config because it is not deterministic across node versions - delete eslintJson.overrides[3].rules['no-console'][1].allow; - expect(eslintJson).toMatchSnapshot(); - - /** - * The project level .eslintrc.json should now have been generated - * and extend from the root, as well as applying any customizations - * which are specific to this projectType. - */ - expect( - readJson(host, joinPathFragments(appProjectRoot, '.eslintrc.json')) - ).toMatchSnapshot(); - - /** - * The project's TSLint file should have been deleted - */ - expect(host.exists(appProjectTSLintJsonPath)).toEqual(false); - }); - - it('should work for Angular libraries', async () => { - await conversionGenerator(host, { - project: libProjectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: false, - }); - - /** - * It should ensure the required Nx packages are installed and available - * - * NOTE: tslint-to-eslint-config should NOT be present - */ - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - /** - * LINT TARGET CONFIG - AFTER CONVERSION - * - * It should replace the TSLint executor with the ESLint one - */ - expect(readProjectConfiguration(host, libProjectName)).toMatchSnapshot(); - - /** - * The root level .eslintrc.json should now have been generated - */ - const eslintJson = readJson(host, '.eslintrc.json'); - expect(eslintJson.overrides[3].rules['no-console'][1].allow).toContain( - 'log' - ); - // Remove no-console config because it is not deterministic across node versions - delete eslintJson.overrides[3].rules['no-console'][1].allow; - expect(eslintJson).toMatchSnapshot(); - - /** - * The project level .eslintrc.json should now have been generated - * and extend from the root, as well as applying any customizations - * which are specific to this projectType. - */ - expect( - readJson(host, joinPathFragments(libProjectRoot, '.eslintrc.json')) - ).toMatchSnapshot(); - - /** - * The project's TSLint file should have been deleted - */ - expect(host.exists(libProjectTSLintJsonPath)).toEqual(false); - }); - - it('should not override .eslint config if migration in progress', async () => { - /** - * First we convert app - */ - await conversionGenerator(host, { - project: appProjectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: true, - }); - - /** - * The root level .eslintrc.json should now have been generated - */ - const eslintContent = readJson(host, '.eslintrc.json'); - expect(eslintContent.overrides[3].rules['no-console'][1].allow).toContain( - 'log' - ); - // Remove no-console config because it is not deterministic across node versions - delete eslintContent.overrides[3].rules['no-console'][1].allow; - expect(eslintContent).toMatchSnapshot(); - - /** - * We will make a change to the eslint config before the next step - */ - eslintContent.overrides[0].rules[ - '@nx/enforce-module-boundaries' - ][1].enforceBuildableLibDependency = false; - writeJson(host, '.eslintrc.json', eslintContent); - - /** - * Convert the lib - */ - await conversionGenerator(host, { - project: libProjectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: true, - }); - - /** - * The project level .eslintrc.json should now have been generated - * and extend from the root, as well as applying any customizations - * which are specific to this projectType. - */ - expect( - readJson(host, joinPathFragments(libProjectRoot, '.eslintrc.json')) - ).toMatchSnapshot(); - - /** - * The root level .eslintrc.json should not be re-created - * if it already existed - */ - const eslintJson2 = readJson(host, '.eslintrc.json'); - expect(eslintJson2).toMatchSnapshot(); - - /** - * The root TSLint file should have been deleted - */ - expect(host.exists('tslint.json')).toEqual(false); - }); -}); diff --git a/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts b/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts deleted file mode 100755 index c9d3ea5858acd..0000000000000 --- a/packages/angular/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { conversionGenerator as cypressConversionGenerator } from '@nx/cypress'; -import { formatFiles, GeneratorCallback, logger, Tree } from '@nx/devkit'; -import { ConvertTSLintToESLintSchema, ProjectConverter } from '@nx/linter'; -import type { Linter } from 'eslint'; -import type { AngularProjectConfiguration } from '../../utils/types'; -import { addLintingGenerator } from '../add-linting/add-linting'; - -/** - * @deprecated This generator will be removed in v17 - */ -export async function conversionGenerator( - host: Tree, - options: ConvertTSLintToESLintSchema -) { - /** - * The ProjectConverter instance encapsulates all the standard operations we need - * to perform in order to convert a project from TSLint to ESLint, as well as some - * extensibility points for adjusting the behavior on a per package basis. - * - * E.g. @nx/angular projects might need to make different changes to the final - * ESLint config when compared with @nx/next projects. - * - * See the ProjectConverter implementation for a full breakdown of what it does. - */ - const projectConverter = new ProjectConverter({ - host, - projectName: options.project, - ignoreExistingTslintConfig: options.ignoreExistingTslintConfig, - eslintInitializer: async ({ projectName, projectConfig }) => { - await addLintingGenerator(host, { - projectName, - projectRoot: projectConfig.root, - prefix: (projectConfig as AngularProjectConfiguration).prefix || 'app', - /** - * We set the parserOptions.project config just in case the converted config uses - * rules which require type-checking. Later in the conversion we check if it actually - * does and remove the config again if it doesn't, so that it is most efficient. - */ - setParserOptionsProject: true, - skipFormat: true, - }); - }, - }); - - /** - * If root eslint configuration already exists it will not be recreated - * but we also don't want to re-run the tslint config conversion - * as it was likely already done - */ - const rootEslintConfigExists = host.exists('.eslintrc.json'); - /** - * Create the standard (which is applicable to the current package) ESLint setup - * for converting the project. - */ - const eslintInitInstallTask = await projectConverter.initESLint(); - - /** - * Convert the root tslint.json and apply the converted rules to the root .eslintrc.json - */ - const rootConfigInstallTask = await projectConverter.convertRootTSLintConfig( - (json) => { - json.overrides = [ - { files: ['*.ts'], rules: {} }, - { files: ['*.html'], rules: {} }, - ]; - return applyAngularRulesToCorrectOverrides(json); - }, - rootEslintConfigExists - ); - - /** - * Convert the project's tslint.json to an equivalent ESLint config. - */ - const projectConfigInstallTask = await projectConverter.convertProjectConfig( - (json) => applyAngularRulesToCorrectOverrides(json) - ); - /** - * Clean up the original TSLint configuration for the project. - */ - projectConverter.removeProjectTSLintFile(); - - // Only project shouldn't be added as a default - const { project, ...defaults } = options; - - /** - * Store user preferences for the collection - */ - projectConverter.setDefaults('@nx/angular', defaults); - - /** - * If the Angular project is an app which has an e2e project, try and convert that as well. - */ - let cypressInstallTask: GeneratorCallback = () => Promise.resolve(undefined); - const e2eProjectName = projectConverter.getE2EProjectName(); - if (e2eProjectName) { - try { - cypressInstallTask = await cypressConversionGenerator(host, { - project: e2eProjectName, - ignoreExistingTslintConfig: options.ignoreExistingTslintConfig, - /** - * We can always set this to false, because it will already be handled by the next - * step of this parent generator, if applicable - */ - removeTSLintIfNoMoreTSLintTargets: false, - skipFormat: true, - }); - } catch { - logger.warn( - 'This Angular app has an e2e project, but it was not possible to convert it from TSLint to ESLint. This could be because the e2e project did not have a tslint.json file to begin with.' - ); - } - } - - /** - * Based on user preference and remaining usage, remove TSLint from the workspace entirely. - */ - let uninstallTSLintTask: GeneratorCallback = () => Promise.resolve(undefined); - if ( - options.removeTSLintIfNoMoreTSLintTargets && - !projectConverter.isTSLintUsedInWorkspace() - ) { - uninstallTSLintTask = projectConverter.removeTSLintFromWorkspace(); - } - - if (!options.skipFormat) { - await formatFiles(host); - } - - return async () => { - await eslintInitInstallTask(); - await rootConfigInstallTask(); - await projectConfigInstallTask(); - await cypressInstallTask(); - await uninstallTSLintTask(); - }; -} - -/** - * In the case of Angular lint rules, we need to apply them to correct override depending upon whether - * or not they require @typescript-eslint/parser or @angular-eslint/template-parser in order to function. - * - * By this point, the applicable overrides have already been scaffolded for us by the Nx generators - * that ran earlier within this generator. - */ -function applyAngularRulesToCorrectOverrides( - json: Linter.Config -): Linter.Config { - const rules = json.rules; - - if (rules && Object.keys(rules).length) { - for (const [ruleName, ruleConfig] of Object.entries(rules)) { - for (const override of json.overrides) { - if ( - override.files.includes('*.html') && - ruleName.startsWith('@angular-eslint/template') - ) { - // Prioritize the converted rules over any base implementations from the original Nx generator - override.rules[ruleName] = ruleConfig; - } - - /** - * By default, tslint-to-eslint-config will try and apply any rules without known converters - * by using eslint-plugin-tslint. We instead explicitly warn the user about this missing converter, - * and therefore at this point we strip out any rules which start with @typescript-eslint/tslint/config - */ - if ( - override.files.includes('*.ts') && - !ruleName.startsWith('@angular-eslint/template') - ) { - // Prioritize the converted rules over any base implementations from the original Nx generator - override.rules[ruleName] = ruleConfig; - } - } - } - } - - // It's possible that there are plugins to apply to the TS override - if (json.plugins) { - for (const override of json.overrides) { - if (override.files.includes('*.ts')) { - override.plugins = override.plugins || []; - override.plugins = [ - ...override.plugins, - ...json.plugins.filter( - (plugin) => plugin !== '@angular-eslint/eslint-plugin-template' - ), - ]; - } - - if ( - override.files.includes('*.html') && - json.plugins.includes('@angular-eslint/eslint-plugin-template') - ) { - override.plugins = ['@angular-eslint/eslint-plugin-template']; - } - } - delete json.plugins; - } - - /** - * We now no longer need the flat list of rules at the root of the config - * because they have all been applied to an appropriate override. - */ - delete json.rules; - return json; -} diff --git a/packages/angular/src/generators/convert-tslint-to-eslint/schema.json b/packages/angular/src/generators/convert-tslint-to-eslint/schema.json deleted file mode 100644 index 7ec4017afe4f9..0000000000000 --- a/packages/angular/src/generators/convert-tslint-to-eslint/schema.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "$id": "NxAngularConvertTSLintToESLintGenerator", - "cli": "nx", - "title": "Convert an Angular project from TSLint to ESLint", - "description": "Convert an Angular project from TSLint to ESLint. NOTE: Does not work in `--dry-run mode`.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "examples": [ - { - "command": "nx g convert-tslint-to-eslint myapp", - "description": "The following will first configure the project, `myapp`, the same way a _new_ project is configured i.e. It will use Nx's new recommended ESLint config. By default, this also adds the existing TSLint configuration on top of the default ESLint config from Nx to continue checking what it checks today. This is done by migrating TSLint rules to their equivalent ESLint rules to the best of its abilities. Some TSLint rules may not have ESLint equivalents and will be reported during the conversion" - }, - { - "command": "nx g convert-tslint-to-eslint myapp --ignoreExistingTslintConfig=true", - "description": "If your TSLint config isn't extremely important to you, ignoring it makes this process more deterministic. Unlike the prior example, this will discard the existing TSLint configuration, meaning that the project will only have the Nx's latest recommended ESLint configuration which may be good enough for some workspaces" - }, - { - "command": "nx g convert-tslint-to-eslint myapp --removeTSLintIfNoMoreTSLintTargets=false", - "description": "By default, this process removes the TSLint related dependencies and configuration once no more projects use TSLint. This can be disabled with the following flag to keep TSLint related dependencies and configuration in the repo" - } - ], - "type": "object", - "properties": { - "project": { - "description": "The name of the Angular project to convert. Please note, if the project is an Angular app with an associated Cypress e2e project, it will also attempt to convert that.", - "type": "string", - "$default": { - "$source": "argv", - "index": 0 - }, - "x-prompt": "Which Angular project would you like to convert from TSLint to ESLint?", - "x-priority": "important" - }, - "ignoreExistingTslintConfig": { - "type": "boolean", - "description": "If true, it will not use existing TSLint config as a reference, it will just reset the project with the latest recommended ESLint config.", - "default": false, - "x-prompt": "Would you like to ignore the existing TSLint config? Recommended if the TSLint config has not been altered much as it makes the new ESLint config cleaner." - }, - "removeTSLintIfNoMoreTSLintTargets": { - "type": "boolean", - "description": "If this conversion leaves no more TSLint usage in the workspace, it will remove TSLint and related dependencies and configuration.", - "default": true, - "x-prompt": "Would you like to remove TSLint and its related config if there are no TSLint projects remaining after this conversion?" - }, - "skipFormat": { - "type": "boolean", - "description": "Skip formatting files.", - "default": false, - "x-priority": "internal" - } - }, - "additionalProperties": false, - "required": ["project"] -} diff --git a/packages/angular/src/generators/library/library.spec.ts b/packages/angular/src/generators/library/library.spec.ts index 6c7adb1305fa8..aa17cb797cada 100644 --- a/packages/angular/src/generators/library/library.spec.ts +++ b/packages/angular/src/generators/library/library.spec.ts @@ -1125,7 +1125,6 @@ describe('lib', () => { await runLibraryGeneratorWithOpts({ linter: Linter.EsLint }); // ASSERT - expect(tree.exists('my-lib/tslint.json')).toBe(false); expect(readProjectConfiguration(tree, 'my-lib').targets['lint']) .toMatchInlineSnapshot(` { diff --git a/packages/cypress/index.ts b/packages/cypress/index.ts index 7b33d4084f832..b24b600a846f1 100644 --- a/packages/cypress/index.ts +++ b/packages/cypress/index.ts @@ -9,6 +9,4 @@ export const cypressComponentConfiguration = componentConfigurationGenerator; export { configurationGenerator as cypressE2EConfigurationGenerator }; export { cypressProjectGenerator } from './src/generators/cypress-project/cypress-project'; export { cypressInitGenerator } from './src/generators/init/init'; -/** @deprecated This generator will be removed in v17 */ -export { conversionGenerator } from './src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint'; export { migrateCypressProject } from './src/generators/migrate-to-cypress-11/migrate-to-cypress-11'; diff --git a/packages/cypress/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap b/packages/cypress/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap deleted file mode 100644 index ec799c83e7c3d..0000000000000 --- a/packages/cypress/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap +++ /dev/null @@ -1,274 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`convert-tslint-to-eslint should work for Cypress applications 1`] = ` -{ - "dependencies": {}, - "devDependencies": { - "@nx/eslint-plugin": "0.0.1", - "@nx/linter": "0.0.1", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "eslint": "~8.46.0", - "eslint-config-prettier": "8.1.0", - "eslint-plugin-cypress": "^2.13.4", - "eslint-plugin-import": "latest", - }, - "name": "test-name", -} -`; - -exports[`convert-tslint-to-eslint should work for Cypress applications 2`] = ` -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "name": "e2e-app-1", - "projectType": "application", - "root": "apps/e2e-app-1", - "targets": { - "lint": { - "executor": "@nx/linter:eslint", - "options": { - "lintFilePatterns": [ - "apps/e2e-app-1/**/*.{js,ts}", - ], - }, - "outputs": [ - "{options.outputFile}", - ], - }, - }, -} -`; - -exports[`convert-tslint-to-eslint should work for Cypress applications 3`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": true, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@typescript-eslint", - ], - "root": true, - "rules": { - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should work for Cypress applications 4`] = ` -{ - "extends": [ - "plugin:cypress/recommended", - "../../.eslintrc.json", - ], - "ignorePatterns": [ - "!**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": {}, - }, - ], - "plugins": [ - "@typescript-eslint", - ], - "rules": { - "@typescript-eslint/no-empty-interface": "error", - }, -} -`; diff --git a/packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts b/packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts deleted file mode 100644 index 4cbcbc7b57a81..0000000000000 --- a/packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { - addProjectConfiguration, - joinPathFragments, - readJson, - readProjectConfiguration, - Tree, - writeJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { exampleRootTslintJson } from '@nx/linter'; -import { conversionGenerator } from './convert-tslint-to-eslint'; - -/** - * Don't run actual child_process implementation of installPackagesTask() - */ -jest.mock('child_process', () => { - return { - ...jest.requireActual('child_process'), - execSync: jest.fn((command: string) => { - if (command.includes('pnpm --version')) { - return '8.2.0'; - } - return; - }), - }; -}); - -const projectName = 'e2e-app-1'; -const projectRoot = `apps/${projectName}`; -const projectTSLintJsonPath = joinPathFragments(projectRoot, 'tslint.json'); -// Used to configure the test Tree and stub the response from tslint-to-eslint-config util findReportedConfiguration() -const projectTslintJsonData = { - raw: { - extends: '../../tslint.json', - rules: { - // User custom TS rule - 'no-empty-interface': true, - // User custom rule with no known automated converter - 'some-super-custom-rule-with-no-converter': true, - }, - linterOptions: { - exclude: ['!**/*'], - }, - }, - tslintPrintConfigResult: { - rules: { - 'no-empty-interface': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'some-super-custom-rule-with-no-converter': { - ruleArguments: [], - ruleSeverity: 'error', - }, - }, - }, -}; - -function mockFindReportedConfiguration(_, pathToTslintJson) { - switch (pathToTslintJson) { - case 'tslint.json': - return exampleRootTslintJson.tslintPrintConfigResult; - case projectTSLintJsonPath: - return projectTslintJsonData.tslintPrintConfigResult; - default: - throw new Error( - `mockFindReportedConfiguration - Did not recognize path ${pathToTslintJson}` - ); - } -} - -/** - * See ./mock-tslint-to-eslint-config.ts for why this is needed - */ -jest.mock('tslint-to-eslint-config', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('tslint-to-eslint-config'), - findReportedConfiguration: jest.fn(mockFindReportedConfiguration), - }; -}); - -/** - * Mock the the mutating fs utilities used within the conversion logic, they are not - * needed because of our stubbed response for findReportedConfiguration() above, and - * they would cause noise in the git data of the actual Nx repo when the tests run. - */ -jest.mock('fs', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('fs'), - writeFileSync: jest.fn(), - mkdirSync: jest.fn(), - }; -}); - -describe('convert-tslint-to-eslint', () => { - let host: Tree; - - beforeEach(async () => { - host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - - writeJson(host, 'tslint.json', exampleRootTslintJson.raw); - - addProjectConfiguration(host, projectName, { - root: projectRoot, - projectType: 'application', - targets: { - /** - * LINT TARGET CONFIG - BEFORE CONVERSION - * - * TSLint executor configured for the project - */ - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', '!apps/e2e-app-1/**/*'], - tsConfig: ['apps/e2e-app-1/tsconfig.app.json'], - }, - }, - }, - }); - - /** - * Existing tslint.json file for the project - */ - writeJson(host, 'apps/e2e-app-1/tslint.json', projectTslintJsonData.raw); - }); - - it('should work for Cypress applications', async () => { - await conversionGenerator(host, { - project: projectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: false, - }); - - /** - * It should ensure the required Nx packages are installed and available - * - * NOTE: tslint-to-eslint-config should NOT be present - */ - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - /** - * LINT TARGET CONFIG - AFTER CONVERSION - * - * It should replace the TSLint executor with the ESLint one - */ - expect(readProjectConfiguration(host, projectName)).toMatchSnapshot(); - - /** - * The root level .eslintrc.json should now have been generated - */ - const eslintJson = readJson(host, '.eslintrc.json'); - expect(eslintJson.overrides[3].rules['no-console'][1].allow).toContain( - 'log' - ); - // Remove no-console config because it is not deterministic across node versions - delete eslintJson.overrides[3].rules['no-console'][1].allow; - expect(eslintJson).toMatchSnapshot(); - - /** - * The project level .eslintrc.json should now have been generated - * and extend from the root, as well as applying any customizations - * which are specific to this projectType. - */ - expect( - readJson(host, joinPathFragments(projectRoot, '.eslintrc.json')) - ).toMatchSnapshot(); - - /** - * The project's TSLint file should have been deleted - */ - expect(host.exists(projectTSLintJsonPath)).toEqual(false); - }); -}); diff --git a/packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts b/packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts deleted file mode 100755 index 652143855765f..0000000000000 --- a/packages/cypress/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - convertNxGenerator, - formatFiles, - GeneratorCallback, - Tree, -} from '@nx/devkit'; -import { - ConvertTSLintToESLintSchema, - Linter, - ProjectConverter, -} from '@nx/linter'; -import { addLinterToCyProject } from '../../utils/add-linter'; -import type { Linter as ESLinter } from 'eslint'; - -/** - * @deprecated This generator will be removed in v17 - */ -export async function conversionGenerator( - host: Tree, - options: ConvertTSLintToESLintSchema -) { - /** - * The ProjectConverter instance encapsulates all the standard operations we need - * to perform in order to convert a project from TSLint to ESLint, as well as some - * extensibility points for adjusting the behavior on a per package basis. - * - * E.g. @nx/angular projects might need to make different changes to the final - * ESLint config when compared with @nx/next projects. - * - * See the ProjectConverter implementation for a full breakdown of what it does. - */ - const projectConverter = new ProjectConverter({ - host, - projectName: options.project, - ignoreExistingTslintConfig: options.ignoreExistingTslintConfig, - eslintInitializer: async ({ projectName, projectConfig }) => { - await addLinterToCyProject(host, { - linter: Linter.EsLint, - project: projectName, - /** - * We set the parserOptions.project config just in case the converted config uses - * rules which require type-checking. Later in the conversion we check if it actually - * does and remove the config again if it doesn't, so that it is most efficient. - */ - setParserOptionsProject: true, - cypressDir: 'src', - overwriteExisting: true, - }); - }, - }); - - /** - * If root eslint configuration already exists it will not be recreated - * but we also don't want to re-run the tslint config conversion - * as it was likely already done - */ - const rootEslintConfigExists = host.exists('.eslintrc.json'); - - /** - * Create the standard (which is applicable to the current package) ESLint setup - * for converting the project. - */ - const eslintInitInstallTask = await projectConverter.initESLint(); - - /** - * Convert the root tslint.json and apply the converted rules to the root .eslintrc.json. - */ - const rootConfigInstallTask = await projectConverter.convertRootTSLintConfig( - (json) => removeCodelyzerRelatedRules(json), - rootEslintConfigExists - ); - - /** - * Convert the project's tslint.json to an equivalent ESLint config. - */ - const projectConfigInstallTask = await projectConverter.convertProjectConfig( - (json) => json - ); - - /** - * Clean up the original TSLint configuration for the project. - */ - projectConverter.removeProjectTSLintFile(); - - // Only project shouldn't be added as a default - const { project, ...defaults } = options; - - /** - * Store user preferences for the collection - */ - projectConverter.setDefaults('@nx/cypress', defaults); - - /** - * Based on user preference and remaining usage, remove TSLint from the workspace entirely. - */ - let uninstallTSLintTask: GeneratorCallback = () => Promise.resolve(undefined); - if ( - options.removeTSLintIfNoMoreTSLintTargets && - !projectConverter.isTSLintUsedInWorkspace() - ) { - uninstallTSLintTask = projectConverter.removeTSLintFromWorkspace(); - } - - if (!options.skipFormat) { - await formatFiles(host); - } - - return async () => { - await eslintInitInstallTask(); - await rootConfigInstallTask(); - await projectConfigInstallTask(); - await uninstallTSLintTask(); - }; -} - -export const conversionSchematic = convertNxGenerator(conversionGenerator); - -/** - * Remove any @angular-eslint rules that were applied as a result of converting prior codelyzer - * rules, because they are only relevant for Angular projects. - */ -function removeCodelyzerRelatedRules(json: ESLinter.Config): ESLinter.Config { - for (const ruleName of Object.keys(json.rules)) { - if (ruleName.startsWith('@angular-eslint')) { - delete json.rules[ruleName]; - } - } - if (json.plugins) { - json.plugins = json.plugins.filter( - (plugin) => !plugin.startsWith('@angular-eslint') - ); - } - return json; -} diff --git a/packages/cypress/src/generators/convert-tslint-to-eslint/schema.json b/packages/cypress/src/generators/convert-tslint-to-eslint/schema.json deleted file mode 100644 index 8aada591fde1f..0000000000000 --- a/packages/cypress/src/generators/convert-tslint-to-eslint/schema.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "$id": "cypress-convert-tslint-to-eslint", - "cli": "nx", - "title": "Convert a Cypress project from TSLint to ESLint", - "description": "Convert a Cypress project from TSLint to ESLint.\n_NOTE: Does not work in `--dry-run` mode_.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "examples": [ - { - "command": "nx g convert-tslint-to-eslint myapp", - "description": "Convert the Cypress project `myapp` from TSLint to ESLint." - } - ], - "type": "object", - "properties": { - "project": { - "description": "The name of the Cypress project to convert.", - "type": "string", - "$default": { - "$source": "argv", - "index": 0 - }, - "x-prompt": "Which Cypress project would you like to convert from TSLint to ESLint?" - }, - "ignoreExistingTslintConfig": { - "type": "boolean", - "description": "If true we will not use existing TSLint config as a reference, we will just reset the project with the latest recommended ESLint config.", - "default": false, - "x-prompt": "Would you like to ignore the existing TSLint config? Recommended if the TSLint config has not been altered much as it makes the new ESLint config cleaner." - }, - "removeTSLintIfNoMoreTSLintTargets": { - "type": "boolean", - "description": "If this conversion leaves no more TSLint usage in the workspace, it will remove TSLint and related dependencies and configuration.", - "default": true, - "x-prompt": "Would you like to remove TSLint and its related config if there are no TSLint projects remaining after this conversion?" - }, - "skipFormat": { - "type": "boolean", - "description": "Skip formatting files.", - "default": false, - "x-priority": "internal" - } - }, - "required": ["project"] -} diff --git a/packages/jest/src/generators/configuration/configuration.spec.ts b/packages/jest/src/generators/configuration/configuration.spec.ts index dc7b9c933ebe4..7d5446b94dbad 100644 --- a/packages/jest/src/generators/configuration/configuration.spec.ts +++ b/packages/jest/src/generators/configuration/configuration.spec.ts @@ -31,10 +31,8 @@ describe('jestProject', () => { sourceRoot: 'libs/lib1/src', targets: { lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - tsConfig: [], - }, + executor: '@nx/linter:eslint', + options: {}, }, }, }); @@ -95,9 +93,6 @@ describe('jestProject', () => { }, }, }); - expect(lib1.targets.lint.options.tsConfig).toContain( - 'libs/lib1/tsconfig.spec.json' - ); }); it('should create a jest.config.ts', async () => { diff --git a/packages/jest/src/generators/configuration/lib/update-workspace.ts b/packages/jest/src/generators/configuration/lib/update-workspace.ts index 230846a81b636..5f72beba39321 100644 --- a/packages/jest/src/generators/configuration/lib/update-workspace.ts +++ b/packages/jest/src/generators/configuration/lib/update-workspace.ts @@ -38,21 +38,5 @@ export function updateWorkspace( }, }; - /** - * @deprecated this will be removed in the v17 - */ - const isUsingTSLint = - projectConfig.targets.lint?.executor === - '@angular-devkit/build-angular:tslint'; - - if (isUsingTSLint) { - projectConfig.targets.lint.options.tsConfig = [ - ...(projectConfig.targets.lint.options.tsConfig || []), - joinPathFragments( - normalizePath(projectConfig.root), - 'tsconfig.spec.json' - ), - ]; - } updateProjectConfiguration(tree, options.project, projectConfig); } diff --git a/packages/linter/.eslintrc.json b/packages/linter/.eslintrc.json index b87b1dd21c38e..4abd07a019ae0 100644 --- a/packages/linter/.eslintrc.json +++ b/packages/linter/.eslintrc.json @@ -38,7 +38,6 @@ "@nx/jest", "typescript", "eslint", - "tslint-to-eslint-config", "@angular-devkit/core", "@typescript-eslint/eslint-plugin" ] diff --git a/packages/linter/index.ts b/packages/linter/index.ts index dc8c31e713336..46439d120412c 100644 --- a/packages/linter/index.ts +++ b/packages/linter/index.ts @@ -1,8 +1,6 @@ export { lintProjectGenerator } from './src/generators/lint-project/lint-project'; export { lintInitGenerator } from './src/generators/init/init'; export { Linter } from './src/generators/utils/linter'; -/** @deprecated This will be removed in v17 */ -export * from './src/utils/convert-tslint-to-eslint'; // @nx/angular needs it for the Angular CLI workspace migration to Nx to // infer whether a config is using type aware rules and set the diff --git a/packages/linter/package.json b/packages/linter/package.json index fe353a6c4459e..1229ee6600ec2 100644 --- a/packages/linter/package.json +++ b/packages/linter/package.json @@ -34,7 +34,6 @@ }, "dependencies": { "@phenomnomnominal/tsquery": "~5.0.1", - "tmp": "~0.2.1", "tslib": "^2.3.0", "@nx/devkit": "file:../devkit", "@nx/js": "file:../js", diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/convert-to-eslint-config.spec.ts.snap b/packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/convert-to-eslint-config.spec.ts.snap deleted file mode 100644 index e4c2d05a7de34..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/convert-to-eslint-config.spec.ts.snap +++ /dev/null @@ -1,244 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`convertTSLintDisableCommentsForProject should replace tslint:disable comments with their ESLint equivalents in .ts files for the given project 1`] = ` -" - /* eslint-disable */ - eval(''); - " -`; - -exports[`convertTSLintDisableCommentsForProject should replace tslint:disable comments with their ESLint equivalents in .ts files for the given project 2`] = ` -" - // eslint-disable-next-line - eval(''); - " -`; - -exports[`convertTSLintDisableCommentsForProject should replace tslint:disable comments with their ESLint equivalents in .ts files for the given project 3`] = ` -" - /* eslint-disable quotes, @typescript-eslint/quotes */ - eval(''); - " -`; - -exports[`convertToESLintConfig() should work for a non-Angular project tslint.json file 1`] = ` -{ - "convertedESLintConfig": { - "env": { - "browser": true, - "es6": true, - "node": true, - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module", - }, - "plugins": [ - "@typescript-eslint", - ], - "root": true, - }, - "ensureESLintPlugins": [], - "unconvertedTSLintRules": [], -} -`; - -exports[`convertToESLintConfig() should work for a project tslint.json file 1`] = ` -{ - "convertedESLintConfig": { - "env": { - "browser": true, - "es6": true, - "node": true, - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module", - }, - "plugins": [ - "@angular-eslint/eslint-plugin", - "@typescript-eslint", - ], - "root": true, - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "angular-app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "angular-app", - "style": "camelCase", - "type": "attribute", - }, - ], - }, - }, - "ensureESLintPlugins": [], - "unconvertedTSLintRules": [], -} -`; - -exports[`convertToESLintConfig() should work for a root tslint.json file 1`] = ` -{ - "convertedESLintConfig": { - "env": { - "browser": true, - "es6": true, - "node": true, - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module", - }, - "plugins": [ - "eslint-plugin-import", - "@angular-eslint/eslint-plugin", - "@angular-eslint/eslint-plugin-template", - "@typescript-eslint", - ], - "root": true, - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "prefix": "app", - "style": "kebab-case", - "type": "element", - }, - ], - "@angular-eslint/directive-selector": [ - "error", - { - "prefix": "app", - "style": "camelCase", - "type": "attribute", - }, - ], - "@angular-eslint/no-conflicting-lifecycle": "error", - "@angular-eslint/no-host-metadata-property": "error", - "@angular-eslint/no-input-rename": "error", - "@angular-eslint/no-inputs-metadata-property": "error", - "@angular-eslint/no-output-native": "error", - "@angular-eslint/no-output-on-prefix": "error", - "@angular-eslint/no-output-rename": "error", - "@angular-eslint/no-outputs-metadata-property": "error", - "@angular-eslint/template/banana-in-box": "error", - "@angular-eslint/template/eqeqeq": "error", - "@angular-eslint/template/no-negated-async": "error", - "@angular-eslint/use-lifecycle-interface": "error", - "@angular-eslint/use-pipe-transform-interface": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - "ensureESLintPlugins": [ - "eslint-plugin-import", - ], - "unconvertedTSLintRules": [], -} -`; - -exports[`convertToESLintConfig() should work for an e2e project tslint.json file 1`] = ` -{ - "convertedESLintConfig": { - "env": { - "browser": true, - "es6": true, - "node": true, - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module", - }, - "plugins": [ - "@typescript-eslint", - ], - "root": true, - }, - "ensureESLintPlugins": [], - "unconvertedTSLintRules": [], -} -`; diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/project-converter.spec.ts.snap b/packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/project-converter.spec.ts.snap deleted file mode 100644 index f8f5916a8c580..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/__snapshots__/project-converter.spec.ts.snap +++ /dev/null @@ -1,351 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ProjectConverter ignoreExistingTslintConfig ignoreExistingTslintConfig: false should use existing TSLint configs and merge their converted ESLint equivalents with recommended ESLint configs 1`] = ` -{ - "overrides": [ - { - "files": [ - "*.ts", - ], - "rules": { - "some-converted-rule": "error", - }, - }, - ], - "rules": { - "some-recommended-root-eslint-rule": "error", - }, -} -`; - -exports[`ProjectConverter ignoreExistingTslintConfig ignoreExistingTslintConfig: false should use existing TSLint configs and merge their converted ESLint equivalents with recommended ESLint configs 2`] = ` -{ - "rules": { - "some-converted-rule": "error", - "some-recommended-project-eslint-rule": "error", - }, -} -`; - -exports[`ProjectConverter ignoreExistingTslintConfig ignoreExistingTslintConfig: true should ignore existing TSLint configs and just reset the project to use recommended ESLint configs 1`] = ` -{ - "rules": { - "some-recommended-root-eslint-rule": "error", - }, -} -`; - -exports[`ProjectConverter ignoreExistingTslintConfig ignoreExistingTslintConfig: true should ignore existing TSLint configs and just reset the project to use recommended ESLint configs 2`] = ` -{ - "rules": { - "some-recommended-project-eslint-rule": "error", - }, -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove all relevant traces of TSLint from the workspace 1`] = ` -{ - "dependencies": {}, - "devDependencies": { - "codelyzer": "latest", - "tslint": "latest", - }, - "name": "test-name", -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove all relevant traces of TSLint from the workspace 2`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "generators": { - "@nx/angular": { - "application": { - "linter": "tslint", - }, - "library": { - "linter": "tslint", - }, - }, - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove all relevant traces of TSLint from the workspace 3`] = ` -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "generators": { - "@nx/angular:application": { - "e2eTestRunner": "cypress", - "linter": "eslint", - "unitTestRunner": "jest", - }, - "@nx/angular:library": { - "linter": "tslint", - }, - }, - "name": "foo", - "projectType": "application", - "root": "apps/foo", - "targets": { - "lint": { - "executor": "@angular-devkit/build-angular:tslint", - "options": { - "exclude": [ - "**/node_modules/**", - "!apps/foo/**/*", - ], - "tsConfig": [ - "apps/foo/tsconfig.app.json", - ], - }, - }, - }, -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove all relevant traces of TSLint from the workspace 4`] = ` -{ - "dependencies": {}, - "devDependencies": {}, - "name": "test-name", -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove all relevant traces of TSLint from the workspace 5`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove all relevant traces of TSLint from the workspace 6`] = ` -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "generators": { - "@nx/angular:application": { - "e2eTestRunner": "cypress", - "unitTestRunner": "jest", - }, - }, - "name": "foo", - "projectType": "application", - "root": "apps/foo", - "targets": { - "lint": { - "executor": "@angular-devkit/build-angular:tslint", - "options": { - "exclude": [ - "**/node_modules/**", - "!apps/foo/**/*", - ], - "tsConfig": [ - "apps/foo/tsconfig.app.json", - ], - }, - }, - }, -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove the entry in generators for convert-tslint-to-eslint because it is no longer needed 1`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "generators": { - "@nx/angular": { - "convert-tslint-to-eslint": { - "removeTSLintIfNoMoreTSLintTargets": true, - }, - }, - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter removeTSLintFromWorkspace() should remove the entry in generators for convert-tslint-to-eslint because it is no longer needed 2`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter setDefaults() should save in nx.json 1`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "generators": { - "@nx/angular": { - "application": { - "linter": "tslint", - }, - "library": { - "linter": "tslint", - }, - }, - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter setDefaults() should save in nx.json 2`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "generators": { - "@nx/angular": { - "application": { - "linter": "tslint", - }, - "convert-tslint-to-eslint": { - "ignoreExistingTslintConfig": true, - "removeTSLintIfNoMoreTSLintTargets": true, - }, - "library": { - "linter": "tslint", - }, - }, - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter setDefaults() should save in nx.json 3`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "generators": { - "@nx/angular": { - "application": { - "linter": "tslint", - }, - "convert-tslint-to-eslint": { - "ignoreExistingTslintConfig": false, - "removeTSLintIfNoMoreTSLintTargets": false, - }, - "library": { - "linter": "tslint", - }, - }, - }, - "npmScope": "proj", - "tasksRunnerOptions": { - "default": { - "options": { - "cacheableOperations": [ - "build", - "lint", - "test", - "e2e", - ], - }, - "runner": "nx/tasks-runners/default", - }, - }, -} -`; - -exports[`ProjectConverter should throw if --dry-run is set 1`] = ` -"NOTE: This generator does not support --dry-run. If you are running this in Nx Console, it should execute fine once you hit the "Run" button. -" -`; - -exports[`ProjectConverter should throw if --dryRun is set 1`] = ` -"NOTE: This generator does not support --dry-run. If you are running this in Nx Console, it should execute fine once you hit the "Run" button. -" -`; - -exports[`ProjectConverter should throw if -d is set 1`] = ` -"NOTE: This generator does not support --dry-run. If you are running this in Nx Console, it should execute fine once you hit the "Run" button. -" -`; - -exports[`ProjectConverter should throw if no root tslint.json is found 1`] = `"We could not find a tslint.json at the root of your workspace, maybe you have already migrated to ESLint?"`; diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.spec.ts b/packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.spec.ts deleted file mode 100644 index 227027e60de12..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.spec.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { convertTslintNxRuleToEslintNxRule } from './convert-nx-enforce-module-boundaries-rule'; - -describe('convertTslintNxRuleToEslintNxRule()', () => { - const configFromNxExamplesRepo = { - allow: ['@nx-example/shared/product/data/testing'], - depConstraints: [ - { - sourceTag: 'type:app', - onlyDependOnLibsWithTags: ['type:feature', 'type:ui'], - }, - { - sourceTag: 'type:feature', - onlyDependOnLibsWithTags: [ - 'type:ui', - 'type:data', - 'type:types', - 'type:state', - ], - }, - { - sourceTag: 'type:types', - onlyDependOnLibsWithTags: ['type:types'], - }, - { - sourceTag: 'type:state', - onlyDependOnLibsWithTags: ['type:state', 'type:types', 'type:data'], - }, - { - sourceTag: 'type:data', - onlyDependOnLibsWithTags: ['type:types'], - }, - { - sourceTag: 'type:e2e', - onlyDependOnLibsWithTags: ['type:e2e-utils'], - }, - { - sourceTag: 'type:ui', - onlyDependOnLibsWithTags: ['type:types', 'type:ui'], - }, - { - sourceTag: 'scope:products', - onlyDependOnLibsWithTags: ['scope:products', 'scope:shared'], - }, - { - sourceTag: 'scope:cart', - onlyDependOnLibsWithTags: ['scope:cart', 'scope:shared'], - }, - ], - enforceBuildableLibDependency: true, - }; - - const testCases = [ - { - tslintJson: {}, - // Should return null if no existing config found - expected: null, - }, - { - // Real usage in nx-examples repo - tslintJson: { - rules: { - 'nx-enforce-module-boundaries': [true, configFromNxExamplesRepo], - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['error', configFromNxExamplesRepo], - }, - }, - { - // Should respect boolean - tslintJson: { - defaultSeverity: 'warning', - rules: { - 'nx-enforce-module-boundaries': [false, configFromNxExamplesRepo], - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['off', configFromNxExamplesRepo], - }, - }, - { - // Should respect boolean + defaultSeverity format - tslintJson: { - defaultSeverity: 'warning', - rules: { - 'nx-enforce-module-boundaries': [true, configFromNxExamplesRepo], - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['warn', configFromNxExamplesRepo], - }, - }, - { - // Should respect object format - tslintJson: { - rules: { - 'nx-enforce-module-boundaries': { - severity: 'error', - options: [configFromNxExamplesRepo], - }, - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['error', configFromNxExamplesRepo], - }, - }, - { - // Should respect object format - tslintJson: { - rules: { - 'nx-enforce-module-boundaries': { - severity: 'warning', - options: [configFromNxExamplesRepo], - }, - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['warn', configFromNxExamplesRepo], - }, - }, - { - // Should respect object format - tslintJson: { - rules: { - 'nx-enforce-module-boundaries': { - severity: 'off', - options: [configFromNxExamplesRepo], - }, - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['off', configFromNxExamplesRepo], - }, - }, - { - // Should respect object format + defaultSeverity option - tslintJson: { - defaultSeverity: 'warning', - rules: { - 'nx-enforce-module-boundaries': { - severity: 'default', - options: [configFromNxExamplesRepo], - }, - }, - }, - expected: { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: ['warn', configFromNxExamplesRepo], - }, - }, - ]; - - testCases.forEach((tc, i) => { - it(`should appropriately convert the nx-enforce-module-boundaries rule usage from TSLint, CASE ${i}`, () => { - expect(convertTslintNxRuleToEslintNxRule(tc.tslintJson)).toEqual( - tc.expected - ); - }); - }); -}); diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.ts b/packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.ts deleted file mode 100644 index 3b144b91efe9c..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/convert-nx-enforce-module-boundaries-rule.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { ESLintRuleSeverity } from 'tslint-to-eslint-config'; - -type TSLintRuleSeverity = 'default' | 'warning' | 'error' | 'off' | boolean; -type TSLintRuleSeverityNonDefaultString = Exclude< - TSLintRuleSeverity, - boolean | 'default' ->; - -function convertTSLintRuleSeverity( - tslintConfig: any, - tslintSeverity: TSLintRuleSeverity -): ESLintRuleSeverity { - if (tslintSeverity === true) { - tslintSeverity = 'default'; - } - if (tslintSeverity === false) { - tslintSeverity = 'off'; - } - if (tslintSeverity === 'default') { - tslintSeverity = tslintConfig.defaultSeverity || 'error'; - } - const narrowedTslintSeverity = - tslintSeverity as TSLintRuleSeverityNonDefaultString; - return narrowedTslintSeverity === 'warning' ? 'warn' : narrowedTslintSeverity; -} - -const NX_TSLINT_RULE_NAME = 'nx-enforce-module-boundaries'; - -/** - * @deprecated This converter will be removed in v17 - */ -export function convertTslintNxRuleToEslintNxRule( - tslintJson: Record -): { - ruleName: string; - ruleConfig: [ESLintRuleSeverity, Record]; -} | null { - /** - * TSLint supports a number of different formats for rule configuration - */ - const existingRuleDefinition = tslintJson?.rules?.[NX_TSLINT_RULE_NAME]; - if (!existingRuleDefinition) { - return null; - } - let existingRuleSeverity: TSLintRuleSeverity = 'error'; - let existingRuleConfig = { - enforceBuildableLibDependency: true, - allow: [], - depConstraints: [ - { - sourceTag: '*', - onlyDependOnLibsWithTags: ['*'], - }, - ], - }; - - if (Array.isArray(existingRuleDefinition)) { - existingRuleSeverity = existingRuleDefinition[0]; - existingRuleConfig = existingRuleDefinition[1]; - } else if ( - typeof existingRuleDefinition === 'object' && - existingRuleDefinition.severity - ) { - existingRuleSeverity = existingRuleDefinition.severity; - if ( - Array.isArray(existingRuleDefinition.options) && - existingRuleDefinition.options[0] - ) { - existingRuleConfig = existingRuleDefinition.options[0]; - } - } - - const ruleSeverity: ESLintRuleSeverity = convertTSLintRuleSeverity( - tslintJson, - existingRuleSeverity - ); - - return { - ruleName: '@nx/enforce-module-boundaries', - ruleConfig: [ruleSeverity, existingRuleConfig], - }; -} diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.spec.ts b/packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.spec.ts deleted file mode 100644 index 20c38199c7c9e..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.spec.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { addProjectConfiguration, Tree } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { join } from 'path'; -import { - convertToESLintConfig, - convertTSLintDisableCommentsForProject, -} from './convert-to-eslint-config'; -import { - exampleAngularProjectTslintJson, - exampleE2eProjectTslintJson, - exampleNonAngularProjectTslintJson, - exampleRootTslintJson, -} from './example-tslint-configs'; - -/** - * The actual `findReportedConfiguration()` function is used to execute - * `tslint --print-config` in a child process and read from the real - * file system. This won't work for us in tests where we are dealing - * with a Tree, so we mock out the responses from `findReportedConfiguration()` - * with previously captured result data from that same command. - */ - -export function mockFindReportedConfiguration(_, pathToTSLintJson) { - if ( - pathToTSLintJson === 'tslint.json' || - pathToTSLintJson === '/tslint.json' - ) { - return exampleRootTslintJson.tslintPrintConfigResult; - } - - if ( - pathToTSLintJson === 'apps/app1/tslint.json' || - pathToTSLintJson === 'libs/lib1/tslint.json' - ) { - return exampleAngularProjectTslintJson.tslintPrintConfigResult; - } - - if (pathToTSLintJson === 'apps/app1-e2e/tslint.json') { - return exampleE2eProjectTslintJson.tslintPrintConfigResult; - } - - if (pathToTSLintJson === 'apps/app2/tslint.json') { - return exampleNonAngularProjectTslintJson.tslintPrintConfigResult; - } - - throw new Error( - `${pathToTSLintJson} is not a part of the supported mock data for these tests` - ); -} - -/** - * See ./mock-tslint-to-eslint-config.ts for why this is needed - */ -jest.mock('tslint-to-eslint-config', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('tslint-to-eslint-config'), - findReportedConfiguration: jest.fn(mockFindReportedConfiguration), - }; -}); - -describe('convertToESLintConfig()', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should work for a root tslint.json file', async () => { - const converted = await convertToESLintConfig( - 'tslint.json', - exampleRootTslintJson.raw, - [] - ); - expect( - converted.convertedESLintConfig.rules['no-console'][1].allow - ).toContain('log'); - // Ensure no-console snapshot is deterministic - delete converted.convertedESLintConfig.rules['no-console'][1].allow; - expect(converted).toMatchSnapshot(); - }); - - it('should work for a project tslint.json file', async () => { - await expect( - convertToESLintConfig( - 'apps/app1/tslint.json', - exampleAngularProjectTslintJson.raw, - [] - ) - ).resolves.toMatchSnapshot(); - }); - - it('should work for an e2e project tslint.json file', async () => { - await expect( - convertToESLintConfig( - 'apps/app1-e2e/tslint.json', - exampleE2eProjectTslintJson.raw, - [] - ) - ).resolves.toMatchSnapshot(); - }); - - it('should work for a non-Angular project tslint.json file', async () => { - await expect( - convertToESLintConfig( - 'apps/app2/tslint.json', - exampleNonAngularProjectTslintJson.raw, - [] - ) - ).resolves.toMatchSnapshot(); - }); -}); - -describe('convertTSLintDisableCommentsForProject', () => { - let tree: Tree; - const projectName = 'foo'; - const projectRoot = `apps/${projectName}`; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - addProjectConfiguration(tree, projectName, { - root: projectRoot, - projectType: 'application', - targets: { - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', `!${projectRoot}/**/*`], - tsConfig: [`${projectRoot}/tsconfig.app.json`], - }, - }, - }, - }); - tree.write( - join(projectRoot, 'top-level-file.ts'), - ` - // tslint:disable - eval(''); - ` - ); - tree.write( - join(projectRoot, 'single-level-nested/file.ts'), - ` - // tslint:disable-next-line - eval(''); - ` - ); - // specific rule, and multi-line-comment style - tree.write( - join(projectRoot, 'multi-level/nested/file.ts'), - ` - /* tslint:disable:quotemark */ - eval(''); - ` - ); - }); - it('should replace tslint:disable comments with their ESLint equivalents in .ts files for the given project', () => { - convertTSLintDisableCommentsForProject(tree, projectName); - - expect( - tree.read(join(projectRoot, 'top-level-file.ts'), 'utf-8') - ).toMatchSnapshot(); - expect( - tree.read(join(projectRoot, 'single-level-nested/file.ts'), 'utf-8') - ).toMatchSnapshot(); - expect( - tree.read(join(projectRoot, 'multi-level/nested/file.ts'), 'utf-8') - ).toMatchSnapshot(); - }); -}); diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.ts b/packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.ts deleted file mode 100644 index 983a1bc11118c..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/convert-to-eslint-config.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { - readProjectConfiguration, - visitNotIgnoredFiles, - writeJsonFile, - getPackageManagerCommand, -} from '@nx/devkit'; -import type { Tree } from '@nx/devkit'; -import { execSync } from 'child_process'; -import type { Linter as ESLintLinter } from 'eslint'; -import { dirSync } from 'tmp'; -import type { - createESLintConfiguration as CreateESLintConfiguration, - TSLintRuleOptions, -} from 'tslint-to-eslint-config'; -import { tslintToEslintConfigVersion } from '../versions'; - -let tslintToEslint; -function getConvertToEslintConfig() { - if (tslintToEslint) { - return tslintToEslint; - } - - try { - // This is usually not possible during runtime but makes it easy to mock in tests - return require('tslint-to-eslint-config'); - } catch {} - - /** - * In order to avoid all users of Nx needing to have tslint-to-eslint-config (and therefore tslint) - * in their node_modules, we dynamically install and uninstall the library as part of the conversion - * process. - * - * NOTE: By taking this approach we have to sacrifice dry-run capabilities for this generator. - */ - const tempDir = dirSync().name; - execSync( - `${ - getPackageManagerCommand().addDev - } tslint-to-eslint-config@${tslintToEslintConfigVersion}`, - { - cwd: tempDir, - stdio: [0, 1, 2], - } - ); - - tslintToEslint = require(require.resolve('tslint-to-eslint-config', { - paths: [tempDir], - })); - return tslintToEslint; -} - -/** - * @deprecated This will be removed in v17 - */ -export async function convertToESLintConfig( - pathToTslintJson: string, - tslintJson: Record, - ignoreExtendsVals: string[] -): Promise<{ - convertedESLintConfig: ESLintLinter.Config; - unconvertedTSLintRules: TSLintRuleOptions[]; - ensureESLintPlugins: string[]; -}> { - /** - * We need to avoid a direct dependency on tslint-to-eslint-config - * and ensure we are only resolving the dependency from the user's - * node_modules on demand (it will be installed as part of the - * conversion generator). - */ - const { - createESLintConfiguration, - findReportedConfiguration, - joinConfigConversionResults, - } = getConvertToEslintConfig(); - - const updatedTSLintJson = tslintJson; - /** - * If ignoreExtendsVals are provided, strip them from the config - * and commit the result to disk per the notes below. - */ - if (ignoreExtendsVals.length && updatedTSLintJson.extends) { - if ( - typeof updatedTSLintJson.extends === 'string' && - ignoreExtendsVals.includes(updatedTSLintJson.extends) - ) { - delete updatedTSLintJson.extends; - } - if (Array.isArray(updatedTSLintJson.extends)) { - updatedTSLintJson.extends = updatedTSLintJson.extends.filter( - (ext) => !ignoreExtendsVals.includes(ext) - ); - } - /** - * The reasons we need to interact with the filesystem here: - * - * 1) The result of the tslint CLI flag `--print-config` is needed for the - * conversion process, and unfortunately no equivalent Node API was ever - * added to tslint, so the tslint CLI needs to always read from disk. - * - * 2) When converting project configs, we need to strip the extends path - * which corresponds to the workspace's root config, otherwise all of the - * root config's rules will be included in the resultant eslint config for - * the project. The interaction with the filesystem is needed because of - * point (1) above - we need to strip the relevant extends and commit that - * change to disk before the tslint CLI reads the config file. - */ - writeJsonFile(pathToTslintJson, updatedTSLintJson); - } - const pm = getPackageManagerCommand(); - const reportedConfiguration = await findReportedConfiguration( - `${pm.exec} tslint --print-config`, - pathToTslintJson - ); - - if (reportedConfiguration instanceof Error) { - if ( - reportedConfiguration.message.includes('unknown option `--print-config') - ) { - throw new Error( - '\nError: TSLint v5.18 required in order to run this schematic. Please update your version and try again.\n' - ); - } - /** - * Make a print-config issue easier to understand for the end user. - * This error could occur if, for example, the user does not have a TSLint plugin installed correctly that they - * reference in their config. - */ - const printConfigFailureMessageStart = `Command failed: ${pm.exec} tslint --print-config "tslint.json"`; - if ( - reportedConfiguration.message.startsWith(printConfigFailureMessageStart) - ) { - throw new Error( - `\nThere was a critical error when trying to inspect your tslint.json: \n${reportedConfiguration.message.replace( - printConfigFailureMessageStart, - '' - )}` - ); - } - - throw new Error(`Unexpected error: ${reportedConfiguration.message}`); - } - - const originalConfigurations = { - tslint: { - full: reportedConfiguration, - raw: updatedTSLintJson, - }, - }; - - const summarizedConfiguration = await ( - createESLintConfiguration as typeof CreateESLintConfiguration - )(originalConfigurations); - - /** - * We are expecting it to not find a converter for nx-enforce-module-boundaries - * and we will explicitly replace it with the ESLint equivalent ourselves. - */ - if (summarizedConfiguration.missing) { - summarizedConfiguration.missing = summarizedConfiguration.missing.filter( - (missingRuleData) => - missingRuleData.ruleName !== 'nx-enforce-module-boundaries' - ); - } - - // These are already covered by our extraEslintDependencies which get installed by the schematic - const expectedESLintPlugins = [ - '@angular-eslint/eslint-plugin', - '@angular-eslint/eslint-plugin-template', - ]; - - const convertedESLintConfig = joinConfigConversionResults( - summarizedConfiguration, - originalConfigurations - ) as ESLintLinter.Config; - - if ( - Array.isArray(convertedESLintConfig.extends) && - convertedESLintConfig.extends.length - ) { - // Ignore any tslint-to-eslint-config default extends that do not apply to Nx - convertedESLintConfig.extends = convertedESLintConfig.extends.filter( - (ext) => !ext.startsWith('prettier') - ); - if (convertedESLintConfig.extends.length === 0) { - delete convertedESLintConfig.extends; - } - } - - return { - convertedESLintConfig, - unconvertedTSLintRules: summarizedConfiguration.missing, - ensureESLintPlugins: Array.from(summarizedConfiguration.plugins).filter( - (pluginName) => !expectedESLintPlugins.includes(pluginName) - ), - }; -} - -function likelyContainsTSLintComment(fileContent: string): boolean { - return fileContent.includes('tslint:'); -} - -/** - * @deprecated This will be removed in v17 - */ -export function convertTSLintDisableCommentsForProject( - tree: Tree, - projectName: string -) { - /** - * We need to avoid a direct dependency on tslint-to-eslint-config - * and ensure we are only resolving the dependency from the user's - * node_modules on demand (it will be installed as part of the - * conversion generator). - */ - const { convertFileComments } = getConvertToEslintConfig(); - const { root } = readProjectConfiguration(tree, projectName); - - visitNotIgnoredFiles(tree, root, (filePath) => { - if (!filePath.endsWith('.ts')) { - return; - } - const fileContent = tree.read(filePath, 'utf-8'); - // Avoid updating files if we don't have to - if (!fileContent || !likelyContainsTSLintComment(fileContent)) { - return; - } - const updatedFileContent = convertFileComments({ fileContent, filePath }); - tree.write(filePath, updatedFileContent); - }); -} diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/example-tslint-configs.ts b/packages/linter/src/utils/convert-tslint-to-eslint/example-tslint-configs.ts deleted file mode 100644 index 2c4123c381aaa..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/example-tslint-configs.ts +++ /dev/null @@ -1,324 +0,0 @@ -// Based on latest Angular project root tslint.json + enforce-module-boundaries config from nx-examples -export const exampleRootTslintJson = { - raw: { - rulesDirectory: [ - 'node_modules/@nrwl/workspace/src/tslint', - 'node_modules/codelyzer', - ], - linterOptions: { - exclude: ['**/*'], - }, - rules: { - 'arrow-return-shorthand': true, - 'callable-types': true, - 'class-name': true, - deprecation: { - severity: 'warn', - }, - forin: true, - 'import-blacklist': [true, 'rxjs/Rx'], - 'interface-over-type-literal': true, - 'member-access': false, - 'member-ordering': [ - true, - { - order: [ - 'static-field', - 'instance-field', - 'static-method', - 'instance-method', - ], - }, - ], - 'no-arg': true, - 'no-bitwise': true, - 'no-console': [true, 'debug', 'info', 'time', 'timeEnd', 'trace'], - 'no-construct': true, - 'no-debugger': true, - 'no-duplicate-super': true, - 'no-empty': false, - 'no-empty-interface': true, - 'no-eval': true, - 'no-inferrable-types': [true, 'ignore-params'], - 'no-misused-new': true, - 'no-non-null-assertion': true, - 'no-shadowed-variable': true, - 'no-string-literal': false, - 'no-string-throw': true, - 'no-switch-case-fall-through': true, - 'no-unnecessary-initializer': true, - 'no-unused-expression': true, - 'no-var-keyword': true, - 'object-literal-sort-keys': false, - 'prefer-const': true, - radix: true, - 'triple-equals': [true, 'allow-null-check'], - 'unified-signatures': true, - 'variable-name': false, - 'nx-enforce-module-boundaries': [ - true, - { - allow: ['@nx-example/shared/product/data/testing'], - depConstraints: [ - { - sourceTag: 'type:app', - onlyDependOnLibsWithTags: ['type:feature', 'type:ui'], - }, - { - sourceTag: 'type:feature', - onlyDependOnLibsWithTags: [ - 'type:ui', - 'type:data', - 'type:types', - 'type:state', - ], - }, - { - sourceTag: 'type:types', - onlyDependOnLibsWithTags: ['type:types'], - }, - { - sourceTag: 'type:state', - onlyDependOnLibsWithTags: [ - 'type:state', - 'type:types', - 'type:data', - ], - }, - { - sourceTag: 'type:data', - onlyDependOnLibsWithTags: ['type:types'], - }, - { - sourceTag: 'type:e2e', - onlyDependOnLibsWithTags: ['type:e2e-utils'], - }, - { - sourceTag: 'type:ui', - onlyDependOnLibsWithTags: ['type:types', 'type:ui'], - }, - { - sourceTag: 'scope:products', - onlyDependOnLibsWithTags: ['scope:products', 'scope:shared'], - }, - { - sourceTag: 'scope:cart', - onlyDependOnLibsWithTags: ['scope:cart', 'scope:shared'], - }, - ], - enforceBuildableLibDependency: true, - }, - ], - 'directive-selector': [true, 'attribute', 'app', 'camelCase'], - 'component-selector': [true, 'element', 'app', 'kebab-case'], - 'no-conflicting-lifecycle': true, - 'no-host-metadata-property': true, - 'no-input-rename': true, - 'no-inputs-metadata-property': true, - 'no-output-native': true, - 'no-output-on-prefix': true, - 'no-output-rename': true, - 'no-outputs-metadata-property': true, - 'template-banana-in-box': true, - 'template-no-negated-async': true, - 'use-lifecycle-interface': true, - 'use-pipe-transform-interface': true, - }, - }, - tslintPrintConfigResult: { - rules: { - 'arrow-return-shorthand': { ruleArguments: [], ruleSeverity: 'error' }, - 'callable-types': { ruleArguments: [], ruleSeverity: 'error' }, - 'class-name': { ruleArguments: [], ruleSeverity: 'error' }, - deprecation: { ruleSeverity: 'warning' }, - forin: { ruleArguments: [], ruleSeverity: 'error' }, - 'import-blacklist': { ruleArguments: ['rxjs/Rx'], ruleSeverity: 'error' }, - 'interface-over-type-literal': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'member-access': { ruleArguments: [], ruleSeverity: 'off' }, - 'member-ordering': { - ruleArguments: [ - { - order: [ - 'static-field', - 'instance-field', - 'static-method', - 'instance-method', - ], - }, - ], - ruleSeverity: 'error', - }, - 'no-arg': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-bitwise': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-console': { - ruleArguments: ['debug', 'info', 'time', 'timeEnd', 'trace'], - ruleSeverity: 'error', - }, - 'no-construct': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-debugger': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-duplicate-super': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-empty': { ruleArguments: [], ruleSeverity: 'off' }, - 'no-empty-interface': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-eval': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-inferrable-types': { - ruleArguments: ['ignore-params'], - ruleSeverity: 'error', - }, - 'no-misused-new': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-non-null-assertion': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-shadowed-variable': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-string-literal': { ruleArguments: [], ruleSeverity: 'off' }, - 'no-string-throw': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-switch-case-fall-through': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'no-unnecessary-initializer': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'no-unused-expression': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-var-keyword': { ruleArguments: [], ruleSeverity: 'error' }, - 'object-literal-sort-keys': { ruleArguments: [], ruleSeverity: 'off' }, - 'prefer-const': { ruleArguments: [], ruleSeverity: 'error' }, - radix: { ruleArguments: [], ruleSeverity: 'error' }, - 'triple-equals': { - ruleArguments: ['allow-null-check'], - ruleSeverity: 'error', - }, - 'unified-signatures': { ruleArguments: [], ruleSeverity: 'error' }, - 'variable-name': { ruleArguments: [], ruleSeverity: 'off' }, - 'nx-enforce-module-boundaries': { - ruleArguments: [ - { - allow: ['@nx-example/shared/product/data/testing'], - depConstraints: [ - { - sourceTag: 'type:app', - onlyDependOnLibsWithTags: ['type:feature', 'type:ui'], - }, - { - sourceTag: 'type:feature', - onlyDependOnLibsWithTags: [ - 'type:ui', - 'type:data', - 'type:types', - 'type:state', - ], - }, - { - sourceTag: 'type:types', - onlyDependOnLibsWithTags: ['type:types'], - }, - { - sourceTag: 'type:state', - onlyDependOnLibsWithTags: [ - 'type:state', - 'type:types', - 'type:data', - ], - }, - { - sourceTag: 'type:data', - onlyDependOnLibsWithTags: ['type:types'], - }, - { - sourceTag: 'type:e2e', - onlyDependOnLibsWithTags: ['type:e2e-utils'], - }, - { - sourceTag: 'type:ui', - onlyDependOnLibsWithTags: ['type:types', 'type:ui'], - }, - { - sourceTag: 'scope:products', - onlyDependOnLibsWithTags: ['scope:products', 'scope:shared'], - }, - { - sourceTag: 'scope:cart', - onlyDependOnLibsWithTags: ['scope:cart', 'scope:shared'], - }, - ], - enforceBuildableLibDependency: true, - }, - ], - ruleSeverity: 'error', - }, - 'directive-selector': { - ruleArguments: ['attribute', 'app', 'camelCase'], - ruleSeverity: 'error', - }, - 'component-selector': { - ruleArguments: ['element', 'app', 'kebab-case'], - ruleSeverity: 'error', - }, - 'no-conflicting-lifecycle': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-host-metadata-property': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-input-rename': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-inputs-metadata-property': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'no-output-native': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-output-on-prefix': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-output-rename': { ruleArguments: [], ruleSeverity: 'error' }, - 'no-outputs-metadata-property': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'template-banana-in-box': { ruleArguments: [], ruleSeverity: 'error' }, - 'template-no-negated-async': { ruleArguments: [], ruleSeverity: 'error' }, - 'use-lifecycle-interface': { ruleArguments: [], ruleSeverity: 'error' }, - 'use-pipe-transform-interface': { - ruleArguments: [], - ruleSeverity: 'error', - }, - }, - }, -}; - -export const exampleAngularProjectTslintJson = { - raw: { - extends: '../../tslint.json', - rules: { - 'directive-selector': [true, 'attribute', 'angular-app', 'camelCase'], - 'component-selector': [true, 'element', 'angular-app', 'kebab-case'], - }, - linterOptions: { - exclude: ['!**/*'], - }, - }, - tslintPrintConfigResult: { - rules: { - 'directive-selector': { - ruleArguments: ['attribute', 'angular-app', 'camelCase'], - ruleSeverity: 'error', - }, - 'component-selector': { - ruleArguments: ['element', 'angular-app', 'kebab-case'], - ruleSeverity: 'error', - }, - }, - }, -}; - -export const exampleNonAngularProjectTslintJson = { - raw: { - extends: '../../tslint.json', - linterOptions: { exclude: ['!**/*'] }, - rules: {}, - }, - tslintPrintConfigResult: { rules: {} }, -}; - -export const exampleE2eProjectTslintJson = { - raw: { - extends: '../../tslint.json', - linterOptions: { exclude: ['!**/*'] }, - rules: {}, - }, - tslintPrintConfigResult: { rules: {} }, -}; diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/index.ts b/packages/linter/src/utils/convert-tslint-to-eslint/index.ts deleted file mode 100644 index cc95094649634..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { - ConvertTSLintToESLintSchema, - ProjectConverter, -} from './project-converter'; - -// For testing -export { exampleRootTslintJson } from './example-tslint-configs'; diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/project-converter.spec.ts b/packages/linter/src/utils/convert-tslint-to-eslint/project-converter.spec.ts deleted file mode 100644 index af975cbf180ff..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/project-converter.spec.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { - addDependenciesToPackageJson, - addProjectConfiguration, - NxJsonConfiguration, - readJson, - readProjectConfiguration, - Tree, - writeJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { ProjectConverter } from './project-converter'; - -/** - * Don't run actual child_process implementation of installPackagesTask() - */ -jest.mock('child_process', () => { - return { - ...jest.requireActual('child_process'), - execSync: jest.fn((command: string) => { - if (command.includes('pnpm --version')) { - return '8.2.0'; - } - return; - }), - }; -}); - -/** - * Don't run the conversion util, it touches the file system and has its own tests - */ -jest.mock('./utils', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('./utils'), - convertTSLintConfig: jest.fn(() => { - return { - convertedESLintConfig: { - rules: { - 'some-converted-rule': 'error', - }, - }, - unconvertedTSLintRules: [], - ensureESLintPlugins: [], - }; - }), - }; -}); - -describe('ProjectConverter', () => { - let host: Tree; - const projectName = 'foo'; - const projectRoot = `apps/${projectName}`; - - beforeEach(async () => { - // Clean up any previous dry run simulations - process.argv = process.argv.filter( - (a) => !['--dry-run', '--dryRun', '-d'].includes(a) - ); - host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - addProjectConfiguration(host, projectName, { - root: projectRoot, - projectType: 'application', - targets: { - /** - * LINT TARGET CONFIG - BEFORE CONVERSION - * - * TSLint executor configured for the project - */ - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', `!${projectRoot}/**/*`], - tsConfig: [`${projectRoot}/tsconfig.app.json`], - }, - }, - }, - /** - * PROJECT-LEVEL GENERATOR CONFIG - BEFORE CONVERSION - * - * Default set to tslint, using shorthand syntax - */ - generators: { - '@nx/angular:library': { - linter: 'tslint', - }, - '@nx/angular:application': { - e2eTestRunner: 'cypress', - linter: 'eslint', - unitTestRunner: 'jest', - }, - }, - }); - }); - - it('should throw if --dry-run is set', () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - process.argv.push('--dry-run'); - - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }) - ).toThrowErrorMatchingSnapshot(); - }); - - it('should throw if --dryRun is set', () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - process.argv.push('--dryRun'); - - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }) - ).toThrowErrorMatchingSnapshot(); - }); - - it('should throw if -d is set', () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - process.argv.push('-d'); - - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }) - ).toThrowErrorMatchingSnapshot(); - }); - - it('should throw if no root tslint.json is found', () => { - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }) - ).toThrowErrorMatchingSnapshot(); - }); - - it('should not throw if no root tslint.json is found but ignore is set', () => { - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: true, - eslintInitializer: () => undefined, - }) - ).not.toThrow(); - }); - - it('should not throw if no project tslint.json is found', () => { - writeJson(host, 'tslint.json', {}); - - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }) - ).not.toThrow(); - }); - - it('should not throw when not in dry-run and config files successfully found', () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - expect( - () => - new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }) - ).not.toThrow(); - }); - - describe('ignoreExistingTslintConfig', () => { - describe('ignoreExistingTslintConfig: false', () => { - it('should use existing TSLint configs and merge their converted ESLint equivalents with recommended ESLint configs', async () => { - const { convertTSLintConfig } = require('./utils'); - (convertTSLintConfig as jest.Mock).mockClear(); - - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - const projectConverterDiscardFalse = new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => { - writeJson(host, '.eslintrc.json', { - rules: { - 'some-recommended-root-eslint-rule': 'error', - }, - }); - writeJson(host, `${projectRoot}/.eslintrc.json`, { - rules: { - 'some-recommended-project-eslint-rule': 'error', - }, - }); - return Promise.resolve(undefined); - }, - }); - await projectConverterDiscardFalse.initESLint(); - - // Existing ESLint rules from init stage will be merged with converted rules - await projectConverterDiscardFalse.convertRootTSLintConfig((j) => j); - expect(readJson(host, '.eslintrc.json')).toMatchSnapshot(); - - // Existing ESLint rules from init stage will be merged with converted rules - await projectConverterDiscardFalse.convertProjectConfig((j) => j); - expect( - readJson(host, `${projectRoot}/.eslintrc.json`) - ).toMatchSnapshot(); - - expect(convertTSLintConfig).toHaveBeenCalledTimes(2); - }); - }); - - describe('ignoreExistingTslintConfig: true', () => { - it('should ignore existing TSLint configs and just reset the project to use recommended ESLint configs', async () => { - const { convertTSLintConfig } = require('./utils'); - (convertTSLintConfig as jest.Mock).mockClear(); - - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - const projectConverterDiscardTrue = new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: true, - eslintInitializer: () => { - writeJson(host, '.eslintrc.json', { - rules: { - 'some-recommended-root-eslint-rule': 'error', - }, - }); - writeJson(host, `${projectRoot}/.eslintrc.json`, { - rules: { - 'some-recommended-project-eslint-rule': 'error', - }, - }); - return Promise.resolve(undefined); - }, - }); - await projectConverterDiscardTrue.initESLint(); - - // Should not contain any converted rules, just existing ESLint rules from init stage - await projectConverterDiscardTrue.convertRootTSLintConfig((j) => j); - expect(readJson(host, '.eslintrc.json')).toMatchSnapshot(); - - // Should not contain any converted rules, just existing ESLint rules from init stage - await projectConverterDiscardTrue.convertProjectConfig((j) => j); - expect( - readJson(host, `${projectRoot}/.eslintrc.json`) - ).toMatchSnapshot(); - - expect(convertTSLintConfig).not.toHaveBeenCalled(); - }); - }); - }); - - describe('setDefaults()', () => { - it('should save in nx.json', async () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - const projectConverter = new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }); - - const nxJson = readJson(host, 'nx.json'); - nxJson.generators = { - '@nx/angular': { - application: { - linter: 'tslint', - }, - library: { - linter: 'tslint', - }, - }, - }; - writeJson(host, 'nx.json', nxJson); - - // BEFORE - no entry for convert-tslint-to-eslint wthin @nx/angular generators - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - - projectConverter.setDefaults('@nx/angular', { - ignoreExistingTslintConfig: true, - removeTSLintIfNoMoreTSLintTargets: true, - }); - - // AFTER (1) - convert-tslint-to-eslint wthin @nx/angular generators has removeTSLintIfNoMoreTSLintTargets set to true - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - - projectConverter.setDefaults('@nx/angular', { - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: false, - }); - - // AFTER (2) - convert-tslint-to-eslint wthin @nx/angular generators has removeTSLintIfNoMoreTSLintTargets set to false - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - }); - }); - - describe('removeTSLintFromWorkspace()', () => { - it('should remove all relevant traces of TSLint from the workspace', async () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - const projectConverter = new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }); - - await addDependenciesToPackageJson( - host, - {}, - { - codelyzer: 'latest', - tslint: 'latest', - } - )(); - - const nxJson = readJson(host, 'nx.json'); - // Not using shorthand syntax this time - nxJson.generators = { - '@nx/angular': { - application: { - linter: 'tslint', - }, - library: { - linter: 'tslint', - }, - }, - }; - writeJson(host, 'nx.json', nxJson); - - // BEFORE - tslint and codelyzer are present - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - // BEFORE - tslint set as both global linter for @nx/angular generators - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - - expect(readProjectConfiguration(host, projectName)).toMatchSnapshot(); - - await projectConverter.removeTSLintFromWorkspace()(); - - // AFTER - it should remove tslint and codelyzer - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - // AFTER - generators config from global project-level settings removed (because eslint is always default) - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - - // AFTER - generators config from project-level settings removed (because eslint is always default) - expect(readProjectConfiguration(host, projectName)).toMatchSnapshot(); - }); - - it('should remove the entry in generators for convert-tslint-to-eslint because it is no longer needed', async () => { - writeJson(host, 'tslint.json', {}); - writeJson(host, `${projectRoot}/tslint.json`, {}); - - const projectConverter = new ProjectConverter({ - host, - projectName, - ignoreExistingTslintConfig: false, - eslintInitializer: () => undefined, - }); - - const nxJson = readJson(host, 'nx.json'); - nxJson.generators = { - '@nx/angular': { - 'convert-tslint-to-eslint': { - removeTSLintIfNoMoreTSLintTargets: true, - }, - }, - }; - writeJson(host, 'nx.json', nxJson); - - // BEFORE - convert-tslint-to-eslint wthin @nx/angular generators has a value for removeTSLintIfNoMoreTSLintTargets - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - - await projectConverter.removeTSLintFromWorkspace()(); - - // AFTER - generators config no longer has a reference to convert-tslint-to-eslint - expect(readJson(host, 'nx.json')).toMatchSnapshot(); - }); - }); -}); diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/project-converter.ts b/packages/linter/src/utils/convert-tslint-to-eslint/project-converter.ts deleted file mode 100644 index 4ca01b619609a..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/project-converter.ts +++ /dev/null @@ -1,565 +0,0 @@ -import type { GeneratorCallback, ProjectConfiguration, Tree } from '@nx/devkit'; -import { - getProjects, - installPackagesTask, - joinPathFragments, - logger, - offsetFromRoot, - readJson, - readNxJson, - readProjectConfiguration, - removeDependenciesFromPackageJson, - updateJson, - updateNxJson, - updateProjectConfiguration, -} from '@nx/devkit'; -import type { Linter } from 'eslint'; -import { removeParserOptionsProjectIfNotRequired } from '../rules-requiring-type-checking'; -import { convertTSLintDisableCommentsForProject } from './convert-to-eslint-config'; -import { - convertTSLintConfig, - deduplicateOverrides, - ensureESLintPluginsAreInstalled, -} from './utils'; - -/** - * Common schema used by all implementations of convert-tslint-to-eslint generators - * - * @deprecated This will be removed in v17 - */ -export interface ConvertTSLintToESLintSchema { - project: string; - // If true, we are effectively just "resetting" to ESLint, rather than converting from TSLint - ignoreExistingTslintConfig: boolean; - removeTSLintIfNoMoreTSLintTargets: boolean; - skipFormat?: boolean; -} - -/** - * - * When we convert a TSLint setup to an ESLint setup for a particular project, there are a number of - * shared/common concerns (implemented as library utilities within @nx/linter), and a few things - * which are specific to this package and the types of projects it produces. - * - * The key structure of the converted ESLint support is as follows: - * - * - We will first generate a workspace root .eslintrc.json which is the same as the one generated - * for new workspaces (i.e. it is NOT just a converted version of their root tslint.json). This allows us - * to have a consistent base for all users, as well as standardized patterns around "overrides". - * - * - The user's original root tslint.json will be converted and any applicable settings will be stored - * within ADDITIONAL override blocks within the root .eslintrc.json. - * - * - The user's project-level tslint.json file will be converted into a corresponding .eslintrc.json file - * and it will extend from the root workspace .eslintrc.json file as normal. - * - * @deprecated This will be removed in v17 - */ -export class ProjectConverter { - private readonly projectConfig: ProjectConfiguration; - private readonly rootTSLintJsonPath = 'tslint.json'; - private readonly rootTSLintJson: Record; - private readonly projectTSLintJsonPath: string; - private readonly projectTSLintJson: Record; - private readonly host: Tree; - private readonly projectName: string; - private readonly ignoreExistingTslintConfig: boolean; - private readonly eslintInitializer: (projectInfo: { - projectName: string; - projectConfig: ProjectConfiguration; - }) => Promise; - - /** - * Using an object as the argument to the constructor means we sacrifice some - * authoring sugar around initializing these properties but it makes the usage - * of the class much easier to read and maintain. - */ - constructor({ - host, - projectName, - ignoreExistingTslintConfig, - eslintInitializer, - }: { - host: Tree; - projectName: string; - ignoreExistingTslintConfig: boolean; - eslintInitializer: (projectInfo: { - projectName: string; - projectConfig: ProjectConfiguration; - }) => Promise; - }) { - this.host = host; - this.projectName = projectName; - this.ignoreExistingTslintConfig = ignoreExistingTslintConfig; - this.eslintInitializer = eslintInitializer; - this.projectConfig = readProjectConfiguration(this.host, this.projectName); - this.projectTSLintJsonPath = joinPathFragments( - this.projectConfig.root, - 'tslint.json' - ); - - /** - * Given the user is converting a project from TSLint to ESLint, we expect them - * to have both a root and a project-specific tslint.json - */ - if (!ignoreExistingTslintConfig) { - if (!host.exists(this.rootTSLintJsonPath)) { - throw new Error( - 'We could not find a tslint.json at the root of your workspace, maybe you have already migrated to ESLint?' - ); - } - this.rootTSLintJson = readJson(host, this.rootTSLintJsonPath); - if (!host.exists(this.projectTSLintJsonPath)) { - logger.warn( - `We could not find a tslint.json for the selected project "${this.projectTSLintJsonPath}", maybe you have already migrated to ESLint?` - ); - } else { - this.projectTSLintJson = readJson(host, this.projectTSLintJsonPath); - } - } - - /** - * We are not able to support --dry-run in this generator, because we need to dynamically install - * and use the tslint-to-eslint-config package within the same execution. - * - * This is a worthwhile trade-off and the dry-run output doesn't offer a ton of value for this use-case anyway. - */ - if ( - process.argv.includes('--dry-run') || - process.argv.includes('--dryRun') || - process.argv.includes('-d') - ) { - throw new Error( - 'NOTE: This generator does not support --dry-run. If you are running this in Nx Console, it should execute fine once you hit the "Run" button.\n' - ); - } - } - - async initESLint(): Promise { - await this.eslintInitializer({ - projectName: this.projectName, - projectConfig: this.projectConfig, - }); - // Ensure that all the dependencies added as part ESLint initialization are installed - return () => { - installPackagesTask(this.host); - }; - } - - /** - * If the package-specific shareable config already exists then the workspace must already - * be part way through migrating from TSLint to ESLint. In this case we do not want to convert - * the root tslint.json again (and this utility will return a noop task), and we instead just - * focus on the project-level config conversion. - */ - async convertRootTSLintConfig( - applyPackageSpecificModifications: (json: Linter.Config) => Linter.Config, - rootEslintConfigExists?: boolean - ): Promise> { - if (this.ignoreExistingTslintConfig) { - return Promise.resolve(() => {}); - } - /** - * If root eslint already exists, we will not override it with converted tslint - * as this might break existing configuration in place. This is the common scenario - * when large projects are migrating one project at a time and apply custom - * changes to root config in the meantime. - * - * We warn user of this action in case .eslintrc.json was created accidentally - */ - if (rootEslintConfigExists) { - logger.warn( - `Root '.eslintrc.json' found. Assuming conversion was already run for other projects.` - ); - return Promise.resolve(() => {}); - } - - const convertedRoot = await convertTSLintConfig( - this.rootTSLintJson, - this.rootTSLintJsonPath, - [] - ); - const convertedRootESLintConfig = convertedRoot.convertedESLintConfig; - - /** - * Already set by Nx's shareable configs - */ - delete convertedRootESLintConfig.env; - delete convertedRootESLintConfig.parser; - delete convertedRootESLintConfig.parserOptions; - if (convertedRootESLintConfig.plugins) { - convertedRootESLintConfig.plugins = - convertedRootESLintConfig.plugins.filter( - (p) => p !== '@typescript-eslint/tslint' - ); - } - - /** - * The only piece of the converted root tslint.json that we need to pull out to - * apply to the existing overrides within the root .eslintrc.json is the - * @nx/enforce-module-boundaries rule. - */ - const nxRuleName = '@nx/enforce-module-boundaries'; - const nxEnforceModuleBoundariesRule = - convertedRootESLintConfig.rules[nxRuleName]; - if (nxEnforceModuleBoundariesRule) { - updateJson(this.host, '.eslintrc.json', (json) => { - if (!json.overrides) { - return json; - } - for (const o of json.overrides) { - if (!o.rules) { - continue; - } - if (!o.rules[nxRuleName]) { - continue; - } - o.rules[nxRuleName] = nxEnforceModuleBoundariesRule; - } - return json; - }); - /** - * Remove it once we've used it on the root, so that is isn't applied - * to the package-specific shareable config - */ - delete convertedRootESLintConfig.rules[nxRuleName]; - } - - /** - * Update the root workspace .eslintrc.json with additional overrides - */ - const finalConvertedRootESLintConfig = applyPackageSpecificModifications( - convertedRootESLintConfig - ); - updateJson(this.host, '.eslintrc.json', (json) => { - json.overrides ||= []; - if ( - finalConvertedRootESLintConfig.overrides && - finalConvertedRootESLintConfig.overrides.length - ) { - json.overrides = [ - ...json.overrides, - ...finalConvertedRootESLintConfig.overrides, - ]; - } else { - json.overrides.push({ - files: ['*.ts'], - ...finalConvertedRootESLintConfig, - }); - } - json.overrides = deduplicateOverrides(json.overrides); - /** - * Remove the parserOptions.project config if it is not required for the final config, - * so that lint runs can be as fast and efficient as possible. - */ - return removeParserOptionsProjectIfNotRequired(json); - }); - - /** - * Through converting the config we may encounter TSLint rules whose closest - * equivalent in the ESLint ecosystem comes from a separate package/plugin. - * - * We therefore automatically install those extra packages for the user and - * explain that that's what we are doing. - */ - return ensureESLintPluginsAreInstalled( - this.host, - convertedRoot.ensureESLintPlugins - ); - } - - async convertProjectConfig( - applyPackageSpecificModifications: (json: Linter.Config) => Linter.Config - ): Promise { - if (this.ignoreExistingTslintConfig || !this.projectTSLintJson) { - return Promise.resolve(() => {}); - } - - const convertedProjectConfig = await convertTSLintConfig( - this.projectTSLintJson, - this.projectTSLintJsonPath, - // Strip the extends on workspace tslint.json (see this util's docs for more info) - [`${offsetFromRoot(this.projectConfig.root)}tslint.json`] - ); - - const convertedProjectESLintConfig = - convertedProjectConfig.convertedESLintConfig; - - /** - * Already set by Nx's shareable configs - */ - delete convertedProjectESLintConfig.env; - delete convertedProjectESLintConfig.parser; - delete convertedProjectESLintConfig.parserOptions; - if (convertedProjectESLintConfig.plugins) { - convertedProjectESLintConfig.plugins = - convertedProjectESLintConfig.plugins.filter( - (p) => p !== '@typescript-eslint/tslint' - ); - } - - const projectESLintConfigPath = joinPathFragments( - this.projectConfig.root, - '.eslintrc.json' - ); - - /** - * Apply updates to the new .eslintrc.json file for the project - */ - updateJson(this.host, projectESLintConfigPath, (json) => { - if (typeof json.extends === 'string') { - json.extends = [json.extends]; - } - // Custom extends from conversion - if ( - Array.isArray(convertedProjectESLintConfig.extends) && - convertedProjectESLintConfig.extends.length - ) { - // Ignore any tslint-to-eslint-config default extends that do not apply to Nx - const applicableExtends = convertedProjectESLintConfig.extends.filter( - (ext) => !ext.startsWith('prettier') - ); - if (applicableExtends.length) { - json.extends = [...json.extends, ...applicableExtends]; - } - } - // Custom plugins from conversion - if ( - Array.isArray(convertedProjectESLintConfig.plugins) && - convertedProjectESLintConfig.plugins.length - ) { - json.plugins = [ - ...(json.plugins ?? []), - ...convertedProjectESLintConfig.plugins, - ]; - } - /** - * Custom rules - * - * By default, tslint-to-eslint-config will try and apply any rules without known converters - * by using eslint-plugin-tslint. We instead explicitly warn the user about this missing converter, - * and therefore at this point we strip out any rules which start with @typescript-eslint/tslint/config - */ - json.rules ||= {}; - if ( - convertedProjectESLintConfig.rules && - Object.keys(convertedProjectESLintConfig.rules).length - ) { - for (const [ruleName, ruleConfig] of Object.entries( - convertedProjectESLintConfig.rules - )) { - if (!ruleName.startsWith('@typescript-eslint/tslint/config')) { - // Prioritize the converted rules over any base implementations from the original Nx generator - json.rules[ruleName] = ruleConfig; - } - } - } - /** - * Apply any package-specific modifications to the converted config before - * updating the config file. - */ - const finalJson = applyPackageSpecificModifications(json); - /** - * Remove the parserOptions.project config if it is not required for the final config, - * so that lint runs can be as fast and efficient as possible. - */ - return removeParserOptionsProjectIfNotRequired(finalJson); - }); - - /** - * Convert any instances of comment-based configuration in the source files - * of the project - */ - convertTSLintDisableCommentsForProject(this.host, this.projectName); - - /** - * Through converting the config we may encounter TSLint rules whose closest - * equivalent in the ESLint ecosystem comes from a separate package/plugin. - * - * We therefore automatically install those extra packages for the user and - * explain that that's what we are doing. - */ - return ensureESLintPluginsAreInstalled( - this.host, - convertedProjectConfig.ensureESLintPlugins - ); - } - - removeProjectTSLintFile() { - this.host.delete(joinPathFragments(this.projectConfig.root, 'tslint.json')); - } - - isTSLintUsedInWorkspace(): boolean { - const projects = getProjects(this.host); - for (const [, projectConfig] of projects.entries()) { - for (const [, targetConfig] of Object.entries(projectConfig.targets)) { - if (targetConfig.executor === '@angular-devkit/build-angular:tslint') { - // Workspace is still using TSLint, exit early - return true; - } - } - } - // If we got this far the user has no remaining TSLint usage - return false; - } - - removeTSLintFromWorkspace(): GeneratorCallback { - logger.info( - `No TSLint usage will remain in the workspace, removing TSLint...` - ); - /** - * Delete the root tslint.json - */ - this.host.delete(this.rootTSLintJsonPath); - - /** - * Prepare the package.json and the uninstall task - */ - const uninstallTask = removeDependenciesFromPackageJson( - this.host, - [], - ['tslint', 'codelyzer'] - ); - - /** - * Update global linter configuration defaults in project configuration - */ - const nxJson = readNxJson(this.host); - this.cleanUpGeneratorsConfig(nxJson); - updateNxJson(this.host, nxJson); - - /** - * Update project-level linter configuration defaults in project configuration - */ - const projects = getProjects(this.host); - for (const [projectName, { generators }] of projects.entries()) { - if (!generators || Object.keys(generators).length === 0) { - continue; - } - const project = readProjectConfiguration(this.host, projectName); - this.cleanUpGeneratorsConfig(project); - updateProjectConfiguration(this.host, projectName, project); - } - - return uninstallTask; - } - - private cleanUpGeneratorsConfig(parentConfig: { generators?: any }) { - if ( - !parentConfig.generators || - Object.keys(parentConfig.generators).length === 0 - ) { - return; - } - for (const [collectionName, maybeGeneratorConfig] of Object.entries( - parentConfig.generators - )) { - // Shorthand syntax is possible - if (collectionName.includes(':')) { - const generatorConfig = maybeGeneratorConfig; - for (const optionName of Object.keys(generatorConfig)) { - if (optionName === 'linter') { - // Default is eslint, so in all cases we can just remove the config altogether - delete generatorConfig[optionName]; - } - } - // If removing linter leaves no other options in the config, remove the config as well - if (Object.keys(generatorConfig).length === 0) { - delete parentConfig.generators[collectionName]; - } - } else { - // Not shorthand syntax, so next level down is generator name -> config mapping - const collectionConfig = maybeGeneratorConfig; - - for (const [generatorName, generatorConfig] of Object.entries( - collectionConfig - )) { - if (generatorName === 'convert-tslint-to-eslint') { - // No longer relevant because of TSLint is being removed the conversion process must be complete - delete collectionConfig[generatorName]; - continue; - } - - for (const optionName of Object.keys(generatorConfig)) { - if (optionName === 'linter') { - // Default is eslint, so in all cases we can just remove the config altogether - delete generatorConfig[optionName]; - } - } - // If removing linter leaves no other options in the config, remove the generator config as well - if (Object.keys(generatorConfig).length === 0) { - delete collectionConfig[generatorName]; - } - } - - // If removing the generator leaves no other generators in the config, remove the config as well - if ( - parentConfig.generators[collectionName] && - Object.keys(parentConfig.generators[collectionName]).length === 0 - ) { - delete parentConfig.generators[collectionName]; - } - } - } - - // If removing the linter defaults leaves absolutely no generators configuration remaining, remove it - if (Object.keys(parentConfig.generators).length === 0) { - delete parentConfig.generators; - } - } - - /** - * If the project which is the subject of the ProjectConverter instance is an application, - * figure out its associated e2e project's name. - */ - getE2EProjectName(): string | null { - if (this.projectConfig.projectType !== 'application') { - return null; - } - let e2eProjectName = null; - - const projects = getProjects(this.host); - for (const [projectName, projectConfig] of projects.entries()) { - for (const [, targetConfig] of Object.entries(projectConfig.targets)) { - if ( - targetConfig.executor === '@nx/cypress:cypress' || - targetConfig.executor === '@nrwl/cypress:cypress' - ) { - if ( - targetConfig.options.devServerTarget === `${this.projectName}:serve` - ) { - e2eProjectName = projectName; - logger.info( - `Found e2e project for "${this.projectName}" called "${e2eProjectName}", converting that project as well...` - ); - } - } - } - } - return e2eProjectName; - } - - setDefaults( - collectionName: string, - defaults: Partial - ) { - const nxJson = readNxJson(this.host); - - nxJson.generators ||= {}; - nxJson.generators[collectionName] ||= {}; - const prev = nxJson.generators[collectionName]; - - nxJson.generators = { - ...nxJson.generators, - [collectionName]: { - ...prev, - 'convert-tslint-to-eslint': { - ...prev['convert-tslint-to-eslint'], - ...defaults, - }, - }, - }; - - updateNxJson(this.host, nxJson); - } -} diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/utils.spec.ts b/packages/linter/src/utils/convert-tslint-to-eslint/utils.spec.ts deleted file mode 100644 index 6b1b4492c31d6..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/utils.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { Linter } from 'eslint'; -import { deduplicateOverrides } from './utils'; - -describe('deduplicateOverrides()', () => { - it('should deduplicate overrides with identical values for "files"', () => { - const initialOverrides: Linter.Config['overrides'] = [ - { - files: ['*.ts'], - env: { - foo: true, - }, - rules: { - bar: 'error', - }, - }, - { - files: ['*.html'], - rules: {}, - }, - { - files: '*.ts', - plugins: ['wat'], - parserOptions: { - qux: false, - }, - rules: { - bar: 'warn', - baz: 'error', - }, - }, - { - files: ['*.ts'], - extends: ['something'], - }, - ]; - expect(deduplicateOverrides(initialOverrides)).toEqual([ - { - files: ['*.ts'], - env: { - foo: true, - }, - plugins: ['wat'], - extends: ['something'], - parserOptions: { - qux: false, - }, - rules: { - bar: 'warn', - baz: 'error', - }, - }, - { - files: ['*.html'], - rules: {}, - }, - ]); - }); -}); diff --git a/packages/linter/src/utils/convert-tslint-to-eslint/utils.ts b/packages/linter/src/utils/convert-tslint-to-eslint/utils.ts deleted file mode 100644 index 7288b7a8880a8..0000000000000 --- a/packages/linter/src/utils/convert-tslint-to-eslint/utils.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { addDependenciesToPackageJson, logger } from '@nx/devkit'; -import type { Tree, GeneratorCallback } from '@nx/devkit'; -import type { Linter } from 'eslint'; -import type { TSLintRuleOptions } from 'tslint-to-eslint-config'; -import { convertTslintNxRuleToEslintNxRule } from './convert-nx-enforce-module-boundaries-rule'; -import { convertToESLintConfig } from './convert-to-eslint-config'; - -export function ensureESLintPluginsAreInstalled( - host: Tree, - eslintPluginsToBeInstalled: string[] -): GeneratorCallback { - if (!eslintPluginsToBeInstalled?.length) { - return () => undefined; - } - - const additionalDevDependencies = {}; - - for (const pluginName of eslintPluginsToBeInstalled) { - additionalDevDependencies[pluginName] = 'latest'; - } - - logger.info( - '\nINFO: To most closely match your tslint.json, we will ensure the `latest` version of the following eslint plugin(s) are installed:' - ); - logger.info('\n - ' + eslintPluginsToBeInstalled.join('\n - ')); - logger.info( - '\nPlease note, you may later wish to pin these to a specific version number in your package.json, rather than leaving it open to `latest`.\n' - ); - - return addDependenciesToPackageJson(host, {}, additionalDevDependencies); -} - -/** - * We don't want the user to depend on the TSLint fallback plugin, we will instead - * explicitly inform them of the rules that could not be converted automatically and - * advise them on what to do next. - */ -function warnInCaseOfUnconvertedRules( - tslintConfigPath: string, - unconvertedTSLintRules: TSLintRuleOptions[] -): void { - const unconvertedTSLintRuleNames = unconvertedTSLintRules - .filter( - // Ignore formatting related rules, they are handled by Nx format/prettier - (unconverted) => - !['import-spacing', 'whitespace', 'typedef'].includes( - unconverted.ruleName - ) - ) - .map((unconverted) => unconverted.ruleName); - - if (unconvertedTSLintRuleNames.length > 0) { - logger.warn( - `\nWARNING: Within "${tslintConfigPath}", the following ${unconvertedTSLintRuleNames.length} rule(s) did not have known converters in https://github.com/typescript-eslint/tslint-to-eslint-config` - ); - logger.warn('\n - ' + unconvertedTSLintRuleNames.join('\n - ')); - logger.warn( - '\nYou will need to decide on how to handle the above manually, but everything else has been handled for you automatically.\n' - ); - } -} - -/** - * @deprecated This will be removed in v17 - */ -export async function convertTSLintConfig( - rawTSLintJson: any, - tslintJsonPath: string, - ignoreExtendsVals: string[] -) { - const convertedProject = await convertToESLintConfig( - tslintJsonPath, - rawTSLintJson, - ignoreExtendsVals - ); - convertedProject.convertedESLintConfig.rules ||= {}; - - /** - * Apply the custom converter for the nx-module-boundaries rule if applicable - */ - const convertedNxRule = convertTslintNxRuleToEslintNxRule(rawTSLintJson); - if (convertedNxRule) { - convertedProject.convertedESLintConfig.rules[convertedNxRule.ruleName] = - convertedNxRule.ruleConfig; - } - - // Remove the `@typescript-eslint/tslint/config` rule - if ( - convertedProject.convertedESLintConfig.rules[ - '@typescript-eslint/tslint/config' - ] - ) { - delete convertedProject.convertedESLintConfig.rules[ - '@typescript-eslint/tslint/config' - ]; - } - - warnInCaseOfUnconvertedRules( - tslintJsonPath, - convertedProject.unconvertedTSLintRules - ); - - return convertedProject; -} - -export function deduplicateOverrides( - overrides: Linter.Config['overrides'] = [] -) { - const map = new Map(); - for (const o of overrides) { - const mapKey: string = - typeof o.files === 'string' ? o.files : o.files.join(','); - const existing: Set = map.get(mapKey); - if (existing) { - existing.add(o); - map.set(mapKey, existing); - continue; - } - const set = new Set(); - set.add(o); - map.set(mapKey, set); - } - - let dedupedOverrides = []; - - for (const [, overrides] of map.entries()) { - const overridesArr = Array.from(overrides); - if (overridesArr.length === 1) { - dedupedOverrides = [...dedupedOverrides, ...overridesArr]; - continue; - } - let mergedOverride = {}; - for (const o of overridesArr) { - mergedOverride = { - ...mergedOverride, - ...(o as any), - }; - } - dedupedOverrides.push(mergedOverride); - } - - return dedupedOverrides; -} diff --git a/packages/linter/src/utils/versions.ts b/packages/linter/src/utils/versions.ts index e3034a0a0b1ed..29c8604e99b77 100644 --- a/packages/linter/src/utils/versions.ts +++ b/packages/linter/src/utils/versions.ts @@ -3,6 +3,4 @@ export const nxVersion = require('../../package.json').version; export const eslintVersion = '~8.46.0'; export const eslintrcVersion = '^2.1.1'; export const eslintConfigPrettierVersion = '8.1.0'; -/** @deprecated This will be removed in v17 */ -export const tslintToEslintConfigVersion = '^2.14.0'; export const typescriptESLintVersion = '^5.60.1'; diff --git a/packages/nest/generators.json b/packages/nest/generators.json index 7b3a61cc5a45a..86d60bc7bc743 100644 --- a/packages/nest/generators.json +++ b/packages/nest/generators.json @@ -10,12 +10,6 @@ "x-type": "application", "description": "Create a NestJS application." }, - "convert-tslint-to-eslint": { - "factory": "./src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionSchematic", - "schema": "./src/generators/convert-tslint-to-eslint/schema.json", - "description": "Convert a project from TSLint to ESLint.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint." - }, "init": { "factory": "./src/generators/init/init#initSchematic", "schema": "./src/generators/init/schema.json", @@ -114,12 +108,6 @@ "x-type": "application", "description": "Create a NestJS application." }, - "convert-tslint-to-eslint": { - "factory": "./src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint#conversionGenerator", - "schema": "./src/generators/convert-tslint-to-eslint/schema.json", - "description": "Convert a project from TSLint to ESLint.", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint." - }, "init": { "factory": "./src/generators/init/init", "schema": "./src/generators/init/schema.json", diff --git a/packages/nest/index.ts b/packages/nest/index.ts index e19a92acc52f5..450368f16d549 100644 --- a/packages/nest/index.ts +++ b/packages/nest/index.ts @@ -1,8 +1,6 @@ export { applicationGenerator } from './src/generators/application/application'; export { classGenerator } from './src/generators/class/class'; export { controllerGenerator } from './src/generators/controller/controller'; -/** @deprecated This generator will be removed in v17 */ -export { conversionGenerator } from './src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint'; export { decoratorGenerator } from './src/generators/decorator/decorator'; export { filterGenerator } from './src/generators/filter/filter'; export { gatewayGenerator } from './src/generators/gateway/gateway'; diff --git a/packages/nest/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap b/packages/nest/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap deleted file mode 100644 index e53ba96cdbda8..0000000000000 --- a/packages/nest/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap +++ /dev/null @@ -1,571 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`convert-tslint-to-eslint should work for NestJS applications 1`] = ` -{ - "dependencies": {}, - "devDependencies": { - "@nx/eslint-plugin": "0.0.1", - "@nx/linter": "0.0.1", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "eslint": "~8.46.0", - "eslint-config-prettier": "8.1.0", - "eslint-plugin-import": "latest", - }, - "name": "test-name", -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS applications 2`] = ` -{ - "$schema": "../node_modules/nx/schemas/project-schema.json", - "name": "nest-app-1", - "projectType": "application", - "root": "nest-app-1", - "targets": { - "lint": { - "executor": "@nx/linter:eslint", - "options": { - "lintFilePatterns": [ - "nest-app-1/**/*.ts", - ], - }, - "outputs": [ - "{options.outputFile}", - ], - }, - }, -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS applications 3`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": true, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@typescript-eslint", - ], - "root": true, - "rules": { - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS applications 4`] = ` -{ - "extends": [ - "../.eslintrc.json", - ], - "ignorePatterns": [ - "!**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - ], - "plugins": [ - "@typescript-eslint", - ], - "rules": { - "@typescript-eslint/no-empty-interface": "error", - }, -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS libraries 1`] = ` -{ - "dependencies": {}, - "devDependencies": { - "@nx/eslint-plugin": "0.0.1", - "@nx/linter": "0.0.1", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "eslint": "~8.46.0", - "eslint-config-prettier": "8.1.0", - "eslint-plugin-import": "latest", - }, - "name": "test-name", -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS libraries 2`] = ` -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "name": "nest-lib-1", - "projectType": "library", - "root": "libs/nest-lib-1", - "targets": { - "lint": { - "executor": "@nx/linter:eslint", - "options": { - "lintFilePatterns": [ - "libs/nest-lib-1/**/*.ts", - ], - }, - "outputs": [ - "{options.outputFile}", - ], - }, - }, -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS libraries 3`] = ` -{ - "ignorePatterns": [ - "**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - { - "allow": [ - "@nx-example/shared/product/data/testing", - ], - "depConstraints": [ - { - "onlyDependOnLibsWithTags": [ - "type:feature", - "type:ui", - ], - "sourceTag": "type:app", - }, - { - "onlyDependOnLibsWithTags": [ - "type:ui", - "type:data", - "type:types", - "type:state", - ], - "sourceTag": "type:feature", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:types", - }, - { - "onlyDependOnLibsWithTags": [ - "type:state", - "type:types", - "type:data", - ], - "sourceTag": "type:state", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - ], - "sourceTag": "type:data", - }, - { - "onlyDependOnLibsWithTags": [ - "type:e2e-utils", - ], - "sourceTag": "type:e2e", - }, - { - "onlyDependOnLibsWithTags": [ - "type:types", - "type:ui", - ], - "sourceTag": "type:ui", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:products", - "scope:shared", - ], - "sourceTag": "scope:products", - }, - { - "onlyDependOnLibsWithTags": [ - "scope:cart", - "scope:shared", - ], - "sourceTag": "scope:cart", - }, - ], - "enforceBuildableLibDependency": true, - }, - ], - }, - }, - { - "extends": [ - "plugin:@nx/typescript", - ], - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "extends": [ - "plugin:@nx/javascript", - ], - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - ], - "plugins": [ - "eslint-plugin-import", - "@typescript-eslint", - ], - "root": true, - "rules": { - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit", - }, - ], - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "format": [ - "camelCase", - "UPPER_CASE", - ], - "leadingUnderscore": "forbid", - "selector": "variable", - "trailingUnderscore": "forbid", - }, - ], - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-inferrable-types": [ - "error", - { - "ignoreParameters": true, - }, - ], - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-shadow": [ - "error", - { - "hoist": "all", - }, - ], - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/unified-signatures": "error", - "arrow-body-style": "error", - "constructor-super": "error", - "dot-notation": "off", - "eqeqeq": [ - "error", - "smart", - ], - "guard-for-in": "error", - "id-denylist": "off", - "id-match": "off", - "import/no-deprecated": "warn", - "no-bitwise": "error", - "no-caller": "error", - "no-console": [ - "error", - {}, - ], - "no-debugger": "error", - "no-empty": "off", - "no-empty-function": "off", - "no-eval": "error", - "no-fallthrough": "error", - "no-new-wrappers": "error", - "no-restricted-imports": [ - "error", - "rxjs/Rx", - ], - "no-shadow": "off", - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unused-expressions": "off", - "no-var": "error", - "prefer-const": "error", - "radix": "error", - }, - }, - ], - "plugins": [ - "@nx", - ], - "root": true, -} -`; - -exports[`convert-tslint-to-eslint should work for NestJS libraries 4`] = ` -{ - "extends": [ - "../../.eslintrc.json", - ], - "ignorePatterns": [ - "!**/*", - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.tsx", - "*.js", - "*.jsx", - ], - "rules": {}, - }, - { - "files": [ - "*.ts", - "*.tsx", - ], - "rules": {}, - }, - { - "files": [ - "*.js", - "*.jsx", - ], - "rules": {}, - }, - ], - "plugins": [ - "@typescript-eslint", - ], - "rules": { - "@typescript-eslint/no-empty-interface": "error", - }, -} -`; diff --git a/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts b/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts deleted file mode 100644 index 04ec87fc49452..0000000000000 --- a/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts +++ /dev/null @@ -1,246 +0,0 @@ -import * as devkit from '@nx/devkit'; -import { - addProjectConfiguration, - joinPathFragments, - readJson, - readProjectConfiguration, - Tree, - writeJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { exampleRootTslintJson } from '@nx/linter'; -import { conversionGenerator } from './convert-tslint-to-eslint'; - -const appProjectName = 'nest-app-1'; -const appProjectRoot = `${appProjectName}`; -const appProjectTSLintJsonPath = joinPathFragments( - appProjectRoot, - 'tslint.json' -); -const libProjectName = 'nest-lib-1'; -const libProjectRoot = `libs/${libProjectName}`; -const libProjectTSLintJsonPath = joinPathFragments( - libProjectRoot, - 'tslint.json' -); -// Used to configure the test Tree and stub the response from tslint-to-eslint-config util findReportedConfiguration() -const projectTslintJsonData = { - raw: { - extends: '../../tslint.json', - rules: { - // User custom TS rule - 'no-empty-interface': true, - // User custom rule with no known automated converter - 'some-super-custom-rule-with-no-converter': true, - }, - linterOptions: { - exclude: ['!**/*'], - }, - }, - tslintPrintConfigResult: { - rules: { - 'no-empty-interface': { - ruleArguments: [], - ruleSeverity: 'error', - }, - 'some-super-custom-rule-with-no-converter': { - ruleArguments: [], - ruleSeverity: 'error', - }, - }, - }, -}; - -function mockFindReportedConfiguration(_, pathToTslintJson) { - switch (pathToTslintJson) { - case 'tslint.json': - return exampleRootTslintJson.tslintPrintConfigResult; - case appProjectTSLintJsonPath: - return projectTslintJsonData.tslintPrintConfigResult; - case libProjectTSLintJsonPath: - return projectTslintJsonData.tslintPrintConfigResult; - default: - throw new Error( - `mockFindReportedConfiguration - Did not recognize path ${pathToTslintJson}` - ); - } -} - -/** - * See ./mock-tslint-to-eslint-config.ts for why this is needed - */ -jest.mock('tslint-to-eslint-config', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('tslint-to-eslint-config'), - findReportedConfiguration: jest.fn(mockFindReportedConfiguration), - }; -}); - -/** - * Mock the the mutating fs utilities used within the conversion logic, they are not - * needed because of our stubbed response for findReportedConfiguration() above, and - * they would cause noise in the git data of the actual Nx repo when the tests run. - */ -jest.mock('fs', () => { - return { - // Since upgrading to (ts-)jest 26 this usage of this mock has caused issues... - // @ts-ignore - ...jest.requireActual('fs'), - writeFileSync: jest.fn(), - mkdirSync: jest.fn(), - }; -}); - -describe('convert-tslint-to-eslint', () => { - let host: Tree; - - beforeEach(async () => { - jest.spyOn(devkit, 'installPackagesTask'); - host = createTreeWithEmptyWorkspace(); - - writeJson(host, 'tslint.json', exampleRootTslintJson.raw); - - addProjectConfiguration(host, appProjectName, { - root: appProjectRoot, - projectType: 'application', - targets: { - /** - * LINT TARGET CONFIG - BEFORE CONVERSION - * - * TSLint executor configured for the project - */ - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', '!nest-app-1/**/*'], - tsConfig: ['nest-app-1/tsconfig.app.json'], - }, - }, - }, - }); - - addProjectConfiguration(host, libProjectName, { - root: libProjectRoot, - projectType: 'library', - targets: { - /** - * LINT TARGET CONFIG - BEFORE CONVERSION - * - * TSLint executor configured for the project - */ - lint: { - executor: '@angular-devkit/build-angular:tslint', - options: { - exclude: ['**/node_modules/**', '!libs/nest-lib-1/**/*'], - tsConfig: ['libs/nest-lib-1/tsconfig.app.json'], - }, - }, - }, - }); - - /** - * Existing tslint.json file for the app project - */ - writeJson(host, 'nest-app-1/tslint.json', projectTslintJsonData.raw); - /** - * Existing tslint.json file for the lib project - */ - writeJson(host, 'libs/nest-lib-1/tslint.json', projectTslintJsonData.raw); - }); - - it('should work for NestJS applications', async () => { - await conversionGenerator(host, { - project: appProjectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: false, - }); - - /** - * It should ensure the required Nx packages are installed and available - * - * NOTE: tslint-to-eslint-config should NOT be present - */ - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - /** - * LINT TARGET CONFIG - AFTER CONVERSION - * - * It should replace the TSLint executor with the ESLint one - */ - expect(readProjectConfiguration(host, appProjectName)).toMatchSnapshot(); - - /** - * The root level .eslintrc.json should now have been generated - */ - const eslintJson = readJson(host, '.eslintrc.json'); - expect(eslintJson.overrides[3].rules['no-console'][1].allow).toContain( - 'log' - ); - // Remove no-console config because it is not deterministic across node versions - delete eslintJson.overrides[3].rules['no-console'][1].allow; - expect(eslintJson).toMatchSnapshot(); - - /** - * The project level .eslintrc.json should now have been generated - * and extend from the root, as well as applying any customizations - * which are specific to this projectType. - */ - expect( - readJson(host, joinPathFragments(appProjectRoot, '.eslintrc.json')) - ).toMatchSnapshot(); - - /** - * The project's TSLint file should have been deleted - */ - expect(host.exists(appProjectTSLintJsonPath)).toEqual(false); - }); - - it('should work for NestJS libraries', async () => { - await conversionGenerator(host, { - project: libProjectName, - ignoreExistingTslintConfig: false, - removeTSLintIfNoMoreTSLintTargets: false, - }); - - /** - * It should ensure the required Nx packages are installed and available - * - * NOTE: tslint-to-eslint-config should NOT be present - */ - expect(readJson(host, 'package.json')).toMatchSnapshot(); - - /** - * LINT TARGET CONFIG - AFTER CONVERSION - * - * It should replace the TSLint executor with the ESLint one - */ - expect(readProjectConfiguration(host, libProjectName)).toMatchSnapshot(); - - /** - * The root level .eslintrc.json should now have been generated - */ - const eslintJson = readJson(host, '.eslintrc.json'); - expect(eslintJson.overrides[3].rules['no-console'][1].allow).toContain( - 'log' - ); - // Remove no-console config because it is not deterministic across node versions - delete eslintJson.overrides[3].rules['no-console'][1].allow; - expect(eslintJson).toMatchSnapshot(); - - /** - * The project level .eslintrc.json should now have been generated - * and extend from the root, as well as applying any customizations - * which are specific to this projectType. - */ - expect( - readJson(host, joinPathFragments(libProjectRoot, '.eslintrc.json')) - ).toMatchSnapshot(); - - /** - * The project's TSLint file should have been deleted - */ - expect(host.exists(libProjectTSLintJsonPath)).toEqual(false); - }); -}); diff --git a/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts b/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts deleted file mode 100755 index b2c3e498daa31..0000000000000 --- a/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { - convertNxGenerator, - formatFiles, - GeneratorCallback, - Tree, -} from '@nx/devkit'; -import { ConvertTSLintToESLintSchema, ProjectConverter } from '@nx/linter'; -import { - addLintingToApplication, - NormalizedSchema as AddLintForApplicationSchema, -} from '@nx/node/src/generators/application/application'; -import { addLint as addLintingToLibraryGenerator } from '@nx/js/src/generators/library/library'; -import type { Linter } from 'eslint'; - -/** - * @deprecated This generator will be removed in v17 - */ -export async function conversionGenerator( - host: Tree, - options: ConvertTSLintToESLintSchema -) { - /** - * The ProjectConverter instance encapsulates all the standard operations we need - * to perform in order to convert a project from TSLint to ESLint, as well as some - * extensibility points for adjusting the behavior on a per package basis. - * - * E.g. @nx/angular projects might need to make different changes to the final - * ESLint config when compared with @nx/nest projects. - * - * See the ProjectConverter implementation for a full breakdown of what it does. - */ - const projectConverter = new ProjectConverter({ - host, - projectName: options.project, - ignoreExistingTslintConfig: options.ignoreExistingTslintConfig, - eslintInitializer: async ({ projectName, projectConfig }) => { - /** - * Using .js is not an option with NestJS, so we always set it to false when - * delegating to the external (more generic) generators below. - */ - const js = false; - /** - * We set the parserOptions.project config just in case the converted config uses - * rules which require type-checking. Later in the conversion we check if it actually - * does and remove the config again if it doesn't, so that it is most efficient. - */ - const setParserOptionsProject = true; - - if (projectConfig.projectType === 'application') { - await addLintingToApplication(host, { - linter: 'eslint', - name: projectName, - appProjectRoot: projectConfig.root, - js, - setParserOptionsProject, - parsedTags: [], - skipFormat: options.skipFormat, - } as AddLintForApplicationSchema); - } - - if (projectConfig.projectType === 'library') { - await addLintingToLibraryGenerator(host, { - linter: 'eslint', - name: projectName, - projectRoot: projectConfig.root, - js, - setParserOptionsProject, - }); - } - }, - }); - - /** - * If root eslint configuration already exists it will not be recreated - * but we also don't want to re-run the tslint config conversion - * as it was likely already done - */ - const rootEslintConfigExists = host.exists('.eslintrc.json'); - - /** - * Create the standard (which is applicable to the current package) ESLint setup - * for converting the project. - */ - const eslintInitInstallTask = await projectConverter.initESLint(); - - /** - * Convert the root tslint.json and apply the converted rules to the root .eslintrc.json. - */ - const rootConfigInstallTask = await projectConverter.convertRootTSLintConfig( - (json) => removeCodelyzerRelatedRules(json), - rootEslintConfigExists - ); - - /** - * Convert the project's tslint.json to an equivalent ESLint config. - */ - const projectConfigInstallTask = await projectConverter.convertProjectConfig( - (json) => json - ); - - /** - * Clean up the original TSLint configuration for the project. - */ - projectConverter.removeProjectTSLintFile(); - - // Only project shouldn't be added as a default - const { project, ...defaults } = options; - - /** - * Store user preferences for the collection - */ - projectConverter.setDefaults('@nx/nest', defaults); - - /** - * Based on user preference and remaining usage, remove TSLint from the workspace entirely. - */ - let uninstallTSLintTask: GeneratorCallback = () => Promise.resolve(undefined); - if ( - options.removeTSLintIfNoMoreTSLintTargets && - !projectConverter.isTSLintUsedInWorkspace() - ) { - uninstallTSLintTask = projectConverter.removeTSLintFromWorkspace(); - } - - if (!options.skipFormat) { - await formatFiles(host); - } - - return async () => { - await eslintInitInstallTask(); - await rootConfigInstallTask(); - await projectConfigInstallTask(); - await uninstallTSLintTask(); - }; -} - -export const conversionSchematic = convertNxGenerator(conversionGenerator); - -/** - * Remove any @angular-eslint rules that were applied as a result of converting prior codelyzer - * rules, because they are only relevant for Angular projects. - */ -function removeCodelyzerRelatedRules(json: Linter.Config): Linter.Config { - for (const ruleName of Object.keys(json.rules)) { - if (ruleName.startsWith('@angular-eslint')) { - delete json.rules[ruleName]; - } - } - - if (json.plugins) { - json.plugins = json.plugins.filter( - (plugin) => !plugin.startsWith('@angular-eslint') - ); - } - return json; -} diff --git a/packages/nest/src/generators/convert-tslint-to-eslint/schema.json b/packages/nest/src/generators/convert-tslint-to-eslint/schema.json deleted file mode 100644 index 47d26cf142db2..0000000000000 --- a/packages/nest/src/generators/convert-tslint-to-eslint/schema.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "$id": "nest-convert-tslint-to-eslint", - "cli": "nx", - "title": "Convert a NestJS project from TSLint to ESLint", - "x-deprecated": "This generator is deprecated and will be removed in a future version of Nx. Migrate to ESLint.", - "description": "Convert a NestJS project from TSLint to ESLint. \n_NOTE: Does not work in `--dry-run` mode_.", - "examples": [ - { - "command": "nx g convert-tslint-to-eslint myapp", - "description": "Convert the NestJS project `myapp` from TSLint to ESLint" - } - ], - "type": "object", - "properties": { - "project": { - "description": "The name of the NestJS project to convert.", - "type": "string", - "$default": { - "$source": "argv", - "index": 0 - }, - "x-prompt": "Which NestJS project would you like to convert from TSLint to ESLint?" - }, - "ignoreExistingTslintConfig": { - "description": "If true we will not use existing TSLint config as a reference, we will just reset the project with the latest recommended ESLint config.", - "type": "boolean", - "default": false, - "x-prompt": "Would you like to ignore the existing TSLint config? Recommended if the TSLint config has not been altered much as it makes the new ESLint config cleaner." - }, - "removeTSLintIfNoMoreTSLintTargets": { - "description": "If this conversion leaves no more TSLint usage in the workspace, it will remove TSLint and related dependencies and configuration.", - "type": "boolean", - "default": true, - "x-prompt": "Would you like to remove TSLint and its related config if there are no TSLint projects remaining after this conversion?" - }, - "skipFormat": { - "type": "boolean", - "description": "Skip formatting files.", - "default": false, - "x-priority": "internal" - } - }, - "required": ["project"] -} diff --git a/packages/storybook/src/generators/configuration/lib/util-functions.ts b/packages/storybook/src/generators/configuration/lib/util-functions.ts index 16e752f68b22a..f4f2654e09ae8 100644 --- a/packages/storybook/src/generators/configuration/lib/util-functions.ts +++ b/packages/storybook/src/generators/configuration/lib/util-functions.ts @@ -361,27 +361,16 @@ export function configureTsSolutionConfig( } /** - * When adding storybook we need to inform TSLint or ESLint + * When adding storybook we need to inform ESLint * of the additional tsconfig.json file which will be the only tsconfig * which includes *.stories files. * - * For TSLint this is done via the builder config, for ESLint this is - * done within the eslint config file. + * This is done within the eslint config file. */ export function updateLintConfig(tree: Tree, schema: StorybookConfigureSchema) { const { name: projectName } = schema; - const { targets, root } = readProjectConfiguration(tree, projectName); - const tslintTargets = Object.values(targets ?? {}).filter( - (target) => target.executor === '@angular-devkit/build-angular:tslint' - ); - - tslintTargets.forEach((target) => { - target.options.tsConfig = dedupe([ - ...target.options.tsConfig, - joinPathFragments(root, './.storybook/tsconfig.json'), - ]); - }); + const { root } = readProjectConfiguration(tree, projectName); const eslintFile = findEslintFile(tree, root); if (!eslintFile) { diff --git a/packages/webpack/src/plugins/write-index-html-plugin.ts b/packages/webpack/src/plugins/write-index-html-plugin.ts index 971b534ccd522..9de5523f25a97 100644 --- a/packages/webpack/src/plugins/write-index-html-plugin.ts +++ b/packages/webpack/src/plugins/write-index-html-plugin.ts @@ -78,7 +78,6 @@ export class WriteIndexHtmlPlugin { for (const file of chunk.files) { files.push({ // The id is guaranteed to exist at this point in the compilation process - // tslint:disable-next-line: no-non-null-assertion id: chunk.id.toString(), name: chunk.name, file, diff --git a/packages/webpack/src/utils/webpack/plugins/postcss-cli-resources.ts b/packages/webpack/src/utils/webpack/plugins/postcss-cli-resources.ts index 5cff9e3dea8d9..66eb97ddb878b 100644 --- a/packages/webpack/src/utils/webpack/plugins/postcss-cli-resources.ts +++ b/packages/webpack/src/utils/webpack/plugins/postcss-cli-resources.ts @@ -161,7 +161,6 @@ export function PostcssCliResources(options: PostcssCliResourcesOptions) { const inputFile = decl.source && decl.source.input.file; const context = (inputFile && path.dirname(inputFile)) || loader.context; - // tslint:disable-next-line:no-conditional-assignment while ((match = urlRegex.exec(value))) { const originalUrl = match[1] || match[2] || match[3]; let processedUrl; diff --git a/packages/workspace/src/generators/move/lib/create-project-configuration-in-new-destination.spec.ts b/packages/workspace/src/generators/move/lib/create-project-configuration-in-new-destination.spec.ts index 43e1688a82d92..a8ea19cb42081 100644 --- a/packages/workspace/src/generators/move/lib/create-project-configuration-in-new-destination.spec.ts +++ b/packages/workspace/src/generators/move/lib/create-project-configuration-in-new-destination.spec.ts @@ -99,13 +99,13 @@ describe('moveProjectConfiguration', () => { }, }, lint: { - executor: '@angular-devkit/build-angular:tslint', + executor: '@nx/linter:eslint', options: { - tsConfig: [ - 'apps/my-source/tsconfig.app.json', - 'apps/my-source/tsconfig.spec.json', + lintFilePatterns: [ + '{projectRoot}/**/*.{ts,tsx,js,jsx}', + '{projectRoot}/**/*.{html,htm}', + '{projectRoot}/project.json', ], - exclude: ['**/node_modules/**', '!apps/my-source/**/*'], }, }, test: { @@ -140,10 +140,13 @@ describe('moveProjectConfiguration', () => { }, }, lint: { - executor: '@angular-devkit/build-angular:tslint', + executor: '@nx/linter:eslint', options: { - tsConfig: ['apps/my-source-e2e/tsconfig.e2e.json'], - exclude: ['**/node_modules/**', '!apps/my-source-e2e/**/*'], + lintFilePatterns: [ + '{projectRoot}/**/*.{ts,tsx,js,jsx}', + '{projectRoot}/**/*.{html,htm}', + '{projectRoot}/project.json', + ], }, }, }, diff --git a/packages/workspace/src/utils/testing-utils.ts b/packages/workspace/src/utils/testing-utils.ts index 2a65c737a042d..96916677b489d 100644 --- a/packages/workspace/src/utils/testing-utils.ts +++ b/packages/workspace/src/utils/testing-utils.ts @@ -1,86 +1,10 @@ -import type { Tree } from '@angular-devkit/schematics'; -import { - _test_addWorkspaceFile, - WorkspaceFormat, -} from '@angular-devkit/core/src/workspace/core'; -import type { NxJsonConfiguration } from '@nx/devkit'; +import { _test_addWorkspaceFile } from '@angular-devkit/core/src/workspace/core'; import { Architect, BuilderContext, Target } from '@angular-devkit/architect'; import { TestingArchitectHost } from '@angular-devkit/architect/testing'; import { json, JsonObject } from '@angular-devkit/core'; import { ScheduleOptions } from '@angular-devkit/architect/src/api'; import { LoggerApi, LogLevel } from '@angular-devkit/core/src/logger'; -/** - * @deprecated This will be removed in v17. Prefer writing Nx Generators with @nx/devkit. Use tree.read(filePath, 'utf-8') instead. - */ -export function getFileContent(tree: Tree, path: string): string { - const fileEntry = tree.get(path); - - if (!fileEntry) { - throw new Error(`The file (${path}) does not exist.`); - } - - return fileEntry.content.toString(); -} - -/** - * @deprecated This will be removed in v17. Prefer writing Nx Generators with @nx/devkit. Tests for Generators can use 'createTreeWithEmptyWorkspace()' from @nx/devkit/testing. - */ -export function createEmptyWorkspace(tree: Tree): Tree { - _test_addWorkspaceFile('workspace.json', WorkspaceFormat.JSON); - - tree.create( - '/workspace.json', - JSON.stringify({ version: 1, projects: {}, newProjectRoot: '' }) - ); - tree.create( - '/package.json', - JSON.stringify({ - name: 'test-name', - dependencies: {}, - devDependencies: {}, - }) - ); - tree.create( - '/nx.json', - JSON.stringify({ - npmScope: 'proj', - projects: {}, - affected: { - defaultBase: 'main', - }, - tasksRunnerOptions: { - default: { - runner: 'nx/tasks-runners/default', - options: { - cacheableOperations: ['build', 'lint', 'test', 'e2e'], - }, - }, - }, - }) - ); - tree.create( - '/tsconfig.base.json', - JSON.stringify({ compilerOptions: { paths: {} } }) - ); - tree.create( - '/tslint.json', - JSON.stringify({ - rules: { - 'nx-enforce-module-boundaries': [ - true, - { - npmScope: '<%= npmScope %>', - lazyLoad: [], - allow: [], - }, - ], - }, - }) - ); - return tree; -} - class NoopLogger implements LoggerApi { private _log = ''; diff --git a/packages/workspace/testing.ts b/packages/workspace/testing.ts index cd585f1ddaeb3..2c8111b732cf5 100644 --- a/packages/workspace/testing.ts +++ b/packages/workspace/testing.ts @@ -1,5 +1 @@ -export { - createEmptyWorkspace, - getFileContent, - MockBuilderContext, -} from './src/utils/testing-utils'; +export { MockBuilderContext } from './src/utils/testing-utils'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f2a462b40848..882bea9193cc2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -908,9 +908,6 @@ devDependencies: tsconfig-paths-webpack-plugin: specifier: 4.0.0 version: 4.0.0 - tslint-to-eslint-config: - specifier: ^2.14.0 - version: 2.14.0(eslint@8.46.0) typedoc: specifier: 0.24.8 version: 0.24.8(typescript@5.1.3) @@ -12977,11 +12974,6 @@ packages: node-gyp-build: 4.5.0 dev: true - /builtin-modules@1.1.1: - resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==} - engines: {node: '>=0.10.0'} - dev: true - /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -13470,12 +13462,6 @@ packages: periscopic: 3.1.0 dev: true - /coffeescript@1.12.7: - resolution: {integrity: sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==} - engines: {node: '>=0.8.0'} - hasBin: true - dev: true - /collect-v8-coverage@1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} dev: true @@ -13541,11 +13527,6 @@ packages: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} dev: true - /commander@10.0.0: - resolution: {integrity: sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==} - engines: {node: '>=14'} - dev: true - /commander@11.0.0: resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} engines: {node: '>=16'} @@ -14071,13 +14052,6 @@ packages: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} dev: true - /cson-parser@4.0.9: - resolution: {integrity: sha512-I79SAcCYquWnEfXYj8hBqOOWKj6eH6zX1hhX3yqmS4K3bYp7jME3UFpHPzu3rUew0oyfc0s8T6IlWGXRAheHag==} - engines: {node: '>=10.13'} - dependencies: - coffeescript: 1.12.7 - dev: true - /css-blank-pseudo@3.0.3(postcss@8.4.19): resolution: {integrity: sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==} engines: {node: ^12 || ^14 || >=16} @@ -15552,15 +15526,6 @@ packages: eslint: 8.46.0 dev: true - /eslint-config-prettier@8.6.0(eslint@8.46.0): - resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - dependencies: - eslint: 8.46.0 - dev: true - /eslint-import-resolver-node@0.3.6: resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} dependencies: @@ -26576,63 +26541,11 @@ packages: /tslib@2.6.1: resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} - /tslint-to-eslint-config@2.14.0(eslint@8.46.0): - resolution: {integrity: sha512-rQVB4U9/bkQbvRsoz9XyKky2BVaeCIW1NXT4P/dUamvtRDmmPrBpOt6OAhCj+Wcs0IEcsb2eV6/Ojy+VFYX+DQ==} - engines: {node: '>=14.0.0'} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 10.0.0 - cson-parser: 4.0.9 - eslint-config-prettier: 8.6.0(eslint@8.46.0) - glob: 8.1.0 - json5: 2.2.3 - lodash: 4.17.21 - minimatch: 5.1.6 - tslint: 6.1.3(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - eslint - dev: true - - /tslint@6.1.3(typescript@4.9.5): - resolution: {integrity: sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==} - engines: {node: '>=4.8.0'} - deprecated: TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information. - hasBin: true - peerDependencies: - typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev' - dependencies: - '@babel/code-frame': 7.22.5 - builtin-modules: 1.1.1 - chalk: 2.4.2 - commander: 2.20.3 - diff: 4.0.2 - glob: 7.1.4 - js-yaml: 3.14.1 - minimatch: 3.0.5 - mkdirp: 0.5.6 - resolve: 1.22.2 - semver: 5.7.1 - tslib: 1.14.1 - tsutils: 2.29.0(typescript@4.9.5) - typescript: 4.9.5 - dev: true - /tsscmp@1.0.6: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} engines: {node: '>=0.6.x'} dev: true - /tsutils@2.29.0(typescript@4.9.5): - resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} - peerDependencies: - typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' - dependencies: - tslib: 1.14.1 - typescript: 4.9.5 - dev: true - /tsutils@3.21.0(typescript@5.1.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'}