From b7339b302a4ee1e5e815a45620504f571e94ef85 Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Sat, 11 Feb 2023 21:37:46 -0500 Subject: [PATCH] feat(core): move tsconfig.base.json to @nrwl/js:init feat(core): move tsconfig.base.json to @nrwl/js:init --- docs/generated/devkit/nrwl_devkit.md | 6 +- docs/generated/manifests/packages.json | 2 +- docs/generated/packages-metadata.json | 2 +- .../packages/devkit/documents/index.md | 6 +- .../packages/expo/generators/init.json | 9 +- .../packages/js/generators/init.json | 16 +- .../packages/next/generators/application.json | 6 - .../packages/storybook/generators/init.json | 5 + .../packages/web/generators/init.json | 3 +- e2e/expo/project.json | 2 +- e2e/nx-misc/src/misc.test.ts | 2 +- .../src/create-nx-workspace-npm.test.ts | 239 ++++++++++++++++++ .../src/create-nx-workspace.test.ts | 1 + packages/angular/package.json | 1 + .../angular-v14/lib/add-unit-test-runner.ts | 3 + .../lib/convert-to-standalone-app.ts | 3 +- .../angular-v14/lib/create-files.ts | 1 - .../angular-v14/lib/update-component-spec.ts | 10 +- .../angular-v14/lib/update-config-files.ts | 2 +- .../angular-v14/lib/update-e2e-project.ts | 2 +- .../src/generators/application/application.ts | 3 +- .../lib/convert-to-standalone-app.ts | 3 +- .../application/lib/create-files.ts | 2 +- .../application/lib/root-router-config.ts | 10 +- .../lib/update-app-component-template.ts | 13 +- .../application/lib/update-component-spec.ts | 14 +- .../application/lib/update-config-files.ts | 2 +- .../application/lib/update-e2e-project.ts | 2 +- .../lib/update-nx-component-template.ts | 19 +- .../change-storybook-targets.ts | 2 +- .../generators/component/lib/entry-point.ts | 2 +- .../lib/check-name-matches.ts | 2 +- .../lib/check-shared-npm-packages.ts | 2 +- .../lib/is-host-remote-config.ts | 4 +- .../lib/parse-ast-webpack-config.ts | 2 +- .../src/generators/init/angular-v14/init.ts | 19 +- packages/angular/src/generators/init/init.ts | 25 +- .../lib/generate-karma-project-files.ts | 2 +- .../lib/add-path-mapping.ts | 2 +- .../generators/library/lib/add-children.ts | 10 +- .../add-lazy-loaded-router-configuration.ts | 10 +- .../library/lib/add-load-children.ts | 10 +- .../library/lib/add-router-configuration.ts | 10 +- .../generators/library/lib/update-project.ts | 2 +- .../generators/library/lib/update-tsconfig.ts | 31 +-- .../angular/src/generators/library/library.ts | 13 +- .../builders/angular-devkit-karma.migrator.ts | 2 +- .../angular-devkit-ng-packagr.migrator.ts | 2 +- .../ng-add/migrators/projects/app.migrator.ts | 2 +- .../ng-add/migrators/projects/e2e.migrator.ts | 5 +- .../generators/ng-add/utilities/workspace.ts | 2 +- .../setup-mf/lib/add-remote-to-host.ts | 11 +- .../setup-ssr/lib/update-app-module.ts | 2 +- .../generators/stories/stories-lib.spec.ts | 2 +- .../lib/generate-storybook-configuration.ts | 2 +- .../src/generators/utils/create-ts-config.ts | 4 +- .../utils/storybook-ast/module-info.ts | 2 +- .../web-worker/lib/update-tsconfig.ts | 2 +- .../angular/src/utils/nx-devkit/ast-utils.ts | 144 +++++++---- .../src/utils/nx-devkit/route-utils.ts | 17 +- packages/cypress/package.json | 1 + .../cypress-project/cypress-project.ts | 12 +- .../migrate-to-cypress-11/conversion.util.ts | 19 +- .../migrate-to-cypress-11.ts | 1 - packages/detox/package.json | 1 + .../application/lib/create-files.ts | 2 +- .../devkit/src/utils/package-json.spec.ts | 12 +- packages/devkit/src/utils/package-json.ts | 7 +- packages/expo/package.json | 1 + packages/expo/src/generators/init/init.ts | 10 +- packages/expo/src/generators/init/schema.d.ts | 1 + packages/expo/src/generators/init/schema.json | 9 +- .../library/lib/normalize-options.ts | 4 +- .../expo/src/generators/library/library.ts | 28 +- packages/jest/package.json | 1 + .../jest/src/generators/init/init.spec.ts | 46 ++-- packages/jest/src/generators/init/init.ts | 19 +- .../generators/jest-project/jest-project.ts | 11 +- packages/jest/src/utils/config/functions.ts | 67 +++-- packages/js/generators.json | 4 +- packages/js/package.json | 1 - .../convert-to-swc/convert-to-swc.spec.ts | 4 +- .../generators/init/files}/tsconfig.base.json | 0 packages/js/src/generators/init/init.ts | 33 ++- packages/js/src/generators/init/schema.d.ts | 4 + packages/js/src/generators/init/schema.json | 16 +- packages/js/src/generators/library/library.ts | 54 ++-- packages/js/src/index.ts | 5 +- .../update-13-8-5/update-swcrc.spec.ts | 4 +- .../src/utils/compiler-helper-dependency.ts | 2 +- packages/js/src/utils/schema.d.ts | 2 +- .../src/utils/typescript}/create-ts-config.ts | 0 .../js/src/utils/typescript/run-type-check.ts | 2 +- packages/js/src/utils/typescript/ts-config.ts | 97 +++++++ packages/js/src/utils/versions.ts | 1 + packages/linter/package.json | 1 + .../workspace-rules-project.ts | 4 +- .../update-13-3-0/eslint-8-updates.ts | 2 +- .../library/lib/add-exports-to-barrel.ts | 10 +- .../nest/src/generators/library/library.ts | 8 +- .../generators/application/lib/add-linting.ts | 5 +- .../lib/create-application-files.ts | 5 +- .../application/lib/normalize-options.ts | 2 +- .../src/generators/application/schema.d.ts | 1 - .../src/generators/application/schema.json | 6 - packages/next/src/generators/init/init.ts | 10 +- .../next/src/generators/library/library.ts | 2 +- packages/next/src/utils/styles.ts | 2 +- .../src/generators/application/application.ts | 14 +- packages/node/src/generators/init/init.ts | 21 +- .../node/src/generators/library/library.ts | 12 +- .../update-package-to-tsc.spec.ts | 1 - .../src/generators/e2e-project/e2e.ts | 4 +- .../src/generators/executor/executor.spec.ts | 4 +- .../generators/generator/generator.spec.ts | 4 +- .../nx-plugin/src/generators/plugin/plugin.ts | 4 +- .../typescript-import-locator.ts | 2 +- packages/nx/src/utils/typescript.ts | 11 +- .../lib/create-application-files.ts | 2 +- .../react-native/src/generators/init/init.ts | 8 +- .../src/generators/library/library.ts | 44 +--- .../src/generators/stories/stories.ts | 2 +- .../storybook-configuration/configuration.ts | 2 +- .../react-native/src/utils/add-linting.ts | 5 +- packages/react/package.json | 1 + .../src/generators/application/application.ts | 11 +- .../generators/application/lib/add-cypress.ts | 3 +- .../generators/application/lib/add-jest.ts | 9 +- .../generators/application/lib/add-routing.ts | 10 +- .../lib/create-application-files.ts | 4 +- .../component-cypress-spec.ts | 20 +- .../component-story/component-story.ts | 11 +- .../component-test/component-test.ts | 13 +- .../src/generators/component/component.ts | 9 +- .../cypress-component-configuration.ts | 2 +- .../lib/add-files.ts | 14 +- packages/react/src/generators/hook/hook.ts | 9 +- packages/react/src/generators/init/init.ts | 11 +- .../library/lib/add-rollup-build-target.ts | 2 +- .../generators/library/lib/create-files.ts | 4 +- .../library/lib/update-app-routes.ts | 13 +- .../library/lib/update-base-tsconfig.ts | 32 --- .../src/generators/library/library.spec.ts | 3 +- .../react/src/generators/library/library.ts | 19 +- packages/react/src/generators/redux/redux.ts | 25 +- .../remote/lib/update-host-with-remote.ts | 19 +- .../src/generators/setup-ssr/setup-ssr.ts | 15 +- .../setup-tailwind/setup-tailwind.ts | 1 - .../react/src/generators/stories/stories.ts | 11 +- .../storybook-configuration/configuration.ts | 4 +- .../react/src/module-federation/ast-utils.ts | 20 +- packages/react/src/utils/ast-utils.ts | 168 ++++++++---- packages/react/src/utils/component-props.ts | 20 +- packages/react/src/utils/create-ts-config.ts | 2 +- packages/storybook/package.json | 1 + .../generators/configuration/configuration.ts | 3 +- .../src/generators/init/init.spec.ts | 8 +- .../storybook/src/generators/init/init.ts | 7 +- .../storybook/src/generators/init/schema.d.ts | 1 + .../storybook/src/generators/init/schema.json | 5 + .../src/generators/application/application.ts | 8 +- packages/web/src/generators/init/init.ts | 12 +- packages/web/src/generators/init/schema.json | 3 +- .../plugins/generate-package-json-plugin.ts | 4 +- packages/webpack/src/utils/with-nx.ts | 2 +- packages/workspace/index.ts | 2 +- packages/workspace/migrations.json | 2 +- .../library/files/root/tsconfig.base.json | 20 ++ .../src/generators/library/library.ts | 31 ++- .../src/generators/library/schema.d.ts | 2 +- .../src/generators/move/lib/update-imports.ts | 33 ++- .../remove/lib/update-jest-config.ts | 19 +- .../generators/remove/lib/update-tsconfig.ts | 2 +- .../src/generators/utils/insert-import.ts | 22 +- .../src/generators/utils/insert-statement.ts | 12 +- packages/workspace/src/utilities/ast-utils.ts | 51 ++-- .../src/utilities/buildable-libs-utils.ts | 16 +- packages/workspace/src/utilities/ts-config.ts | 54 ++++ .../workspace/src/utilities/typescript.ts | 53 +--- .../src/utilities/typescript/compilation.ts | 28 +- .../utilities/typescript/get-source-nodes.ts | 2 +- packages/workspace/src/utils/ast-utils.ts | 62 +++-- packages/workspace/src/utils/rules/to-js.ts | 8 +- scripts/depcheck/missing.ts | 1 + 184 files changed, 1583 insertions(+), 791 deletions(-) create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm.test.ts rename packages/{workspace/src/generators/new/files-integrated-repo => js/src/generators/init/files}/tsconfig.base.json (100%) create mode 100644 packages/js/src/generators/init/schema.d.ts rename packages/{workspace/src/utils => js/src/utils/typescript}/create-ts-config.ts (100%) create mode 100644 packages/js/src/utils/typescript/ts-config.ts delete mode 100644 packages/react/src/generators/library/lib/update-base-tsconfig.ts create mode 100644 packages/workspace/src/generators/library/files/root/tsconfig.base.json create mode 100644 packages/workspace/src/utilities/ts-config.ts diff --git a/docs/generated/devkit/nrwl_devkit.md b/docs/generated/devkit/nrwl_devkit.md index e22916605a606..eab5a0242e15a 100644 --- a/docs/generated/devkit/nrwl_devkit.md +++ b/docs/generated/devkit/nrwl_devkit.md @@ -1190,14 +1190,14 @@ Detect workspace scope from the package.json name ### ensurePackage -▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `Promise`<`void`\> +▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `void` Ensure that dependencies and devDependencies from package.json are installed at the required versions. For example: ```typescript -ensurePackage(tree, {}, { '@nrwl/jest': nxVersion }); +ensurePackage(tree, '@nrwl/jest', nxVersion); ``` This will check that @nrwl/jest@ exists in devDependencies. @@ -1217,7 +1217,7 @@ When running with --dryRun, the function will throw when dependencies are missin #### Returns -`Promise`<`void`\> +`void` --- diff --git a/docs/generated/manifests/packages.json b/docs/generated/manifests/packages.json index 23090c3230690..ca0cf6abfe9d4 100644 --- a/docs/generated/manifests/packages.json +++ b/docs/generated/manifests/packages.json @@ -1088,7 +1088,7 @@ "type": "generator" }, "/packages/js/generators/init": { - "description": "Init placeholder.", + "description": "Initialize a TS/JS workspace.", "file": "generated/packages/js/generators/init.json", "hidden": true, "name": "init", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index eaa4c4da742c1..93138e912ebb9 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -1070,7 +1070,7 @@ "type": "generator" }, { - "description": "Init placeholder.", + "description": "Initialize a TS/JS workspace.", "file": "generated/packages/js/generators/init.json", "hidden": true, "name": "init", diff --git a/docs/generated/packages/devkit/documents/index.md b/docs/generated/packages/devkit/documents/index.md index e22916605a606..eab5a0242e15a 100644 --- a/docs/generated/packages/devkit/documents/index.md +++ b/docs/generated/packages/devkit/documents/index.md @@ -1190,14 +1190,14 @@ Detect workspace scope from the package.json name ### ensurePackage -▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `Promise`<`void`\> +▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `void` Ensure that dependencies and devDependencies from package.json are installed at the required versions. For example: ```typescript -ensurePackage(tree, {}, { '@nrwl/jest': nxVersion }); +ensurePackage(tree, '@nrwl/jest', nxVersion); ``` This will check that @nrwl/jest@ exists in devDependencies. @@ -1217,7 +1217,7 @@ When running with --dryRun, the function will throw when dependencies are missin #### Returns -`Promise`<`void`\> +`void` --- diff --git a/docs/generated/packages/expo/generators/init.json b/docs/generated/packages/expo/generators/init.json index 2adc4901b2f9c..2f138ef5e031a 100644 --- a/docs/generated/packages/expo/generators/init.json +++ b/docs/generated/packages/expo/generators/init.json @@ -28,8 +28,13 @@ }, "skipPackageJson": { "type": "boolean", - "description": "Do not add dependencies to `package.json`.", - "default": false + "default": false, + "description": "Do not add dependencies to `package.json`." + }, + "js": { + "type": "boolean", + "default": false, + "description": "Use JavaScript instead of TypeScript" } }, "required": [], diff --git a/docs/generated/packages/js/generators/init.json b/docs/generated/packages/js/generators/init.json index 914e2da79d739..4de61e9142090 100644 --- a/docs/generated/packages/js/generators/init.json +++ b/docs/generated/packages/js/generators/init.json @@ -7,11 +7,25 @@ "cli": "nx", "title": "Init nrwl/js", "description": "Init generator placeholder for nrwl/js.", + "properties": { + "js": { + "type": "boolean", + "default": false, + "description": "Use JavaScript instead of TypeScript" + }, + "skipFormat": { + "type": "boolean", + "aliases": ["skip-format"], + "description": "Skip formatting files.", + "default": true, + "x-priority": "internal" + } + }, "presets": [] }, "aliases": ["lib"], "x-type": "init", - "description": "Init placeholder.", + "description": "Initialize a TS/JS workspace.", "hidden": true, "implementation": "/packages/js/src/generators/init/init#initGenerator.ts", "path": "/packages/js/src/generators/init/schema.json", diff --git a/docs/generated/packages/next/generators/application.json b/docs/generated/packages/next/generators/application.json index 1b3a854ed9645..68c5481d6a8bd 100644 --- a/docs/generated/packages/next/generators/application.json +++ b/docs/generated/packages/next/generators/application.json @@ -76,12 +76,6 @@ "default": false, "x-priority": "internal" }, - "skipWorkspaceJson": { - "description": "Skip updating `workspace.json` with default options based on values provided to this app (e.g. `babel`, `style`).", - "type": "boolean", - "default": false, - "x-priority": "internal" - }, "unitTestRunner": { "type": "string", "enum": ["jest", "none"], diff --git a/docs/generated/packages/storybook/generators/init.json b/docs/generated/packages/storybook/generators/init.json index fdc4028ba030d..be6485b90851f 100644 --- a/docs/generated/packages/storybook/generators/init.json +++ b/docs/generated/packages/storybook/generators/init.json @@ -52,6 +52,11 @@ "type": "boolean", "default": false, "hidden": true + }, + "js": { + "type": "boolean", + "description": "Generate JavaScript story files rather than TypeScript story files.", + "default": false } }, "presets": [] diff --git a/docs/generated/packages/web/generators/init.json b/docs/generated/packages/web/generators/init.json index 49f1ae99026f3..d4903a3218836 100644 --- a/docs/generated/packages/web/generators/init.json +++ b/docs/generated/packages/web/generators/init.json @@ -35,7 +35,8 @@ "skipPackageJson": { "description": "Do not add dependencies to `package.json`.", "type": "boolean", - "default": false + "default": false, + "x-priority": "internal" }, "skipBabelConfig": { "description": "Do not generate a root babel.config.json (if babel is not needed).", diff --git a/e2e/expo/project.json b/e2e/expo/project.json index 9e84a4fc0cb1e..f660ac0090db7 100644 --- a/e2e/expo/project.json +++ b/e2e/expo/project.json @@ -4,7 +4,7 @@ "sourceRoot": "e2e/expo", "projectType": "application", "targets": { - "e2e": {}, + "e2e-macos": {}, "run-e2e-tests": {} }, "implicitDependencies": ["expo"] diff --git a/e2e/nx-misc/src/misc.test.ts b/e2e/nx-misc/src/misc.test.ts index 84bb36be3b9a4..22e2f3f36b810 100644 --- a/e2e/nx-misc/src/misc.test.ts +++ b/e2e/nx-misc/src/misc.test.ts @@ -22,7 +22,7 @@ describe('Nx Commands', () => { afterAll(() => cleanupProject()); describe('show', () => { - it('ttt should show the list of projects', () => { + it('should show the list of projects', () => { const app1 = uniq('myapp'); const app2 = uniq('myapp'); expect(runCLI('show projects')).toEqual(''); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm.test.ts new file mode 100644 index 0000000000000..3421724ba5290 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm.test.ts @@ -0,0 +1,239 @@ +import { + checkFilesExist, + cleanupProject, + packageInstall, + readJson, + runCLI, + runCreateWorkspace, + uniq, +} from '@nrwl/e2e/utils'; + +describe('create-nx-workspace --preset=npm', () => { + let wsName; + + beforeEach(() => { + wsName = uniq('npm'); + runCreateWorkspace(wsName, { + preset: 'npm', + }); + }); + + afterEach(() => cleanupProject()); + + describe('angular project', () => { + beforeEach(() => { + packageInstall('@nrwl/angular', wsName); + // install peers deps + const angularPackages = [ + '@angular-devkit/core', + '@angular-devkit/schematics', + '@schematics/angular', + ]; + packageInstall(angularPackages.join(` `), wsName, 'latest'); + }); + + it('should add angular application', () => { + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/angular:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }, 1_000_000); + + it('should add angular library', () => { + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nrwl/angular:lib ${libName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }, 1_000_000); + }); + + it('should add workspace library', () => { + packageInstall('@nrwl/workspace', wsName); + + const libName = uniq('lib'); + + expect(() => + runCLI(`generate @nrwl/workspace:library ${libName} --no-interactive`) + ).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add js library', () => { + packageInstall('@nrwl/js', wsName); + + const libName = uniq('lib'); + + expect(() => + runCLI(`generate @nrwl/js:library ${libName} --no-interactive`) + ).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add web application', () => { + packageInstall('@nrwl/web', wsName); + + const appName = uniq('my-app'); + + expect(() => + runCLI(`generate @nrwl/web:app ${appName} --no-interactive`) + ).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add react application', () => { + packageInstall('@nrwl/react', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/react:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add react library', () => { + packageInstall('@nrwl/react', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nrwl/react:lib ${libName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add next application', () => { + packageInstall('@nrwl/next', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/next:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add next library', () => { + packageInstall('@nrwl/next', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nrwl/next:lib ${libName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add react-native application', () => { + packageInstall('@nrwl/react-native', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/react-native:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add react-native library', () => { + packageInstall('@nrwl/react-native', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nrwl/react-native:lib ${libName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add node application', () => { + packageInstall('@nrwl/node', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/node:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add node library', () => { + packageInstall('@nrwl/node', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nrwl/node:lib ${libName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add nest application', () => { + packageInstall('@nrwl/nest', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/nest:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add nest library', () => { + packageInstall('@nrwl/nest', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nrwl/nest:lib ${libName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [libName]: [`packages/${libName}/src/index.ts`], + }); + }); + + it('should add express application', () => { + packageInstall('@nrwl/express', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nrwl/express:app ${appName} --no-interactive`); + }).not.toThrowError(); + checkFilesExist('tsconfig.base.json'); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace.test.ts b/e2e/workspace-create/src/create-nx-workspace.test.ts index dae9faa0ceac1..df0c805f00c62 100644 --- a/e2e/workspace-create/src/create-nx-workspace.test.ts +++ b/e2e/workspace-create/src/create-nx-workspace.test.ts @@ -129,6 +129,7 @@ describe('create-nx-workspace', () => { }); expectNoAngularDevkit(); + checkFilesDoNotExist('tsconfig.base.json'); }); it('should be able to create an empty workspace with ts/js capabilities', () => { diff --git a/packages/angular/package.json b/packages/angular/package.json index cd51b4693ab62..11bb92bf7965a 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -39,6 +39,7 @@ "@nrwl/cypress": "file:../cypress", "@nrwl/devkit": "file:../devkit", "@nrwl/jest": "file:../jest", + "@nrwl/js": "file:../js", "@nrwl/linter": "file:../linter", "@nrwl/webpack": "file:../webpack", "@nrwl/workspace": "file:../workspace", diff --git a/packages/angular/src/generators/application/angular-v14/lib/add-unit-test-runner.ts b/packages/angular/src/generators/application/angular-v14/lib/add-unit-test-runner.ts index 83d33817a09e3..3d4289d23269c 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/add-unit-test-runner.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/add-unit-test-runner.ts @@ -17,6 +17,9 @@ export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) { rootProject: options.rootProject, }); } else if (options.unitTestRunner === UnitTestRunner.Karma) { + const { + karmaProjectGenerator, + } = require('../../../karma-project/karma-project'); await karmaProjectGenerator(host, { project: options.name, skipFormat: true, diff --git a/packages/angular/src/generators/application/angular-v14/lib/convert-to-standalone-app.ts b/packages/angular/src/generators/application/angular-v14/lib/convert-to-standalone-app.ts index d3e7432ece7ed..f033258af74b4 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/convert-to-standalone-app.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/convert-to-standalone-app.ts @@ -1,7 +1,6 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments } from '@nrwl/devkit'; import type { NormalizedSchema } from './normalized-schema'; -import { tsquery } from '@phenomnomnominal/tsquery'; export function convertToStandaloneApp(tree: Tree, options: NormalizedSchema) { const pathToAppModule = joinPathFragments( @@ -24,6 +23,7 @@ function updateMainEntrypoint( ) { let routerModuleSetup: string; if (options.routing) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const appModuleContents = tree.read(pathToAppModule, 'utf-8'); const ast = tsquery.ast(appModuleContents); @@ -73,6 +73,7 @@ function updateAppComponent(tree: Tree, options: NormalizedSchema) { ); const appComponentContents = tree.read(pathToAppComponent, 'utf-8'); + const { tsquery } = require('@phenomnomnominal/tsquery'); const ast = tsquery.ast(appComponentContents); const COMPONENT_DECORATOR_SELECTOR = 'Decorator > CallExpression:has(Identifier[name=Component]) ObjectLiteralExpression'; diff --git a/packages/angular/src/generators/application/angular-v14/lib/create-files.ts b/packages/angular/src/generators/application/angular-v14/lib/create-files.ts index d2ec7f3b8cdcb..459e1b80df97d 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/create-files.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/create-files.ts @@ -1,6 +1,5 @@ import type { Tree } from '@nrwl/devkit'; import { generateFiles, joinPathFragments } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import type { NormalizedSchema } from './normalized-schema'; export function createFiles(tree: Tree, options: NormalizedSchema) { diff --git a/packages/angular/src/generators/application/angular-v14/lib/update-component-spec.ts b/packages/angular/src/generators/application/angular-v14/lib/update-component-spec.ts index d5f2f6772e3e7..7f6765cfec918 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/update-component-spec.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/update-component-spec.ts @@ -1,22 +1,26 @@ import type { Tree } from '@nrwl/devkit'; import type { NormalizedSchema } from './normalized-schema'; -import * as ts from 'typescript'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { addImportToTestBed, replaceIntoToTestBed, } from '../../../../utils/nx-devkit/ast-utils'; +let tsModule: typeof import('typescript'); + export function updateComponentSpec(host: Tree, options: NormalizedSchema) { + if (!tsModule) { + tsModule = require('typescript'); + } if (options.skipTests !== true) { const componentSpecPath = `${options.appProjectRoot}/src/app/app.component.spec.ts`; const componentSpecSource = host.read(componentSpecPath, 'utf-8'); - let componentSpecSourceFile = ts.createSourceFile( + let componentSpecSourceFile = tsModule.createSourceFile( componentSpecPath, componentSpecSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts b/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts index 120d7ab114020..83be60371c874 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts @@ -9,13 +9,13 @@ import { updateJson, } from '@nrwl/devkit'; import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { E2eTestRunner, UnitTestRunner } from '../../../../utils/test-runners'; import type { NormalizedSchema } from './normalized-schema'; import { createTsConfig, extractTsConfigBase, } from '../../../utils/create-ts-config'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; export function updateConfigFiles(host: Tree, options: NormalizedSchema) { if (!options.rootProject) { diff --git a/packages/angular/src/generators/application/angular-v14/lib/update-e2e-project.ts b/packages/angular/src/generators/application/angular-v14/lib/update-e2e-project.ts index 9db6ee4dcf3ad..5586c81ac1bc4 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/update-e2e-project.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/update-e2e-project.ts @@ -6,7 +6,7 @@ import { updateJson, updateProjectConfiguration, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import type { NormalizedSchema } from './normalized-schema'; export function updateE2eProject(tree: Tree, options: NormalizedSchema) { diff --git a/packages/angular/src/generators/application/application.ts b/packages/angular/src/generators/application/application.ts index ed21599326b40..640bad8a016e3 100644 --- a/packages/angular/src/generators/application/application.ts +++ b/packages/angular/src/generators/application/application.ts @@ -1,5 +1,6 @@ import { formatFiles, + GeneratorCallback, installPackagesTask, moveFilesToNewDirectory, readNxJson, @@ -39,7 +40,7 @@ import { lt } from 'semver'; export async function applicationGenerator( tree: Tree, schema: Partial -) { +): Promise { const installedAngularVersionInfo = getInstalledAngularVersionInfo(tree); if (lt(installedAngularVersionInfo.version, '14.1.0') && schema.standalone) { diff --git a/packages/angular/src/generators/application/lib/convert-to-standalone-app.ts b/packages/angular/src/generators/application/lib/convert-to-standalone-app.ts index 2d727750d0f38..992c4414bd8a1 100644 --- a/packages/angular/src/generators/application/lib/convert-to-standalone-app.ts +++ b/packages/angular/src/generators/application/lib/convert-to-standalone-app.ts @@ -1,7 +1,6 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments } from '@nrwl/devkit'; import type { NormalizedSchema } from './normalized-schema'; -import { tsquery } from '@phenomnomnominal/tsquery'; export function convertToStandaloneApp(tree: Tree, options: NormalizedSchema) { const pathToAppModule = joinPathFragments( @@ -22,6 +21,7 @@ function updateMainEntrypoint( tree: Tree, pathToAppModule: string ) { + const { tsquery } = require('@phenomnomnominal/tsquery'); let routerModuleSetup: string; if (options.routing) { const appModuleContents = tree.read(pathToAppModule, 'utf-8'); @@ -63,6 +63,7 @@ bootstrapApplication(AppComponent${ }).catch((err) => console.error(err));`; function updateAppComponent(tree: Tree, options: NormalizedSchema) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const pathToAppComponent = joinPathFragments( options.appProjectRoot, 'src/app/app.component.ts' diff --git a/packages/angular/src/generators/application/lib/create-files.ts b/packages/angular/src/generators/application/lib/create-files.ts index 1588633a0c487..edd8d9cf49ad7 100644 --- a/packages/angular/src/generators/application/lib/create-files.ts +++ b/packages/angular/src/generators/application/lib/create-files.ts @@ -1,6 +1,6 @@ import type { Tree } from '@nrwl/devkit'; import { generateFiles, joinPathFragments } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import type { NormalizedSchema } from './normalized-schema'; export function createFiles(tree: Tree, options: NormalizedSchema) { diff --git a/packages/angular/src/generators/application/lib/root-router-config.ts b/packages/angular/src/generators/application/lib/root-router-config.ts index b31f69878d5a1..d64f65b3c245e 100644 --- a/packages/angular/src/generators/application/lib/root-router-config.ts +++ b/packages/angular/src/generators/application/lib/root-router-config.ts @@ -2,9 +2,10 @@ import type { Tree } from '@nrwl/devkit'; import type { NormalizedSchema } from './normalized-schema'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; -import * as ts from 'typescript'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; +let tsModule: typeof import('typescript'); + export function addRouterRootConfiguration( host: Tree, options: NormalizedSchema @@ -12,10 +13,13 @@ export function addRouterRootConfiguration( const modulePath = `${options.appProjectRoot}/src/app/app.module.ts`; const moduleSource = host.read(modulePath, 'utf-8'); - let sourceFile = ts.createSourceFile( + if (!tsModule) { + tsModule = require('typescript'); + } + let sourceFile = tsModule.createSourceFile( modulePath, moduleSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/application/lib/update-app-component-template.ts b/packages/angular/src/generators/application/lib/update-app-component-template.ts index 2ec7041167d0c..6107f318e55b2 100644 --- a/packages/angular/src/generators/application/lib/update-app-component-template.ts +++ b/packages/angular/src/generators/application/lib/update-app-component-template.ts @@ -1,16 +1,21 @@ import type { Tree } from '@nrwl/devkit'; import type { NormalizedSchema } from './normalized-schema'; -import * as ts from 'typescript'; import { replaceNodeValue } from '@nrwl/workspace/src/utilities/ast-utils'; import { getDecoratorPropertyValueNode } from '../../../utils/nx-devkit/ast-utils'; import { nrwlHomeTemplate } from './nrwl-home-tpl'; -export function updateAppComponentTemplate( +let tsModule: typeof import('typescript'); + +export async function updateAppComponentTemplate( host: Tree, options: NormalizedSchema ) { + if (!tsModule) { + tsModule = require('typescript'); + } + const content = options.routing ? `${nrwlHomeTemplate.getSelector( options.prefix @@ -35,10 +40,10 @@ export function updateAppComponentTemplate( replaceNodeValue( host, - ts.createSourceFile( + tsModule.createSourceFile( componentPath, host.read(componentPath, 'utf-8'), - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ), componentPath, diff --git a/packages/angular/src/generators/application/lib/update-component-spec.ts b/packages/angular/src/generators/application/lib/update-component-spec.ts index 1e598540e9f8a..41ce5120e699a 100644 --- a/packages/angular/src/generators/application/lib/update-component-spec.ts +++ b/packages/angular/src/generators/application/lib/update-component-spec.ts @@ -1,22 +1,26 @@ import type { Tree } from '@nrwl/devkit'; -import type { NormalizedSchema } from './normalized-schema'; - -import * as ts from 'typescript'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { addImportToTestBed, replaceIntoToTestBed, } from '../../../utils/nx-devkit/ast-utils'; +import type { NormalizedSchema } from './normalized-schema'; + +let tsModule: typeof import('typescript'); export function updateComponentSpec(host: Tree, options: NormalizedSchema) { + if (!tsModule) { + tsModule = require('typescript'); + } + if (options.skipTests !== true) { const componentSpecPath = `${options.appProjectRoot}/src/app/app.component.spec.ts`; const componentSpecSource = host.read(componentSpecPath, 'utf-8'); - let componentSpecSourceFile = ts.createSourceFile( + let componentSpecSourceFile = tsModule.createSourceFile( componentSpecPath, componentSpecSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/application/lib/update-config-files.ts b/packages/angular/src/generators/application/lib/update-config-files.ts index ae069c3799fa6..ce669a2e313a5 100644 --- a/packages/angular/src/generators/application/lib/update-config-files.ts +++ b/packages/angular/src/generators/application/lib/update-config-files.ts @@ -9,10 +9,10 @@ import { updateJson, } from '@nrwl/devkit'; import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners'; import type { NormalizedSchema } from './normalized-schema'; import { createTsConfig } from '../../utils/create-ts-config'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; export function updateConfigFiles(host: Tree, options: NormalizedSchema) { updateTsConfigOptions(host, options); diff --git a/packages/angular/src/generators/application/lib/update-e2e-project.ts b/packages/angular/src/generators/application/lib/update-e2e-project.ts index 9db6ee4dcf3ad..5586c81ac1bc4 100644 --- a/packages/angular/src/generators/application/lib/update-e2e-project.ts +++ b/packages/angular/src/generators/application/lib/update-e2e-project.ts @@ -6,7 +6,7 @@ import { updateJson, updateProjectConfiguration, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import type { NormalizedSchema } from './normalized-schema'; export function updateE2eProject(tree: Tree, options: NormalizedSchema) { diff --git a/packages/angular/src/generators/application/lib/update-nx-component-template.ts b/packages/angular/src/generators/application/lib/update-nx-component-template.ts index a56564c07fd03..55f12cf150e9a 100644 --- a/packages/angular/src/generators/application/lib/update-nx-component-template.ts +++ b/packages/angular/src/generators/application/lib/update-nx-component-template.ts @@ -1,7 +1,6 @@ import type { Tree } from '@nrwl/devkit'; import type { NormalizedSchema } from './normalized-schema'; -import * as ts from 'typescript'; import { addGlobal, replaceNodeValue, @@ -9,10 +8,16 @@ import { import { getDecoratorPropertyValueNode } from '../../../utils/nx-devkit/ast-utils'; import { nrwlHomeTemplate } from './nrwl-home-tpl'; +let tsModule: typeof import('typescript'); + export function updateNxComponentTemplate( host: Tree, options: NormalizedSchema ) { + if (!tsModule) { + tsModule = require('typescript'); + } + const componentPath = `${options.appProjectRoot}/src/app/nx-welcome.component.ts`; const templateNodeValue = getDecoratorPropertyValueNode( host, @@ -24,10 +29,10 @@ export function updateNxComponentTemplate( replaceNodeValue( host, - ts.createSourceFile( + tsModule.createSourceFile( componentPath, host.read(componentPath, 'utf-8'), - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ), componentPath, @@ -36,10 +41,10 @@ export function updateNxComponentTemplate( ); // Fixing extra comma issue `,,` - let sourceFile = ts.createSourceFile( + let sourceFile = tsModule.createSourceFile( componentPath, host.read(componentPath, 'utf-8'), - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const componentFile = host @@ -56,10 +61,10 @@ export function updateNxComponentTemplate( }); // Add ESLint ignore to pass the lint step - sourceFile = ts.createSourceFile( + sourceFile = tsModule.createSourceFile( componentPath, host.read(componentPath, 'utf-8'), - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); addGlobal(host, sourceFile, componentPath, '/* eslint-disable */'); diff --git a/packages/angular/src/generators/change-storybook-targets/change-storybook-targets.ts b/packages/angular/src/generators/change-storybook-targets/change-storybook-targets.ts index 2df1294590f64..9fcc46494abee 100644 --- a/packages/angular/src/generators/change-storybook-targets/change-storybook-targets.ts +++ b/packages/angular/src/generators/change-storybook-targets/change-storybook-targets.ts @@ -8,7 +8,7 @@ export async function angularChangeStorybookTargestGenerator( tree: Tree, schema: Schema ) { - await ensurePackage(tree, '@nrwl/storybook', nxVersion); + ensurePackage(tree, '@nrwl/storybook', nxVersion); const { changeStorybookTargetsGenerator } = await import('@nrwl/storybook'); await changeStorybookTargetsGenerator(tree); diff --git a/packages/angular/src/generators/component/lib/entry-point.ts b/packages/angular/src/generators/component/lib/entry-point.ts index baca0200b47d9..f37587a1b4e5c 100644 --- a/packages/angular/src/generators/component/lib/entry-point.ts +++ b/packages/angular/src/generators/component/lib/entry-point.ts @@ -1,5 +1,4 @@ import type { Tree } from '@nrwl/devkit'; -import { tsquery } from '@phenomnomnominal/tsquery'; import type { StringLiteral } from 'typescript'; import { getRelativeImportToFile } from '../../utils/path'; @@ -12,6 +11,7 @@ export function shouldExportInEntryPoint( return false; } + const { tsquery } = require('@phenomnomnominal/tsquery'); const moduleImportPath = getRelativeImportToFile(entryPoint, modulePath); const entryPointContent = tree.read(entryPoint, 'utf-8'); const entryPointAst = tsquery.ast(entryPointContent); diff --git a/packages/angular/src/generators/convert-to-with-mf/lib/check-name-matches.ts b/packages/angular/src/generators/convert-to-with-mf/lib/check-name-matches.ts index 94efb92c58bc4..fc2bb2a12e716 100644 --- a/packages/angular/src/generators/convert-to-with-mf/lib/check-name-matches.ts +++ b/packages/angular/src/generators/convert-to-with-mf/lib/check-name-matches.ts @@ -1,10 +1,10 @@ import type { SourceFile } from 'typescript'; -import { tsquery } from '@phenomnomnominal/tsquery'; export function checkOutputNameMatchesProjectName( ast: SourceFile, projectName: string ) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const OUTPUT_SELECTOR = 'PropertyAssignment:has(Identifier[name=output]) > ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=uniqueName]))'; const UNIQUENAME_SELECTOR = diff --git a/packages/angular/src/generators/convert-to-with-mf/lib/check-shared-npm-packages.ts b/packages/angular/src/generators/convert-to-with-mf/lib/check-shared-npm-packages.ts index 85f57d5f73c46..27a061033b689 100644 --- a/packages/angular/src/generators/convert-to-with-mf/lib/check-shared-npm-packages.ts +++ b/packages/angular/src/generators/convert-to-with-mf/lib/check-shared-npm-packages.ts @@ -1,7 +1,7 @@ import type { SourceFile, Node } from 'typescript'; -import { tsquery } from '@phenomnomnominal/tsquery'; export function checkSharedNpmPackagesMatchExpected(ast: SourceFile) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const SHARE_HELPER_SELECTOR = 'PropertyAssignment:has(Identifier[name=shared]) > CallExpression:has(Identifier[name=share])'; const SHARED_PACKAGE_CONFIG_SELECTOR = diff --git a/packages/angular/src/generators/convert-to-with-mf/lib/is-host-remote-config.ts b/packages/angular/src/generators/convert-to-with-mf/lib/is-host-remote-config.ts index e550c7f4576a5..3cb42170dd203 100644 --- a/packages/angular/src/generators/convert-to-with-mf/lib/is-host-remote-config.ts +++ b/packages/angular/src/generators/convert-to-with-mf/lib/is-host-remote-config.ts @@ -1,5 +1,4 @@ import type { SourceFile } from 'typescript'; -import { tsquery } from '@phenomnomnominal/tsquery'; export type IsHostRemoteConfigResult = 'host' | 'remote' | 'both' | false; @@ -12,6 +11,7 @@ const PROPERTY_SELECTOR = 'ObjectLiteralExpression > PropertyAssignment'; export function isHostRemoteConfig(ast: SourceFile): IsHostRemoteConfigResult { let isHost = false; let isRemote = false; + const { tsquery } = require('@phenomnomnominal/tsquery'); const remotesNodes = tsquery(ast, REMOTES_EXPRESSION_SELECTOR, { visitAllChildren: true, @@ -33,6 +33,7 @@ export function isHostRemoteConfig(ast: SourceFile): IsHostRemoteConfigResult { } export function getRemotesFromHost(ast: SourceFile) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const remotesObjectNodes = tsquery(ast, REMOTES_EXPRESSION_SELECTOR, { visitAllChildren: true, }); @@ -62,6 +63,7 @@ export function getRemotesFromHost(ast: SourceFile) { } export function getExposedModulesFromRemote(ast: SourceFile) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const exposesObjectNodes = tsquery(ast, EXPOSES_EXPRESSION_SELECTOR, { visitAllChildren: true, }); diff --git a/packages/angular/src/generators/convert-to-with-mf/lib/parse-ast-webpack-config.ts b/packages/angular/src/generators/convert-to-with-mf/lib/parse-ast-webpack-config.ts index f86126c85f63d..72c1e76ac7a90 100644 --- a/packages/angular/src/generators/convert-to-with-mf/lib/parse-ast-webpack-config.ts +++ b/packages/angular/src/generators/convert-to-with-mf/lib/parse-ast-webpack-config.ts @@ -1,5 +1,4 @@ import type { Tree } from '@nrwl/devkit'; -import { tsquery } from '@phenomnomnominal/tsquery'; export function parseASTOfWebpackConfig( tree: Tree, @@ -10,6 +9,7 @@ export function parseASTOfWebpackConfig( `Cannot migrate webpack config at \`${pathToWebpackConfig}\` as it does not exist. Please ensure this file exists and that the path to the file is correct.` ); } + const { tsquery } = require('@phenomnomnominal/tsquery'); const source = tree.read(pathToWebpackConfig, 'utf-8'); return tsquery.ast(source); diff --git a/packages/angular/src/generators/init/angular-v14/init.ts b/packages/angular/src/generators/init/angular-v14/init.ts index affd213e109e2..1324e8c2c2f96 100755 --- a/packages/angular/src/generators/init/angular-v14/init.ts +++ b/packages/angular/src/generators/init/angular-v14/init.ts @@ -9,6 +9,7 @@ import { } from '@nrwl/devkit'; import { jestInitGenerator } from '@nrwl/jest'; import { Linter } from '@nrwl/linter'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { backwardCompatibleVersions } from '../../../utils/backward-compatible-versions'; import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners'; @@ -25,19 +26,29 @@ export async function angularInitGenerator( ): Promise { const options = normalizeOptions(rawOptions); setDefaults(host, options); + await jsInitGenerator(host, { + js: false, + skipFormat: true, + }); + + const tasks: GeneratorCallback[] = []; + + if (!options.skipPackageJson) { + tasks.push(updateDependencies(host)); + } - const depsTask = !options.skipPackageJson - ? updateDependencies(host) - : () => {}; const unitTestTask = await addUnitTestRunner(host, options); + tasks.push(unitTestTask); const e2eTask = addE2ETestRunner(host, options); + tasks.push(e2eTask); + addGitIgnoreEntry(host, '.angular'); if (!options.skipFormat) { await formatFiles(host); } - return runTasksInSerial(depsTask, unitTestTask, e2eTask); + return runTasksInSerial(...tasks); } function normalizeOptions(options: Schema): Required { diff --git a/packages/angular/src/generators/init/init.ts b/packages/angular/src/generators/init/init.ts index a59e52063e40a..94eaddc73d75b 100755 --- a/packages/angular/src/generators/init/init.ts +++ b/packages/angular/src/generators/init/init.ts @@ -9,6 +9,7 @@ import { } from '@nrwl/devkit'; import { jestInitGenerator } from '@nrwl/jest'; import { Linter } from '@nrwl/linter'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { join } from 'path'; import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners'; @@ -50,19 +51,28 @@ export async function angularInitGenerator( const options = normalizeOptions(rawOptions); setDefaults(tree, options); + await jsInitGenerator(tree, { + js: false, + skipFormat: true, + }); - const depsTask = !options.skipPackageJson - ? updateDependencies(tree) - : () => {}; + const tasks: GeneratorCallback[] = []; + + if (!options.skipPackageJson) { + tasks.push(updateDependencies(tree)); + } const unitTestTask = await addUnitTestRunner(tree, options); - const e2eTask = addE2ETestRunner(tree, options); + tasks.push(unitTestTask); + const e2eTask = await addE2ETestRunner(tree, options); + tasks.push(e2eTask); + addGitIgnoreEntry(tree, '.angular'); if (!options.skipFormat) { await formatFiles(tree); } - return runTasksInSerial(depsTask, unitTestTask, e2eTask); + return runTasksInSerial(...tasks); } function normalizeOptions(options: Schema): Required { @@ -160,7 +170,10 @@ async function addUnitTestRunner( } } -function addE2ETestRunner(tree: Tree, options: Schema): GeneratorCallback { +async function addE2ETestRunner( + tree: Tree, + options: Schema +): Promise { switch (options.e2eTestRunner) { case E2eTestRunner.Protractor: return !options.skipPackageJson diff --git a/packages/angular/src/generators/karma-project/lib/generate-karma-project-files.ts b/packages/angular/src/generators/karma-project/lib/generate-karma-project-files.ts index edaea8171510c..594c91dfe5c40 100644 --- a/packages/angular/src/generators/karma-project/lib/generate-karma-project-files.ts +++ b/packages/angular/src/generators/karma-project/lib/generate-karma-project-files.ts @@ -6,7 +6,6 @@ import { offsetFromRoot, readProjectConfiguration, } from '@nrwl/devkit'; -import { tsquery } from '@phenomnomnominal/tsquery'; import { getInstalledAngularVersionInfo } from '../../utils/version-utils'; import { v14TestFile } from './v14-test-file'; @@ -76,6 +75,7 @@ function isUsingConfigSetInBaseKarmaConfig(tree: Tree) { if (!tree.exists('karma.conf.js')) { return false; } + const { tsquery } = require('@phenomnomnominal/tsquery'); const CONFIG_SET_SELECTOR = 'PropertyAccessExpression:has(Identifier[name=config], Identifier[name=set])'; diff --git a/packages/angular/src/generators/library-secondary-entry-point/lib/add-path-mapping.ts b/packages/angular/src/generators/library-secondary-entry-point/lib/add-path-mapping.ts index 2168c9405f602..2f22e47334ed9 100644 --- a/packages/angular/src/generators/library-secondary-entry-point/lib/add-path-mapping.ts +++ b/packages/angular/src/generators/library-secondary-entry-point/lib/add-path-mapping.ts @@ -1,5 +1,5 @@ import { Tree, updateJson } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; import { NormalizedGeneratorOptions } from '../schema'; export function addPathMapping( diff --git a/packages/angular/src/generators/library/lib/add-children.ts b/packages/angular/src/generators/library/lib/add-children.ts index b3a09bf544329..13efcd3ae4672 100644 --- a/packages/angular/src/generators/library/lib/add-children.ts +++ b/packages/angular/src/generators/library/lib/add-children.ts @@ -1,10 +1,11 @@ import { names, Tree } from '@nrwl/devkit'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; -import * as ts from 'typescript'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { NormalizedSchema } from './normalized-schema'; import { addRoute } from '../../../utils/nx-devkit/route-utils'; +let tsModule: typeof import('typescript'); + export function addChildren( tree: Tree, options: NormalizedSchema['libraryOptions'] @@ -12,16 +13,19 @@ export function addChildren( if (!tree.exists(options.parent)) { throw new Error(`Cannot find '${options.parent}'`); } + if (!tsModule) { + tsModule = require('typescript'); + } const routeFileSource = tree.read(options.parent, 'utf-8'); const constName = options.standalone ? `${names(options.name).propertyName}Routes` : `${names(options.fileName).propertyName}Routes`; const importPath = options.importPath; - let sourceFile = ts.createSourceFile( + let sourceFile = tsModule.createSourceFile( options.parent, routeFileSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/library/lib/add-lazy-loaded-router-configuration.ts b/packages/angular/src/generators/library/lib/add-lazy-loaded-router-configuration.ts index 193784fe9aa41..ae21c5e4e95b7 100644 --- a/packages/angular/src/generators/library/lib/add-lazy-loaded-router-configuration.ts +++ b/packages/angular/src/generators/library/lib/add-lazy-loaded-router-configuration.ts @@ -1,14 +1,18 @@ import { joinPathFragments, names, Tree } from '@nrwl/devkit'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; -import * as ts from 'typescript'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { NormalizedSchema } from './normalized-schema'; import { dirname } from 'path'; +let tsModule: typeof import('typescript'); + export function addLazyLoadedRouterConfiguration( tree: Tree, options: NormalizedSchema['libraryOptions'] ) { + if (!tsModule) { + tsModule = require('typescript'); + } const constName = `${names(options.fileName).propertyName}Routes`; tree.write( joinPathFragments(dirname(options.modulePath), 'lib.routes.ts'), @@ -18,10 +22,10 @@ export const ${constName}: Route[] = [/* {path: '', pathMatch: 'full', component ); const routeFileSource = tree.read(options.modulePath, 'utf-8'); - let sourceFile = ts.createSourceFile( + let sourceFile = tsModule.createSourceFile( options.modulePath, routeFileSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); sourceFile = addImportToModule( diff --git a/packages/angular/src/generators/library/lib/add-load-children.ts b/packages/angular/src/generators/library/lib/add-load-children.ts index f7d57e5a391ce..1467505aa71cd 100644 --- a/packages/angular/src/generators/library/lib/add-load-children.ts +++ b/packages/angular/src/generators/library/lib/add-load-children.ts @@ -1,8 +1,9 @@ import { names, Tree } from '@nrwl/devkit'; -import * as ts from 'typescript'; import { NormalizedSchema } from './normalized-schema'; import { addRoute } from '../../../utils/nx-devkit/route-utils'; +let tsModule: typeof import('typescript'); + export function addLoadChildren( tree: Tree, options: NormalizedSchema['libraryOptions'] @@ -10,12 +11,15 @@ export function addLoadChildren( if (!tree.exists(options.parent)) { throw new Error(`Cannot find '${options.parent}'`); } + if (!tsModule) { + tsModule = require('typescript'); + } const moduleSource = tree.read(options.parent, 'utf-8'); - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( options.parent, moduleSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/library/lib/add-router-configuration.ts b/packages/angular/src/generators/library/lib/add-router-configuration.ts index 9078c4a85f58a..8829ea187856c 100644 --- a/packages/angular/src/generators/library/lib/add-router-configuration.ts +++ b/packages/angular/src/generators/library/lib/add-router-configuration.ts @@ -1,21 +1,25 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments, names } from '@nrwl/devkit'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; -import * as ts from 'typescript'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { NormalizedSchema } from './normalized-schema'; import { dirname } from 'path'; +let tsModule: typeof import('typescript'); + export function addRouterConfiguration( tree: Tree, options: NormalizedSchema['libraryOptions'] ) { + if (!tsModule) { + tsModule = require('typescript'); + } const constName = `${names(options.fileName).propertyName}Routes`; const moduleSource = tree.read(options.modulePath, 'utf-8'); - let moduleSourceFile = ts.createSourceFile( + let moduleSourceFile = tsModule.createSourceFile( options.modulePath, moduleSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/library/lib/update-project.ts b/packages/angular/src/generators/library/lib/update-project.ts index 747098b8f837b..beb408c8262b3 100644 --- a/packages/angular/src/generators/library/lib/update-project.ts +++ b/packages/angular/src/generators/library/lib/update-project.ts @@ -8,7 +8,7 @@ import { Tree, updateJson, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; import { NormalizedSchema } from './normalized-schema'; import { updateNgPackage } from './update-ng-package'; diff --git a/packages/angular/src/generators/library/lib/update-tsconfig.ts b/packages/angular/src/generators/library/lib/update-tsconfig.ts index a7c9f8608fa48..83ce3fb94048e 100644 --- a/packages/angular/src/generators/library/lib/update-tsconfig.ts +++ b/packages/angular/src/generators/library/lib/update-tsconfig.ts @@ -1,38 +1,12 @@ import type { Tree } from '@nrwl/devkit'; -import { joinPathFragments, updateJson } from '@nrwl/devkit'; -import { - getRelativePathToRootTsConfig, - getRootTsConfigPathInTree, -} from '@nrwl/workspace/src/utilities/typescript'; +import { updateJson } from '@nrwl/devkit'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { NormalizedSchema } from './normalized-schema'; import { createTsConfig, extractTsConfigBase, } from '../../utils/create-ts-config'; -function updateRootConfig( - host: Tree, - options: NormalizedSchema['libraryOptions'] -) { - updateJson(host, getRootTsConfigPathInTree(host), (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - c.paths[options.importPath] = [ - joinPathFragments(options.projectRoot, '/src/index.ts'), - ]; - - return json; - }); -} - function updateProjectConfig( host: Tree, options: NormalizedSchema['libraryOptions'] @@ -82,7 +56,6 @@ export function updateTsConfig( options: NormalizedSchema['libraryOptions'] ) { extractTsConfigBase(host); - updateRootConfig(host, options); updateProjectConfig(host, options); updateProjectIvyConfig(host, options); } diff --git a/packages/angular/src/generators/library/library.ts b/packages/angular/src/generators/library/library.ts index 964a6996d89c2..d9e0a91366856 100644 --- a/packages/angular/src/generators/library/library.ts +++ b/packages/angular/src/generators/library/library.ts @@ -1,6 +1,7 @@ import { addDependenciesToPackageJson, formatFiles, + GeneratorCallback, installPackagesTask, moveFilesToNewDirectory, removeDependenciesFromPackageJson, @@ -9,6 +10,7 @@ import { import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter'; import { jestProjectGenerator } from '@nrwl/jest'; import { Linter } from '@nrwl/linter'; +import { updateRootTsConfig } from '@nrwl/js'; import { lt } from 'semver'; import init from '../../generators/init/init'; import { E2eTestRunner } from '../../utils/test-runners'; @@ -31,7 +33,10 @@ import { updateProject } from './lib/update-project'; import { updateTsConfig } from './lib/update-tsconfig'; import { Schema } from './schema'; -export async function libraryGenerator(tree: Tree, schema: Schema) { +export async function libraryGenerator( + tree: Tree, + schema: Schema +): Promise { // Do some validation checks if (!schema.routing && schema.lazy) { throw new Error(`To use "--lazy" option, "--routing" must also be set.`); @@ -57,7 +62,7 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { } const options = normalizeOptions(tree, schema); - const { libraryOptions, componentOptions } = options; + const { libraryOptions } = options; await init(tree, { ...libraryOptions, @@ -86,6 +91,8 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { libraryOptions.projectRoot ); } + + const { updateProject } = await import('./lib/update-project'); await updateProject(tree, libraryOptions); updateTsConfig(tree, libraryOptions); await addUnitTestRunner(tree, libraryOptions); @@ -122,6 +129,8 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { addBuildableLibrariesPostCssDependencies(tree); } + updateRootTsConfig(tree, { ...libraryOptions, js: false }); + if (!libraryOptions.skipFormat) { await formatFiles(tree); } diff --git a/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-karma.migrator.ts b/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-karma.migrator.ts index 102afe32ccc9d..965787750e46b 100644 --- a/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-karma.migrator.ts +++ b/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-karma.migrator.ts @@ -8,7 +8,7 @@ import { offsetFromRoot, updateProjectConfiguration, } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; import { basename } from 'path'; import type { Logger, ProjectMigrationInfo } from '../../utilities'; import { BuilderMigrator } from './builder.migrator'; diff --git a/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-ng-packagr.migrator.ts b/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-ng-packagr.migrator.ts index 60e85190cb8a9..20938dc3bfdee 100644 --- a/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-ng-packagr.migrator.ts +++ b/packages/angular/src/generators/ng-add/migrators/builders/angular-devkit-ng-packagr.migrator.ts @@ -9,7 +9,7 @@ import { updateJson, updateProjectConfiguration, } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; import { basename } from 'path'; import { addBuildableLibrariesPostCssDependencies } from '../../../utils/dependencies'; import type { Logger, ProjectMigrationInfo } from '../../utilities'; diff --git a/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.ts b/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.ts index 02e6f77fe3107..63c268825834b 100644 --- a/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.ts +++ b/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.ts @@ -5,7 +5,7 @@ import { updateJson, updateProjectConfiguration, } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; import { basename } from 'path'; import type { GeneratorOptions } from '../../schema'; import type { diff --git a/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts b/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts index 3044d94da831f..65d449ddbe4df 100644 --- a/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts +++ b/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.ts @@ -22,8 +22,7 @@ import { } from '@nrwl/devkit'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; -import { tsquery } from '@phenomnomnominal/tsquery'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; import { basename, relative } from 'path'; import type { Node, @@ -578,6 +577,7 @@ export class E2eMigrator extends ProjectMigrator { } private updateCypress10ConfigFile(configFilePath: string): void { + const { tsquery } = require('@phenomnomnominal/tsquery'); this.cypressPreset = nxE2EPreset(configFilePath); const fileContent = this.tree.read(configFilePath, 'utf-8'); @@ -657,6 +657,7 @@ export class E2eMigrator extends ProjectMigrator { recorder: FileChangeRecorder, { ...globalConfig }: CypressCommonConfig ): void { + const { tsquery } = require('@phenomnomnominal/tsquery'); const e2eConfig = {}; const presetSpreadAssignment = `...nxE2EPreset(__dirname),`; if (!e2eNode) { diff --git a/packages/angular/src/generators/ng-add/utilities/workspace.ts b/packages/angular/src/generators/ng-add/utilities/workspace.ts index 6097eb2df9c77..7d176ab9268e7 100644 --- a/packages/angular/src/generators/ng-add/utilities/workspace.ts +++ b/packages/angular/src/generators/ng-add/utilities/workspace.ts @@ -13,7 +13,7 @@ import { Linter, lintInitGenerator } from '@nrwl/linter'; import { DEFAULT_NRWL_PRETTIER_CONFIG } from '@nrwl/workspace/src/generators/new/generate-workspace-files'; import { deduceDefaultBase } from '@nrwl/workspace/src/utilities/default-base'; import { resolveUserExistingPrettierConfig } from '@nrwl/workspace/src/utilities/prettier'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; import { prettierVersion } from '@nrwl/workspace/src/utils/versions'; import { toNewFormat } from 'nx/src/adapter/angular-json'; import { angularDevkitVersion, nxVersion } from '../../../utils/versions'; diff --git a/packages/angular/src/generators/setup-mf/lib/add-remote-to-host.ts b/packages/angular/src/generators/setup-mf/lib/add-remote-to-host.ts index 080df9f29c7f7..33dadf007e769 100644 --- a/packages/angular/src/generators/setup-mf/lib/add-remote-to-host.ts +++ b/packages/angular/src/generators/setup-mf/lib/add-remote-to-host.ts @@ -8,11 +8,13 @@ import { } from '@nrwl/devkit'; import type { Schema } from '../schema'; import { tsquery } from '@phenomnomnominal/tsquery'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { ArrayLiteralExpression } from 'typescript'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { addRoute } from '../../../utils/nx-devkit/route-utils'; +let tsModule: typeof import('typescript'); + export function checkIsCommaNeeded(mfRemoteText: string) { const remoteText = mfRemoteText.replace(/\s+/g, ''); return !remoteText.endsWith(',]') @@ -118,6 +120,9 @@ function addLazyLoadedRouteToHostAppModule( options: Schema, hostFederationType: 'dynamic' | 'static' ) { + if (!tsModule) { + tsModule = require('typescript'); + } const hostAppConfig = readProjectConfiguration(tree, options.host); const pathToHostRootRouting = `${hostAppConfig.sourceRoot}/app/app.routes.ts`; @@ -128,10 +133,10 @@ function addLazyLoadedRouteToHostAppModule( const hostRootRoutingFile = tree.read(pathToHostRootRouting, 'utf-8'); - let sourceFile = ts.createSourceFile( + let sourceFile = tsModule.createSourceFile( pathToHostRootRouting, hostRootRoutingFile, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/generators/setup-ssr/lib/update-app-module.ts b/packages/angular/src/generators/setup-ssr/lib/update-app-module.ts index da9183868381f..32b214ef5f862 100644 --- a/packages/angular/src/generators/setup-ssr/lib/update-app-module.ts +++ b/packages/angular/src/generators/setup-ssr/lib/update-app-module.ts @@ -1,9 +1,9 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments, readProjectConfiguration } from '@nrwl/devkit'; import type { Schema } from '../schema'; -import { tsquery } from '@phenomnomnominal/tsquery'; export function updateAppModule(tree: Tree, schema: Schema) { + const { tsquery } = require('@phenomnomnominal/tsquery'); // read the content of app module const projectConfig = readProjectConfiguration(tree, schema.project); const pathToAppModule = joinPathFragments( diff --git a/packages/angular/src/generators/stories/stories-lib.spec.ts b/packages/angular/src/generators/stories/stories-lib.spec.ts index df60822a59301..a3f0fa198cb45 100644 --- a/packages/angular/src/generators/stories/stories-lib.spec.ts +++ b/packages/angular/src/generators/stories/stories-lib.spec.ts @@ -48,7 +48,7 @@ describe('angularStories generator: libraries', () => { beforeEach(async () => { tree = await createStorybookTestWorkspaceForLib(libName); - await ensurePackage(tree, '@nrwl/storybook', nxVersion); + ensurePackage(tree, '@nrwl/storybook', nxVersion); cypressProjectGenerator = await ( await import('@nrwl/storybook') ).cypressProjectGenerator; diff --git a/packages/angular/src/generators/storybook-configuration/lib/generate-storybook-configuration.ts b/packages/angular/src/generators/storybook-configuration/lib/generate-storybook-configuration.ts index c5b79d95a52be..519258325b057 100644 --- a/packages/angular/src/generators/storybook-configuration/lib/generate-storybook-configuration.ts +++ b/packages/angular/src/generators/storybook-configuration/lib/generate-storybook-configuration.ts @@ -6,7 +6,7 @@ export async function generateStorybookConfiguration( tree: Tree, options: StorybookConfigurationOptions ): Promise { - await ensurePackage(tree, '@nrwl/storybook', nxVersion); + ensurePackage(tree, '@nrwl/storybook', nxVersion); const { configurationGenerator } = await import('@nrwl/storybook'); return await configurationGenerator(tree, { name: options.name, diff --git a/packages/angular/src/generators/utils/create-ts-config.ts b/packages/angular/src/generators/utils/create-ts-config.ts index 7cf55f6593f18..f92d81cd8b31b 100644 --- a/packages/angular/src/generators/utils/create-ts-config.ts +++ b/packages/angular/src/generators/utils/create-ts-config.ts @@ -1,9 +1,9 @@ import type { Tree } from '@nrwl/devkit'; import { writeJson } from '@nrwl/devkit'; -import { tsConfigBaseOptions } from '@nrwl/workspace/src/utils/create-ts-config'; +import { tsConfigBaseOptions } from '@nrwl/js'; import { getInstalledAngularMajorVersion } from './version-utils'; -export { extractTsConfigBase } from '@nrwl/workspace/src/utils/create-ts-config'; +export { extractTsConfigBase } from '@nrwl/js'; export function createTsConfig( host: Tree, diff --git a/packages/angular/src/generators/utils/storybook-ast/module-info.ts b/packages/angular/src/generators/utils/storybook-ast/module-info.ts index 9fea560a3ffe2..62ee531cec398 100644 --- a/packages/angular/src/generators/utils/storybook-ast/module-info.ts +++ b/packages/angular/src/generators/utils/storybook-ast/module-info.ts @@ -6,7 +6,6 @@ import { visitNotIgnoredFiles, } from '@nrwl/devkit'; import { findNodes } from 'nx/src/utils/typescript'; -import { tsquery } from '@phenomnomnominal/tsquery'; import { extname } from 'path'; import type { ClassDeclaration, @@ -79,6 +78,7 @@ export function getModuleFilePaths( } function hasNgModule(tree: Tree, filePath: string): boolean { + const { tsquery } = require('@phenomnomnominal/tsquery'); const fileContent = tree.read(filePath, 'utf-8'); const ast = tsquery.ast(fileContent); const ngModule = tsquery( diff --git a/packages/angular/src/generators/web-worker/lib/update-tsconfig.ts b/packages/angular/src/generators/web-worker/lib/update-tsconfig.ts index 21d7bce675e7a..548e378c0cbf8 100644 --- a/packages/angular/src/generators/web-worker/lib/update-tsconfig.ts +++ b/packages/angular/src/generators/web-worker/lib/update-tsconfig.ts @@ -4,7 +4,7 @@ import { readProjectConfiguration, updateJson, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; export function updateTsConfig(tree: Tree, project: string): void { const { root } = readProjectConfiguration(tree, project); diff --git a/packages/angular/src/utils/nx-devkit/ast-utils.ts b/packages/angular/src/utils/nx-devkit/ast-utils.ts index d57d373c13063..38bc8110bc8be 100644 --- a/packages/angular/src/utils/nx-devkit/ast-utils.ts +++ b/packages/angular/src/utils/nx-devkit/ast-utils.ts @@ -1,7 +1,7 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { findNodes } from 'nx/src/utils/typescript'; import { getSourceNodes } from '@nrwl/workspace/src/utilities/typescript/get-source-nodes'; -import * as path from 'path'; +import { dirname, join } from 'path'; import { names, readProjectConfiguration, Tree } from '@nrwl/devkit'; import { getImport, @@ -9,7 +9,8 @@ import { removeChange, replaceChange, } from '@nrwl/workspace/src/utilities/ast-utils'; -import { tsquery } from '@phenomnomnominal/tsquery'; + +let tsModule: typeof import('typescript'); type DecoratorName = 'Component' | 'Directive' | 'NgModule' | 'Pipe'; @@ -17,10 +18,13 @@ function _angularImportsFromNode( node: ts.ImportDeclaration, _sourceFile: ts.SourceFile ): { [name: string]: string } { + if (!tsModule) { + tsModule = require('typescript'); + } const ms = node.moduleSpecifier; let modulePath: string; switch (ms.kind) { - case ts.SyntaxKind.StringLiteral: + case tsModule.SyntaxKind.StringLiteral: modulePath = (ms as ts.StringLiteral).text; break; default: @@ -37,7 +41,7 @@ function _angularImportsFromNode( return {}; } else if (node.importClause.namedBindings) { const nb = node.importClause.namedBindings; - if (nb.kind == ts.SyntaxKind.NamespaceImport) { + if (nb.kind == tsModule.SyntaxKind.NamespaceImport) { // This is of the form `import * as name from 'path'`. Return `name.`. return { [`${(nb as ts.NamespaceImport).name.text}.`]: modulePath, @@ -84,9 +88,12 @@ export function getDecoratorMetadata( identifier: string, module: string ): ts.Node[] { + if (!tsModule) { + tsModule = require('typescript'); + } const angularImports: { [name: string]: string } = findNodes( source, - ts.SyntaxKind.ImportDeclaration + tsModule.SyntaxKind.ImportDeclaration ) .map((node: ts.ImportDeclaration) => _angularImportsFromNode(node, source)) .reduce( @@ -106,13 +113,14 @@ export function getDecoratorMetadata( return getSourceNodes(source) .filter((node) => { return ( - node.kind == ts.SyntaxKind.Decorator && - (node as ts.Decorator).expression.kind == ts.SyntaxKind.CallExpression + node.kind == tsModule.SyntaxKind.Decorator && + (node as ts.Decorator).expression.kind == + tsModule.SyntaxKind.CallExpression ); }) .map((node) => (node as ts.Decorator).expression as ts.CallExpression) .filter((expr) => { - if (expr.expression.kind == ts.SyntaxKind.Identifier) { + if (expr.expression.kind == tsModule.SyntaxKind.Identifier) { const id = expr.expression as ts.Identifier; return ( @@ -120,12 +128,12 @@ export function getDecoratorMetadata( angularImports[id.getFullText(source)] === module ); } else if ( - expr.expression.kind == ts.SyntaxKind.PropertyAccessExpression + expr.expression.kind == tsModule.SyntaxKind.PropertyAccessExpression ) { // This covers foo.NgModule when importing * as foo. const paExpr = expr.expression as ts.PropertyAccessExpression; // If the left expression is not an identifier, just give up at that point. - if (paExpr.expression.kind !== ts.SyntaxKind.Identifier) { + if (paExpr.expression.kind !== tsModule.SyntaxKind.Identifier) { return false; } @@ -140,7 +148,7 @@ export function getDecoratorMetadata( .filter( (expr) => expr.arguments[0] && - expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression + expr.arguments[0].kind == tsModule.SyntaxKind.ObjectLiteralExpression ) .map((expr) => expr.arguments[0] as ts.ObjectLiteralExpression); } @@ -160,19 +168,22 @@ function _addSymbolToDecoratorMetadata( if (!node) { return source; } + if (!tsModule) { + tsModule = require('typescript'); + } // Get all the children property assignment of object literals. const matchingProperties: ts.ObjectLiteralElement[] = ( node as ts.ObjectLiteralExpression ).properties - .filter((prop) => prop.kind == ts.SyntaxKind.PropertyAssignment) + .filter((prop) => prop.kind == tsModule.SyntaxKind.PropertyAssignment) // Filter out every fields that's not "metadataField". Also handles string literals // (but not expressions). .filter((prop: ts.PropertyAssignment) => { const name = prop.name; switch (name.kind) { - case ts.SyntaxKind.Identifier: + case tsModule.SyntaxKind.Identifier: return (name as ts.Identifier).getText(source) == metadataField; - case ts.SyntaxKind.StringLiteral: + case tsModule.SyntaxKind.StringLiteral: return (name as ts.StringLiteral).text == metadataField; } @@ -211,7 +222,9 @@ function _addSymbolToDecoratorMetadata( const assignment = matchingProperties[0] as ts.PropertyAssignment; // If it's not an array, nothing we can do really. - if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) { + if ( + assignment.initializer.kind !== tsModule.SyntaxKind.ArrayLiteralExpression + ) { return source; } @@ -244,7 +257,7 @@ function _addSymbolToDecoratorMetadata( let toInsert: string; let position = node.getEnd(); - if (!isArray && node.kind == ts.SyntaxKind.ObjectLiteralExpression) { + if (!isArray && node.kind == tsModule.SyntaxKind.ObjectLiteralExpression) { // We haven't found the field in the metadata declaration. Insert a new // field. const expr = node as ts.ObjectLiteralExpression; @@ -264,7 +277,10 @@ function _addSymbolToDecoratorMetadata( toInsert = `, ${metadataField}: [${expression}]`; } } - } else if (!isArray && node.kind == ts.SyntaxKind.ArrayLiteralExpression) { + } else if ( + !isArray && + node.kind == tsModule.SyntaxKind.ArrayLiteralExpression + ) { // We found the field but it's empty. Insert it just before the `]`. position--; toInsert = `${expression}`; @@ -398,17 +414,22 @@ export function addImportToTestBed( specPath: string, symbolName: string ): ts.SourceFile { + if (!tsModule) { + tsModule = require('typescript'); + } const allCalls: ts.CallExpression[] = ( - findNodes(source, ts.SyntaxKind.CallExpression) + findNodes(source, tsModule.SyntaxKind.CallExpression) ); const configureTestingModuleObjectLiterals = allCalls - .filter((c) => c.expression.kind === ts.SyntaxKind.PropertyAccessExpression) + .filter( + (c) => c.expression.kind === tsModule.SyntaxKind.PropertyAccessExpression + ) .filter( (c: any) => c.expression.name.getText(source) === 'configureTestingModule' ) .map((c) => - c.arguments[0].kind === ts.SyntaxKind.ObjectLiteralExpression + c.arguments[0].kind === tsModule.SyntaxKind.ObjectLiteralExpression ? c.arguments[0] : null ); @@ -434,17 +455,22 @@ export function addDeclarationsToTestBed( specPath: string, symbolName: string[] ): ts.SourceFile { + if (!tsModule) { + tsModule = require('typescript'); + } const allCalls: ts.CallExpression[] = ( - findNodes(source, ts.SyntaxKind.CallExpression) + findNodes(source, tsModule.SyntaxKind.CallExpression) ); const configureTestingModuleObjectLiterals = allCalls - .filter((c) => c.expression.kind === ts.SyntaxKind.PropertyAccessExpression) + .filter( + (c) => c.expression.kind === tsModule.SyntaxKind.PropertyAccessExpression + ) .filter( (c: any) => c.expression.name.getText(source) === 'configureTestingModule' ) .map((c) => - c.arguments[0].kind === ts.SyntaxKind.ObjectLiteralExpression + c.arguments[0].kind === tsModule.SyntaxKind.ObjectLiteralExpression ? c.arguments[0] : null ); @@ -471,17 +497,22 @@ export function replaceIntoToTestBed( newSymbol: string, previousSymbol: string ): ts.SourceFile { + if (!tsModule) { + tsModule = require('typescript'); + } const allCalls: ts.CallExpression[] = ( - findNodes(source, ts.SyntaxKind.CallExpression) + findNodes(source, tsModule.SyntaxKind.CallExpression) ); const configureTestingModuleObjectLiterals = allCalls - .filter((c) => c.expression.kind === ts.SyntaxKind.PropertyAccessExpression) + .filter( + (c) => c.expression.kind === tsModule.SyntaxKind.PropertyAccessExpression + ) .filter( (c: any) => c.expression.name.getText(source) === 'configureTestingModule' ) .map((c) => - c.arguments[0].kind === ts.SyntaxKind.ObjectLiteralExpression + c.arguments[0].kind === tsModule.SyntaxKind.ObjectLiteralExpression ? c.arguments[0] : null ); @@ -560,6 +591,9 @@ export function addRouteToNgModule( function getListOfRoutes( source: ts.SourceFile ): ts.NodeArray | null { + if (!tsModule) { + tsModule = require('typescript'); + } const imports: any = getMatchingProperty( source, 'imports', @@ -567,11 +601,13 @@ function getListOfRoutes( '@angular/core' ); - if (imports?.initializer.kind === ts.SyntaxKind.ArrayLiteralExpression) { + if ( + imports?.initializer.kind === tsModule.SyntaxKind.ArrayLiteralExpression + ) { const a = imports.initializer as ts.ArrayLiteralExpression; for (const e of a.elements) { - if (e.kind === ts.SyntaxKind.CallExpression) { + if (e.kind === tsModule.SyntaxKind.CallExpression) { const ee = e as ts.CallExpression; const text = ee.expression.getText(source); if ( @@ -580,13 +616,13 @@ function getListOfRoutes( ee.arguments.length > 0 ) { const routes = ee.arguments[0]; - if (routes.kind === ts.SyntaxKind.ArrayLiteralExpression) { + if (routes.kind === tsModule.SyntaxKind.ArrayLiteralExpression) { return (routes as ts.ArrayLiteralExpression).elements; - } else if (routes.kind === ts.SyntaxKind.Identifier) { + } else if (routes.kind === tsModule.SyntaxKind.Identifier) { // find the array expression const variableDeclarations = findNodes( source, - ts.SyntaxKind.VariableDeclaration + tsModule.SyntaxKind.VariableDeclaration ) as ts.VariableDeclaration[]; const routesDeclaration = variableDeclarations.find((x) => { @@ -611,6 +647,7 @@ export function addProviderToBootstrapApplication( filePath: string, providerToAdd: string ) { + const { tsquery } = require('@phenomnomnominal/tsquery'); const PROVIDERS_ARRAY_SELECTOR = 'CallExpression:has(Identifier[name=bootstrapApplication]) ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=providers]) > ArrayLiteralExpression'; @@ -711,6 +748,9 @@ export function readBootstrapInfo( bootstrapComponentClassName: string; bootstrapComponentFileName: string; } { + if (!tsModule) { + tsModule = require('typescript'); + } const config = readProjectConfiguration(host, app); let mainPath; @@ -725,10 +765,10 @@ export function readBootstrapInfo( } const mainSource = host.read(mainPath)!.toString('utf-8'); - const main = ts.createSourceFile( + const main = tsModule.createSourceFile( mainPath, mainSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const moduleImports = getImport( @@ -743,19 +783,16 @@ export function readBootstrapInfo( b.endsWith('Module') )[0]; - const modulePath = `${path.join( - path.dirname(mainPath), - moduleImport.moduleSpec - )}.ts`; + const modulePath = `${join(dirname(mainPath), moduleImport.moduleSpec)}.ts`; if (!host.exists(modulePath)) { throw new Error(`Cannot find '${modulePath}'`); } const moduleSourceText = host.read(modulePath)!.toString('utf-8'); - const moduleSource = ts.createSourceFile( + const moduleSource = tsModule.createSourceFile( modulePath, moduleSourceText, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); @@ -763,8 +800,8 @@ export function readBootstrapInfo( moduleSource, moduleClassName ); - const bootstrapComponentFileName = `./${path.join( - path.dirname(moduleImport.moduleSpec), + const bootstrapComponentFileName = `./${join( + dirname(moduleImport.moduleSpec), `${ names( bootstrapComponentClassName.substring( @@ -793,11 +830,14 @@ export function getDecoratorPropertyValueNode( property: string, module: string ) { + if (!tsModule) { + tsModule = require('typescript'); + } const moduleSourceText = host.read(modulePath)!.toString('utf-8'); - const moduleSource = ts.createSourceFile( + const moduleSource = tsModule.createSourceFile( modulePath, moduleSourceText, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const templateNode = getMatchingProperty( @@ -815,17 +855,20 @@ function getMatchingObjectLiteralElement( source: ts.SourceFile, property: string ) { + if (!tsModule) { + tsModule = require('typescript'); + } return ( (node as ts.ObjectLiteralExpression).properties - .filter((prop) => prop.kind == ts.SyntaxKind.PropertyAssignment) + .filter((prop) => prop.kind == tsModule.SyntaxKind.PropertyAssignment) // Filter out every fields that's not "metadataField". Also handles string literals // (but not expressions). .filter((prop: ts.PropertyAssignment) => { const name = prop.name; switch (name.kind) { - case ts.SyntaxKind.Identifier: + case tsModule.SyntaxKind.Identifier: return (name as ts.Identifier).getText(source) === property; - case ts.SyntaxKind.StringLiteral: + case tsModule.SyntaxKind.StringLiteral: return (name as ts.StringLiteral).text === property; } return false; @@ -834,15 +877,18 @@ function getMatchingObjectLiteralElement( } export function getTsSourceFile(host: Tree, path: string): ts.SourceFile { + if (!tsModule) { + tsModule = require('typescript'); + } const buffer = host.read(path); if (!buffer) { throw new Error(`Could not read TS file (${path}).`); } const content = buffer.toString(); - const source = ts.createSourceFile( + const source = tsModule.createSourceFile( path, content, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/angular/src/utils/nx-devkit/route-utils.ts b/packages/angular/src/utils/nx-devkit/route-utils.ts index 4c17999fbe7b4..5f02234b959e0 100644 --- a/packages/angular/src/utils/nx-devkit/route-utils.ts +++ b/packages/angular/src/utils/nx-devkit/route-utils.ts @@ -1,9 +1,9 @@ import { Tree } from '@nrwl/devkit'; -import { tsquery } from '@phenomnomnominal/tsquery'; -import * as ts from 'typescript'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { addRouteToNgModule } from './ast-utils'; +let tsModule: typeof import('typescript'); + export function addRoute( tree: Tree, routesFile: string, @@ -17,14 +17,18 @@ export function addRoute( `Path to parent routing declaration (${routesFile}) does not exist. Please ensure path is correct.` ); } + if (!tsModule) { + tsModule = require('typescript'); + } + const { tsquery } = require('@phenomnomnominal/tsquery'); let routesFileContents = tree.read(routesFile, 'utf-8'); if (!lazy) { - let parentSourceFile = ts.createSourceFile( + let parentSourceFile = tsModule.createSourceFile( routesFile, routesFileContents, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); @@ -51,10 +55,10 @@ export function addRoute( if (!isRoutesArray) { if (routesFileContents.includes('@NgModule')) { - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( routesFile, routesFileContents, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); @@ -91,6 +95,7 @@ export function addProviderToRoute( ); } + const { tsquery } = require('@phenomnomnominal/tsquery'); let routesFileContents = tree.read(routesFile, 'utf-8'); const ast = tsquery.ast(routesFileContents); diff --git a/packages/cypress/package.json b/packages/cypress/package.json index c6fed3ff65d59..9e210cf0a9570 100644 --- a/packages/cypress/package.json +++ b/packages/cypress/package.json @@ -35,6 +35,7 @@ }, "dependencies": { "@nrwl/devkit": "file:../devkit", + "@nrwl/js": "file:../js", "@nrwl/linter": "file:../linter", "@nrwl/workspace": "file:../workspace", "@phenomnomnominal/tsquery": "4.1.1", diff --git a/packages/cypress/src/generators/cypress-project/cypress-project.ts b/packages/cypress/src/generators/cypress-project/cypress-project.ts index 66dec822dad1e..39ccb515f25c0 100644 --- a/packages/cypress/src/generators/cypress-project/cypress-project.ts +++ b/packages/cypress/src/generators/cypress-project/cypress-project.ts @@ -5,6 +5,7 @@ import { extractLayoutDirectory, formatFiles, generateFiles, + GeneratorCallback, getProjects, getWorkspaceLayout, joinPathFragments, @@ -20,7 +21,10 @@ import { } from '@nrwl/devkit'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { + initGenerator as jsInitGenerator, + getRelativePathToRootTsConfig, +} from '@nrwl/js'; import { globalJavaScriptOverrides, globalTypeScriptOverrides, @@ -261,7 +265,11 @@ export async function addLinter(host: Tree, options: CypressProjectSchema) { export async function cypressProjectGenerator(host: Tree, schema: Schema) { const options = normalizeOptions(host, schema); - const tasks = []; + await jsInitGenerator(host, { + js: schema.js, + skipFormat: true, + }); + const tasks: GeneratorCallback[] = []; const cypressVersion = installedCypressVersion(); // if there is an installed cypress version, then we don't call // init since we want to keep the existing version that is installed diff --git a/packages/cypress/src/generators/migrate-to-cypress-11/conversion.util.ts b/packages/cypress/src/generators/migrate-to-cypress-11/conversion.util.ts index 6f8a18e270c70..5e78ee93a8fc0 100644 --- a/packages/cypress/src/generators/migrate-to-cypress-11/conversion.util.ts +++ b/packages/cypress/src/generators/migrate-to-cypress-11/conversion.util.ts @@ -8,14 +8,11 @@ import { visitNotIgnoredFiles, normalizePath, } from '@nrwl/devkit'; -import { tsquery } from '@phenomnomnominal/tsquery'; import { basename, dirname, extname, relative } from 'path'; -import { - isCallExpression, - isExportDeclaration, - isImportDeclaration, - StringLiteral, -} from 'typescript'; +import type { StringLiteral } from 'typescript'; + +let tsModule: typeof import('typescript'); +let tsquery: typeof import('@phenomnomnominal/tsquery').tsquery; const validFilesEndingsToUpdate = [ '.js', @@ -272,6 +269,14 @@ export function updateImports( oldImportPath: string, newImportPath: string ) { + if (!tsquery) { + tsquery = require('@phenomnomnominal/tsquery').tsquery; + } + if (!tsModule) { + tsModule = require('typescript'); + } + const { isCallExpression, isExportDeclaration, isImportDeclaration } = + tsModule; const endOfImportSelector = `StringLiteral[value=/${oldImportPath}$/]`; const fileContent = tree.read(filePath, 'utf-8'); const newContent = tsquery.replace( diff --git a/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.ts b/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.ts index 844fe4e3d79c6..481670176b732 100644 --- a/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.ts +++ b/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.ts @@ -15,7 +15,6 @@ import { } from '@nrwl/devkit'; import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; import { CypressExecutorOptions } from '../../executors/cypress/cypress.impl'; -import { cypressVersion } from '../../utils/versions'; import { addConfigToTsConfig, createNewCypressConfig, diff --git a/packages/detox/package.json b/packages/detox/package.json index 4991d746fe351..4a146872139f1 100644 --- a/packages/detox/package.json +++ b/packages/detox/package.json @@ -27,6 +27,7 @@ "dependencies": { "@nrwl/devkit": "file:../devkit", "@nrwl/jest": "file:../jest", + "@nrwl/js": "file:../js", "@nrwl/linter": "file:../linter", "@nrwl/react": "file:../react", "@nrwl/workspace": "file:../workspace" diff --git a/packages/detox/src/generators/application/lib/create-files.ts b/packages/detox/src/generators/application/lib/create-files.ts index 3759757aa6756..b63df109c4fa3 100644 --- a/packages/detox/src/generators/application/lib/create-files.ts +++ b/packages/detox/src/generators/application/lib/create-files.ts @@ -6,7 +6,7 @@ import { toJS, Tree, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { join } from 'path'; import { NormalizedSchema } from './normalize-options'; diff --git a/packages/devkit/src/utils/package-json.spec.ts b/packages/devkit/src/utils/package-json.spec.ts index bf052b1a53c28..f68cf999ce0b3 100644 --- a/packages/devkit/src/utils/package-json.spec.ts +++ b/packages/devkit/src/utils/package-json.spec.ts @@ -459,27 +459,27 @@ describe('ensurePackage', () => { it('should return successfully when package is present', async () => { writeJson(tree, 'package.json', {}); - await expect( + expect( ensurePackage(tree, '@nrwl/devkit', '>=15.0.0', { throwOnMissing: true, }) - ).resolves.toBeUndefined(); // return void + ).toBeUndefined(); // return void }); it('should throw when dependencies are missing', async () => { writeJson(tree, 'package.json', {}); - await expect(() => + expect(() => ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', { throwOnMissing: true, }) - ).rejects.toThrow(/-D( -W)? @nrwl\/does-not-exist@>=15.0.0/); + ).toThrow(/-D( -W)? @nrwl\/does-not-exist@>=15.0.0/); - await expect(() => + expect(() => ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', { dev: false, throwOnMissing: true, }) - ).rejects.toThrow('@nrwl/does-not-exist@>=15.0.0'); + ).toThrow('@nrwl/does-not-exist@>=15.0.0'); }); }); diff --git a/packages/devkit/src/utils/package-json.ts b/packages/devkit/src/utils/package-json.ts index 2cf180408bac9..a4660321c94bc 100644 --- a/packages/devkit/src/utils/package-json.ts +++ b/packages/devkit/src/utils/package-json.ts @@ -372,7 +372,7 @@ function requiresRemovingOfPackages( * * For example: * ```typescript - * ensurePackage(tree, {}, { '@nrwl/jest': nxVersion }) + * ensurePackage(tree, '@nrwl/jest', nxVersion) * ``` * This will check that @nrwl/jest@ exists in devDependencies. * If it exists then function returns, otherwise it will install the package before continuing. @@ -382,9 +382,8 @@ function requiresRemovingOfPackages( * @param pkg the package to check (e.g. @nrwl/jest) * @param requiredVersion the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0) * @param {EnsurePackageOptions} options - * @returns {Promise} */ -export async function ensurePackage( +export function ensurePackage( tree: Tree, pkg: string, requiredVersion: string, @@ -392,7 +391,7 @@ export async function ensurePackage( dev?: boolean; throwOnMissing?: boolean; } = {} -): Promise { +): void { // Read package and version from root package.json file. const dev = options.dev ?? true; const throwOnMissing = options.throwOnMissing ?? !!process.env.NX_DRY_RUN; // NX_DRY_RUN is set in `packages/nx/src/command-line/generate.ts` diff --git a/packages/expo/package.json b/packages/expo/package.json index 8c326c1861de8..102372ebd4435 100644 --- a/packages/expo/package.json +++ b/packages/expo/package.json @@ -29,6 +29,7 @@ "@nrwl/detox": "file:../detox", "@nrwl/devkit": "file:../devkit", "@nrwl/jest": "file:../jest", + "@nrwl/js": "file:../js", "@nrwl/linter": "file:../linter", "@nrwl/react": "file:../react", "@nrwl/webpack": "file:../webpack", diff --git a/packages/expo/src/generators/init/init.ts b/packages/expo/src/generators/init/init.ts index 486c51e62ee6d..38d13e9ea7140 100644 --- a/packages/expo/src/generators/init/init.ts +++ b/packages/expo/src/generators/init/init.ts @@ -2,6 +2,7 @@ import { addDependenciesToPackageJson, convertNxGenerator, formatFiles, + GeneratorCallback, removeDependenciesFromPackageJson, Tree, } from '@nrwl/devkit'; @@ -34,6 +35,7 @@ import { import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { jestInitGenerator } from '@nrwl/jest'; import { detoxInitGenerator } from '@nrwl/detox'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { addGitIgnoreEntry } from './lib/add-git-ignore-entry'; import { initRootBabelConfig } from './lib/init-root-babel-config'; @@ -41,8 +43,12 @@ import { initRootBabelConfig } from './lib/init-root-babel-config'; export async function expoInitGenerator(host: Tree, schema: Schema) { addGitIgnoreEntry(host); initRootBabelConfig(host); + await jsInitGenerator(host, { + js: schema.js, + skipFormat: true, + }); - const tasks = []; + const tasks: GeneratorCallback[] = []; if (!schema.skipPackageJson) { tasks.push(moveDependency(host)); @@ -50,7 +56,7 @@ export async function expoInitGenerator(host: Tree, schema: Schema) { } if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') { - const jestTask = jestInitGenerator(host, {}); + const jestTask = await jestInitGenerator(host, {}); tasks.push(jestTask); } diff --git a/packages/expo/src/generators/init/schema.d.ts b/packages/expo/src/generators/init/schema.d.ts index a09789f88ae8b..78ab8ce76b679 100644 --- a/packages/expo/src/generators/init/schema.d.ts +++ b/packages/expo/src/generators/init/schema.d.ts @@ -3,4 +3,5 @@ export interface Schema { skipFormat?: boolean; e2eTestRunner?: 'detox' | 'none'; skipPackageJson?: boolean; // default is false + js?: boolean; } diff --git a/packages/expo/src/generators/init/schema.json b/packages/expo/src/generators/init/schema.json index e3b7a158003e7..e36c5eefcbcb6 100644 --- a/packages/expo/src/generators/init/schema.json +++ b/packages/expo/src/generators/init/schema.json @@ -25,8 +25,13 @@ }, "skipPackageJson": { "type": "boolean", - "description": "Do not add dependencies to `package.json`.", - "default": false + "default": false, + "description": "Do not add dependencies to `package.json`." + }, + "js": { + "type": "boolean", + "default": false, + "description": "Use JavaScript instead of TypeScript" } }, "required": [] diff --git a/packages/expo/src/generators/library/lib/normalize-options.ts b/packages/expo/src/generators/library/lib/normalize-options.ts index 60f6bee1ad2c6..8428f8523b35c 100644 --- a/packages/expo/src/generators/library/lib/normalize-options.ts +++ b/packages/expo/src/generators/library/lib/normalize-options.ts @@ -1,4 +1,5 @@ import { + getImportPath, getWorkspaceLayout, joinPathFragments, names, @@ -34,7 +35,8 @@ export function normalizeOptions( ? options.tags.split(',').map((s) => s.trim()) : []; - const importPath = options.importPath || `@${npmScope}/${projectDirectory}`; + const importPath = + options.importPath || getImportPath(npmScope, projectDirectory); const appMain = options.js ? 'src/index.js' : 'src/index.ts'; diff --git a/packages/expo/src/generators/library/library.ts b/packages/expo/src/generators/library/library.ts index 27f7ab54783bd..c4af21134efc8 100644 --- a/packages/expo/src/generators/library/library.ts +++ b/packages/expo/src/generators/library/library.ts @@ -14,6 +14,7 @@ import { updateJson, } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { updateRootTsConfig } from '@nrwl/js'; import init from '../init/init'; import { addLinting } from '../../utils/add-linting'; @@ -52,7 +53,7 @@ export async function expoLibraryGenerator( ); if (!options.skipTsConfig) { - updateBaseTsConfig(host, options); + updateRootTsConfig(host, options); } const jestTask = await addJest( @@ -131,31 +132,6 @@ function updateTsConfig(tree: Tree, options: NormalizedSchema) { ); } -function updateBaseTsConfig(host: Tree, options: NormalizedSchema) { - updateJson(host, 'tsconfig.base.json', (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - const { libsDir } = getWorkspaceLayout(host); - - c.paths[options.importPath] = [ - maybeJs( - options, - joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`) - ), - ]; - - return json; - }); -} - function createFiles(host: Tree, options: NormalizedSchema) { generateFiles( host, diff --git a/packages/jest/package.json b/packages/jest/package.json index 0590ba69311ea..1a907a464337a 100644 --- a/packages/jest/package.json +++ b/packages/jest/package.json @@ -37,6 +37,7 @@ "@jest/reporters": "28.1.1", "@jest/test-result": "28.1.1", "@nrwl/devkit": "file:../devkit", + "@nrwl/js": "file:../js", "@phenomnomnominal/tsquery": "4.1.1", "chalk": "^4.1.0", "dotenv": "~10.0.0", diff --git a/packages/jest/src/generators/init/init.spec.ts b/packages/jest/src/generators/init/init.spec.ts index 685df1d3e042c..b3091ca1039be 100644 --- a/packages/jest/src/generators/init/init.spec.ts +++ b/packages/jest/src/generators/init/init.spec.ts @@ -19,7 +19,7 @@ describe('jest', () => { }); it('should generate files with --js flag', async () => { - jestInitGenerator(tree, { js: true }); + await jestInitGenerator(tree, { js: true }); expect(tree.exists('jest.config.js')).toBeTruthy(); expect( @@ -31,7 +31,7 @@ describe('jest', () => { }); it('should generate files ', async () => { - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); expect(tree.exists('jest.config.ts')).toBeTruthy(); expect( @@ -64,7 +64,7 @@ export default { } `; tree.write('jest.config.ts', expected); - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); expect(tree.read('jest.config.ts', 'utf-8')).toEqual(expected); }); @@ -75,7 +75,7 @@ export default { return json; }); - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); const productionFileSet = readJson(tree, 'nx.json') .namedInputs.production; @@ -98,7 +98,7 @@ export default { return json; }); - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); let nxJson: NxJsonConfiguration; updateJson(tree, 'nx.json', (json) => { @@ -119,12 +119,12 @@ export default { nxJson = json; return json; }); - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); expect(readJson(tree, 'nx.json')).toEqual(nxJson); }); it('should add dependencies', async () => { - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); const packageJson = readJson(tree, 'package.json'); expect(packageJson.devDependencies.jest).toBeDefined(); expect(packageJson.devDependencies['@nrwl/jest']).toBeDefined(); @@ -133,46 +133,46 @@ export default { expect(packageJson.devDependencies['ts-node']).toBeDefined(); }); - it('should make js jest files', () => { - jestInitGenerator(tree, { js: true }); + it('should make js jest files', async () => { + await jestInitGenerator(tree, { js: true }); expect(tree.exists('jest.config.js')).toBeTruthy(); expect(tree.exists('jest.preset.js')).toBeTruthy(); }); describe('Deprecated: --babelJest', () => { it('should add babel dependencies', async () => { - jestInitGenerator(tree, { babelJest: true }); + await jestInitGenerator(tree, { babelJest: true }); const packageJson = readJson(tree, 'package.json'); expect(packageJson.devDependencies['babel-jest']).toBeDefined(); }); }); describe('--compiler', () => { - it('should support tsc compiler', () => { - jestInitGenerator(tree, { compiler: 'tsc' }); + it('should support tsc compiler', async () => { + await jestInitGenerator(tree, { compiler: 'tsc' }); const packageJson = readJson(tree, 'package.json'); expect(packageJson.devDependencies['ts-jest']).toBeDefined(); }); - it('should support babel compiler', () => { - jestInitGenerator(tree, { compiler: 'babel' }); + it('should support babel compiler', async () => { + await jestInitGenerator(tree, { compiler: 'babel' }); const packageJson = readJson(tree, 'package.json'); expect(packageJson.devDependencies['babel-jest']).toBeDefined(); }); - it('should support swc compiler', () => { - jestInitGenerator(tree, { compiler: 'swc' }); + it('should support swc compiler', async () => { + await jestInitGenerator(tree, { compiler: 'swc' }); const packageJson = readJson(tree, 'package.json'); expect(packageJson.devDependencies['@swc/jest']).toBeDefined(); }); }); describe('root project', () => { - it('should not add a monorepo jest.config.ts to the project', () => { - jestInitGenerator(tree, { rootProject: true }); + it('should not add a monorepo jest.config.ts to the project', async () => { + await jestInitGenerator(tree, { rootProject: true }); expect(tree.exists('jest.config.ts')).toBeFalsy(); }); - it('should rename the project jest.config.ts to project jest config', () => { + it('should rename the project jest.config.ts to project jest config', async () => { addProjectConfiguration(tree, 'my-project', { root: '.', name: 'my-project', @@ -202,7 +202,7 @@ export default { }; ` ); - jestInitGenerator(tree, { rootProject: false }); + await jestInitGenerator(tree, { rootProject: false }); expect(tree.exists('jest.config.app.ts')).toBeTruthy(); expect(tree.read('jest.config.ts', 'utf-8')) .toEqual(`import { getJestProjects } from '@nrwl/jest'; @@ -221,7 +221,7 @@ projects: getJestProjects() `); }); - it('should work with --js', () => { + it('should work with --js', async () => { addProjectConfiguration(tree, 'my-project', { root: '.', name: 'my-project', @@ -251,7 +251,7 @@ module.exports = { }; ` ); - jestInitGenerator(tree, { js: true, rootProject: false }); + await jestInitGenerator(tree, { js: true, rootProject: false }); expect(tree.exists('jest.config.app.js')).toBeTruthy(); expect(tree.read('jest.config.js', 'utf-8')) .toEqual(`const { getJestProjects } = require('@nrwl/jest'); @@ -275,7 +275,7 @@ projects: getJestProjects() }); it('should add the jest extension to the recommended property', async () => { - jestInitGenerator(tree, {}); + await jestInitGenerator(tree, {}); const extensionsJson = readJson(tree, '.vscode/extensions.json'); expect(extensionsJson).toMatchInlineSnapshot(` Object { diff --git a/packages/jest/src/generators/init/init.ts b/packages/jest/src/generators/init/init.ts index f5480ca9ba2bc..9cf32e6f38964 100644 --- a/packages/jest/src/generators/init/init.ts +++ b/packages/jest/src/generators/init/init.ts @@ -11,6 +11,8 @@ import { updateNxJson, updateProjectConfiguration, } from '@nrwl/devkit'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; +import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { findRootJestConfig } from '../../utils/config/find-root-jest-files'; import { babelJestVersion, @@ -184,18 +186,27 @@ function updateExtensions(host: Tree) { }); } -export function jestInitGenerator(tree: Tree, schema: JestInitSchema) { +export async function jestInitGenerator( + tree: Tree, + schema: JestInitSchema +): Promise { const options = normalizeOptions(schema); + await jsInitGenerator(tree, { + js: schema.js, + skipFormat: true, + }); + const tasks: GeneratorCallback[] = []; + createJestConfig(tree, options); - let installTask: GeneratorCallback = () => {}; if (!options.skipPackageJson) { removeDependenciesFromPackageJson(tree, ['@nrwl/jest'], []); - installTask = updateDependencies(tree, options); + const installTask = updateDependencies(tree, options); + tasks.push(installTask); } updateExtensions(tree); - return installTask; + return runTasksInSerial(...tasks); } function normalizeOptions(options: JestInitSchema) { diff --git a/packages/jest/src/generators/jest-project/jest-project.ts b/packages/jest/src/generators/jest-project/jest-project.ts index f4a5d5c14da91..315f43397c9da 100644 --- a/packages/jest/src/generators/jest-project/jest-project.ts +++ b/packages/jest/src/generators/jest-project/jest-project.ts @@ -4,7 +4,12 @@ import { createFiles } from './lib/create-files'; import { updateTsConfig } from './lib/update-tsconfig'; import { updateWorkspace } from './lib/update-workspace'; import { JestProjectSchema } from './schema'; -import { formatFiles, Tree, convertNxGenerator } from '@nrwl/devkit'; +import { + formatFiles, + Tree, + convertNxGenerator, + GeneratorCallback, +} from '@nrwl/devkit'; const schemaDefaults = { setupFile: 'none', @@ -51,9 +56,9 @@ function normalizeOptions(options: JestProjectSchema) { export async function jestProjectGenerator( tree: Tree, schema: JestProjectSchema -) { +): Promise { const options = normalizeOptions(schema); - const installTask = init(tree, options); + const installTask = await init(tree, options); checkForTestTarget(tree, options); createFiles(tree, options); diff --git a/packages/jest/src/utils/config/functions.ts b/packages/jest/src/utils/config/functions.ts index 571ed6cc02ab5..e3eb572067336 100644 --- a/packages/jest/src/utils/config/functions.ts +++ b/packages/jest/src/utils/config/functions.ts @@ -1,9 +1,11 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit'; import { Config } from '@jest/types'; import { createContext, runInContext } from 'vm'; import { dirname, join } from 'path'; +let tsModule: typeof import('typescript'); + function makeTextToInsert( value: unknown, precedingCommaNeeded: boolean @@ -15,8 +17,12 @@ function findPropertyAssignment( object: ts.ObjectLiteralExpression, propertyName: string ) { + if (!tsModule) { + tsModule = require('typescript'); + } + return object.properties.find((prop) => { - if (!ts.isPropertyAssignment(prop)) { + if (!tsModule.isPropertyAssignment(prop)) { return false; } const propNameText = prop.name.getText(); @@ -35,6 +41,11 @@ export function addOrUpdateProperty( value: unknown, path: string ) { + if (!tsModule) { + tsModule = require('typescript'); + } + const { SyntaxKind } = tsModule; + const propertyName = properties.shift(); const propertyAssignment = findPropertyAssignment(object, propertyName); @@ -42,10 +53,10 @@ export function addOrUpdateProperty( if (propertyAssignment) { if ( - propertyAssignment.initializer.kind === ts.SyntaxKind.StringLiteral || - propertyAssignment.initializer.kind === ts.SyntaxKind.NumericLiteral || - propertyAssignment.initializer.kind === ts.SyntaxKind.FalseKeyword || - propertyAssignment.initializer.kind === ts.SyntaxKind.TrueKeyword + propertyAssignment.initializer.kind === SyntaxKind.StringLiteral || + propertyAssignment.initializer.kind === SyntaxKind.NumericLiteral || + propertyAssignment.initializer.kind === SyntaxKind.FalseKeyword || + propertyAssignment.initializer.kind === SyntaxKind.TrueKeyword ) { const updatedContents = applyChangesToString(originalContents, [ { @@ -65,8 +76,7 @@ export function addOrUpdateProperty( } if ( - propertyAssignment.initializer.kind === - ts.SyntaxKind.ArrayLiteralExpression + propertyAssignment.initializer.kind === SyntaxKind.ArrayLiteralExpression ) { const arrayLiteral = propertyAssignment.initializer as ts.ArrayLiteralExpression; @@ -106,8 +116,7 @@ export function addOrUpdateProperty( return; } } else if ( - propertyAssignment.initializer.kind === - ts.SyntaxKind.ObjectLiteralExpression + propertyAssignment.initializer.kind === SyntaxKind.ObjectLiteralExpression ) { return addOrUpdateProperty( tree, @@ -143,6 +152,10 @@ export function removeProperty( object: ts.ObjectLiteralExpression, properties: string[] ): ts.PropertyAssignment | null { + if (!tsModule) { + tsModule = require('typescript'); + } + const propertyName = properties.shift(); const propertyAssignment = findPropertyAssignment(object, propertyName); @@ -150,7 +163,7 @@ export function removeProperty( if ( properties.length > 0 && propertyAssignment.initializer.kind === - ts.SyntaxKind.ObjectLiteralExpression + tsModule.SyntaxKind.ObjectLiteralExpression ) { return removeProperty( propertyAssignment.initializer as ts.ObjectLiteralExpression, @@ -164,20 +177,28 @@ export function removeProperty( } function isModuleExport(node: ts.Statement) { + if (!tsModule) { + tsModule = require('typescript'); + } + return ( - ts.isExpressionStatement(node) && + tsModule.isExpressionStatement(node) && node.expression?.kind && - ts.isBinaryExpression(node.expression) && + tsModule.isBinaryExpression(node.expression) && node.expression.left.getText() === 'module.exports' && - node.expression.operatorToken?.kind === ts.SyntaxKind.EqualsToken + node.expression.operatorToken?.kind === tsModule.SyntaxKind.EqualsToken ); } function isDefaultExport(node: ts.Statement) { + if (!tsModule) { + tsModule = require('typescript'); + } + return ( - ts.isExportAssignment(node) && + tsModule.isExportAssignment(node) && node.expression?.kind && - ts.isObjectLiteralExpression(node.expression) && + tsModule.isObjectLiteralExpression(node.expression) && node.getText().startsWith('export default') ); } @@ -188,10 +209,14 @@ function isDefaultExport(node: ts.Statement) { export function jestConfigObjectAst( fileContent: string ): ts.ObjectLiteralExpression { - const sourceFile = ts.createSourceFile( + if (!tsModule) { + tsModule = require('typescript'); + } + + const sourceFile = tsModule.createSourceFile( 'jest.config.ts', fileContent, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); @@ -200,7 +225,7 @@ export function jestConfigObjectAst( ); let ast: ts.ObjectLiteralExpression; - if (ts.isExpressionStatement(exportStatement)) { + if (tsModule.isExpressionStatement(exportStatement)) { const moduleExports = exportStatement.expression as ts.BinaryExpression; if (!moduleExports) { throw new Error( @@ -211,7 +236,7 @@ export function jestConfigObjectAst( } ast = moduleExports.right as ts.ObjectLiteralExpression; - } else if (ts.isExportAssignment(exportStatement)) { + } else if (tsModule.isExportAssignment(exportStatement)) { const defaultExport = exportStatement.expression as ts.ObjectLiteralExpression; @@ -233,7 +258,7 @@ export function jestConfigObjectAst( ); } - if (!ts.isObjectLiteralExpression(ast)) { + if (!tsModule.isObjectLiteralExpression(ast)) { throw new Error( `The 'export default' or 'module.exports' expression is not an object literal.` ); diff --git a/packages/js/generators.json b/packages/js/generators.json index 46e4249744b89..1913a999db978 100644 --- a/packages/js/generators.json +++ b/packages/js/generators.json @@ -14,7 +14,7 @@ "schema": "./src/generators/init/schema.json", "aliases": ["lib"], "x-type": "init", - "description": "Init placeholder.", + "description": "Initialize a TS/JS workspace.", "hidden": true }, "convert-to-swc": { @@ -38,7 +38,7 @@ "schema": "./src/generators/init/schema.json", "aliases": ["lib"], "x-type": "init", - "description": "Init placeholder.", + "description": "Initialize a TS/JS workspace.", "hidden": true }, "convert-to-swc": { diff --git a/packages/js/package.json b/packages/js/package.json index 79a2278d67da4..0d0bd42e8c99d 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -40,7 +40,6 @@ "@babel/preset-typescript": "^7.15.0", "@babel/runtime": "^7.14.8", "@nrwl/devkit": "file:../devkit", - "@nrwl/linter": "file:../linter", "@nrwl/workspace": "file:../workspace", "babel-plugin-const-enum": "^1.0.1", "babel-plugin-macros": "^2.8.0", diff --git a/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts b/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts index 54ba71097aaa7..1387930af3dee 100644 --- a/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts +++ b/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts @@ -2,7 +2,7 @@ import { readProjectConfiguration, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { join } from 'path'; import { LibraryGeneratorSchema } from '../../utils/schema'; -import { libraryGenerator } from '../library/library'; +import { libraryGenerator as jsLibraryGenerator } from '../library/library'; import { convertToSwcGenerator } from './convert-to-swc'; describe('convert to swc', () => { @@ -28,7 +28,7 @@ describe('convert to swc', () => { }); it('should convert tsc to swc', async () => { - await libraryGenerator(tree, { + await jsLibraryGenerator(tree, { ...defaultLibGenerationOptions, name: 'tsc-lib', buildable: true, diff --git a/packages/workspace/src/generators/new/files-integrated-repo/tsconfig.base.json b/packages/js/src/generators/init/files/tsconfig.base.json similarity index 100% rename from packages/workspace/src/generators/new/files-integrated-repo/tsconfig.base.json rename to packages/js/src/generators/init/files/tsconfig.base.json diff --git a/packages/js/src/generators/init/init.ts b/packages/js/src/generators/init/init.ts index b6cf117dbbdd6..b771a2d8adc32 100644 --- a/packages/js/src/generators/init/init.ts +++ b/packages/js/src/generators/init/init.ts @@ -1,10 +1,33 @@ -import { convertNxGenerator, logger } from '@nrwl/devkit'; +import { + convertNxGenerator, + ensurePackage, + formatFiles, + generateFiles, + joinPathFragments, + Tree, +} from '@nrwl/devkit'; +import { getRootTsConfigFileName } from '../../utils/typescript/ts-config'; +import { typescriptVersion } from '../../utils/versions'; +import { InitSchema } from './schema'; -export async function initGenerator() { - logger.info( - 'This is a placeholder for @nrwl/js:init generator. If you want to create a library, use @nrwl/js:lib instead' - ); +export async function initGenerator( + host: Tree, + schema: InitSchema +): Promise { + if (!schema.js) { + ensurePackage(host, 'typescript', typescriptVersion); + } + + // add tsconfig.base.json + if (!getRootTsConfigFileName()) { + generateFiles(host, joinPathFragments(__dirname, './files'), '.', {}); + } + + if (!schema.skipFormat) { + await formatFiles(host); + } } export default initGenerator; + export const initSchematic = convertNxGenerator(initGenerator); diff --git a/packages/js/src/generators/init/schema.d.ts b/packages/js/src/generators/init/schema.d.ts new file mode 100644 index 0000000000000..6fef81d0b67dc --- /dev/null +++ b/packages/js/src/generators/init/schema.d.ts @@ -0,0 +1,4 @@ +export interface InitSchema { + js?: boolean; + skipFormat?: boolean; +} diff --git a/packages/js/src/generators/init/schema.json b/packages/js/src/generators/init/schema.json index 00e651cc61390..3b4fe1cba57ae 100644 --- a/packages/js/src/generators/init/schema.json +++ b/packages/js/src/generators/init/schema.json @@ -3,5 +3,19 @@ "$id": "NxTypescriptInit", "cli": "nx", "title": "Init nrwl/js", - "description": "Init generator placeholder for nrwl/js." + "description": "Init generator placeholder for nrwl/js.", + "properties": { + "js": { + "type": "boolean", + "default": false, + "description": "Use JavaScript instead of TypeScript" + }, + "skipFormat": { + "type": "boolean", + "aliases": ["skip-format"], + "description": "Skip formatting files.", + "default": true, + "x-priority": "internal" + } + } } diff --git a/packages/js/src/generators/library/library.ts b/packages/js/src/generators/library/library.ts index 8f767667c07da..8c1b094c9d86a 100644 --- a/packages/js/src/generators/library/library.ts +++ b/packages/js/src/generators/library/library.ts @@ -19,12 +19,13 @@ import { writeJson, } from '@nrwl/devkit'; import { getImportPath } from 'nx/src/utils/path'; -import { Linter, lintProjectGenerator } from '@nrwl/linter'; +// nx-ignore-next-line +const { Linter } = require('@nrwl/linter'); // use require to import to avoid circular dependency import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { getRelativePathToRootTsConfig, - getRootTsConfigPathInTree, -} from '@nrwl/workspace/src/utilities/typescript'; + updateRootTsConfig, +} from '../../utils/typescript/ts-config'; import { join } from 'path'; import { addMinimalPublishScript } from '../../utils/minimal-publish-script'; import { LibraryGeneratorSchema } from '../../utils/schema'; @@ -35,6 +36,7 @@ import { nxVersion, typesNodeVersion, } from '../../utils/versions'; +import jsInitGenerator from '../init/init'; export async function libraryGenerator( tree: Tree, @@ -54,6 +56,10 @@ export async function projectGenerator( destinationDir: string, filesDir: string ) { + await jsInitGenerator(tree, { + js: schema.js, + skipFormat: true, + }); const tasks: GeneratorCallback[] = []; const options = normalizeOptions(tree, schema, destinationDir); @@ -64,7 +70,7 @@ export async function projectGenerator( tasks.push(addProjectDependencies(tree, options)); if (options.bundler === 'vite') { - await ensurePackage(tree, '@nrwl/vite', nxVersion); + ensurePackage(tree, '@nrwl/vite', nxVersion); // nx-ignore-next-line const { viteConfigurationGenerator } = require('@nrwl/vite'); const viteTask = await viteConfigurationGenerator(tree, { @@ -77,10 +83,6 @@ export async function projectGenerator( tasks.push(viteTask); } - if (!schema.skipTsConfig) { - updateRootTsConfig(tree, options); - } - if (schema.bundler === 'webpack' || schema.bundler === 'rollup') { ensureBabelRootConfigExists(tree); } @@ -99,7 +101,7 @@ export async function projectGenerator( options.unitTestRunner === 'vitest' && options.bundler !== 'vite' // Test would have been set up already ) { - await ensurePackage(tree, '@nrwl/vite', nxVersion); + ensurePackage(tree, '@nrwl/vite', nxVersion); // nx-ignore-next-line const { vitestGenerator } = require('@nrwl/vite'); const vitestTask = await vitestGenerator(tree, { @@ -110,6 +112,10 @@ export async function projectGenerator( tasks.push(vitestTask); } + if (!schema.skipTsConfig) { + updateRootTsConfig(tree, options); + } + if (!options.skipFormat) { await formatFiles(tree); } @@ -191,10 +197,12 @@ function addProject( } } -export function addLint( +export async function addLint( tree: Tree, options: NormalizedSchema ): Promise { + ensurePackage(tree, '@nrwl/linter', nxVersion); + const { lintProjectGenerator } = require('@nrwl/linter'); return lintProjectGenerator(tree, { project: options.name, linter: options.linter, @@ -320,7 +328,7 @@ async function addJest( tree: Tree, options: NormalizedSchema ): Promise { - await ensurePackage(tree, '@nrwl/jest', nxVersion); + ensurePackage(tree, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = require('@nrwl/jest'); return await jestProjectGenerator(tree, { ...options, @@ -435,30 +443,6 @@ function getCaseAwareFileName(options: { return options.pascalCaseFiles ? normalized.className : normalized.fileName; } -function updateRootTsConfig(host: Tree, options: NormalizedSchema) { - updateJson(host, getRootTsConfigPathInTree(host), (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - c.paths[options.importPath] = [ - joinPathFragments( - options.projectRoot, - './src', - 'index.' + (options.js ? 'js' : 'ts') - ), - ]; - - return json; - }); -} - function addProjectDependencies( tree: Tree, options: NormalizedSchema diff --git a/packages/js/src/index.ts b/packages/js/src/index.ts index 70cd02c72c9d4..3602ce2de97bc 100644 --- a/packages/js/src/index.ts +++ b/packages/js/src/index.ts @@ -1,10 +1,13 @@ export * from './utils/typescript/load-ts-transformers'; export * from './utils/typescript/print-diagnostics'; export * from './utils/typescript/run-type-check'; +export * from './utils/compiler-helper-dependency'; +export * from './utils/typescript/ts-config'; +export * from './utils/typescript/create-ts-config'; export * from './utils/package-json'; export * from './utils/assets'; export * from './utils/package-json/update-package-json'; export { libraryGenerator } from './generators/library/library'; - +export { initGenerator } from './generators/init/init'; export { createLockFile } from 'nx/src/lock-file/lock-file'; export { createPackageJson } from 'nx/src/utils/create-package-json'; diff --git a/packages/js/src/migrations/update-13-8-5/update-swcrc.spec.ts b/packages/js/src/migrations/update-13-8-5/update-swcrc.spec.ts index 1d8bf9db41433..f9e62c0d17219 100644 --- a/packages/js/src/migrations/update-13-8-5/update-swcrc.spec.ts +++ b/packages/js/src/migrations/update-13-8-5/update-swcrc.spec.ts @@ -15,9 +15,9 @@ describe('Migration: adjust .swcrc', () => { let tree: Tree; let projectConfiguration: ProjectConfiguration; - beforeEach(() => { + beforeEach(async () => { tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - libraryGenerator(tree, { + await libraryGenerator(tree, { name: 'swc', buildable: true, linter: 'none', diff --git a/packages/js/src/utils/compiler-helper-dependency.ts b/packages/js/src/utils/compiler-helper-dependency.ts index c9fab1c13eb39..8432d018373d5 100644 --- a/packages/js/src/utils/compiler-helper-dependency.ts +++ b/packages/js/src/utils/compiler-helper-dependency.ts @@ -5,8 +5,8 @@ import { readJsonFile, } from '@nrwl/devkit'; import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; -import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { join } from 'path'; +import { readTsConfig } from './typescript/ts-config'; import { ExecutorOptions, SwcExecutorOptions } from './schema'; import { getSwcrcPath } from './swc/get-swcrc-path'; diff --git a/packages/js/src/utils/schema.d.ts b/packages/js/src/utils/schema.d.ts index c09831472c11e..73d151197ff5c 100644 --- a/packages/js/src/utils/schema.d.ts +++ b/packages/js/src/utils/schema.d.ts @@ -1,5 +1,5 @@ // nx-ignore-next-line -const { Linter } = require('@nrwl/linter'); +const { Linter } = require('@nrwl/linter'); // use require to import to avoid circular dependency import type { AssetGlob, FileInputOutput, diff --git a/packages/workspace/src/utils/create-ts-config.ts b/packages/js/src/utils/typescript/create-ts-config.ts similarity index 100% rename from packages/workspace/src/utils/create-ts-config.ts rename to packages/js/src/utils/typescript/create-ts-config.ts diff --git a/packages/js/src/utils/typescript/run-type-check.ts b/packages/js/src/utils/typescript/run-type-check.ts index 7636027f5b81b..ad3b381ff7cdc 100644 --- a/packages/js/src/utils/typescript/run-type-check.ts +++ b/packages/js/src/utils/typescript/run-type-check.ts @@ -1,9 +1,9 @@ -import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import * as chalk from 'chalk'; import * as path from 'path'; import type { BuilderProgram, Diagnostic, Program } from 'typescript'; import { codeFrameColumns } from 'nx/src/utils/code-frames'; import { highlight } from '../code-frames/highlight'; +import { readTsConfig } from '../../utils/typescript/ts-config'; export interface TypeCheckResult { warnings?: string[]; diff --git a/packages/js/src/utils/typescript/ts-config.ts b/packages/js/src/utils/typescript/ts-config.ts new file mode 100644 index 0000000000000..a8b3fc4f75fdc --- /dev/null +++ b/packages/js/src/utils/typescript/ts-config.ts @@ -0,0 +1,97 @@ +import { + joinPathFragments, + offsetFromRoot, + Tree, + updateJson, + workspaceRoot, +} from '@nrwl/devkit'; +import { existsSync } from 'fs'; +import { dirname, join } from 'path'; + +let tsModule: typeof import('typescript'); + +export function readTsConfig(tsConfigPath: string) { + if (!tsModule) { + tsModule = require('typescript'); + } + const readResult = tsModule.readConfigFile( + tsConfigPath, + tsModule.sys.readFile + ); + return tsModule.parseJsonConfigFileContent( + readResult.config, + tsModule.sys, + dirname(tsConfigPath) + ); +} + +export function getRootTsConfigPathInTree(tree: Tree): string | null { + for (const path of ['tsconfig.base.json', 'tsconfig.json']) { + if (tree.exists(path)) { + return path; + } + } + + return 'tsconfig.base.json'; +} + +export function getRelativePathToRootTsConfig( + tree: Tree, + targetPath: string +): string { + return offsetFromRoot(targetPath) + getRootTsConfigPathInTree(tree); +} + +export function getRootTsConfigFileName(): string | null { + for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) { + const tsConfigPath = join(workspaceRoot, tsConfigName); + if (existsSync(tsConfigPath)) { + return tsConfigName; + } + } + + return null; +} + +export function getRootTsConfigPath(): string | null { + const tsConfigFileName = getRootTsConfigFileName(); + + return tsConfigFileName ? join(workspaceRoot, tsConfigFileName) : null; +} + +export function updateRootTsConfig( + host: Tree, + options: { + name: string; + importPath?: string; + projectRoot: string; + js?: boolean; + } +) { + if (!options.importPath) { + throw new Error( + `Unable to update ${options.name} using the import path "${options.importPath}". Make sure to specify a valid import path one.` + ); + } + updateJson(host, getRootTsConfigPathInTree(host), (json) => { + const c = json.compilerOptions; + c.paths = c.paths || {}; + delete c.paths[options.name]; + + if (c.paths[options.importPath]) { + throw new Error( + `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` + ); + } + + c.paths[options.importPath] = [ + joinPathFragments( + options.projectRoot, + './src', + 'index.' + (options.js ? 'js' : 'ts') + ), + ]; + + return json; + }); +} diff --git a/packages/js/src/utils/versions.ts b/packages/js/src/utils/versions.ts index de57225198044..6a733cf50b819 100644 --- a/packages/js/src/utils/versions.ts +++ b/packages/js/src/utils/versions.ts @@ -6,3 +6,4 @@ export const esbuildVersion = '^0.17.5'; export const swcCliVersion = '~0.1.55'; export const swcHelpersVersion = '~0.4.11'; export const typesNodeVersion = '18.7.1'; +export const typescriptVersion = '~4.8.2'; diff --git a/packages/linter/package.json b/packages/linter/package.json index f67ff05e9615e..6ee91db1058ec 100644 --- a/packages/linter/package.json +++ b/packages/linter/package.json @@ -34,6 +34,7 @@ }, "dependencies": { "@nrwl/devkit": "file:../devkit", + "@nrwl/js": "file:../js", "@phenomnomnominal/tsquery": "4.1.1", "tmp": "~0.2.1", "tslib": "^2.3.0" diff --git a/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts b/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts index 0c130a1237e83..a2f34337c6f3d 100644 --- a/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts +++ b/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts @@ -13,7 +13,7 @@ import { updateJson, updateNxJson, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { join } from 'path'; import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules'; import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions'; @@ -24,7 +24,7 @@ export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules'; export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules'; export async function lintWorkspaceRulesProjectGenerator(tree: Tree) { - await ensurePackage(tree, '@nrwl/jest/', nxVersion); + ensurePackage(tree, '@nrwl/jest/', nxVersion); const { addPropertyToJestConfig, jestProjectGenerator } = await import( '@nrwl/jest' ); diff --git a/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts b/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts index c6800a74fbb85..9eb48b1440845 100644 --- a/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts +++ b/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts @@ -10,7 +10,7 @@ import { nxVersion } from '../../utils/versions'; export default async function eslint8Updates(tree: Tree) { try { - await ensurePackage(tree, '@nrwl/jest/', nxVersion); + ensurePackage(tree, '@nrwl/jest/', nxVersion); const { addPropertyToJestConfig } = await import('@nrwl/jest'); const existingJestConfigPath = normalizePath( 'tools/eslint-rules/jest.config.js' diff --git a/packages/nest/src/generators/library/lib/add-exports-to-barrel.ts b/packages/nest/src/generators/library/lib/add-exports-to-barrel.ts index 5aa95674d58fc..a917cd4badca8 100644 --- a/packages/nest/src/generators/library/lib/add-exports-to-barrel.ts +++ b/packages/nest/src/generators/library/lib/add-exports-to-barrel.ts @@ -3,19 +3,23 @@ import { addGlobal, removeChange, } from '@nrwl/workspace/src/utilities/ast-utils'; -import * as ts from 'typescript'; import type { NormalizedOptions } from '../schema'; +let tsModule: typeof import('typescript'); + export function addExportsToBarrelFile( tree: Tree, options: NormalizedOptions ): void { + if (!tsModule) { + tsModule = require('typescript'); + } const indexPath = `${options.projectRoot}/src/index.ts`; const indexContent = tree.read(indexPath, 'utf-8'); - let sourceFile = ts.createSourceFile( + let sourceFile = tsModule.createSourceFile( indexPath, indexContent, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/nest/src/generators/library/library.ts b/packages/nest/src/generators/library/library.ts index 471f59dc631de..82e3127be76ca 100644 --- a/packages/nest/src/generators/library/library.ts +++ b/packages/nest/src/generators/library/library.ts @@ -1,7 +1,6 @@ import type { GeneratorCallback, Tree } from '@nrwl/devkit'; import { convertNxGenerator, formatFiles } from '@nrwl/devkit'; import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; -import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { addDependencies } from '../init/lib'; import { addExportsToBarrelFile, @@ -19,10 +18,7 @@ export async function libraryGenerator( rawOptions: LibraryGeneratorOptions ): Promise { const options = normalizeOptions(tree, rawOptions); - const jsLibraryTask = await jsLibraryGenerator( - tree, - toJsLibraryGeneratorOptions(options) - ); + await jsLibraryGenerator(tree, toJsLibraryGeneratorOptions(options)); const installDepsTask = addDependencies(tree); deleteFiles(tree, options); createFiles(tree, options); @@ -34,7 +30,7 @@ export async function libraryGenerator( await formatFiles(tree); } - return runTasksInSerial(jsLibraryTask, installDepsTask); + return installDepsTask; } export default libraryGenerator; diff --git a/packages/next/src/generators/application/lib/add-linting.ts b/packages/next/src/generators/application/lib/add-linting.ts index 7c21ad543f5d9..b3b5ba7bc70f6 100644 --- a/packages/next/src/generators/application/lib/add-linting.ts +++ b/packages/next/src/generators/application/lib/add-linting.ts @@ -6,7 +6,10 @@ import { Tree, updateJson, } from '@nrwl/devkit'; -import { extendReactEslintJson, extraEslintDependencies } from '@nrwl/react'; +import { + extendReactEslintJson, + extraEslintDependencies, +} from '@nrwl/react/src/utils/lint'; import { NormalizedSchema } from './normalize-options'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; diff --git a/packages/next/src/generators/application/lib/create-application-files.ts b/packages/next/src/generators/application/lib/create-application-files.ts index 6b369bc4a6767..c4319c306da45 100644 --- a/packages/next/src/generators/application/lib/create-application-files.ts +++ b/packages/next/src/generators/application/lib/create-application-files.ts @@ -1,11 +1,12 @@ import { join } from 'path'; +import { generateFiles, names, toJS, Tree } from '@nrwl/devkit'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; + import { NormalizedSchema } from './normalize-options'; import { createAppJsx, createStyleRules, } from './create-application-files.helpers'; -import { generateFiles, names, toJS, Tree } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; export function createApplicationFiles(host: Tree, options: NormalizedSchema) { const templateVariables = { diff --git a/packages/next/src/generators/application/lib/normalize-options.ts b/packages/next/src/generators/application/lib/normalize-options.ts index a4133d35d8dc7..fab1c9653bfe9 100644 --- a/packages/next/src/generators/application/lib/normalize-options.ts +++ b/packages/next/src/generators/application/lib/normalize-options.ts @@ -1,4 +1,4 @@ -import { assertValidStyle } from '@nrwl/react'; +import { assertValidStyle } from '@nrwl/react/src/utils/assertion'; import { extractLayoutDirectory, getWorkspaceLayout, diff --git a/packages/next/src/generators/application/schema.d.ts b/packages/next/src/generators/application/schema.d.ts index d41b279e27670..9af6170384e43 100644 --- a/packages/next/src/generators/application/schema.d.ts +++ b/packages/next/src/generators/application/schema.d.ts @@ -11,7 +11,6 @@ export interface Schema { unitTestRunner?: 'jest' | 'none'; e2eTestRunner?: 'cypress' | 'none'; linter?: Linter; - skipWorkspaceJson?: boolean; js?: boolean; setParserOptionsProject?: boolean; standaloneConfig?: boolean; diff --git a/packages/next/src/generators/application/schema.json b/packages/next/src/generators/application/schema.json index 7e4152c58e933..343453186b06c 100644 --- a/packages/next/src/generators/application/schema.json +++ b/packages/next/src/generators/application/schema.json @@ -76,12 +76,6 @@ "default": false, "x-priority": "internal" }, - "skipWorkspaceJson": { - "description": "Skip updating `workspace.json` with default options based on values provided to this app (e.g. `babel`, `style`).", - "type": "boolean", - "default": false, - "x-priority": "internal" - }, "unitTestRunner": { "type": "string", "enum": ["jest", "none"], diff --git a/packages/next/src/generators/init/init.ts b/packages/next/src/generators/init/init.ts index 0f08db7e2eedc..80b7af7449b59 100644 --- a/packages/next/src/generators/init/init.ts +++ b/packages/next/src/generators/init/init.ts @@ -7,7 +7,9 @@ import { import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { jestInitGenerator } from '@nrwl/jest'; import { cypressInitGenerator } from '@nrwl/cypress'; -import { reactDomVersion, reactInitGenerator, reactVersion } from '@nrwl/react'; +import { reactDomVersion, reactVersion } from '@nrwl/react/src/utils/versions'; +import reactInitGenerator from '@nrwl/react/src/generators/init/init'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { eslintConfigNextVersion, @@ -35,10 +37,14 @@ function updateDependencies(host: Tree) { } export async function nextInitGenerator(host: Tree, schema: InitSchema) { + await jsInitGenerator(host, { + js: schema.js, + skipFormat: true, + }); const tasks: GeneratorCallback[] = []; if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') { - const jestTask = jestInitGenerator(host, schema); + const jestTask = await jestInitGenerator(host, schema); tasks.push(jestTask); } if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') { diff --git a/packages/next/src/generators/library/library.ts b/packages/next/src/generators/library/library.ts index bfd437ec17ab5..04f022ef9ad37 100644 --- a/packages/next/src/generators/library/library.ts +++ b/packages/next/src/generators/library/library.ts @@ -7,7 +7,7 @@ import { Tree, updateJson, } from '@nrwl/devkit'; -import { libraryGenerator as reactLibraryGenerator } from '@nrwl/react'; +import { libraryGenerator as reactLibraryGenerator } from '@nrwl/react/src/generators/library/library'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { nextInitGenerator } from '../init/init'; import { Schema } from './schema'; diff --git a/packages/next/src/utils/styles.ts b/packages/next/src/utils/styles.ts index 59af4ab8af553..051e39d7378d9 100644 --- a/packages/next/src/utils/styles.ts +++ b/packages/next/src/utils/styles.ts @@ -5,7 +5,7 @@ import { updateJson, } from '@nrwl/devkit'; -import { CSS_IN_JS_DEPENDENCIES } from '@nrwl/react'; +import { CSS_IN_JS_DEPENDENCIES } from '@nrwl/react/src/utils/styled'; import { babelPluginStyledComponentsVersion, emotionServerVersion, diff --git a/packages/node/src/generators/application/application.ts b/packages/node/src/generators/application/application.ts index 20333a3164d25..53eb2c51b7d65 100644 --- a/packages/node/src/generators/application/application.ts +++ b/packages/node/src/generators/application/application.ts @@ -20,16 +20,14 @@ import { updateProjectConfiguration, updateTsConfigsToJs, } from '@nrwl/devkit'; - -import { join } from 'path'; - import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { jestProjectGenerator } from '@nrwl/jest'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; +import { tsConfigBaseOptions } from '@nrwl/js'; +import { join } from 'path'; -import { Schema } from './schema'; import { initGenerator } from '../init/init'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { esbuildVersion, expressTypingsVersion, @@ -39,11 +37,11 @@ import { koaVersion, nxVersion, } from '../../utils/versions'; - -import * as shared from '@nrwl/workspace/src/utils/create-ts-config'; import { e2eProjectGenerator } from '../e2e-project/e2e-project'; import { setupDockerGenerator } from '../setup-docker/setup-docker'; +import { Schema } from './schema'; + export interface NormalizedSchema extends Schema { appProjectRoot: string; parsedTags: string[]; @@ -309,7 +307,7 @@ function updateTsConfigOptions(tree: Tree, options: NormalizedSchema) { if (options.rootProject) { return { compilerOptions: { - ...shared.tsConfigBaseOptions, + ...tsConfigBaseOptions, ...json.compilerOptions, esModuleInterop: true, }, diff --git a/packages/node/src/generators/init/init.ts b/packages/node/src/generators/init/init.ts index 88e6a5e0e30c2..0147cb4124b79 100644 --- a/packages/node/src/generators/init/init.ts +++ b/packages/node/src/generators/init/init.ts @@ -7,6 +7,8 @@ import { Tree, } from '@nrwl/devkit'; import { jestInitGenerator } from '@nrwl/jest'; +import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { nxVersion, tslibVersion, @@ -35,22 +37,23 @@ function normalizeOptions(schema: Schema) { export async function initGenerator(tree: Tree, schema: Schema) { const options = normalizeOptions(schema); + await jsInitGenerator(tree, { + js: schema.js, + skipFormat: true, + }); - let jestInstall: GeneratorCallback; + const tasks: GeneratorCallback[] = []; if (options.unitTestRunner === 'jest') { - jestInstall = await jestInitGenerator(tree, schema); + tasks.push(await jestInitGenerator(tree, schema)); } - const installTask = await updateDependencies(tree); + + tasks.push(updateDependencies(tree)); + if (!options.skipFormat) { await formatFiles(tree); } - return async () => { - if (jestInstall) { - await jestInstall(); - } - await installTask(); - }; + return runTasksInSerial(...tasks); } export default initGenerator; diff --git a/packages/node/src/generators/library/library.ts b/packages/node/src/generators/library/library.ts index d7cca4b087d63..a262b9acbd9e2 100644 --- a/packages/node/src/generators/library/library.ts +++ b/packages/node/src/generators/library/library.ts @@ -3,6 +3,7 @@ import { extractLayoutDirectory, formatFiles, generateFiles, + GeneratorCallback, getWorkspaceLayout, joinPathFragments, names, @@ -16,9 +17,11 @@ import { import { getImportPath } from 'nx/src/utils/path'; import { Schema } from './schema'; import { libraryGenerator as workspaceLibraryGenerator } from '@nrwl/workspace/generators'; +import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { join } from 'path'; import { addSwcDependencies } from '@nrwl/js/src/utils/swc/add-swc-dependencies'; import { addSwcConfig } from '@nrwl/js/src/utils/swc/add-swc-config'; +import { initGenerator } from '../init/init'; export interface NormalizedSchema extends Schema { name: string; @@ -32,6 +35,12 @@ export interface NormalizedSchema extends Schema { export async function libraryGenerator(tree: Tree, schema: Schema) { const options = normalizeOptions(tree, schema); + const tasks: GeneratorCallback[] = [ + await initGenerator(tree, { + ...options, + skipFormat: true, + }), + ]; if (options.publishable === true && !schema.importPath) { throw new Error( @@ -46,6 +55,7 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { skipFormat: true, setParserOptionsProject: options.setParserOptionsProject, }); + tasks.push(libraryInstall); createFiles(tree, options); if (options.js) { @@ -57,7 +67,7 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { await formatFiles(tree); } - return libraryInstall; + return runTasksInSerial(...tasks); } export default libraryGenerator; diff --git a/packages/node/src/migrations/update-13-8-5/update-package-to-tsc.spec.ts b/packages/node/src/migrations/update-13-8-5/update-package-to-tsc.spec.ts index 50211e23fabb9..7a3b6a9e87274 100644 --- a/packages/node/src/migrations/update-13-8-5/update-package-to-tsc.spec.ts +++ b/packages/node/src/migrations/update-13-8-5/update-package-to-tsc.spec.ts @@ -1,6 +1,5 @@ import { addProjectConfiguration, - readJson, readProjectConfiguration, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; diff --git a/packages/nx-plugin/src/generators/e2e-project/e2e.ts b/packages/nx-plugin/src/generators/e2e-project/e2e.ts index 37f960b8605cb..a1edf3183c171 100644 --- a/packages/nx-plugin/src/generators/e2e-project/e2e.ts +++ b/packages/nx-plugin/src/generators/e2e-project/e2e.ts @@ -10,11 +10,11 @@ import { readProjectConfiguration, updateProjectConfiguration, } from '@nrwl/devkit'; +import type { Tree } from '@nrwl/devkit'; import { jestProjectGenerator } from '@nrwl/jest'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import * as path from 'path'; -import type { Tree } from '@nrwl/devkit'; import type { Schema } from './schema'; interface NormalizedSchema extends Schema { diff --git a/packages/nx-plugin/src/generators/executor/executor.spec.ts b/packages/nx-plugin/src/generators/executor/executor.spec.ts index ba1b98b1f2c4e..ae76d7c1192fb 100644 --- a/packages/nx-plugin/src/generators/executor/executor.spec.ts +++ b/packages/nx-plugin/src/generators/executor/executor.spec.ts @@ -2,7 +2,7 @@ import { Tree, readJson, readProjectConfiguration } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { executorGenerator } from './executor'; import { pluginGenerator } from '../plugin/plugin'; -import { libraryGenerator } from '@nrwl/js'; +import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; describe('NxPlugin Executor Generator', () => { let tree: Tree; @@ -93,7 +93,7 @@ describe('NxPlugin Executor Generator', () => { }); it('should create executors.json if it is not present', async () => { - await libraryGenerator(tree, { + await jsLibraryGenerator(tree, { name: 'test-js-lib', buildable: true, }); diff --git a/packages/nx-plugin/src/generators/generator/generator.spec.ts b/packages/nx-plugin/src/generators/generator/generator.spec.ts index a874cd07e91f4..66336f9faa3d0 100644 --- a/packages/nx-plugin/src/generators/generator/generator.spec.ts +++ b/packages/nx-plugin/src/generators/generator/generator.spec.ts @@ -1,6 +1,6 @@ import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { libraryGenerator } from '@nrwl/js'; +import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; import { pluginGenerator } from '../plugin/plugin'; import { generatorGenerator } from './generator'; @@ -91,7 +91,7 @@ describe('NxPlugin Generator Generator', () => { }); it('should create generators.json if it is not present', async () => { - await libraryGenerator(tree, { + await jsLibraryGenerator(tree, { name: 'test-js-lib', buildable: true, }); diff --git a/packages/nx-plugin/src/generators/plugin/plugin.ts b/packages/nx-plugin/src/generators/plugin/plugin.ts index 2f8436777e65c..9fcdc93bab554 100644 --- a/packages/nx-plugin/src/generators/plugin/plugin.ts +++ b/packages/nx-plugin/src/generators/plugin/plugin.ts @@ -9,7 +9,7 @@ import { Tree, updateProjectConfiguration, } from '@nrwl/devkit'; -import { libraryGenerator } from '@nrwl/js'; +import { libraryGenerator as jsLibraryGenerator } from '@nrwl/js'; import { addSwcDependencies } from '@nrwl/js/src/utils/swc/add-swc-dependencies'; import { Linter } from '@nrwl/linter'; import { swcNodeVersion } from 'nx/src/utils/versions'; @@ -90,7 +90,7 @@ function updateWorkspaceJson(host: Tree, options: NormalizedSchema) { export async function pluginGenerator(host: Tree, schema: Schema) { const options = normalizeOptions(host, schema); - await libraryGenerator(host, { + await jsLibraryGenerator(host, { ...schema, config: 'project', buildable: true, diff --git a/packages/nx/src/project-graph/build-dependencies/typescript-import-locator.ts b/packages/nx/src/project-graph/build-dependencies/typescript-import-locator.ts index 79eeb419aa3ac..ef6814479c31f 100644 --- a/packages/nx/src/project-graph/build-dependencies/typescript-import-locator.ts +++ b/packages/nx/src/project-graph/build-dependencies/typescript-import-locator.ts @@ -4,7 +4,7 @@ import { stripSourceCode } from '../../utils/strip-source-code'; import { defaultFileRead } from '../file-utils'; import { DependencyType } from '../../config/project-graph'; -let tsModule: any; +let tsModule: typeof import('typescript'); export class TypeScriptImportLocator { private readonly scanner: ts.Scanner; diff --git a/packages/nx/src/utils/typescript.ts b/packages/nx/src/utils/typescript.ts index 8f0b40b17677f..0670e7a072310 100644 --- a/packages/nx/src/utils/typescript.ts +++ b/packages/nx/src/utils/typescript.ts @@ -6,7 +6,7 @@ import type { Node, SyntaxKind } from 'typescript'; const normalizedAppRoot = workspaceRoot.replace(/\\/g, '/'); -let tsModule: any; +let tsModule: typeof import('typescript'); export function readTsConfig(tsConfigPath: string) { if (!tsModule) { @@ -27,19 +27,22 @@ function readTsConfigOptions(tsConfigPath: string) { if (!tsModule) { tsModule = require('typescript'); } + const readResult = tsModule.readConfigFile( tsConfigPath, tsModule.sys.readFile ); + // we don't need to scan the files, we only care about options - const host = { + const host: Partial = { readDirectory: () => [], readFile: () => '', fileExists: tsModule.sys.fileExists, }; + return tsModule.parseJsonConfigFileContent( readResult.config, - host, + host as ts.ParseConfigHost, dirname(tsConfigPath) ).options; } @@ -51,7 +54,7 @@ let compilerHost: { }; /** - * Find a module based on it's import + * Find a module based on its import * * @param importExpr Import used to resolve to a module * @param filePath diff --git a/packages/react-native/src/generators/application/lib/create-application-files.ts b/packages/react-native/src/generators/application/lib/create-application-files.ts index 46d198448165a..b8ae5b82200e0 100644 --- a/packages/react-native/src/generators/application/lib/create-application-files.ts +++ b/packages/react-native/src/generators/application/lib/create-application-files.ts @@ -1,5 +1,5 @@ import { generateFiles, offsetFromRoot, toJS, Tree } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { join } from 'path'; import { NormalizedSchema } from './normalize-options'; diff --git a/packages/react-native/src/generators/init/init.ts b/packages/react-native/src/generators/init/init.ts index b75e6e0cf9124..8a9a543a6359b 100644 --- a/packages/react-native/src/generators/init/init.ts +++ b/packages/react-native/src/generators/init/init.ts @@ -13,6 +13,7 @@ import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs'; import { jestInitGenerator } from '@nrwl/jest'; import { detoxInitGenerator } from '@nrwl/detox'; import { babelPresetReactVersion } from '@nrwl/react/src/utils/versions'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { babelRuntimeVersion, @@ -42,7 +43,10 @@ import { addGitIgnoreEntry } from './lib/add-git-ignore-entry'; export async function reactNativeInitGenerator(host: Tree, schema: Schema) { addGitIgnoreEntry(host); addBabelInputs(host); - + await jsInitGenerator(host, { + js: schema.js, + skipFormat: true, + }); const tasks: GeneratorCallback[] = []; if (!schema.skipPackageJson) { @@ -53,7 +57,7 @@ export async function reactNativeInitGenerator(host: Tree, schema: Schema) { } if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') { - const jestTask = jestInitGenerator(host, schema); + const jestTask = await jestInitGenerator(host, schema); tasks.push(jestTask); } diff --git a/packages/react-native/src/generators/library/library.ts b/packages/react-native/src/generators/library/library.ts index f4c590304df43..35cc1c660711b 100644 --- a/packages/react-native/src/generators/library/library.ts +++ b/packages/react-native/src/generators/library/library.ts @@ -14,15 +14,12 @@ import { updateJson, } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { getRelativePathToRootTsConfig, updateRootTsConfig } from '@nrwl/js'; import init from '../init/init'; import { addLinting } from '../../utils/add-linting'; import { addJest } from '../../utils/add-jest'; import { NormalizedSchema, normalizeOptions } from './lib/normalize-options'; import { Schema } from './schema'; -import { - getRelativePathToRootTsConfig, - getRootTsConfigPathInTree, -} from '@nrwl/workspace/src/utilities/typescript'; export async function reactNativeLibraryGenerator( host: Tree, @@ -35,15 +32,15 @@ export async function reactNativeLibraryGenerator( ); } - addProject(host, options); - createFiles(host, options); - const initTask = await init(host, { ...options, skipFormat: true, e2eTestRunner: 'none', }); + addProject(host, options); + createFiles(host, options); + const lintTask = await addLinting(host, { ...options, projectName: options.name, @@ -52,10 +49,6 @@ export async function reactNativeLibraryGenerator( ], }); - if (!options.skipTsConfig) { - updateBaseTsConfig(host, options); - } - const jestTask = await addJest( host, options.unitTestRunner, @@ -69,6 +62,10 @@ export async function reactNativeLibraryGenerator( updateLibPackageNpmScope(host, options); } + if (!options.skipTsConfig) { + updateRootTsConfig(host, { ...options, js: false }); + } + if (!options.skipFormat) { await formatFiles(host); } @@ -133,31 +130,6 @@ function updateTsConfig(tree: Tree, options: NormalizedSchema) { ); } -function updateBaseTsConfig(host: Tree, options: NormalizedSchema) { - updateJson(host, getRootTsConfigPathInTree(host), (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - const { libsDir } = getWorkspaceLayout(host); - - c.paths[options.importPath] = [ - maybeJs( - options, - joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`) - ), - ]; - - return json; - }); -} - function createFiles(host: Tree, options: NormalizedSchema) { generateFiles( host, diff --git a/packages/react-native/src/generators/stories/stories.ts b/packages/react-native/src/generators/stories/stories.ts index 29ce066dafa99..d54584fd2f76a 100644 --- a/packages/react-native/src/generators/stories/stories.ts +++ b/packages/react-native/src/generators/stories/stories.ts @@ -20,7 +20,7 @@ export async function createAllStories( projectName: string, ignorePaths?: string[] ) { - await ensurePackage(tree, '@nrwl/storybook', nxVersion); + ensurePackage(tree, '@nrwl/storybook', nxVersion); const { isTheFileAStory } = await import( '@nrwl/storybook/src/utils/utilities' ); diff --git a/packages/react-native/src/generators/storybook-configuration/configuration.ts b/packages/react-native/src/generators/storybook-configuration/configuration.ts index 05ef7c520bc6d..afdd8d681cf5c 100644 --- a/packages/react-native/src/generators/storybook-configuration/configuration.ts +++ b/packages/react-native/src/generators/storybook-configuration/configuration.ts @@ -27,7 +27,7 @@ export async function storybookConfigurationGenerator( host: Tree, schema: StorybookConfigureSchema ): Promise { - await ensurePackage(host, '@nrwl/storybook', nxVersion); + ensurePackage(host, '@nrwl/storybook', nxVersion); const { configurationGenerator } = await import('@nrwl/storybook'); const installTask = await configurationGenerator(host, { diff --git a/packages/react-native/src/utils/add-linting.ts b/packages/react-native/src/utils/add-linting.ts index 758efe02171a2..2296b3666884d 100644 --- a/packages/react-native/src/utils/add-linting.ts +++ b/packages/react-native/src/utils/add-linting.ts @@ -7,7 +7,10 @@ import { Tree, updateJson, } from '@nrwl/devkit'; -import { extendReactEslintJson, extraEslintDependencies } from '@nrwl/react'; +import { + extendReactEslintJson, + extraEslintDependencies, +} from '@nrwl/react/src/utils/lint'; import type { Linter as ESLintLinter } from 'eslint'; interface NormalizedSchema { diff --git a/packages/react/package.json b/packages/react/package.json index 74f1b33998858..ce4e0237ccffa 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "@nrwl/devkit": "file:../devkit", + "@nrwl/js": "file:../js", "@nrwl/linter": "file:../linter", "@nrwl/workspace": "file:../workspace", "@phenomnomnominal/tsquery": "4.1.1", diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index e8fda83121cdd..40723a7c02d0b 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -77,7 +77,10 @@ async function addLinting(host: Tree, options: NormalizedSchema) { return runTasksInSerial(...tasks); } -export async function applicationGenerator(host: Tree, schema: Schema) { +export async function applicationGenerator( + host: Tree, + schema: Schema +): Promise { const tasks = []; const options = normalizeOptions(host, schema); @@ -99,7 +102,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) { addProject(host, options); if (options.bundler === 'vite') { - await ensurePackage(host, '@nrwl/vite', nxVersion); + ensurePackage(host, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = await import('@nrwl/vite'); // We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development. // See: https://vitejs.dev/guide/env-and-mode.html @@ -120,7 +123,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) { }); tasks.push(viteTask); } else if (options.bundler === 'webpack') { - await ensurePackage(host, '@nrwl/webpack', nxVersion); + ensurePackage(host, '@nrwl/webpack', nxVersion); const { webpackInitGenerator } = await import('@nrwl/webpack'); const webpackInitTask = await webpackInitGenerator(host, { @@ -130,7 +133,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) { } if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') { - await ensurePackage(host, '@nrwl/vite', nxVersion); + ensurePackage(host, '@nrwl/vite', nxVersion); const { vitestGenerator } = await import('@nrwl/vite'); const vitestTask = await vitestGenerator(host, { diff --git a/packages/react/src/generators/application/lib/add-cypress.ts b/packages/react/src/generators/application/lib/add-cypress.ts index 2e0df69c34a54..b1d2a1835753e 100644 --- a/packages/react/src/generators/application/lib/add-cypress.ts +++ b/packages/react/src/generators/application/lib/add-cypress.ts @@ -6,7 +6,8 @@ export async function addCypress(host: Tree, options: NormalizedSchema) { if (options.e2eTestRunner !== 'cypress') { return () => {}; } - await ensurePackage(host, '@nrwl/cypress', nxVersion); + + ensurePackage(host, '@nrwl/cypress', nxVersion); const { cypressProjectGenerator } = await import('@nrwl/cypress'); return await cypressProjectGenerator(host, { diff --git a/packages/react/src/generators/application/lib/add-jest.ts b/packages/react/src/generators/application/lib/add-jest.ts index 56c06f9b972e7..1c31467c31ee0 100644 --- a/packages/react/src/generators/application/lib/add-jest.ts +++ b/packages/react/src/generators/application/lib/add-jest.ts @@ -1,9 +1,12 @@ -import { ensurePackage, Tree } from '@nrwl/devkit'; +import { ensurePackage, GeneratorCallback, Tree } from '@nrwl/devkit'; import { NormalizedSchema } from '../schema'; import { nxVersion } from '../../../utils/versions'; -export async function addJest(host: Tree, options: NormalizedSchema) { - await ensurePackage(host, '@nrwl/jest', nxVersion); +export async function addJest( + host: Tree, + options: NormalizedSchema +): Promise { + ensurePackage(host, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = await import('@nrwl/jest'); if (options.unitTestRunner !== 'jest') { diff --git a/packages/react/src/generators/application/lib/add-routing.ts b/packages/react/src/generators/application/lib/add-routing.ts index 944b704caa89f..8f6025b7e5aa4 100644 --- a/packages/react/src/generators/application/lib/add-routing.ts +++ b/packages/react/src/generators/application/lib/add-routing.ts @@ -1,4 +1,3 @@ -import * as ts from 'typescript'; import { addInitialRoutes } from '../../../utils/ast-utils'; import { NormalizedSchema } from '../schema'; import { @@ -12,20 +11,25 @@ import { addDependenciesToPackageJson, } from '@nrwl/devkit'; +let tsModule: typeof import('typescript'); + export function addRouting(host: Tree, options: NormalizedSchema) { if (!options.routing) { return () => {}; } + if (!tsModule) { + tsModule = require('typescript'); + } const appPath = joinPathFragments( options.appProjectRoot, maybeJs(options, `src/app/${options.fileName}.tsx`) ); const appFileContent = host.read(appPath, 'utf-8'); - const appSource = ts.createSourceFile( + const appSource = tsModule.createSourceFile( appPath, appFileContent, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/application/lib/create-application-files.ts b/packages/react/src/generators/application/lib/create-application-files.ts index cea05f609cf36..cee90900628fb 100644 --- a/packages/react/src/generators/application/lib/create-application-files.ts +++ b/packages/react/src/generators/application/lib/create-application-files.ts @@ -1,9 +1,9 @@ -import { NormalizedSchema } from '../schema'; import { names, offsetFromRoot, Tree, toJS, generateFiles } from '@nrwl/devkit'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { join } from 'path'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { createTsConfig } from '../../../utils/create-ts-config'; import { getInSourceVitestTestsTemplate } from '../../../utils/get-in-source-vitest-tests-template'; +import { NormalizedSchema } from '../schema'; import { getAppTests } from './get-app-tests'; export function createApplicationFiles(host: Tree, options: NormalizedSchema) { diff --git a/packages/react/src/generators/component-cypress-spec/component-cypress-spec.ts b/packages/react/src/generators/component-cypress-spec/component-cypress-spec.ts index a3818e8a35166..02e2e7df98a86 100644 --- a/packages/react/src/generators/component-cypress-spec/component-cypress-spec.ts +++ b/packages/react/src/generators/component-cypress-spec/component-cypress-spec.ts @@ -6,13 +6,15 @@ import { Tree, } from '@nrwl/devkit'; import { basename, join } from 'path'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { findExportDeclarationsForJsx, getComponentNode, getComponentPropsInterface, } from '../../utils/ast-utils'; +let tsModule: typeof import('typescript'); + export interface CreateComponentSpecFileSchema { project: string; componentPath: string; @@ -29,10 +31,13 @@ export function componentCypressGenerator( // TODO: candidate to refactor with the angular component story export function getArgsDefaultValue(property: ts.SyntaxKind): string { + if (!tsModule) { + tsModule = require('typescript'); + } const typeNameToDefault: Record = { - [ts.SyntaxKind.StringKeyword]: '', - [ts.SyntaxKind.NumberKeyword]: 0, - [ts.SyntaxKind.BooleanKeyword]: false, + [tsModule.SyntaxKind.StringKeyword]: '', + [tsModule.SyntaxKind.NumberKeyword]: 0, + [tsModule.SyntaxKind.BooleanKeyword]: false, }; const resolvedValue = typeNameToDefault[property]; @@ -49,6 +54,9 @@ export function createComponentSpecFile( tree: Tree, { project, componentPath, js, cypressProject }: CreateComponentSpecFileSchema ) { + if (!tsModule) { + tsModule = require('typescript'); + } const e2eProjectName = cypressProject || `${project}-e2e`; const projects = getProjects(tree); const e2eProject = projects.get(e2eProjectName); @@ -73,10 +81,10 @@ export function createComponentSpecFile( throw new Error(`Failed to read ${componentFilePath}`); } - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( componentFilePath, contents, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/component-story/component-story.ts b/packages/react/src/generators/component-story/component-story.ts index 632fdeb2bdf42..ac5e6290b6b02 100644 --- a/packages/react/src/generators/component-story/component-story.ts +++ b/packages/react/src/generators/component-story/component-story.ts @@ -7,13 +7,15 @@ import { normalizePath, Tree, } from '@nrwl/devkit'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { findExportDeclarationsForJsx, getComponentNode, } from '../../utils/ast-utils'; import { getDefaultsForComponent } from '../../utils/component-props'; +let tsModule: typeof import('typescript'); + export interface CreateComponentStoriesFileSchema { project: string; componentPath: string; @@ -23,6 +25,9 @@ export function createComponentStoriesFile( host: Tree, { project, componentPath }: CreateComponentStoriesFileSchema ) { + if (!tsModule) { + tsModule = require('typescript'); + } const proj = getProjects(host).get(project); const sourceRoot = proj.sourceRoot; @@ -55,10 +60,10 @@ export function createComponentStoriesFile( throw new Error(`Failed to read ${componentFilePath}`); } - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( componentFilePath, contents, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/component-test/component-test.ts b/packages/react/src/generators/component-test/component-test.ts index 26e69f1ca0abf..68e943b80e544 100644 --- a/packages/react/src/generators/component-test/component-test.ts +++ b/packages/react/src/generators/component-test/component-test.ts @@ -6,7 +6,6 @@ import { Tree, } from '@nrwl/devkit'; import { basename, dirname, extname, relative } from 'path'; -import * as ts from 'typescript'; import { findExportDeclarationsForJsx, getComponentNode, @@ -15,11 +14,13 @@ import { getDefaultsForComponent } from '../../utils/component-props'; import { nxVersion } from '../../utils/versions'; import { ComponentTestSchema } from './schema'; +let tsModule: typeof import('typescript'); + export async function componentTestGenerator( tree: Tree, options: ComponentTestSchema ) { - await ensurePackage(tree, '@nrwl/cypress', nxVersion); + ensurePackage(tree, '@nrwl/cypress', nxVersion); const { assertMinimumCypressVersion } = await import( '@nrwl/cypress/src/utils/cypress-version' ); @@ -44,10 +45,14 @@ export async function componentTestGenerator( } function generateSpecsForComponents(tree: Tree, filePath: string) { - const sourceFile = ts.createSourceFile( + if (!tsModule) { + tsModule = require('typescript'); + } + + const sourceFile = tsModule.createSourceFile( filePath, tree.read(filePath, 'utf-8'), - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/component/component.ts b/packages/react/src/generators/component/component.ts index b965494461584..bcd8bf1c6b158 100644 --- a/packages/react/src/generators/component/component.ts +++ b/packages/react/src/generators/component/component.ts @@ -13,7 +13,6 @@ import { Tree, } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; -import * as ts from 'typescript'; import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies'; import { assertValidStyle } from '../../utils/assertion'; import { addImport } from '../../utils/ast-utils'; @@ -103,7 +102,11 @@ function createComponentFiles(host: Tree, options: NormalizedSchema) { } } +let tsModule: typeof import('typescript'); function addExportsToBarrel(host: Tree, options: NormalizedSchema) { + if (!tsModule) { + tsModule = require('typescript'); + } const workspace = getProjects(host); const isApp = workspace.get(options.project).projectType === 'application'; @@ -114,10 +117,10 @@ function addExportsToBarrel(host: Tree, options: NormalizedSchema) { ); const indexSource = host.read(indexFilePath, 'utf-8'); if (indexSource !== null) { - const indexSourceFile = ts.createSourceFile( + const indexSourceFile = tsModule.createSourceFile( indexFilePath, indexSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const changes = applyChangesToString( diff --git a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts index 1265d86ca15a6..4273183210e35 100644 --- a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts +++ b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts @@ -18,7 +18,7 @@ export async function cypressComponentConfigGenerator( tree: Tree, options: CypressComponentConfigurationSchema ) { - await ensurePackage(tree, '@nrwl/cypress', nxVersion); + ensurePackage(tree, '@nrwl/cypress', nxVersion); const { cypressComponentProject } = await import('@nrwl/cypress'); const projectConfig = readProjectConfiguration(tree, options.project); const installTask = await cypressComponentProject(tree, { diff --git a/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts b/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts index ee35899f62758..462baf476bd1f 100644 --- a/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts +++ b/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts @@ -6,18 +6,18 @@ import { logger, parseTargetString, ProjectConfiguration, - readCachedProjectGraph, readProjectConfiguration, Tree, visitNotIgnoredFiles, } from '@nrwl/devkit'; import { nxVersion } from 'nx/src/utils/versions'; -import * as ts from 'typescript'; import { getComponentNode } from '../../../utils/ast-utils'; import { componentTestGenerator } from '../../component-test/component-test'; import { CypressComponentConfigurationSchema } from '../schema'; import { FoundTarget } from './update-configs'; +let tsModule: typeof import('typescript'); + const allowedFileExt = new RegExp(/\.[jt]sx?/g); const isSpecFile = new RegExp(/(spec|test)\./g); @@ -58,7 +58,7 @@ export async function addFiles( options.bundler === 'webpack' || (!options.bundler && actualBundler === 'webpack') ) { - await ensurePackage(tree, '@nrwl/webpack', nxVersion); + ensurePackage(tree, '@nrwl/webpack', nxVersion); } if (options.generateTests) { @@ -97,15 +97,19 @@ async function getBundler( } function isComponent(tree: Tree, filePath: string): boolean { + if (!tsModule) { + tsModule = require('typescript'); + } + if (isSpecFile.test(filePath) || !allowedFileExt.test(filePath)) { return false; } const content = tree.read(filePath, 'utf-8'); - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( filePath, content, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/hook/hook.ts b/packages/react/src/generators/hook/hook.ts index 8dfa40144ef5e..5405e086cfd46 100644 --- a/packages/react/src/generators/hook/hook.ts +++ b/packages/react/src/generators/hook/hook.ts @@ -1,5 +1,4 @@ // TODO(jack): Remove inline renderHook function when RTL releases with its own version -import * as ts from 'typescript'; import { applyChangesToString, convertNxGenerator, @@ -60,7 +59,11 @@ function createFiles(host: Tree, options: NormalizedSchema) { } } +let tsModule: typeof import('typescript'); function addExportsToBarrel(host: Tree, options: NormalizedSchema) { + if (!tsModule) { + tsModule = require('typescript'); + } const workspace = getProjects(host); const isApp = workspace.get(options.project).projectType === 'application'; @@ -71,10 +74,10 @@ function addExportsToBarrel(host: Tree, options: NormalizedSchema) { ); const indexSource = host.read(indexFilePath, 'utf-8'); if (indexSource !== null) { - const indexSourceFile = ts.createSourceFile( + const indexSourceFile = tsModule.createSourceFile( indexFilePath, indexSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const changes = applyChangesToString( diff --git a/packages/react/src/generators/init/init.ts b/packages/react/src/generators/init/init.ts index a50b41672a581..9675642a6fa97 100755 --- a/packages/react/src/generators/init/init.ts +++ b/packages/react/src/generators/init/init.ts @@ -10,6 +10,7 @@ import { writeJson, } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { babelPresetReactVersion, nxVersion, @@ -85,13 +86,19 @@ function initRootBabelConfig(tree: Tree, schema: InitSchema) { } export async function reactInitGenerator(host: Tree, schema: InitSchema) { + await jsInitGenerator(host, { + js: schema.js, + skipFormat: true, + }); const tasks: GeneratorCallback[] = []; setDefault(host); if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') { - await ensurePackage(host, '@nrwl/cypress', nxVersion); - const { cypressInitGenerator } = await import('@nrwl/cypress'); + ensurePackage(host, '@nrwl/cypress', nxVersion); + const { cypressInitGenerator } = await import( + '@nrwl/cypress/src/generators/init/init' + ); const cypressTask = cypressInitGenerator(host, {}); tasks.push(cypressTask); } diff --git a/packages/react/src/generators/library/lib/add-rollup-build-target.ts b/packages/react/src/generators/library/lib/add-rollup-build-target.ts index 2344aa00cd5a3..df12588a8404b 100644 --- a/packages/react/src/generators/library/lib/add-rollup-build-target.ts +++ b/packages/react/src/generators/library/lib/add-rollup-build-target.ts @@ -20,7 +20,7 @@ export async function addRollupBuildTarget( host: Tree, options: NormalizedSchema ) { - await ensurePackage(host, '@nrwl/rollup', nxVersion); + ensurePackage(host, '@nrwl/rollup', nxVersion); const { rollupInitGenerator } = await import('@nrwl/rollup'); // These are used in `@nrwl/react/plugins/bundle-rollup` diff --git a/packages/react/src/generators/library/lib/create-files.ts b/packages/react/src/generators/library/lib/create-files.ts index 15fc967ccd127..be4ce71e1b8c9 100644 --- a/packages/react/src/generators/library/lib/create-files.ts +++ b/packages/react/src/generators/library/lib/create-files.ts @@ -1,4 +1,4 @@ -import { Tree } from 'nx/src/generators/tree'; +import type { Tree } from '@nrwl/devkit'; import { generateFiles, joinPathFragments, @@ -6,7 +6,7 @@ import { offsetFromRoot, toJS, } from '@nrwl/devkit'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { NormalizedSchema } from '../schema'; import { createTsConfig } from '../../../utils/create-ts-config'; diff --git a/packages/react/src/generators/library/lib/update-app-routes.ts b/packages/react/src/generators/library/lib/update-app-routes.ts index fe87a36cf694f..b9f62edef2dc5 100644 --- a/packages/react/src/generators/library/lib/update-app-routes.ts +++ b/packages/react/src/generators/library/lib/update-app-routes.ts @@ -6,21 +6,23 @@ import { } from '@nrwl/devkit'; import { Tree } from 'nx/src/generators/tree'; import { getImportPath, joinPathFragments } from 'nx/src/utils/path'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { NormalizedSchema } from '../schema'; import { addBrowserRouter, - addInitialRoutes, addRoute, findComponentImportPath, } from '../../../utils/ast-utils'; +import { addInitialRoutes } from '../../../utils/ast-utils'; import { maybeJs } from './maybe-js'; import { reactRouterDomVersion, typesReactRouterDomVersion, } from '../../../utils/versions'; +let tsModule: typeof import('typescript'); + export function updateAppRoutes(host: Tree, options: NormalizedSchema) { if (!options.appMain || !options.appSourceRoot) { return () => {}; @@ -97,13 +99,16 @@ function readComponent( if (!host.exists(path)) { throw new Error(`Cannot find ${path}`); } + if (!tsModule) { + tsModule = require('typescript'); + } const content = host.read(path, 'utf-8'); - const source = ts.createSourceFile( + const source = tsModule.createSourceFile( path, content, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/library/lib/update-base-tsconfig.ts b/packages/react/src/generators/library/lib/update-base-tsconfig.ts deleted file mode 100644 index 91a31186ca768..0000000000000 --- a/packages/react/src/generators/library/lib/update-base-tsconfig.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Tree } from 'nx/src/generators/tree'; -import { updateJson } from 'nx/src/generators/utils/json'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; -import { getWorkspaceLayout, joinPathFragments } from '@nrwl/devkit'; - -import { NormalizedSchema } from '../schema'; -import { maybeJs } from './maybe-js'; - -export function updateBaseTsConfig(host: Tree, options: NormalizedSchema) { - updateJson(host, getRootTsConfigPathInTree(host), (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - const { libsDir } = getWorkspaceLayout(host); - - c.paths[options.importPath] = [ - maybeJs( - options, - joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`) - ), - ]; - - return json; - }); -} diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index 09f9307a3561f..6604c4cce162b 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -97,7 +97,8 @@ describe('lib', () => { await libraryGenerator(tree, defaultSchema); - const tsconfigJson = readJson(tree, '/tsconfig.base.json'); + expect(tree.exists('tsconfig.base.json')).toEqual(true); + const tsconfigJson = readJson(tree, 'tsconfig.base.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([ 'libs/my-lib/src/index.ts', ]); diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index 0dafa404e0349..d8cb0d13e8ee3 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -9,6 +9,7 @@ import { updateJson, } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { updateRootTsConfig } from '@nrwl/js'; import { nxVersion } from '../../utils/versions'; import componentGenerator from '../component/component'; @@ -20,7 +21,6 @@ import { addRollupBuildTarget } from './lib/add-rollup-build-target'; import { addLinting } from './lib/add-linting'; import { updateAppRoutes } from './lib/update-app-routes'; import { createFiles } from './lib/create-files'; -import { updateBaseTsConfig } from './lib/update-base-tsconfig'; import { extractTsConfigBase } from '../../utils/create-ts-config'; import { installCommonDependencies } from './lib/install-common-dependencies'; import { setDefaults } from './lib/set-defaults'; @@ -38,8 +38,6 @@ export async function libraryGenerator(host: Tree, schema: Schema) { options.style = 'none'; } - extractTsConfigBase(host); - const initTask = await initGenerator(host, { ...options, e2eTestRunner: 'none', @@ -62,13 +60,9 @@ export async function libraryGenerator(host: Tree, schema: Schema) { createFiles(host, options); - if (!options.skipTsConfig) { - updateBaseTsConfig(host, options); - } - // Set up build target if (options.buildable && options.bundler === 'vite') { - await ensurePackage(host, '@nrwl/vite', nxVersion); + ensurePackage(host, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = await import('@nrwl/vite'); const viteTask = await viteConfigurationGenerator(host, { uiFramework: 'react', @@ -86,7 +80,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) { // Set up test target if (options.unitTestRunner === 'jest') { - await ensurePackage(host, '@nrwl/jest', nxVersion); + ensurePackage(host, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = await import('@nrwl/jest'); const jestTask = await jestProjectGenerator(host, { @@ -112,7 +106,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) { options.unitTestRunner === 'vitest' && options.bundler !== 'vite' // tests are already configured if bundler is vite ) { - await ensurePackage(host, '@nrwl/vite', nxVersion); + ensurePackage(host, '@nrwl/vite', nxVersion); const { vitestGenerator } = await import('@nrwl/vite'); const vitestTask = await vitestGenerator(host, { uiFramework: 'react', @@ -157,6 +151,11 @@ export async function libraryGenerator(host: Tree, schema: Schema) { tasks.push(routeTask); setDefaults(host, options); + extractTsConfigBase(host); + if (!options.skipTsConfig) { + updateRootTsConfig(host, options); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/react/src/generators/redux/redux.ts b/packages/react/src/generators/redux/redux.ts index e6cbc419e0061..e6051db5bc1c2 100644 --- a/packages/react/src/generators/redux/redux.ts +++ b/packages/react/src/generators/redux/redux.ts @@ -1,5 +1,4 @@ import * as path from 'path'; -import * as ts from 'typescript'; import { addImport, addReduxStoreToMain, @@ -20,7 +19,9 @@ import { toJS, Tree, } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getRootTsConfigPathInTree } from '@nrwl/js'; + +let tsModule: typeof import('typescript'); export async function reduxGenerator(host: Tree, schema: Schema) { const options = normalizeOptions(host, schema); @@ -63,6 +64,10 @@ function addReduxPackageDependencies(host: Tree) { } function addExportsToBarrel(host: Tree, options: NormalizedSchema) { + if (!tsModule) { + tsModule = require('typescript'); + } + const indexFilePath = path.join( options.projectSourcePath, options.js ? 'index.js' : 'index.ts' @@ -70,10 +75,10 @@ function addExportsToBarrel(host: Tree, options: NormalizedSchema) { const indexSource = host.read(indexFilePath, 'utf-8'); if (indexSource !== null) { - const indexSourceFile = ts.createSourceFile( + const indexSourceFile = tsModule.createSourceFile( indexFilePath, indexSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); @@ -95,10 +100,10 @@ function addStoreConfiguration(host: Tree, options: NormalizedSchema) { const mainSource = host.read(options.appMainFilePath, 'utf-8'); if (!mainSource.includes('redux')) { - const mainSourceFile = ts.createSourceFile( + const mainSourceFile = tsModule.createSourceFile( options.appMainFilePath, mainSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const changes = applyChangesToString( @@ -110,15 +115,19 @@ function addStoreConfiguration(host: Tree, options: NormalizedSchema) { } function updateReducerConfiguration(host: Tree, options: NormalizedSchema) { + if (!tsModule) { + tsModule = require('typescript'); + } + if (!options.appProjectSourcePath) { return; } const mainSource = host.read(options.appMainFilePath, 'utf-8'); - const mainSourceFile = ts.createSourceFile( + const mainSourceFile = tsModule.createSourceFile( options.appMainFilePath, mainSource, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); const changes = applyChangesToString( diff --git a/packages/react/src/generators/remote/lib/update-host-with-remote.ts b/packages/react/src/generators/remote/lib/update-host-with-remote.ts index a487ca323b84b..bacae7ffb5354 100644 --- a/packages/react/src/generators/remote/lib/update-host-with-remote.ts +++ b/packages/react/src/generators/remote/lib/update-host-with-remote.ts @@ -11,13 +11,18 @@ import { addRemoteRoute, addRemoteToConfig, } from '../../../module-federation/ast-utils'; -import * as ts from 'typescript'; + +let tsModule: typeof import('typescript'); export function updateHostWithRemote( host: Tree, hostName: string, remoteName: string ) { + if (!tsModule) { + tsModule = require('typescript'); + } + const hostConfig = readProjectConfiguration(host, hostName); const moduleFederationConfigPath = joinPathFragments( hostConfig.root, @@ -33,10 +38,10 @@ export function updateHostWithRemote( // find the host project path // Update remotes inside ${host_path}/src/remotes.d.ts let sourceCode = host.read(moduleFederationConfigPath).toString(); - const source = ts.createSourceFile( + const source = tsModule.createSourceFile( moduleFederationConfigPath, sourceCode, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); host.write( @@ -52,10 +57,10 @@ export function updateHostWithRemote( if (host.exists(remoteDefsPath)) { let sourceCode = host.read(remoteDefsPath).toString(); - const source = ts.createSourceFile( + const source = tsModule.createSourceFile( moduleFederationConfigPath, sourceCode, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); host.write( @@ -70,10 +75,10 @@ export function updateHostWithRemote( if (host.exists(appComponentPath)) { let sourceCode = host.read(appComponentPath).toString(); - const source = ts.createSourceFile( + const source = tsModule.createSourceFile( moduleFederationConfigPath, sourceCode, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); host.write( diff --git a/packages/react/src/generators/setup-ssr/setup-ssr.ts b/packages/react/src/generators/setup-ssr/setup-ssr.ts index 563b438e01e60..bbb8a105a7ad3 100644 --- a/packages/react/src/generators/setup-ssr/setup-ssr.ts +++ b/packages/react/src/generators/setup-ssr/setup-ssr.ts @@ -1,4 +1,4 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { addDependenciesToPackageJson, applyChangesToString, @@ -24,14 +24,25 @@ import { } from '../../utils/versions'; import { addStaticRouter } from '../../utils/ast-utils'; +let tsModule: typeof import('typescript'); + function readEntryFile( host: Tree, path: string ): { content: string; source: ts.SourceFile } { + if (!tsModule) { + tsModule = require('typescript'); + } + const content = host.read(path, 'utf-8'); return { content, - source: ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true), + source: tsModule.createSourceFile( + path, + content, + tsModule.ScriptTarget.Latest, + true + ), }; } diff --git a/packages/react/src/generators/setup-tailwind/setup-tailwind.ts b/packages/react/src/generators/setup-tailwind/setup-tailwind.ts index 9eb221e8b8f73..0b77625d2f516 100644 --- a/packages/react/src/generators/setup-tailwind/setup-tailwind.ts +++ b/packages/react/src/generators/setup-tailwind/setup-tailwind.ts @@ -7,7 +7,6 @@ import { joinPathFragments, logger, readProjectConfiguration, - updateProjectConfiguration, } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; diff --git a/packages/react/src/generators/stories/stories.ts b/packages/react/src/generators/stories/stories.ts index c4a6e3e5adc81..5cf9e1e69612c 100644 --- a/packages/react/src/generators/stories/stories.ts +++ b/packages/react/src/generators/stories/stories.ts @@ -4,7 +4,6 @@ import { findExportDeclarationsForJsx, getComponentNode, } from '../../utils/ast-utils'; -import * as ts from 'typescript'; import { convertNxGenerator, getProjects, @@ -17,6 +16,8 @@ import { import { basename, join } from 'path'; import minimatch = require('minimatch'); +let tsModule: typeof import('typescript'); + export interface StorybookStoriesSchema { project: string; generateCypressSpecs: boolean; @@ -55,15 +56,19 @@ export function containsComponentDeclaration( tree: Tree, componentPath: string ): boolean { + if (!tsModule) { + tsModule = require('typescript'); + } + const contents = tree.read(componentPath, 'utf-8'); if (contents === null) { throw new Error(`Failed to read ${componentPath}`); } - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( componentPath, contents, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); diff --git a/packages/react/src/generators/storybook-configuration/configuration.ts b/packages/react/src/generators/storybook-configuration/configuration.ts index 8c5551b4135f7..7b75b35c2f8b0 100644 --- a/packages/react/src/generators/storybook-configuration/configuration.ts +++ b/packages/react/src/generators/storybook-configuration/configuration.ts @@ -11,7 +11,7 @@ import { import { nxVersion } from '../../utils/versions'; async function generateStories(host: Tree, schema: StorybookConfigureSchema) { - await ensurePackage(host, '@nrwl/cypress', nxVersion); + ensurePackage(host, '@nrwl/cypress', nxVersion); const { getE2eProjectName } = await import( '@nrwl/cypress/src/utils/project-name' ); @@ -35,7 +35,7 @@ export async function storybookConfigurationGenerator( host: Tree, schema: StorybookConfigureSchema ) { - await ensurePackage(host, '@nrwl/storybook', nxVersion); + ensurePackage(host, '@nrwl/storybook', nxVersion); const { configurationGenerator } = await import('@nrwl/storybook'); let bundler = schema.bundler ?? 'webpack'; diff --git a/packages/react/src/module-federation/ast-utils.ts b/packages/react/src/module-federation/ast-utils.ts index 9e25c9767bf1f..1e620fae27893 100644 --- a/packages/react/src/module-federation/ast-utils.ts +++ b/packages/react/src/module-federation/ast-utils.ts @@ -1,19 +1,25 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { ChangeType, StringChange } from '@nrwl/devkit'; import { findNodes } from 'nx/src/utils/typescript'; import { - addImport, findClosestOpening, findElements, + addImport, } from '../utils/ast-utils'; +let tsModule: typeof import('typescript'); + export function addRemoteToConfig( source: ts.SourceFile, app: string ): StringChange[] { + if (!tsModule) { + tsModule = require('typescript'); + } + const assignments = findNodes( source, - ts.SyntaxKind.PropertyAssignment + tsModule.SyntaxKind.PropertyAssignment ) as ts.PropertyAssignment[]; const remotesAssignment = assignments.find( @@ -46,10 +52,10 @@ export function addRemoteToConfig( const binaryExpressions = findNodes( source, - ts.SyntaxKind.BinaryExpression + tsModule.SyntaxKind.BinaryExpression ) as ts.BinaryExpression[]; const exportExpression = binaryExpressions.find((b) => { - if (b.left.kind === ts.SyntaxKind.PropertyAccessExpression) { + if (b.left.kind === tsModule.SyntaxKind.PropertyAccessExpression) { const pae = b.left as ts.PropertyAccessExpression; return ( pae.expression.getText() === 'module' && @@ -58,7 +64,9 @@ export function addRemoteToConfig( } }); - if (exportExpression?.right.kind === ts.SyntaxKind.ObjectLiteralExpression) { + if ( + exportExpression?.right.kind === tsModule.SyntaxKind.ObjectLiteralExpression + ) { const ole = exportExpression.right as ts.ObjectLiteralExpression; return [ { diff --git a/packages/react/src/utils/ast-utils.ts b/packages/react/src/utils/ast-utils.ts index 2ebfa559562ed..a890613cdc765 100644 --- a/packages/react/src/utils/ast-utils.ts +++ b/packages/react/src/utils/ast-utils.ts @@ -1,4 +1,4 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { findNodes } from 'nx/src/utils/typescript'; import { ChangeType, @@ -7,11 +7,17 @@ import { StringInsertion, } from '@nrwl/devkit'; +let tsModule: typeof import('typescript'); + export function addImport( source: ts.SourceFile, statement: string ): StringChange[] { - const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration); + if (!tsModule) { + tsModule = require('typescript'); + } + + const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); if (allImports.length > 0) { const lastImport = allImports[allImports.length - 1]; return [ @@ -35,17 +41,21 @@ export function addImport( export function findMainRenderStatement( source: ts.SourceFile ): ts.CallExpression | null { + if (!tsModule) { + tsModule = require('typescript'); + } + // 1. Try to find ReactDOM.render. const calls = findNodes( source, - ts.SyntaxKind.CallExpression + tsModule.SyntaxKind.CallExpression ) as ts.CallExpression[]; for (const expr of calls) { const inner = expr.expression; // React 17 and below if ( - ts.isPropertyAccessExpression(inner) && + tsModule.isPropertyAccessExpression(inner) && /ReactDOM/i.test(inner.expression.getText()) && inner.name.getText() === 'render' ) { @@ -54,7 +64,7 @@ export function findMainRenderStatement( // React 18 if ( - ts.isPropertyAccessExpression(inner) && + tsModule.isPropertyAccessExpression(inner) && /root/.test(inner.expression.getText()) && inner.name.getText() === 'render' ) { @@ -65,7 +75,7 @@ export function findMainRenderStatement( // 2. Try to find render from 'react-dom'. const imports = findNodes( source, - ts.SyntaxKind.ImportDeclaration + tsModule.SyntaxKind.ImportDeclaration ) as ts.ImportDeclaration[]; const hasRenderImport = imports.some( (i) => @@ -75,7 +85,7 @@ export function findMainRenderStatement( if (hasRenderImport) { const calls = findNodes( source, - ts.SyntaxKind.CallExpression + tsModule.SyntaxKind.CallExpression ) as ts.CallExpression[]; for (const expr of calls) { if (expr.expression.getText() === 'render') { @@ -106,17 +116,23 @@ export function findDefaultExportDeclaration( | ts.FunctionDeclaration | ts.ClassDeclaration | null { + if (!tsModule) { + tsModule = require('typescript'); + } const identifier = findDefaultExportIdentifier(source); if (identifier) { - const variables = findNodes(source, ts.SyntaxKind.VariableDeclaration); - const fns = findNodes(source, ts.SyntaxKind.FunctionDeclaration); - const cls = findNodes(source, ts.SyntaxKind.ClassDeclaration); + const variables = findNodes( + source, + tsModule.SyntaxKind.VariableDeclaration + ); + const fns = findNodes(source, tsModule.SyntaxKind.FunctionDeclaration); + const cls = findNodes(source, tsModule.SyntaxKind.ClassDeclaration); const all = [...variables, ...fns, ...cls] as Array< ts.VariableDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration >; const exported = all - .filter((x) => x.name.kind === ts.SyntaxKind.Identifier) + .filter((x) => x.name.kind === tsModule.SyntaxKind.Identifier) .find((x) => (x.name as ts.Identifier).text === identifier.text); return exported || null; @@ -130,14 +146,20 @@ export function findExportDeclarationsForJsx( ): Array< ts.VariableDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration > | null { - const variables = findNodes(source, ts.SyntaxKind.VariableDeclaration); - const variableStatements = findNodes(source, ts.SyntaxKind.VariableStatement); - const fns = findNodes(source, ts.SyntaxKind.FunctionDeclaration); - const cls = findNodes(source, ts.SyntaxKind.ClassDeclaration); + if (!tsModule) { + tsModule = require('typescript'); + } + const variables = findNodes(source, tsModule.SyntaxKind.VariableDeclaration); + const variableStatements = findNodes( + source, + tsModule.SyntaxKind.VariableStatement + ); + const fns = findNodes(source, tsModule.SyntaxKind.FunctionDeclaration); + const cls = findNodes(source, tsModule.SyntaxKind.ClassDeclaration); const exportDeclarations: ts.ExportDeclaration[] = findNodes( source, - ts.SyntaxKind.ExportDeclaration + tsModule.SyntaxKind.ExportDeclaration ) as ts.ExportDeclaration[]; let componentNamesNodes: ts.Node[] = []; @@ -145,7 +167,7 @@ export function findExportDeclarationsForJsx( exportDeclarations.forEach((node) => { componentNamesNodes = [ ...componentNamesNodes, - ...findNodes(node, ts.SyntaxKind.ExportSpecifier), + ...findNodes(node, tsModule.SyntaxKind.ExportSpecifier), ]; }); @@ -162,27 +184,28 @@ export function findExportDeclarationsForJsx( const nodesContainingJSX = all.filter((x) => { foundJSX = findNodes(x, [ - ts.SyntaxKind.JsxSelfClosingElement, - ts.SyntaxKind.JsxOpeningElement, + tsModule.SyntaxKind.JsxSelfClosingElement, + tsModule.SyntaxKind.JsxOpeningElement, ]); return foundJSX?.length; }); const exported = nodesContainingJSX.filter((x) => { - foundExport = findNodes(x, ts.SyntaxKind.ExportKeyword); - if (x.kind === ts.SyntaxKind.VariableStatement) { + foundExport = findNodes(x, tsModule.SyntaxKind.ExportKeyword); + if (x.kind === tsModule.SyntaxKind.VariableStatement) { const nameNode = findNodes( x, - ts.SyntaxKind.VariableDeclaration + tsModule.SyntaxKind.VariableDeclaration )?.[0] as ts.VariableDeclaration; return ( - nameNode?.name?.kind === ts.SyntaxKind.Identifier || + nameNode?.name?.kind === tsModule.SyntaxKind.Identifier || foundExport?.length || componentNames?.includes(nameNode?.name?.getText()) ); } else { return ( - (x.name.kind === ts.SyntaxKind.Identifier && foundExport?.length) || + (x.name.kind === tsModule.SyntaxKind.Identifier && + foundExport?.length) || componentNames?.includes(x.name.getText()) ); } @@ -191,10 +214,10 @@ export function findExportDeclarationsForJsx( const exportedDeclarations: Array< ts.VariableDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration > = exported.map((x) => { - if (x.kind === ts.SyntaxKind.VariableStatement) { + if (x.kind === tsModule.SyntaxKind.VariableStatement) { const nameNode = findNodes( x, - ts.SyntaxKind.VariableDeclaration + tsModule.SyntaxKind.VariableDeclaration )?.[0] as ts.VariableDeclaration; return nameNode; } @@ -207,13 +230,16 @@ export function findExportDeclarationsForJsx( export function findDefaultExportIdentifier( source: ts.SourceFile ): ts.Identifier | null { + if (!tsModule) { + tsModule = require('typescript'); + } const exports = findNodes( source, - ts.SyntaxKind.ExportAssignment + tsModule.SyntaxKind.ExportAssignment ) as ts.ExportAssignment[]; const identifier = exports .map((x) => x.expression) - .find((x) => x.kind === ts.SyntaxKind.Identifier) as ts.Identifier; + .find((x) => x.kind === tsModule.SyntaxKind.Identifier) as ts.Identifier; return identifier || null; } @@ -221,13 +247,16 @@ export function findDefaultExportIdentifier( export function findDefaultClassOrFunction( source: ts.SourceFile | null ): ts.FunctionDeclaration | ts.ClassDeclaration | null { + if (!tsModule) { + tsModule = require('typescript'); + } const fns = findNodes( source, - ts.SyntaxKind.FunctionDeclaration + tsModule.SyntaxKind.FunctionDeclaration ) as ts.FunctionDeclaration[]; const cls = findNodes( source, - ts.SyntaxKind.ClassDeclaration + tsModule.SyntaxKind.ClassDeclaration ) as ts.ClassDeclaration[]; return ( @@ -240,10 +269,13 @@ export function findDefaultClassOrFunction( function hasDefaultExportModifier( x: ts.ClassDeclaration | ts.FunctionDeclaration ) { + if (!tsModule) { + tsModule = require('typescript'); + } return ( x.modifiers && - x.modifiers.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) && - x.modifiers.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword) + x.modifiers.some((m) => m.kind === tsModule.SyntaxKind.ExportKeyword) && + x.modifiers.some((m) => m.kind === tsModule.SyntaxKind.DefaultKeyword) ); } @@ -251,9 +283,12 @@ export function findComponentImportPath( componentName: string, source: ts.SourceFile ) { + if (!tsModule) { + tsModule = require('typescript'); + } const allImports = findNodes( source, - ts.SyntaxKind.ImportDeclaration + tsModule.SyntaxKind.ImportDeclaration ) as ts.ImportDeclaration[]; const matching = allImports.filter((i: ts.ImportDeclaration) => { return ( @@ -272,9 +307,12 @@ export function findComponentImportPath( } export function findElements(source: ts.SourceFile, tagName: string) { + if (!tsModule) { + tsModule = require('typescript'); + } const nodes = findNodes(source, [ - ts.SyntaxKind.JsxSelfClosingElement, - ts.SyntaxKind.JsxOpeningElement, + tsModule.SyntaxKind.JsxSelfClosingElement, + tsModule.SyntaxKind.JsxOpeningElement, ]); return nodes.filter((node) => isTag(tagName, node)); } @@ -292,16 +330,19 @@ export function findClosestOpening(tagName: string, node: ts.Node) { } export function isTag(tagName: string, node: ts.Node) { - if (ts.isJsxOpeningLikeElement(node)) { + if (!tsModule) { + tsModule = require('typescript'); + } + if (tsModule.isJsxOpeningLikeElement(node)) { return ( - node.tagName.kind === ts.SyntaxKind.Identifier && + node.tagName.kind === tsModule.SyntaxKind.Identifier && node.tagName.text === tagName ); } - if (ts.isJsxElement(node) && node.openingElement) { + if (tsModule.isJsxElement(node) && node.openingElement) { return ( - node.openingElement.tagName.kind === ts.SyntaxKind.Identifier && + node.openingElement.tagName.kind === tsModule.SyntaxKind.Identifier && node.openingElement.tagName.getText() === tagName ); } @@ -313,9 +354,13 @@ export function addInitialRoutes( sourcePath: string, source: ts.SourceFile ): StringChange[] { + if (!tsModule) { + tsModule = require('typescript'); + } + const jsxClosingElements = findNodes(source, [ - ts.SyntaxKind.JsxClosingElement, - ts.SyntaxKind.JsxClosingFragment, + tsModule.SyntaxKind.JsxClosingElement, + tsModule.SyntaxKind.JsxClosingFragment, ]); const outerMostJsxClosing = jsxClosingElements[jsxClosingElements.length - 1]; @@ -535,9 +580,12 @@ export function updateReduxStore( modulePath: string; } ): StringChange[] { + if (!tsModule) { + tsModule = require('typescript'); + } const calls = findNodes( source, - ts.SyntaxKind.CallExpression + tsModule.SyntaxKind.CallExpression ) as ts.CallExpression[]; let reducerDescriptor: ts.ObjectLiteralExpression; @@ -547,13 +595,13 @@ export function updateReduxStore( continue; } const arg = expr.arguments[0]; - if (ts.isObjectLiteralExpression(arg)) { + if (tsModule.isObjectLiteralExpression(arg)) { let found: ts.ObjectLiteralExpression; for (const prop of arg.properties) { if ( - ts.isPropertyAssignment(prop) && + tsModule.isPropertyAssignment(prop) && prop.name.getText() === 'reducer' && - ts.isObjectLiteralExpression(prop.initializer) + tsModule.isObjectLiteralExpression(prop.initializer) ) { found = prop.initializer; break; @@ -572,7 +620,7 @@ export function updateReduxStore( continue; } const arg = expr.arguments[0]; - if (ts.isObjectLiteralExpression(arg)) { + if (tsModule.isObjectLiteralExpression(arg)) { reducerDescriptor = arg; break; } @@ -602,14 +650,17 @@ export function updateReduxStore( } export function getComponentNode(sourceFile: ts.SourceFile): ts.Node | null { + if (!tsModule) { + tsModule = require('typescript'); + } const defaultExport = findDefaultExport(sourceFile); if ( !( defaultExport && - (findNodes(defaultExport, ts.SyntaxKind.JsxElement).length > 0 || - findNodes(defaultExport, ts.SyntaxKind.JsxSelfClosingElement).length > - 0) + (findNodes(defaultExport, tsModule.SyntaxKind.JsxElement).length > 0 || + findNodes(defaultExport, tsModule.SyntaxKind.JsxSelfClosingElement) + .length > 0) ) ) { return null; @@ -622,11 +673,15 @@ export function getComponentPropsInterface( sourceFile: ts.SourceFile, cmpDeclaration: ts.Node ): ts.InterfaceDeclaration | null { + if (!tsModule) { + tsModule = require('typescript'); + } let propsTypeName: string = null; - if (ts.isFunctionDeclaration(cmpDeclaration)) { + if (tsModule.isFunctionDeclaration(cmpDeclaration)) { const propsParam: ts.ParameterDeclaration = cmpDeclaration.parameters.find( - (x) => ts.isParameter(x) && (x.name as ts.Identifier).text === 'props' + (x) => + tsModule.isParameter(x) && (x.name as ts.Identifier).text === 'props' ); if (propsParam?.type?.['typeName']) { @@ -636,13 +691,16 @@ export function getComponentPropsInterface( } } else if ( (cmpDeclaration as ts.VariableDeclaration).initializer && - ts.isArrowFunction((cmpDeclaration as ts.VariableDeclaration).initializer) + tsModule.isArrowFunction( + (cmpDeclaration as ts.VariableDeclaration).initializer + ) ) { const arrowFn = (cmpDeclaration as ts.VariableDeclaration) .initializer as ts.ArrowFunction; const propsParam: ts.ParameterDeclaration = arrowFn.parameters.find( - (x) => ts.isParameter(x) && (x.name as ts.Identifier).text === 'props' + (x) => + tsModule.isParameter(x) && (x.name as ts.Identifier).text === 'props' ); if (propsParam?.type?.['typeName']) { @@ -652,7 +710,7 @@ export function getComponentPropsInterface( } } else if ( // do we have a class component extending from React.Component - ts.isClassDeclaration(cmpDeclaration) && + tsModule.isClassDeclaration(cmpDeclaration) && cmpDeclaration.heritageClauses && cmpDeclaration.heritageClauses.length > 0 ) { @@ -677,7 +735,7 @@ export function getComponentPropsInterface( } if (propsTypeName) { - return findNodes(sourceFile, ts.SyntaxKind.InterfaceDeclaration).find( + return findNodes(sourceFile, tsModule.SyntaxKind.InterfaceDeclaration).find( (x: ts.InterfaceDeclaration) => { return (x.name as ts.Identifier).getText() === propsTypeName; } diff --git a/packages/react/src/utils/component-props.ts b/packages/react/src/utils/component-props.ts index 3fcc45c190675..bcf2b9fe7e56f 100644 --- a/packages/react/src/utils/component-props.ts +++ b/packages/react/src/utils/component-props.ts @@ -1,12 +1,17 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { getComponentPropsInterface } from './ast-utils'; +let tsModule: typeof import('typescript'); + // TODO: candidate to refactor with the angular component story export function getArgsDefaultValue(property: ts.SyntaxKind): string { + if (!tsModule) { + tsModule = require('typescript'); + } const typeNameToDefault: Record = { - [ts.SyntaxKind.StringKeyword]: "''", - [ts.SyntaxKind.NumberKeyword]: 0, - [ts.SyntaxKind.BooleanKeyword]: false, + [tsModule.SyntaxKind.StringKeyword]: "''", + [tsModule.SyntaxKind.NumberKeyword]: 0, + [tsModule.SyntaxKind.BooleanKeyword]: false, }; const resolvedValue = typeNameToDefault[property]; @@ -21,6 +26,9 @@ export function getDefaultsForComponent( sourceFile: ts.SourceFile, cmpDeclaration: ts.Node ) { + if (!tsModule) { + tsModule = require('typescript'); + } const propsInterface = getComponentPropsInterface(sourceFile, cmpDeclaration); let propsTypeName: string = null; @@ -37,7 +45,7 @@ export function getDefaultsForComponent( if (propsInterface) { propsTypeName = propsInterface.name.text; props = propsInterface.members.map((member: ts.PropertySignature) => { - if (member.type.kind === ts.SyntaxKind.FunctionType) { + if (member.type.kind === tsModule.SyntaxKind.FunctionType) { argTypes.push({ name: (member.name as ts.Identifier).text, type: 'action', @@ -58,7 +66,7 @@ export function getDefaultsForComponent( export function getImportForType(sourceFile: ts.SourceFile, typeName: string) { return sourceFile.statements.find( (statement: ts.Node) => - ts.isImportDeclaration(statement) && + tsModule.isImportDeclaration(statement) && statement.getText().includes(typeName) ); } diff --git a/packages/react/src/utils/create-ts-config.ts b/packages/react/src/utils/create-ts-config.ts index 6a1ea02232983..cedc62debf966 100644 --- a/packages/react/src/utils/create-ts-config.ts +++ b/packages/react/src/utils/create-ts-config.ts @@ -1,5 +1,5 @@ import { Tree } from 'nx/src/generators/tree'; -import * as shared from '@nrwl/workspace/src/utils/create-ts-config'; +import * as shared from '@nrwl/js/src/utils/typescript/create-ts-config'; import { writeJson } from 'nx/src/generators/utils/json'; export function createTsConfig( diff --git a/packages/storybook/package.json b/packages/storybook/package.json index d441d8a458a65..d3d93510415a2 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -33,6 +33,7 @@ "@nrwl/cypress": "file:../cypress", "@nrwl/devkit": "file:../devkit", "@nrwl/linter": "file:../linter", + "@nrwl/js": "file:../js", "@nrwl/workspace": "file:../workspace", "dotenv": "~10.0.0", "@phenomnomnominal/tsquery": "4.1.1", diff --git a/packages/storybook/src/generators/configuration/configuration.ts b/packages/storybook/src/generators/configuration/configuration.ts index 93e47b7902768..3294aa50f74d6 100644 --- a/packages/storybook/src/generators/configuration/configuration.ts +++ b/packages/storybook/src/generators/configuration/configuration.ts @@ -132,7 +132,8 @@ export async function configurationGenerator( } } - const initTask = initGenerator(tree, { + const initTask = await initGenerator(tree, { + js: schema.js, uiFramework: schema.storybook7betaConfiguration ? schema.storybook7UiFramework : schema.uiFramework, diff --git a/packages/storybook/src/generators/init/init.spec.ts b/packages/storybook/src/generators/init/init.spec.ts index 078a3d6fe0fa5..9c2091c396c8f 100644 --- a/packages/storybook/src/generators/init/init.spec.ts +++ b/packages/storybook/src/generators/init/init.spec.ts @@ -393,7 +393,7 @@ describe('@nrwl/storybook:init', () => { }); describe('update root tsconfig.json', () => { - it('should set the tsnode module to commonjs if there is a root tsconfig.json', () => { + it('should set the tsnode module to commonjs if there is a root tsconfig.json', async () => { tree.write( 'tsconfig.json', JSON.stringify({ @@ -422,14 +422,14 @@ describe('@nrwl/storybook:init', () => { ], }) ); - initGenerator(tree, { + await initGenerator(tree, { uiFramework: '@storybook/react', }); const tsconfig = readJson(tree, 'tsconfig.json'); expect(tsconfig['ts-node'].compilerOptions.module).toEqual('commonjs'); }); - it('should set the tsnode module to commonjs and respect other tsnode settings', () => { + it('should set the tsnode module to commonjs and respect other tsnode settings', async () => { tree.write( 'tsconfig.json', JSON.stringify({ @@ -457,7 +457,7 @@ describe('@nrwl/storybook:init', () => { }, }) ); - initGenerator(tree, { + await initGenerator(tree, { uiFramework: '@storybook/react', }); const tsconfig = readJson(tree, 'tsconfig.json'); diff --git a/packages/storybook/src/generators/init/init.ts b/packages/storybook/src/generators/init/init.ts index 96626bc4dd6f9..6e46bc6a5883b 100644 --- a/packages/storybook/src/generators/init/init.ts +++ b/packages/storybook/src/generators/init/init.ts @@ -7,6 +7,7 @@ import { updateJson, updateNxJson, } from '@nrwl/devkit'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { babelCoreVersion, @@ -210,7 +211,11 @@ function editRootTsConfig(tree: Tree) { } } -export function initGenerator(tree: Tree, schema: Schema) { +export async function initGenerator(tree: Tree, schema: Schema) { + await jsInitGenerator(tree, { + js: schema.js, + skipFormat: true, + }); const installTask = checkDependenciesInstalled(tree, schema); moveToDevDependencies(tree); editRootTsConfig(tree); diff --git a/packages/storybook/src/generators/init/schema.d.ts b/packages/storybook/src/generators/init/schema.d.ts index 68fce6a2857c3..c4aad2b86812f 100644 --- a/packages/storybook/src/generators/init/schema.d.ts +++ b/packages/storybook/src/generators/init/schema.d.ts @@ -4,4 +4,5 @@ export interface Schema { uiFramework: UiFramework | UiFramework7; bundler?: 'webpack' | 'vite'; // TODO(katerina): Remove when Storybook 7 storybook7betaConfiguration?: boolean; + js?: boolean; } diff --git a/packages/storybook/src/generators/init/schema.json b/packages/storybook/src/generators/init/schema.json index 1866e84a84673..1fc6e1e3bd747 100644 --- a/packages/storybook/src/generators/init/schema.json +++ b/packages/storybook/src/generators/init/schema.json @@ -49,6 +49,11 @@ "type": "boolean", "default": false, "hidden": true + }, + "js": { + "type": "boolean", + "description": "Generate JavaScript story files rather than TypeScript story files.", + "default": false } } } diff --git a/packages/web/src/generators/application/application.ts b/packages/web/src/generators/application/application.ts index d31ae15096fc3..880e795141430 100644 --- a/packages/web/src/generators/application/application.ts +++ b/packages/web/src/generators/application/application.ts @@ -24,7 +24,7 @@ import { jestProjectGenerator } from '@nrwl/jest'; import { swcCoreVersion } from '@nrwl/js/src/utils/versions'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; -import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { getRelativePathToRootTsConfig } from '@nrwl/js'; import { nxVersion, swcLoaderVersion } from '../../utils/versions'; import { webInitGenerator } from '../init/init'; @@ -74,7 +74,7 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) { ]; if (options.bundler === 'webpack') { - await ensurePackage(tree, '@nrwl/webpack', nxVersion); + ensurePackage(tree, '@nrwl/webpack', nxVersion); const { webpackProjectGenerator } = require('@nrwl/webpack'); await webpackProjectGenerator(tree, { project: options.projectName, @@ -196,7 +196,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) { await addProject(host, options); if (options.bundler === 'vite') { - await ensurePackage(host, '@nrwl/vite', nxVersion); + ensurePackage(host, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = require('@nrwl/vite'); // We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development. // See: https://vitejs.dev/guide/env-and-mode.html @@ -219,7 +219,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) { } if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') { - await ensurePackage(host, '@nrwl/vite', nxVersion); + ensurePackage(host, '@nrwl/vite', nxVersion); const { vitestGenerator } = require('@nrwl/vite'); const vitestTask = await vitestGenerator(host, { uiFramework: 'none', diff --git a/packages/web/src/generators/init/init.ts b/packages/web/src/generators/init/init.ts index 831be47935695..b2c64baae86d9 100644 --- a/packages/web/src/generators/init/init.ts +++ b/packages/web/src/generators/init/init.ts @@ -9,13 +9,14 @@ import { } from '@nrwl/devkit'; import { jestInitGenerator } from '@nrwl/jest'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; +import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs'; +import { initGenerator as jsInitGenerator } from '@nrwl/js'; import { nxVersion, tsLibVersion, typesNodeVersion, } from '../../utils/versions'; import { Schema } from './schema'; -import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs'; function updateDependencies(tree: Tree, schema: Schema) { removeDependenciesFromPackageJson(tree, ['@nrwl/web'], []); @@ -25,10 +26,6 @@ function updateDependencies(tree: Tree, schema: Schema) { '@types/node': typesNodeVersion, }; - if (schema.bundler === 'webpack') { - devDependencies['@nrwl/webpack'] = nxVersion; - } - return addDependenciesToPackageJson( tree, { @@ -41,10 +38,13 @@ function updateDependencies(tree: Tree, schema: Schema) { } export async function webInitGenerator(tree: Tree, schema: Schema) { + await jsInitGenerator(tree, { + js: false, + }); let tasks: GeneratorCallback[] = []; if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') { - const jestTask = jestInitGenerator(tree, { + const jestTask = await jestInitGenerator(tree, { skipPackageJson: schema.skipPackageJson, }); tasks.push(jestTask); diff --git a/packages/web/src/generators/init/schema.json b/packages/web/src/generators/init/schema.json index 8e7a8daab5367..b8be6c1f8fc35 100644 --- a/packages/web/src/generators/init/schema.json +++ b/packages/web/src/generators/init/schema.json @@ -32,7 +32,8 @@ "skipPackageJson": { "description": "Do not add dependencies to `package.json`.", "type": "boolean", - "default": false + "default": false, + "x-priority": "internal" }, "skipBabelConfig": { "description": "Do not generate a root babel.config.json (if babel is not needed).", diff --git a/packages/webpack/src/plugins/generate-package-json-plugin.ts b/packages/webpack/src/plugins/generate-package-json-plugin.ts index 88c2cfc415375..5c64a569345fd 100644 --- a/packages/webpack/src/plugins/generate-package-json-plugin.ts +++ b/packages/webpack/src/plugins/generate-package-json-plugin.ts @@ -8,8 +8,8 @@ import { import { getHelperDependenciesFromProjectGraph, HelperDependency, -} from '@nrwl/js/src/utils/compiler-helper-dependency'; -import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; + readTsConfig, +} from '@nrwl/js'; import { getLockFileName } from 'nx/src/lock-file/lock-file'; const pluginName = 'GeneratePackageJsonPlugin'; diff --git a/packages/webpack/src/utils/with-nx.ts b/packages/webpack/src/utils/with-nx.ts index e7e177cc8dd60..0e73d2f38d162 100644 --- a/packages/webpack/src/utils/with-nx.ts +++ b/packages/webpack/src/utils/with-nx.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import { Configuration, WebpackPluginInstance, ProgressPlugin } from 'webpack'; import { ExecutorContext } from 'nx/src/config/misc-interfaces'; import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin'; -import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; +import { readTsConfig } from '@nrwl/js'; import { LicenseWebpackPlugin } from 'license-webpack-plugin'; import TerserPlugin = require('terser-webpack-plugin'); import nodeExternals = require('webpack-node-externals'); diff --git a/packages/workspace/index.ts b/packages/workspace/index.ts index cd8b7762e5738..0451ed527d6a1 100644 --- a/packages/workspace/index.ts +++ b/packages/workspace/index.ts @@ -1,4 +1,4 @@ -export { readTsConfig } from './src/utilities/typescript'; +export { readTsConfig } from './src/utilities/ts-config'; export { ProjectType, projectRootDir } from './src/utils/project-type'; export { renameSync, diff --git a/packages/workspace/migrations.json b/packages/workspace/migrations.json index d8b0369aafbd5..7211a1cb9c85f 100644 --- a/packages/workspace/migrations.json +++ b/packages/workspace/migrations.json @@ -50,7 +50,7 @@ }, "13-10-0-update-tasks-runner": { "version": "13.10.0-beta.0", - "description": "Update the tasks runner property to import it from the nx package instead of @nrwl/worksapce", + "description": "Update the tasks runner property to import it from the nx package instead of @nrwl/workspace", "cli": "nx", "implementation": "./src/migrations/update-13-10-0/update-tasks-runner" }, diff --git a/packages/workspace/src/generators/library/files/root/tsconfig.base.json b/packages/workspace/src/generators/library/files/root/tsconfig.base.json new file mode 100644 index 0000000000000..11253ac5c2b7b --- /dev/null +++ b/packages/workspace/src/generators/library/files/root/tsconfig.base.json @@ -0,0 +1,20 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "rootDir": ".", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es2015", + "module": "esnext", + "lib": ["es2017", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "baseUrl": ".", + "paths": {} + }, + "exclude": ["node_modules", "tmp"] +} diff --git a/packages/workspace/src/generators/library/library.ts b/packages/workspace/src/generators/library/library.ts index 3aed029f37001..c811616b40038 100644 --- a/packages/workspace/src/generators/library/library.ts +++ b/packages/workspace/src/generators/library/library.ts @@ -21,9 +21,10 @@ import { join } from 'path'; import { runTasksInSerial } from '../../utilities/run-tasks-in-serial'; import { getRelativePathToRootTsConfig, + getRootTsConfigFileName, getRootTsConfigPathInTree, -} from '../../utilities/typescript'; -import { nxVersion } from '../../utils/versions'; +} from '../../utilities/ts-config'; +import { nxVersion, typescriptVersion } from '../../utils/versions'; import { Schema } from './schema'; export interface NormalizedSchema extends Schema { @@ -69,7 +70,7 @@ export async function addLint( tree: Tree, options: NormalizedSchema ): Promise { - await ensurePackage(tree, '@nrwl/linter', nxVersion); + ensurePackage(tree, '@nrwl/linter', nxVersion); const { lintProjectGenerator } = require('@nrwl/linter'); return lintProjectGenerator(tree, { project: options.name, @@ -171,7 +172,7 @@ async function addJest( tree: Tree, options: NormalizedSchema ): Promise { - await ensurePackage(tree, '@nrwl/jest', nxVersion); + ensurePackage(tree, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = require('@nrwl/jest'); return await jestProjectGenerator(tree, { ...options, @@ -185,18 +186,25 @@ async function addJest( }); } +function addTypescript(tree: Tree, options: NormalizedSchema) { + if (!options.js) { + ensurePackage(tree, 'typescript', typescriptVersion); + } + + // add tsconfig.base.json + if (!options.skipTsConfig && !getRootTsConfigFileName()) { + generateFiles(tree, joinPathFragments(__dirname, './files/root'), '.', {}); + } +} + export async function libraryGenerator(tree: Tree, schema: Schema) { const options = normalizeOptions(tree, schema); + const tasks: GeneratorCallback[] = []; + addTypescript(tree, options); createFiles(tree, options); - - if (!options.skipTsConfig) { - updateRootTsConfig(tree, options); - } addProject(tree, options); - const tasks: GeneratorCallback[] = []; - if (options.linter !== 'none') { const lintCallback = await addLint(tree, options); tasks.push(lintCallback); @@ -205,6 +213,9 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { const jestCallback = await addJest(tree, options); tasks.push(jestCallback); } + if (!options.skipTsConfig) { + updateRootTsConfig(tree, options); + } if (!options.skipFormat) { await formatFiles(tree); diff --git a/packages/workspace/src/generators/library/schema.d.ts b/packages/workspace/src/generators/library/schema.d.ts index c9dae74e97155..b3c3529149bfa 100644 --- a/packages/workspace/src/generators/library/schema.d.ts +++ b/packages/workspace/src/generators/library/schema.d.ts @@ -1,5 +1,5 @@ // nx-ignore-next-line -const { Linter } = require('@nrwl/linter'); +const { Linter } = require('@nrwl/linter'); // use require to import to avoid circular dependency export interface Schema { name: string; diff --git a/packages/workspace/src/generators/move/lib/update-imports.ts b/packages/workspace/src/generators/move/lib/update-imports.ts index b815a643fdbba..1ee0dee2027eb 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.ts @@ -11,14 +11,16 @@ import { writeJson, } from '@nrwl/devkit'; import { getImportPath } from 'nx/src/utils/path'; -import * as ts from 'typescript'; -import { getRootTsConfigPathInTree } from '../../../utilities/typescript'; +import type * as ts from 'typescript'; +import { getRootTsConfigPathInTree } from '../../../utilities/ts-config'; import { findNodes } from 'nx/src/utils/typescript'; import { NormalizedSchema } from '../schema'; import { normalizeSlashes } from './utils'; import { relative } from 'path'; import { parse } from 'jsonc-parser'; +let tsModule: typeof import('typescript'); + /** * Updates all the imports in the workspace and modifies the tsconfig appropriately. * @@ -125,11 +127,14 @@ export function updateImports( * Changes imports in a file from one import to another */ function updateImportPaths(tree: Tree, path: string, from: string, to: string) { + if (!tsModule) { + tsModule = require('typescript'); + } const contents = tree.read(path, 'utf-8'); - const sourceFile = ts.createSourceFile( + const sourceFile = tsModule.createSourceFile( path, contents, - ts.ScriptTarget.Latest, + tsModule.ScriptTarget.Latest, true ); @@ -150,15 +155,18 @@ function updateImportDeclarations( from: string, to: string ): StringChange[] { + if (!tsModule) { + tsModule = require('typescript'); + } const importDecls = findNodes( sourceFile, - ts.SyntaxKind.ImportDeclaration + tsModule.SyntaxKind.ImportDeclaration ) as ts.ImportDeclaration[]; const changes: StringChange[] = []; for (const { moduleSpecifier } of importDecls) { - if (ts.isStringLiteral(moduleSpecifier)) { + if (tsModule.isStringLiteral(moduleSpecifier)) { changes.push(...updateModuleSpecifier(moduleSpecifier, from, to)); } } @@ -174,9 +182,12 @@ function updateDynamicImports( from: string, to: string ): StringChange[] { + if (!tsModule) { + tsModule = require('typescript'); + } const expressions = findNodes( sourceFile, - ts.SyntaxKind.CallExpression + tsModule.SyntaxKind.CallExpression ) as ts.CallExpression[]; const changes: StringChange[] = []; @@ -186,19 +197,19 @@ function updateDynamicImports( // handle dynamic import statements if ( - expression.kind === ts.SyntaxKind.ImportKeyword && + expression.kind === tsModule.SyntaxKind.ImportKeyword && moduleSpecifier && - ts.isStringLiteral(moduleSpecifier) + tsModule.isStringLiteral(moduleSpecifier) ) { changes.push(...updateModuleSpecifier(moduleSpecifier, from, to)); } // handle require statements if ( - ts.isIdentifier(expression) && + tsModule.isIdentifier(expression) && expression.text === 'require' && moduleSpecifier && - ts.isStringLiteral(moduleSpecifier) + tsModule.isStringLiteral(moduleSpecifier) ) { changes.push(...updateModuleSpecifier(moduleSpecifier, from, to)); } diff --git a/packages/workspace/src/generators/remove/lib/update-jest-config.ts b/packages/workspace/src/generators/remove/lib/update-jest-config.ts index 7a5fa9501615b..17c508e5801bf 100644 --- a/packages/workspace/src/generators/remove/lib/update-jest-config.ts +++ b/packages/workspace/src/generators/remove/lib/update-jest-config.ts @@ -7,18 +7,15 @@ import { import { getSourceNodes } from '../../../utilities/typescript/get-source-nodes'; import { Schema } from '../schema'; -import { +import type { ArrayLiteralExpression, - createSourceFile, - isArrayLiteralExpression, - isPropertyAssignment, - isStringLiteral, PropertyAssignment, - ScriptTarget, StringLiteral, } from 'typescript'; import { join } from 'path'; +let tsModule: typeof import('typescript'); + function isUsingUtilityFunction(host: Tree) { return host.read('jest.config.ts').toString().includes('getJestProjects()'); } @@ -31,6 +28,16 @@ export function updateJestConfig( schema: Schema, projectConfig: ProjectConfiguration ) { + if (!tsModule) { + tsModule = require('typescript'); + } + const { + createSourceFile, + ScriptTarget, + isPropertyAssignment, + isArrayLiteralExpression, + isStringLiteral, + } = tsModule; const projectToRemove = schema.projectName; if ( diff --git a/packages/workspace/src/generators/remove/lib/update-tsconfig.ts b/packages/workspace/src/generators/remove/lib/update-tsconfig.ts index 1d3e16c0086b7..19dc1e18683f0 100644 --- a/packages/workspace/src/generators/remove/lib/update-tsconfig.ts +++ b/packages/workspace/src/generators/remove/lib/update-tsconfig.ts @@ -5,7 +5,7 @@ import { Tree, updateJson, } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '../../../utilities/typescript'; +import { getRootTsConfigPathInTree } from '../../../utilities/ts-config'; import { Schema } from '../schema'; import { createProjectRootMappings, diff --git a/packages/workspace/src/generators/utils/insert-import.ts b/packages/workspace/src/generators/utils/insert-import.ts index ebf13ceb5b280..f7ab9b4510550 100644 --- a/packages/workspace/src/generators/utils/insert-import.ts +++ b/packages/workspace/src/generators/utils/insert-import.ts @@ -1,13 +1,8 @@ import { insertStatement } from './insert-statement'; import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit'; -import { - createSourceFile, - isImportDeclaration, - isNamedImports, - isStringLiteral, - NamedImports, - ScriptTarget, -} from 'typescript'; +import type { NamedImports } from 'typescript'; + +let tsModule: typeof import('typescript'); export function insertImport( tree: Tree, @@ -15,6 +10,17 @@ export function insertImport( name: string, modulePath: string ) { + if (!tsModule) { + tsModule = require('typescript'); + } + const { + createSourceFile, + ScriptTarget, + isStringLiteral, + isImportDeclaration, + isNamedImports, + } = tsModule; + const contents = tree.read(path, 'utf-8'); const sourceFile = createSourceFile(path, contents, ScriptTarget.ESNext); diff --git a/packages/workspace/src/generators/utils/insert-statement.ts b/packages/workspace/src/generators/utils/insert-statement.ts index 85dfee7004461..022a8d36a53d9 100644 --- a/packages/workspace/src/generators/utils/insert-statement.ts +++ b/packages/workspace/src/generators/utils/insert-statement.ts @@ -1,14 +1,16 @@ import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit'; -import { - createSourceFile, - isImportDeclaration, - ScriptTarget, -} from 'typescript'; + +let tsModule: typeof import('typescript'); /** * Insert a statement after the last import statement in a file */ export function insertStatement(tree: Tree, path: string, statement: string) { + if (!tsModule) { + tsModule = require('typescript'); + } + const { createSourceFile, isImportDeclaration, ScriptTarget } = tsModule; + const contents = tree.read(path, 'utf-8'); const sourceFile = createSourceFile(path, contents, ScriptTarget.ESNext); diff --git a/packages/workspace/src/utilities/ast-utils.ts b/packages/workspace/src/utilities/ast-utils.ts index 5f94ccdc4dc7d..335d6ab1aaf14 100644 --- a/packages/workspace/src/utilities/ast-utils.ts +++ b/packages/workspace/src/utilities/ast-utils.ts @@ -1,8 +1,10 @@ import type { Tree } from '@nrwl/devkit'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { getSourceNodes } from './typescript'; import { findNodes } from 'nx/src/utils/typescript'; +let tsModule: typeof import('typescript'); + function nodesByPosition(first: ts.Node, second: ts.Node): number { return first.getStart() - second.getStart(); } @@ -86,15 +88,18 @@ export function insertImport( fileName: string, isDefault = false ): ts.SourceFile { + if (!tsModule) { + tsModule = require('typescript'); + } const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + const allImports = findNodes(rootNode, tsModule.SyntaxKind.ImportDeclaration); // get nodes that map to import statements from the file fileName const relevantImports = allImports.filter((node) => { // StringLiteral of the ImportDeclaration is the import file (fileName in this case). const importFiles = node .getChildren() - .filter((child) => child.kind === ts.SyntaxKind.StringLiteral) + .filter((child) => child.kind === tsModule.SyntaxKind.StringLiteral) .map((n) => (n as ts.StringLiteral).text); return importFiles.filter((file) => file === fileName).length === 1; @@ -107,9 +112,9 @@ export function insertImport( relevantImports.forEach((n) => { Array.prototype.push.apply( imports, - findNodes(n, ts.SyntaxKind.Identifier) + findNodes(n, tsModule.SyntaxKind.Identifier) ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + if (findNodes(n, tsModule.SyntaxKind.AsteriskToken).length > 0) { importsAsterisk = true; } }); @@ -128,9 +133,12 @@ export function insertImport( const fallbackPos = findNodes( relevantImports[0], - ts.SyntaxKind.CloseBraceToken + tsModule.SyntaxKind.CloseBraceToken )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + findNodes( + relevantImports[0], + tsModule.SyntaxKind.FromKeyword + )[0].getStart(); return insertAfterLastOccurrence( host, @@ -146,9 +154,10 @@ export function insertImport( } // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - (n: ts.StringLiteral) => n.text === 'use strict' - ); + const useStrict = findNodes( + rootNode, + tsModule.SyntaxKind.StringLiteral + ).filter((n: ts.StringLiteral) => n.text === 'use strict'); let fallbackPos = 0; if (useStrict.length > 0) { fallbackPos = useStrict[0].end; @@ -169,7 +178,7 @@ export function insertImport( toInsert, fileToEdit, fallbackPos, - ts.SyntaxKind.StringLiteral + tsModule.SyntaxKind.StringLiteral ); } @@ -206,7 +215,10 @@ export function addGlobal( modulePath: string, statement: string ): ts.SourceFile { - const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration); + if (!tsModule) { + tsModule = require('typescript'); + } + const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); if (allImports.length > 0) { const lastImport = allImports[allImports.length - 1]; return insertChange( @@ -225,7 +237,10 @@ export function getImport( source: ts.SourceFile, predicate: (a: any) => boolean ): { moduleSpec: string; bindings: string[] }[] { - const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration); + if (!tsModule) { + tsModule = require('typescript'); + } + const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const matching = allImports.filter((i: ts.ImportDeclaration) => predicate(i.moduleSpecifier.getText()) ); @@ -267,9 +282,12 @@ export function addParameterToConstructor( modulePath: string, opts: { className: string; param: string } ): ts.SourceFile { + if (!tsModule) { + tsModule = require('typescript'); + } const clazz = findClass(source, opts.className); const constructor = clazz.members.filter( - (m) => m.kind === ts.SyntaxKind.Constructor + (m) => m.kind === tsModule.SyntaxKind.Constructor )[0]; if (constructor) { @@ -307,11 +325,14 @@ export function findClass( className: string, silent: boolean = false ): ts.ClassDeclaration { + if (!tsModule) { + tsModule = require('typescript'); + } const nodes = getSourceNodes(source); const clazz = nodes.filter( (n) => - n.kind === ts.SyntaxKind.ClassDeclaration && + n.kind === tsModule.SyntaxKind.ClassDeclaration && (n).name.text === className )[0] as ts.ClassDeclaration; diff --git a/packages/workspace/src/utilities/buildable-libs-utils.ts b/packages/workspace/src/utilities/buildable-libs-utils.ts index d05ef605b9a94..b4c495101d1b3 100644 --- a/packages/workspace/src/utilities/buildable-libs-utils.ts +++ b/packages/workspace/src/utilities/buildable-libs-utils.ts @@ -8,11 +8,13 @@ import { stripIndents, writeJsonFile, } from '@nrwl/devkit'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import { unlinkSync } from 'fs'; import { output } from './output'; import { isNpmProject } from 'nx/src/project-graph/operators'; +let tsModule: typeof import('typescript'); + function isBuildable(target: string, node: ProjectGraphProjectNode): boolean { return ( node.data.targets && @@ -188,13 +190,19 @@ export function computeCompilerOptionsPaths( } function readPaths(tsConfig: string | ts.ParsedCommandLine) { + if (!tsModule) { + tsModule = require('typescript'); + } try { let config: ts.ParsedCommandLine; if (typeof tsConfig === 'string') { - const configFile = ts.readConfigFile(tsConfig, ts.sys.readFile); - config = ts.parseJsonConfigFileContent( + const configFile = tsModule.readConfigFile( + tsConfig, + tsModule.sys.readFile + ); + config = tsModule.parseJsonConfigFileContent( configFile.config, - ts.sys, + tsModule.sys, dirname(tsConfig) ); } else { diff --git a/packages/workspace/src/utilities/ts-config.ts b/packages/workspace/src/utilities/ts-config.ts new file mode 100644 index 0000000000000..e68f64e7ebad4 --- /dev/null +++ b/packages/workspace/src/utilities/ts-config.ts @@ -0,0 +1,54 @@ +import { offsetFromRoot, Tree, workspaceRoot } from '@nrwl/devkit'; +import { existsSync } from 'fs'; +import { dirname, join } from 'path'; + +let tsModule: typeof import('typescript'); + +export function readTsConfig(tsConfigPath: string) { + if (!tsModule) { + tsModule = require('typescript'); + } + const readResult = tsModule.readConfigFile( + tsConfigPath, + tsModule.sys.readFile + ); + return tsModule.parseJsonConfigFileContent( + readResult.config, + tsModule.sys, + dirname(tsConfigPath) + ); +} + +export function getRootTsConfigPathInTree(tree: Tree): string | null { + for (const path of ['tsconfig.base.json', 'tsconfig.json']) { + if (tree.exists(path)) { + return path; + } + } + + return 'tsconfig.base.json'; +} + +export function getRelativePathToRootTsConfig( + tree: Tree, + targetPath: string +): string { + return offsetFromRoot(targetPath) + getRootTsConfigPathInTree(tree); +} + +export function getRootTsConfigFileName(): string | null { + for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) { + const tsConfigPath = join(workspaceRoot, tsConfigName); + if (existsSync(tsConfigPath)) { + return tsConfigName; + } + } + + return null; +} + +export function getRootTsConfigPath(): string | null { + const tsConfigFileName = getRootTsConfigFileName(); + + return tsConfigFileName ? join(workspaceRoot, tsConfigFileName) : null; +} diff --git a/packages/workspace/src/utilities/typescript.ts b/packages/workspace/src/utilities/typescript.ts index 9b3f7485b8eab..3337ed0234db2 100644 --- a/packages/workspace/src/utilities/typescript.ts +++ b/packages/workspace/src/utilities/typescript.ts @@ -1,7 +1,5 @@ -import { offsetFromRoot, Tree } from '@nrwl/devkit'; import { workspaceRoot } from '@nrwl/devkit'; -import { existsSync } from 'fs'; -import { dirname, join } from 'path'; +import { dirname } from 'path'; import type * as ts from 'typescript'; export { compileTypeScript } from './typescript/compilation'; export type { TypeScriptCompilationOptions } from './typescript/compilation'; @@ -12,21 +10,6 @@ const normalizedAppRoot = workspaceRoot.replace(/\\/g, '/'); let tsModule: typeof import('typescript'); -export function readTsConfig(tsConfigPath: string) { - if (!tsModule) { - tsModule = require('typescript'); - } - const readResult = tsModule.readConfigFile( - tsConfigPath, - tsModule.sys.readFile - ); - return tsModule.parseJsonConfigFileContent( - readResult.config, - tsModule.sys, - dirname(tsConfigPath) - ); -} - function readTsConfigOptions(tsConfigPath: string) { if (!tsModule) { tsModule = require('typescript'); @@ -96,37 +79,3 @@ function getCompilerHost(tsConfigPath: string) { ); return { options, host, moduleResolutionCache }; } - -export function getRootTsConfigPathInTree(tree: Tree): string | null { - for (const path of ['tsconfig.base.json', 'tsconfig.json']) { - if (tree.exists(path)) { - return path; - } - } - - return 'tsconfig.base.json'; -} - -export function getRelativePathToRootTsConfig( - tree: Tree, - targetPath: string -): string { - return offsetFromRoot(targetPath) + getRootTsConfigPathInTree(tree); -} - -export function getRootTsConfigFileName(): string | null { - for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) { - const tsConfigPath = join(workspaceRoot, tsConfigName); - if (existsSync(tsConfigPath)) { - return tsConfigName; - } - } - - return null; -} - -export function getRootTsConfigPath(): string | null { - const tsConfigFileName = getRootTsConfigFileName(); - - return tsConfigFileName ? join(workspaceRoot, tsConfigFileName) : null; -} diff --git a/packages/workspace/src/utilities/typescript/compilation.ts b/packages/workspace/src/utilities/typescript/compilation.ts index 9b2d9b1b42af7..bb3532bc12476 100644 --- a/packages/workspace/src/utilities/typescript/compilation.ts +++ b/packages/workspace/src/utilities/typescript/compilation.ts @@ -1,8 +1,10 @@ import { joinPathFragments, logger } from '@nrwl/devkit'; import { removeSync } from 'fs-extra'; -import * as ts from 'typescript'; +import type * as ts from 'typescript'; import type { CustomTransformers, Diagnostic, Program } from 'typescript'; -import { readTsConfig } from '../typescript'; +import { readTsConfig } from '../ts-config'; + +let tsModule: typeof import('typescript'); export interface TypeScriptCompilationOptions { outputPath: string; @@ -44,6 +46,9 @@ export function compileTypeScriptWatcher( errorCount: number ) => void | Promise ) { + if (!tsModule) { + tsModule = require('typescript'); + } const normalizedOptions = normalizeOptions(options); const tsConfig = getNormalizedTsConfig(normalizedOptions); @@ -51,10 +56,10 @@ export function compileTypeScriptWatcher( removeSync(normalizedOptions.outputPath); } - const host = ts.createWatchCompilerHost( + const host = tsModule.createWatchCompilerHost( tsConfig.fileNames, tsConfig.options, - ts.sys + tsModule.sys ); const originalAfterProgramCreate = host.afterProgramCreate; @@ -94,7 +99,7 @@ export function compileTypeScriptWatcher( await callback?.(a, b, c, d); }; - return ts.createWatchProgram(host); + return tsModule.createWatchProgram(host); } function mergeCustomTransformers( @@ -153,8 +158,11 @@ function createProgram( tsconfig: ts.ParsedCommandLine, { projectName, getCustomTransformers }: TypeScriptCompilationOptions ): { success: boolean } { - const host = ts.createCompilerHost(tsconfig.options); - const program = ts.createProgram({ + if (!tsModule) { + tsModule = require('typescript'); + } + const host = tsModule.createCompilerHost(tsconfig.options); + const program = tsModule.createProgram({ rootNames: tsconfig.fileNames, options: tsconfig.options, host, @@ -168,11 +176,11 @@ function createProgram( getCustomTransformers?.(program) ); if (results.emitSkipped) { - const diagnostics = ts.formatDiagnosticsWithColorAndContext( + const diagnostics = tsModule.formatDiagnosticsWithColorAndContext( results.diagnostics, { - getCurrentDirectory: () => ts.sys.getCurrentDirectory(), - getNewLine: () => ts.sys.newLine, + getCurrentDirectory: () => tsModule.sys.getCurrentDirectory(), + getNewLine: () => tsModule.sys.newLine, getCanonicalFileName: (name) => name, } ); diff --git a/packages/workspace/src/utilities/typescript/get-source-nodes.ts b/packages/workspace/src/utilities/typescript/get-source-nodes.ts index e2b6fa7f24da6..b3b321e60d4b7 100644 --- a/packages/workspace/src/utilities/typescript/get-source-nodes.ts +++ b/packages/workspace/src/utilities/typescript/get-source-nodes.ts @@ -1,4 +1,4 @@ -import * as ts from 'typescript'; +import type * as ts from 'typescript'; export function getSourceNodes(sourceFile: ts.SourceFile): ts.Node[] { const nodes: ts.Node[] = [sourceFile]; diff --git a/packages/workspace/src/utils/ast-utils.ts b/packages/workspace/src/utils/ast-utils.ts index c8afac24f4e91..4c2de791d24c3 100644 --- a/packages/workspace/src/utils/ast-utils.ts +++ b/packages/workspace/src/utils/ast-utils.ts @@ -17,20 +17,17 @@ import { Source, Tree, } from '@angular-devkit/schematics'; -import * as ts from 'typescript'; -import { - parseJson, - ProjectConfiguration, - serializeJson, - FileData, -} from '@nrwl/devkit'; +import type * as ts from 'typescript'; +import { parseJson, serializeJson } from '@nrwl/devkit'; import { getWorkspacePath } from './cli-config-utils'; -import { extname, join, normalize, Path } from '@angular-devkit/core'; -import type { NxJsonConfiguration, ProjectsConfigurations } from '@nrwl/devkit'; +import { join, Path } from '@angular-devkit/core'; +import type { NxJsonConfiguration } from '@nrwl/devkit'; import { addInstallTask } from './rules/add-install-task'; import { findNodes } from 'nx/src/utils/typescript'; import { getSourceNodes } from '../utilities/typescript/get-source-nodes'; +let tsModule: typeof import('typescript'); + function nodesByPosition(first: ts.Node, second: ts.Node): number { return first.getStart() - second.getStart(); } @@ -181,9 +178,12 @@ export function addParameterToConstructor( modulePath: string, opts: { className: string; param: string } ): Change[] { + if (!tsModule) { + tsModule = require('typescript'); + } const clazz = findClass(source, opts.className); const constructor = clazz.members.filter( - (m) => m.kind === ts.SyntaxKind.Constructor + (m) => m.kind === tsModule.SyntaxKind.Constructor )[0]; if (constructor) { throw new Error('Should be tested'); @@ -221,12 +221,15 @@ export function findClass( className: string, silent: boolean = false ): ts.ClassDeclaration { + if (!tsModule) { + tsModule = require('typescript'); + } const nodes = getSourceNodes(source); const clazz = ( nodes.filter( (n) => - n.kind === ts.SyntaxKind.ClassDeclaration && + n.kind === tsModule.SyntaxKind.ClassDeclaration && (n).name.text === className )[0] ); @@ -276,7 +279,10 @@ export function getImport( source: ts.SourceFile, predicate: (a: any) => boolean ): { moduleSpec: string; bindings: string[] }[] { - const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration); + if (!tsModule) { + tsModule = require('typescript'); + } + const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const matching = allImports.filter((i: ts.ImportDeclaration) => predicate(i.moduleSpecifier.getText()) ); @@ -300,7 +306,10 @@ export function addGlobal( modulePath: string, statement: string ): Change[] { - const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration); + if (!tsModule) { + tsModule = require('typescript'); + } + const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); if (allImports.length > 0) { const lastImport = allImports[allImports.length - 1]; return [ @@ -573,15 +582,18 @@ export function insertImport( fileName: string, isDefault = false ): Change { + if (!tsModule) { + tsModule = require('typescript'); + } const rootNode = source; - const allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration); + const allImports = findNodes(rootNode, tsModule.SyntaxKind.ImportDeclaration); // get nodes that map to import statements from the file fileName const relevantImports = allImports.filter((node) => { // StringLiteral of the ImportDeclaration is the import file (fileName in this case). const importFiles = node .getChildren() - .filter((child) => child.kind === ts.SyntaxKind.StringLiteral) + .filter((child) => child.kind === tsModule.SyntaxKind.StringLiteral) .map((n) => (n as ts.StringLiteral).text); return importFiles.filter((file) => file === fileName).length === 1; @@ -594,9 +606,9 @@ export function insertImport( relevantImports.forEach((n) => { Array.prototype.push.apply( imports, - findNodes(n, ts.SyntaxKind.Identifier) + findNodes(n, tsModule.SyntaxKind.Identifier) ); - if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) { + if (findNodes(n, tsModule.SyntaxKind.AsteriskToken).length > 0) { importsAsterisk = true; } }); @@ -615,9 +627,12 @@ export function insertImport( const fallbackPos = findNodes( relevantImports[0], - ts.SyntaxKind.CloseBraceToken + tsModule.SyntaxKind.CloseBraceToken )[0].getStart() || - findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart(); + findNodes( + relevantImports[0], + tsModule.SyntaxKind.FromKeyword + )[0].getStart(); return insertAfterLastOccurrence( imports, @@ -631,9 +646,10 @@ export function insertImport( } // no such import declaration exists - const useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter( - (n: ts.StringLiteral) => n.text === 'use strict' - ); + const useStrict = findNodes( + rootNode, + tsModule.SyntaxKind.StringLiteral + ).filter((n: ts.StringLiteral) => n.text === 'use strict'); let fallbackPos = 0; if (useStrict.length > 0) { fallbackPos = useStrict[0].end; @@ -652,7 +668,7 @@ export function insertImport( toInsert, fileToEdit, fallbackPos, - ts.SyntaxKind.StringLiteral + tsModule.SyntaxKind.StringLiteral ); } diff --git a/packages/workspace/src/utils/rules/to-js.ts b/packages/workspace/src/utils/rules/to-js.ts index 05a855fa8b41c..5f46e9e511528 100644 --- a/packages/workspace/src/utils/rules/to-js.ts +++ b/packages/workspace/src/utils/rules/to-js.ts @@ -1,4 +1,3 @@ -import { transpile, JsxEmit, ScriptTarget } from 'typescript'; import { forEach, Rule, @@ -10,7 +9,14 @@ import { import { normalize } from '@angular-devkit/core'; import { updateJsonInTree } from '../ast-utils'; +let tsModule: typeof import('typescript'); + export function toJS(): Rule { + if (!tsModule) { + tsModule = require('typescript'); + } + + const { transpile, JsxEmit, ScriptTarget } = tsModule; return chain([ forEach( when( diff --git a/scripts/depcheck/missing.ts b/scripts/depcheck/missing.ts index bcf5cd30c8184..1ccc3293574fc 100644 --- a/scripts/depcheck/missing.ts +++ b/scripts/depcheck/missing.ts @@ -63,6 +63,7 @@ const IGNORE_MATCHES_IN_PACKAGE = { 'identity-obj-proxy', '@angular-devkit/schematics', ], + js: ['@nrwl/linter'], linter: [ 'eslint', '@angular-devkit/schematics',