diff --git a/e2e/nx-misc/src/workspace.test.ts b/e2e/nx-misc/src/workspace.test.ts index e15b3144734cd..57d4c68554f53 100644 --- a/e2e/nx-misc/src/workspace.test.ts +++ b/e2e/nx-misc/src/workspace.test.ts @@ -756,180 +756,3 @@ describe('Workspace Tests', () => { }); }); }); - -describe('workspace-generator', () => { - const packageManager = getSelectedPackageManager() || 'pnpm'; - const proj = uniq('workspace'); - - beforeAll(() => { - runCreateWorkspace(proj, { - preset: 'ts', - packageManager, - }); - }); - - afterAll(() => cleanupProject()); - - let custom: string; - let failing: string; - - beforeEach(() => { - custom = uniq('custom'); - failing = uniq('custom-failing'); - runCLI(`g @nrwl/workspace:workspace-generator ${custom} --no-interactive`); - runCLI(`g @nrwl/workspace:workspace-generator ${failing} --no-interactive`); - - checkFilesExist( - `tools/generators/${custom}/index.ts`, - `tools/generators/${custom}/schema.json` - ); - checkFilesExist( - `tools/generators/${failing}/index.ts`, - `tools/generators/${failing}/schema.json` - ); - }); - - it('should compile only generator files with dependencies', () => { - const workspace = uniq('workspace'); - - updateFile( - 'tools/utils/command-line-utils.ts', - ` - export const noop = () => {} - ` - ); - updateFile( - 'tools/utils/logger.ts', - ` - export const log = (...args: any[]) => console.log(...args) - ` - ); - updateFile( - `tools/generators/utils.ts`, - ` - export const noop = ()=>{} - ` - ); - updateFile(`tools/generators/${custom}/index.ts`, (content) => { - return ` - import { log } from '../../utils/logger'; \n - ${content} - `; - }); - - runCLI(`workspace-generator ${custom} ${workspace} --no-interactive -d`); - - expect(() => - checkFilesExist( - `dist/out-tsc/tools/generators/${custom}/index.js`, - `dist/out-tsc/tools/generators/utils.js`, - `dist/out-tsc/tools/utils/logger.js` - ) - ).not.toThrow(); - expect(() => - checkFilesExist(`dist/out-tsc/tools/utils/utils.js`) - ).toThrow(); - }); - - it('should support workspace-specific generators', async () => { - const json = readJson(`tools/generators/${custom}/schema.json`); - json.properties['directory'] = { - type: 'string', - description: 'lib directory', - }; - json.properties['skipTsConfig'] = { - type: 'boolean', - description: 'skip changes to tsconfig', - }; - json.properties['inlineprop'] = json.properties['name']; - json.required = ['inlineprop']; - delete json.properties['name']; - - updateFile(`tools/generators/${custom}/schema.json`, JSON.stringify(json)); - - const indexFile = readFile(`tools/generators/${custom}/index.ts`); - updateFile( - `tools/generators/${custom}/index.ts`, - indexFile.replace( - 'name: schema.name', - 'name: schema.inlineprop, directory: schema.directory, skipTsConfig: schema.skipTsConfig' - ) - ); - - const helpOutput = runCLI(`workspace-generator ${custom} --help`); - expect(helpOutput).toContain( - `workspace-generator ${custom} [inlineprop] (options)` - ); - expect(helpOutput).toContain(`--directory`); - expect(helpOutput).toContain(`--skipTsConfig`); - - const workspace = uniq('workspace'); - const dryRunOutput = runCLI( - `workspace-generator ${custom} ${workspace} --no-interactive --directory=dir --skipTsConfig=true -d` - ); - expect(exists(`packages/dir/${workspace}/src/index.ts`)).toEqual(false); - expect(dryRunOutput).toContain( - `CREATE packages/dir/${workspace}/src/index.ts` - ); - - runCLI( - `workspace-generator ${custom} ${workspace} --no-interactive --directory=dir` - ); - checkFilesExist(`packages/dir/${workspace}/src/index.ts`); - - const jsonFailing = readJson(`tools/generators/${failing}/schema.json`); - jsonFailing.properties = {}; - jsonFailing.required = []; - updateFile( - `tools/generators/${failing}/schema.json`, - JSON.stringify(jsonFailing) - ); - - updateFile( - `tools/generators/${failing}/index.ts`, - ` - export default function() { - throw new Error(); - } - ` - ); - - try { - await runCLI(`workspace-generator ${failing} --no-interactive`); - fail(`Should exit 1 for a workspace-generator that throws an error`); - } catch (e) {} - - const listOutput = runCLI('workspace-generator --list-generators'); - expect(listOutput).toContain(custom); - expect(listOutput).toContain(failing); - }, 1000000); - - it('should support angular devkit schematics', () => { - const angularDevkitSchematic = uniq('angular-devkit-schematic'); - runCLI( - `g @nrwl/workspace:workspace-generator ${angularDevkitSchematic} --no-interactive` - ); - - const json = readJson( - `tools/generators/${angularDevkitSchematic}/schema.json` - ); - json.properties = {}; - json.required = []; - delete json.cli; - updateFile( - `tools/generators/${angularDevkitSchematic}/schema.json`, - JSON.stringify(json) - ); - - updateFile( - `tools/generators/${angularDevkitSchematic}/index.ts`, - ` - export default function() { - return (tree) => tree; - } - ` - ); - - runCLI(`workspace-generator ${angularDevkitSchematic} --no-interactive`); - }); -}); diff --git a/packages/workspace/src/generators/workspace-generator/workspace-generator.ts b/packages/workspace/src/generators/workspace-generator/workspace-generator.ts index fe6e3a6e60228..da0f9c888b747 100644 --- a/packages/workspace/src/generators/workspace-generator/workspace-generator.ts +++ b/packages/workspace/src/generators/workspace-generator/workspace-generator.ts @@ -4,7 +4,7 @@ import { Tree, stripIndents } from '@nx/devkit'; export default async function (host: Tree, schema: Schema) { const message = stripIndents`Workspace Generators are no longer supported. Instead, Nx now supports executing generators or executors from local plugins. To get - started, install @nrwl/nx-plugin and run \`nx g plugin\`. + started, install @nx/nx-plugin and run \`nx g plugin\`. Afterwards, or if you already have an Nx plugin, you can run \`nx g generator --project {my-plugin}\` to add a new generator. diff --git a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts b/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts index 20887e513fc3e..ac9fa31229cd2 100644 --- a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts +++ b/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts @@ -1,4 +1,4 @@ -import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree, readProjectConfiguration, @@ -7,11 +7,12 @@ import { GeneratorsJson, ProjectConfiguration, stripIndents, -} from '@nrwl/devkit'; + getProjects, +} from '@nx/devkit'; import generator from './move-workspace-generators-to-local-plugin'; -describe('local-plugin-from-tools generator', () => { +describe('move-workspace-generators-to-local-plugin', () => { let tree: Tree; beforeEach(() => { @@ -23,6 +24,7 @@ describe('local-plugin-from-tools generator', () => { name: 'my-generator', }); await generator(tree); + console.log(getProjects(tree).keys()); const config = readProjectConfiguration(tree, 'workspace-plugin'); expect(config.root).toEqual('tools/workspace-plugin'); @@ -136,8 +138,8 @@ async function workspaceGeneratorGenerator( host.write( joinPathFragments(outputDirectory, 'index.ts'), - stripIndents`import { Tree, formatFiles, installPackagesTask } from '@nrwl/devkit'; - import { libraryGenerator } from '@nrwl/workspace/generators'; + stripIndents`import { Tree, formatFiles, installPackagesTask } from '@nx/devkit'; + import { libraryGenerator } from '@nx/workspace/generators'; export default async function(tree: Tree, schema: any) { await libraryGenerator(tree, {name: schema.name}); diff --git a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts b/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts index bf213ebc6d936..a7b7e4b6764a6 100644 --- a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts +++ b/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts @@ -5,13 +5,14 @@ import { getProjects, getWorkspaceLayout, joinPathFragments, + output, ProjectConfiguration, readJson, readProjectConfiguration, Tree, updateJson, writeJson, -} from '@nrwl/devkit'; +} from '@nx/devkit'; // nx-ignore-next-line import * as path from 'path'; import { @@ -39,7 +40,7 @@ export default async function (tree: Tree) { tree, {}, { - '@nrwl/nx-plugin': nxVersion, + '@nx/nx-plugin': nxVersion, } ) ); @@ -80,19 +81,13 @@ function collectAndMoveGenerators(tree: Tree, destinationProjectRoot: string) { } async function createNewPlugin(tree: Tree) { - ensurePackage('@nrwl/nx-plugin', nxVersion); + ensurePackage('@nx/nx-plugin', nxVersion); const { pluginGenerator } = // nx-ignore-next-line - require('@nrwl/nx-plugin/src/generators/plugin/plugin'); - const { createExecutorsJson } = - // nx-ignore-next-line - require('@nrwl/nx-plugin/src/generators/executor/executor'); - const { createGeneratorsJson } = - // nx-ignore-next-line - require('@nrwl/nx-plugin/src/generators/generator/generator'); + require('@nx/nx-plugin/src/generators/plugin/plugin'); // nx-ignore-next-line - const { Linter } = ensurePackage('@nrwl/linter', nxVersion); + const { Linter } = ensurePackage('@nx/linter', nxVersion); const { npmScope } = getWorkspaceLayout(tree); const importPath = npmScope ? `${npmScope}/${PROJECT_NAME}` : PROJECT_NAME; @@ -109,8 +104,11 @@ async function createNewPlugin(tree: Tree) { unitTestRunner: 'jest', e2eTestRunner: 'none', }); - createExecutorsJson(tree, readProjectConfiguration(tree, PROJECT_NAME).root); - createGeneratorsJson(tree, readProjectConfiguration(tree, PROJECT_NAME).root); + getCreateGeneratorsJson()( + tree, + readProjectConfiguration(tree, PROJECT_NAME).root, + PROJECT_NAME + ); await moveGeneratedPlugin(tree, DESTINATION, importPath); } @@ -141,20 +139,50 @@ function updateExistingPlugin(tree: Tree, project: ProjectConfiguration) { project.root, 'generators.json' ); - const generatorsJsonPath = + let generatorsJsonPath = packageJson.generators || packageJson.schematics || tree.exists(defaultGeneratorsPath) ? defaultGeneratorsPath : null; if (!generatorsJsonPath) { - throw new Error('Unable to locate generators.json for ' + project.name); + getCreateGeneratorsJson()( + tree, + readProjectConfiguration(tree, PROJECT_NAME).root, + PROJECT_NAME + ); + generatorsJsonPath = defaultGeneratorsPath; } - const generatorsJson = readJson(tree, generatorsJsonPath); - const generators = collectAndMoveGenerators(tree, project.root); - generatorsJson.generators = { - ...generators, - ...generatorsJson.generators, - }; - writeJson(tree, generatorsJsonPath, generatorsJson); + updateJson(tree, generatorsJsonPath, (json) => { + const generators = collectAndMoveGenerators(tree, project.root); + json.generators ??= {}; + for (const generator in generators) { + if (json.generators[generator]) { + output.warn({ + title: `Generator ${generator} already exists in ${project.name}`, + bodyLines: [ + 'Since you have a generator with the same name in your plugin, the generator from workspace-generators has been discarded.', + ], + }); + } else { + json.generators[generator] = generators[generator]; + } + } + return json; + }); +} + +function getCreateGeneratorsJson(): ( + host: Tree, + projectRoot: string, + projectName: string, + skipLintChecks?: boolean, + skipFormat?: boolean +) => Promise { + // We cant use `as typeof import('@nx/nx-plugin/src/generators/generator/generator');` here + // because it will cause a typescript error at build time. + const { createGeneratorsJson } = + // nx-ignore-next-line + require('@nx/nx-plugin/src/generators/generator/generator'); + return createGeneratorsJson; } diff --git a/scripts/depcheck/missing.ts b/scripts/depcheck/missing.ts index ff5cc4a85fb45..a0dbcdb40e615 100644 --- a/scripts/depcheck/missing.ts +++ b/scripts/depcheck/missing.ts @@ -192,7 +192,7 @@ const IGNORE_MATCHES_BY_FILE: Record = { '../../packages/angular/src/migrations/update-12-3-0/update-storybook.ts' ), ], - '@nrwl/nx-plugin': [ + '@nx/nx-plugin': [ join( __dirname, '../../packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts'