From 747e3ab1930dcc502fa96bd7b9e6398c29d9bc3a 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/packages.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 | 1269 ----------------- .../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 - packages/nx/src/native/index.d.ts | 1 - .../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 | 101 -- 58 files changed, 18 insertions(+), 6884 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 bbbc9643973963..8db3ded60cb232 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -6138,14 +6138,6 @@ "isExternal": false, "disableCollapsible": false }, - { - "id": "convert-tslint-to-eslint", - "path": "/packages/angular/generators/convert-tslint-to-eslint", - "name": "convert-tslint-to-eslint", - "children": [], - "isExternal": false, - "disableCollapsible": false - }, { "id": "directive", "path": "/packages/angular/generators/directive", @@ -7192,14 +7184,6 @@ "isExternal": false, "disableCollapsible": false }, - { - "id": "convert-tslint-to-eslint", - "path": "/packages/nest/generators/convert-tslint-to-eslint", - "name": "convert-tslint-to-eslint", - "children": [], - "isExternal": false, - "disableCollapsible": false - }, { "id": "init", "path": "/packages/nest/generators/init", diff --git a/docs/generated/manifests/packages.json b/docs/generated/manifests/packages.json index c0a17ec7bc62f7..21897ab62ad368 100644 --- a/docs/generated/manifests/packages.json +++ b/docs/generated/manifests/packages.json @@ -168,15 +168,6 @@ "path": "/packages/angular/generators/component-test", "type": "generator" }, - "/packages/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": "/packages/angular/generators/convert-tslint-to-eslint", - "type": "generator" - }, "/packages/angular/generators/directive": { "description": "Generate an Angular directive.", "file": "generated/packages/angular/generators/directive.json", @@ -1162,15 +1153,6 @@ "path": "/packages/nest/generators/application", "type": "generator" }, - "/packages/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": "/packages/nest/generators/convert-tslint-to-eslint", - "type": "generator" - }, "/packages/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 b7fe8d96eaa257..77984b26b4c708 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", @@ -1144,15 +1135,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 cd5f0ee01d6908..00000000000000 --- 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 5b576883e4925a..c1cac768ee6f3a 100644 --- a/docs/generated/packages/linter/documents/overview.md +++ b/docs/generated/packages/linter/documents/overview.md @@ -29,7 +29,6 @@ nx lint my-lib ## Utils - [convert-to-flat-config](/packages/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](/packages/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 a9459ede5db587..00000000000000 --- 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 e48b86656430ad..72bdb4ad83d05d 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 200fcfbdeacfd1..3795a0f55d1b39 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 5b576883e4925a..c1cac768ee6f3a 100644 --- a/docs/shared/packages/linter/linter-plugin.md +++ b/docs/shared/packages/linter/linter-plugin.md @@ -29,7 +29,6 @@ nx lint my-lib ## Utils - [convert-to-flat-config](/packages/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](/packages/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 d52e3eae0b166f..7abc86cd9e3966 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -324,7 +324,6 @@ - [component-cypress-spec](/packages/angular/generators/component-cypress-spec) - [component-story](/packages/angular/generators/component-story) - [component-test](/packages/angular/generators/component-test) - - [convert-tslint-to-eslint](/packages/angular/generators/convert-tslint-to-eslint) - [directive](/packages/angular/generators/directive) - [init](/packages/angular/generators/init) - [library](/packages/angular/generators/library) @@ -451,7 +450,6 @@ - [Overview](/packages/nest/documents/overview) - [generators](/packages/nest/generators) - [application](/packages/nest/generators/application) - - [convert-tslint-to-eslint](/packages/nest/generators/convert-tslint-to-eslint) - [init](/packages/nest/generators/init) - [library](/packages/nest/generators/library) - [class](/packages/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 811de2229340ab..91f4e89fe38d10 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 b772f6c6ce65e1..8c955b520c0c7e 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 1f421878a7b996..57e3133a25d061 100644 --- a/package.json +++ b/package.json @@ -276,7 +276,6 @@ "ts-node": "10.9.1", "tsconfig-paths": "^4.1.2", "tsconfig-paths-webpack-plugin": "4.0.0", - "tslint-to-eslint-config": "^2.13.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 9102c2499f10c4..1f4ffbe4ea583b 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 f8a41e3493b42a..b86fb43f9aa249 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 d6ec3c79615268..00000000000000 --- a/packages/angular/src/generators/convert-tslint-to-eslint/__snapshots__/convert-tslint-to-eslint.spec.ts.snap +++ /dev/null @@ -1,1269 +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": [ - { - "files": [ - "*.json", - ], - "parser": "jsonc-eslint-parser", - "rules": {}, - }, - { - "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": [ - { - "files": [ - "*.json", - ], - "parser": "jsonc-eslint-parser", - "rules": {}, - }, - { - "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": [ - { - "files": [ - "*.json", - ], - "parser": "jsonc-eslint-parser", - "rules": {}, - }, - { - "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 83a7ea48db5f96..00000000000000 --- 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 cf2c2412c76ef9..00000000000000 --- 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 c9d3ea5858acdc..00000000000000 --- 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 7ec4017afe4f9f..00000000000000 --- 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 1caea7bd46963d..4f64ff559cc319 100644 --- a/packages/angular/src/generators/library/library.spec.ts +++ b/packages/angular/src/generators/library/library.spec.ts @@ -1123,7 +1123,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 7b33d4084f832e..b24b600a846f13 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 ec799c83e7c3da..00000000000000 --- 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 4cbcbc7b57a813..00000000000000 --- 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 652143855765f8..00000000000000 --- 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 8aada591fde1fd..00000000000000 --- 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 dc7b9c933ebe4a..7d5446b94dbad2 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 230846a81b6363..5f72beba39321d 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 b87b1dd21c38ef..4abd07a019ae00 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 dc8c31e7133369..46439d120412c6 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 fe353a6c4459e8..1229ee6600ec24 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 e4c2d05a7de34e..00000000000000 --- 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 f8f5916a8c580c..00000000000000 --- 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 227027e60de12b..00000000000000 --- 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 3b144b91efe9c6..00000000000000 --- 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 20c38199c7c9ea..00000000000000 --- 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 983a1bc11118c4..00000000000000 --- 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 2c4123c381aaa6..00000000000000 --- 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 cc95094649634a..00000000000000 --- 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 af975cbf180ffd..00000000000000 --- 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 4ca01b619609a4..00000000000000 --- 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 6b1b4492c31d63..00000000000000 --- 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 7288b7a8880a8d..00000000000000 --- 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 da83374b056a30..29c8604e99b776 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.13.0'; export const typescriptESLintVersion = '^5.60.1'; diff --git a/packages/nest/generators.json b/packages/nest/generators.json index 7b3a61cc5a45a0..86d60bc7bc7433 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 e19a92acc52f53..450368f16d5491 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 e53ba96cdbda8a..00000000000000 --- 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 04ec87fc49452c..00000000000000 --- 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 b2c3e498daa313..00000000000000 --- 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 47d26cf142db2b..00000000000000 --- 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/nx/src/native/index.d.ts b/packages/nx/src/native/index.d.ts index 5a4c28fd591eeb..aa1c89ed7e4b55 100644 --- a/packages/nx/src/native/index.d.ts +++ b/packages/nx/src/native/index.d.ts @@ -1,4 +1,3 @@ -/* tslint:disable */ /* eslint-disable */ /* auto-generated by NAPI-RS */ diff --git a/packages/storybook/src/generators/configuration/lib/util-functions.ts b/packages/storybook/src/generators/configuration/lib/util-functions.ts index 0983b52851fc7f..4384aea545b703 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 971b534ccd5223..9de5523f25a974 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 5cff9e3dea8d96..66eb97ddb878bf 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 43e1688a82d923..a8ea19cb42081a 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 2a65c737a042d1..96916677b489d4 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 cd585f1ddaeb33..2c8111b732cf5e 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 a59f59dee04610..bc5038800e424a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -904,9 +904,6 @@ devDependencies: tsconfig-paths-webpack-plugin: specifier: 4.0.0 version: 4.0.0 - tslint-to-eslint-config: - specifier: ^2.13.0 - version: 2.13.3(eslint@8.46.0) typedoc: specifier: 0.24.8 version: 0.24.8(typescript@5.1.3) @@ -12593,11 +12590,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'} @@ -13103,12 +13095,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 @@ -13207,11 +13193,6 @@ packages: engines: {node: '>= 12'} dev: true - /commander@9.4.0: - resolution: {integrity: sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==} - engines: {node: ^12.20.0 || >=14} - dev: true - /common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} dev: true @@ -13748,13 +13729,6 @@ packages: engines: {node: '>=8'} 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} @@ -16766,17 +16740,6 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 - /glob@8.0.3: - resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==} - engines: {node: '>=12'} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.0 - once: 1.4.0 - dev: true - /glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} @@ -18878,12 +18841,6 @@ packages: minimist: 1.2.8 dev: true - /json5@2.2.1: - resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} - engines: {node: '>=6'} - hasBin: true - dev: true - /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -26870,63 +26827,11 @@ packages: /tslib@2.6.1: resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} - /tslint-to-eslint-config@2.13.3(eslint@8.46.0): - resolution: {integrity: sha512-rIzyHJlClLuvtAfJijl0seqrx20OlEOz6CnMYG6j4wupy7IP4oPSgqz3J72d7MCUIiUKqM9bMNrlvGWyuhHEVw==} - engines: {node: '>=14.0.0'} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 9.4.0 - cson-parser: 4.0.9 - eslint-config-prettier: 8.5.0(eslint@8.46.0) - glob: 8.0.3 - json5: 2.2.1 - lodash: 4.17.21 - minimatch: 5.1.0 - tslint: 6.1.3(typescript@4.8.2) - typescript: 4.8.2 - transitivePeerDependencies: - - eslint - dev: true - - /tslint@6.1.3(typescript@4.8.2): - 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.8.2) - typescript: 4.8.2 - dev: true - /tsscmp@1.0.6: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} engines: {node: '>=0.6.x'} dev: true - /tsutils@2.29.0(typescript@4.8.2): - 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.8.2 - dev: true - /tsutils@3.21.0(typescript@5.1.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -27075,12 +26980,6 @@ packages: typescript: 5.1.3 dev: true - /typescript@4.8.2: - resolution: {integrity: sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - /typescript@4.9.4: resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} engines: {node: '>=4.2.0'}