cleanup(misc): clean up init generators (#21088)
This commit is contained in:
parent
dcef077032
commit
047dc22aed
@ -8,28 +8,7 @@
|
|||||||
"title": "Init Angular Plugin",
|
"title": "Init Angular Plugin",
|
||||||
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||||
"type": "object",
|
"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": {
|
"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": {
|
"skipInstall": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Skip installing after adding `@nx/workspace`.",
|
"description": "Skip installing after adding `@nx/workspace`.",
|
||||||
@ -42,38 +21,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"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": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|||||||
@ -9,6 +9,12 @@
|
|||||||
"description": "Add Cypress Configuration to the workspace.",
|
"description": "Add Cypress Configuration to the workspace.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|||||||
@ -18,12 +18,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
|
||||||
"framework": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "App framework to test",
|
|
||||||
"enum": ["react-native", "expo"],
|
|
||||||
"default": "react-native"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,16 +9,15 @@
|
|||||||
"description": "Init Webpack Plugin.",
|
"description": "Init Webpack Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"compiler": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["babel", "swc", "tsc"],
|
|
||||||
"description": "The compiler to initialize for.",
|
|
||||||
"default": "babel"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -8,33 +8,16 @@
|
|||||||
"description": "Add Nx Expo Schematics.",
|
"description": "Add Nx Expo Schematics.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
|
||||||
"description": "Adds the specified e2e test runner",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["detox", "none"],
|
|
||||||
"default": "detox"
|
|
||||||
},
|
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`."
|
"description": "Do not add dependencies to `package.json`."
|
||||||
},
|
|
||||||
"js": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"description": "Use JavaScript instead of TypeScript"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,16 +9,15 @@
|
|||||||
"description": "Init Express Plugin.",
|
"description": "Init Express Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Do not add dependencies to `package.json`."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,36 +9,17 @@
|
|||||||
"description": "Add Jest Configuration to a workspace.",
|
"description": "Add Jest Configuration to a workspace.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"babelJest": {
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"alias": "babel-jest",
|
"default": false,
|
||||||
"description": "Use `babel-jest` instead of `ts-jest`.",
|
"x-priority": "internal"
|
||||||
"default": false
|
|
||||||
},
|
},
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"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": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,12 +9,6 @@
|
|||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -9,40 +9,16 @@
|
|||||||
"description": "Init Next Plugin.",
|
"description": "Init Next Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"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": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"js": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"description": "Use JavaScript instead of TypeScript"
|
|
||||||
},
|
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
|
||||||
"rootProject": {
|
|
||||||
"description": "Create an application at the root of the workspace.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"hidden": true,
|
|
||||||
"x-priority": "internal"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,21 +9,15 @@
|
|||||||
"description": "Init Node Plugin.",
|
"description": "Init Node Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"js": {
|
"skipPackageJson": {
|
||||||
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false
|
||||||
"description": "Use JavaScript instead of TypeScript"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -14,20 +14,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"rootProject": {
|
|
||||||
"description": "Create a project at the root of the workspace",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"description": "The file extension to be used for style files.",
|
|
||||||
"type": "string",
|
|
||||||
"default": "css"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -63,6 +63,11 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
|
"skipInstall": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Skip running `playwright install`. This is to ensure that playwright browsers are installed.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["project"],
|
"required": ["project"],
|
||||||
|
|||||||
@ -19,11 +19,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
|
||||||
"skipInstall": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Skip running `playwright install`. This is to ensure that playwright browsers are installed.",
|
|
||||||
"default": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,29 +9,12 @@
|
|||||||
"description": "Add Nx React native schematics.",
|
"description": "Add Nx React native schematics.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"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": {
|
"skipPackageJson": {
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -9,18 +9,6 @@
|
|||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"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": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -30,17 +18,6 @@
|
|||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"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": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,16 +9,15 @@
|
|||||||
"description": "Init Webpack Plugin.",
|
"description": "Init Webpack Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"compiler": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["babel", "swc", "tsc"],
|
|
||||||
"description": "The compiler to initialize for.",
|
|
||||||
"default": "babel"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -8,41 +8,14 @@
|
|||||||
"$id": "init-storybook-plugin",
|
"$id": "init-storybook-plugin",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"uiFramework": {
|
"skipFormat": {
|
||||||
"type": "string",
|
"description": "Skip formatting files.",
|
||||||
"description": "Storybook UI Framework to use.",
|
"type": "boolean",
|
||||||
"enum": [
|
"default": false
|
||||||
"@storybook/angular",
|
},
|
||||||
"@storybook/html-webpack5",
|
"skipPackageJson": {
|
||||||
"@storybook/nextjs",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"@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": {
|
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Generate JavaScript story files rather than TypeScript story files.",
|
|
||||||
"default": false
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,32 +8,17 @@
|
|||||||
"$id": "init-vite-plugin",
|
"$id": "init-vite-plugin",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"uiFramework": {
|
"skipFormat": {
|
||||||
"type": "string",
|
"description": "Skip formatting files.",
|
||||||
"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": {
|
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Add dependencies needed to build libraries.",
|
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"testEnvironment": {
|
"skipPackageJson": {
|
||||||
"description": "The vitest environment to use. See https://vitest.dev/config/#environment.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "string",
|
"type": "boolean",
|
||||||
"enum": ["node", "jsdom", "happy-dom", "edge-runtime"],
|
"default": false
|
||||||
"default": "jsdom"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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": []
|
"presets": []
|
||||||
},
|
},
|
||||||
"description": "Initialize Vite in the workspace.",
|
"description": "Initialize Vite in the workspace.",
|
||||||
|
|||||||
@ -14,26 +14,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"js": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"description": "Use JavaScript instead of TypeScript",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"rootProject": {
|
|
||||||
"description": "Create a project at the root of the workspace",
|
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"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": [],
|
"required": [],
|
||||||
|
|||||||
@ -9,25 +9,6 @@
|
|||||||
"description": "Init Web Plugin.",
|
"description": "Init Web Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"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": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -9,22 +9,15 @@
|
|||||||
"description": "Initialize the Webpack Plugin.",
|
"description": "Initialize the Webpack Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"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": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -11,7 +11,10 @@ import {
|
|||||||
describe('Storybook executors for Angular', () => {
|
describe('Storybook executors for Angular', () => {
|
||||||
const angularStorybookLib = uniq('test-ui-ng-lib');
|
const angularStorybookLib = uniq('test-ui-ng-lib');
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
newProject();
|
newProject({
|
||||||
|
packages: ['@nx/angular'],
|
||||||
|
unsetProjectNameAndRootFormat: false,
|
||||||
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`g @nx/angular:library ${angularStorybookLib} --project-name-and-root-format=as-provided --no-interactive`
|
`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 { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
import * as enquirer from 'enquirer';
|
import * as enquirer from 'enquirer';
|
||||||
|
import { backwardCompatibleVersions } from '../../utils/backward-compatible-versions';
|
||||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||||
import {
|
import {
|
||||||
|
angularDevkitVersion,
|
||||||
|
angularVersion,
|
||||||
autoprefixerVersion,
|
autoprefixerVersion,
|
||||||
postcssVersion,
|
postcssVersion,
|
||||||
tailwindVersion,
|
tailwindVersion,
|
||||||
@ -48,6 +51,36 @@ describe('app', () => {
|
|||||||
appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
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', () => {
|
describe('not nested', () => {
|
||||||
it('should create project configs', async () => {
|
it('should create project configs', async () => {
|
||||||
// ACT
|
// 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 () => {
|
it('should import "ApplicationConfig" from "@angular/platform-browser"', async () => {
|
||||||
await generateApp(appTree, 'my-app', { standalone: true });
|
await generateApp(appTree, 'my-app', { standalone: true });
|
||||||
|
|
||||||
|
|||||||
@ -7,9 +7,11 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { angularInitGenerator } from '../init/init';
|
import { angularInitGenerator } from '../init/init';
|
||||||
import { setupSsr } from '../setup-ssr/setup-ssr';
|
import { setupSsr } from '../setup-ssr/setup-ssr';
|
||||||
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
|
||||||
|
import { ensureAngularDependencies } from '../utils/ensure-angular-dependencies';
|
||||||
import {
|
import {
|
||||||
addE2e,
|
addE2e,
|
||||||
addLinting,
|
addLinting,
|
||||||
@ -20,6 +22,7 @@ import {
|
|||||||
enableStrictTypeChecking,
|
enableStrictTypeChecking,
|
||||||
normalizeOptions,
|
normalizeOptions,
|
||||||
setApplicationStrictDefault,
|
setApplicationStrictDefault,
|
||||||
|
setGeneratorDefaults,
|
||||||
updateEditorTsConfig,
|
updateEditorTsConfig,
|
||||||
} from './lib';
|
} from './lib';
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
@ -41,10 +44,17 @@ export async function applicationGeneratorInternal(
|
|||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
const rootOffset = offsetFromRoot(options.appProjectRoot);
|
const rootOffset = offsetFromRoot(options.appProjectRoot);
|
||||||
|
|
||||||
|
await jsInitGenerator(tree, {
|
||||||
|
...options,
|
||||||
|
tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
||||||
|
js: false,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
await angularInitGenerator(tree, {
|
await angularInitGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
|
ensureAngularDependencies(tree);
|
||||||
|
|
||||||
createProject(tree, options);
|
createProject(tree, options);
|
||||||
|
|
||||||
@ -62,6 +72,7 @@ export async function applicationGeneratorInternal(
|
|||||||
await addUnitTestRunner(tree, options);
|
await addUnitTestRunner(tree, options);
|
||||||
await addE2e(tree, options);
|
await addE2e(tree, options);
|
||||||
updateEditorTsConfig(tree, options);
|
updateEditorTsConfig(tree, options);
|
||||||
|
setGeneratorDefaults(tree, options);
|
||||||
|
|
||||||
if (options.rootProject) {
|
if (options.rootProject) {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
|
|||||||
@ -1,37 +1,15 @@
|
|||||||
import { Tree, joinPathFragments } from '@nx/devkit';
|
import { Tree } from '@nx/devkit';
|
||||||
import { configurationGenerator } from '@nx/jest';
|
|
||||||
import { UnitTestRunner } from '../../../utils/test-runners';
|
import { UnitTestRunner } from '../../../utils/test-runners';
|
||||||
|
import { addJest } from '../../utils/add-jest';
|
||||||
import type { NormalizedSchema } from './normalized-schema';
|
import type { NormalizedSchema } from './normalized-schema';
|
||||||
|
|
||||||
export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) {
|
export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) {
|
||||||
if (options.unitTestRunner === UnitTestRunner.Jest) {
|
if (options.unitTestRunner === UnitTestRunner.Jest) {
|
||||||
await configurationGenerator(host, {
|
await addJest(host, {
|
||||||
...options,
|
name: options.name,
|
||||||
project: options.name,
|
projectRoot: options.appProjectRoot,
|
||||||
setupFile: 'angular',
|
|
||||||
supportTsx: false,
|
|
||||||
skipSerializers: false,
|
|
||||||
skipPackageJson: options.skipPackageJson,
|
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 './normalize-options';
|
||||||
export * from './normalized-schema';
|
export * from './normalized-schema';
|
||||||
export * from './set-app-strict-default';
|
export * from './set-app-strict-default';
|
||||||
|
export * from './set-generator-defaults';
|
||||||
export * from './update-editor-tsconfig';
|
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,
|
exportComponentInEntryPoint,
|
||||||
findModuleFromOptions,
|
findModuleFromOptions,
|
||||||
normalizeOptions,
|
normalizeOptions,
|
||||||
|
setGeneratorDefaults,
|
||||||
} from './lib';
|
} from './lib';
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
|
|
||||||
@ -92,6 +93,7 @@ export async function componentGeneratorInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
exportComponentInEntryPoint(tree, options);
|
exportComponentInEntryPoint(tree, options);
|
||||||
|
setGeneratorDefaults(tree, options);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './component';
|
export * from './component';
|
||||||
export * from './module';
|
export * from './module';
|
||||||
export * from './normalize-options';
|
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', () => ({
|
import { readNxJson, updateJson, updateNxJson, type Tree } from '@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 { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
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';
|
import init from './init';
|
||||||
|
|
||||||
describe('init', () => {
|
describe('init', () => {
|
||||||
@ -30,262 +9,11 @@ describe('init', () => {
|
|||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
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', () => {
|
describe('angular cache dir', () => {
|
||||||
it('should add .angular to .gitignore', async () => {
|
it('should add .angular to .gitignore', async () => {
|
||||||
tree.write('.gitignore', '');
|
tree.write('.gitignore', '');
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('.gitignore', 'utf-8')).toContain('.angular');
|
expect(tree.read('.gitignore', 'utf-8')).toContain('.angular');
|
||||||
});
|
});
|
||||||
@ -301,12 +29,7 @@ bar
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const angularEntries = tree
|
const angularEntries = tree
|
||||||
.read('.gitignore', 'utf-8')
|
.read('.gitignore', 'utf-8')
|
||||||
@ -317,12 +40,7 @@ bar
|
|||||||
it('should add .angular to .prettierignore', async () => {
|
it('should add .angular to .prettierignore', async () => {
|
||||||
tree.write('.prettierignore', '');
|
tree.write('.prettierignore', '');
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('.prettierignore', 'utf-8')).toContain('.angular');
|
expect(tree.read('.prettierignore', 'utf-8')).toContain('.angular');
|
||||||
});
|
});
|
||||||
@ -338,12 +56,7 @@ bar
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const angularEntries = tree
|
const angularEntries = tree
|
||||||
.read('.prettierignore', 'utf-8')
|
.read('.prettierignore', 'utf-8')
|
||||||
@ -353,18 +66,14 @@ bar
|
|||||||
|
|
||||||
it('should add configured angular cache dir to .gitignore and .prettierignore', async () => {
|
it('should add configured angular cache dir to .gitignore and .prettierignore', async () => {
|
||||||
tree.write('.gitignore', '');
|
tree.write('.gitignore', '');
|
||||||
|
tree.write('.prettierignore', '');
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
updateNxJson(tree, {
|
updateNxJson(tree, {
|
||||||
...nxJson,
|
...nxJson,
|
||||||
cli: { cache: { path: 'node_modules/.cache/angular' } },
|
cli: { cache: { path: 'node_modules/.cache/angular' } },
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('.gitignore', 'utf-8')).toContain(
|
expect(tree.read('.gitignore', 'utf-8')).toContain(
|
||||||
'node_modules/.cache/angular'
|
'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', () => {
|
describe('angular cache dir', () => {
|
||||||
it('should add .angular to .gitignore', async () => {
|
it('should add .angular to .gitignore', async () => {
|
||||||
tree.write('.gitignore', '');
|
tree.write('.gitignore', '');
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('.gitignore', 'utf-8')).toContain('.angular');
|
expect(tree.read('.gitignore', 'utf-8')).toContain('.angular');
|
||||||
});
|
});
|
||||||
@ -686,12 +117,7 @@ bar
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const angularEntries = tree
|
const angularEntries = tree
|
||||||
.read('.gitignore', 'utf-8')
|
.read('.gitignore', 'utf-8')
|
||||||
@ -702,12 +128,7 @@ bar
|
|||||||
it('should add .angular to .prettierignore', async () => {
|
it('should add .angular to .prettierignore', async () => {
|
||||||
tree.write('.prettierignore', '');
|
tree.write('.prettierignore', '');
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('.prettierignore', 'utf-8')).toContain('.angular');
|
expect(tree.read('.prettierignore', 'utf-8')).toContain('.angular');
|
||||||
});
|
});
|
||||||
@ -723,12 +144,7 @@ bar
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const angularEntries = tree
|
const angularEntries = tree
|
||||||
.read('.prettierignore', 'utf-8')
|
.read('.prettierignore', 'utf-8')
|
||||||
@ -738,18 +154,14 @@ bar
|
|||||||
|
|
||||||
it('should add configured angular cache dir to .gitignore and .prettierignore', async () => {
|
it('should add configured angular cache dir to .gitignore and .prettierignore', async () => {
|
||||||
tree.write('.gitignore', '');
|
tree.write('.gitignore', '');
|
||||||
|
tree.write('.prettierignore', '');
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
updateNxJson(tree, {
|
updateNxJson(tree, {
|
||||||
...nxJson,
|
...nxJson,
|
||||||
cli: { cache: { path: 'node_modules/.cache/angular' } },
|
cli: { cache: { path: 'node_modules/.cache/angular' } },
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
await init(tree, {
|
await init(tree, { skipFormat: true });
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
e2eTestRunner: E2eTestRunner.Cypress,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('.gitignore', 'utf-8')).toContain(
|
expect(tree.read('.gitignore', 'utf-8')).toContain(
|
||||||
'node_modules/.cache/angular'
|
'node_modules/.cache/angular'
|
||||||
|
|||||||
@ -2,222 +2,59 @@ import {
|
|||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
GeneratorCallback,
|
|
||||||
logger,
|
logger,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
runTasksInSerial,
|
type GeneratorCallback,
|
||||||
Tree,
|
type Tree,
|
||||||
updateNxJson,
|
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { jestInitGenerator } from '@nx/jest';
|
import { getInstalledPackageVersion, versions } from '../utils/version-utils';
|
||||||
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 { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { nxVersion } from '../../utils/versions';
|
|
||||||
|
|
||||||
export async function angularInitGenerator(
|
export async function angularInitGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
rawOptions: Schema
|
options: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): 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);
|
ignoreAngularCacheDirectory(tree);
|
||||||
|
const installTask = installAngularDevkitCoreIfMissing(tree, options);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(...tasks);
|
return installTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(options: Schema): Required<Schema> {
|
function installAngularDevkitCoreIfMissing(
|
||||||
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(
|
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: Schema
|
options: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): GeneratorCallback {
|
||||||
switch (options.e2eTestRunner) {
|
const packageVersion = getInstalledPackageVersion(
|
||||||
case E2eTestRunner.Cypress:
|
tree,
|
||||||
const { cypressInitGenerator } = ensurePackage<
|
'@angular-devkit/core'
|
||||||
typeof import('@nx/cypress')
|
);
|
||||||
>('@nx/cypress', nxVersion);
|
|
||||||
return cypressInitGenerator(tree, {
|
if (!packageVersion) {
|
||||||
skipPackageJson: options.skipPackageJson,
|
const pkgVersions = versions(tree);
|
||||||
});
|
const devkitVersion =
|
||||||
case E2eTestRunner.Playwright:
|
getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ??
|
||||||
const { initGenerator: playwrightInitGenerator } = ensurePackage<
|
pkgVersions.angularDevkitVersion;
|
||||||
typeof import('@nx/playwright')
|
|
||||||
>('@nx/playwright', nxVersion);
|
try {
|
||||||
return playwrightInitGenerator(tree, {
|
ensurePackage('@angular-devkit/core', devkitVersion);
|
||||||
skipFormat: true,
|
} catch {
|
||||||
skipPackageJson: options.skipPackageJson,
|
// @schematics/angular cannot be required so this fails but this will still allow wrapping the schematic later on
|
||||||
});
|
}
|
||||||
default:
|
|
||||||
return () => {};
|
if (!options.skipPackageJson) {
|
||||||
|
return addDependenciesToPackageJson(
|
||||||
|
tree,
|
||||||
|
{},
|
||||||
|
{ ['@angular-devkit/core']: devkitVersion }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function ignoreAngularCacheDirectory(tree: Tree): void {
|
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 {
|
export interface Schema {
|
||||||
unitTestRunner?: UnitTestRunner;
|
|
||||||
e2eTestRunner?: E2eTestRunner;
|
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipInstall?: boolean;
|
skipInstall?: boolean;
|
||||||
style?: Styles;
|
|
||||||
linter?: Linter;
|
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
rootProject?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,28 +5,7 @@
|
|||||||
"title": "Init Angular Plugin",
|
"title": "Init Angular Plugin",
|
||||||
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||||
"type": "object",
|
"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": {
|
"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": {
|
"skipInstall": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Skip installing after adding `@nx/workspace`.",
|
"description": "Skip installing after adding `@nx/workspace`.",
|
||||||
@ -39,41 +18,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"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": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"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 { createApp } from '../../utils/nx-devkit/testing';
|
||||||
import { UnitTestRunner } from '../../utils/test-runners';
|
import { UnitTestRunner } from '../../utils/test-runners';
|
||||||
import {
|
import {
|
||||||
|
angularDevkitVersion,
|
||||||
|
angularVersion,
|
||||||
autoprefixerVersion,
|
autoprefixerVersion,
|
||||||
postcssVersion,
|
postcssVersion,
|
||||||
tailwindVersion,
|
tailwindVersion,
|
||||||
@ -62,6 +64,36 @@ describe('lib', () => {
|
|||||||
).resolves.not.toThrow();
|
).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', () => {
|
describe('not nested', () => {
|
||||||
it('should update ng-package.json', async () => {
|
it('should update ng-package.json', async () => {
|
||||||
// ACT
|
// ACT
|
||||||
|
|||||||
@ -5,11 +5,9 @@ import {
|
|||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { configurationGenerator } from '@nx/jest';
|
|
||||||
import { Linter } from '@nx/eslint';
|
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 init from '../../generators/init/init';
|
||||||
import { E2eTestRunner } from '../../utils/test-runners';
|
|
||||||
import addLintingGenerator from '../add-linting/add-linting';
|
import addLintingGenerator from '../add-linting/add-linting';
|
||||||
import setupTailwindGenerator from '../setup-tailwind/setup-tailwind';
|
import setupTailwindGenerator from '../setup-tailwind/setup-tailwind';
|
||||||
import {
|
import {
|
||||||
@ -30,6 +28,9 @@ import { updateTsConfig } from './lib/update-tsconfig';
|
|||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { createFiles } from './lib/create-files';
|
import { createFiles } from './lib/create-files';
|
||||||
import { addProject } from './lib/add-project';
|
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(
|
export async function libraryGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
@ -69,11 +70,9 @@ export async function libraryGeneratorInternal(
|
|||||||
|
|
||||||
const pkgVersions = versions(tree);
|
const pkgVersions = versions(tree);
|
||||||
|
|
||||||
await init(tree, {
|
await jsInitGenerator(tree, { ...options, js: false, skipFormat: true });
|
||||||
...libraryOptions,
|
await init(tree, { ...libraryOptions, skipFormat: true });
|
||||||
skipFormat: true,
|
ensureAngularDependencies(tree);
|
||||||
e2eTestRunner: E2eTestRunner.None,
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = addProject(tree, libraryOptions);
|
const project = addProject(tree, libraryOptions);
|
||||||
|
|
||||||
@ -81,6 +80,7 @@ export async function libraryGeneratorInternal(
|
|||||||
updateTsConfig(tree, libraryOptions);
|
updateTsConfig(tree, libraryOptions);
|
||||||
await addUnitTestRunner(tree, libraryOptions);
|
await addUnitTestRunner(tree, libraryOptions);
|
||||||
updateNpmScopeIfBuildableOrPublishable(tree, libraryOptions);
|
updateNpmScopeIfBuildableOrPublishable(tree, libraryOptions);
|
||||||
|
setGeneratorDefaults(tree, options);
|
||||||
|
|
||||||
if (!libraryOptions.standalone) {
|
if (!libraryOptions.standalone) {
|
||||||
addModule(tree, libraryOptions);
|
addModule(tree, libraryOptions);
|
||||||
@ -127,33 +127,12 @@ async function addUnitTestRunner(
|
|||||||
options: NormalizedSchema['libraryOptions']
|
options: NormalizedSchema['libraryOptions']
|
||||||
) {
|
) {
|
||||||
if (options.unitTestRunner === 'jest') {
|
if (options.unitTestRunner === 'jest') {
|
||||||
await configurationGenerator(host, {
|
await addJest(host, {
|
||||||
project: options.name,
|
name: options.name,
|
||||||
setupFile: 'angular',
|
projectRoot: options.projectRoot,
|
||||||
supportTsx: false,
|
|
||||||
skipSerializers: false,
|
|
||||||
skipFormat: true,
|
|
||||||
skipPackageJson: options.skipPackageJson,
|
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 type { Tree } from '@nx/devkit';
|
||||||
import { angularInitGenerator } from '../init/init';
|
|
||||||
import { migrateFromAngularCli } from './migrate-from-angular-cli';
|
import { migrateFromAngularCli } from './migrate-from-angular-cli';
|
||||||
import type { GeneratorOptions } from './schema';
|
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) {
|
export async function ngAddGenerator(tree: Tree, options: GeneratorOptions) {
|
||||||
if (getWorkspaceType(tree) === 'angular') {
|
return await migrateFromAngularCli(tree, options);
|
||||||
return await migrateFromAngularCli(tree, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await angularInitGenerator(tree, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ngAddGenerator;
|
export default ngAddGenerator;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
writeJson,
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Linter, lintInitGenerator } from '@nx/eslint';
|
import { Linter, lintInitGenerator } from '@nx/eslint';
|
||||||
|
import { setupRootEsLint } from '@nx/eslint/src/generators/lint-project/setup-root-eslint';
|
||||||
import {
|
import {
|
||||||
getRootTsConfigPathInTree,
|
getRootTsConfigPathInTree,
|
||||||
initGenerator as jsInitGenerator,
|
initGenerator as jsInitGenerator,
|
||||||
@ -189,25 +190,16 @@ export function updateRootEsLintConfig(
|
|||||||
existingEsLintConfig: any | undefined,
|
existingEsLintConfig: any | undefined,
|
||||||
unitTestRunner?: string
|
unitTestRunner?: string
|
||||||
): void {
|
): void {
|
||||||
if (tree.exists('.eslintrc.json')) {
|
lintInitGenerator(tree, {});
|
||||||
/**
|
|
||||||
* 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 });
|
|
||||||
|
|
||||||
if (!existingEsLintConfig) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
existingEsLintConfig.ignorePatterns = ['**/*'];
|
existingEsLintConfig.ignorePatterns = ['**/*'];
|
||||||
if (!(existingEsLintConfig.plugins ?? []).includes('@nrwl/nx')) {
|
if (!(existingEsLintConfig.plugins ?? []).includes('@nx')) {
|
||||||
existingEsLintConfig.plugins = Array.from(
|
existingEsLintConfig.plugins = Array.from(
|
||||||
new Set([...(existingEsLintConfig.plugins ?? []), '@nx'])
|
new Set([...(existingEsLintConfig.plugins ?? []), '@nx'])
|
||||||
);
|
);
|
||||||
|
|||||||
@ -34,9 +34,7 @@ export async function storybookConfigurationGenerator(
|
|||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return storybookGeneratorInstallTask;
|
||||||
storybookGeneratorInstallTask();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default storybookConfigurationGenerator;
|
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,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
import {
|
||||||
|
getRelativePathToRootTsConfig,
|
||||||
|
initGenerator as jsInitGenerator,
|
||||||
|
} from '@nx/js';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { addLinterToCyProject } from '../../utils/add-linter';
|
import { addLinterToCyProject } from '../../utils/add-linter';
|
||||||
import { addDefaultE2EConfig } from '../../utils/config';
|
import { addDefaultE2EConfig } from '../../utils/config';
|
||||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||||
import { viteVersion } from '../../utils/versions';
|
import { typesNodeVersion, viteVersion } from '../../utils/versions';
|
||||||
import cypressInitGenerator from '../init/init';
|
import cypressInitGenerator from '../init/init';
|
||||||
import { addBaseCypressSetup } from '../base-setup/base-setup';
|
import { addBaseCypressSetup } from '../base-setup/base-setup';
|
||||||
|
|
||||||
@ -56,7 +59,8 @@ export async function configurationGenerator(
|
|||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
if (!installedCypressVersion()) {
|
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 projectGraph = await createProjectGraphAsync();
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
@ -65,9 +69,7 @@ export async function configurationGenerator(
|
|||||||
? p === '@nx/cypress/plugin'
|
? p === '@nx/cypress/plugin'
|
||||||
: p.plugin === '@nx/cypress/plugin'
|
: p.plugin === '@nx/cypress/plugin'
|
||||||
);
|
);
|
||||||
if (opts.bundler === 'vite') {
|
|
||||||
tasks.push(addDependenciesToPackageJson(tree, {}, { vite: viteVersion }));
|
|
||||||
}
|
|
||||||
await addFiles(tree, opts, projectGraph, hasPlugin);
|
await addFiles(tree, opts, projectGraph, hasPlugin);
|
||||||
if (!hasPlugin) {
|
if (!hasPlugin) {
|
||||||
addTarget(tree, opts);
|
addTarget(tree, opts);
|
||||||
@ -79,6 +81,10 @@ export async function configurationGenerator(
|
|||||||
});
|
});
|
||||||
tasks.push(linterTask);
|
tasks.push(linterTask);
|
||||||
|
|
||||||
|
if (!opts.skipPackageJson) {
|
||||||
|
tasks.push(ensureDependencies(tree, opts));
|
||||||
|
}
|
||||||
|
|
||||||
if (!opts.skipFormat) {
|
if (!opts.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
@ -86,6 +92,18 @@ export async function configurationGenerator(
|
|||||||
return runTasksInSerial(...tasks);
|
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) {
|
function normalizeOptions(tree: Tree, options: CypressE2EConfigSchema) {
|
||||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||||
if (projectConfig?.targets?.e2e) {
|
if (projectConfig?.targets?.e2e) {
|
||||||
|
|||||||
@ -18,13 +18,20 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { checkAndCleanWithSemver } from '@nx/devkit/src/utils/semver';
|
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 { Linter } from '@nx/eslint';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { major } from 'semver';
|
import { major } from 'semver';
|
||||||
import { addLinterToCyProject } from '../../utils/add-linter';
|
import { addLinterToCyProject } from '../../utils/add-linter';
|
||||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
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 { cypressInitGenerator } from '../init/init';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
@ -186,18 +193,9 @@ export async function cypressProjectGeneratorInternal(
|
|||||||
// if there is an installed cypress version, then we don't call
|
// if there is an installed cypress version, then we don't call
|
||||||
// init since we want to keep the existing version that is installed
|
// init since we want to keep the existing version that is installed
|
||||||
if (!cypressVersion) {
|
if (!cypressVersion) {
|
||||||
tasks.push(await cypressInitGenerator(host, options));
|
tasks.push(await jsInitGenerator(host, { ...options, skipFormat: true }));
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.bundler === 'vite') {
|
|
||||||
tasks.push(
|
tasks.push(
|
||||||
addDependenciesToPackageJson(
|
await cypressInitGenerator(host, { ...options, skipFormat: true })
|
||||||
host,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
vite: viteVersion,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,12 +209,29 @@ export async function cypressProjectGeneratorInternal(
|
|||||||
overwriteExisting: true,
|
overwriteExisting: true,
|
||||||
});
|
});
|
||||||
tasks.push(installTask);
|
tasks.push(installTask);
|
||||||
|
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(ensureDependencies(host, options));
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
return runTasksInSerial(...tasks);
|
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(
|
async function normalizeOptions(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
options: Schema
|
options: Schema
|
||||||
|
|||||||
@ -26,7 +26,6 @@ describe('init', () => {
|
|||||||
|
|
||||||
expect(packageJson.devDependencies.cypress).toBeDefined();
|
expect(packageJson.devDependencies.cypress).toBeDefined();
|
||||||
expect(packageJson.devDependencies['@nx/cypress']).toBeDefined();
|
expect(packageJson.devDependencies['@nx/cypress']).toBeDefined();
|
||||||
expect(packageJson.devDependencies['@types/node']).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies[existing]).toBeDefined();
|
expect(packageJson.devDependencies[existing]).toBeDefined();
|
||||||
expect(packageJson.dependencies['@nx/cypress']).toBeUndefined();
|
expect(packageJson.dependencies['@nx/cypress']).toBeUndefined();
|
||||||
expect(packageJson.dependencies[existing]).toBeDefined();
|
expect(packageJson.dependencies[existing]).toBeDefined();
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
|
formatFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
@ -7,13 +8,8 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import { cypressVersion, nxVersion } from '../../utils/versions';
|
||||||
cypressVersion,
|
|
||||||
nxVersion,
|
|
||||||
typesNodeVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { initGenerator } from '@nx/js';
|
|
||||||
import { CypressPluginOptions } from '../../plugins/plugin';
|
import { CypressPluginOptions } from '../../plugins/plugin';
|
||||||
|
|
||||||
function setupE2ETargetDefaults(tree: Tree) {
|
function setupE2ETargetDefaults(tree: Tree) {
|
||||||
@ -38,17 +34,21 @@ function setupE2ETargetDefaults(tree: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateDependencies(tree: Tree) {
|
function updateDependencies(tree: Tree) {
|
||||||
removeDependenciesFromPackageJson(tree, ['@nx/cypress'], []);
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/cypress'], []));
|
||||||
|
|
||||||
return addDependenciesToPackageJson(
|
tasks.push(
|
||||||
tree,
|
addDependenciesToPackageJson(
|
||||||
{},
|
tree,
|
||||||
{
|
{},
|
||||||
['@nx/cypress']: nxVersion,
|
{
|
||||||
cypress: cypressVersion,
|
['@nx/cypress']: nxVersion,
|
||||||
'@types/node': typesNodeVersion,
|
cypress: cypressVersion,
|
||||||
}
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPlugin(tree: Tree) {
|
function addPlugin(tree: Tree) {
|
||||||
@ -93,30 +93,24 @@ function updateProductionFileset(tree: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function cypressInitGenerator(tree: Tree, options: Schema) {
|
export async function cypressInitGenerator(tree: Tree, options: Schema) {
|
||||||
const addPlugins = process.env.NX_PCV3 === 'true';
|
|
||||||
updateProductionFileset(tree);
|
updateProductionFileset(tree);
|
||||||
if (!addPlugins) {
|
|
||||||
|
if (process.env.NX_PCV3 === 'true') {
|
||||||
|
addPlugin(tree);
|
||||||
|
} else {
|
||||||
setupE2ETargetDefaults(tree);
|
setupE2ETargetDefaults(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
let installTask: GeneratorCallback = () => {};
|
||||||
|
|
||||||
tasks.push(
|
|
||||||
await initGenerator(tree, {
|
|
||||||
...options,
|
|
||||||
skipFormat: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (addPlugins) {
|
|
||||||
addPlugin(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
tasks.push(updateDependencies(tree));
|
installTask = updateDependencies(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(...tasks);
|
if (!options.skipFormat) {
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
return installTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default cypressInitGenerator;
|
export default cypressInitGenerator;
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
skipPackageJson?: boolean;
|
|
||||||
|
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
|
skipPackageJson?: boolean;
|
||||||
addPlugins?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,12 @@
|
|||||||
"description": "Add Cypress Configuration to the workspace.",
|
"description": "Add Cypress Configuration to the workspace.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { addProject } from './lib/add-project';
|
|||||||
import { createFiles } from './lib/create-files';
|
import { createFiles } from './lib/create-files';
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
import { ensureDependencies } from './lib/ensure-dependencies';
|
||||||
|
|
||||||
export async function detoxApplicationGenerator(host: Tree, schema: Schema) {
|
export async function detoxApplicationGenerator(host: Tree, schema: Schema) {
|
||||||
return await detoxApplicationGeneratorInternal(host, {
|
return await detoxApplicationGeneratorInternal(host, {
|
||||||
@ -30,12 +31,13 @@ export async function detoxApplicationGeneratorInternal(
|
|||||||
addGitIgnoreEntry(host, options);
|
addGitIgnoreEntry(host, options);
|
||||||
|
|
||||||
const lintingTask = await addLinting(host, options);
|
const lintingTask = await addLinting(host, options);
|
||||||
|
const depsTask = ensureDependencies(host, options);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(initTask, lintingTask);
|
return runTasksInSerial(initTask, lintingTask, depsTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default detoxApplicationGenerator;
|
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, {});
|
await detoxInitGenerator(tree, {});
|
||||||
const packageJson = readJson(tree, 'package.json');
|
const packageJson = readJson(tree, 'package.json');
|
||||||
expect(packageJson.devDependencies['@nx/detox']).toBeDefined();
|
expect(packageJson.devDependencies['@nx/detox']).toBeDefined();
|
||||||
expect(packageJson.devDependencies['@types/node']).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies['detox']).toBeDefined();
|
expect(packageJson.devDependencies['detox']).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,16 +8,9 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
} from '@nx/devkit';
|
} 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 { DetoxPluginOptions } from '../../plugins/plugin';
|
||||||
|
import { detoxVersion, nxVersion } from '../../utils/versions';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
|
||||||
export async function detoxInitGenerator(host: Tree, schema: Schema) {
|
export async function detoxInitGenerator(host: Tree, schema: Schema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -45,12 +38,6 @@ export function updateDependencies(host: Tree, schema: Schema) {
|
|||||||
{
|
{
|
||||||
'@nx/detox': nxVersion,
|
'@nx/detox': nxVersion,
|
||||||
detox: detoxVersion,
|
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 {
|
export interface Schema {
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipPackageJson?: boolean; //default is false
|
skipPackageJson?: boolean; //default is false
|
||||||
framework?: 'react-native' | 'expo';
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,12 +15,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
|
||||||
"framework": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "App framework to test",
|
|
||||||
"enum": ["react-native", "expo"],
|
|
||||||
"default": "react-native"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"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 { Schema } from './schema';
|
||||||
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
|
|
||||||
export async function esbuildInitGenerator(tree: Tree, schema: Schema) {
|
export async function esbuildInitGenerator(tree: Tree, schema: Schema) {
|
||||||
const task = addDependenciesToPackageJson(
|
let installTask: GeneratorCallback = () => {};
|
||||||
tree,
|
if (!schema.skipPackageJson) {
|
||||||
{},
|
installTask = addDependenciesToPackageJson(
|
||||||
{
|
tree,
|
||||||
'@nx/esbuild': nxVersion,
|
{},
|
||||||
esbuild: esbuildVersion,
|
{
|
||||||
}
|
'@nx/esbuild': nxVersion,
|
||||||
);
|
esbuild: esbuildVersion,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return task;
|
return installTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default esbuildInitGenerator;
|
export default esbuildInitGenerator;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
compiler?: 'babel' | 'swc' | 'tsc';
|
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
|
skipPackageJson?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,16 +6,15 @@
|
|||||||
"description": "Init Webpack Plugin.",
|
"description": "Init Webpack Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"compiler": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["babel", "swc", "tsc"],
|
|
||||||
"description": "The compiler to initialize for.",
|
|
||||||
"default": "babel"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"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;
|
process.env.NX_PCV3 = envV3;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate the global eslint config', async () => {
|
it('should add the root eslint config to the lint targetDefaults for lint', () => {
|
||||||
await lintInitGenerator(tree, {
|
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,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(readJson(tree, 'nx.json').targetDefaults['@nx/eslint:lint']).toEqual(
|
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', '{}');
|
tree.write('.eslintrc.js', '{}');
|
||||||
|
|
||||||
await lintInitGenerator(tree, {
|
lintInitGenerator(tree, {});
|
||||||
linter: Linter.EsLint,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.exists('.eslintrc.json')).toBe(false);
|
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) => {
|
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||||
json.namedInputs ??= {};
|
json.namedInputs ??= {};
|
||||||
json.namedInputs.production = ['default'];
|
json.namedInputs.production = ['default'];
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
await lintInitGenerator(tree, {});
|
lintInitGenerator(tree, {});
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
readJson<NxJsonConfiguration>(tree, 'nx.json').targetDefaults[
|
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';
|
process.env.NX_PCV3 = 'true';
|
||||||
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||||
json.namedInputs ??= {};
|
json.namedInputs ??= {};
|
||||||
@ -88,7 +72,7 @@ describe('@nx/eslint:init', () => {
|
|||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
await lintInitGenerator(tree, {});
|
lintInitGenerator(tree, {});
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
readJson<NxJsonConfiguration>(tree, 'nx.json').targetDefaults[
|
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) => {
|
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||||
json.namedInputs ??= {};
|
json.namedInputs ??= {};
|
||||||
json.namedInputs.production = ['default'];
|
json.namedInputs.production = ['default'];
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
await lintInitGenerator(tree, {});
|
lintInitGenerator(tree, {});
|
||||||
expect(
|
expect(
|
||||||
readJson<NxJsonConfiguration>(tree, 'nx.json').plugins
|
readJson<NxJsonConfiguration>(tree, 'nx.json').plugins
|
||||||
).not.toBeDefined();
|
).not.toBeDefined();
|
||||||
|
|
||||||
process.env.NX_PCV3 = 'true';
|
process.env.NX_PCV3 = 'true';
|
||||||
await lintInitGenerator(tree, {});
|
lintInitGenerator(tree, {});
|
||||||
expect(readJson<NxJsonConfiguration>(tree, 'nx.json').plugins)
|
expect(readJson<NxJsonConfiguration>(tree, 'nx.json').plugins)
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
|
|||||||
@ -3,28 +3,16 @@ import {
|
|||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
updateJson,
|
runTasksInSerial,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
writeJson,
|
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import { eslintVersion, nxVersion } from '../../utils/versions';
|
||||||
eslintConfigPrettierVersion,
|
|
||||||
eslintVersion,
|
|
||||||
nxVersion,
|
|
||||||
typescriptESLintVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
|
|
||||||
import { Linter } from '../utils/linter';
|
|
||||||
import { findEslintFile } from '../utils/eslint-file';
|
import { findEslintFile } from '../utils/eslint-file';
|
||||||
import { getGlobalEsLintConfiguration } from './global-eslint-config';
|
|
||||||
import { EslintPluginOptions } from '../../plugins/plugin';
|
import { EslintPluginOptions } from '../../plugins/plugin';
|
||||||
import { hasEslintPlugin } from '../utils/plugin';
|
import { hasEslintPlugin } from '../utils/plugin';
|
||||||
|
|
||||||
export interface LinterInitOptions {
|
export interface LinterInitOptions {
|
||||||
linter?: Linter;
|
|
||||||
unitTestRunner?: string;
|
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
rootProject?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProductionFileset(tree: Tree) {
|
function updateProductionFileset(tree: Tree) {
|
||||||
@ -78,22 +66,6 @@ function addPlugin(tree: Tree) {
|
|||||||
updateNxJson(tree, nxJson);
|
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 {
|
function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
||||||
const addPlugins = process.env.NX_PCV3 === 'true';
|
const addPlugins = process.env.NX_PCV3 === 'true';
|
||||||
const hasPlugin = hasEslintPlugin(tree);
|
const hasPlugin = hasEslintPlugin(tree);
|
||||||
@ -108,17 +80,6 @@ function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
|||||||
return () => {};
|
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);
|
updateProductionFileset(tree);
|
||||||
|
|
||||||
if (addPlugins) {
|
if (addPlugins) {
|
||||||
@ -127,22 +88,22 @@ function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback {
|
|||||||
addTargetDefaults(tree);
|
addTargetDefaults(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVSCodeExtensions(tree);
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
return !options.skipPackageJson
|
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/eslint'], []));
|
||||||
? addDependenciesToPackageJson(
|
tasks.push(
|
||||||
|
addDependenciesToPackageJson(
|
||||||
tree,
|
tree,
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
'@nx/eslint': nxVersion,
|
'@nx/eslint': nxVersion,
|
||||||
'@nx/eslint-plugin': nxVersion,
|
|
||||||
'@typescript-eslint/parser': typescriptESLintVersion,
|
|
||||||
'@typescript-eslint/eslint-plugin': typescriptESLintVersion,
|
|
||||||
eslint: eslintVersion,
|
eslint: eslintVersion,
|
||||||
'eslint-config-prettier': eslintConfigPrettierVersion,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
: () => {};
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lintInitGenerator(tree: Tree, options: LinterInitOptions) {
|
export function lintInitGenerator(tree: Tree, options: LinterInitOptions) {
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
import { Linter } from '../utils/linter';
|
import { Linter } from '../utils/linter';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { lintProjectGenerator } from './lint-project';
|
import { lintProjectGenerator } from './lint-project';
|
||||||
import { eslintVersion } from '../../utils/versions';
|
|
||||||
|
|
||||||
describe('@nx/eslint:lint-project', () => {
|
describe('@nx/eslint:lint-project', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
@ -272,4 +271,55 @@ describe('@nx/eslint:lint-project', () => {
|
|||||||
const eslintConfig = readJson(tree, 'libs/test-lib/.eslintrc.json');
|
const eslintConfig = readJson(tree, 'libs/test-lib/.eslintrc.json');
|
||||||
expect(eslintConfig.extends).toBeUndefined();
|
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 {
|
import type {
|
||||||
|
GeneratorCallback,
|
||||||
NxJsonConfiguration,
|
NxJsonConfiguration,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
@ -8,6 +9,7 @@ import {
|
|||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
|
runTasksInSerial,
|
||||||
updateJson,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
writeJson,
|
writeJson,
|
||||||
@ -35,6 +37,7 @@ import {
|
|||||||
baseEsLintFlatConfigFile,
|
baseEsLintFlatConfigFile,
|
||||||
} from '../../utils/config-file';
|
} from '../../utils/config-file';
|
||||||
import { hasEslintPlugin } from '../utils/plugin';
|
import { hasEslintPlugin } from '../utils/plugin';
|
||||||
|
import { setupRootEsLint } from './setup-root-eslint';
|
||||||
|
|
||||||
interface LintProjectOptions {
|
interface LintProjectOptions {
|
||||||
project: string;
|
project: string;
|
||||||
@ -52,12 +55,17 @@ export async function lintProjectGenerator(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: LintProjectOptions
|
options: LintProjectOptions
|
||||||
) {
|
) {
|
||||||
const installTask = lintInitGenerator(tree, {
|
const tasks: GeneratorCallback[] = [];
|
||||||
linter: options.linter,
|
const initTask = lintInitGenerator(tree, {
|
||||||
|
skipPackageJson: options.skipPackageJson,
|
||||||
|
});
|
||||||
|
tasks.push(initTask);
|
||||||
|
const rootEsLintTask = setupRootEsLint(tree, {
|
||||||
unitTestRunner: options.unitTestRunner,
|
unitTestRunner: options.unitTestRunner,
|
||||||
skipPackageJson: options.skipPackageJson,
|
skipPackageJson: options.skipPackageJson,
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
});
|
});
|
||||||
|
tasks.push(rootEsLintTask);
|
||||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||||
|
|
||||||
let lintFilePatterns = options.eslintFilePatterns;
|
let lintFilePatterns = options.eslintFilePatterns;
|
||||||
@ -154,7 +162,7 @@ export async function lintProjectGenerator(
|
|||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return installTask;
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEsLintConfiguration(
|
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,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
|
|
||||||
import { runSymlink } from '../../utils/symlink-task';
|
import { runSymlink } from '../../utils/symlink-task';
|
||||||
import { addLinting } from '../../utils/add-linting';
|
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 { addEasScripts } from './lib/add-eas-scripts';
|
||||||
import { addDetox } from './lib/add-detox';
|
import { addDetox } from './lib/add-detox';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
|
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
|
||||||
|
|
||||||
export async function expoApplicationGenerator(
|
export async function expoApplicationGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -34,7 +37,18 @@ export async function expoApplicationGeneratorInternal(
|
|||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const options = await normalizeOptions(host, schema);
|
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 });
|
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
||||||
|
tasks.push(initTask);
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(ensureDependencies(host));
|
||||||
|
}
|
||||||
|
initRootBabelConfig(host);
|
||||||
|
|
||||||
createApplicationFiles(host, options);
|
createApplicationFiles(host, options);
|
||||||
addProject(host, options);
|
addProject(host, options);
|
||||||
@ -46,6 +60,7 @@ export async function expoApplicationGeneratorInternal(
|
|||||||
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
tasks.push(lintTask);
|
||||||
|
|
||||||
const jestTask = await addJest(
|
const jestTask = await addJest(
|
||||||
host,
|
host,
|
||||||
@ -55,15 +70,18 @@ export async function expoApplicationGeneratorInternal(
|
|||||||
options.js,
|
options.js,
|
||||||
options.skipPackageJson
|
options.skipPackageJson
|
||||||
);
|
);
|
||||||
|
tasks.push(jestTask);
|
||||||
const detoxTask = await addDetox(host, options);
|
const detoxTask = await addDetox(host, options);
|
||||||
|
tasks.push(detoxTask);
|
||||||
const symlinkTask = runSymlink(host.root, options.appProjectRoot);
|
const symlinkTask = runSymlink(host.root, options.appProjectRoot);
|
||||||
|
tasks.push(symlinkTask);
|
||||||
addEasScripts(host);
|
addEasScripts(host);
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(initTask, lintTask, jestTask, detoxTask, symlinkTask);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default expoApplicationGenerator;
|
export default expoApplicationGenerator;
|
||||||
|
|||||||
@ -11,12 +11,11 @@ describe('init', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add react native dependencies', async () => {
|
it('should add react native dependencies', async () => {
|
||||||
await expoInitGenerator(tree, { e2eTestRunner: 'none' });
|
await expoInitGenerator(tree, {});
|
||||||
const packageJson = readJson(tree, 'package.json');
|
const packageJson = readJson(tree, 'package.json');
|
||||||
expect(packageJson.dependencies['react']).toBeDefined();
|
expect(packageJson.dependencies['react']).toBeDefined();
|
||||||
expect(packageJson.dependencies['expo']).toBeDefined();
|
expect(packageJson.dependencies['expo']).toBeDefined();
|
||||||
expect(packageJson.dependencies['react-native']).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 () => {
|
it('should add .gitignore entries for React native files and directories', async () => {
|
||||||
@ -26,7 +25,7 @@ describe('init', () => {
|
|||||||
/node_modules
|
/node_modules
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
await expoInitGenerator(tree, { e2eTestRunner: 'none' });
|
await expoInitGenerator(tree, {});
|
||||||
|
|
||||||
const content = tree.read('/.gitignore').toString();
|
const content = tree.read('/.gitignore').toString();
|
||||||
|
|
||||||
|
|||||||
@ -8,73 +8,32 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Schema } from './schema';
|
import { ExpoPluginOptions } from '../../../plugins/plugin';
|
||||||
import {
|
import {
|
||||||
babelPresetExpoVersion,
|
|
||||||
easCliVersion,
|
easCliVersion,
|
||||||
expoCliVersion,
|
expoCliVersion,
|
||||||
expoMetroConfigVersion,
|
|
||||||
expoSplashScreenVersion,
|
|
||||||
expoStatusBarVersion,
|
|
||||||
expoVersion,
|
expoVersion,
|
||||||
jestExpoVersion,
|
|
||||||
metroVersion,
|
|
||||||
nxVersion,
|
nxVersion,
|
||||||
reactDomVersion,
|
reactDomVersion,
|
||||||
reactNativeSvgTransformerVersion,
|
|
||||||
reactNativeSvgVersion,
|
|
||||||
reactNativeVersion,
|
reactNativeVersion,
|
||||||
reactNativeWebVersion,
|
|
||||||
reactTestRendererVersion,
|
|
||||||
reactVersion,
|
reactVersion,
|
||||||
testingLibraryJestNativeVersion,
|
|
||||||
testingLibraryReactNativeVersion,
|
|
||||||
typesReactVersion,
|
|
||||||
} from '../../utils/versions';
|
} 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 { 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) {
|
export async function expoInitGenerator(host: Tree, schema: Schema) {
|
||||||
addGitIgnoreEntry(host);
|
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') {
|
if (process.env.NX_PCV3 === 'true') {
|
||||||
addPlugin(host);
|
addPlugin(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
if (!schema.skipPackageJson) {
|
||||||
|
tasks.push(moveDependency(host));
|
||||||
|
tasks.push(updateDependencies(host));
|
||||||
|
}
|
||||||
|
|
||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
@ -90,25 +49,11 @@ export function updateDependencies(host: Tree) {
|
|||||||
'react-dom': reactDomVersion,
|
'react-dom': reactDomVersion,
|
||||||
'react-native': reactNativeVersion,
|
'react-native': reactNativeVersion,
|
||||||
expo: expoVersion,
|
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,
|
'@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,
|
'@expo/cli': expoCliVersion,
|
||||||
'eas-cli': easCliVersion,
|
'eas-cli': easCliVersion,
|
||||||
'babel-preset-expo': babelPresetExpoVersion,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
unitTestRunner?: 'jest' | 'none';
|
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
e2eTestRunner?: 'detox' | 'none';
|
|
||||||
skipPackageJson?: boolean; // default is false
|
skipPackageJson?: boolean; // default is false
|
||||||
js?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,33 +5,16 @@
|
|||||||
"description": "Add Nx Expo Schematics.",
|
"description": "Add Nx Expo Schematics.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
|
||||||
"description": "Adds the specified e2e test runner",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["detox", "none"],
|
|
||||||
"default": "detox"
|
|
||||||
},
|
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`."
|
"description": "Do not add dependencies to `package.json`."
|
||||||
},
|
|
||||||
"js": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"description": "Use JavaScript instead of TypeScript"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -7,14 +7,19 @@ import {
|
|||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
|
ProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
TargetConfiguration,
|
|
||||||
toJS,
|
toJS,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
|
updateProjectConfiguration,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import { addTsConfigPath, getRelativePathToRootTsConfig } from '@nx/js';
|
import {
|
||||||
|
addTsConfigPath,
|
||||||
|
getRelativePathToRootTsConfig,
|
||||||
|
initGenerator as jsInitGenerator,
|
||||||
|
} from '@nx/js';
|
||||||
import init from '../init/init';
|
import init from '../init/init';
|
||||||
import { addLinting } from '../../utils/add-linting';
|
import { addLinting } from '../../utils/add-linting';
|
||||||
import { addJest } from '../../utils/add-jest';
|
import { addJest } from '../../utils/add-jest';
|
||||||
@ -25,6 +30,8 @@ import {
|
|||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
|
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
|
||||||
|
|
||||||
export async function expoLibraryGenerator(
|
export async function expoLibraryGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -49,12 +56,17 @@ export async function expoLibraryGeneratorInternal(
|
|||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
const initTask = await init(host, {
|
const jsInitTask = await jsInitGenerator(host, {
|
||||||
...options,
|
...schema,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
e2eTestRunner: 'none',
|
|
||||||
});
|
});
|
||||||
|
tasks.push(jsInitTask);
|
||||||
|
const initTask = await init(host, { ...options, skipFormat: true });
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(ensureDependencies(host));
|
||||||
|
}
|
||||||
|
initRootBabelConfig(host);
|
||||||
|
|
||||||
const addProjectTask = await addProject(host, options);
|
const addProjectTask = await addProject(host, options);
|
||||||
if (addProjectTask) {
|
if (addProjectTask) {
|
||||||
@ -103,54 +115,58 @@ export async function expoLibraryGeneratorInternal(
|
|||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addProject(host: Tree, options: NormalizedSchema) {
|
async function addProject(
|
||||||
const targets: { [key: string]: TargetConfiguration } = {};
|
host: Tree,
|
||||||
|
options: NormalizedSchema
|
||||||
let task: GeneratorCallback;
|
): Promise<GeneratorCallback> {
|
||||||
if (options.publishable || options.buildable) {
|
const project: ProjectConfiguration = {
|
||||||
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, {
|
|
||||||
root: options.projectRoot,
|
root: options.projectRoot,
|
||||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||||
projectType: 'library',
|
projectType: 'library',
|
||||||
tags: options.parsedTags,
|
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) {
|
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 type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { formatFiles, toJS, updateJson } 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 { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
||||||
|
import { tslibVersion } from '@nx/node/src/utils/versions';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { initGenerator } from '../init/init';
|
import { initGenerator } from '../init/init';
|
||||||
import type { Schema } from './schema';
|
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) {
|
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
|
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
const initTask = await initGenerator(tree, { ...options, skipFormat: true });
|
const initTask = await initGenerator(tree, { ...options, skipFormat: true });
|
||||||
|
tasks.push(initTask);
|
||||||
const applicationTask = await nodeApplicationGenerator(tree, {
|
const applicationTask = await nodeApplicationGenerator(tree, {
|
||||||
...schema,
|
...schema,
|
||||||
bundler: 'webpack',
|
bundler: 'webpack',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
|
tasks.push(applicationTask);
|
||||||
addMainFile(tree, options);
|
addMainFile(tree, options);
|
||||||
addTypes(tree, options);
|
addTypes(tree, options);
|
||||||
|
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(ensureDependencies(tree));
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return async () => {
|
return runTasksInSerial(...tasks);
|
||||||
await initTask();
|
|
||||||
await applicationTask();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default applicationGenerator;
|
export default applicationGenerator;
|
||||||
@ -107,3 +120,11 @@ async function normalizeOptions(
|
|||||||
appProjectRoot,
|
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');
|
const packageJson = readJson(tree, 'package.json');
|
||||||
// add express
|
// add express
|
||||||
expect(packageJson.dependencies['express']).toBeDefined();
|
expect(packageJson.dependencies['express']).toBeDefined();
|
||||||
// add tslib
|
|
||||||
expect(packageJson.dependencies['tslib']).toBeDefined();
|
|
||||||
// move `@nx/express` to dev
|
// move `@nx/express` to dev
|
||||||
expect(packageJson.dependencies['@nx/express']).toBeUndefined();
|
expect(packageJson.dependencies['@nx/express']).toBeUndefined();
|
||||||
expect(packageJson.devDependencies['@nx/express']).toBeDefined();
|
expect(packageJson.devDependencies['@nx/express']).toBeDefined();
|
||||||
// add express types
|
|
||||||
expect(packageJson.devDependencies['@types/express']).toBeDefined();
|
|
||||||
// keep existing packages
|
// keep existing packages
|
||||||
expect(packageJson.devDependencies[existing]).toBeDefined();
|
expect(packageJson.devDependencies[existing]).toBeDefined();
|
||||||
expect(packageJson.dependencies[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 {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
|
GeneratorCallback,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { initGenerator as nodeInitGenerator } from '@nx/node';
|
import { expressVersion, nxVersion } from '../../utils/versions';
|
||||||
import { tslibVersion } from '@nx/node/src/utils/versions';
|
|
||||||
import {
|
|
||||||
expressTypingsVersion,
|
|
||||||
expressVersion,
|
|
||||||
nxVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
|
|
||||||
function updateDependencies(tree: Tree) {
|
function updateDependencies(tree: Tree) {
|
||||||
removeDependenciesFromPackageJson(tree, ['@nx/express'], []);
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
return addDependenciesToPackageJson(
|
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/express'], []));
|
||||||
tree,
|
|
||||||
{
|
tasks.push(
|
||||||
express: expressVersion,
|
addDependenciesToPackageJson(
|
||||||
tslib: tslibVersion,
|
tree,
|
||||||
},
|
{ express: expressVersion },
|
||||||
{
|
{ '@nx/express': nxVersion }
|
||||||
'@types/express': expressTypingsVersion,
|
)
|
||||||
'@nx/express': nxVersion,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initGenerator(tree: Tree, schema: Schema) {
|
export async function initGenerator(tree: Tree, schema: Schema) {
|
||||||
const initTask = await nodeInitGenerator(tree, {
|
let installTask: GeneratorCallback = () => {};
|
||||||
...schema,
|
if (!schema.skipPackageJson) {
|
||||||
skipFormat: true,
|
installTask = updateDependencies(tree);
|
||||||
});
|
}
|
||||||
const installTask = updateDependencies(tree);
|
|
||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return async () => {
|
return installTask;
|
||||||
await initTask();
|
|
||||||
await installTask();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default initGenerator;
|
export default initGenerator;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
unitTestRunner?: 'jest' | 'none';
|
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
|
skipPackageJson?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,16 +6,15 @@
|
|||||||
"description": "Init Express Plugin.",
|
"description": "Init Express Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipPackageJson": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Do not add dependencies to `package.json`."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import init from '../init/init';
|
import { jestInitGenerator } from '../init/init';
|
||||||
import { checkForTestTarget } from './lib/check-for-test-target';
|
import { checkForTestTarget } from './lib/check-for-test-target';
|
||||||
import { createFiles } from './lib/create-files';
|
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 { updateTsConfig } from './lib/update-tsconfig';
|
||||||
|
import { updateVsCodeRecommendedExtensions } from './lib/update-vscode-recommended-extensions';
|
||||||
import { updateWorkspace } from './lib/update-workspace';
|
import { updateWorkspace } from './lib/update-workspace';
|
||||||
import { JestProjectSchema, NormalizedJestProjectSchema } from './schema';
|
import { JestProjectSchema, NormalizedJestProjectSchema } from './schema';
|
||||||
import {
|
import {
|
||||||
@ -10,7 +13,9 @@ import {
|
|||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
|
runTasksInSerial,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
|
|
||||||
const schemaDefaults = {
|
const schemaDefaults = {
|
||||||
setupFile: 'none',
|
setupFile: 'none',
|
||||||
@ -61,11 +66,20 @@ export async function configurationGenerator(
|
|||||||
schema: JestProjectSchema
|
schema: JestProjectSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const options = normalizeOptions(tree, schema);
|
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);
|
checkForTestTarget(tree, options);
|
||||||
createFiles(tree, options);
|
createFiles(tree, options);
|
||||||
updateTsConfig(tree, options);
|
updateTsConfig(tree, options);
|
||||||
|
updateVsCodeRecommendedExtensions(tree);
|
||||||
|
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
const hasPlugin = nxJson.plugins?.some((p) =>
|
const hasPlugin = nxJson.plugins?.some((p) =>
|
||||||
@ -80,7 +94,8 @@ export async function configurationGenerator(
|
|||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
return installTask;
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default configurationGenerator;
|
export default configurationGenerator;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`jest should generate files 1`] = `
|
exports[`createJestConfig should generate files 1`] = `
|
||||||
"import { getJestProjects } from '@nx/jest';
|
"import { getJestProjects } from '@nx/jest';
|
||||||
|
|
||||||
export default {
|
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;
|
"const nxPreset = require('@nx/jest/preset').default;
|
||||||
|
|
||||||
module.exports = { ...nxPreset }"
|
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');
|
"const { getJestProjects } = require('@nx/jest');
|
||||||
|
|
||||||
module.exports = {
|
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;
|
"const nxPreset = require('@nx/jest/preset').default;
|
||||||
|
|
||||||
module.exports = { ...nxPreset }"
|
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 {
|
import {
|
||||||
addProjectConfiguration as _addProjectConfiguration,
|
|
||||||
NxJsonConfiguration,
|
|
||||||
ProjectGraph,
|
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
|
||||||
stripIndents,
|
|
||||||
Tree,
|
|
||||||
updateJson,
|
updateJson,
|
||||||
writeJson,
|
type NxJsonConfiguration,
|
||||||
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { jestInitGenerator } from './init';
|
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', () => {
|
describe('jest', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
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 () => {
|
it('should add target defaults for test', async () => {
|
||||||
@ -135,11 +54,10 @@ export default {
|
|||||||
json.namedInputs.production = ['default', '^production'];
|
json.namedInputs.production = ['default', '^production'];
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
await jestInitGenerator(tree, {});
|
await jestInitGenerator(tree, {});
|
||||||
|
|
||||||
let nxJson: NxJsonConfiguration;
|
let nxJson: NxJsonConfiguration;
|
||||||
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
|
||||||
|
json.namedInputs ??= {};
|
||||||
json.namedInputs.production = [
|
json.namedInputs.production = [
|
||||||
'default',
|
'default',
|
||||||
'^production',
|
'^production',
|
||||||
@ -157,226 +75,18 @@ export default {
|
|||||||
nxJson = json;
|
nxJson = json;
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
tree.write('jest.preset.js', '');
|
||||||
|
|
||||||
await jestInitGenerator(tree, {});
|
await jestInitGenerator(tree, {});
|
||||||
|
|
||||||
expect(readJson<NxJsonConfiguration>(tree, 'nx.json')).toEqual(nxJson);
|
expect(readJson<NxJsonConfiguration>(tree, 'nx.json')).toEqual(nxJson);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add dependencies', async () => {
|
it('should add dependencies', async () => {
|
||||||
await jestInitGenerator(tree, {});
|
await jestInitGenerator(tree, {});
|
||||||
|
|
||||||
const packageJson = readJson(tree, 'package.json');
|
const packageJson = readJson(tree, 'package.json');
|
||||||
expect(packageJson.devDependencies.jest).toBeDefined();
|
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||||
expect(packageJson.devDependencies['@nx/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 {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
createProjectGraphAsync,
|
formatFiles,
|
||||||
GeneratorCallback,
|
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
stripIndents,
|
|
||||||
TargetConfiguration,
|
|
||||||
Tree,
|
|
||||||
updateJson,
|
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
updateProjectConfiguration,
|
type GeneratorCallback,
|
||||||
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import { jestVersion, nxVersion } from '../../utils/versions';
|
||||||
|
import type { JestInitSchema } from './schema';
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addPlugin(tree: Tree) {
|
function addPlugin(tree: Tree) {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
@ -77,127 +32,6 @@ function addPlugin(tree: Tree) {
|
|||||||
updateNxJson(tree, nxJson);
|
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) {
|
function updateProductionFileSet(tree: Tree) {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
@ -223,23 +57,21 @@ function updateProductionFileSet(tree: Tree) {
|
|||||||
updateNxJson(tree, nxJson);
|
updateNxJson(tree, nxJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addJestTargetDefaults(tree: Tree, hasPlugin: boolean) {
|
function addJestTargetDefaults(tree: Tree) {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
nxJson.targetDefaults ??= {};
|
nxJson.targetDefaults ??= {};
|
||||||
nxJson.targetDefaults['@nx/jest:jest'] ??= {};
|
nxJson.targetDefaults['@nx/jest:jest'] ??= {};
|
||||||
|
|
||||||
if (!hasPlugin) {
|
const productionFileSet = nxJson.namedInputs?.production;
|
||||||
const productionFileSet = nxJson.namedInputs?.production;
|
|
||||||
|
|
||||||
nxJson.targetDefaults['@nx/jest:jest'].cache ??= true;
|
nxJson.targetDefaults['@nx/jest:jest'].cache ??= true;
|
||||||
// Test targets depend on all their project's sources + production sources of dependencies
|
// Test targets depend on all their project's sources + production sources of dependencies
|
||||||
nxJson.targetDefaults['@nx/jest:jest'].inputs ??= [
|
nxJson.targetDefaults['@nx/jest:jest'].inputs ??= [
|
||||||
'default',
|
'default',
|
||||||
productionFileSet ? '^production' : '^default',
|
productionFileSet ? '^production' : '^default',
|
||||||
'{workspaceRoot}/jest.preset.js',
|
'{workspaceRoot}/jest.preset.js',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
nxJson.targetDefaults['@nx/jest:jest'].options ??= {
|
nxJson.targetDefaults['@nx/jest:jest'].options ??= {
|
||||||
passWithNoTests: true,
|
passWithNoTests: true,
|
||||||
@ -254,87 +86,41 @@ function addJestTargetDefaults(tree: Tree, hasPlugin: boolean) {
|
|||||||
updateNxJson(tree, nxJson);
|
updateNxJson(tree, nxJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDependencies(tree: Tree, options: NormalizedSchema) {
|
function updateDependencies(tree: Tree) {
|
||||||
const dependencies = {
|
return addDependenciesToPackageJson(
|
||||||
tslib: tslibVersion,
|
tree,
|
||||||
};
|
{},
|
||||||
const devDeps = {
|
{
|
||||||
'@nx/jest': nxVersion,
|
'@nx/jest': nxVersion,
|
||||||
jest: jestVersion,
|
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);
|
|
||||||
}
|
}
|
||||||
return json;
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function jestInitGenerator(
|
export async function jestInitGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: JestInitSchema
|
options: JestInitSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const options = normalizeOptions(schema);
|
if (!tree.exists('jest.preset.js')) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
updateProductionFileSet(tree);
|
||||||
|
if (process.env.NX_PCV3 === 'true') {
|
||||||
tasks.push(
|
addPlugin(tree);
|
||||||
await jsInitGenerator(tree, {
|
} else {
|
||||||
...schema,
|
addJestTargetDefaults(tree);
|
||||||
skipFormat: true,
|
}
|
||||||
})
|
}
|
||||||
);
|
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
await createJestConfig(tree, options);
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/jest'], []));
|
||||||
if (!options.skipPackageJson) {
|
tasks.push(updateDependencies(tree));
|
||||||
removeDependenciesFromPackageJson(tree, ['@nx/jest'], []);
|
}
|
||||||
const installTask = updateDependencies(tree, options);
|
|
||||||
tasks.push(installTask);
|
if (!options.skipFormat) {
|
||||||
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateExtensions(tree);
|
|
||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(options: JestInitSchema) {
|
|
||||||
return {
|
|
||||||
...schemaDefaults,
|
|
||||||
...options,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default jestInitGenerator;
|
export default jestInitGenerator;
|
||||||
|
|||||||
@ -1,11 +1,4 @@
|
|||||||
export interface JestInitSchema {
|
export interface JestInitSchema {
|
||||||
compiler?: 'tsc' | 'babel' | 'swc';
|
skipFormat?: boolean;
|
||||||
js?: boolean;
|
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
testEnvironment?: 'node' | 'jsdom' | 'none';
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
babelJest?: boolean;
|
|
||||||
rootProject?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,36 +6,17 @@
|
|||||||
"description": "Add Jest Configuration to a workspace.",
|
"description": "Add Jest Configuration to a workspace.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"babelJest": {
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"alias": "babel-jest",
|
"default": false,
|
||||||
"description": "Use `babel-jest` instead of `ts-jest`.",
|
"x-priority": "internal"
|
||||||
"default": false
|
|
||||||
},
|
},
|
||||||
"skipPackageJson": {
|
"skipPackageJson": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"x-priority": "internal"
|
"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": []
|
"required": []
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
|||||||
import { initGenerator } from '../init/init';
|
import { initGenerator } from '../init/init';
|
||||||
import {
|
import {
|
||||||
createFiles,
|
createFiles,
|
||||||
|
ensureDependencies,
|
||||||
normalizeOptions,
|
normalizeOptions,
|
||||||
toNodeApplicationGeneratorOptions,
|
toNodeApplicationGeneratorOptions,
|
||||||
updateTsConfig,
|
updateTsConfig,
|
||||||
@ -26,23 +27,30 @@ export async function applicationGeneratorInternal(
|
|||||||
rawOptions: ApplicationGeneratorOptions
|
rawOptions: ApplicationGeneratorOptions
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const options = await normalizeOptions(tree, rawOptions);
|
const options = await normalizeOptions(tree, rawOptions);
|
||||||
|
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
const initTask = await initGenerator(tree, {
|
const initTask = await initGenerator(tree, {
|
||||||
skipPackageJson: options.skipPackageJson,
|
skipPackageJson: options.skipPackageJson,
|
||||||
unitTestRunner: options.unitTestRunner,
|
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
|
tasks.push(initTask);
|
||||||
const nodeApplicationTask = await nodeApplicationGenerator(
|
const nodeApplicationTask = await nodeApplicationGenerator(
|
||||||
tree,
|
tree,
|
||||||
toNodeApplicationGeneratorOptions(options)
|
toNodeApplicationGeneratorOptions(options)
|
||||||
);
|
);
|
||||||
|
tasks.push(nodeApplicationTask);
|
||||||
createFiles(tree, options);
|
createFiles(tree, options);
|
||||||
updateTsConfig(tree, options);
|
updateTsConfig(tree, options);
|
||||||
|
|
||||||
|
if (!options.skipPackageJson) {
|
||||||
|
tasks.push(ensureDependencies(tree));
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(initTask, nodeApplicationTask);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default applicationGenerator;
|
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 './create-files';
|
||||||
|
export * from './ensure-dependencies';
|
||||||
export * from './normalize-options';
|
export * from './normalize-options';
|
||||||
export * from './update-tsconfig';
|
export * from './update-tsconfig';
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
import type { Tree } from '@nx/devkit';
|
||||||
import * as devkit from '@nx/devkit';
|
import * as devkit from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import {
|
import { nestJsSchematicsVersion, nxVersion } from '../../utils/versions';
|
||||||
nestJsSchematicsVersion,
|
|
||||||
nestJsVersion,
|
|
||||||
nxVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import { initGenerator } from './init';
|
import { initGenerator } from './init';
|
||||||
|
|
||||||
describe('init generator', () => {
|
describe('init generator', () => {
|
||||||
@ -20,34 +16,12 @@ describe('init generator', () => {
|
|||||||
await initGenerator(tree, {});
|
await initGenerator(tree, {});
|
||||||
|
|
||||||
const packageJson = devkit.readJson(tree, 'package.json');
|
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(
|
expect(packageJson.devDependencies['@nestjs/schematics']).toBe(
|
||||||
nestJsSchematicsVersion
|
nestJsSchematicsVersion
|
||||||
);
|
);
|
||||||
expect(packageJson.devDependencies['@nestjs/testing']).toBe(nestJsVersion);
|
|
||||||
expect(packageJson.devDependencies['@nx/nest']).toBe(nxVersion);
|
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', () => {
|
describe('--skipFormat', () => {
|
||||||
it('should format files by default', async () => {
|
it('should format files by default', async () => {
|
||||||
jest.spyOn(devkit, 'formatFiles');
|
jest.spyOn(devkit, 'formatFiles');
|
||||||
|
|||||||
@ -1,33 +1,23 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
import { formatFiles } from '@nx/devkit';
|
||||||
import { initGenerator as nodeInitGenerator } from '@nx/node';
|
|
||||||
|
|
||||||
import { addDependencies, normalizeOptions } from './lib';
|
import { addDependencies } from './lib';
|
||||||
import type { InitGeneratorOptions } from './schema';
|
import type { InitGeneratorOptions } from './schema';
|
||||||
|
|
||||||
export async function initGenerator(
|
export async function initGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
rawOptions: InitGeneratorOptions
|
options: InitGeneratorOptions
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const options = normalizeOptions(rawOptions);
|
let installPackagesTask: GeneratorCallback = () => {};
|
||||||
const tasks: GeneratorCallback[] = [];
|
|
||||||
|
|
||||||
const nodeInitTask = await nodeInitGenerator(tree, {
|
|
||||||
...options,
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
tasks.push(nodeInitTask);
|
|
||||||
|
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
const installPackagesTask = addDependencies(tree);
|
installPackagesTask = addDependencies(tree);
|
||||||
tasks.push(installPackagesTask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return runTasksInSerial(...tasks);
|
return installPackagesTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default initGenerator;
|
export default initGenerator;
|
||||||
|
|||||||
@ -1,28 +1,13 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { addDependenciesToPackageJson } from '@nx/devkit';
|
import { addDependenciesToPackageJson } from '@nx/devkit';
|
||||||
import {
|
import { nestJsSchematicsVersion, nxVersion } from '../../../utils/versions';
|
||||||
nestJsSchematicsVersion,
|
|
||||||
nestJsVersion,
|
|
||||||
nxVersion,
|
|
||||||
reflectMetadataVersion,
|
|
||||||
rxjsVersion,
|
|
||||||
tsLibVersion,
|
|
||||||
} from '../../../utils/versions';
|
|
||||||
|
|
||||||
export function addDependencies(tree: Tree): GeneratorCallback {
|
export function addDependencies(tree: Tree): GeneratorCallback {
|
||||||
return addDependenciesToPackageJson(
|
return addDependenciesToPackageJson(
|
||||||
tree,
|
tree,
|
||||||
{
|
{},
|
||||||
'@nestjs/common': nestJsVersion,
|
|
||||||
'@nestjs/core': nestJsVersion,
|
|
||||||
'@nestjs/platform-express': nestJsVersion,
|
|
||||||
'reflect-metadata': reflectMetadataVersion,
|
|
||||||
rxjs: rxjsVersion,
|
|
||||||
tslib: tsLibVersion,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'@nestjs/schematics': nestJsSchematicsVersion,
|
'@nestjs/schematics': nestJsSchematicsVersion,
|
||||||
'@nestjs/testing': nestJsVersion,
|
|
||||||
'@nx/nest': nxVersion,
|
'@nx/nest': nxVersion,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,2 +1 @@
|
|||||||
export * from './add-dependencies';
|
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 {
|
export interface InitGeneratorOptions {
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
unitTestRunner?: UnitTestRunner;
|
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,12 +6,6 @@
|
|||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"unitTestRunner": {
|
|
||||||
"description": "Adds the specified unit test runner.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"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