feat(nx-plugin): add support for the ts solution config setup to the @nx/plugin plugin (#28724)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
2d77495cc5
commit
f7f26d847e
@ -20,13 +20,13 @@
|
||||
"generateExportsField": {
|
||||
"type": "boolean",
|
||||
"alias": "exports",
|
||||
"description": "Update the output package.json file's 'exports' field. This field is used by Node and bundles.",
|
||||
"description": "Update the output package.json file's 'exports' field. This field is used by Node and bundlers. Ignored when `generatePackageJson` is set to `false`.",
|
||||
"default": false,
|
||||
"x-priority": "important"
|
||||
},
|
||||
"additionalEntryPoints": {
|
||||
"type": "array",
|
||||
"description": "Additional entry-points to add to exports field in the package.json file.",
|
||||
"description": "Additional entry-points to add to exports field in the package.json file. Ignored when `generatePackageJson` is set to `false`.",
|
||||
"items": { "type": "string" },
|
||||
"x-priority": "important"
|
||||
},
|
||||
@ -132,9 +132,14 @@
|
||||
},
|
||||
"generateLockfile": {
|
||||
"type": "boolean",
|
||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match. Ignored when `generatePackageJson` is set to `false`.",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"generatePackageJson": {
|
||||
"type": "boolean",
|
||||
"description": "Generate package.json file in the output folder.",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"required": ["main", "outputPath", "tsConfig"],
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-package",
|
||||
"factory": "./src/generators/create-package/create-package",
|
||||
"factory": "./src/generators/create-package/create-package#createPackageGeneratorInternal",
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
@ -31,15 +31,13 @@
|
||||
},
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests.",
|
||||
"default": "jest"
|
||||
"enum": ["none", "jest"],
|
||||
"description": "Test runner to use for unit tests."
|
||||
},
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint"],
|
||||
"default": "eslint"
|
||||
"enum": ["none", "eslint"]
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
@ -62,13 +60,17 @@
|
||||
"type": "string",
|
||||
"description": "The name of the e2e project.",
|
||||
"x-prompt": "What is the name of the e2e project? Leave blank to skip e2e tests"
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["directory", "name", "project"],
|
||||
"presets": []
|
||||
},
|
||||
"description": "Create a package which can be used by npx to create a new workspace",
|
||||
"implementation": "/packages/plugin/src/generators/create-package/create-package.ts",
|
||||
"implementation": "/packages/plugin/src/generators/create-package/create-package#createPackageGeneratorInternal.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/plugin/src/generators/create-package/schema.json",
|
||||
|
||||
@ -33,8 +33,7 @@
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint", "none"],
|
||||
"default": "eslint"
|
||||
"enum": ["none", "eslint"]
|
||||
},
|
||||
"minimal": {
|
||||
"type": "boolean",
|
||||
@ -46,6 +45,10 @@
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["pluginName", "npmPackageName"],
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "plugin",
|
||||
"factory": "./src/generators/plugin/plugin",
|
||||
"factory": "./src/generators/plugin/plugin#pluginGeneratorInternal",
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
@ -34,14 +34,14 @@
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint"],
|
||||
"default": "eslint"
|
||||
"enum": ["none", "eslint"],
|
||||
"x-priority": "important"
|
||||
},
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests.",
|
||||
"default": "jest"
|
||||
"type": "string",
|
||||
"enum": ["none", "jest"],
|
||||
"x-priority": "important"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
@ -92,13 +92,17 @@
|
||||
"type": "boolean",
|
||||
"description": "Generates a boilerplate for publishing the plugin to npm.",
|
||||
"default": false
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["directory"],
|
||||
"presets": []
|
||||
},
|
||||
"description": "Create a Nx Plugin.",
|
||||
"implementation": "/packages/plugin/src/generators/plugin/plugin.ts",
|
||||
"implementation": "/packages/plugin/src/generators/plugin/plugin#pluginGeneratorInternal.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/plugin/src/generators/plugin/schema.json",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "preset",
|
||||
"factory": "./src/generators/preset/generator",
|
||||
"factory": "./src/generators/preset/generator#presetGeneratorInternal",
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
@ -27,6 +27,10 @@
|
||||
"createPackageName": {
|
||||
"type": "string",
|
||||
"description": "Name of package which creates a workspace"
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["pluginName"],
|
||||
@ -35,7 +39,7 @@
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-workspace --preset @nx/plugin`.",
|
||||
"hidden": true,
|
||||
"x-use-standalone-layout": true,
|
||||
"implementation": "/packages/plugin/src/generators/preset/generator.ts",
|
||||
"implementation": "/packages/plugin/src/generators/preset/generator#presetGeneratorInternal.ts",
|
||||
"aliases": [],
|
||||
"path": "/packages/plugin/src/generators/preset/schema.json",
|
||||
"type": "generator"
|
||||
|
||||
@ -60,7 +60,7 @@ describe('Nx Plugin', () => {
|
||||
|
||||
runCLI(`generate @nx/plugin:plugin ${plugin} --linter=eslint`);
|
||||
runCLI(
|
||||
`generate @nx/plugin:migration --path=${plugin}/src/migrations/update-${version} --packageVersion=${version} --packageJsonUpdates=false`
|
||||
`generate @nx/plugin:migration --path=${plugin}/src/migrations/update-${version}/update-${version} --packageVersion=${version} --packageJsonUpdates=false`
|
||||
);
|
||||
|
||||
const lintResults = runCLI(`lint ${plugin}`);
|
||||
@ -92,7 +92,7 @@ describe('Nx Plugin', () => {
|
||||
|
||||
runCLI(`generate @nx/plugin:plugin ${plugin} --linter=eslint`);
|
||||
runCLI(
|
||||
`generate @nx/plugin:generator ${plugin}/src/generators/${generator} --name ${generator}`
|
||||
`generate @nx/plugin:generator ${plugin}/src/generators/${generator}/generator --name ${generator}`
|
||||
);
|
||||
|
||||
const lintResults = runCLI(`lint ${plugin}`);
|
||||
@ -129,7 +129,7 @@ describe('Nx Plugin', () => {
|
||||
|
||||
runCLI(`generate @nx/plugin:plugin ${plugin} --linter=eslint`);
|
||||
runCLI(
|
||||
`generate @nx/plugin:executor --name ${executor} --path=${plugin}/src/executors/${executor} --includeHasher`
|
||||
`generate @nx/plugin:executor --name ${executor} --path=${plugin}/src/executors/${executor}/executor --includeHasher`
|
||||
);
|
||||
|
||||
const lintResults = runCLI(`lint ${plugin}`);
|
||||
@ -178,19 +178,19 @@ describe('Nx Plugin', () => {
|
||||
runCLI(`generate @nx/plugin:plugin ${plugin} --linter=eslint`);
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:generator --name=${goodGenerator} --path=${plugin}/src/generators/${goodGenerator}`
|
||||
`generate @nx/plugin:generator --name=${goodGenerator} --path=${plugin}/src/generators/${goodGenerator}/generator`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:generator --name=${badFactoryPath} --path=${plugin}/src/generators/${badFactoryPath}`
|
||||
`generate @nx/plugin:generator --name=${badFactoryPath} --path=${plugin}/src/generators/${badFactoryPath}/generator`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:executor --name=${goodExecutor} --path=${plugin}/src/executors/${goodExecutor}`
|
||||
`generate @nx/plugin:executor --name=${goodExecutor} --path=${plugin}/src/executors/${goodExecutor}/executor`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:executor --name=${badExecutorBadImplPath} --path=${plugin}/src/executors/${badExecutorBadImplPath}`
|
||||
`generate @nx/plugin:executor --name=${badExecutorBadImplPath} --path=${plugin}/src/executors/${badExecutorBadImplPath}/executor`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
@ -308,11 +308,11 @@ describe('Nx Plugin', () => {
|
||||
const generatedProject = uniq('project');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:generator --name ${generator} --path ${plugin}/src/generators/${generator}`
|
||||
`generate @nx/plugin:generator --name ${generator} --path ${plugin}/src/generators/${generator}/generator`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
`generate @nx/plugin:executor --name ${executor} --path ${plugin}/src/executors/${executor}`
|
||||
`generate @nx/plugin:executor --name ${executor} --path ${plugin}/src/executors/${executor}/executor`
|
||||
);
|
||||
|
||||
updateFile(
|
||||
@ -349,7 +349,7 @@ describe('Nx Plugin', () => {
|
||||
|
||||
expect(() => {
|
||||
runCLI(
|
||||
`generate @nx/plugin:generator ${plugin}/src/generators/${generator} --name ${generator}`
|
||||
`generate @nx/plugin:generator ${plugin}/src/generators/${generator}/generator --name ${generator}`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
|
||||
@ -20,12 +20,12 @@ import {
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { resolveImportPath } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { promptWhenInteractive } from '@nx/devkit/src/generators/prompt';
|
||||
import { Linter, LinterType } from '@nx/eslint';
|
||||
import {
|
||||
getRelativePathToRootTsConfig,
|
||||
initGenerator as jsInitGenerator,
|
||||
} from '@nx/js';
|
||||
import { normalizeLinterOption } from '@nx/js/src/utils/generator-prompts';
|
||||
import {
|
||||
getProjectPackageManagerWorkspaceState,
|
||||
getProjectPackageManagerWorkspaceStateWarningTask,
|
||||
@ -165,28 +165,7 @@ function ensureDependencies(tree: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
async function normalizeOptions(tree: Tree, options: CypressE2EConfigSchema) {
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
|
||||
let linter = options.linter;
|
||||
if (!linter) {
|
||||
const choices = isTsSolutionSetup
|
||||
? [{ name: 'none' }, { name: 'eslint' }]
|
||||
: [{ name: 'eslint' }, { name: 'none' }];
|
||||
const defaultValue = isTsSolutionSetup ? 'none' : 'eslint';
|
||||
|
||||
linter = await promptWhenInteractive<{
|
||||
linter: 'none' | 'eslint';
|
||||
}>(
|
||||
{
|
||||
type: 'select',
|
||||
name: 'linter',
|
||||
message: `Which linter would you like to use?`,
|
||||
choices,
|
||||
initial: 0,
|
||||
},
|
||||
{ linter: defaultValue }
|
||||
).then(({ linter }) => linter);
|
||||
}
|
||||
const linter = await normalizeLinterOption(tree, options.linter);
|
||||
|
||||
const projectConfig: ProjectConfiguration | undefined =
|
||||
readProjectConfiguration(tree, options.project);
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
import {
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
output,
|
||||
readJson,
|
||||
logger,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
getRootTsConfigFileName,
|
||||
initGenerator as jsInitGenerator,
|
||||
} from '@nx/js';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { JestPluginOptions } from '../../plugins/plugin';
|
||||
import { getPresetExt } from '../../utils/config/config-file';
|
||||
import { jestInitGenerator } from '../init/init';
|
||||
@ -74,6 +71,7 @@ function normalizeOptions(
|
||||
...schemaDefaults,
|
||||
...options,
|
||||
rootProject: project.root === '.' || project.root === '',
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
}
|
||||
|
||||
@ -115,10 +113,15 @@ export async function configurationGeneratorInternal(
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasPlugin || options.addExplicitTargets) {
|
||||
updateWorkspace(tree, options);
|
||||
}
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
ignoreTestOutput(tree);
|
||||
}
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
@ -126,4 +129,18 @@ export async function configurationGeneratorInternal(
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function ignoreTestOutput(tree: Tree): void {
|
||||
if (!tree.exists('.gitignore')) {
|
||||
logger.warn(`Couldn't find a root .gitignore file to update.`);
|
||||
}
|
||||
|
||||
let content = tree.read('.gitignore', 'utf-8');
|
||||
if (/^test-output$/gm.test(content)) {
|
||||
return;
|
||||
}
|
||||
|
||||
content = `${content}\ntest-output\n`;
|
||||
tree.write('.gitignore', content);
|
||||
}
|
||||
|
||||
export default configurationGenerator;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
preset: '<%= offsetFromRoot %>jest.preset.<%= presetExt %>',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],<% if(testEnvironment) { %>
|
||||
testEnvironment: '<%= testEnvironment %>',<% } %>
|
||||
coverageDirectory: '<%= offsetFromRoot %>coverage/<%= projectRoot %>',
|
||||
coverageDirectory: '<%= coverageDirectory %>',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"extends": "<%= extendedConfig %>",
|
||||
"compilerOptions": {
|
||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"outDir": "<%= outDir %>",<% if (module) { %>
|
||||
"module": "<%= module %>",<% } %>
|
||||
"target": "es2016",
|
||||
"types": ["jest", "node"]
|
||||
},<% if(setupFile !== 'none') { %>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<% if (supportTsx){ %>'^.+\\.[tj]sx?$'<% } else { %>'^.+\\.[tj]s$'<% } %>: <% if (transformerOptions) { %>['<%= transformer %>', <%- transformerOptions %>]<% } else { %>'<%= transformer %>'<% } %>
|
||||
},
|
||||
<% if (supportTsx) { %>moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],<% } else { %>moduleFileExtensions: ['ts', 'js', 'html'],<% } %><% } %>
|
||||
coverageDirectory: '<%= offsetFromRoot %>coverage/<%= projectRoot %>'<% if(rootProject){ %>,
|
||||
coverageDirectory: '<%= coverageDirectory %>'<% if(rootProject){ %>,
|
||||
testMatch: [
|
||||
'<rootDir>/src/**/__tests__/**/*.[jt]s?(x)',
|
||||
'<rootDir>/src/**/*(*.)@(spec|test).[jt]s?(x)',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"extends": "<%= extendedConfig %>",
|
||||
"compilerOptions": {
|
||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"outDir": "<%= outDir %>",<% if (module) { %>
|
||||
"module": "<%= module %>",<% } %>
|
||||
"types": ["jest", "node"]
|
||||
},<% if(setupFile !== 'none') { %>
|
||||
"files": ["src/test-setup.ts"],<% } %>
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { join } from 'path';
|
||||
import type { JestPresetExtension } from '../../../utils/config/config-file';
|
||||
import { NormalizedJestProjectSchema } from '../schema';
|
||||
@ -33,6 +34,12 @@ export function createFiles(
|
||||
transformerOptions = "{ tsconfig: '<rootDir>/tsconfig.spec.json' }";
|
||||
}
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
|
||||
const projectRoot = options.rootProject
|
||||
? options.project
|
||||
: projectConfig.root;
|
||||
const rootOffset = offsetFromRoot(projectConfig.root);
|
||||
generateFiles(tree, join(__dirname, filesFolder), projectConfig.root, {
|
||||
tmpl: '',
|
||||
...options,
|
||||
@ -45,9 +52,17 @@ export function createFiles(
|
||||
transformerOptions,
|
||||
js: !!options.js,
|
||||
rootProject: options.rootProject,
|
||||
projectRoot: options.rootProject ? options.project : projectConfig.root,
|
||||
offsetFromRoot: offsetFromRoot(projectConfig.root),
|
||||
projectRoot,
|
||||
offsetFromRoot: rootOffset,
|
||||
presetExt,
|
||||
coverageDirectory: isTsSolutionSetup
|
||||
? `test-output/jest/coverage`
|
||||
: `${rootOffset}coverage/${projectRoot}`,
|
||||
extendedConfig: isTsSolutionSetup
|
||||
? `${rootOffset}tsconfig.base.json`
|
||||
: './tsconfig.json',
|
||||
outDir: isTsSolutionSetup ? `./out-tsc/jest` : `${rootOffset}dist/out-tsc`,
|
||||
module: !isTsSolutionSetup ? 'commonjs' : undefined,
|
||||
});
|
||||
|
||||
if (options.setupFile === 'none') {
|
||||
|
||||
@ -19,9 +19,13 @@ export function updateWorkspace(
|
||||
projectConfig.targets[options.targetName] = {
|
||||
executor: '@nx/jest:jest',
|
||||
outputs: [
|
||||
options.rootProject
|
||||
? joinPathFragments('{workspaceRoot}', 'coverage', '{projectName}')
|
||||
: joinPathFragments('{workspaceRoot}', 'coverage', '{projectRoot}'),
|
||||
options.isTsSolutionSetup
|
||||
? '{projectRoot}/test-output/jest/coverage'
|
||||
: joinPathFragments(
|
||||
'{workspaceRoot}',
|
||||
'coverage',
|
||||
options.rootProject ? '{projectName}' : '{projectRoot}'
|
||||
),
|
||||
],
|
||||
options: {
|
||||
jestConfig: joinPathFragments(
|
||||
|
||||
@ -29,4 +29,5 @@ export interface JestProjectSchema {
|
||||
|
||||
export type NormalizedJestProjectSchema = JestProjectSchema & {
|
||||
rootProject: boolean;
|
||||
isTsSolutionSetup: boolean;
|
||||
};
|
||||
|
||||
@ -57,5 +57,6 @@ export function normalizeOptions(
|
||||
outputPath,
|
||||
options.main.replace(`${projectRoot}/`, '').replace('.ts', '.js')
|
||||
),
|
||||
generatePackageJson: options.generatePackageJson ?? true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -16,13 +16,13 @@
|
||||
"generateExportsField": {
|
||||
"type": "boolean",
|
||||
"alias": "exports",
|
||||
"description": "Update the output package.json file's 'exports' field. This field is used by Node and bundles.",
|
||||
"description": "Update the output package.json file's 'exports' field. This field is used by Node and bundlers. Ignored when `generatePackageJson` is set to `false`.",
|
||||
"default": false,
|
||||
"x-priority": "important"
|
||||
},
|
||||
"additionalEntryPoints": {
|
||||
"type": "array",
|
||||
"description": "Additional entry-points to add to exports field in the package.json file.",
|
||||
"description": "Additional entry-points to add to exports field in the package.json file. Ignored when `generatePackageJson` is set to `false`.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -103,9 +103,14 @@
|
||||
},
|
||||
"generateLockfile": {
|
||||
"type": "boolean",
|
||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match. Ignored when `generatePackageJson` is set to `false`.",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"generatePackageJson": {
|
||||
"type": "boolean",
|
||||
"description": "Generate package.json file in the output folder.",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"required": ["main", "outputPath", "tsConfig"],
|
||||
|
||||
@ -114,6 +114,7 @@ export async function* tscExecutor(
|
||||
tsCompilationOptions,
|
||||
async () => {
|
||||
await assetHandler.processAllAssetsOnce();
|
||||
if (options.generatePackageJson) {
|
||||
updatePackageJson(
|
||||
{
|
||||
...options,
|
||||
@ -127,6 +128,7 @@ export async function* tscExecutor(
|
||||
target,
|
||||
dependencies
|
||||
);
|
||||
}
|
||||
postProcessInlinedDependencies(
|
||||
tsCompilationOptions.outputPath,
|
||||
tsCompilationOptions.projectRoot,
|
||||
@ -145,7 +147,9 @@ export async function* tscExecutor(
|
||||
if (isDaemonEnabled() && options.watch) {
|
||||
const disposeWatchAssetChanges =
|
||||
await assetHandler.watchAndProcessOnAssetChange();
|
||||
const disposePackageJsonChanges = await watchForSingleFileChanges(
|
||||
let disposePackageJsonChanges: undefined | (() => void);
|
||||
if (options.generatePackageJson) {
|
||||
disposePackageJsonChanges = await watchForSingleFileChanges(
|
||||
context.projectName,
|
||||
options.projectRoot,
|
||||
'package.json',
|
||||
@ -164,10 +168,11 @@ export async function* tscExecutor(
|
||||
dependencies
|
||||
)
|
||||
);
|
||||
}
|
||||
const handleTermination = async (exitCode: number) => {
|
||||
await typescriptCompilation.close();
|
||||
disposeWatchAssetChanges();
|
||||
disposePackageJsonChanges();
|
||||
disposePackageJsonChanges?.();
|
||||
process.exit(exitCode);
|
||||
};
|
||||
process.on('SIGINT', () => handleTermination(128 + 2));
|
||||
|
||||
@ -1561,6 +1561,7 @@ describe('lib', () => {
|
||||
"name": "@proj/my-lib",
|
||||
"nx": {
|
||||
"name": "my-lib",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "my-lib/src",
|
||||
},
|
||||
"private": true,
|
||||
|
||||
@ -33,6 +33,7 @@ import { findMatchingProjects } from 'nx/src/utils/find-matching-projects';
|
||||
import { type PackageJson } from 'nx/src/utils/package-json';
|
||||
import { join } from 'path';
|
||||
import type { CompilerOptions } from 'typescript';
|
||||
import { normalizeLinterOption } from '../../utils/generator-prompts';
|
||||
import {
|
||||
getProjectPackageManagerWorkspaceState,
|
||||
getProjectPackageManagerWorkspaceStateWarningTask,
|
||||
@ -41,6 +42,10 @@ import { addSwcConfig } from '../../utils/swc/add-swc-config';
|
||||
import { getSwcDependencies } from '../../utils/swc/add-swc-dependencies';
|
||||
import { getNeededCompilerOptionOverrides } from '../../utils/typescript/configuration';
|
||||
import { tsConfigBaseOptions } from '../../utils/typescript/create-ts-config';
|
||||
import {
|
||||
ensureProjectIsExcludedFromPluginRegistrations,
|
||||
ensureProjectIsIncludedInPluginRegistrations,
|
||||
} from '../../utils/typescript/plugin';
|
||||
import {
|
||||
addTsConfigPath,
|
||||
getRelativePathToRootTsConfig,
|
||||
@ -64,10 +69,6 @@ import type {
|
||||
LibraryGeneratorSchema,
|
||||
NormalizedLibraryGeneratorOptions,
|
||||
} from './schema';
|
||||
import {
|
||||
ensureProjectIsExcludedFromPluginRegistrations,
|
||||
ensureProjectIsIncludedInPluginRegistrations,
|
||||
} from '../../utils/typescript/plugin';
|
||||
|
||||
const defaultOutputDirectory = 'dist';
|
||||
|
||||
@ -202,16 +203,6 @@ export async function libraryGeneratorInternal(
|
||||
tree,
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.spec.json'),
|
||||
(json) => {
|
||||
const rootOffset = offsetFromRoot(options.projectRoot);
|
||||
// ensure it extends from the root tsconfig.base.json
|
||||
json.extends = joinPathFragments(rootOffset, 'tsconfig.base.json');
|
||||
// ensure outDir is set to the correct value
|
||||
json.compilerOptions ??= {};
|
||||
json.compilerOptions.outDir = joinPathFragments(
|
||||
rootOffset,
|
||||
'dist/out-tsc',
|
||||
options.projectRoot
|
||||
);
|
||||
// add project reference to the runtime tsconfig.lib.json file
|
||||
json.references ??= [];
|
||||
json.references.push({ path: './tsconfig.lib.json' });
|
||||
@ -225,6 +216,7 @@ export async function libraryGeneratorInternal(
|
||||
}
|
||||
|
||||
if (
|
||||
!options.skipWorkspacesWarning &&
|
||||
options.isUsingTsSolutionConfig &&
|
||||
options.projectPackageManagerWorkspaceState !== 'included'
|
||||
) {
|
||||
@ -278,7 +270,8 @@ async function configureProject(
|
||||
options.config !== 'npm-scripts' &&
|
||||
(options.bundler === 'swc' ||
|
||||
options.bundler === 'esbuild' ||
|
||||
(!options.isUsingTsSolutionConfig && options.bundler === 'tsc'))
|
||||
((!options.isUsingTsSolutionConfig || options.useTscExecutor) &&
|
||||
options.bundler === 'tsc'))
|
||||
) {
|
||||
const outputPath = getOutputPath(options);
|
||||
const executor = getBuildExecutor(options.bundler);
|
||||
@ -305,6 +298,8 @@ async function configureProject(
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
if (options.bundler === 'esbuild') {
|
||||
projectConfiguration.targets.build.options.declarationRootDir = `${options.projectRoot}/src`;
|
||||
} else if (options.bundler === 'swc') {
|
||||
projectConfiguration.targets.build.options.stripLeadingPaths = true;
|
||||
}
|
||||
} else {
|
||||
projectConfiguration.targets.build.options.assets = [];
|
||||
@ -356,8 +351,6 @@ async function configureProject(
|
||||
if (!projectConfiguration.tags?.length) {
|
||||
delete projectConfiguration.tags;
|
||||
}
|
||||
// automatically inferred as `library`
|
||||
delete projectConfiguration.projectType;
|
||||
|
||||
// empty targets are cleaned up automatically by `updateProjectConfiguration`
|
||||
updateProjectConfiguration(tree, options.name, projectConfiguration);
|
||||
@ -690,23 +683,12 @@ async function normalizeOptions(
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false;
|
||||
|
||||
options.linter = await normalizeLinterOption(tree, options.linter);
|
||||
|
||||
const hasPlugin = isUsingTypeScriptPlugin(tree);
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree);
|
||||
|
||||
if (isUsingTsSolutionConfig) {
|
||||
options.linter ??= await promptWhenInteractive<{
|
||||
linter: 'none' | 'eslint';
|
||||
}>(
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'linter',
|
||||
message: `Which linter would you like to use?`,
|
||||
choices: [{ name: 'none' }, { name: 'eslint' }],
|
||||
initial: 0,
|
||||
},
|
||||
{ linter: 'none' }
|
||||
).then(({ linter }) => linter);
|
||||
|
||||
options.unitTestRunner ??= await promptWhenInteractive<{
|
||||
unitTestRunner: 'none' | 'jest' | 'vitest';
|
||||
}>(
|
||||
@ -720,19 +702,6 @@ async function normalizeOptions(
|
||||
{ unitTestRunner: 'none' }
|
||||
).then(({ unitTestRunner }) => unitTestRunner);
|
||||
} else {
|
||||
options.linter ??= await promptWhenInteractive<{
|
||||
linter: 'none' | 'eslint';
|
||||
}>(
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'linter',
|
||||
message: `Which linter would you like to use?`,
|
||||
choices: [{ name: 'eslint' }, { name: 'none' }],
|
||||
initial: 0,
|
||||
},
|
||||
{ linter: 'eslint' }
|
||||
).then(({ linter }) => linter);
|
||||
|
||||
options.unitTestRunner ??= await promptWhenInteractive<{
|
||||
unitTestRunner: 'none' | 'jest' | 'vitest';
|
||||
}>(
|
||||
@ -1109,10 +1078,10 @@ function determineEntryFields(
|
||||
return {
|
||||
type: 'commonjs',
|
||||
main: options.isUsingTsSolutionConfig
|
||||
? './dist/src/index.js'
|
||||
? './dist/index.js'
|
||||
: './src/index.js',
|
||||
typings: options.isUsingTsSolutionConfig
|
||||
? './dist/src/index.d.ts'
|
||||
? './dist/index.d.ts'
|
||||
: './src/index.d.ts',
|
||||
};
|
||||
case 'rollup':
|
||||
|
||||
@ -37,6 +37,8 @@ export interface LibraryGeneratorSchema {
|
||||
simpleName?: boolean;
|
||||
addPlugin?: boolean;
|
||||
useProjectJson?: boolean;
|
||||
skipWorkspacesWarning?: boolean;
|
||||
useTscExecutor?: boolean;
|
||||
}
|
||||
|
||||
export interface NormalizedLibraryGeneratorOptions
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { output, ProjectConfiguration, readJson, type Tree } from '@nx/devkit';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
const startLocalRegistryScript = (localRegistryTarget: string) => `
|
||||
/**
|
||||
const startLocalRegistryScript = (localRegistryTarget: string) => `/**
|
||||
* This script starts a local registry for e2e testing purposes.
|
||||
* It is meant to be called in jest's globalSetup.
|
||||
*/
|
||||
|
||||
/// <reference path="registry.d.ts" />
|
||||
|
||||
import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry';
|
||||
import { execFileSync } from 'child_process';
|
||||
import { releasePublish, releaseVersion } from 'nx/release';
|
||||
|
||||
export default async () => {
|
||||
@ -38,12 +40,13 @@ export default async () => {
|
||||
};
|
||||
`;
|
||||
|
||||
const stopLocalRegistryScript = `
|
||||
/**
|
||||
const stopLocalRegistryScript = `/**
|
||||
* This script stops the local registry for e2e testing purposes.
|
||||
* It is meant to be called in jest's globalTeardown.
|
||||
*/
|
||||
|
||||
/// <reference path="registry.d.ts" />
|
||||
|
||||
export default () => {
|
||||
if (global.stopLocalRegistry) {
|
||||
global.stopLocalRegistry();
|
||||
@ -51,16 +54,27 @@ export default () => {
|
||||
};
|
||||
`;
|
||||
|
||||
const registryDeclarationText = `declare function stopLocalRegistry(): void;
|
||||
`;
|
||||
|
||||
export function addLocalRegistryScripts(tree: Tree) {
|
||||
const startLocalRegistryPath = 'tools/scripts/start-local-registry.ts';
|
||||
const stopLocalRegistryPath = 'tools/scripts/stop-local-registry.ts';
|
||||
const registryDeclarationPath = 'tools/scripts/registry.d.ts';
|
||||
|
||||
const projectConfiguration: ProjectConfiguration = readJson(
|
||||
let projectName: string;
|
||||
try {
|
||||
({ name: projectName } = readJson<ProjectConfiguration>(
|
||||
tree,
|
||||
'project.json'
|
||||
);
|
||||
));
|
||||
} catch {
|
||||
// if project.json doesn't exist, try package.json
|
||||
const { name, nx } = readJson<PackageJson>(tree, 'package.json');
|
||||
projectName = nx?.name ?? name;
|
||||
}
|
||||
|
||||
const localRegistryTarget = `${projectConfiguration.name}:local-registry`;
|
||||
const localRegistryTarget = `${projectName}:local-registry`;
|
||||
if (!tree.exists(startLocalRegistryPath)) {
|
||||
tree.write(
|
||||
startLocalRegistryPath,
|
||||
@ -80,6 +94,9 @@ export function addLocalRegistryScripts(tree: Tree) {
|
||||
if (!tree.exists(stopLocalRegistryPath)) {
|
||||
tree.write(stopLocalRegistryPath, stopLocalRegistryScript);
|
||||
}
|
||||
if (!tree.exists(registryDeclarationPath)) {
|
||||
tree.write(registryDeclarationPath, registryDeclarationText);
|
||||
}
|
||||
|
||||
return { startLocalRegistryPath, stopLocalRegistryPath };
|
||||
}
|
||||
|
||||
62
packages/js/src/utils/generator-prompts.ts
Normal file
62
packages/js/src/utils/generator-prompts.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { promptWhenInteractive } from '@nx/devkit/src/generators/prompt';
|
||||
import { isUsingTsSolutionSetup } from './typescript/ts-solution-setup';
|
||||
|
||||
export async function normalizeLinterOption(
|
||||
tree: Tree,
|
||||
linter: undefined | 'none' | 'eslint'
|
||||
): Promise<'none' | 'eslint'> {
|
||||
if (linter) {
|
||||
return linter;
|
||||
}
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
const choices = isTsSolutionSetup
|
||||
? [{ name: 'none' }, { name: 'eslint' }]
|
||||
: [{ name: 'eslint' }, { name: 'none' }];
|
||||
const defaultValue = isTsSolutionSetup ? 'none' : 'eslint';
|
||||
|
||||
return await promptWhenInteractive<{
|
||||
linter: 'none' | 'eslint';
|
||||
}>(
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'linter',
|
||||
message: `Which linter would you like to use?`,
|
||||
choices,
|
||||
initial: 0,
|
||||
},
|
||||
{ linter: defaultValue }
|
||||
).then(({ linter }) => linter);
|
||||
}
|
||||
|
||||
export async function normalizeUnitTestRunnerOption<
|
||||
T extends 'none' | 'jest' | 'vitest'
|
||||
>(
|
||||
tree: Tree,
|
||||
unitTestRunner: undefined | T,
|
||||
testRunners: Array<'jest' | 'vitest'> = ['jest', 'vitest']
|
||||
): Promise<T> {
|
||||
if (unitTestRunner) {
|
||||
return unitTestRunner;
|
||||
}
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
const choices = isTsSolutionSetup
|
||||
? [{ name: 'none' }, ...testRunners.map((runner) => ({ name: runner }))]
|
||||
: [...testRunners.map((runner) => ({ name: runner })), { name: 'none' }];
|
||||
const defaultValue = (isTsSolutionSetup ? 'none' : testRunners[0]) as T;
|
||||
|
||||
return await promptWhenInteractive<{
|
||||
unitTestRunner: T;
|
||||
}>(
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'unitTestRunner',
|
||||
message: `Which unit test runner would you like to use?`,
|
||||
choices,
|
||||
initial: 0,
|
||||
},
|
||||
{ unitTestRunner: defaultValue }
|
||||
).then(({ unitTestRunner }) => unitTestRunner);
|
||||
}
|
||||
2
packages/js/src/utils/schema.d.ts
vendored
2
packages/js/src/utils/schema.d.ts
vendored
@ -19,12 +19,14 @@ export interface ExecutorOptions {
|
||||
externalBuildTargets?: string[];
|
||||
generateLockfile?: boolean;
|
||||
stripLeadingPaths?: boolean;
|
||||
generatePackageJson?: boolean;
|
||||
}
|
||||
|
||||
export interface NormalizedExecutorOptions extends ExecutorOptions {
|
||||
rootDir: string;
|
||||
projectRoot: string;
|
||||
mainOutputPath: string;
|
||||
generatePackageJson: boolean;
|
||||
files: Array<FileInputOutput>;
|
||||
root?: string;
|
||||
sourceRoot?: string;
|
||||
|
||||
@ -42,6 +42,8 @@ export interface PackageJson {
|
||||
type?: 'module' | 'commonjs';
|
||||
main?: string;
|
||||
types?: string;
|
||||
// interchangeable with `types`: https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#including-declarations-in-your-npm-package
|
||||
typings?: string;
|
||||
module?: string;
|
||||
exports?:
|
||||
| string
|
||||
|
||||
@ -20,8 +20,8 @@ import {
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { resolveImportPath } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { promptWhenInteractive } from '@nx/devkit/src/generators/prompt';
|
||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import { normalizeLinterOption } from '@nx/js/src/utils/generator-prompts';
|
||||
import {
|
||||
getProjectPackageManagerWorkspaceState,
|
||||
getProjectPackageManagerWorkspaceStateWarningTask,
|
||||
@ -216,36 +216,7 @@ async function normalizeOptions(
|
||||
(process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false);
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
|
||||
let linter = options.linter;
|
||||
if (isTsSolutionSetup) {
|
||||
linter ??= await promptWhenInteractive<{
|
||||
linter: 'none' | 'eslint';
|
||||
}>(
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'linter',
|
||||
message: `Which linter would you like to use?`,
|
||||
choices: [{ name: 'none' }, { name: 'eslint' }],
|
||||
initial: 0,
|
||||
},
|
||||
{ linter: 'none' }
|
||||
).then(({ linter }) => linter);
|
||||
} else {
|
||||
linter ??= await promptWhenInteractive<{
|
||||
linter: 'none' | 'eslint';
|
||||
}>(
|
||||
{
|
||||
type: 'autocomplete',
|
||||
name: 'linter',
|
||||
message: `Which linter would you like to use?`,
|
||||
choices: [{ name: 'eslint' }, { name: 'none' }],
|
||||
initial: 0,
|
||||
},
|
||||
{ linter: 'eslint' }
|
||||
).then(({ linter }) => linter);
|
||||
}
|
||||
const linter = await normalizeLinterOption(tree, options.linter);
|
||||
|
||||
return {
|
||||
...options,
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
"extends": ["@nx/workspace"],
|
||||
"generators": {
|
||||
"plugin": {
|
||||
"factory": "./src/generators/plugin/plugin",
|
||||
"factory": "./src/generators/plugin/plugin#pluginGeneratorInternal",
|
||||
"schema": "./src/generators/plugin/schema.json",
|
||||
"description": "Create a Nx Plugin."
|
||||
},
|
||||
"create-package": {
|
||||
"factory": "./src/generators/create-package/create-package",
|
||||
"factory": "./src/generators/create-package/create-package#createPackageGeneratorInternal",
|
||||
"schema": "./src/generators/create-package/schema.json",
|
||||
"description": "Create a package which can be used by npx to create a new workspace"
|
||||
},
|
||||
@ -39,7 +39,7 @@
|
||||
"description": "Adds linting configuration to validate common json files for nx plugins."
|
||||
},
|
||||
"preset": {
|
||||
"factory": "./src/generators/preset/generator",
|
||||
"factory": "./src/generators/preset/generator#presetGeneratorInternal",
|
||||
"schema": "./src/generators/preset/schema.json",
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-workspace --preset @nx/plugin`.",
|
||||
"hidden": true,
|
||||
|
||||
@ -13,22 +13,36 @@ import {
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||
import {
|
||||
getProjectPackageManagerWorkspaceState,
|
||||
getProjectPackageManagerWorkspaceStateWarningTask,
|
||||
} from '@nx/js/src/utils/package-manager-workspaces';
|
||||
import { addTsLibDependencies } from '@nx/js/src/utils/typescript/add-tslib-dependencies';
|
||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { tsLibVersion } from '@nx/js/src/utils/versions';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { nxVersion } from 'nx/src/utils/versions';
|
||||
import generatorGenerator from '../generator/generator';
|
||||
import { join } from 'path';
|
||||
import { hasGenerator } from '../../utils/has-generator';
|
||||
import { generatorGenerator } from '../generator/generator';
|
||||
import { CreatePackageSchema } from './schema';
|
||||
import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema';
|
||||
import { hasGenerator } from '../../utils/has-generator';
|
||||
import { join } from 'path';
|
||||
import { tsLibVersion } from '@nx/js/src/utils/versions';
|
||||
|
||||
export async function createPackageGenerator(
|
||||
host: Tree,
|
||||
schema: CreatePackageSchema
|
||||
) {
|
||||
assertNotUsingTsSolutionSetup(host, 'plugin', 'create-package');
|
||||
return await createPackageGeneratorInternal(host, {
|
||||
useProjectJson: true,
|
||||
addPlugin: false,
|
||||
...schema,
|
||||
});
|
||||
}
|
||||
|
||||
export async function createPackageGeneratorInternal(
|
||||
host: Tree,
|
||||
schema: CreatePackageSchema
|
||||
) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
const options = await normalizeSchema(host, schema);
|
||||
@ -56,6 +70,20 @@ export async function createPackageGenerator(
|
||||
await formatFiles(host);
|
||||
}
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
const projectPackageManagerWorkspaceState =
|
||||
getProjectPackageManagerWorkspaceState(host, options.projectRoot);
|
||||
|
||||
if (projectPackageManagerWorkspaceState !== 'included') {
|
||||
tasks.push(
|
||||
getProjectPackageManagerWorkspaceStateWarningTask(
|
||||
projectPackageManagerWorkspaceState,
|
||||
host.root
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
@ -73,9 +101,10 @@ async function addPresetGenerator(
|
||||
if (!hasGenerator(host, schema.project, 'preset')) {
|
||||
await generatorGenerator(host, {
|
||||
name: 'preset',
|
||||
path: join(projectRoot, 'src/generators/preset'),
|
||||
path: join(projectRoot, 'src/generators/preset/generator'),
|
||||
unitTestRunner: schema.unitTestRunner,
|
||||
skipFormat: true,
|
||||
skipLintChecks: schema.linter === 'none',
|
||||
});
|
||||
}
|
||||
|
||||
@ -97,18 +126,30 @@ async function createCliPackage(
|
||||
importPath: options.name,
|
||||
skipFormat: true,
|
||||
skipTsConfig: true,
|
||||
useTscExecutor: true,
|
||||
skipWorkspacesWarning: true,
|
||||
});
|
||||
|
||||
host.delete(joinPathFragments(options.projectRoot, 'src'));
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
|
||||
// Add the bin entry to the package.json
|
||||
updateJson(
|
||||
updateJson<PackageJson>(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
(packageJson) => {
|
||||
packageJson.bin = {
|
||||
[options.name]: './bin/index.js',
|
||||
};
|
||||
if (isTsSolutionSetup) {
|
||||
packageJson.bin[options.name] = './dist/bin/index.js';
|
||||
// this package only exposes a binary entry point and no JS programmatic API
|
||||
delete packageJson.main;
|
||||
delete packageJson.types;
|
||||
delete packageJson.typings;
|
||||
delete packageJson.exports;
|
||||
}
|
||||
packageJson.dependencies = {
|
||||
'create-nx-workspace': nxVersion,
|
||||
...(options.bundler === 'tsc' && { tslib: tsLibVersion }),
|
||||
@ -131,14 +172,23 @@ async function createCliPackage(
|
||||
'bin/index.ts'
|
||||
);
|
||||
projectConfiguration.implicitDependencies = [options.project];
|
||||
if (options.isTsSolutionSetup) {
|
||||
if (options.bundler === 'tsc') {
|
||||
projectConfiguration.targets.build.options.generatePackageJson = false;
|
||||
} else if (options.bundler === 'swc') {
|
||||
delete projectConfiguration.targets.build.options.stripLeadingPaths;
|
||||
}
|
||||
}
|
||||
updateProjectConfiguration(host, options.projectName, projectConfiguration);
|
||||
|
||||
// Add bin files to tsconfg.lib.json
|
||||
// Add bin files and update rootDir in tsconfg.lib.json
|
||||
updateJson(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
||||
(tsConfig) => {
|
||||
tsConfig.include.push('bin/**/*.ts');
|
||||
tsConfig.compilerOptions ??= {};
|
||||
tsConfig.compilerOptions.rootDir = '.';
|
||||
return tsConfig;
|
||||
}
|
||||
);
|
||||
|
||||
@ -11,8 +11,9 @@ async function main() {
|
||||
console.log(`Creating the workspace: ${name}`);
|
||||
|
||||
// This assumes "<%= preset %>" and "<%= projectName %>" are at the same version
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const presetVersion = require('../package.json').version;
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires<% if (isTsSolutionSetup) { %>
|
||||
const presetVersion = require('../../package.json').version;<% } else { %>
|
||||
const presetVersion = require('../package.json').version;<% } %>
|
||||
|
||||
// TODO: update below to customize the workspace
|
||||
const { directory } = await createWorkspace(
|
||||
|
||||
@ -6,12 +6,15 @@ export interface CreatePackageSchema {
|
||||
directory: string;
|
||||
|
||||
// options to create cli package, passed to js library generator
|
||||
skipFormat: boolean;
|
||||
skipFormat?: boolean;
|
||||
tags?: string;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
linter: Linter | LinterType;
|
||||
compiler: 'swc' | 'tsc';
|
||||
unitTestRunner?: 'jest' | 'none';
|
||||
linter?: Linter | LinterType;
|
||||
compiler?: 'swc' | 'tsc';
|
||||
|
||||
// options to create e2e project, passed to e2e project generator
|
||||
e2eProject?: string;
|
||||
|
||||
useProjectJson?: boolean;
|
||||
addPlugin?: boolean;
|
||||
}
|
||||
|
||||
@ -33,15 +33,13 @@
|
||||
},
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests.",
|
||||
"default": "jest"
|
||||
"enum": ["none", "jest"],
|
||||
"description": "Test runner to use for unit tests."
|
||||
},
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint"],
|
||||
"default": "eslint"
|
||||
"enum": ["none", "eslint"]
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
@ -64,6 +62,10 @@
|
||||
"type": "string",
|
||||
"description": "The name of the e2e project.",
|
||||
"x-prompt": "What is the name of the e2e project? Leave blank to skip e2e tests"
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["directory", "name", "project"]
|
||||
|
||||
@ -1,17 +1,35 @@
|
||||
import { readProjectConfiguration, Tree } from '@nx/devkit';
|
||||
import { readNxJson, Tree } from '@nx/devkit';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import type { LinterType } from '@nx/eslint';
|
||||
import {
|
||||
normalizeLinterOption,
|
||||
normalizeUnitTestRunnerOption,
|
||||
} from '@nx/js/src/utils/generator-prompts';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { CreatePackageSchema } from '../schema';
|
||||
|
||||
export interface NormalizedSchema extends CreatePackageSchema {
|
||||
bundler: 'swc' | 'tsc';
|
||||
projectName: string;
|
||||
projectRoot: string;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
linter: LinterType;
|
||||
useProjectJson: boolean;
|
||||
addPlugin: boolean;
|
||||
isTsSolutionSetup: boolean;
|
||||
}
|
||||
|
||||
export async function normalizeSchema(
|
||||
host: Tree,
|
||||
schema: CreatePackageSchema
|
||||
): Promise<NormalizedSchema> {
|
||||
const linter = await normalizeLinterOption(host, schema.linter);
|
||||
const unitTestRunner = await normalizeUnitTestRunnerOption(
|
||||
host,
|
||||
schema.unitTestRunner,
|
||||
['jest']
|
||||
);
|
||||
|
||||
if (!schema.directory) {
|
||||
throw new Error(
|
||||
`Please provide the --directory option. It should be the directory containing the project '${schema.project}'.`
|
||||
@ -27,11 +45,25 @@ export async function normalizeSchema(
|
||||
directory: schema.directory,
|
||||
});
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
const nxJson = readNxJson(host);
|
||||
const addPlugin =
|
||||
schema.addPlugin ??
|
||||
(isTsSolutionSetup &&
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false);
|
||||
|
||||
return {
|
||||
...schema,
|
||||
bundler: schema.compiler ?? 'tsc',
|
||||
projectName,
|
||||
projectRoot,
|
||||
name: projectNames.projectSimpleName,
|
||||
linter,
|
||||
unitTestRunner,
|
||||
// We default to generate a project.json file if the new setup is not being used
|
||||
useProjectJson: schema.useProjectJson ?? !isTsSolutionSetup,
|
||||
addPlugin,
|
||||
isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,12 +1,8 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
extractLayoutDirectory,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorCallback,
|
||||
getPackageManagerCommand,
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
@ -14,15 +10,29 @@ import {
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
type GeneratorCallback,
|
||||
type ProjectConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
resolveImportPath,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { LinterType, lintProjectGenerator } from '@nx/eslint';
|
||||
import { addPropertyToJestConfig, configurationGenerator } from '@nx/jest';
|
||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import { setupVerdaccio } from '@nx/js/src/generators/setup-verdaccio/generator';
|
||||
import { addLocalRegistryScripts } from '@nx/js/src/utils/add-local-registry-scripts';
|
||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { Linter, LinterType, lintProjectGenerator } from '@nx/eslint';
|
||||
import { normalizeLinterOption } from '@nx/js/src/utils/generator-prompts';
|
||||
import {
|
||||
getProjectPackageManagerWorkspaceState,
|
||||
getProjectPackageManagerWorkspaceStateWarningTask,
|
||||
} from '@nx/js/src/utils/package-manager-workspaces';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { join } from 'path';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
@ -30,21 +40,25 @@ interface NormalizedSchema extends Schema {
|
||||
projectRoot: string;
|
||||
projectName: string;
|
||||
pluginPropertyName: string;
|
||||
linter: Linter | LinterType;
|
||||
linter: LinterType;
|
||||
useProjectJson: boolean;
|
||||
addPlugin: boolean;
|
||||
isTsSolutionSetup: boolean;
|
||||
}
|
||||
|
||||
async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
const linter = await normalizeLinterOption(host, options.linter);
|
||||
|
||||
const projectName = options.rootProject ? 'e2e' : `${options.pluginName}-e2e`;
|
||||
|
||||
const nxJson = readNxJson(host);
|
||||
const addPlugin =
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false;
|
||||
|
||||
options.addPlugin ??= addPlugin;
|
||||
options.addPlugin ??
|
||||
(process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false);
|
||||
|
||||
let projectRoot: string;
|
||||
const projectNameAndRootOptions = await determineProjectNameAndRootOptions(
|
||||
@ -61,13 +75,17 @@ async function normalizeOptions(
|
||||
projectRoot = projectNameAndRootOptions.projectRoot;
|
||||
|
||||
const pluginPropertyName = names(options.pluginName).propertyName;
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
|
||||
return {
|
||||
...options,
|
||||
projectName,
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
linter,
|
||||
pluginPropertyName,
|
||||
projectRoot,
|
||||
addPlugin,
|
||||
useProjectJson: options.useProjectJson ?? !isTsSolutionSetup,
|
||||
isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
@ -99,13 +117,29 @@ function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
async function addJest(host: Tree, options: NormalizedSchema) {
|
||||
addProjectConfiguration(host, options.projectName, {
|
||||
const projectConfiguration: ProjectConfiguration = {
|
||||
name: options.projectName,
|
||||
root: options.projectRoot,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.projectRoot}/src`,
|
||||
targets: {},
|
||||
implicitDependencies: [options.pluginName],
|
||||
});
|
||||
};
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
writeJson<PackageJson>(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
{
|
||||
name: resolveImportPath(host, options.projectName, options.projectRoot),
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
}
|
||||
);
|
||||
updateProjectConfiguration(host, options.projectName, projectConfiguration);
|
||||
} else {
|
||||
projectConfiguration.targets = {};
|
||||
addProjectConfiguration(host, options.projectName, projectConfiguration);
|
||||
}
|
||||
|
||||
const jestTask = await configurationGenerator(host, {
|
||||
project: options.projectName,
|
||||
@ -134,6 +168,7 @@ async function addJest(host: Tree, options: NormalizedSchema) {
|
||||
);
|
||||
|
||||
const project = readProjectConfiguration(host, options.projectName);
|
||||
project.targets ??= {};
|
||||
const e2eTarget = project.targets.e2e;
|
||||
|
||||
project.targets.e2e = {
|
||||
@ -169,16 +204,24 @@ async function addLintingToApplication(
|
||||
return lintTask;
|
||||
}
|
||||
|
||||
function updatePluginPackageJson(tree: Tree, options: NormalizedSchema) {
|
||||
const { root } = readProjectConfiguration(tree, options.pluginName);
|
||||
updateJson(tree, joinPathFragments(root, 'package.json'), (json) => {
|
||||
// to publish the plugin, we need to remove the private flag
|
||||
delete json.private;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
export async function e2eProjectGenerator(host: Tree, schema: Schema) {
|
||||
return await e2eProjectGeneratorInternal(host, {
|
||||
addPlugin: false,
|
||||
useProjectJson: true,
|
||||
...schema,
|
||||
});
|
||||
}
|
||||
|
||||
export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) {
|
||||
assertNotUsingTsSolutionSetup(host, 'plugin', 'e2e-project');
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
validatePlugin(host, schema.pluginName);
|
||||
@ -190,8 +233,9 @@ export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) {
|
||||
})
|
||||
);
|
||||
tasks.push(await addJest(host, options));
|
||||
updatePluginPackageJson(host, options);
|
||||
|
||||
if (options.linter !== Linter.None) {
|
||||
if (options.linter !== 'none') {
|
||||
tasks.push(
|
||||
await addLintingToApplication(host, {
|
||||
...options,
|
||||
@ -199,10 +243,37 @@ export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
if (options.isTsSolutionSetup && !options.rootProject) {
|
||||
// update root tsconfig.json references with the new lib tsconfig
|
||||
updateJson(host, 'tsconfig.json', (json) => {
|
||||
json.references ??= [];
|
||||
json.references.push({
|
||||
path: options.projectRoot.startsWith('./')
|
||||
? options.projectRoot
|
||||
: './' + options.projectRoot,
|
||||
});
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
|
||||
if (options.isTsSolutionSetup && !options.skipWorkspacesWarning) {
|
||||
const projectPackageManagerWorkspaceState =
|
||||
getProjectPackageManagerWorkspaceState(host, options.projectRoot);
|
||||
|
||||
if (projectPackageManagerWorkspaceState !== 'included') {
|
||||
tasks.push(
|
||||
getProjectPackageManagerWorkspaceStateWarningTask(
|
||||
projectPackageManagerWorkspaceState,
|
||||
host.root
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
|
||||
@ -9,5 +9,7 @@ export interface Schema {
|
||||
linter?: Linter | LinterType;
|
||||
skipFormat?: boolean;
|
||||
rootProject?: boolean;
|
||||
useProjectJson?: boolean;
|
||||
addPlugin?: boolean;
|
||||
skipWorkspacesWarning?: boolean;
|
||||
}
|
||||
|
||||
@ -33,8 +33,7 @@
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint", "none"],
|
||||
"default": "eslint"
|
||||
"enum": ["none", "eslint"]
|
||||
},
|
||||
"minimal": {
|
||||
"type": "boolean",
|
||||
@ -46,6 +45,10 @@
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["pluginName", "npmPackageName"]
|
||||
|
||||
@ -28,7 +28,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
it('should generate files', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: false,
|
||||
});
|
||||
@ -52,7 +52,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
unitTestRunner: 'jest',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
includeHasher: false,
|
||||
});
|
||||
|
||||
@ -73,7 +73,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
it('should update executors.json', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: false,
|
||||
});
|
||||
@ -94,7 +94,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
it('should generate custom description', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
description: 'my-executor custom description',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: false,
|
||||
@ -116,7 +116,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
|
||||
await executorGenerator(tree, {
|
||||
name: 'test-executor',
|
||||
path: 'test-js-lib/src/executors/my-executor',
|
||||
path: 'test-js-lib/src/executors/my-executor/executor',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: false,
|
||||
});
|
||||
@ -127,12 +127,56 @@ describe('NxPlugin Executor Generator', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should support custom executor file name', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/my-custom-executor',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: true,
|
||||
});
|
||||
|
||||
expect(
|
||||
tree.exists('my-plugin/src/executors/my-executor/schema.d.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('my-plugin/src/executors/my-executor/schema.json')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('my-plugin/src/executors/my-executor/my-custom-executor.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists(
|
||||
'my-plugin/src/executors/my-executor/my-custom-executor.spec.ts'
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('my-plugin/src/executors/my-executor/hasher.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('my-plugin/src/executors/my-executor/hasher.spec.ts')
|
||||
).toBeTruthy();
|
||||
expect(tree.read('my-plugin/executors.json', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"{
|
||||
"executors": {
|
||||
"my-executor": {
|
||||
"implementation": "./src/executors/my-executor/my-custom-executor",
|
||||
"schema": "./src/executors/my-executor/schema.json",
|
||||
"description": "my-executor executor",
|
||||
"hasher": "./src/executors/my-executor/hasher"
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
describe('--unitTestRunner', () => {
|
||||
describe('none', () => {
|
||||
it('should not generate unit test files', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
unitTestRunner: 'none',
|
||||
includeHasher: false,
|
||||
});
|
||||
@ -151,7 +195,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
it('should generate hasher files', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: true,
|
||||
});
|
||||
@ -180,7 +224,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
it('should update executors.json', async () => {
|
||||
await executorGenerator(tree, {
|
||||
name: 'my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor',
|
||||
path: 'my-plugin/src/executors/my-executor/executor',
|
||||
unitTestRunner: 'jest',
|
||||
includeHasher: true,
|
||||
});
|
||||
|
||||
@ -1,49 +1,54 @@
|
||||
import {
|
||||
readProjectConfiguration,
|
||||
names,
|
||||
generateFiles,
|
||||
updateJson,
|
||||
joinPathFragments,
|
||||
writeJson,
|
||||
readJson,
|
||||
ExecutorsJson,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
names,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
updateJson,
|
||||
writeJson,
|
||||
type ExecutorsJson,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import type { Schema } from './schema';
|
||||
import * as path from 'path';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
import pluginLintCheckGenerator from '../lint-checks/generator';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { relative } from 'path';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { join } from 'path';
|
||||
import { getArtifactMetadataDirectory } from '../../utils/paths';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import pluginLintCheckGenerator from '../lint-checks/generator';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
interface NormalizedSchema extends Schema {
|
||||
className: string;
|
||||
propertyName: string;
|
||||
projectRoot: string;
|
||||
filePath: string;
|
||||
projectSourceRoot: string;
|
||||
fileName: string;
|
||||
directory: string;
|
||||
project: string;
|
||||
isTsSolutionSetup: boolean;
|
||||
}
|
||||
|
||||
function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(host, path.join(__dirname, './files/executor'), options.path, {
|
||||
generateFiles(host, join(__dirname, './files/executor'), options.directory, {
|
||||
...options,
|
||||
});
|
||||
|
||||
if (options.unitTestRunner === 'none') {
|
||||
host.delete(joinPathFragments(options.path, `executor.spec.ts`));
|
||||
host.delete(
|
||||
joinPathFragments(options.directory, `${options.fileName}.spec.ts`)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function addHasherFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(host, path.join(__dirname, './files/hasher'), options.path, {
|
||||
generateFiles(host, join(__dirname, './files/hasher'), options.directory, {
|
||||
...options,
|
||||
});
|
||||
|
||||
if (options.unitTestRunner === 'none') {
|
||||
host.delete(joinPathFragments(options.path, 'hasher.spec.ts'));
|
||||
host.delete(joinPathFragments(options.directory, 'hasher.spec.ts'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,6 +101,19 @@ async function updateExecutorJson(host: Tree, options: NormalizedSchema) {
|
||||
options.project,
|
||||
options.skipLintChecks
|
||||
);
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
updateJson<PackageJson>(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
const filesSet = new Set(json.files ?? ['dist', '!**/*.tsbuildinfo']);
|
||||
filesSet.add('executors.json');
|
||||
json.files = [...filesSet];
|
||||
return json;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// add dependencies
|
||||
updateJson<PackageJson>(
|
||||
@ -113,22 +131,20 @@ async function updateExecutorJson(host: Tree, options: NormalizedSchema) {
|
||||
return updateJson(host, executorsPath, (json) => {
|
||||
let executors = json.executors ?? json.builders;
|
||||
executors ||= {};
|
||||
|
||||
const dir = getArtifactMetadataDirectory(
|
||||
host,
|
||||
options.project,
|
||||
options.directory,
|
||||
options.isTsSolutionSetup
|
||||
);
|
||||
executors[options.name] = {
|
||||
implementation: `./${joinPathFragments(
|
||||
relative(options.projectRoot, options.path),
|
||||
'executor'
|
||||
)}`,
|
||||
schema: `./${joinPathFragments(
|
||||
relative(options.projectRoot, options.path),
|
||||
'schema.json'
|
||||
)}`,
|
||||
implementation: `${dir}/${options.fileName}`,
|
||||
schema: `${dir}/schema.json`,
|
||||
description: options.description,
|
||||
};
|
||||
if (options.includeHasher) {
|
||||
executors[options.name].hasher = `./${joinPathFragments(
|
||||
relative(options.projectRoot, options.path),
|
||||
'hasher'
|
||||
)}`;
|
||||
executors[options.name].hasher = `${dir}/hasher`;
|
||||
}
|
||||
json.executors = executors;
|
||||
|
||||
@ -140,33 +156,40 @@ async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
const { project, artifactName, filePath, directory } =
|
||||
await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
name: options.name,
|
||||
const {
|
||||
artifactName: name,
|
||||
directory,
|
||||
fileName,
|
||||
project,
|
||||
} = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: options.path,
|
||||
fileName: 'executor',
|
||||
name: options.name,
|
||||
});
|
||||
|
||||
const { className, propertyName } = names(artifactName);
|
||||
const { className, propertyName } = names(name);
|
||||
|
||||
const { root: projectRoot } = readProjectConfiguration(tree, project);
|
||||
const { root: projectRoot, sourceRoot: projectSourceRoot } =
|
||||
readProjectConfiguration(tree, project);
|
||||
|
||||
let description: string;
|
||||
if (options.description) {
|
||||
description = options.description;
|
||||
} else {
|
||||
description = `${options.name} executor`;
|
||||
description = `${name} executor`;
|
||||
}
|
||||
|
||||
return {
|
||||
...options,
|
||||
filePath,
|
||||
fileName,
|
||||
project,
|
||||
directory,
|
||||
name,
|
||||
className,
|
||||
propertyName,
|
||||
description,
|
||||
projectRoot,
|
||||
projectSourceRoot,
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
|
||||
import { <%= className %>ExecutorSchema } from './schema';
|
||||
import executor from './executor';
|
||||
import executor from './<%= fileName %>';
|
||||
|
||||
const options: <%= className %>ExecutorSchema = {};
|
||||
const context: ExecutorContext = {
|
||||
@ -1,7 +1,7 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { Tree, readProjectConfiguration } from '@nx/devkit';
|
||||
|
||||
import { <%= generatorFnName %> } from './generator';
|
||||
import { <%= generatorFnName %> } from './<%= fileName %>';
|
||||
import { <%= schemaInterfaceName %> } from './schema';
|
||||
|
||||
describe('<%= name %> generator', () => {
|
||||
@ -32,7 +32,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
it('should generate files', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
|
||||
@ -54,7 +54,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
setCwd('my-plugin/src/nx-integrations/generators/my-generator');
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/nx-integrations/generators/my-generator',
|
||||
path: 'my-plugin/src/nx-integrations/generators/my-generator/generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
|
||||
@ -82,7 +82,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
|
||||
it('should generate files for derived', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
path: `${projectName}/src/generators/my-generator`,
|
||||
path: `${projectName}/src/generators/my-generator/generator`,
|
||||
name: 'my-generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
@ -104,7 +104,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
it('should update generators.json', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
|
||||
@ -123,7 +123,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
|
||||
it('should update generators.json for derived', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
name: 'my-generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
@ -144,12 +144,12 @@ describe('NxPlugin Generator Generator', () => {
|
||||
it('should throw if recreating an existing generator', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
expect(
|
||||
generatorGenerator(tree, {
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
name: 'my-generator',
|
||||
unitTestRunner: 'jest',
|
||||
})
|
||||
@ -162,7 +162,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
|
||||
await generatorGenerator(tree, {
|
||||
name: generatorName,
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
unitTestRunner: 'jest',
|
||||
description: 'my-generator description',
|
||||
});
|
||||
@ -192,7 +192,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
const libConfig = readProjectConfiguration(tree, 'test-js-lib');
|
||||
await generatorGenerator(tree, {
|
||||
name: 'test-generator',
|
||||
path: 'test-js-lib/src/generators/test-generator',
|
||||
path: 'test-js-lib/src/generators/test-generator/generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
|
||||
@ -207,7 +207,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
it('should generate custom description', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
description: 'my-generator custom description',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
@ -219,12 +219,50 @@ describe('NxPlugin Generator Generator', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should support custom generator file name', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/my-custom-generator',
|
||||
unitTestRunner: 'jest',
|
||||
});
|
||||
|
||||
expect(
|
||||
tree.exists('my-plugin/src/generators/my-generator/schema.d.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('my-plugin/src/generators/my-generator/schema.json')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists(
|
||||
'my-plugin/src/generators/my-generator/my-custom-generator.ts'
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists(
|
||||
'my-plugin/src/generators/my-generator/my-custom-generator.spec.ts'
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(tree.read('my-plugin/generators.json', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"{
|
||||
"generators": {
|
||||
"my-generator": {
|
||||
"factory": "./src/generators/my-generator/my-custom-generator",
|
||||
"schema": "./src/generators/my-generator/schema.json",
|
||||
"description": "my-generator generator"
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
describe('--unitTestRunner', () => {
|
||||
describe('none', () => {
|
||||
it('should not generate files', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
name: 'my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator',
|
||||
path: 'my-plugin/src/generators/my-generator/generator',
|
||||
unitTestRunner: 'none',
|
||||
});
|
||||
|
||||
@ -241,7 +279,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
describe('preset generator', () => {
|
||||
it('should default to standalone layout: true', async () => {
|
||||
await generatorGenerator(tree, {
|
||||
path: 'my-plugin/src/generators/preset',
|
||||
path: 'my-plugin/src/generators/preset/generator',
|
||||
name: 'preset',
|
||||
unitTestRunner: 'none',
|
||||
});
|
||||
|
||||
@ -1,22 +1,24 @@
|
||||
import {
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorsJson,
|
||||
joinPathFragments,
|
||||
Tree,
|
||||
writeJson,
|
||||
generateFiles,
|
||||
names,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { join } from 'node:path';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { hasGenerator } from '../../utils/has-generator';
|
||||
import { getArtifactMetadataDirectory } from '../../utils/paths';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import pluginLintCheckGenerator from '../lint-checks/generator';
|
||||
import type { Schema } from './schema';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { join, relative } from 'path';
|
||||
|
||||
type NormalizedSchema = Schema & {
|
||||
directory: string;
|
||||
@ -26,20 +28,24 @@ type NormalizedSchema = Schema & {
|
||||
projectRoot: string;
|
||||
projectSourceRoot: string;
|
||||
project: string;
|
||||
isTsSolutionSetup: boolean;
|
||||
};
|
||||
|
||||
async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
const { project, fileName, artifactName, filePath, directory } =
|
||||
await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
name: options.name,
|
||||
const {
|
||||
artifactName: name,
|
||||
directory,
|
||||
fileName,
|
||||
project,
|
||||
} = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: options.path,
|
||||
fileName: 'generator',
|
||||
name: options.name,
|
||||
});
|
||||
|
||||
const { className, propertyName } = names(artifactName);
|
||||
const { className, propertyName } = names(name);
|
||||
|
||||
const { root: projectRoot, sourceRoot: projectSourceRoot } =
|
||||
readProjectConfiguration(tree, project);
|
||||
@ -48,37 +54,39 @@ async function normalizeOptions(
|
||||
if (options.description) {
|
||||
description = options.description;
|
||||
} else {
|
||||
description = `${options.name} generator`;
|
||||
description = `${name} generator`;
|
||||
}
|
||||
|
||||
return {
|
||||
...options,
|
||||
directory,
|
||||
project,
|
||||
name,
|
||||
fileName,
|
||||
className,
|
||||
propertyName,
|
||||
description,
|
||||
projectRoot,
|
||||
projectSourceRoot,
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
}
|
||||
|
||||
function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
const indexPath = join(options.path, 'files/src/index.ts.template');
|
||||
const indexPath = join(options.directory, 'files/src/index.ts.template');
|
||||
|
||||
if (!host.exists(indexPath)) {
|
||||
host.write(indexPath, 'const variable = "<%= name %>";');
|
||||
}
|
||||
|
||||
generateFiles(host, join(__dirname, './files/generator'), options.path, {
|
||||
generateFiles(host, join(__dirname, './files/generator'), options.directory, {
|
||||
...options,
|
||||
generatorFnName: `${options.propertyName}Generator`,
|
||||
schemaInterfaceName: `${options.className}GeneratorSchema`,
|
||||
});
|
||||
|
||||
if (options.unitTestRunner === 'none') {
|
||||
host.delete(join(options.path, `generator.spec.ts`));
|
||||
host.delete(join(options.directory, `${options.fileName}.spec.ts`));
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +142,19 @@ async function updateGeneratorJson(host: Tree, options: NormalizedSchema) {
|
||||
options.skipLintChecks,
|
||||
options.skipFormat
|
||||
);
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
updateJson<PackageJson>(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
const filesSet = new Set(json.files ?? ['dist', '!**/*.tsbuildinfo']);
|
||||
filesSet.add('generators.json');
|
||||
json.files = [...filesSet];
|
||||
return json;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// add dependencies
|
||||
updateJson<PackageJson>(
|
||||
@ -151,15 +172,16 @@ async function updateGeneratorJson(host: Tree, options: NormalizedSchema) {
|
||||
updateJson<GeneratorsJson>(host, generatorsPath, (json) => {
|
||||
let generators = json.generators ?? json.schematics;
|
||||
generators = generators || {};
|
||||
|
||||
const dir = getArtifactMetadataDirectory(
|
||||
host,
|
||||
options.project,
|
||||
options.directory,
|
||||
options.isTsSolutionSetup
|
||||
);
|
||||
generators[options.name] = {
|
||||
factory: `./${joinPathFragments(
|
||||
relative(options.projectRoot, options.path),
|
||||
'generator'
|
||||
)}`,
|
||||
schema: `./${joinPathFragments(
|
||||
relative(options.projectRoot, options.path),
|
||||
'schema.json'
|
||||
)}`,
|
||||
factory: `${dir}/${options.fileName}`,
|
||||
schema: `${dir}/schema.json`,
|
||||
description: options.description,
|
||||
};
|
||||
// @todo(v17): Remove this, prop is defunct.
|
||||
|
||||
@ -27,7 +27,7 @@ describe('NxPlugin migration generator', () => {
|
||||
|
||||
it('should update the workspace.json file', async () => {
|
||||
await migrationGenerator(tree, {
|
||||
path: `packages/my-plugin/${projectName}`,
|
||||
path: `packages/my-plugin/${projectName}/update-1.0.0`,
|
||||
packageVersion: '1.0.0',
|
||||
});
|
||||
|
||||
@ -43,7 +43,7 @@ describe('NxPlugin migration generator', () => {
|
||||
it('should generate files', async () => {
|
||||
await migrationGenerator(tree, {
|
||||
name: 'my-migration',
|
||||
path: 'packages/my-plugin/migrations/1.0.0',
|
||||
path: 'packages/my-plugin/migrations/1.0.0/my-migration',
|
||||
packageVersion: '1.0.0',
|
||||
});
|
||||
|
||||
@ -71,7 +71,7 @@ describe('NxPlugin migration generator', () => {
|
||||
it('should generate files with default name', async () => {
|
||||
await migrationGenerator(tree, {
|
||||
description: 'my-migration description',
|
||||
path: 'packages/my-plugin/src/migrations/update-1.0.0',
|
||||
path: 'packages/my-plugin/src/migrations/update-1.0.0/update-1.0.0',
|
||||
packageVersion: '1.0.0',
|
||||
});
|
||||
|
||||
@ -91,7 +91,7 @@ describe('NxPlugin migration generator', () => {
|
||||
it('should generate files with default description', async () => {
|
||||
await migrationGenerator(tree, {
|
||||
name: 'my-migration',
|
||||
path: 'packages/my-plugin/src/migrations/update-1.0.0',
|
||||
path: 'packages/my-plugin/src/migrations/update-1.0.0/update-1.0.0',
|
||||
packageVersion: '1.0.0',
|
||||
});
|
||||
|
||||
@ -105,7 +105,7 @@ describe('NxPlugin migration generator', () => {
|
||||
it('should generate files with package.json updates', async () => {
|
||||
await migrationGenerator(tree, {
|
||||
name: 'my-migration',
|
||||
path: 'packages/my-plugin/src/migrations/update-1.0.0',
|
||||
path: 'packages/my-plugin/src/migrations/update-1.0.0/update-1.0.0',
|
||||
packageVersion: '1.0.0',
|
||||
packageJsonUpdates: true,
|
||||
});
|
||||
|
||||
@ -1,46 +1,44 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import {
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
names,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import type { Schema } from './schema';
|
||||
import * as path from 'path';
|
||||
import { relative } from 'path';
|
||||
import { addMigrationJsonChecks } from '../lint-checks/generator';
|
||||
import { PackageJson, readNxMigrateConfig } from 'nx/src/utils/package-json';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { join } from 'node:path';
|
||||
import { PackageJson, readNxMigrateConfig } from 'nx/src/utils/package-json';
|
||||
import { getArtifactMetadataDirectory } from '../../utils/paths';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { addMigrationJsonChecks } from '../lint-checks/generator';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
interface NormalizedSchema extends Schema {
|
||||
directory: string;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
projectSourceRoot: string;
|
||||
project: string;
|
||||
isTsSolutionSetup: boolean;
|
||||
}
|
||||
|
||||
async function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
let name: string;
|
||||
if (options.name) {
|
||||
name = names(options.name).fileName;
|
||||
} else {
|
||||
name = names(`update-${options.packageVersion}`).fileName;
|
||||
}
|
||||
|
||||
const { project, fileName, artifactName, filePath, directory } =
|
||||
await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
name: name,
|
||||
const {
|
||||
artifactName: name,
|
||||
directory,
|
||||
fileName,
|
||||
project,
|
||||
} = await determineArtifactNameAndDirectoryOptions(tree, {
|
||||
path: options.path,
|
||||
fileName: name,
|
||||
name: options.name,
|
||||
});
|
||||
|
||||
const { root: projectRoot, sourceRoot: projectSourceRoot } =
|
||||
@ -49,24 +47,23 @@ async function normalizeOptions(
|
||||
const description: string =
|
||||
options.description ?? `Migration for v${options.packageVersion}`;
|
||||
|
||||
// const { root: projectRoot, sourceRoot: projectSourceRoot } =
|
||||
// readProjectConfiguration(host, options.project);
|
||||
|
||||
const normalized: NormalizedSchema = {
|
||||
...options,
|
||||
directory,
|
||||
fileName,
|
||||
project,
|
||||
name: artifactName,
|
||||
name,
|
||||
description,
|
||||
projectRoot,
|
||||
projectSourceRoot,
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
generateFiles(host, path.join(__dirname, 'files/migration'), options.path, {
|
||||
generateFiles(host, join(__dirname, 'files/migration'), options.directory, {
|
||||
...options,
|
||||
tmpl: '',
|
||||
});
|
||||
@ -88,13 +85,17 @@ function updateMigrationsJson(host: Tree, options: NormalizedSchema) {
|
||||
: {};
|
||||
|
||||
const generators = migrations.generators ?? {};
|
||||
|
||||
const dir = getArtifactMetadataDirectory(
|
||||
host,
|
||||
options.project,
|
||||
options.directory,
|
||||
options.isTsSolutionSetup
|
||||
);
|
||||
generators[options.name] = {
|
||||
version: options.packageVersion,
|
||||
description: options.description,
|
||||
implementation: `./${joinPathFragments(
|
||||
relative(options.projectRoot, options.path),
|
||||
options.name
|
||||
)}`,
|
||||
implementation: `${dir}/${options.fileName}`,
|
||||
};
|
||||
migrations.generators = generators;
|
||||
|
||||
@ -115,20 +116,30 @@ function updateMigrationsJson(host: Tree, options: NormalizedSchema) {
|
||||
function updatePackageJson(host: Tree, options: NormalizedSchema) {
|
||||
updateJson<PackageJson>(
|
||||
host,
|
||||
path.join(options.projectRoot, 'package.json'),
|
||||
join(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
const addFile = (file: string) => {
|
||||
if (options.isTsSolutionSetup) {
|
||||
const filesSet = new Set(json.files ?? ['dist', '!**/*.tsbuildinfo']);
|
||||
filesSet.add(file.replace(/^\.\//, ''));
|
||||
json.files = [...filesSet];
|
||||
}
|
||||
};
|
||||
|
||||
const migrationKey = json['ng-update'] ? 'ng-update' : 'nx-migrations';
|
||||
const preexistingValue = json[migrationKey];
|
||||
if (typeof preexistingValue === 'string') {
|
||||
if (typeof json[migrationKey] === 'string') {
|
||||
addFile(json[migrationKey]);
|
||||
return json;
|
||||
} else if (!json[migrationKey]) {
|
||||
json[migrationKey] = {
|
||||
migrations: './migrations.json',
|
||||
};
|
||||
} else if (preexistingValue.migrations) {
|
||||
preexistingValue.migrations = './migrations.json';
|
||||
} else if (json[migrationKey].migrations) {
|
||||
json[migrationKey].migrations = './migrations.json';
|
||||
}
|
||||
|
||||
addFile(json[migrationKey].migrations);
|
||||
|
||||
// add dependencies
|
||||
json.dependencies = {
|
||||
'@nx/devkit': nxVersion,
|
||||
@ -141,6 +152,10 @@ function updatePackageJson(host: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
function updateProjectConfig(host: Tree, options: NormalizedSchema) {
|
||||
if (options.isTsSolutionSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const project = readProjectConfiguration(host, options.project);
|
||||
|
||||
const assets = project.targets.build?.options?.assets;
|
||||
@ -164,10 +179,9 @@ export async function migrationGenerator(host: Tree, schema: Schema) {
|
||||
const options = await normalizeOptions(host, schema);
|
||||
|
||||
addFiles(host, options);
|
||||
updatePackageJson(host, options);
|
||||
updateMigrationsJson(host, options);
|
||||
updateProjectConfig(host, options);
|
||||
updateMigrationsJson(host, options);
|
||||
updatePackageJson(host, options);
|
||||
|
||||
if (!host.exists('migrations.json')) {
|
||||
const packageJsonPath = joinPathFragments(
|
||||
|
||||
@ -10,18 +10,22 @@ import {
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||
import {
|
||||
getProjectPackageManagerWorkspaceState,
|
||||
getProjectPackageManagerWorkspaceStateWarningTask,
|
||||
} from '@nx/js/src/utils/package-manager-workspaces';
|
||||
import {
|
||||
addSwcDependencies,
|
||||
addSwcRegisterDependencies,
|
||||
} from '@nx/js/src/utils/swc/add-swc-dependencies';
|
||||
import { addTsLibDependencies } from '@nx/js/src/utils/typescript/add-tslib-dependencies';
|
||||
import * as path from 'path';
|
||||
import { e2eProjectGenerator } from '../e2e-project/e2e';
|
||||
import pluginLintCheckGenerator from '../lint-checks/generator';
|
||||
import { NormalizedSchema, normalizeOptions } from './utils/normalize-schema';
|
||||
import { addTsLibDependencies } from '@nx/js/src/utils/typescript/add-tslib-dependencies';
|
||||
import { addSwcRegisterDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
||||
|
||||
import type { Schema } from './schema';
|
||||
import { NormalizedSchema, normalizeOptions } from './utils/normalize-schema';
|
||||
|
||||
const nxVersion = require('../../../package.json').version;
|
||||
|
||||
@ -43,40 +47,44 @@ function updatePluginConfig(host: Tree, options: NormalizedSchema) {
|
||||
const project = readProjectConfiguration(host, options.name);
|
||||
|
||||
if (project.targets.build) {
|
||||
project.targets.build.options.assets ??= [];
|
||||
if (options.isTsSolutionSetup && options.bundler === 'tsc') {
|
||||
project.targets.build.options.rootDir = project.sourceRoot;
|
||||
project.targets.build.options.generatePackageJson = false;
|
||||
}
|
||||
|
||||
project.targets.build.options.assets = [
|
||||
...(project.targets.build.options.assets ?? []),
|
||||
];
|
||||
|
||||
const root = options.projectRoot === '.' ? '.' : './' + options.projectRoot;
|
||||
project.targets.build.options.assets = [
|
||||
...project.targets.build.options.assets,
|
||||
{
|
||||
input: `${root}/src`,
|
||||
glob: '**/!(*.ts)',
|
||||
output: './src',
|
||||
},
|
||||
{
|
||||
input: `${root}/src`,
|
||||
glob: '**/*.d.ts',
|
||||
output: './src',
|
||||
},
|
||||
{
|
||||
input: root,
|
||||
glob: 'generators.json',
|
||||
output: '.',
|
||||
},
|
||||
{
|
||||
input: root,
|
||||
glob: 'executors.json',
|
||||
output: '.',
|
||||
},
|
||||
];
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
project.targets.build.options.assets.push(
|
||||
{ input: `${root}/src`, glob: '**/!(*.ts)', output: '.' },
|
||||
{ input: `${root}/src`, glob: '**/*.d.ts', output: '.' }
|
||||
);
|
||||
} else {
|
||||
project.targets.build.options.assets.push(
|
||||
{ input: `${root}/src`, glob: '**/!(*.ts)', output: './src' },
|
||||
{ input: `${root}/src`, glob: '**/*.d.ts', output: './src' },
|
||||
{ input: root, glob: 'generators.json', output: '.' },
|
||||
{ input: root, glob: 'executors.json', output: '.' }
|
||||
);
|
||||
}
|
||||
|
||||
updateProjectConfiguration(host, options.name, project);
|
||||
}
|
||||
}
|
||||
|
||||
export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
assertNotUsingTsSolutionSetup(host, 'plugin', 'plugin');
|
||||
export async function pluginGenerator(tree: Tree, schema: Schema) {
|
||||
return await pluginGeneratorInternal(tree, {
|
||||
useProjectJson: true,
|
||||
addPlugin: false,
|
||||
...schema,
|
||||
});
|
||||
}
|
||||
|
||||
export async function pluginGeneratorInternal(host: Tree, schema: Schema) {
|
||||
const options = await normalizeOptions(host, schema);
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
@ -89,7 +97,13 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
bundler: options.bundler,
|
||||
publishable: options.publishable,
|
||||
importPath: options.npmPackageName,
|
||||
linter: options.linter,
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
useProjectJson: options.useProjectJson,
|
||||
addPlugin: options.addPlugin,
|
||||
skipFormat: true,
|
||||
skipWorkspacesWarning: true,
|
||||
useTscExecutor: true,
|
||||
})
|
||||
);
|
||||
|
||||
@ -131,6 +145,10 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
npmPackageName: options.npmPackageName,
|
||||
skipFormat: true,
|
||||
rootProject: options.rootProject,
|
||||
linter: options.linter,
|
||||
useProjectJson: options.useProjectJson,
|
||||
addPlugin: options.addPlugin,
|
||||
skipWorkspacesWarning: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -143,6 +161,20 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
|
||||
if (options.isTsSolutionSetup) {
|
||||
const projectPackageManagerWorkspaceState =
|
||||
getProjectPackageManagerWorkspaceState(host, options.projectRoot);
|
||||
|
||||
if (projectPackageManagerWorkspaceState !== 'included') {
|
||||
tasks.push(
|
||||
getProjectPackageManagerWorkspaceStateWarningTask(
|
||||
projectPackageManagerWorkspaceState,
|
||||
host.root
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
|
||||
@ -9,10 +9,12 @@ export interface Schema {
|
||||
skipLintChecks?: boolean; // default is false
|
||||
e2eTestRunner?: 'jest' | 'none';
|
||||
tags?: string;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
linter: Linter | LinterType;
|
||||
unitTestRunner?: 'jest' | 'none';
|
||||
linter?: Linter | LinterType;
|
||||
setParserOptionsProject?: boolean;
|
||||
compiler: 'swc' | 'tsc';
|
||||
compiler?: 'swc' | 'tsc';
|
||||
rootProject?: boolean;
|
||||
publishable?: boolean;
|
||||
useProjectJson?: boolean;
|
||||
addPlugin?: boolean;
|
||||
}
|
||||
|
||||
@ -34,14 +34,14 @@
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint"],
|
||||
"default": "eslint"
|
||||
"enum": ["none", "eslint"],
|
||||
"x-priority": "important"
|
||||
},
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests.",
|
||||
"default": "jest"
|
||||
"type": "string",
|
||||
"enum": ["none", "jest"],
|
||||
"x-priority": "important"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
@ -92,6 +92,10 @@
|
||||
"type": "boolean",
|
||||
"description": "Generates a boilerplate for publishing the plugin to npm.",
|
||||
"default": false
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["directory"]
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
import { Tree, extractLayoutDirectory, getWorkspaceLayout } from '@nx/devkit';
|
||||
import { readNxJson, type Tree } from '@nx/devkit';
|
||||
import {
|
||||
determineProjectNameAndRootOptions,
|
||||
ensureProjectName,
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import type { LinterType } from '@nx/eslint';
|
||||
import {
|
||||
normalizeLinterOption,
|
||||
normalizeUnitTestRunnerOption,
|
||||
} from '@nx/js/src/utils/generator-prompts';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import type { Schema } from '../schema';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
@ -14,12 +20,32 @@ export interface NormalizedSchema extends Schema {
|
||||
npmPackageName: string;
|
||||
bundler: 'swc' | 'tsc';
|
||||
publishable: boolean;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
linter: LinterType;
|
||||
useProjectJson: boolean;
|
||||
addPlugin: boolean;
|
||||
isTsSolutionSetup: boolean;
|
||||
}
|
||||
|
||||
export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
const linter = await normalizeLinterOption(host, options.linter);
|
||||
const unitTestRunner = await normalizeUnitTestRunnerOption(
|
||||
host,
|
||||
options.unitTestRunner,
|
||||
['jest']
|
||||
);
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
const nxJson = readNxJson(host);
|
||||
const addPlugin =
|
||||
options.addPlugin ??
|
||||
(isTsSolutionSetup &&
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false);
|
||||
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const {
|
||||
projectName,
|
||||
@ -50,5 +76,11 @@ export async function normalizeOptions(
|
||||
parsedTags,
|
||||
npmPackageName,
|
||||
publishable: options.publishable ?? false,
|
||||
linter,
|
||||
unitTestRunner,
|
||||
// We default to generate a project.json file if the new setup is not being used
|
||||
useProjectJson: options.useProjectJson ?? !isTsSolutionSetup,
|
||||
addPlugin,
|
||||
isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,34 +1,42 @@
|
||||
import {
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
names,
|
||||
readNxJson,
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
updateJson,
|
||||
type GeneratorCallback,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { createPackageGenerator } from '../create-package/create-package';
|
||||
import { pluginGenerator } from '../plugin/plugin';
|
||||
import { PresetGeneratorSchema } from './schema';
|
||||
import createPackageGenerator from '../create-package/create-package';
|
||||
import type {
|
||||
NormalizedPresetGeneratorOptions,
|
||||
PresetGeneratorSchema,
|
||||
} from './schema';
|
||||
|
||||
export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
||||
assertNotUsingTsSolutionSetup(tree, 'plugin', 'preset');
|
||||
export async function presetGenerator(
|
||||
tree: Tree,
|
||||
rawOptions: PresetGeneratorSchema
|
||||
) {
|
||||
return await presetGeneratorInternal(tree, {
|
||||
addPlugin: false,
|
||||
useProjectJson: true,
|
||||
...rawOptions,
|
||||
});
|
||||
}
|
||||
|
||||
export async function presetGeneratorInternal(
|
||||
tree: Tree,
|
||||
rawOptions: PresetGeneratorSchema
|
||||
) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const pluginProjectName = names(
|
||||
options.pluginName.includes('/')
|
||||
? options.pluginName.split('/')[1]
|
||||
: options.pluginName
|
||||
).fileName;
|
||||
options.createPackageName =
|
||||
options.createPackageName === 'false' // for command line in e2e, it is passed as a string
|
||||
? undefined
|
||||
: options.createPackageName;
|
||||
const options = normalizeOptions(tree, rawOptions);
|
||||
|
||||
const pluginTask = await pluginGenerator(tree, {
|
||||
compiler: 'tsc',
|
||||
linter: Linter.EsLint,
|
||||
linter: 'eslint',
|
||||
skipFormat: true,
|
||||
unitTestRunner: 'jest',
|
||||
importPath: options.pluginName,
|
||||
@ -37,9 +45,11 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
||||
// when creating a CLI package, the plugin will be in the packages folder
|
||||
directory:
|
||||
options.createPackageName && options.createPackageName !== 'false'
|
||||
? `packages/${pluginProjectName}`
|
||||
: pluginProjectName,
|
||||
? `packages/${options.pluginName}`
|
||||
: options.pluginName,
|
||||
rootProject: options.createPackageName ? false : true,
|
||||
useProjectJson: options.useProjectJson,
|
||||
addPlugin: options.addPlugin,
|
||||
});
|
||||
tasks.push(pluginTask);
|
||||
|
||||
@ -54,8 +64,10 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
||||
project: options.pluginName,
|
||||
skipFormat: true,
|
||||
unitTestRunner: 'jest',
|
||||
linter: Linter.EsLint,
|
||||
linter: 'eslint',
|
||||
compiler: 'tsc',
|
||||
useProjectJson: options.useProjectJson,
|
||||
addPlugin: options.addPlugin,
|
||||
});
|
||||
tasks.push(cliTask);
|
||||
}
|
||||
@ -67,9 +79,42 @@ export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
||||
|
||||
function moveNxPluginToDevDeps(tree: Tree) {
|
||||
updateJson<PackageJson>(tree, 'package.json', (json) => {
|
||||
if (json.dependencies['@nx/plugin']) {
|
||||
const nxPluginEntry = json.dependencies['@nx/plugin'];
|
||||
delete json.dependencies['@nx/plugin'];
|
||||
json.devDependencies['@nx/plugin'] = nxPluginEntry;
|
||||
}
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: PresetGeneratorSchema
|
||||
): NormalizedPresetGeneratorOptions {
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
|
||||
const nxJson = readNxJson(tree);
|
||||
const addPlugin =
|
||||
options.addPlugin ??
|
||||
(isTsSolutionSetup &&
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false);
|
||||
|
||||
return {
|
||||
...options,
|
||||
pluginName: names(
|
||||
options.pluginName.includes('/')
|
||||
? options.pluginName.split('/')[1]
|
||||
: options.pluginName
|
||||
).fileName,
|
||||
createPackageName:
|
||||
options.createPackageName === 'false' // for command line in e2e, it is passed as a string
|
||||
? undefined
|
||||
: options.createPackageName,
|
||||
addPlugin,
|
||||
useProjectJson: options.useProjectJson ?? !isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
export default presetGenerator;
|
||||
|
||||
@ -1,4 +1,13 @@
|
||||
export interface PresetGeneratorSchema {
|
||||
pluginName: string;
|
||||
createPackageName?: string;
|
||||
useProjectJson?: boolean;
|
||||
addPlugin?: boolean;
|
||||
}
|
||||
|
||||
export interface NormalizedPresetGeneratorOptions
|
||||
extends PresetGeneratorSchema {
|
||||
createPackageName: string;
|
||||
useProjectJson: boolean;
|
||||
addPlugin: boolean;
|
||||
}
|
||||
|
||||
@ -24,6 +24,10 @@
|
||||
"createPackageName": {
|
||||
"type": "string",
|
||||
"description": "Name of package which creates a workspace"
|
||||
},
|
||||
"useProjectJson": {
|
||||
"type": "boolean",
|
||||
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
|
||||
}
|
||||
},
|
||||
"required": ["pluginName"]
|
||||
|
||||
49
packages/plugin/src/utils/paths.ts
Normal file
49
packages/plugin/src/utils/paths.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { readProjectConfiguration, type Tree } from '@nx/devkit';
|
||||
import { dirname, join, relative } from 'node:path/posix';
|
||||
|
||||
export function getArtifactMetadataDirectory(
|
||||
tree: Tree,
|
||||
projectName: string,
|
||||
sourceDirectory: string,
|
||||
isTsSolutionSetup: boolean
|
||||
): string {
|
||||
const project = readProjectConfiguration(tree, projectName);
|
||||
|
||||
if (!isTsSolutionSetup) {
|
||||
return `./${relative(project.root, sourceDirectory)}`;
|
||||
}
|
||||
|
||||
const target = Object.values(project.targets ?? {}).find(
|
||||
(t) => t.executor === '@nx/js:tsc' || t.executor === '@nx/js:swc'
|
||||
);
|
||||
|
||||
// the repo is using the new ts setup where the outputs are contained inside the project
|
||||
if (target?.executor === '@nx/js:tsc') {
|
||||
// the @nx/js:tsc executor defaults rootDir to the project root
|
||||
return `./${join(
|
||||
'dist',
|
||||
relative(target.options.rootDir ?? project.root, sourceDirectory)
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (target?.executor === '@nx/js:swc') {
|
||||
return `./${join(
|
||||
'dist',
|
||||
target.options.stripLeadingPaths
|
||||
? relative(dirname(target.options.main), sourceDirectory)
|
||||
: relative(project.root, sourceDirectory)
|
||||
)}`;
|
||||
}
|
||||
|
||||
// We generate the plugin with the executors above, so we shouldn't get here
|
||||
// unless the user manually changed the build process. In that case, we can't
|
||||
// reliably determine the output directory because it depends on the build
|
||||
// tool, so we'll just assume some defaults.
|
||||
const baseDir =
|
||||
project.sourceRoot ??
|
||||
(tree.exists(join(project.root, 'src'))
|
||||
? join(project.root, 'src')
|
||||
: project.root);
|
||||
|
||||
return `./${join('dist', relative(baseDir, sourceDirectory))}`;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"extends": "<%= extendedConfig %>",
|
||||
"compilerOptions": {
|
||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
||||
"outDir": "<%= outDir %>",
|
||||
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"]
|
||||
},
|
||||
"include": [
|
||||
|
||||
@ -13,21 +13,20 @@ import {
|
||||
Tree,
|
||||
updateJson,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { join } from 'path';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import {
|
||||
addOrChangeTestTarget,
|
||||
createOrEditViteConfig,
|
||||
} from '../../utils/generator-utils';
|
||||
import { VitestGeneratorSchema } from './schema';
|
||||
|
||||
import initGenerator from '../init/init';
|
||||
import {
|
||||
vitestCoverageIstanbulVersion,
|
||||
vitestCoverageV8Version,
|
||||
} from '../../utils/versions';
|
||||
|
||||
import { addTsLibDependencies, initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { join } from 'path';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import initGenerator from '../init/init';
|
||||
import { VitestGeneratorSchema } from './schema';
|
||||
|
||||
export function vitestGenerator(
|
||||
tree: Tree,
|
||||
@ -270,11 +269,17 @@ function createFiles(
|
||||
options: VitestGeneratorSchema,
|
||||
projectRoot: string
|
||||
) {
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||
const rootOffset = offsetFromRoot(projectRoot);
|
||||
|
||||
generateFiles(tree, join(__dirname, 'files'), projectRoot, {
|
||||
tmpl: '',
|
||||
...options,
|
||||
projectRoot,
|
||||
offsetFromRoot: offsetFromRoot(projectRoot),
|
||||
extendedConfig: isTsSolutionSetup
|
||||
? `${rootOffset}tsconfig.base.json`
|
||||
: './tsconfig.json',
|
||||
outDir: isTsSolutionSetup ? `./out-tsc/jest` : `${rootOffset}dist/out-tsc`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# compiled output
|
||||
dist
|
||||
tmp
|
||||
/out-tsc
|
||||
out-tsc
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# compiled output
|
||||
dist
|
||||
tmp
|
||||
/out-tsc
|
||||
out-tsc
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# compiled output
|
||||
dist
|
||||
tmp
|
||||
/out-tsc
|
||||
out-tsc
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user