diff --git a/docs/generated/cli/workspace-generator.md b/docs/generated/cli/workspace-generator.md index b5332ac1316c49..edb0b80d3f48a0 100644 --- a/docs/generated/cli/workspace-generator.md +++ b/docs/generated/cli/workspace-generator.md @@ -12,7 +12,7 @@ description: 'Runs a workspace generator from the tools/generators directory' ## Usage ```shell -nx workspace-generator [name] +nx workspace-generator [generator] ``` Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. diff --git a/docs/generated/packages/nx/documents/workspace-generator.md b/docs/generated/packages/nx/documents/workspace-generator.md index b5332ac1316c49..edb0b80d3f48a0 100644 --- a/docs/generated/packages/nx/documents/workspace-generator.md +++ b/docs/generated/packages/nx/documents/workspace-generator.md @@ -12,7 +12,7 @@ description: 'Runs a workspace generator from the tools/generators directory' ## Usage ```shell -nx workspace-generator [name] +nx workspace-generator [generator] ``` Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. diff --git a/packages/nx/src/command-line/nx-commands.ts b/packages/nx/src/command-line/nx-commands.ts index 78ce53be2305b4..efa385c32a4ab8 100644 --- a/packages/nx/src/command-line/nx-commands.ts +++ b/packages/nx/src/command-line/nx-commands.ts @@ -238,11 +238,11 @@ export const commandsObject = yargs * @deprecated(v17): Remove `workspace-generator in v17. Use local plugins. */ .command({ - command: 'workspace-generator [name]', + command: 'workspace-generator [generator]', describe: 'Runs a workspace generator from the tools/generators directory', deprecated: 'Use a local plugin instead. See: https://nx.dev/deprecated/workspace-generators', - aliases: ['workspace-schematic [name]'], + aliases: ['workspace-schematic [generator]'], builder: async (yargs) => linkToNxDevAndExamples(withGenerateOptions(yargs), 'workspace-generator'), handler: workspaceGeneratorHandler, diff --git a/packages/nx/src/command-line/workspace-generators.ts b/packages/nx/src/command-line/workspace-generators.ts index df8981abff6287..be1041d790ffc3 100644 --- a/packages/nx/src/command-line/workspace-generators.ts +++ b/packages/nx/src/command-line/workspace-generators.ts @@ -13,7 +13,7 @@ export async function workspaceGenerators(args: yargs.Arguments) { const generator = process.argv.slice(3); output.warn({ - title: `${NX_PREFIX} Workspace Generators are no longer supported`, + title: `Workspace Generators are no longer supported`, bodyLines: [ 'Instead, Nx now supports executing generators or executors from ', 'local plugins. To run a generator from a local plugin, ', 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 a7b7e4b6764a66..8d35bef72b741c 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 @@ -22,6 +22,7 @@ import { import { moveGenerator } from '../../generators/move/move'; import { nxVersion } from '../../utils/versions'; import { PackageJson } from 'nx/src/utils/package-json'; +import { posix } from 'path'; const PROJECT_NAME = 'workspace-plugin'; const DESTINATION = `tools/${PROJECT_NAME}`; @@ -74,12 +75,71 @@ function collectAndMoveGenerators(tree: Tree, destinationProjectRoot: string) { schema: `./src/generators/${joinPathFragments(c, 'schema.json')}`, description: schema.description ?? `Generator ${c}`, }; - tree.rename(childDir, joinPathFragments(destinationDir, c)); + moveFilesInDirectory( + tree, + childDir, + joinPathFragments(destinationDir, c) + ); } } return generators; } +function moveFilesInDirectory(tree: Tree, source: string, destination: string) { + const relative = posix.relative(source, posix.dirname(destination)); + if (!relative.startsWith('../')) { + // If the destination is in the same directory or a subdirectory of the source + // we can just move the files. If it is not, we need to update the relative imports. + return; + } + let offsetLevel = 0; + const pathParts = relative.split('/'); + for (const part of pathParts) { + if (part === '..') { + offsetLevel++; + } else { + break; + } + } + for (const c of tree.children(source)) { + if (!tree.isFile(c)) { + moveFilesInDirectory( + tree, + joinPathFragments(source, c), + joinPathFragments(destination, c) + ); + } + tree.rename( + joinPathFragments(source, c), + joinPathFragments(destination, c) + ); + // If its a TS file we can update relative imports with find + replace + // This could be done with AST, but since we are only looking at relative + // imports its easy to do via string replace. We replace any strings starting + // with a relative path outside of their own directory. + if (c.endsWith('.ts')) { + let content = tree.read(joinPathFragments(destination, c)).toString(); + // +2 is a bit of a magic number here - represents extra directory levels in a normal + // plugin structure compared to the workspace-generator layout + const extraDirectoriesInPluginStructure = 2; + content = content.replace( + new RegExp(`'` + `\.\.\/`.repeat(offsetLevel), 'g'), + "'" + '../'.repeat(offsetLevel + extraDirectoriesInPluginStructure) + ); + content = content.replace( + new RegExp(`"` + `\.\.\/`.repeat(offsetLevel), 'g'), + '"' + '../'.repeat(offsetLevel + extraDirectoriesInPluginStructure) + ); + // We write it back in the same spot, since it is moved as if it was a regular file after this + tree.write(joinPathFragments(source, c), content); + } + tree.rename( + joinPathFragments(source, c), + joinPathFragments(destination, c) + ); + } +} + async function createNewPlugin(tree: Tree) { ensurePackage('@nx/nx-plugin', nxVersion); const { pluginGenerator } = @@ -90,7 +150,7 @@ async function createNewPlugin(tree: Tree) { const { Linter } = ensurePackage('@nx/linter', nxVersion); const { npmScope } = getWorkspaceLayout(tree); - const importPath = npmScope ? `${npmScope}/${PROJECT_NAME}` : PROJECT_NAME; + const importPath = npmScope ? `@${npmScope}/${PROJECT_NAME}` : PROJECT_NAME; await pluginGenerator(tree, { minimal: true,