cleanup(misc): clean up init generators (#21088)
This commit is contained in:
parent
dcef077032
commit
047dc22aed
@ -8,28 +8,7 @@
|
||||
"title": "Init Angular Plugin",
|
||||
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nx/angular:init --style=scss",
|
||||
"description": "Installs angular dependencies and initializes the `@nx/angular` plugin with the `scss` stylesheet format."
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests.",
|
||||
"default": "jest",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["cypress", "playwright", "none"],
|
||||
"x-prompt": "Which E2E test runner would you like to use?",
|
||||
"description": "Test runner to use for end to end (e2e) tests.",
|
||||
"default": "cypress",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipInstall": {
|
||||
"type": "boolean",
|
||||
"description": "Skip installing after adding `@nx/workspace`.",
|
||||
@ -42,38 +21,6 @@
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint", "none"],
|
||||
"default": "eslint",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
"default": "css",
|
||||
"enum": ["css", "scss", "sass", "less"],
|
||||
"x-prompt": {
|
||||
"message": "Which stylesheet format would you like to use?",
|
||||
"type": "list",
|
||||
"items": [
|
||||
{ "value": "css", "label": "CSS" },
|
||||
{
|
||||
"value": "scss",
|
||||
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
||||
},
|
||||
{
|
||||
"value": "sass",
|
||||
"label": "SASS(.sass) [ http://sass-lang.com ]"
|
||||
},
|
||||
{
|
||||
"value": "less",
|
||||
"label": "LESS [ http://lesscss.org ]"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@ -9,6 +9,12 @@
|
||||
"description": "Add Cypress Configuration to the workspace.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@ -18,12 +18,6 @@
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"framework": {
|
||||
"type": "string",
|
||||
"description": "App framework to test",
|
||||
"enum": ["react-native", "expo"],
|
||||
"default": "react-native"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,16 +9,15 @@
|
||||
"description": "Init Webpack Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"enum": ["babel", "swc", "tsc"],
|
||||
"description": "The compiler to initialize for.",
|
||||
"default": "babel"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -8,33 +8,16 @@
|
||||
"description": "Add Nx Expo Schematics.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "Adds the specified e2e test runner",
|
||||
"type": "string",
|
||||
"enum": ["detox", "none"],
|
||||
"default": "detox"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`."
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,16 +9,15 @@
|
||||
"description": "Init Express Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`."
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,36 +9,17 @@
|
||||
"description": "Add Jest Configuration to a workspace.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"babelJest": {
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"alias": "babel-jest",
|
||||
"description": "Use `babel-jest` instead of `ts-jest`.",
|
||||
"default": false
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"testEnvironment": {
|
||||
"type": "string",
|
||||
"enum": ["jsdom", "node", "none"],
|
||||
"description": "The test environment for jest. This controls which jest-environment-* package is installed",
|
||||
"default": "jsdom",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript for config files"
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "initialize Jest for an application at the root of the workspace",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"hidden": true,
|
||||
"x-priority": "internal"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,12 +9,6 @@
|
||||
"cli": "nx",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
|
||||
@ -9,40 +9,16 @@
|
||||
"description": "Init Next Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "Adds the specified e2e test runner.",
|
||||
"type": "string",
|
||||
"enum": ["cypress", "none"],
|
||||
"default": "cypress"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "Create an application at the root of the workspace.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"hidden": true,
|
||||
"x-priority": "internal"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,21 +9,15 @@
|
||||
"description": "Init Node Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"js": {
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript"
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -14,20 +14,10 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "Create a project at the root of the workspace",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
"default": "css"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -63,6 +63,11 @@
|
||||
"default": false,
|
||||
"hidden": true,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipInstall": {
|
||||
"type": "boolean",
|
||||
"description": "Skip running `playwright install`. This is to ensure that playwright browsers are installed.",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": ["project"],
|
||||
|
||||
@ -19,11 +19,6 @@
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipInstall": {
|
||||
"type": "boolean",
|
||||
"description": "Skip running `playwright install`. This is to ensure that playwright browsers are installed.",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,29 +9,12 @@
|
||||
"description": "Add Nx React native schematics.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "Adds the specified E2E test runner.",
|
||||
"type": "string",
|
||||
"enum": ["detox", "none"],
|
||||
"default": "detox"
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
|
||||
@ -9,18 +9,6 @@
|
||||
"cli": "nx",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "Adds the specified E2E test runner.",
|
||||
"type": "string",
|
||||
"enum": ["cypress", "playwright", "none"],
|
||||
"default": "cypress"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
@ -30,17 +18,6 @@
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipHelperLibs": {
|
||||
"description": "Do not install tslib.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"hidden": true
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,16 +9,15 @@
|
||||
"description": "Init Webpack Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"enum": ["babel", "swc", "tsc"],
|
||||
"description": "The compiler to initialize for.",
|
||||
"default": "babel"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -8,41 +8,14 @@
|
||||
"$id": "init-storybook-plugin",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uiFramework": {
|
||||
"type": "string",
|
||||
"description": "Storybook UI Framework to use.",
|
||||
"enum": [
|
||||
"@storybook/angular",
|
||||
"@storybook/html-webpack5",
|
||||
"@storybook/nextjs",
|
||||
"@storybook/preact-webpack5",
|
||||
"@storybook/react-webpack5",
|
||||
"@storybook/react-vite",
|
||||
"@storybook/server-webpack5",
|
||||
"@storybook/svelte-webpack5",
|
||||
"@storybook/svelte-vite",
|
||||
"@storybook/sveltekit",
|
||||
"@storybook/vue-webpack5",
|
||||
"@storybook/vue-vite",
|
||||
"@storybook/vue3-webpack5",
|
||||
"@storybook/vue3-vite",
|
||||
"@storybook/web-components-webpack5",
|
||||
"@storybook/web-components-vite",
|
||||
"@storybook/react",
|
||||
"@storybook/html",
|
||||
"@storybook/web-components",
|
||||
"@storybook/vue",
|
||||
"@storybook/vue3",
|
||||
"@storybook/svelte",
|
||||
"@storybook/react-native"
|
||||
],
|
||||
"x-prompt": "What UI framework plugin should storybook use?",
|
||||
"x-priority": "important",
|
||||
"aliases": ["storybook7UiFramework"]
|
||||
},
|
||||
"js": {
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"description": "Generate JavaScript story files rather than TypeScript story files.",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
|
||||
@ -8,32 +8,17 @@
|
||||
"$id": "init-vite-plugin",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uiFramework": {
|
||||
"type": "string",
|
||||
"description": "UI Framework to use for Vite.",
|
||||
"enum": ["react", "none"],
|
||||
"default": "react",
|
||||
"x-prompt": "What UI framework plugin should Vite use?"
|
||||
},
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"description": "Compiler to use for Vite when UI Framework is React.",
|
||||
"enum": ["babel", "swc"],
|
||||
"default": "babel"
|
||||
},
|
||||
"includeLib": {
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"description": "Add dependencies needed to build libraries.",
|
||||
"default": false
|
||||
},
|
||||
"testEnvironment": {
|
||||
"description": "The vitest environment to use. See https://vitest.dev/config/#environment.",
|
||||
"type": "string",
|
||||
"enum": ["node", "jsdom", "happy-dom", "edge-runtime"],
|
||||
"default": "jsdom"
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"examplesFile": "---\ntitle: Examples for the Vite init generator\ndescription: This page contains examples for the Vite @nx/vite:init generator, which helps you initialize vite in your Nx workspace, by installing the necessary dependencies.\n---\n\nThis is a generator will initialize Vite.js in your workspace. It will install all the necessary dependencies. You can read more about how this generator works, in the [Vite package overview page](/packages/vite).\n\n{% callout type=\"note\" title=\"string\" %}\nYou don't need to use this generator on its own.\n{% /callout %}\n\nThis generator will be called automatically when you are either converting an existing React or Web app to use Vite, using the [`@nx/vite:configuration` generator](/packages/vite/generators/configuration), or when you are creating a new React or Web app using the [`@nx/react:app`](/packages/react/generators/application) or [`@nx/web:app`](/packages/web/generators/application) generators, if you choose `vite` as the `bundler`.\n\nIf you need to for some reason, you can use it on its own like this:\n\n```bash\nnx g @nx/vite:init\n```\n\n## Examples\n\n### Install all the necessary dependencies for Vite and the React plugin\n\n```bash\nnx g @nx/vite:init --uiFramework=react\n```\n\n### Install all the necessary dependencies for Vite\n\n```bash\nnx g @nx/vite:init --uiFramework=none\n```\n",
|
||||
"presets": []
|
||||
},
|
||||
"description": "Initialize Vite in the workspace.",
|
||||
|
||||
@ -14,26 +14,10 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"description": "Use JavaScript instead of TypeScript",
|
||||
"default": false
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "Create a project at the root of the workspace",
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"routing": {
|
||||
"type": "boolean",
|
||||
"description": "Generate application with routes.",
|
||||
"x-prompt": "Would you like to add Vue Router to this application?",
|
||||
"default": false
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
"default": "css"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -9,25 +9,6 @@
|
||||
"description": "Init Web Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bundler": {
|
||||
"type": "string",
|
||||
"description": "The bundler to use.",
|
||||
"enum": ["webpack", "none", "vite"],
|
||||
"default": "webpack"
|
||||
},
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "Adds the specified e2e test runner",
|
||||
"type": "string",
|
||||
"enum": ["cypress", "playwright", "none"],
|
||||
"x-prompt": "Which E2E test runner would you like to use?",
|
||||
"default": "cypress"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files",
|
||||
"type": "boolean",
|
||||
|
||||
@ -9,22 +9,15 @@
|
||||
"description": "Initialize the Webpack Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uiFramework": {
|
||||
"type": "string",
|
||||
"description": "UI Framework to use for Webpack.",
|
||||
"enum": ["react", "none"],
|
||||
"x-prompt": "What UI framework plugin should Webpack use?"
|
||||
},
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"enum": ["babel", "swc", "tsc"],
|
||||
"description": "The compiler to initialize for.",
|
||||
"default": "babel"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -11,7 +11,10 @@ import {
|
||||
describe('Storybook executors for Angular', () => {
|
||||
const angularStorybookLib = uniq('test-ui-ng-lib');
|
||||
beforeAll(() => {
|
||||
newProject();
|
||||
newProject({
|
||||
packages: ['@nx/angular'],
|
||||
unsetProjectNameAndRootFormat: false,
|
||||
});
|
||||
runCLI(
|
||||
`g @nx/angular:library ${angularStorybookLib} --project-name-and-root-format=as-provided --no-interactive`
|
||||
);
|
||||
|
||||
@ -12,8 +12,11 @@ import {
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import * as enquirer from 'enquirer';
|
||||
import { backwardCompatibleVersions } from '../../utils/backward-compatible-versions';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import {
|
||||
angularDevkitVersion,
|
||||
angularVersion,
|
||||
autoprefixerVersion,
|
||||
postcssVersion,
|
||||
tailwindVersion,
|
||||
@ -48,6 +51,36 @@ describe('app', () => {
|
||||
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
it('should add angular dependencies', async () => {
|
||||
// ACT
|
||||
await generateApp(appTree);
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(appTree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/common']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/compiler']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/core']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe(
|
||||
angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/router']).toBe(angularVersion);
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe(angularDevkitVersion);
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular/language-service']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe(
|
||||
angularDevkitVersion
|
||||
);
|
||||
|
||||
// codelyzer should no longer be there by default
|
||||
expect(devDependencies['codelyzer']).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('not nested', () => {
|
||||
it('should create project configs', async () => {
|
||||
// ACT
|
||||
@ -1120,6 +1153,60 @@ describe('app', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('should add angular dependencies', async () => {
|
||||
// ACT
|
||||
await generateApp(appTree, 'my-app');
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(
|
||||
appTree,
|
||||
'package.json'
|
||||
);
|
||||
|
||||
expect(dependencies['@angular/animations']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/common']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/compiler']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/core']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/platform-browser']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/router']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['rxjs']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.rxjsVersion
|
||||
);
|
||||
expect(dependencies['zone.js']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.zoneJsVersion
|
||||
);
|
||||
expect(devDependencies['@angular/cli']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularDevkitVersion
|
||||
);
|
||||
expect(devDependencies['@angular/compiler-cli']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularDevkitVersion
|
||||
);
|
||||
expect(devDependencies['@angular/language-service']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularDevkitVersion
|
||||
);
|
||||
|
||||
// codelyzer should no longer be there by default
|
||||
expect(devDependencies['codelyzer']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should import "ApplicationConfig" from "@angular/platform-browser"', async () => {
|
||||
await generateApp(appTree, 'my-app', { standalone: true });
|
||||
|
||||
|
||||
@ -7,9 +7,11 @@ import {
|
||||
Tree,
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { angularInitGenerator } from '../init/init';
|
||||
import { setupSsr } from '../setup-ssr/setup-ssr';
|
||||
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
||||
import { ensureAngularDependencies } from '../utils/ensure-angular-dependencies';
|
||||
import {
|
||||
addE2e,
|
||||
addLinting,
|
||||
@ -20,6 +22,7 @@ import {
|
||||
enableStrictTypeChecking,
|
||||
normalizeOptions,
|
||||
setApplicationStrictDefault,
|
||||
setGeneratorDefaults,
|
||||
updateEditorTsConfig,
|
||||
} from './lib';
|
||||
import type { Schema } from './schema';
|
||||
@ -41,10 +44,17 @@ export async function applicationGeneratorInternal(
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
const rootOffset = offsetFromRoot(options.appProjectRoot);
|
||||
|
||||
await jsInitGenerator(tree, {
|
||||
...options,
|
||||
tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
||||
js: false,
|
||||
skipFormat: true,
|
||||
});
|
||||
await angularInitGenerator(tree, {
|
||||
...options,
|
||||
skipFormat: true,
|
||||
});
|
||||
ensureAngularDependencies(tree);
|
||||
|
||||
createProject(tree, options);
|
||||
|
||||
@ -62,6 +72,7 @@ export async function applicationGeneratorInternal(
|
||||
await addUnitTestRunner(tree, options);
|
||||
await addE2e(tree, options);
|
||||
updateEditorTsConfig(tree, options);
|
||||
setGeneratorDefaults(tree, options);
|
||||
|
||||
if (options.rootProject) {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
@ -1,37 +1,15 @@
|
||||
import { Tree, joinPathFragments } from '@nx/devkit';
|
||||
import { configurationGenerator } from '@nx/jest';
|
||||
import { Tree } from '@nx/devkit';
|
||||
import { UnitTestRunner } from '../../../utils/test-runners';
|
||||
import { addJest } from '../../utils/add-jest';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) {
|
||||
if (options.unitTestRunner === UnitTestRunner.Jest) {
|
||||
await configurationGenerator(host, {
|
||||
...options,
|
||||
project: options.name,
|
||||
setupFile: 'angular',
|
||||
supportTsx: false,
|
||||
skipSerializers: false,
|
||||
await addJest(host, {
|
||||
name: options.name,
|
||||
projectRoot: options.appProjectRoot,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
skipFormat: true,
|
||||
strict: options.strict,
|
||||
});
|
||||
const setupFile = joinPathFragments(
|
||||
options.appProjectRoot,
|
||||
'src',
|
||||
'test-setup.ts'
|
||||
);
|
||||
if (options.strict && host.exists(setupFile)) {
|
||||
const contents = host.read(setupFile, 'utf-8');
|
||||
host.write(
|
||||
setupFile,
|
||||
`// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
|
||||
globalThis.ngJest = {
|
||||
testEnvironmentOptions: {
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
},
|
||||
};
|
||||
${contents}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,4 +8,5 @@ export * from './enable-strict-type-checking';
|
||||
export * from './normalize-options';
|
||||
export * from './normalized-schema';
|
||||
export * from './set-app-strict-default';
|
||||
export * from './set-generator-defaults';
|
||||
export * from './update-editor-tsconfig';
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
import { readNxJson, updateNxJson, type Tree } from '@nx/devkit';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
export function setGeneratorDefaults(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema
|
||||
): void {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
nxJson.generators = nxJson.generators ?? {};
|
||||
nxJson.generators['@nx/angular:application'] = {
|
||||
e2eTestRunner: options.e2eTestRunner,
|
||||
linter: options.linter,
|
||||
style: options.style,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
...(nxJson.generators['@nx/angular:application'] || {}),
|
||||
};
|
||||
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
@ -6,6 +6,7 @@ import {
|
||||
exportComponentInEntryPoint,
|
||||
findModuleFromOptions,
|
||||
normalizeOptions,
|
||||
setGeneratorDefaults,
|
||||
} from './lib';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
@ -92,6 +93,7 @@ export async function componentGeneratorInternal(
|
||||
}
|
||||
|
||||
exportComponentInEntryPoint(tree, options);
|
||||
setGeneratorDefaults(tree, options);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './component';
|
||||
export * from './module';
|
||||
export * from './normalize-options';
|
||||
export * from './set-generator-defaults';
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import { readNxJson, updateNxJson, type Tree } from '@nx/devkit';
|
||||
import type { NormalizedSchema } from '../schema';
|
||||
|
||||
export function setGeneratorDefaults(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema
|
||||
): void {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
nxJson.generators = nxJson.generators ?? {};
|
||||
nxJson.generators['@nx/angular:component'] = {
|
||||
style: options.style,
|
||||
...(nxJson.generators['@nx/angular:component'] || {}),
|
||||
};
|
||||
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
@ -1,26 +1,5 @@
|
||||
jest.mock('@nx/devkit', () => ({
|
||||
...jest.requireActual('@nx/devkit'),
|
||||
// need to mock so it doesn't resolve what the workspace has installed
|
||||
// and be able to test with different versions
|
||||
ensurePackage: jest.fn(() => ({
|
||||
cypressInitGenerator: jest.fn(),
|
||||
initGenerator: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
import {
|
||||
ensurePackage,
|
||||
NxJsonConfiguration,
|
||||
readJson,
|
||||
readNxJson,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import { readNxJson, updateJson, updateNxJson, type Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { backwardCompatibleVersions } from '../../utils/backward-compatible-versions';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import { angularDevkitVersion, angularVersion } from '../../utils/versions';
|
||||
import init from './init';
|
||||
|
||||
describe('init', () => {
|
||||
@ -30,262 +9,11 @@ describe('init', () => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
it('should add angular dependencies', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/common']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/compiler']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/core']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe(
|
||||
angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/router']).toBe(angularVersion);
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe(angularDevkitVersion);
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular/language-service']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe(
|
||||
angularDevkitVersion
|
||||
);
|
||||
|
||||
// codelyzer should no longer be there by default
|
||||
expect(devDependencies['codelyzer']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should add angular dependencies respecting base packages versions', async () => {
|
||||
// ARRANGE
|
||||
updateJson(tree, 'package.json', (json) => ({
|
||||
...json,
|
||||
dependencies: {
|
||||
...json.dependencies,
|
||||
'@angular/core': '~15.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
...json.devDependencies,
|
||||
'@angular-devkit/build-angular': '~15.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
// ACT
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/common']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/compiler']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/core']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/platform-browser']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/router']).toBe('~15.0.0');
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular/language-service']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe('~15.0.0');
|
||||
});
|
||||
|
||||
it('should not overwrite already installed dependencies', async () => {
|
||||
// ARRANGE
|
||||
updateJson(tree, 'package.json', (json) => ({
|
||||
...json,
|
||||
dependencies: {
|
||||
...json.dependencies,
|
||||
'@angular/animations': '~15.0.1',
|
||||
'@angular/core': '~15.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
// ACT
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
// ASSERT
|
||||
const { dependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe('~15.0.1');
|
||||
expect(dependencies['@angular/core']).toBe('~15.0.0');
|
||||
});
|
||||
|
||||
describe('--unit-test-runner', () => {
|
||||
describe('jest', () => {
|
||||
it('should add jest dependencies', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
// ASSERT
|
||||
expect(devDependencies['@nx/jest']).toBeDefined();
|
||||
expect(devDependencies['jest']).toBeDefined();
|
||||
expect(devDependencies['jest-preset-angular']).toBeDefined();
|
||||
});
|
||||
|
||||
it('should add jest configuration', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const hasJestConfigFile = tree.exists('jest.config.ts');
|
||||
|
||||
// ASSERT
|
||||
expect(hasJestConfigFile).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set defaults', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].unitTestRunner).toEqual(
|
||||
'jest'
|
||||
);
|
||||
expect(generators['@nx/angular:library'].unitTestRunner).toEqual(
|
||||
'jest'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--e2e-test-runner', () => {
|
||||
describe('playwright', () => {
|
||||
it('should call @nx/playwright:init', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Playwright,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(ensurePackage).toHaveBeenLastCalledWith(
|
||||
'@nx/playwright',
|
||||
'0.0.1'
|
||||
);
|
||||
});
|
||||
|
||||
it('should set defaults', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Playwright,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].e2eTestRunner).toEqual(
|
||||
'playwright'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('cypress', () => {
|
||||
it('should call @nx/cypress:init', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(ensurePackage).toHaveBeenLastCalledWith('@nx/cypress', '0.0.1');
|
||||
});
|
||||
|
||||
it('should set defaults', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].e2eTestRunner).toEqual(
|
||||
'cypress'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--linter', () => {
|
||||
describe('eslint', () => {
|
||||
it('should set the default to eslint', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].linter).toEqual('eslint');
|
||||
expect(generators['@nx/angular:library'].linter).toEqual('eslint');
|
||||
});
|
||||
});
|
||||
|
||||
describe('none', () => {
|
||||
it('should set the default to none', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
linter: Linter.None,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].linter).toEqual('none');
|
||||
expect(generators['@nx/angular:library'].linter).toEqual('none');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('angular cache dir', () => {
|
||||
it('should add .angular to .gitignore', async () => {
|
||||
tree.write('.gitignore', '');
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
expect(tree.read('.gitignore', 'utf-8')).toContain('.angular');
|
||||
});
|
||||
@ -301,12 +29,7 @@ bar
|
||||
`
|
||||
);
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
const angularEntries = tree
|
||||
.read('.gitignore', 'utf-8')
|
||||
@ -317,12 +40,7 @@ bar
|
||||
it('should add .angular to .prettierignore', async () => {
|
||||
tree.write('.prettierignore', '');
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
expect(tree.read('.prettierignore', 'utf-8')).toContain('.angular');
|
||||
});
|
||||
@ -338,12 +56,7 @@ bar
|
||||
`
|
||||
);
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
const angularEntries = tree
|
||||
.read('.prettierignore', 'utf-8')
|
||||
@ -353,18 +66,14 @@ bar
|
||||
|
||||
it('should add configured angular cache dir to .gitignore and .prettierignore', async () => {
|
||||
tree.write('.gitignore', '');
|
||||
tree.write('.prettierignore', '');
|
||||
const nxJson = readNxJson(tree);
|
||||
updateNxJson(tree, {
|
||||
...nxJson,
|
||||
cli: { cache: { path: 'node_modules/.cache/angular' } },
|
||||
} as any);
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
expect(tree.read('.gitignore', 'utf-8')).toContain(
|
||||
'node_modules/.cache/angular'
|
||||
@ -388,289 +97,11 @@ bar
|
||||
}));
|
||||
});
|
||||
|
||||
it('should add angular dependencies', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/common']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/compiler']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/core']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/platform-browser']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/router']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(dependencies['rxjs']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.rxjsVersion
|
||||
);
|
||||
expect(dependencies['zone.js']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.zoneJsVersion
|
||||
);
|
||||
expect(devDependencies['@angular/cli']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularDevkitVersion
|
||||
);
|
||||
expect(devDependencies['@angular/compiler-cli']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularDevkitVersion
|
||||
);
|
||||
expect(devDependencies['@angular/language-service']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularVersion
|
||||
);
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.angularDevkitVersion
|
||||
);
|
||||
|
||||
// codelyzer should no longer be there by default
|
||||
expect(devDependencies['codelyzer']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should add angular dependencies respecting base packages versions', async () => {
|
||||
// ARRANGE
|
||||
updateJson(tree, 'package.json', (json) => ({
|
||||
...json,
|
||||
dependencies: {
|
||||
...json.dependencies,
|
||||
'@angular/core': '~15.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
...json.devDependencies,
|
||||
'@angular-devkit/build-angular': '~15.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
// ACT
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/common']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/compiler']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/core']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/platform-browser']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/router']).toBe('~15.0.0');
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular/language-service']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe('~15.0.0');
|
||||
});
|
||||
|
||||
it('should not overwrite already installed dependencies', async () => {
|
||||
// ARRANGE
|
||||
updateJson(tree, 'package.json', (json) => ({
|
||||
...json,
|
||||
dependencies: {
|
||||
...json.dependencies,
|
||||
'@angular/animations': '~15.0.1',
|
||||
'@angular/core': '~15.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
// ACT
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
// ASSERT
|
||||
const { dependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe('~15.0.1');
|
||||
expect(dependencies['@angular/core']).toBe('~15.0.0');
|
||||
});
|
||||
|
||||
describe('--unit-test-runner', () => {
|
||||
describe('jest', () => {
|
||||
it('should add jest dependencies', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
// ASSERT
|
||||
expect(devDependencies['@nx/jest']).toBeDefined();
|
||||
expect(devDependencies['jest']).toBeDefined();
|
||||
expect(devDependencies['jest-preset-angular']).toEqual(
|
||||
backwardCompatibleVersions.angularV15.jestPresetAngularVersion
|
||||
);
|
||||
});
|
||||
|
||||
it('should add jest configuration', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const hasJestConfigFile = tree.exists('jest.config.ts');
|
||||
|
||||
// ASSERT
|
||||
expect(hasJestConfigFile).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set defaults', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].unitTestRunner).toEqual(
|
||||
'jest'
|
||||
);
|
||||
expect(generators['@nx/angular:library'].unitTestRunner).toEqual(
|
||||
'jest'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--e2e-test-runner', () => {
|
||||
it('should call @nx/playwright:init', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Playwright,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
expect(ensurePackage).toHaveBeenLastCalledWith(
|
||||
'@nx/playwright',
|
||||
'0.0.1'
|
||||
);
|
||||
});
|
||||
|
||||
it('should set defaults', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Playwright,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].e2eTestRunner).toEqual(
|
||||
'playwright'
|
||||
);
|
||||
});
|
||||
|
||||
describe('cypress', () => {
|
||||
it('should add cypress dependencies', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
// ASSERT
|
||||
expect(ensurePackage).toHaveBeenLastCalledWith(
|
||||
'@nx/cypress',
|
||||
'0.0.1'
|
||||
);
|
||||
});
|
||||
|
||||
it('should set defaults', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].e2eTestRunner).toEqual(
|
||||
'cypress'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('--linter', () => {
|
||||
describe('eslint', () => {
|
||||
it('should set the default to eslint', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].linter).toEqual(
|
||||
'eslint'
|
||||
);
|
||||
expect(generators['@nx/angular:library'].linter).toEqual('eslint');
|
||||
});
|
||||
});
|
||||
|
||||
describe('none', () => {
|
||||
it('should set the default to none', async () => {
|
||||
// ACT
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.None,
|
||||
linter: Linter.None,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const { generators } = readJson<NxJsonConfiguration>(tree, 'nx.json');
|
||||
|
||||
// ASSERT
|
||||
expect(generators['@nx/angular:application'].linter).toEqual('none');
|
||||
expect(generators['@nx/angular:library'].linter).toEqual('none');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('angular cache dir', () => {
|
||||
it('should add .angular to .gitignore', async () => {
|
||||
tree.write('.gitignore', '');
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
expect(tree.read('.gitignore', 'utf-8')).toContain('.angular');
|
||||
});
|
||||
@ -686,12 +117,7 @@ bar
|
||||
`
|
||||
);
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
const angularEntries = tree
|
||||
.read('.gitignore', 'utf-8')
|
||||
@ -702,12 +128,7 @@ bar
|
||||
it('should add .angular to .prettierignore', async () => {
|
||||
tree.write('.prettierignore', '');
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
expect(tree.read('.prettierignore', 'utf-8')).toContain('.angular');
|
||||
});
|
||||
@ -723,12 +144,7 @@ bar
|
||||
`
|
||||
);
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
const angularEntries = tree
|
||||
.read('.prettierignore', 'utf-8')
|
||||
@ -738,18 +154,14 @@ bar
|
||||
|
||||
it('should add configured angular cache dir to .gitignore and .prettierignore', async () => {
|
||||
tree.write('.gitignore', '');
|
||||
tree.write('.prettierignore', '');
|
||||
const nxJson = readNxJson(tree);
|
||||
updateNxJson(tree, {
|
||||
...nxJson,
|
||||
cli: { cache: { path: 'node_modules/.cache/angular' } },
|
||||
} as any);
|
||||
|
||||
await init(tree, {
|
||||
unitTestRunner: UnitTestRunner.Jest,
|
||||
e2eTestRunner: E2eTestRunner.Cypress,
|
||||
linter: Linter.EsLint,
|
||||
skipFormat: true,
|
||||
});
|
||||
await init(tree, { skipFormat: true });
|
||||
|
||||
expect(tree.read('.gitignore', 'utf-8')).toContain(
|
||||
'node_modules/.cache/angular'
|
||||
|
||||
@ -2,222 +2,59 @@ import {
|
||||
addDependenciesToPackageJson,
|
||||
ensurePackage,
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
logger,
|
||||
readNxJson,
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
updateNxJson,
|
||||
type GeneratorCallback,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { jestInitGenerator } from '@nx/jest';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import {
|
||||
addDependenciesToPackageJsonIfDontExist,
|
||||
getInstalledPackageVersion,
|
||||
versions,
|
||||
} from '../utils/version-utils';
|
||||
import type {
|
||||
PackageCompatVersions,
|
||||
PackageLatestVersions,
|
||||
} from '../../utils/backward-compatible-versions';
|
||||
import { getInstalledPackageVersion, versions } from '../utils/version-utils';
|
||||
import { Schema } from './schema';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
|
||||
export async function angularInitGenerator(
|
||||
tree: Tree,
|
||||
rawOptions: Schema
|
||||
options: Schema
|
||||
): Promise<GeneratorCallback> {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const options = normalizeOptions(rawOptions);
|
||||
|
||||
const pkgVersions = versions(tree);
|
||||
|
||||
const peerDepsToInstall = ['@angular-devkit/core'];
|
||||
let devkitVersion: string;
|
||||
peerDepsToInstall.forEach((pkg) => {
|
||||
const packageVersion = getInstalledPackageVersion(tree, pkg);
|
||||
|
||||
if (!packageVersion) {
|
||||
devkitVersion ??=
|
||||
getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ??
|
||||
pkgVersions.angularDevkitVersion;
|
||||
|
||||
try {
|
||||
ensurePackage(pkg, devkitVersion);
|
||||
} catch {
|
||||
// @schematics/angular cannot be required so this fails but this will still allow wrapping the schematic later on
|
||||
}
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(
|
||||
addDependenciesToPackageJson(tree, {}, { [pkg]: devkitVersion })
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
setDefaults(tree, options);
|
||||
|
||||
const jsTask = await jsInitGenerator(tree, {
|
||||
...options,
|
||||
tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
||||
js: false,
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(jsTask);
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(updateDependencies(tree, pkgVersions));
|
||||
}
|
||||
const unitTestTask = await addUnitTestRunner(
|
||||
tree,
|
||||
options,
|
||||
pkgVersions.jestPresetAngularVersion
|
||||
);
|
||||
tasks.push(unitTestTask);
|
||||
const e2eTask = await addE2ETestRunner(tree, options);
|
||||
tasks.push(e2eTask);
|
||||
|
||||
ignoreAngularCacheDirectory(tree);
|
||||
const installTask = installAngularDevkitCoreIfMissing(tree, options);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
return installTask;
|
||||
}
|
||||
|
||||
function normalizeOptions(options: Schema): Required<Schema> {
|
||||
return {
|
||||
e2eTestRunner: options.e2eTestRunner ?? E2eTestRunner.Cypress,
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
skipFormat: options.skipFormat ?? false,
|
||||
skipInstall: options.skipInstall ?? false,
|
||||
skipPackageJson: options.skipPackageJson ?? false,
|
||||
style: options.style ?? 'css',
|
||||
unitTestRunner: options.unitTestRunner ?? UnitTestRunner.Jest,
|
||||
rootProject: options.rootProject,
|
||||
};
|
||||
}
|
||||
|
||||
function setDefaults(host: Tree, options: Schema) {
|
||||
const nxJson = readNxJson(host);
|
||||
|
||||
nxJson.generators = nxJson.generators || {};
|
||||
nxJson.generators['@nx/angular:application'] = {
|
||||
style: options.style,
|
||||
linter: options.linter,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
e2eTestRunner: options.e2eTestRunner,
|
||||
...(nxJson.generators['@nx/angular:application'] || {}),
|
||||
};
|
||||
nxJson.generators['@nx/angular:library'] = {
|
||||
linter: options.linter,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
...(nxJson.generators['@nx/angular:library'] || {}),
|
||||
};
|
||||
nxJson.generators['@nx/angular:component'] = {
|
||||
style: options.style,
|
||||
...(nxJson.generators['@nx/angular:component'] || {}),
|
||||
};
|
||||
|
||||
updateNxJson(host, nxJson);
|
||||
}
|
||||
|
||||
function updateDependencies(
|
||||
tree: Tree,
|
||||
versions: PackageLatestVersions | PackageCompatVersions
|
||||
): GeneratorCallback {
|
||||
const angularVersion =
|
||||
getInstalledPackageVersion(tree, '@angular/core') ??
|
||||
versions.angularVersion;
|
||||
const angularDevkitVersion =
|
||||
getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ??
|
||||
versions.angularDevkitVersion;
|
||||
const rxjsVersion =
|
||||
getInstalledPackageVersion(tree, 'rxjs') ?? versions.rxjsVersion;
|
||||
const tsLibVersion =
|
||||
getInstalledPackageVersion(tree, 'tslib') ?? versions.tsLibVersion;
|
||||
const zoneJsVersion =
|
||||
getInstalledPackageVersion(tree, 'zone.js') ?? versions.zoneJsVersion;
|
||||
|
||||
return addDependenciesToPackageJsonIfDontExist(
|
||||
tree,
|
||||
{
|
||||
'@angular/animations': angularVersion,
|
||||
'@angular/common': angularVersion,
|
||||
'@angular/compiler': angularVersion,
|
||||
'@angular/core': angularVersion,
|
||||
'@angular/forms': angularVersion,
|
||||
'@angular/platform-browser': angularVersion,
|
||||
'@angular/platform-browser-dynamic': angularVersion,
|
||||
'@angular/router': angularVersion,
|
||||
rxjs: rxjsVersion,
|
||||
tslib: tsLibVersion,
|
||||
'zone.js': zoneJsVersion,
|
||||
},
|
||||
{
|
||||
'@angular/cli': angularDevkitVersion,
|
||||
'@angular/compiler-cli': angularVersion,
|
||||
'@angular/language-service': angularVersion,
|
||||
'@angular-devkit/build-angular': angularDevkitVersion,
|
||||
'@angular-devkit/schematics': angularDevkitVersion,
|
||||
'@schematics/angular': angularDevkitVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function addUnitTestRunner(
|
||||
tree: Tree,
|
||||
options: Schema,
|
||||
jestPresetAngularVersion: string
|
||||
): Promise<GeneratorCallback> {
|
||||
switch (options.unitTestRunner) {
|
||||
case UnitTestRunner.Jest:
|
||||
if (!options.skipPackageJson) {
|
||||
process.env.npm_config_legacy_peer_deps ??= 'true';
|
||||
|
||||
addDependenciesToPackageJsonIfDontExist(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'jest-preset-angular': jestPresetAngularVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return jestInitGenerator(tree, {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
default:
|
||||
return () => {};
|
||||
}
|
||||
}
|
||||
|
||||
async function addE2ETestRunner(
|
||||
function installAngularDevkitCoreIfMissing(
|
||||
tree: Tree,
|
||||
options: Schema
|
||||
): Promise<GeneratorCallback> {
|
||||
switch (options.e2eTestRunner) {
|
||||
case E2eTestRunner.Cypress:
|
||||
const { cypressInitGenerator } = ensurePackage<
|
||||
typeof import('@nx/cypress')
|
||||
>('@nx/cypress', nxVersion);
|
||||
return cypressInitGenerator(tree, {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
case E2eTestRunner.Playwright:
|
||||
const { initGenerator: playwrightInitGenerator } = ensurePackage<
|
||||
typeof import('@nx/playwright')
|
||||
>('@nx/playwright', nxVersion);
|
||||
return playwrightInitGenerator(tree, {
|
||||
skipFormat: true,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
default:
|
||||
return () => {};
|
||||
): GeneratorCallback {
|
||||
const packageVersion = getInstalledPackageVersion(
|
||||
tree,
|
||||
'@angular-devkit/core'
|
||||
);
|
||||
|
||||
if (!packageVersion) {
|
||||
const pkgVersions = versions(tree);
|
||||
const devkitVersion =
|
||||
getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ??
|
||||
pkgVersions.angularDevkitVersion;
|
||||
|
||||
try {
|
||||
ensurePackage('@angular-devkit/core', devkitVersion);
|
||||
} catch {
|
||||
// @schematics/angular cannot be required so this fails but this will still allow wrapping the schematic later on
|
||||
}
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{ ['@angular-devkit/core']: devkitVersion }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {};
|
||||
}
|
||||
|
||||
function ignoreAngularCacheDirectory(tree: Tree): void {
|
||||
|
||||
@ -1,14 +1,5 @@
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { Styles } from '../utils/types';
|
||||
|
||||
export interface Schema {
|
||||
unitTestRunner?: UnitTestRunner;
|
||||
e2eTestRunner?: E2eTestRunner;
|
||||
skipFormat?: boolean;
|
||||
skipInstall?: boolean;
|
||||
style?: Styles;
|
||||
linter?: Linter;
|
||||
skipPackageJson?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
@ -5,28 +5,7 @@
|
||||
"title": "Init Angular Plugin",
|
||||
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nx/angular:init --style=scss",
|
||||
"description": "Installs angular dependencies and initializes the `@nx/angular` plugin with the `scss` stylesheet format."
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests.",
|
||||
"default": "jest",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["cypress", "playwright", "none"],
|
||||
"x-prompt": "Which E2E test runner would you like to use?",
|
||||
"description": "Test runner to use for end to end (e2e) tests.",
|
||||
"default": "cypress",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipInstall": {
|
||||
"type": "boolean",
|
||||
"description": "Skip installing after adding `@nx/workspace`.",
|
||||
@ -39,41 +18,6 @@
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint", "none"],
|
||||
"default": "eslint",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
"default": "css",
|
||||
"enum": ["css", "scss", "sass", "less"],
|
||||
"x-prompt": {
|
||||
"message": "Which stylesheet format would you like to use?",
|
||||
"type": "list",
|
||||
"items": [
|
||||
{
|
||||
"value": "css",
|
||||
"label": "CSS"
|
||||
},
|
||||
{
|
||||
"value": "scss",
|
||||
"label": "SASS(.scss) [ http://sass-lang.com ]"
|
||||
},
|
||||
{
|
||||
"value": "sass",
|
||||
"label": "SASS(.sass) [ http://sass-lang.com ]"
|
||||
},
|
||||
{
|
||||
"value": "less",
|
||||
"label": "LESS [ http://lesscss.org ]"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
import { readNxJson, updateNxJson, type Tree } from '@nx/devkit';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
export function setGeneratorDefaults(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema
|
||||
): void {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
nxJson.generators = nxJson.generators ?? {};
|
||||
nxJson.generators['@nx/angular:library'] = {
|
||||
linter: options.libraryOptions.linter,
|
||||
unitTestRunner: options.libraryOptions.unitTestRunner,
|
||||
...(nxJson.generators['@nx/angular:library'] || {}),
|
||||
};
|
||||
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
@ -13,6 +13,8 @@ import { Linter } from '@nx/eslint';
|
||||
import { createApp } from '../../utils/nx-devkit/testing';
|
||||
import { UnitTestRunner } from '../../utils/test-runners';
|
||||
import {
|
||||
angularDevkitVersion,
|
||||
angularVersion,
|
||||
autoprefixerVersion,
|
||||
postcssVersion,
|
||||
tailwindVersion,
|
||||
@ -62,6 +64,36 @@ describe('lib', () => {
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('should add angular dependencies', async () => {
|
||||
// ACT
|
||||
await runLibraryGeneratorWithOpts();
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/common']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/compiler']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/core']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe(
|
||||
angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/router']).toBe(angularVersion);
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe(angularDevkitVersion);
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular/language-service']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe(
|
||||
angularDevkitVersion
|
||||
);
|
||||
|
||||
// codelyzer should no longer be there by default
|
||||
expect(devDependencies['codelyzer']).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('not nested', () => {
|
||||
it('should update ng-package.json', async () => {
|
||||
// ACT
|
||||
|
||||
@ -5,11 +5,9 @@ import {
|
||||
joinPathFragments,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { configurationGenerator } from '@nx/jest';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { addTsConfigPath } from '@nx/js';
|
||||
import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import init from '../../generators/init/init';
|
||||
import { E2eTestRunner } from '../../utils/test-runners';
|
||||
import addLintingGenerator from '../add-linting/add-linting';
|
||||
import setupTailwindGenerator from '../setup-tailwind/setup-tailwind';
|
||||
import {
|
||||
@ -30,6 +28,9 @@ import { updateTsConfig } from './lib/update-tsconfig';
|
||||
import { Schema } from './schema';
|
||||
import { createFiles } from './lib/create-files';
|
||||
import { addProject } from './lib/add-project';
|
||||
import { addJest } from '../utils/add-jest';
|
||||
import { setGeneratorDefaults } from './lib/set-generator-defaults';
|
||||
import { ensureAngularDependencies } from '../utils/ensure-angular-dependencies';
|
||||
|
||||
export async function libraryGenerator(
|
||||
tree: Tree,
|
||||
@ -69,11 +70,9 @@ export async function libraryGeneratorInternal(
|
||||
|
||||
const pkgVersions = versions(tree);
|
||||
|
||||
await init(tree, {
|
||||
...libraryOptions,
|
||||
skipFormat: true,
|
||||
e2eTestRunner: E2eTestRunner.None,
|
||||
});
|
||||
await jsInitGenerator(tree, { ...options, js: false, skipFormat: true });
|
||||
await init(tree, { ...libraryOptions, skipFormat: true });
|
||||
ensureAngularDependencies(tree);
|
||||
|
||||
const project = addProject(tree, libraryOptions);
|
||||
|
||||
@ -81,6 +80,7 @@ export async function libraryGeneratorInternal(
|
||||
updateTsConfig(tree, libraryOptions);
|
||||
await addUnitTestRunner(tree, libraryOptions);
|
||||
updateNpmScopeIfBuildableOrPublishable(tree, libraryOptions);
|
||||
setGeneratorDefaults(tree, options);
|
||||
|
||||
if (!libraryOptions.standalone) {
|
||||
addModule(tree, libraryOptions);
|
||||
@ -127,33 +127,12 @@ async function addUnitTestRunner(
|
||||
options: NormalizedSchema['libraryOptions']
|
||||
) {
|
||||
if (options.unitTestRunner === 'jest') {
|
||||
await configurationGenerator(host, {
|
||||
project: options.name,
|
||||
setupFile: 'angular',
|
||||
supportTsx: false,
|
||||
skipSerializers: false,
|
||||
skipFormat: true,
|
||||
await addJest(host, {
|
||||
name: options.name,
|
||||
projectRoot: options.projectRoot,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
strict: options.strict,
|
||||
});
|
||||
const setupFile = joinPathFragments(
|
||||
options.projectRoot,
|
||||
'src',
|
||||
'test-setup.ts'
|
||||
);
|
||||
if (options.strict && host.exists(setupFile)) {
|
||||
const contents = host.read(setupFile, 'utf-8');
|
||||
host.write(
|
||||
setupFile,
|
||||
`// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
|
||||
globalThis.ngJest = {
|
||||
testEnvironmentOptions: {
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
},
|
||||
};
|
||||
${contents}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import * as angularCliMigrator from './migrate-from-angular-cli';
|
||||
import * as initGenerator from '../init/init';
|
||||
import { ngAddGenerator } from './ng-add';
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
|
||||
describe('ngAdd generator', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
jest
|
||||
.spyOn(angularCliMigrator, 'migrateFromAngularCli')
|
||||
.mockImplementation(() => Promise.resolve(() => {}));
|
||||
jest
|
||||
.spyOn(initGenerator, 'angularInitGenerator')
|
||||
.mockImplementation(() => Promise.resolve(() => {}));
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should initialize the Angular plugin when in an Nx workspace', async () => {
|
||||
await ngAddGenerator(tree, { skipFormat: true });
|
||||
|
||||
expect(initGenerator.angularInitGenerator).toHaveBeenCalled();
|
||||
expect(angularCliMigrator.migrateFromAngularCli).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should perform a migration when in an Angular CLI workspace', async () => {
|
||||
tree.delete('nx.json');
|
||||
|
||||
await ngAddGenerator(tree, { skipFormat: true });
|
||||
|
||||
expect(angularCliMigrator.migrateFromAngularCli).toHaveBeenCalled();
|
||||
expect(initGenerator.angularInitGenerator).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@ -1,18 +1,9 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { angularInitGenerator } from '../init/init';
|
||||
import { migrateFromAngularCli } from './migrate-from-angular-cli';
|
||||
import type { GeneratorOptions } from './schema';
|
||||
|
||||
function getWorkspaceType(tree: Tree): 'angular' | 'nx' {
|
||||
return tree.exists('nx.json') ? 'nx' : 'angular';
|
||||
}
|
||||
|
||||
export async function ngAddGenerator(tree: Tree, options: GeneratorOptions) {
|
||||
if (getWorkspaceType(tree) === 'angular') {
|
||||
return await migrateFromAngularCli(tree, options);
|
||||
}
|
||||
|
||||
return await angularInitGenerator(tree, options);
|
||||
return await migrateFromAngularCli(tree, options);
|
||||
}
|
||||
|
||||
export default ngAddGenerator;
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { Linter, lintInitGenerator } from '@nx/eslint';
|
||||
import { setupRootEsLint } from '@nx/eslint/src/generators/lint-project/setup-root-eslint';
|
||||
import {
|
||||
getRootTsConfigPathInTree,
|
||||
initGenerator as jsInitGenerator,
|
||||
@ -189,25 +190,16 @@ export function updateRootEsLintConfig(
|
||||
existingEsLintConfig: any | undefined,
|
||||
unitTestRunner?: string
|
||||
): void {
|
||||
if (tree.exists('.eslintrc.json')) {
|
||||
/**
|
||||
* If it still exists it means that there was no project at the root of the
|
||||
* workspace, so it was not moved. In that case, we remove the file so the
|
||||
* init generator do its work. We still receive the content of the file,
|
||||
* so we update it after the init generator has run.
|
||||
*/
|
||||
tree.delete('.eslintrc.json');
|
||||
}
|
||||
|
||||
lintInitGenerator(tree, { linter: Linter.EsLint, unitTestRunner });
|
||||
lintInitGenerator(tree, {});
|
||||
|
||||
if (!existingEsLintConfig) {
|
||||
// There was no eslint config in the root, so we keep the generated one as-is.
|
||||
// There was no eslint config in the root, so we set it up and use it as-is
|
||||
setupRootEsLint(tree, { unitTestRunner });
|
||||
return;
|
||||
}
|
||||
|
||||
existingEsLintConfig.ignorePatterns = ['**/*'];
|
||||
if (!(existingEsLintConfig.plugins ?? []).includes('@nrwl/nx')) {
|
||||
if (!(existingEsLintConfig.plugins ?? []).includes('@nx')) {
|
||||
existingEsLintConfig.plugins = Array.from(
|
||||
new Set([...(existingEsLintConfig.plugins ?? []), '@nx'])
|
||||
);
|
||||
|
||||
@ -34,9 +34,7 @@ export async function storybookConfigurationGenerator(
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return () => {
|
||||
storybookGeneratorInstallTask();
|
||||
};
|
||||
return storybookGeneratorInstallTask;
|
||||
}
|
||||
|
||||
export default storybookConfigurationGenerator;
|
||||
|
||||
55
packages/angular/src/generators/utils/add-jest.ts
Normal file
55
packages/angular/src/generators/utils/add-jest.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { joinPathFragments, type Tree } from '@nx/devkit';
|
||||
import { configurationGenerator } from '@nx/jest';
|
||||
import { jestPresetAngularVersion } from '../../utils/versions';
|
||||
import { addDependenciesToPackageJsonIfDontExist } from './version-utils';
|
||||
|
||||
export type AddJestOptions = {
|
||||
name: string;
|
||||
projectRoot: string;
|
||||
skipPackageJson: boolean;
|
||||
strict: boolean;
|
||||
};
|
||||
|
||||
export async function addJest(
|
||||
tree: Tree,
|
||||
options: AddJestOptions
|
||||
): Promise<void> {
|
||||
if (!options.skipPackageJson) {
|
||||
process.env.npm_config_legacy_peer_deps ??= 'true';
|
||||
|
||||
addDependenciesToPackageJsonIfDontExist(
|
||||
tree,
|
||||
{},
|
||||
{ 'jest-preset-angular': jestPresetAngularVersion }
|
||||
);
|
||||
}
|
||||
|
||||
await configurationGenerator(tree, {
|
||||
project: options.name,
|
||||
setupFile: 'angular',
|
||||
supportTsx: false,
|
||||
skipSerializers: false,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
const setupFile = joinPathFragments(
|
||||
options.projectRoot,
|
||||
'src',
|
||||
'test-setup.ts'
|
||||
);
|
||||
if (options.strict && tree.exists(setupFile)) {
|
||||
const contents = tree.read(setupFile, 'utf-8');
|
||||
tree.write(
|
||||
setupFile,
|
||||
`// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
|
||||
globalThis.ngJest = {
|
||||
testEnvironmentOptions: {
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
},
|
||||
};
|
||||
${contents}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
import { readJson, updateJson, type Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { angularDevkitVersion, angularVersion } from '../../utils/versions';
|
||||
import { ensureAngularDependencies } from './ensure-angular-dependencies';
|
||||
|
||||
describe('ensureAngularDependencies', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should add angular dependencies', () => {
|
||||
// ACT
|
||||
ensureAngularDependencies(tree);
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/common']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/compiler']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/core']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser']).toBe(angularVersion);
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe(
|
||||
angularVersion
|
||||
);
|
||||
expect(dependencies['@angular/router']).toBe(angularVersion);
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe(angularDevkitVersion);
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular/language-service']).toBe(angularVersion);
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe(
|
||||
angularDevkitVersion
|
||||
);
|
||||
|
||||
// codelyzer should no longer be there by default
|
||||
expect(devDependencies['codelyzer']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should add angular dependencies respecting base packages versions', () => {
|
||||
// ARRANGE
|
||||
updateJson(tree, 'package.json', (json) => ({
|
||||
...json,
|
||||
dependencies: {
|
||||
...json.dependencies,
|
||||
'@angular/core': '~15.0.0',
|
||||
},
|
||||
devDependencies: {
|
||||
...json.devDependencies,
|
||||
'@angular-devkit/build-angular': '~15.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
// ACT
|
||||
ensureAngularDependencies(tree);
|
||||
|
||||
// ASSERT
|
||||
const { dependencies, devDependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/common']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/compiler']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/core']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/platform-browser']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/platform-browser-dynamic']).toBe('~15.0.0');
|
||||
expect(dependencies['@angular/router']).toBe('~15.0.0');
|
||||
expect(dependencies['rxjs']).toBeDefined();
|
||||
expect(dependencies['tslib']).toBeDefined();
|
||||
expect(dependencies['zone.js']).toBeDefined();
|
||||
expect(devDependencies['@angular/cli']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular/compiler-cli']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular/language-service']).toBe('~15.0.0');
|
||||
expect(devDependencies['@angular-devkit/build-angular']).toBe('~15.0.0');
|
||||
});
|
||||
|
||||
it('should not overwrite already installed dependencies', () => {
|
||||
// ARRANGE
|
||||
updateJson(tree, 'package.json', (json) => ({
|
||||
...json,
|
||||
dependencies: {
|
||||
...json.dependencies,
|
||||
'@angular/animations': '~15.0.1',
|
||||
'@angular/core': '~15.0.0',
|
||||
},
|
||||
}));
|
||||
|
||||
// ACT
|
||||
ensureAngularDependencies(tree);
|
||||
|
||||
// ASSERT
|
||||
const { dependencies } = readJson(tree, 'package.json');
|
||||
|
||||
expect(dependencies['@angular/animations']).toBe('~15.0.1');
|
||||
expect(dependencies['@angular/core']).toBe('~15.0.0');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,48 @@
|
||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||
import {
|
||||
addDependenciesToPackageJsonIfDontExist,
|
||||
getInstalledPackageVersion,
|
||||
versions,
|
||||
} from './version-utils';
|
||||
|
||||
export function ensureAngularDependencies(tree: Tree): GeneratorCallback {
|
||||
const pkgVersions = versions(tree);
|
||||
|
||||
const angularVersion =
|
||||
getInstalledPackageVersion(tree, '@angular/core') ??
|
||||
pkgVersions.angularVersion;
|
||||
const angularDevkitVersion =
|
||||
getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ??
|
||||
pkgVersions.angularDevkitVersion;
|
||||
const rxjsVersion =
|
||||
getInstalledPackageVersion(tree, 'rxjs') ?? pkgVersions.rxjsVersion;
|
||||
const tsLibVersion =
|
||||
getInstalledPackageVersion(tree, 'tslib') ?? pkgVersions.tsLibVersion;
|
||||
const zoneJsVersion =
|
||||
getInstalledPackageVersion(tree, 'zone.js') ?? pkgVersions.zoneJsVersion;
|
||||
|
||||
return addDependenciesToPackageJsonIfDontExist(
|
||||
tree,
|
||||
{
|
||||
'@angular/animations': angularVersion,
|
||||
'@angular/common': angularVersion,
|
||||
'@angular/compiler': angularVersion,
|
||||
'@angular/core': angularVersion,
|
||||
'@angular/forms': angularVersion,
|
||||
'@angular/platform-browser': angularVersion,
|
||||
'@angular/platform-browser-dynamic': angularVersion,
|
||||
'@angular/router': angularVersion,
|
||||
rxjs: rxjsVersion,
|
||||
tslib: tsLibVersion,
|
||||
'zone.js': zoneJsVersion,
|
||||
},
|
||||
{
|
||||
'@angular/cli': angularDevkitVersion,
|
||||
'@angular/compiler-cli': angularVersion,
|
||||
'@angular/language-service': angularVersion,
|
||||
'@angular-devkit/build-angular': angularDevkitVersion,
|
||||
'@angular-devkit/schematics': angularDevkitVersion,
|
||||
'@schematics/angular': angularDevkitVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -16,13 +16,16 @@ import {
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import {
|
||||
getRelativePathToRootTsConfig,
|
||||
initGenerator as jsInitGenerator,
|
||||
} from '@nx/js';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { join } from 'path';
|
||||
import { addLinterToCyProject } from '../../utils/add-linter';
|
||||
import { addDefaultE2EConfig } from '../../utils/config';
|
||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||
import { viteVersion } from '../../utils/versions';
|
||||
import { typesNodeVersion, viteVersion } from '../../utils/versions';
|
||||
import cypressInitGenerator from '../init/init';
|
||||
import { addBaseCypressSetup } from '../base-setup/base-setup';
|
||||
|
||||
@ -56,7 +59,8 @@ export async function configurationGenerator(
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
if (!installedCypressVersion()) {
|
||||
tasks.push(await cypressInitGenerator(tree, opts));
|
||||
tasks.push(await jsInitGenerator(tree, { ...options, skipFormat: true }));
|
||||
tasks.push(await cypressInitGenerator(tree, { ...opts, skipFormat: true }));
|
||||
}
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const nxJson = readNxJson(tree);
|
||||
@ -65,9 +69,7 @@ export async function configurationGenerator(
|
||||
? p === '@nx/cypress/plugin'
|
||||
: p.plugin === '@nx/cypress/plugin'
|
||||
);
|
||||
if (opts.bundler === 'vite') {
|
||||
tasks.push(addDependenciesToPackageJson(tree, {}, { vite: viteVersion }));
|
||||
}
|
||||
|
||||
await addFiles(tree, opts, projectGraph, hasPlugin);
|
||||
if (!hasPlugin) {
|
||||
addTarget(tree, opts);
|
||||
@ -79,6 +81,10 @@ export async function configurationGenerator(
|
||||
});
|
||||
tasks.push(linterTask);
|
||||
|
||||
if (!opts.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(tree, opts));
|
||||
}
|
||||
|
||||
if (!opts.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
@ -86,6 +92,18 @@ export async function configurationGenerator(
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function ensureDependencies(tree: Tree, options: NormalizedSchema) {
|
||||
const devDependencies: Record<string, string> = {
|
||||
'@types/node': typesNodeVersion,
|
||||
};
|
||||
|
||||
if (options.bundler === 'vite') {
|
||||
devDependencies['vite'] = viteVersion;
|
||||
}
|
||||
|
||||
return addDependenciesToPackageJson(tree, {}, devDependencies);
|
||||
}
|
||||
|
||||
function normalizeOptions(tree: Tree, options: CypressE2EConfigSchema) {
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
if (projectConfig?.targets?.e2e) {
|
||||
|
||||
@ -18,13 +18,20 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { checkAndCleanWithSemver } from '@nx/devkit/src/utils/semver';
|
||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import {
|
||||
getRelativePathToRootTsConfig,
|
||||
initGenerator as jsInitGenerator,
|
||||
} from '@nx/js';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { join } from 'path';
|
||||
import { major } from 'semver';
|
||||
import { addLinterToCyProject } from '../../utils/add-linter';
|
||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||
import { cypressVersion, viteVersion } from '../../utils/versions';
|
||||
import {
|
||||
cypressVersion,
|
||||
typesNodeVersion,
|
||||
viteVersion,
|
||||
} from '../../utils/versions';
|
||||
import { cypressInitGenerator } from '../init/init';
|
||||
import { Schema } from './schema';
|
||||
|
||||
@ -186,18 +193,9 @@ export async function cypressProjectGeneratorInternal(
|
||||
// if there is an installed cypress version, then we don't call
|
||||
// init since we want to keep the existing version that is installed
|
||||
if (!cypressVersion) {
|
||||
tasks.push(await cypressInitGenerator(host, options));
|
||||
}
|
||||
|
||||
if (schema.bundler === 'vite') {
|
||||
tasks.push(await jsInitGenerator(host, { ...options, skipFormat: true }));
|
||||
tasks.push(
|
||||
addDependenciesToPackageJson(
|
||||
host,
|
||||
{},
|
||||
{
|
||||
vite: viteVersion,
|
||||
}
|
||||
)
|
||||
await cypressInitGenerator(host, { ...options, skipFormat: true })
|
||||
);
|
||||
}
|
||||
|
||||
@ -211,12 +209,29 @@ export async function cypressProjectGeneratorInternal(
|
||||
overwriteExisting: true,
|
||||
});
|
||||
tasks.push(installTask);
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(host, options));
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function ensureDependencies(tree: Tree, options: CypressProjectSchema) {
|
||||
const devDependencies: Record<string, string> = {
|
||||
'@types/node': typesNodeVersion,
|
||||
};
|
||||
|
||||
if (options.bundler === 'vite') {
|
||||
devDependencies['vite'] = viteVersion;
|
||||
}
|
||||
|
||||
return addDependenciesToPackageJson(tree, {}, devDependencies);
|
||||
}
|
||||
|
||||
async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
|
||||
@ -26,7 +26,6 @@ describe('init', () => {
|
||||
|
||||
expect(packageJson.devDependencies.cypress).toBeDefined();
|
||||
expect(packageJson.devDependencies['@nx/cypress']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/node']).toBeDefined();
|
||||
expect(packageJson.devDependencies[existing]).toBeDefined();
|
||||
expect(packageJson.dependencies['@nx/cypress']).toBeUndefined();
|
||||
expect(packageJson.dependencies[existing]).toBeDefined();
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
readNxJson,
|
||||
removeDependenciesFromPackageJson,
|
||||
@ -7,13 +8,8 @@ import {
|
||||
Tree,
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
cypressVersion,
|
||||
nxVersion,
|
||||
typesNodeVersion,
|
||||
} from '../../utils/versions';
|
||||
import { cypressVersion, nxVersion } from '../../utils/versions';
|
||||
import { Schema } from './schema';
|
||||
import { initGenerator } from '@nx/js';
|
||||
import { CypressPluginOptions } from '../../plugins/plugin';
|
||||
|
||||
function setupE2ETargetDefaults(tree: Tree) {
|
||||
@ -38,17 +34,21 @@ function setupE2ETargetDefaults(tree: Tree) {
|
||||
}
|
||||
|
||||
function updateDependencies(tree: Tree) {
|
||||
removeDependenciesFromPackageJson(tree, ['@nx/cypress'], []);
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/cypress'], []));
|
||||
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
['@nx/cypress']: nxVersion,
|
||||
cypress: cypressVersion,
|
||||
'@types/node': typesNodeVersion,
|
||||
}
|
||||
tasks.push(
|
||||
addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
['@nx/cypress']: nxVersion,
|
||||
cypress: cypressVersion,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function addPlugin(tree: Tree) {
|
||||
@ -93,30 +93,24 @@ function updateProductionFileset(tree: Tree) {
|
||||
}
|
||||
|
||||
export async function cypressInitGenerator(tree: Tree, options: Schema) {
|
||||
const addPlugins = process.env.NX_PCV3 === 'true';
|
||||
updateProductionFileset(tree);
|
||||
if (!addPlugins) {
|
||||
|
||||
if (process.env.NX_PCV3 === 'true') {
|
||||
addPlugin(tree);
|
||||
} else {
|
||||
setupE2ETargetDefaults(tree);
|
||||
}
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
tasks.push(
|
||||
await initGenerator(tree, {
|
||||
...options,
|
||||
skipFormat: true,
|
||||
})
|
||||
);
|
||||
|
||||
if (addPlugins) {
|
||||
addPlugin(tree);
|
||||
}
|
||||
|
||||
let installTask: GeneratorCallback = () => {};
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(updateDependencies(tree));
|
||||
installTask = updateDependencies(tree);
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return installTask;
|
||||
}
|
||||
|
||||
export default cypressInitGenerator;
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
export interface Schema {
|
||||
skipPackageJson?: boolean;
|
||||
|
||||
skipFormat?: boolean;
|
||||
|
||||
addPlugins?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
}
|
||||
|
||||
@ -6,6 +6,12 @@
|
||||
"description": "Add Cypress Configuration to the workspace.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@ -7,6 +7,7 @@ import { addProject } from './lib/add-project';
|
||||
import { createFiles } from './lib/create-files';
|
||||
import { normalizeOptions } from './lib/normalize-options';
|
||||
import { Schema } from './schema';
|
||||
import { ensureDependencies } from './lib/ensure-dependencies';
|
||||
|
||||
export async function detoxApplicationGenerator(host: Tree, schema: Schema) {
|
||||
return await detoxApplicationGeneratorInternal(host, {
|
||||
@ -30,12 +31,13 @@ export async function detoxApplicationGeneratorInternal(
|
||||
addGitIgnoreEntry(host, options);
|
||||
|
||||
const lintingTask = await addLinting(host, options);
|
||||
const depsTask = ensureDependencies(host, options);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
|
||||
return runTasksInSerial(initTask, lintingTask);
|
||||
return runTasksInSerial(initTask, lintingTask, depsTask);
|
||||
}
|
||||
|
||||
export default detoxApplicationGenerator;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
import { addDependenciesToPackageJson, type Tree } from '@nx/devkit';
|
||||
import { jestVersion, typesNodeVersion } from '@nx/jest/src/utils/versions';
|
||||
import {
|
||||
configPluginsDetoxVersion,
|
||||
testingLibraryJestDom,
|
||||
} from '../../../utils/versions';
|
||||
import type { NormalizedSchema } from './normalize-options';
|
||||
|
||||
export function ensureDependencies(tree: Tree, options: NormalizedSchema) {
|
||||
const devDependencies: Record<string, string> = {
|
||||
'@testing-library/jest-dom': testingLibraryJestDom,
|
||||
'@types/node': typesNodeVersion,
|
||||
'jest-circus': jestVersion,
|
||||
};
|
||||
|
||||
if (options.framework === 'expo') {
|
||||
devDependencies['@config-plugins/detox'] = configPluginsDetoxVersion;
|
||||
}
|
||||
|
||||
return addDependenciesToPackageJson(tree, {}, devDependencies);
|
||||
}
|
||||
@ -13,7 +13,6 @@ describe('init', () => {
|
||||
await detoxInitGenerator(tree, {});
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['@nx/detox']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/node']).toBeDefined();
|
||||
expect(packageJson.devDependencies['detox']).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@ -8,16 +8,9 @@ import {
|
||||
Tree,
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import { jestVersion, typesNodeVersion } from '@nx/jest/src/utils/versions';
|
||||
|
||||
import { Schema } from './schema';
|
||||
import {
|
||||
configPluginsDetoxVersion,
|
||||
detoxVersion,
|
||||
nxVersion,
|
||||
testingLibraryJestDom,
|
||||
} from '../../utils/versions';
|
||||
import { DetoxPluginOptions } from '../../plugins/plugin';
|
||||
import { detoxVersion, nxVersion } from '../../utils/versions';
|
||||
import { Schema } from './schema';
|
||||
|
||||
export async function detoxInitGenerator(host: Tree, schema: Schema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
@ -45,12 +38,6 @@ export function updateDependencies(host: Tree, schema: Schema) {
|
||||
{
|
||||
'@nx/detox': nxVersion,
|
||||
detox: detoxVersion,
|
||||
'@testing-library/jest-dom': testingLibraryJestDom,
|
||||
'@types/node': typesNodeVersion,
|
||||
'jest-circus': jestVersion,
|
||||
...(schema.framework === 'expo'
|
||||
? { '@config-plugins/detox': configPluginsDetoxVersion }
|
||||
: {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
export interface Schema {
|
||||
skipFormat?: boolean;
|
||||
skipPackageJson?: boolean; //default is false
|
||||
framework?: 'react-native' | 'expo';
|
||||
}
|
||||
|
||||
@ -15,12 +15,6 @@
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"framework": {
|
||||
"type": "string",
|
||||
"description": "App framework to test",
|
||||
"enum": ["react-native", "expo"],
|
||||
"default": "react-native"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@ -1,23 +1,31 @@
|
||||
import { addDependenciesToPackageJson, formatFiles, Tree } from '@nx/devkit';
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { Schema } from './schema';
|
||||
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
|
||||
export async function esbuildInitGenerator(tree: Tree, schema: Schema) {
|
||||
const task = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@nx/esbuild': nxVersion,
|
||||
esbuild: esbuildVersion,
|
||||
}
|
||||
);
|
||||
let installTask: GeneratorCallback = () => {};
|
||||
if (!schema.skipPackageJson) {
|
||||
installTask = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@nx/esbuild': nxVersion,
|
||||
esbuild: esbuildVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return task;
|
||||
return installTask;
|
||||
}
|
||||
|
||||
export default esbuildInitGenerator;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export interface Schema {
|
||||
compiler?: 'babel' | 'swc' | 'tsc';
|
||||
skipFormat?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
}
|
||||
|
||||
@ -6,16 +6,15 @@
|
||||
"description": "Init Webpack Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"enum": ["babel", "swc", "tsc"],
|
||||
"description": "The compiler to initialize for.",
|
||||
"default": "babel"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`@nx/eslint:init should generate the global eslint config 1`] = `
|
||||
"{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
"plugins": [
|
||||
"@nx"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": [
|
||||
"error",
|
||||
{
|
||||
"enforceBuildableLibDependency": true,
|
||||
"allow": [],
|
||||
"depConstraints": [
|
||||
{
|
||||
"sourceTag": "*",
|
||||
"onlyDependOnLibsWithTags": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@nx/typescript"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@nx/javascript"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
"
|
||||
`;
|
||||
@ -16,22 +16,8 @@ describe('@nx/eslint:init', () => {
|
||||
process.env.NX_PCV3 = envV3;
|
||||
});
|
||||
|
||||
it('should generate the global eslint config', async () => {
|
||||
await lintInitGenerator(tree, {
|
||||
linter: Linter.EsLint,
|
||||
});
|
||||
|
||||
expect(tree.read('.eslintrc.json', 'utf-8')).toMatchSnapshot();
|
||||
expect(tree.read('.eslintignore', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"node_modules
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add the root eslint config to the lint targetDefaults for lint', async () => {
|
||||
await lintInitGenerator(tree, {
|
||||
linter: Linter.EsLint,
|
||||
});
|
||||
it('should add the root eslint config to the lint targetDefaults for lint', () => {
|
||||
lintInitGenerator(tree, {});
|
||||
|
||||
expect(readJson(tree, 'nx.json').targetDefaults['@nx/eslint:lint']).toEqual(
|
||||
{
|
||||
@ -46,24 +32,22 @@ describe('@nx/eslint:init', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should not generate the global eslint config if it already exist', async () => {
|
||||
it('should not generate the global eslint config if it already exist', () => {
|
||||
tree.write('.eslintrc.js', '{}');
|
||||
|
||||
await lintInitGenerator(tree, {
|
||||
linter: Linter.EsLint,
|
||||
});
|
||||
lintInitGenerator(tree, {});
|
||||
|
||||
expect(tree.exists('.eslintrc.json')).toBe(false);
|
||||
});
|
||||
|
||||
it('should setup lint target defaults', async () => {
|
||||
it('should setup lint target defaults', () => {
|
||||
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||
json.namedInputs ??= {};
|
||||
json.namedInputs.production = ['default'];
|
||||
return json;
|
||||
});
|
||||
|
||||
await lintInitGenerator(tree, {});
|
||||
lintInitGenerator(tree, {});
|
||||
|
||||
expect(
|
||||
readJson<NxJsonConfiguration>(tree, 'nx.json').targetDefaults[
|
||||
@ -80,7 +64,7 @@ describe('@nx/eslint:init', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should setup @nx/eslint/plugin', async () => {
|
||||
it('should setup @nx/eslint/plugin', () => {
|
||||
process.env.NX_PCV3 = 'true';
|
||||
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||
json.namedInputs ??= {};
|
||||
@ -88,7 +72,7 @@ describe('@nx/eslint:init', () => {
|
||||
return json;
|
||||
});
|
||||
|
||||
await lintInitGenerator(tree, {});
|
||||
lintInitGenerator(tree, {});
|
||||
|
||||
expect(
|
||||
readJson<NxJsonConfiguration>(tree, 'nx.json').targetDefaults[
|
||||
@ -108,20 +92,20 @@ describe('@nx/eslint:init', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add @nx/eslint/plugin in subsequent step', async () => {
|
||||
it('should add @nx/eslint/plugin in subsequent step', () => {
|
||||
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||
json.namedInputs ??= {};
|
||||
json.namedInputs.production = ['default'];
|
||||
return json;
|
||||
});
|
||||
|
||||
await lintInitGenerator(tree, {});
|
||||
lintInitGenerator(tree, {});
|
||||
expect(
|
||||
readJson<NxJsonConfiguration>(tree, 'nx.json').plugins
|
||||
).not.toBeDefined();
|
||||
|
||||
process.env.NX_PCV3 = 'true';
|
||||
await lintInitGenerator(tree, {});
|
||||
lintInitGenerator(tree, {});
|
||||
expect(readJson<NxJsonConfiguration>(tree, 'nx.json').plugins)
|
||||
.toMatchInlineSnapshot(`
|
||||
[
|
||||
|
||||
@ -3,28 +3,16 @@ import {
|
||||
addDependenciesToPackageJson,
|
||||
readNxJson,
|
||||
removeDependenciesFromPackageJson,
|
||||
updateJson,
|
||||
runTasksInSerial,
|
||||
updateNxJson,
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
eslintConfigPrettierVersion,
|
||||
eslintVersion,
|
||||
nxVersion,
|
||||
typescriptESLintVersion,
|
||||
} from '../../utils/versions';
|
||||
|
||||
import { Linter } from '../utils/linter';
|
||||
import { eslintVersion, nxVersion } from '../../utils/versions';
|
||||
import { findEslintFile } from '../utils/eslint-file';
|
||||
import { getGlobalEsLintConfiguration } from './global-eslint-config';
|
||||
import { EslintPluginOptions } from '../../plugins/plugin';
|
||||
import { hasEslintPlugin } from '../utils/plugin';
|
||||
|
||||
export interface LinterInitOptions {
|
||||
linter?: Linter;
|
||||
unitTestRunner?: string;
|
||||
skipPackageJson?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
function updateProductionFileset(tree: Tree) {
|
||||
@ -78,22 +66,6 @@ function addPlugin(tree: Tree) {
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
|
||||
function updateVSCodeExtensions(tree: Tree) {
|
||||
if (tree.exists('.vscode/extensions.json')) {
|
||||
updateJson(tree, '.vscode/extensions.json', (json) => {
|
||||
json.recommendations ||= [];
|
||||
const extension = 'dbaeumer.vscode-eslint';
|
||||
if (!json.recommendations.includes(extension)) {
|
||||
json.recommendations.push(extension);
|
||||
}
|
||||
return json;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes ESLint configuration in a workspace and adds necessary dependencies.
|
||||
*/
|
||||
function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
||||
const addPlugins = process.env.NX_PCV3 === 'true';
|
||||
const hasPlugin = hasEslintPlugin(tree);
|
||||
@ -108,17 +80,6 @@ function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
removeDependenciesFromPackageJson(tree, ['@nx/eslint'], []);
|
||||
}
|
||||
|
||||
writeJson(
|
||||
tree,
|
||||
'.eslintrc.json',
|
||||
getGlobalEsLintConfiguration(options.unitTestRunner, options.rootProject)
|
||||
);
|
||||
tree.write('.eslintignore', 'node_modules\n');
|
||||
|
||||
updateProductionFileset(tree);
|
||||
|
||||
if (addPlugins) {
|
||||
@ -127,22 +88,22 @@ function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
||||
addTargetDefaults(tree);
|
||||
}
|
||||
|
||||
updateVSCodeExtensions(tree);
|
||||
|
||||
return !options.skipPackageJson
|
||||
? addDependenciesToPackageJson(
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/eslint'], []));
|
||||
tasks.push(
|
||||
addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@nx/eslint': nxVersion,
|
||||
'@nx/eslint-plugin': nxVersion,
|
||||
'@typescript-eslint/parser': typescriptESLintVersion,
|
||||
'@typescript-eslint/eslint-plugin': typescriptESLintVersion,
|
||||
eslint: eslintVersion,
|
||||
'eslint-config-prettier': eslintConfigPrettierVersion,
|
||||
}
|
||||
)
|
||||
: () => {};
|
||||
);
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export function lintInitGenerator(tree: Tree, options: LinterInitOptions) {
|
||||
|
||||
@ -9,7 +9,6 @@ import {
|
||||
import { Linter } from '../utils/linter';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { lintProjectGenerator } from './lint-project';
|
||||
import { eslintVersion } from '../../utils/versions';
|
||||
|
||||
describe('@nx/eslint:lint-project', () => {
|
||||
let tree: Tree;
|
||||
@ -272,4 +271,55 @@ describe('@nx/eslint:lint-project', () => {
|
||||
const eslintConfig = readJson(tree, 'libs/test-lib/.eslintrc.json');
|
||||
expect(eslintConfig.extends).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should generate the global eslint config', async () => {
|
||||
await lintProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
linter: Linter.EsLint,
|
||||
project: 'test-lib',
|
||||
});
|
||||
|
||||
expect(tree.read('.eslintrc.json', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"{
|
||||
"root": true,
|
||||
"ignorePatterns": ["**/*"],
|
||||
"plugins": ["@nx"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": [
|
||||
"error",
|
||||
{
|
||||
"enforceBuildableLibDependency": true,
|
||||
"allow": [],
|
||||
"depConstraints": [
|
||||
{
|
||||
"sourceTag": "*",
|
||||
"onlyDependOnLibsWithTags": ["*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"extends": ["plugin:@nx/typescript"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"extends": ["plugin:@nx/javascript"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(tree.read('.eslintignore', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"node_modules
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import type {
|
||||
GeneratorCallback,
|
||||
NxJsonConfiguration,
|
||||
ProjectConfiguration,
|
||||
Tree,
|
||||
@ -8,6 +9,7 @@ import {
|
||||
offsetFromRoot,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
@ -35,6 +37,7 @@ import {
|
||||
baseEsLintFlatConfigFile,
|
||||
} from '../../utils/config-file';
|
||||
import { hasEslintPlugin } from '../utils/plugin';
|
||||
import { setupRootEsLint } from './setup-root-eslint';
|
||||
|
||||
interface LintProjectOptions {
|
||||
project: string;
|
||||
@ -52,12 +55,17 @@ export async function lintProjectGenerator(
|
||||
tree: Tree,
|
||||
options: LintProjectOptions
|
||||
) {
|
||||
const installTask = lintInitGenerator(tree, {
|
||||
linter: options.linter,
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const initTask = lintInitGenerator(tree, {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
tasks.push(initTask);
|
||||
const rootEsLintTask = setupRootEsLint(tree, {
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
tasks.push(rootEsLintTask);
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
|
||||
let lintFilePatterns = options.eslintFilePatterns;
|
||||
@ -154,7 +162,7 @@ export async function lintProjectGenerator(
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return installTask;
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function createEsLintConfiguration(
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
writeJson,
|
||||
type GeneratorCallback,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
eslintConfigPrettierVersion,
|
||||
nxVersion,
|
||||
typescriptESLintVersion,
|
||||
} from '../../utils/versions';
|
||||
import { getGlobalEsLintConfiguration } from '../init/global-eslint-config';
|
||||
import { findEslintFile } from '../utils/eslint-file';
|
||||
|
||||
export type SetupRootEsLintOptions = {
|
||||
unitTestRunner?: string;
|
||||
skipPackageJson?: boolean;
|
||||
rootProject?: boolean;
|
||||
};
|
||||
|
||||
export function setupRootEsLint(
|
||||
tree: Tree,
|
||||
options: SetupRootEsLintOptions
|
||||
): GeneratorCallback {
|
||||
const rootEslintFile = findEslintFile(tree);
|
||||
if (rootEslintFile) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
writeJson(
|
||||
tree,
|
||||
'.eslintrc.json',
|
||||
getGlobalEsLintConfiguration(options.unitTestRunner, options.rootProject)
|
||||
);
|
||||
|
||||
if (tree.exists('.eslintignore')) {
|
||||
let content = tree.read('.eslintignore', 'utf-8');
|
||||
if (!/^node_modules$/gm.test(content)) {
|
||||
content = `${content}\nnode_modules\n`;
|
||||
tree.write('.eslintignore', content);
|
||||
}
|
||||
} else {
|
||||
tree.write('.eslintignore', 'node_modules\n');
|
||||
}
|
||||
|
||||
return !options.skipPackageJson
|
||||
? addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@nx/eslint-plugin': nxVersion,
|
||||
'@typescript-eslint/parser': typescriptESLintVersion,
|
||||
'@typescript-eslint/eslint-plugin': typescriptESLintVersion,
|
||||
'eslint-config-prettier': eslintConfigPrettierVersion,
|
||||
}
|
||||
)
|
||||
: () => {};
|
||||
}
|
||||
@ -5,6 +5,7 @@ import {
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
|
||||
import { runSymlink } from '../../utils/symlink-task';
|
||||
import { addLinting } from '../../utils/add-linting';
|
||||
@ -17,6 +18,8 @@ import { createApplicationFiles } from './lib/create-application-files';
|
||||
import { addEasScripts } from './lib/add-eas-scripts';
|
||||
import { addDetox } from './lib/add-detox';
|
||||
import { Schema } from './schema';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
|
||||
|
||||
export async function expoApplicationGenerator(
|
||||
host: Tree,
|
||||
@ -34,7 +37,18 @@ export async function expoApplicationGeneratorInternal(
|
||||
): Promise<GeneratorCallback> {
|
||||
const options = await normalizeOptions(host, schema);
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const jsInitTask = await jsInitGenerator(host, {
|
||||
...schema,
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(jsInitTask);
|
||||
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
||||
tasks.push(initTask);
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(host));
|
||||
}
|
||||
initRootBabelConfig(host);
|
||||
|
||||
createApplicationFiles(host, options);
|
||||
addProject(host, options);
|
||||
@ -46,6 +60,7 @@ export async function expoApplicationGeneratorInternal(
|
||||
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||
],
|
||||
});
|
||||
tasks.push(lintTask);
|
||||
|
||||
const jestTask = await addJest(
|
||||
host,
|
||||
@ -55,15 +70,18 @@ export async function expoApplicationGeneratorInternal(
|
||||
options.js,
|
||||
options.skipPackageJson
|
||||
);
|
||||
tasks.push(jestTask);
|
||||
const detoxTask = await addDetox(host, options);
|
||||
tasks.push(detoxTask);
|
||||
const symlinkTask = runSymlink(host.root, options.appProjectRoot);
|
||||
tasks.push(symlinkTask);
|
||||
addEasScripts(host);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
|
||||
return runTasksInSerial(initTask, lintTask, jestTask, detoxTask, symlinkTask);
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default expoApplicationGenerator;
|
||||
|
||||
@ -11,12 +11,11 @@ describe('init', () => {
|
||||
});
|
||||
|
||||
it('should add react native dependencies', async () => {
|
||||
await expoInitGenerator(tree, { e2eTestRunner: 'none' });
|
||||
await expoInitGenerator(tree, {});
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.dependencies['react']).toBeDefined();
|
||||
expect(packageJson.dependencies['expo']).toBeDefined();
|
||||
expect(packageJson.dependencies['react-native']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/react']).toBeDefined();
|
||||
});
|
||||
|
||||
it('should add .gitignore entries for React native files and directories', async () => {
|
||||
@ -26,7 +25,7 @@ describe('init', () => {
|
||||
/node_modules
|
||||
`
|
||||
);
|
||||
await expoInitGenerator(tree, { e2eTestRunner: 'none' });
|
||||
await expoInitGenerator(tree, {});
|
||||
|
||||
const content = tree.read('/.gitignore').toString();
|
||||
|
||||
|
||||
@ -8,73 +8,32 @@ import {
|
||||
Tree,
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import { Schema } from './schema';
|
||||
import { ExpoPluginOptions } from '../../../plugins/plugin';
|
||||
import {
|
||||
babelPresetExpoVersion,
|
||||
easCliVersion,
|
||||
expoCliVersion,
|
||||
expoMetroConfigVersion,
|
||||
expoSplashScreenVersion,
|
||||
expoStatusBarVersion,
|
||||
expoVersion,
|
||||
jestExpoVersion,
|
||||
metroVersion,
|
||||
nxVersion,
|
||||
reactDomVersion,
|
||||
reactNativeSvgTransformerVersion,
|
||||
reactNativeSvgVersion,
|
||||
reactNativeVersion,
|
||||
reactNativeWebVersion,
|
||||
reactTestRendererVersion,
|
||||
reactVersion,
|
||||
testingLibraryJestNativeVersion,
|
||||
testingLibraryReactNativeVersion,
|
||||
typesReactVersion,
|
||||
} from '../../utils/versions';
|
||||
import { ExpoPluginOptions } from '../../../plugins/plugin';
|
||||
|
||||
import { jestInitGenerator } from '@nx/jest';
|
||||
import { detoxInitGenerator } from '@nx/detox';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
|
||||
import { addGitIgnoreEntry } from './lib/add-git-ignore-entry';
|
||||
import { initRootBabelConfig } from './lib/init-root-babel-config';
|
||||
import { Schema } from './schema';
|
||||
|
||||
export async function expoInitGenerator(host: Tree, schema: Schema) {
|
||||
addGitIgnoreEntry(host);
|
||||
initRootBabelConfig(host);
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
tasks.push(
|
||||
await jsInitGenerator(host, {
|
||||
...schema,
|
||||
skipFormat: true,
|
||||
})
|
||||
);
|
||||
|
||||
if (!schema.skipPackageJson) {
|
||||
tasks.push(moveDependency(host));
|
||||
tasks.push(updateDependencies(host));
|
||||
}
|
||||
|
||||
if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') {
|
||||
const jestTask = await jestInitGenerator(host, schema);
|
||||
tasks.push(jestTask);
|
||||
}
|
||||
|
||||
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'detox') {
|
||||
const detoxTask = await detoxInitGenerator(host, {
|
||||
...schema,
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(detoxTask);
|
||||
}
|
||||
|
||||
if (process.env.NX_PCV3 === 'true') {
|
||||
addPlugin(host);
|
||||
}
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
if (!schema.skipPackageJson) {
|
||||
tasks.push(moveDependency(host));
|
||||
tasks.push(updateDependencies(host));
|
||||
}
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
@ -90,25 +49,11 @@ export function updateDependencies(host: Tree) {
|
||||
'react-dom': reactDomVersion,
|
||||
'react-native': reactNativeVersion,
|
||||
expo: expoVersion,
|
||||
'expo-splash-screen': expoSplashScreenVersion,
|
||||
'expo-status-bar': expoStatusBarVersion,
|
||||
'react-native-web': reactNativeWebVersion,
|
||||
'@expo/metro-config': expoMetroConfigVersion,
|
||||
'react-native-svg-transformer': reactNativeSvgTransformerVersion,
|
||||
'react-native-svg': reactNativeSvgVersion,
|
||||
},
|
||||
{
|
||||
'@nx/expo': nxVersion,
|
||||
'@types/react': typesReactVersion,
|
||||
metro: metroVersion,
|
||||
'metro-resolver': metroVersion,
|
||||
'react-test-renderer': reactTestRendererVersion,
|
||||
'@testing-library/react-native': testingLibraryReactNativeVersion,
|
||||
'@testing-library/jest-native': testingLibraryJestNativeVersion,
|
||||
'jest-expo': jestExpoVersion,
|
||||
'@expo/cli': expoCliVersion,
|
||||
'eas-cli': easCliVersion,
|
||||
'babel-preset-expo': babelPresetExpoVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
export interface Schema {
|
||||
unitTestRunner?: 'jest' | 'none';
|
||||
skipFormat?: boolean;
|
||||
e2eTestRunner?: 'detox' | 'none';
|
||||
skipPackageJson?: boolean; // default is false
|
||||
js?: boolean;
|
||||
}
|
||||
|
||||
@ -5,33 +5,16 @@
|
||||
"description": "Add Nx Expo Schematics.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"e2eTestRunner": {
|
||||
"description": "Adds the specified e2e test runner",
|
||||
"type": "string",
|
||||
"enum": ["detox", "none"],
|
||||
"default": "detox"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`."
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@ -7,14 +7,19 @@ import {
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
TargetConfiguration,
|
||||
toJS,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
|
||||
import { addTsConfigPath, getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import {
|
||||
addTsConfigPath,
|
||||
getRelativePathToRootTsConfig,
|
||||
initGenerator as jsInitGenerator,
|
||||
} from '@nx/js';
|
||||
import init from '../init/init';
|
||||
import { addLinting } from '../../utils/add-linting';
|
||||
import { addJest } from '../../utils/add-jest';
|
||||
@ -25,6 +30,8 @@ import {
|
||||
} from '../../utils/versions';
|
||||
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
||||
import { Schema } from './schema';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
|
||||
|
||||
export async function expoLibraryGenerator(
|
||||
host: Tree,
|
||||
@ -49,12 +56,17 @@ export async function expoLibraryGeneratorInternal(
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
const initTask = await init(host, {
|
||||
...options,
|
||||
const jsInitTask = await jsInitGenerator(host, {
|
||||
...schema,
|
||||
skipFormat: true,
|
||||
e2eTestRunner: 'none',
|
||||
});
|
||||
tasks.push(jsInitTask);
|
||||
const initTask = await init(host, { ...options, skipFormat: true });
|
||||
tasks.push(initTask);
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(host));
|
||||
}
|
||||
initRootBabelConfig(host);
|
||||
|
||||
const addProjectTask = await addProject(host, options);
|
||||
if (addProjectTask) {
|
||||
@ -103,54 +115,58 @@ export async function expoLibraryGeneratorInternal(
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
async function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const targets: { [key: string]: TargetConfiguration } = {};
|
||||
|
||||
let task: GeneratorCallback;
|
||||
if (options.publishable || options.buildable) {
|
||||
const { rollupInitGenerator } = ensurePackage<typeof import('@nx/rollup')>(
|
||||
'@nx/rollup',
|
||||
nxVersion
|
||||
);
|
||||
|
||||
const external = [
|
||||
'react/jsx-runtime',
|
||||
'react-native',
|
||||
'react',
|
||||
'react-dom',
|
||||
];
|
||||
|
||||
targets.build = {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath: `dist/${options.projectRoot}`,
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
project: `${options.projectRoot}/package.json`,
|
||||
entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
external,
|
||||
rollupConfig: `@nx/react/plugins/bundle-rollup`,
|
||||
assets: [
|
||||
{
|
||||
glob: `${options.projectRoot}/README.md`,
|
||||
input: '.',
|
||||
output: '.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
task = await rollupInitGenerator(host, { ...options, skipFormat: true });
|
||||
}
|
||||
|
||||
addProjectConfiguration(host, options.name, {
|
||||
async function addProject(
|
||||
host: Tree,
|
||||
options: NormalizedSchema
|
||||
): Promise<GeneratorCallback> {
|
||||
const project: ProjectConfiguration = {
|
||||
root: options.projectRoot,
|
||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||
projectType: 'library',
|
||||
tags: options.parsedTags,
|
||||
targets,
|
||||
targets: {},
|
||||
};
|
||||
addProjectConfiguration(host, options.name, project);
|
||||
|
||||
if (!options.publishable && !options.buildable) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const { configurationGenerator } = ensurePackage<typeof import('@nx/rollup')>(
|
||||
'@nx/rollup',
|
||||
nxVersion
|
||||
);
|
||||
const rollupConfigTask = await configurationGenerator(host, {
|
||||
...options,
|
||||
project: options.name,
|
||||
skipFormat: true,
|
||||
});
|
||||
|
||||
return task;
|
||||
const external = ['react/jsx-runtime', 'react-native', 'react', 'react-dom'];
|
||||
|
||||
project.targets.build = {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath: `dist/${options.projectRoot}`,
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
project: `${options.projectRoot}/package.json`,
|
||||
entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
external,
|
||||
rollupConfig: `@nx/react/plugins/bundle-rollup`,
|
||||
assets: [
|
||||
{
|
||||
glob: `${options.projectRoot}/README.md`,
|
||||
input: '.',
|
||||
output: '.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
updateProjectConfiguration(host, options.name, project);
|
||||
|
||||
return rollupConfigTask;
|
||||
}
|
||||
|
||||
function updateTsConfig(tree: Tree, options: NormalizedSchema) {
|
||||
|
||||
44
packages/expo/src/utils/ensure-dependencies.ts
Normal file
44
packages/expo/src/utils/ensure-dependencies.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
type GeneratorCallback,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
babelPresetExpoVersion,
|
||||
expoMetroConfigVersion,
|
||||
expoSplashScreenVersion,
|
||||
expoStatusBarVersion,
|
||||
jestExpoVersion,
|
||||
metroVersion,
|
||||
reactNativeSvgTransformerVersion,
|
||||
reactNativeSvgVersion,
|
||||
reactNativeWebVersion,
|
||||
reactTestRendererVersion,
|
||||
testingLibraryJestNativeVersion,
|
||||
testingLibraryReactNativeVersion,
|
||||
typesReactVersion,
|
||||
} from './versions';
|
||||
|
||||
export function ensureDependencies(host: Tree): GeneratorCallback {
|
||||
return addDependenciesToPackageJson(
|
||||
host,
|
||||
{
|
||||
'expo-splash-screen': expoSplashScreenVersion,
|
||||
'expo-status-bar': expoStatusBarVersion,
|
||||
'react-native-web': reactNativeWebVersion,
|
||||
'@expo/metro-config': expoMetroConfigVersion,
|
||||
'react-native-svg-transformer': reactNativeSvgTransformerVersion,
|
||||
'react-native-svg': reactNativeSvgVersion,
|
||||
},
|
||||
{
|
||||
'@types/react': typesReactVersion,
|
||||
metro: metroVersion,
|
||||
'metro-resolver': metroVersion,
|
||||
'react-test-renderer': reactTestRendererVersion,
|
||||
'@testing-library/react-native': testingLibraryReactNativeVersion,
|
||||
'@testing-library/jest-native': testingLibraryJestNativeVersion,
|
||||
'jest-expo': jestExpoVersion,
|
||||
'babel-preset-expo': babelPresetExpoVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -1,8 +1,16 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { formatFiles, toJS, updateJson } from '@nx/devkit';
|
||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
runTasksInSerial,
|
||||
toJS,
|
||||
updateJson,
|
||||
} from '@nx/devkit';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
||||
import { tslibVersion } from '@nx/node/src/utils/versions';
|
||||
import { join } from 'path';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { initGenerator } from '../init/init';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
@ -63,23 +71,28 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
|
||||
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const initTask = await initGenerator(tree, { ...options, skipFormat: true });
|
||||
tasks.push(initTask);
|
||||
const applicationTask = await nodeApplicationGenerator(tree, {
|
||||
...schema,
|
||||
bundler: 'webpack',
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(applicationTask);
|
||||
addMainFile(tree, options);
|
||||
addTypes(tree, options);
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(tree));
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
await initTask();
|
||||
await applicationTask();
|
||||
};
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default applicationGenerator;
|
||||
@ -107,3 +120,11 @@ async function normalizeOptions(
|
||||
appProjectRoot,
|
||||
};
|
||||
}
|
||||
|
||||
function ensureDependencies(tree: Tree): GeneratorCallback {
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{ tslib: tslibVersion },
|
||||
{ '@nx/express': nxVersion }
|
||||
);
|
||||
}
|
||||
|
||||
@ -22,22 +22,11 @@ describe('init', () => {
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
// add express
|
||||
expect(packageJson.dependencies['express']).toBeDefined();
|
||||
// add tslib
|
||||
expect(packageJson.dependencies['tslib']).toBeDefined();
|
||||
// move `@nx/express` to dev
|
||||
expect(packageJson.dependencies['@nx/express']).toBeUndefined();
|
||||
expect(packageJson.devDependencies['@nx/express']).toBeDefined();
|
||||
// add express types
|
||||
expect(packageJson.devDependencies['@types/express']).toBeDefined();
|
||||
// keep existing packages
|
||||
expect(packageJson.devDependencies[existing]).toBeDefined();
|
||||
expect(packageJson.dependencies[existing]).toBeDefined();
|
||||
});
|
||||
|
||||
it('should not add jest config if unitTestRunner is none', async () => {
|
||||
await initGenerator(tree, {
|
||||
unitTestRunner: 'none',
|
||||
});
|
||||
expect(tree.exists('jest.config.js')).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,48 +1,41 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
removeDependenciesFromPackageJson,
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as nodeInitGenerator } from '@nx/node';
|
||||
import { tslibVersion } from '@nx/node/src/utils/versions';
|
||||
import {
|
||||
expressTypingsVersion,
|
||||
expressVersion,
|
||||
nxVersion,
|
||||
} from '../../utils/versions';
|
||||
import { expressVersion, nxVersion } from '../../utils/versions';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
function updateDependencies(tree: Tree) {
|
||||
removeDependenciesFromPackageJson(tree, ['@nx/express'], []);
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{
|
||||
express: expressVersion,
|
||||
tslib: tslibVersion,
|
||||
},
|
||||
{
|
||||
'@types/express': expressTypingsVersion,
|
||||
'@nx/express': nxVersion,
|
||||
}
|
||||
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/express'], []));
|
||||
|
||||
tasks.push(
|
||||
addDependenciesToPackageJson(
|
||||
tree,
|
||||
{ express: expressVersion },
|
||||
{ '@nx/express': nxVersion }
|
||||
)
|
||||
);
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export async function initGenerator(tree: Tree, schema: Schema) {
|
||||
const initTask = await nodeInitGenerator(tree, {
|
||||
...schema,
|
||||
skipFormat: true,
|
||||
});
|
||||
const installTask = updateDependencies(tree);
|
||||
let installTask: GeneratorCallback = () => {};
|
||||
if (!schema.skipPackageJson) {
|
||||
installTask = updateDependencies(tree);
|
||||
}
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
await initTask();
|
||||
await installTask();
|
||||
};
|
||||
return installTask;
|
||||
}
|
||||
|
||||
export default initGenerator;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export interface Schema {
|
||||
unitTestRunner?: 'jest' | 'none';
|
||||
skipFormat?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
}
|
||||
|
||||
@ -6,16 +6,15 @@
|
||||
"description": "Init Express Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`."
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import init from '../init/init';
|
||||
import { jestInitGenerator } from '../init/init';
|
||||
import { checkForTestTarget } from './lib/check-for-test-target';
|
||||
import { createFiles } from './lib/create-files';
|
||||
import { createJestConfig } from './lib/create-jest-config';
|
||||
import { ensureDependencies } from './lib/ensure-dependencies';
|
||||
import { updateTsConfig } from './lib/update-tsconfig';
|
||||
import { updateVsCodeRecommendedExtensions } from './lib/update-vscode-recommended-extensions';
|
||||
import { updateWorkspace } from './lib/update-workspace';
|
||||
import { JestProjectSchema, NormalizedJestProjectSchema } from './schema';
|
||||
import {
|
||||
@ -10,7 +13,9 @@ import {
|
||||
GeneratorCallback,
|
||||
readProjectConfiguration,
|
||||
readNxJson,
|
||||
runTasksInSerial,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
|
||||
const schemaDefaults = {
|
||||
setupFile: 'none',
|
||||
@ -61,11 +66,20 @@ export async function configurationGenerator(
|
||||
schema: JestProjectSchema
|
||||
): Promise<GeneratorCallback> {
|
||||
const options = normalizeOptions(tree, schema);
|
||||
const installTask = await init(tree, options);
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
|
||||
tasks.push(await jestInitGenerator(tree, options));
|
||||
if (!schema.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(tree, options));
|
||||
}
|
||||
|
||||
await createJestConfig(tree, options);
|
||||
checkForTestTarget(tree, options);
|
||||
createFiles(tree, options);
|
||||
updateTsConfig(tree, options);
|
||||
updateVsCodeRecommendedExtensions(tree);
|
||||
|
||||
const nxJson = readNxJson(tree);
|
||||
const hasPlugin = nxJson.plugins?.some((p) =>
|
||||
@ -80,7 +94,8 @@ export async function configurationGenerator(
|
||||
if (!schema.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
return installTask;
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default configurationGenerator;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`jest should generate files 1`] = `
|
||||
exports[`createJestConfig should generate files 1`] = `
|
||||
"import { getJestProjects } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
@ -8,13 +8,13 @@ projects: getJestProjects()
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`jest should generate files 2`] = `
|
||||
exports[`createJestConfig should generate files 2`] = `
|
||||
"const nxPreset = require('@nx/jest/preset').default;
|
||||
|
||||
module.exports = { ...nxPreset }"
|
||||
`;
|
||||
|
||||
exports[`jest should generate files with --js flag 1`] = `
|
||||
exports[`createJestConfig should generate files with --js flag 1`] = `
|
||||
"const { getJestProjects } = require('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
@ -22,7 +22,7 @@ projects: getJestProjects()
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`jest should generate files with --js flag 2`] = `
|
||||
exports[`createJestConfig should generate files with --js flag 2`] = `
|
||||
"const nxPreset = require('@nx/jest/preset').default;
|
||||
|
||||
module.exports = { ...nxPreset }"
|
||||
@ -0,0 +1,224 @@
|
||||
let projectGraph: ProjectGraph;
|
||||
jest.mock('@nx/devkit', () => ({
|
||||
...jest.requireActual<any>('@nx/devkit'),
|
||||
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
|
||||
return projectGraph;
|
||||
}),
|
||||
}));
|
||||
|
||||
import {
|
||||
addProjectConfiguration as _addProjectConfiguration,
|
||||
readProjectConfiguration,
|
||||
stripIndents,
|
||||
type ProjectConfiguration,
|
||||
type ProjectGraph,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { createJestConfig } from './create-jest-config';
|
||||
|
||||
function addProjectConfiguration(
|
||||
tree: Tree,
|
||||
name: string,
|
||||
project: ProjectConfiguration
|
||||
) {
|
||||
_addProjectConfiguration(tree, name, project);
|
||||
projectGraph.nodes[name] = {
|
||||
name: name,
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: project.root,
|
||||
targets: project.targets,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('createJestConfig', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
projectGraph = {
|
||||
nodes: {},
|
||||
dependencies: {},
|
||||
externalNodes: {},
|
||||
};
|
||||
});
|
||||
|
||||
it('should generate files with --js flag', async () => {
|
||||
await createJestConfig(tree, { js: true });
|
||||
|
||||
expect(tree.exists('jest.config.js')).toBeTruthy();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.config.js', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.preset.js', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should generate files ', async () => {
|
||||
await createJestConfig(tree, {});
|
||||
|
||||
expect(tree.exists('jest.config.ts')).toBeTruthy();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.config.ts', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.preset.js', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not override existing files', async () => {
|
||||
addProjectConfiguration(tree, 'my-project', {
|
||||
root: 'apps/my-app',
|
||||
name: 'my-app',
|
||||
sourceRoot: 'apps/my-app/src',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'apps/my-app/jest.config.ts',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expected = stripIndents`
|
||||
import { getJestProjects } from '@nx/jest';
|
||||
export default {
|
||||
projects: getJestProjects(),
|
||||
extraThing: "Goes Here"
|
||||
}
|
||||
`;
|
||||
tree.write('jest.config.ts', expected);
|
||||
|
||||
await createJestConfig(tree, {});
|
||||
|
||||
expect(tree.read('jest.config.ts', 'utf-8')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should make js jest files', async () => {
|
||||
await createJestConfig(tree, { js: true });
|
||||
|
||||
expect(tree.exists('jest.config.js')).toBeTruthy();
|
||||
expect(tree.exists('jest.preset.js')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('root project', () => {
|
||||
it('should not add a monorepo jest.config.ts to the project', async () => {
|
||||
await createJestConfig(tree, { rootProject: true });
|
||||
|
||||
expect(tree.exists('jest.config.ts')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should rename the project jest.config.ts to project jest config', async () => {
|
||||
addProjectConfiguration(tree, 'my-project', {
|
||||
root: '.',
|
||||
name: 'my-project',
|
||||
projectType: 'application',
|
||||
sourceRoot: 'src',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'jest.config.ts',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
tree.write(
|
||||
'jest.config.ts',
|
||||
`
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'my-project',
|
||||
testEnvironment: 'node',
|
||||
preset: './jest.preset.js',
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
await createJestConfig(tree, { rootProject: false });
|
||||
|
||||
expect(tree.exists('jest.config.app.ts')).toBeTruthy();
|
||||
expect(tree.read('jest.config.app.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'my-project',
|
||||
testEnvironment: 'node',
|
||||
preset: './jest.preset.js',
|
||||
};
|
||||
"
|
||||
`);
|
||||
expect(tree.read('jest.config.ts', 'utf-8'))
|
||||
.toEqual(`import { getJestProjects } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};`);
|
||||
expect(readProjectConfiguration(tree, 'my-project').targets.test)
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"executor": "@nx/jest:jest",
|
||||
"options": {
|
||||
"jestConfig": "jest.config.app.ts",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should work with --js', async () => {
|
||||
addProjectConfiguration(tree, 'my-project', {
|
||||
root: '.',
|
||||
name: 'my-project',
|
||||
sourceRoot: 'src',
|
||||
projectType: 'application',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'jest.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
tree.write(
|
||||
'jest.config.js',
|
||||
`
|
||||
/* eslint-disable */
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'my-project',
|
||||
testEnvironment: 'node',
|
||||
preset: './jest.preset.js',
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
await createJestConfig(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('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,143 @@
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
stripIndents,
|
||||
updateProjectConfiguration,
|
||||
type TargetConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||
import { findRootJestConfig } from '../../../utils/config/find-root-jest-files';
|
||||
import type { NormalizedJestProjectSchema } from '../schema';
|
||||
|
||||
export async function createJestConfig(
|
||||
tree: Tree,
|
||||
options: Partial<NormalizedJestProjectSchema>
|
||||
) {
|
||||
if (!tree.exists('jest.preset.js')) {
|
||||
// preset is always js file.
|
||||
tree.write(
|
||||
`jest.preset.js`,
|
||||
`
|
||||
const nxPreset = require('@nx/jest/preset').default;
|
||||
|
||||
module.exports = { ...nxPreset }`
|
||||
);
|
||||
}
|
||||
if (options.rootProject) {
|
||||
// we don't want any config to be made because the `configurationGenerator` will do it.
|
||||
// will copy the template config file
|
||||
return;
|
||||
}
|
||||
const rootJestPath = findRootJestConfig(tree);
|
||||
if (!rootJestPath) {
|
||||
// if there's not root jest config, we will create one and return
|
||||
// this can happen when:
|
||||
// - root jest config was renamed => in which case there is migration needed
|
||||
// - root project didn't have jest setup => again, no migration is needed
|
||||
generateGlobalConfig(tree, options.js);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tree.exists(rootJestPath)) {
|
||||
// moving from root project config to monorepo-style config
|
||||
const { nodes: projects } = await createProjectGraphAsync();
|
||||
const projectConfigurations = Object.values(projects);
|
||||
const rootProject = projectConfigurations.find(
|
||||
(projectNode) => projectNode.data?.root === '.'
|
||||
);
|
||||
// root project might have been removed,
|
||||
// if it's missing there's nothing to migrate
|
||||
if (rootProject) {
|
||||
const jestTarget = Object.entries(rootProject.data?.targets ?? {}).find(
|
||||
([_, t]) =>
|
||||
((t?.executor === '@nx/jest:jest' ||
|
||||
t?.executor === '@nrwl/jest:jest') &&
|
||||
t?.options?.jestConfig === rootJestPath) ||
|
||||
(t?.executor === 'nx:run-commands' && t?.options?.command === 'jest')
|
||||
);
|
||||
if (!jestTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [jestTargetName, jestTargetConfigInGraph] = jestTarget;
|
||||
// if root project doesn't have jest target, there's nothing to migrate
|
||||
const rootProjectConfig = readProjectConfiguration(
|
||||
tree,
|
||||
rootProject.name
|
||||
);
|
||||
|
||||
if (
|
||||
rootProjectConfig.targets['test']?.executor === 'nx:run-commands'
|
||||
? rootProjectConfig.targets['test']?.command !== 'jest'
|
||||
: rootProjectConfig.targets['test']?.options?.jestConfig !==
|
||||
rootJestPath
|
||||
) {
|
||||
// Jest target has already been updated
|
||||
return;
|
||||
}
|
||||
|
||||
const jestProjectConfig = `jest.config.${
|
||||
rootProjectConfig.projectType === 'application' ? 'app' : 'lib'
|
||||
}.${options.js ? 'js' : 'ts'}`;
|
||||
|
||||
tree.rename(rootJestPath, jestProjectConfig);
|
||||
|
||||
const nxJson = readNxJson(tree);
|
||||
const targetDefaults = readTargetDefaultsForTarget(
|
||||
jestTargetName,
|
||||
nxJson.targetDefaults,
|
||||
jestTargetConfigInGraph.executor
|
||||
);
|
||||
|
||||
const target: TargetConfiguration = (rootProjectConfig.targets[
|
||||
jestTargetName
|
||||
] ??=
|
||||
jestTargetConfigInGraph.executor === 'nx:run-commands'
|
||||
? { command: `jest --config ${jestProjectConfig}` }
|
||||
: {
|
||||
executor: jestTargetConfigInGraph.executor,
|
||||
options: {},
|
||||
});
|
||||
|
||||
if (target.executor === '@nx/jest:jest') {
|
||||
target.options.jestConfig = jestProjectConfig;
|
||||
}
|
||||
|
||||
if (targetDefaults?.cache === undefined) {
|
||||
target.cache = jestTargetConfigInGraph.cache;
|
||||
}
|
||||
if (targetDefaults?.inputs === undefined) {
|
||||
target.inputs = jestTargetConfigInGraph.inputs;
|
||||
}
|
||||
if (targetDefaults?.outputs === undefined) {
|
||||
target.outputs = jestTargetConfigInGraph.outputs;
|
||||
}
|
||||
if (targetDefaults?.dependsOn === undefined) {
|
||||
target.dependsOn = jestTargetConfigInGraph.dependsOn;
|
||||
}
|
||||
|
||||
updateProjectConfiguration(tree, rootProject.name, rootProjectConfig);
|
||||
// generate new global config as it was move to project config or is missing
|
||||
generateGlobalConfig(tree, options.js);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateGlobalConfig(tree: Tree, isJS: boolean) {
|
||||
const contents = isJS
|
||||
? stripIndents`
|
||||
const { getJestProjects } = require('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};`
|
||||
: stripIndents`
|
||||
import { getJestProjects } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};`;
|
||||
tree.write(`jest.config.${isJS ? 'js' : 'ts'}`, contents);
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
import { readJson, type Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { ensureDependencies } from './ensure-dependencies';
|
||||
|
||||
describe('ensureDependencies', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
describe('Deprecated: --babelJest', () => {
|
||||
it('should add babel dependencies', () => {
|
||||
ensureDependencies(tree, { babelJest: true });
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['babel-jest']).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('--compiler', () => {
|
||||
it('should support tsc compiler', () => {
|
||||
ensureDependencies(tree, { compiler: 'tsc' });
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
});
|
||||
|
||||
it('should support babel compiler', () => {
|
||||
ensureDependencies(tree, { compiler: 'babel' });
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['babel-jest']).toBeDefined();
|
||||
});
|
||||
|
||||
it('should support swc compiler', () => {
|
||||
ensureDependencies(tree, { compiler: 'swc' });
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['@swc/jest']).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should add dependencies --testEnvironment=node', () => {
|
||||
ensureDependencies(tree, { testEnvironment: 'node' });
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(packageJson.devDependencies['jest-environment-node']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should add dependencies --testEnvironment=none', () => {
|
||||
ensureDependencies(tree, { testEnvironment: 'none' });
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-node']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,48 @@
|
||||
import { addDependenciesToPackageJson, type Tree } from '@nx/devkit';
|
||||
import {
|
||||
babelJestVersion,
|
||||
jestTypesVersion,
|
||||
jestVersion,
|
||||
nxVersion,
|
||||
swcJestVersion,
|
||||
tsJestVersion,
|
||||
tslibVersion,
|
||||
tsNodeVersion,
|
||||
typesNodeVersion,
|
||||
} from '../../../utils/versions';
|
||||
import type { NormalizedJestProjectSchema } from '../schema';
|
||||
|
||||
export function ensureDependencies(
|
||||
tree: Tree,
|
||||
options: Partial<NormalizedJestProjectSchema>
|
||||
) {
|
||||
const dependencies: Record<string, string> = {
|
||||
tslib: tslibVersion,
|
||||
};
|
||||
const devDeps: Record<string, string> = {
|
||||
// because the default jest-preset uses ts-jest,
|
||||
// jest will throw an error if it's not installed
|
||||
// even if not using it in overriding transformers
|
||||
'ts-jest': tsJestVersion,
|
||||
};
|
||||
|
||||
if (options.testEnvironment !== 'none') {
|
||||
devDeps[`jest-environment-${options.testEnvironment}`] = jestVersion;
|
||||
}
|
||||
|
||||
if (!options.js) {
|
||||
devDeps['ts-node'] = tsNodeVersion;
|
||||
devDeps['@types/jest'] = jestTypesVersion;
|
||||
devDeps['@types/node'] = typesNodeVersion;
|
||||
}
|
||||
|
||||
if (options.compiler === 'babel' || options.babelJest) {
|
||||
devDeps['babel-jest'] = babelJestVersion;
|
||||
// in some cases @nx/js will not already be present i.e. node only projects
|
||||
devDeps['@nx/js'] = nxVersion;
|
||||
} else if (options.compiler === 'swc') {
|
||||
devDeps['@swc/jest'] = swcJestVersion;
|
||||
}
|
||||
|
||||
return addDependenciesToPackageJson(tree, dependencies, devDeps);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import { readJson, writeJson, type Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { updateVsCodeRecommendedExtensions } from './update-vscode-recommended-extensions';
|
||||
|
||||
describe('updateVsCodeRecommendedExtensions', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
it('should add the jest extension to the recommended property', () => {
|
||||
writeJson(tree, '.vscode/extensions.json', {
|
||||
recommendations: [
|
||||
'nrwl.angular-console',
|
||||
'angular.ng-template',
|
||||
'dbaeumer.vscode-eslint',
|
||||
'esbenp.prettier-vscode',
|
||||
],
|
||||
});
|
||||
|
||||
updateVsCodeRecommendedExtensions(tree);
|
||||
|
||||
const extensionsJson = readJson(tree, '.vscode/extensions.json');
|
||||
expect(extensionsJson).toMatchInlineSnapshot(`
|
||||
{
|
||||
"recommendations": [
|
||||
"nrwl.angular-console",
|
||||
"angular.ng-template",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"firsttris.vscode-jest-runner",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,16 @@
|
||||
import { updateJson, type Tree } from '@nx/devkit';
|
||||
|
||||
export function updateVsCodeRecommendedExtensions(host: Tree) {
|
||||
if (!host.exists('.vscode/extensions.json')) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateJson(host, '.vscode/extensions.json', (json) => {
|
||||
json.recommendations = json.recommendations || [];
|
||||
const extension = 'firsttris.vscode-jest-runner';
|
||||
if (!json.recommendations.includes(extension)) {
|
||||
json.recommendations.push(extension);
|
||||
}
|
||||
return json;
|
||||
});
|
||||
}
|
||||
@ -1,98 +1,17 @@
|
||||
let projectGraph: ProjectGraph;
|
||||
jest.mock('@nx/devkit', () => ({
|
||||
...jest.requireActual<any>('@nx/devkit'),
|
||||
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
|
||||
return projectGraph;
|
||||
}),
|
||||
}));
|
||||
|
||||
import {
|
||||
addProjectConfiguration as _addProjectConfiguration,
|
||||
NxJsonConfiguration,
|
||||
ProjectGraph,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
stripIndents,
|
||||
Tree,
|
||||
updateJson,
|
||||
writeJson,
|
||||
type NxJsonConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { jestInitGenerator } from './init';
|
||||
|
||||
function addProjectConfiguration(tree, name, project) {
|
||||
_addProjectConfiguration(tree, name, project);
|
||||
projectGraph.nodes[name] = {
|
||||
name: name,
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: project.root,
|
||||
targets: project.targets,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('jest', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
|
||||
projectGraph = {
|
||||
nodes: {},
|
||||
dependencies: {},
|
||||
externalNodes: {},
|
||||
};
|
||||
});
|
||||
|
||||
it('should generate files with --js flag', async () => {
|
||||
await jestInitGenerator(tree, { js: true });
|
||||
|
||||
expect(tree.exists('jest.config.js')).toBeTruthy();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.config.js', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.preset.js', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should generate files ', async () => {
|
||||
await jestInitGenerator(tree, {});
|
||||
|
||||
expect(tree.exists('jest.config.ts')).toBeTruthy();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.config.ts', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
stripIndents`${tree.read('jest.preset.js', 'utf-8')}`
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not override existing files', async () => {
|
||||
addProjectConfiguration(tree, 'my-project', {
|
||||
root: 'apps/my-app',
|
||||
name: 'my-app',
|
||||
sourceRoot: 'apps/my-app/src',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'apps/my-app/jest.config.ts',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const expected = stripIndents`
|
||||
import { getJestProjects } from '@nx/jest';
|
||||
export default {
|
||||
projects: getJestProjects(),
|
||||
extraThing: "Goes Here"
|
||||
}
|
||||
`;
|
||||
tree.write('jest.config.ts', expected);
|
||||
await jestInitGenerator(tree, {});
|
||||
expect(tree.read('jest.config.ts', 'utf-8')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should add target defaults for test', async () => {
|
||||
@ -135,11 +54,10 @@ export default {
|
||||
json.namedInputs.production = ['default', '^production'];
|
||||
return json;
|
||||
});
|
||||
|
||||
await jestInitGenerator(tree, {});
|
||||
|
||||
let nxJson: NxJsonConfiguration;
|
||||
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||
json.namedInputs ??= {};
|
||||
json.namedInputs.production = [
|
||||
'default',
|
||||
'^production',
|
||||
@ -157,226 +75,18 @@ export default {
|
||||
nxJson = json;
|
||||
return json;
|
||||
});
|
||||
tree.write('jest.preset.js', '');
|
||||
|
||||
await jestInitGenerator(tree, {});
|
||||
|
||||
expect(readJson<NxJsonConfiguration>(tree, 'nx.json')).toEqual(nxJson);
|
||||
});
|
||||
|
||||
it('should add dependencies', async () => {
|
||||
await jestInitGenerator(tree, {});
|
||||
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||
expect(packageJson.devDependencies['@nx/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(packageJson.devDependencies['jest-environment-jsdom']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-node']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should add dependencies --testEnvironment=node', async () => {
|
||||
await jestInitGenerator(tree, { testEnvironment: 'node' });
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||
expect(packageJson.devDependencies['@nx/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(packageJson.devDependencies['jest-environment-node']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should add dependencies --testEnvironment=none', async () => {
|
||||
await jestInitGenerator(tree, { testEnvironment: 'none' });
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||
expect(packageJson.devDependencies['@nx/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-node']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
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 () => {
|
||||
await jestInitGenerator(tree, { babelJest: true });
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['babel-jest']).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('--compiler', () => {
|
||||
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', async () => {
|
||||
await jestInitGenerator(tree, { compiler: 'babel' });
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies['babel-jest']).toBeDefined();
|
||||
});
|
||||
|
||||
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', 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', async () => {
|
||||
addProjectConfiguration(tree, 'my-project', {
|
||||
root: '.',
|
||||
name: 'my-project',
|
||||
projectType: 'application',
|
||||
sourceRoot: 'src',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'jest.config.ts',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
tree.write(
|
||||
'jest.config.ts',
|
||||
`
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'my-project',
|
||||
testEnvironment: 'node',
|
||||
preset: './jest.preset.js',
|
||||
};
|
||||
`
|
||||
);
|
||||
await jestInitGenerator(tree, { rootProject: false });
|
||||
expect(tree.exists('jest.config.app.ts')).toBeTruthy();
|
||||
expect(tree.read('jest.config.app.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'my-project',
|
||||
testEnvironment: 'node',
|
||||
preset: './jest.preset.js',
|
||||
};
|
||||
"
|
||||
`);
|
||||
expect(tree.read('jest.config.ts', 'utf-8'))
|
||||
.toEqual(`import { getJestProjects } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};`);
|
||||
expect(readProjectConfiguration(tree, 'my-project').targets.test)
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"executor": "@nx/jest:jest",
|
||||
"options": {
|
||||
"jestConfig": "jest.config.app.ts",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should work with --js', async () => {
|
||||
addProjectConfiguration(tree, 'my-project', {
|
||||
root: '.',
|
||||
name: 'my-project',
|
||||
sourceRoot: 'src',
|
||||
projectType: 'application',
|
||||
targets: {
|
||||
test: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'jest.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
tree.write(
|
||||
'jest.config.js',
|
||||
`
|
||||
/* eslint-disable */
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'my-project',
|
||||
testEnvironment: 'node',
|
||||
preset: './jest.preset.js',
|
||||
};
|
||||
`
|
||||
);
|
||||
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('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('adds jest extension', () => {
|
||||
beforeEach(async () => {
|
||||
writeJson(tree, '.vscode/extensions.json', {
|
||||
recommendations: [
|
||||
'nrwl.angular-console',
|
||||
'angular.ng-template',
|
||||
'dbaeumer.vscode-eslint',
|
||||
'esbenp.prettier-vscode',
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should add the jest extension to the recommended property', async () => {
|
||||
await jestInitGenerator(tree, {});
|
||||
const extensionsJson = readJson(tree, '.vscode/extensions.json');
|
||||
expect(extensionsJson).toMatchInlineSnapshot(`
|
||||
{
|
||||
"recommendations": [
|
||||
"nrwl.angular-console",
|
||||
"angular.ng-template",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"firsttris.vscode-jest-runner",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,60 +1,15 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
createProjectGraphAsync,
|
||||
GeneratorCallback,
|
||||
formatFiles,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
removeDependenciesFromPackageJson,
|
||||
runTasksInSerial,
|
||||
stripIndents,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateNxJson,
|
||||
updateProjectConfiguration,
|
||||
type GeneratorCallback,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
|
||||
import { findRootJestConfig } from '../../utils/config/find-root-jest-files';
|
||||
import {
|
||||
babelJestVersion,
|
||||
jestTypesVersion,
|
||||
jestVersion,
|
||||
nxVersion,
|
||||
swcJestVersion,
|
||||
tsJestVersion,
|
||||
tslibVersion,
|
||||
tsNodeVersion,
|
||||
typesNodeVersion,
|
||||
} from '../../utils/versions';
|
||||
import { JestInitSchema } from './schema';
|
||||
import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||
|
||||
interface NormalizedSchema extends ReturnType<typeof normalizeOptions> {}
|
||||
|
||||
const schemaDefaults = {
|
||||
compiler: 'tsc',
|
||||
js: false,
|
||||
rootProject: false,
|
||||
testEnvironment: 'jsdom',
|
||||
} as const;
|
||||
|
||||
function generateGlobalConfig(tree: Tree, isJS: boolean) {
|
||||
const contents = isJS
|
||||
? stripIndents`
|
||||
const { getJestProjects } = require('@nx/jest');
|
||||
|
||||
module.exports = {
|
||||
projects: getJestProjects()
|
||||
};`
|
||||
: stripIndents`
|
||||
import { getJestProjects } from '@nx/jest';
|
||||
|
||||
export default {
|
||||
projects: getJestProjects()
|
||||
};`;
|
||||
tree.write(`jest.config.${isJS ? 'js' : 'ts'}`, contents);
|
||||
}
|
||||
import { jestVersion, nxVersion } from '../../utils/versions';
|
||||
import type { JestInitSchema } from './schema';
|
||||
|
||||
function addPlugin(tree: Tree) {
|
||||
const nxJson = readNxJson(tree);
|
||||
@ -77,127 +32,6 @@ function addPlugin(tree: Tree) {
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
|
||||
async function createJestConfig(tree: Tree, options: NormalizedSchema) {
|
||||
if (!tree.exists('jest.preset.js')) {
|
||||
// preset is always js file.
|
||||
tree.write(
|
||||
`jest.preset.js`,
|
||||
`
|
||||
const nxPreset = require('@nx/jest/preset').default;
|
||||
|
||||
module.exports = { ...nxPreset }`
|
||||
);
|
||||
|
||||
const shouldAddPlugin = process.env.NX_PCV3 === 'true';
|
||||
if (shouldAddPlugin) {
|
||||
addPlugin(tree);
|
||||
}
|
||||
|
||||
updateProductionFileSet(tree);
|
||||
if (!shouldAddPlugin) {
|
||||
addJestTargetDefaults(tree, shouldAddPlugin);
|
||||
}
|
||||
}
|
||||
if (options.rootProject) {
|
||||
// we don't want any config to be made because the `configurationGenerator` will do it.
|
||||
// will copy the template config file
|
||||
return;
|
||||
}
|
||||
const rootJestPath = findRootJestConfig(tree);
|
||||
if (!rootJestPath) {
|
||||
// if there's not root jest config, we will create one and return
|
||||
// this can happen when:
|
||||
// - root jest config was renamed => in which case there is migration needed
|
||||
// - root project didn't have jest setup => again, no migration is needed
|
||||
generateGlobalConfig(tree, options.js);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tree.exists(rootJestPath)) {
|
||||
// moving from root project config to monorepo-style config
|
||||
const { nodes: projects } = await createProjectGraphAsync();
|
||||
const projectConfigurations = Object.values(projects);
|
||||
const rootProject = projectConfigurations.find(
|
||||
(projectNode) => projectNode.data?.root === '.'
|
||||
);
|
||||
// root project might have been removed,
|
||||
// if it's missing there's nothing to migrate
|
||||
if (rootProject) {
|
||||
const jestTarget = Object.entries(rootProject.data?.targets ?? {}).find(
|
||||
([_, t]) =>
|
||||
((t?.executor === '@nx/jest:jest' ||
|
||||
t?.executor === '@nrwl/jest:jest') &&
|
||||
t?.options?.jestConfig === rootJestPath) ||
|
||||
(t?.executor === 'nx:run-commands' && t?.options?.command === 'jest')
|
||||
);
|
||||
if (!jestTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [jestTargetName, jestTargetConfigInGraph] = jestTarget;
|
||||
// if root project doesn't have jest target, there's nothing to migrate
|
||||
const rootProjectConfig = readProjectConfiguration(
|
||||
tree,
|
||||
rootProject.name
|
||||
);
|
||||
|
||||
if (
|
||||
rootProjectConfig.targets['test']?.executor === 'nx:run-commands'
|
||||
? rootProjectConfig.targets['test']?.command !== 'jest'
|
||||
: rootProjectConfig.targets['test']?.options?.jestConfig !==
|
||||
rootJestPath
|
||||
) {
|
||||
// Jest target has already been updated
|
||||
return;
|
||||
}
|
||||
|
||||
const jestProjectConfig = `jest.config.${
|
||||
rootProjectConfig.projectType === 'application' ? 'app' : 'lib'
|
||||
}.${options.js ? 'js' : 'ts'}`;
|
||||
|
||||
tree.rename(rootJestPath, jestProjectConfig);
|
||||
|
||||
const nxJson = readNxJson(tree);
|
||||
const targetDefaults = readTargetDefaultsForTarget(
|
||||
jestTargetName,
|
||||
nxJson.targetDefaults,
|
||||
jestTargetConfigInGraph.executor
|
||||
);
|
||||
|
||||
const target: TargetConfiguration = (rootProjectConfig.targets[
|
||||
jestTargetName
|
||||
] ??=
|
||||
jestTargetConfigInGraph.executor === 'nx:run-commands'
|
||||
? { command: `jest --config ${jestProjectConfig}` }
|
||||
: {
|
||||
executor: jestTargetConfigInGraph.executor,
|
||||
options: {},
|
||||
});
|
||||
|
||||
if (target.executor === '@nx/jest:jest') {
|
||||
target.options.jestConfig = jestProjectConfig;
|
||||
}
|
||||
|
||||
if (targetDefaults?.cache === undefined) {
|
||||
target.cache = jestTargetConfigInGraph.cache;
|
||||
}
|
||||
if (targetDefaults?.inputs === undefined) {
|
||||
target.inputs = jestTargetConfigInGraph.inputs;
|
||||
}
|
||||
if (targetDefaults?.outputs === undefined) {
|
||||
target.outputs = jestTargetConfigInGraph.outputs;
|
||||
}
|
||||
if (targetDefaults?.dependsOn === undefined) {
|
||||
target.dependsOn = jestTargetConfigInGraph.dependsOn;
|
||||
}
|
||||
|
||||
updateProjectConfiguration(tree, rootProject.name, rootProjectConfig);
|
||||
// generate new global config as it was move to project config or is missing
|
||||
generateGlobalConfig(tree, options.js);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateProductionFileSet(tree: Tree) {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
@ -223,23 +57,21 @@ function updateProductionFileSet(tree: Tree) {
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
|
||||
function addJestTargetDefaults(tree: Tree, hasPlugin: boolean) {
|
||||
function addJestTargetDefaults(tree: Tree) {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
nxJson.targetDefaults ??= {};
|
||||
nxJson.targetDefaults['@nx/jest:jest'] ??= {};
|
||||
|
||||
if (!hasPlugin) {
|
||||
const productionFileSet = nxJson.namedInputs?.production;
|
||||
const productionFileSet = nxJson.namedInputs?.production;
|
||||
|
||||
nxJson.targetDefaults['@nx/jest:jest'].cache ??= true;
|
||||
// Test targets depend on all their project's sources + production sources of dependencies
|
||||
nxJson.targetDefaults['@nx/jest:jest'].inputs ??= [
|
||||
'default',
|
||||
productionFileSet ? '^production' : '^default',
|
||||
'{workspaceRoot}/jest.preset.js',
|
||||
];
|
||||
}
|
||||
nxJson.targetDefaults['@nx/jest:jest'].cache ??= true;
|
||||
// Test targets depend on all their project's sources + production sources of dependencies
|
||||
nxJson.targetDefaults['@nx/jest:jest'].inputs ??= [
|
||||
'default',
|
||||
productionFileSet ? '^production' : '^default',
|
||||
'{workspaceRoot}/jest.preset.js',
|
||||
];
|
||||
|
||||
nxJson.targetDefaults['@nx/jest:jest'].options ??= {
|
||||
passWithNoTests: true,
|
||||
@ -254,87 +86,41 @@ function addJestTargetDefaults(tree: Tree, hasPlugin: boolean) {
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
|
||||
function updateDependencies(tree: Tree, options: NormalizedSchema) {
|
||||
const dependencies = {
|
||||
tslib: tslibVersion,
|
||||
};
|
||||
const devDeps = {
|
||||
'@nx/jest': nxVersion,
|
||||
jest: jestVersion,
|
||||
|
||||
// because the default jest-preset uses ts-jest,
|
||||
// jest will throw an error if it's not installed
|
||||
// even if not using it in overriding transformers
|
||||
'ts-jest': tsJestVersion,
|
||||
};
|
||||
|
||||
if (options.testEnvironment !== 'none') {
|
||||
devDeps[`jest-environment-${options.testEnvironment}`] = jestVersion;
|
||||
}
|
||||
|
||||
if (!options.js) {
|
||||
devDeps['ts-node'] = tsNodeVersion;
|
||||
devDeps['@types/jest'] = jestTypesVersion;
|
||||
devDeps['@types/node'] = typesNodeVersion;
|
||||
}
|
||||
|
||||
if (options.compiler === 'babel' || options.babelJest) {
|
||||
devDeps['babel-jest'] = babelJestVersion;
|
||||
// in some cases @nx/js will not already be present i.e. node only projects
|
||||
devDeps['@nx/js'] = nxVersion;
|
||||
} else if (options.compiler === 'swc') {
|
||||
devDeps['@swc/jest'] = swcJestVersion;
|
||||
}
|
||||
|
||||
return addDependenciesToPackageJson(tree, dependencies, devDeps);
|
||||
}
|
||||
|
||||
function updateExtensions(host: Tree) {
|
||||
if (!host.exists('.vscode/extensions.json')) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateJson(host, '.vscode/extensions.json', (json) => {
|
||||
json.recommendations = json.recommendations || [];
|
||||
const extension = 'firsttris.vscode-jest-runner';
|
||||
if (!json.recommendations.includes(extension)) {
|
||||
json.recommendations.push(extension);
|
||||
function updateDependencies(tree: Tree) {
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@nx/jest': nxVersion,
|
||||
jest: jestVersion,
|
||||
}
|
||||
return json;
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
export async function jestInitGenerator(
|
||||
tree: Tree,
|
||||
schema: JestInitSchema
|
||||
options: JestInitSchema
|
||||
): Promise<GeneratorCallback> {
|
||||
const options = normalizeOptions(schema);
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
tasks.push(
|
||||
await jsInitGenerator(tree, {
|
||||
...schema,
|
||||
skipFormat: true,
|
||||
})
|
||||
);
|
||||
|
||||
await createJestConfig(tree, options);
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
removeDependenciesFromPackageJson(tree, ['@nx/jest'], []);
|
||||
const installTask = updateDependencies(tree, options);
|
||||
tasks.push(installTask);
|
||||
if (!tree.exists('jest.preset.js')) {
|
||||
updateProductionFileSet(tree);
|
||||
if (process.env.NX_PCV3 === 'true') {
|
||||
addPlugin(tree);
|
||||
} else {
|
||||
addJestTargetDefaults(tree);
|
||||
}
|
||||
}
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/jest'], []));
|
||||
tasks.push(updateDependencies(tree));
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
updateExtensions(tree);
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function normalizeOptions(options: JestInitSchema) {
|
||||
return {
|
||||
...schemaDefaults,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
export default jestInitGenerator;
|
||||
|
||||
@ -1,11 +1,4 @@
|
||||
export interface JestInitSchema {
|
||||
compiler?: 'tsc' | 'babel' | 'swc';
|
||||
js?: boolean;
|
||||
skipFormat?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
testEnvironment?: 'node' | 'jsdom' | 'none';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
babelJest?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
@ -6,36 +6,17 @@
|
||||
"description": "Add Jest Configuration to a workspace.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"babelJest": {
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"alias": "babel-jest",
|
||||
"description": "Use `babel-jest` instead of `ts-jest`.",
|
||||
"default": false
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipPackageJson": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"testEnvironment": {
|
||||
"type": "string",
|
||||
"enum": ["jsdom", "node", "none"],
|
||||
"description": "The test environment for jest. This controls which jest-environment-* package is installed",
|
||||
"default": "jsdom",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Use JavaScript instead of TypeScript for config files"
|
||||
},
|
||||
"rootProject": {
|
||||
"description": "initialize Jest for an application at the root of the workspace",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"hidden": true,
|
||||
"x-priority": "internal"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@ -5,6 +5,7 @@ import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
||||
import { initGenerator } from '../init/init';
|
||||
import {
|
||||
createFiles,
|
||||
ensureDependencies,
|
||||
normalizeOptions,
|
||||
toNodeApplicationGeneratorOptions,
|
||||
updateTsConfig,
|
||||
@ -26,23 +27,30 @@ export async function applicationGeneratorInternal(
|
||||
rawOptions: ApplicationGeneratorOptions
|
||||
): Promise<GeneratorCallback> {
|
||||
const options = await normalizeOptions(tree, rawOptions);
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const initTask = await initGenerator(tree, {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(initTask);
|
||||
const nodeApplicationTask = await nodeApplicationGenerator(
|
||||
tree,
|
||||
toNodeApplicationGeneratorOptions(options)
|
||||
);
|
||||
tasks.push(nodeApplicationTask);
|
||||
createFiles(tree, options);
|
||||
updateTsConfig(tree, options);
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(tree));
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return runTasksInSerial(initTask, nodeApplicationTask);
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default applicationGenerator;
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||
import { addDependenciesToPackageJson } from '@nx/devkit';
|
||||
import {
|
||||
nestJsVersion,
|
||||
reflectMetadataVersion,
|
||||
rxjsVersion,
|
||||
tsLibVersion,
|
||||
} from '../../../utils/versions';
|
||||
|
||||
export function ensureDependencies(tree: Tree): GeneratorCallback {
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{
|
||||
'@nestjs/common': nestJsVersion,
|
||||
'@nestjs/core': nestJsVersion,
|
||||
'@nestjs/platform-express': nestJsVersion,
|
||||
'reflect-metadata': reflectMetadataVersion,
|
||||
rxjs: rxjsVersion,
|
||||
tslib: tsLibVersion,
|
||||
},
|
||||
{
|
||||
'@nestjs/testing': nestJsVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './create-files';
|
||||
export * from './ensure-dependencies';
|
||||
export * from './normalize-options';
|
||||
export * from './update-tsconfig';
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import * as devkit from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import {
|
||||
nestJsSchematicsVersion,
|
||||
nestJsVersion,
|
||||
nxVersion,
|
||||
} from '../../utils/versions';
|
||||
import { nestJsSchematicsVersion, nxVersion } from '../../utils/versions';
|
||||
import { initGenerator } from './init';
|
||||
|
||||
describe('init generator', () => {
|
||||
@ -20,34 +16,12 @@ describe('init generator', () => {
|
||||
await initGenerator(tree, {});
|
||||
|
||||
const packageJson = devkit.readJson(tree, 'package.json');
|
||||
expect(packageJson.dependencies['@nestjs/common']).toBe(nestJsVersion);
|
||||
expect(packageJson.dependencies['@nestjs/core']).toBe(nestJsVersion);
|
||||
expect(packageJson.dependencies['@nestjs/platform-express']).toBe(
|
||||
nestJsVersion
|
||||
);
|
||||
expect(packageJson.dependencies['reflect-metadata']).toBeDefined();
|
||||
expect(packageJson.dependencies['rxjs']).toBeDefined();
|
||||
expect(packageJson.dependencies['tslib']).toBeDefined();
|
||||
expect(packageJson.dependencies['@nx/nest']).toBeUndefined();
|
||||
expect(packageJson.devDependencies['@nestjs/schematics']).toBe(
|
||||
nestJsSchematicsVersion
|
||||
);
|
||||
expect(packageJson.devDependencies['@nestjs/testing']).toBe(nestJsVersion);
|
||||
expect(packageJson.devDependencies['@nx/nest']).toBe(nxVersion);
|
||||
});
|
||||
|
||||
it('should add jest config when unitTestRunner is jest', async () => {
|
||||
await initGenerator(tree, { unitTestRunner: 'jest' });
|
||||
|
||||
expect(tree.exists('jest.config.ts')).toBe(true);
|
||||
});
|
||||
|
||||
it('should not add jest config when unitTestRunner is none', async () => {
|
||||
await initGenerator(tree, { unitTestRunner: 'none' });
|
||||
|
||||
expect(tree.exists('jest.config.ts')).toBe(false);
|
||||
});
|
||||
|
||||
describe('--skipFormat', () => {
|
||||
it('should format files by default', async () => {
|
||||
jest.spyOn(devkit, 'formatFiles');
|
||||
|
||||
@ -1,33 +1,23 @@
|
||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
||||
import { initGenerator as nodeInitGenerator } from '@nx/node';
|
||||
import { formatFiles } from '@nx/devkit';
|
||||
|
||||
import { addDependencies, normalizeOptions } from './lib';
|
||||
import { addDependencies } from './lib';
|
||||
import type { InitGeneratorOptions } from './schema';
|
||||
|
||||
export async function initGenerator(
|
||||
tree: Tree,
|
||||
rawOptions: InitGeneratorOptions
|
||||
options: InitGeneratorOptions
|
||||
): Promise<GeneratorCallback> {
|
||||
const options = normalizeOptions(rawOptions);
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
const nodeInitTask = await nodeInitGenerator(tree, {
|
||||
...options,
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(nodeInitTask);
|
||||
|
||||
let installPackagesTask: GeneratorCallback = () => {};
|
||||
if (!options.skipPackageJson) {
|
||||
const installPackagesTask = addDependencies(tree);
|
||||
tasks.push(installPackagesTask);
|
||||
installPackagesTask = addDependencies(tree);
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
return installPackagesTask;
|
||||
}
|
||||
|
||||
export default initGenerator;
|
||||
|
||||
@ -1,28 +1,13 @@
|
||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||
import { addDependenciesToPackageJson } from '@nx/devkit';
|
||||
import {
|
||||
nestJsSchematicsVersion,
|
||||
nestJsVersion,
|
||||
nxVersion,
|
||||
reflectMetadataVersion,
|
||||
rxjsVersion,
|
||||
tsLibVersion,
|
||||
} from '../../../utils/versions';
|
||||
import { nestJsSchematicsVersion, nxVersion } from '../../../utils/versions';
|
||||
|
||||
export function addDependencies(tree: Tree): GeneratorCallback {
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{
|
||||
'@nestjs/common': nestJsVersion,
|
||||
'@nestjs/core': nestJsVersion,
|
||||
'@nestjs/platform-express': nestJsVersion,
|
||||
'reflect-metadata': reflectMetadataVersion,
|
||||
rxjs: rxjsVersion,
|
||||
tslib: tsLibVersion,
|
||||
},
|
||||
{},
|
||||
{
|
||||
'@nestjs/schematics': nestJsSchematicsVersion,
|
||||
'@nestjs/testing': nestJsVersion,
|
||||
'@nx/nest': nxVersion,
|
||||
}
|
||||
);
|
||||
|
||||
@ -1,2 +1 @@
|
||||
export * from './add-dependencies';
|
||||
export * from './normalize-options';
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import type { InitGeneratorOptions } from '../schema';
|
||||
|
||||
export function normalizeOptions(
|
||||
options: InitGeneratorOptions
|
||||
): InitGeneratorOptions {
|
||||
return {
|
||||
...options,
|
||||
unitTestRunner: options.unitTestRunner ?? 'jest',
|
||||
};
|
||||
}
|
||||
@ -2,6 +2,5 @@ import { UnitTestRunner } from '../utils';
|
||||
|
||||
export interface InitGeneratorOptions {
|
||||
skipFormat?: boolean;
|
||||
unitTestRunner?: UnitTestRunner;
|
||||
skipPackageJson?: boolean;
|
||||
}
|
||||
|
||||
@ -6,12 +6,6 @@
|
||||
"cli": "nx",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"unitTestRunner": {
|
||||
"description": "Adds the specified unit test runner.",
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"default": "jest"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user