From 5df5be8cc911f79e70044c88c18245c5120f4c67 Mon Sep 17 00:00:00 2001 From: Jonathan Cammisuli Date: Fri, 3 Sep 2021 11:07:10 -0400 Subject: [PATCH 1/4] feat: Add commands to add applications and libraries directly --- .vscode/launch.json | 1 + apps/vscode/src/main.ts | 53 ++++++++- apps/vscode/src/package.json | 46 ++++++++ libs/schema/src/index.ts | 13 ++- libs/server/src/index.ts | 4 +- libs/server/src/lib/select-generator.ts | 58 ++++++++++ libs/server/src/lib/select-schematic.ts | 51 --------- ...tions.ts => read-generator-collections.ts} | 104 ++++++++++-------- libs/server/src/lib/utils/utils.ts | 4 +- .../src/lib/run-target-tree-item.ts | 4 +- .../vscode/tasks/src/lib/cli-task-commands.ts | 55 +++++++-- .../src/lib/get-task-execution-schema.ts | 76 ++++++------- libs/vscode/webview/src/lib/webview.ts | 5 +- 13 files changed, 323 insertions(+), 151 deletions(-) create mode 100644 libs/server/src/lib/select-generator.ts delete mode 100644 libs/server/src/lib/select-schematic.ts rename libs/server/src/lib/utils/{read-schematic-collections.ts => read-generator-collections.ts} (66%) diff --git a/.vscode/launch.json b/.vscode/launch.json index a0b9e88fe3..275d8b03f8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,6 +17,7 @@ "${workspaceFolder}/node_modules" ], "request": "launch", + "skipFiles": ["/**"], "type": "pwa-extensionHost" }, { diff --git a/apps/vscode/src/main.ts b/apps/vscode/src/main.ts index 8b7abbe930..ce6543bb79 100644 --- a/apps/vscode/src/main.ts +++ b/apps/vscode/src/main.ts @@ -21,6 +21,7 @@ import { getOutputChannel, getTelemetry, initTelemetry, + readAllGeneratorCollections, teardownTelemetry, watchFile, } from '@nx-console/server'; @@ -44,6 +45,7 @@ import { NxProjectTreeProvider, } from '@nx-console/vscode/nx-project-view'; import { + getNxConfig, verifyWorkspace, WorkspaceCodeLensProvider, } from '@nx-console/vscode/nx-workspace'; @@ -53,6 +55,7 @@ import { WorkspaceJsonSchema, ProjectJsonSchema, } from '@nx-console/vscode/json-schema'; +import { GeneratorType } from '@nx-console/schema'; let runTargetTreeView: TreeView; let nxProjectTreeView: TreeView; @@ -196,10 +199,10 @@ function scanForWorkspace(vscodeWorkspacePath: string) { while (currentDirectory !== root) { if (existsSync(join(currentDirectory, 'angular.json'))) { - return setWorkspace(join(currentDirectory, 'angular.json')); + setWorkspace(join(currentDirectory, 'angular.json')); } if (existsSync(join(currentDirectory, 'workspace.json'))) { - return setWorkspace(join(currentDirectory, 'workspace.json')); + setWorkspace(join(currentDirectory, 'workspace.json')); } currentDirectory = dirname(currentDirectory); } @@ -244,6 +247,8 @@ async function setWorkspace(workspaceJsonPath: string) { ); } + await setApplicationAndLibraryContext(workspaceJsonPath); + const isNxWorkspace = existsSync(join(workspaceJsonPath, '..', 'nx.json')); const isAngularWorkspace = workspaceJsonPath.endsWith('angular.json'); @@ -271,6 +276,50 @@ async function setWorkspace(workspaceJsonPath: string) { getTelemetry().record('WorkspaceType', { workspaceType }); } +async function setApplicationAndLibraryContext(workspaceJsonPath: string) { + const nxConfig = getNxConfig(dirname(workspaceJsonPath)); + + commands.executeCommand('setContext', 'nxAppsDir', [ + join( + dirname(workspaceJsonPath), + nxConfig.workspaceLayout?.appsDir ?? 'apps' + ), + ]); + commands.executeCommand('setContext', 'nxLibsDir', [ + join( + dirname(workspaceJsonPath), + nxConfig.workspaceLayout?.libsDir ?? 'libs' + ), + ]); + + const generatorCollections = await readAllGeneratorCollections( + workspaceJsonPath + ); + let hasApplicationGenerators = false; + let hasLibraryGenerators = false; + + generatorCollections.forEach((generatorCollection) => { + generatorCollection.generators.forEach((generator) => { + if (generator.type === 'application') { + hasApplicationGenerators = true; + } else if (generator.type === 'library') { + hasLibraryGenerators = true; + } + }); + }); + + commands.executeCommand( + 'setContext', + 'nx.hasApplicationGenerators', + hasApplicationGenerators + ); + commands.executeCommand( + 'setContext', + 'nx.hasLibraryGenerators', + hasLibraryGenerators + ); +} + function registerWorkspaceFileWatcher( context: ExtensionContext, workspaceJsonPath: string diff --git a/apps/vscode/src/package.json b/apps/vscode/src/package.json index 96d8e1280b..0cd9fc97d2 100644 --- a/apps/vscode/src/package.json +++ b/apps/vscode/src/package.json @@ -65,6 +65,16 @@ "when": "isNxWorkspace && config.nxConsole.enableGenerateFromContextMenu", "command": "nx.run.fileexplorer", "group": "2_workspace" + }, + { + "when": "isNxWorkspace && explorerResourceIsFolder && resourcePath in nxAppsDir && config.nxConsole.enableGenerateFromContextMenu && nx.hasApplicationGenerators", + "command": "nx.generate.ui.app.fileexplorer", + "group": "2_workspace" + }, + { + "when": "isNxWorkspace && explorerResourceIsFolder && resourcePath in nxLibsDir && config.nxConsole.enableGenerateFromContextMenu && nx.hasLibraryGenerators", + "command": "nx.generate.ui.lib.fileexplorer", + "group": "2_workspace" } ], "view/title": [ @@ -108,6 +118,22 @@ "command": "nx.run.fileexplorer", "when": "false" }, + { + "command": "nx.generate.ui.app.fileexplorer", + "when": "false" + }, + { + "command": "nx.generate.ui.lib.fileexplorer", + "when": "false" + }, + { + "command": "nx.generate.ui.app", + "when": "isNxWorkspace && nx.hasApplicationGenerators" + }, + { + "command": "nx.generate.ui.lib", + "when": "isNxWorkspace && && nx.hasLibraryGenerators" + }, { "command": "ng.lint", "when": "isAngularWorkspace" @@ -511,6 +537,26 @@ "category": "Nx", "title": "Nx run", "command": "nx.run.fileexplorer" + }, + { + "category": "Nx", + "title": "Add application", + "command": "nx.generate.ui.app" + }, + { + "category": "Nx", + "title": "Add library", + "command": "nx.generate.ui.lib" + }, + { + "category": "Nx", + "title": "Nx add application", + "command": "nx.generate.ui.app.fileexplorer" + }, + { + "category": "Nx", + "title": "Nx add library", + "command": "nx.generate.ui.lib.fileexplorer" } ], "configuration": { diff --git a/libs/schema/src/index.ts b/libs/schema/src/index.ts index 57f412aca9..edb4badccf 100644 --- a/libs/schema/src/index.ts +++ b/libs/schema/src/index.ts @@ -47,16 +47,23 @@ export interface TaskExecutionSchema { contextValues?: Record; } -export interface SchematicCollection { +export interface GeneratorCollection { name: string; - schematics: Schematic[]; + generators: Generator[]; } -export interface Schematic { +export enum GeneratorType { + Application = 'application', + Library = 'library', + Other = 'other', +} + +export interface Generator { collection: string; name: string; description: string; options?: Option[]; + type: GeneratorType; } export interface DefaultValue { diff --git a/libs/server/src/index.ts b/libs/server/src/index.ts index cd267bcf57..e1b8114479 100644 --- a/libs/server/src/index.ts +++ b/libs/server/src/index.ts @@ -1,11 +1,11 @@ export * from './lib/abstract-tree-provider'; export * from './lib/extensions'; export * from './lib/stores'; -export * from './lib/select-schematic'; +export * from './lib/select-generator'; export * from './lib/telemetry'; export * from './lib/utils/output-channel'; export * from './lib/utils/read-projects'; -export * from './lib/utils/read-schematic-collections'; +export * from './lib/utils/read-generator-collections'; export { fileExistsSync, findClosestNg, diff --git a/libs/server/src/lib/select-generator.ts b/libs/server/src/lib/select-generator.ts new file mode 100644 index 0000000000..d099e4875c --- /dev/null +++ b/libs/server/src/lib/select-generator.ts @@ -0,0 +1,58 @@ +import { Generator, GeneratorType } from '@nx-console/schema'; +import { TaskExecutionSchema } from '@nx-console/schema'; +import { QuickPickItem, window } from 'vscode'; +import { + readAllGeneratorCollections, + readGeneratorOptions, +} from './utils/read-generator-collections'; + +export async function selectGenerator( + workspaceJsonPath: string, + generatorType?: GeneratorType +): Promise { + interface GenerateQuickPickItem extends QuickPickItem { + collectionName: string; + generator: Generator; + } + + let generators = (await readAllGeneratorCollections(workspaceJsonPath)) + .filter((c) => c && c.generators.length) + .map((c): GenerateQuickPickItem[] => + c.generators.map( + (s: Generator): GenerateQuickPickItem => ({ + description: s.description, + label: `${c.name} - ${s.name}`, + collectionName: c.name, + generator: s, + }) + ) + ) + .flat(); + + if (generatorType) { + generators = generators.filter((generator) => { + return generator.generator.type === generatorType; + }); + } + + if (generators) { + const selection = await window.showQuickPick(generators); + if (selection) { + const options = + selection.generator.options || + (await readGeneratorOptions( + workspaceJsonPath, + selection.collectionName, + selection.generator.name + )); + const positional = `${selection.collectionName}:${selection.generator.name}`; + return { + ...selection.generator, + options, + command: 'generate', + positional, + cliName: 'nx', + }; + } + } +} diff --git a/libs/server/src/lib/select-schematic.ts b/libs/server/src/lib/select-schematic.ts deleted file mode 100644 index 6bc474dfb3..0000000000 --- a/libs/server/src/lib/select-schematic.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Schematic } from '@nx-console/schema'; -import { TaskExecutionSchema } from '@nx-console/schema'; -import { QuickPickItem, window } from 'vscode'; -import { - readAllSchematicCollections, - readSchematicOptions, -} from './utils/read-schematic-collections'; - -export async function selectSchematic( - workspaceJsonPath: string -): Promise { - interface GenerateQuickPickItem extends QuickPickItem { - collectionName: string; - schematic: Schematic; - } - - const schematics = (await readAllSchematicCollections(workspaceJsonPath)) - .filter((c) => c && c.schematics.length) - .map((c): GenerateQuickPickItem[] => - c.schematics.map( - (s: Schematic): GenerateQuickPickItem => ({ - description: s.description, - label: `${c.name} - ${s.name}`, - collectionName: c.name, - schematic: s, - }) - ) - ) - .flat(); - - if (schematics) { - const selection = await window.showQuickPick(schematics); - if (selection) { - const options = - selection.schematic.options || - (await readSchematicOptions( - workspaceJsonPath, - selection.collectionName, - selection.schematic.name - )); - const positional = `${selection.collectionName}:${selection.schematic.name}`; - return { - ...selection.schematic, - options, - command: 'generate', - positional, - cliName: 'nx', - }; - } - } -} diff --git a/libs/server/src/lib/utils/read-schematic-collections.ts b/libs/server/src/lib/utils/read-generator-collections.ts similarity index 66% rename from libs/server/src/lib/utils/read-schematic-collections.ts rename to libs/server/src/lib/utils/read-generator-collections.ts index db45273736..9ecd32f134 100644 --- a/libs/server/src/lib/utils/read-schematic-collections.ts +++ b/libs/server/src/lib/utils/read-generator-collections.ts @@ -1,4 +1,9 @@ -import { Option, Schematic, SchematicCollection } from '@nx-console/schema'; +import { + Option, + Generator, + GeneratorCollection, + GeneratorType, +} from '@nx-console/schema'; import { basename, dirname, join } from 'path'; import { @@ -12,11 +17,11 @@ import { toWorkspaceFormat, } from './utils'; -export async function readAllSchematicCollections( +export async function readAllGeneratorCollections( workspaceJsonPath: string -): Promise { +): Promise { const basedir = join(workspaceJsonPath, '..'); - let collections = await readSchematicCollectionsFromNodeModules( + let collections = await readGeneratorCollectionsFromNodeModules( workspaceJsonPath ); collections = [ @@ -31,19 +36,19 @@ export async function readAllSchematicCollections( )), ]; return collections.filter( - (collection): collection is SchematicCollection => - collection && collection.schematics.length > 0 + (collection): collection is GeneratorCollection => + collection && collection.generators.length > 0 ); } async function checkAndReadWorkspaceCollection( basedir: string, - workspaceSchematicsPath: string + workspaceGeneratorsPath: string ) { - if (directoryExists(join(basedir, workspaceSchematicsPath))) { - return readWorkspaceSchematicsCollection( + if (directoryExists(join(basedir, workspaceGeneratorsPath))) { + return readWorkspaceGeneratorsCollection( basedir, - workspaceSchematicsPath + workspaceGeneratorsPath ).then((val) => [val]); } return Promise.resolve([]); @@ -56,19 +61,19 @@ function readWorkspaceJsonDefaults(workspaceJsonPath: string): any { const collectionDefaults = Object.keys(defaults).reduce( (collectionDefaultsMap: any, key) => { if (key.includes(':')) { - const [collectionName, schematicName] = key.split(':'); + const [collectionName, generatorName] = key.split(':'); if (!collectionDefaultsMap[collectionName]) { collectionDefaultsMap[collectionName] = {}; } - collectionDefaultsMap[collectionName][schematicName] = defaults[key]; + collectionDefaultsMap[collectionName][generatorName] = defaults[key]; } else { const collectionName = key; if (!collectionDefaultsMap[collectionName]) { collectionDefaultsMap[collectionName] = {}; } - Object.keys(defaults[collectionName]).forEach((schematicName) => { - collectionDefaultsMap[collectionName][schematicName] = - defaults[collectionName][schematicName]; + Object.keys(defaults[collectionName]).forEach((generatorName) => { + collectionDefaultsMap[collectionName][generatorName] = + defaults[collectionName][generatorName]; }); } return collectionDefaultsMap; @@ -78,13 +83,13 @@ function readWorkspaceJsonDefaults(workspaceJsonPath: string): any { return collectionDefaults; } -async function readSchematicCollectionsFromNodeModules( +async function readGeneratorCollectionsFromNodeModules( workspaceJsonPath: string -): Promise { +): Promise { const basedir = join(workspaceJsonPath, '..'); const nodeModulesDir = join(basedir, 'node_modules'); const packages = listOfUnnestedNpmPackages(nodeModulesDir); - const schematicCollections = packages.filter((p) => { + const generatorCollections = packages.filter((p) => { try { const packageJson = readAndCacheJsonFile( join(p, 'package.json'), @@ -106,26 +111,23 @@ async function readSchematicCollectionsFromNodeModules( return ( await Promise.all( - schematicCollections.map((c) => readCollection(nodeModulesDir, c)) + generatorCollections.map((c) => readCollection(nodeModulesDir, c)) ) - ).filter((c): c is SchematicCollection => Boolean(c)); + ).filter((c): c is GeneratorCollection => Boolean(c)); } -async function readWorkspaceSchematicsCollection( +async function readWorkspaceGeneratorsCollection( basedir: string, - workspaceSchematicsPath: string -): Promise<{ - name: string; - schematics: Schematic[]; -}> { - const collectionDir = join(basedir, workspaceSchematicsPath); + workspaceGeneratorsPath: string +): Promise { + const collectionDir = join(basedir, workspaceGeneratorsPath); const collectionName = 'workspace-schematic'; if (fileExistsSync(join(collectionDir, 'collection.json'))) { const collection = readAndCacheJsonFile('collection.json', collectionDir); - return await readCollectionSchematics(collectionName, collection.json); + return readCollectionGenerators(collectionName, collection.json); } else { - const schematics: Schematic[] = await Promise.all( + const generators: Generator[] = await Promise.all( listFiles(collectionDir) .filter((f) => basename(f) === 'schema.json') .map(async (f) => { @@ -135,17 +137,18 @@ async function readWorkspaceSchematicsCollection( collection: collectionName, options: await normalizeSchema(schemaJson.json), description: '', + type: GeneratorType.Other, }; }) ); - return { name: collectionName, schematics }; + return { name: collectionName, generators }; } } async function readCollection( basedir: string, collectionName: string -): Promise { +): Promise { try { const packageJson = readAndCacheJsonFile( join(collectionName, 'package.json'), @@ -155,29 +158,42 @@ async function readCollection( packageJson.json.schematics || packageJson.json.generators, dirname(packageJson.path) ); - return readCollectionSchematics(collectionName, collection.json); + return readCollectionGenerators(collectionName, collection.json); } catch (e) { // this happens when package is misconfigured. We decided to ignore such a case. return null; } } -async function readCollectionSchematics( +function readCollectionGenerators( collectionName: string, collectionJson: any -) { - const generators = new Set(); +): GeneratorCollection { + const generators = new Set(); try { Object.entries( Object.assign({}, collectionJson.schematics, collectionJson.generators) - ).forEach(async ([k, v]: [any, any]) => { + ).forEach(([k, v]: [any, any]) => { try { if (canAdd(k, v)) { + let generatorType: GeneratorType; + switch (v['x-type']) { + case 'application': + generatorType = GeneratorType.Application; + break; + case 'library': + generatorType = GeneratorType.Library; + break; + default: + generatorType = GeneratorType.Other; + break; + } generators.add({ name: k, collection: collectionName, description: v.description || '', + type: generatorType, }); } } catch (e) { @@ -193,14 +209,14 @@ async function readCollectionSchematics( } return { name: collectionName, - schematics: Array.from(generators), + generators: Array.from(generators), }; } -export async function readSchematicOptions( +export async function readGeneratorOptions( workspaceJsonPath: string, collectionName: string, - schematicName: string + generatorName: string ): Promise { const basedir = join(workspaceJsonPath, '..'); const nodeModulesDir = join(basedir, 'node_modules'); @@ -213,22 +229,22 @@ export async function readSchematicOptions( collectionPackageJson.json.generators, dirname(collectionPackageJson.path) ); - const schematics = Object.assign( + const generators = Object.assign( {}, collectionJson.json.schematics, collectionJson.json.generators ); - const schematicSchema = readAndCacheJsonFile( - schematics[schematicName].schema, + const generatorSchema = readAndCacheJsonFile( + generators[generatorName].schema, dirname(collectionJson.path) ); const workspaceDefaults = readWorkspaceJsonDefaults(workspaceJsonPath); const defaults = workspaceDefaults && workspaceDefaults[collectionName] && - workspaceDefaults[collectionName][schematicName]; - return await normalizeSchema(schematicSchema.json, defaults); + workspaceDefaults[collectionName][generatorName]; + return await normalizeSchema(generatorSchema.json, defaults); } function canAdd( diff --git a/libs/server/src/lib/utils/utils.ts b/libs/server/src/lib/utils/utils.ts index 227fcb38ed..b735763e13 100644 --- a/libs/server/src/lib/utils/utils.ts +++ b/libs/server/src/lib/utils/utils.ts @@ -21,7 +21,7 @@ import { } from 'jsonc-parser'; import { getOutputChannel } from './output-channel'; -export interface SchematicDefaults { +export interface GeneratorDefaults { [name: string]: string; } @@ -216,7 +216,7 @@ export async function normalizeSchema( properties: { [k: string]: any }; required: string[]; }, - projectDefaults?: SchematicDefaults + projectDefaults?: GeneratorDefaults ): Promise { const options: CliOption[] = await parseJsonSchemaToOptions(registry, s); const requiredFields = new Set(s.required || []); diff --git a/libs/vscode/nx-run-target-view/src/lib/run-target-tree-item.ts b/libs/vscode/nx-run-target-view/src/lib/run-target-tree-item.ts index ebc5ee8ea2..d1a6e5a0a5 100644 --- a/libs/vscode/nx-run-target-view/src/lib/run-target-tree-item.ts +++ b/libs/vscode/nx-run-target-view/src/lib/run-target-tree-item.ts @@ -1,3 +1,4 @@ +import { GeneratorType } from '@nx-console/schema'; import { join } from 'path'; import { TreeItem, TreeItemCollapsibleState, TreeView, Uri } from 'vscode'; @@ -73,7 +74,8 @@ export class RunTargetTreeItem extends TreeItem { constructor( readonly workspaceJsonPath: string, readonly route: WorkspaceRouteTitle, - readonly extensionPath: string + readonly extensionPath: string, + readonly generatorType?: GeneratorType ) { super(route, TreeItemCollapsibleState.None); } diff --git a/libs/vscode/tasks/src/lib/cli-task-commands.ts b/libs/vscode/tasks/src/lib/cli-task-commands.ts index ec7c9ac8fc..250c969038 100644 --- a/libs/vscode/tasks/src/lib/cli-task-commands.ts +++ b/libs/vscode/tasks/src/lib/cli-task-commands.ts @@ -1,6 +1,6 @@ import { commands, ExtensionContext, window, Uri } from 'vscode'; -import { selectSchematic } from '@nx-console/server'; +import { selectGenerator } from '@nx-console/server'; import { verifyWorkspace } from '@nx-console/vscode/nx-workspace'; import { verifyBuilderDefinition } from '@nx-console/vscode/verify'; import { @@ -10,7 +10,7 @@ import { import { CliTaskProvider } from './cli-task-provider'; import { CliTaskQuickPickItem } from './cli-task-quick-pick-item'; import { selectFlags } from './select-flags'; -import { Option } from '@nx-console/schema'; +import { GeneratorType, Option } from '@nx-console/schema'; import { OptionType } from '@angular/cli/models/interface'; import { WorkspaceJsonConfiguration } from '@nrwl/devkit'; @@ -66,7 +66,7 @@ export function registerCliTaskCommands( ); commands.registerCommand(`${cli}.generate`, () => - selectSchematicAndPromptForFlags() + selectGeneratorAndPromptForFlags() ); commands.registerCommand(`${cli}.generate.ui`, () => @@ -76,13 +76,53 @@ export function registerCliTaskCommands( commands.registerCommand(`${cli}.generate.ui.fileexplorer`, (uri: Uri) => selectCliCommandAndShowUi('generate', context.extensionPath, uri) ); + + commands.registerCommand(`${cli}.generate.ui.app`, (uri: Uri) => { + selectCliCommandAndShowUi( + 'generate', + context.extensionPath, + uri, + GeneratorType.Application + ); + }); + commands.registerCommand(`${cli}.generate.ui.lib`, (uri: Uri) => { + selectCliCommandAndShowUi( + 'generate', + context.extensionPath, + uri, + GeneratorType.Library + ); + }); + commands.registerCommand( + `${cli}.generate.ui.app.fileexplorer`, + (uri: Uri) => { + selectCliCommandAndShowUi( + 'generate', + context.extensionPath, + uri, + GeneratorType.Application + ); + } + ); + commands.registerCommand( + `${cli}.generate.ui.lib.fileexplorer`, + (uri: Uri) => { + selectCliCommandAndShowUi( + 'generate', + context.extensionPath, + uri, + GeneratorType.Library + ); + } + ); }); } function selectCliCommandAndShowUi( command: string, extensionPath: string, - uri?: Uri + uri?: Uri, + generatorType?: GeneratorType ) { const workspacePath = cliTaskProvider.getWorkspacePath(); if (!workspacePath) { @@ -99,7 +139,8 @@ function selectCliCommandAndShowUi( const workspaceTreeItem = new RunTargetTreeItem( configurationFilePath, `${command[0].toUpperCase()}${command.slice(1)}` as WorkspaceRouteTitle, - extensionPath + extensionPath, + generatorType ); commands.executeCommand( @@ -194,7 +235,7 @@ async function selectCliCommandAndPromptForFlags( } } -async function selectSchematicAndPromptForFlags() { +async function selectGeneratorAndPromptForFlags() { const { validWorkspaceJson, workspaceType, configurationFilePath } = verifyWorkspace(); @@ -202,7 +243,7 @@ async function selectSchematicAndPromptForFlags() { return; } - const selection = await selectSchematic(configurationFilePath); + const selection = await selectGenerator(configurationFilePath); if (!selection) { return; } diff --git a/libs/vscode/webview/src/lib/get-task-execution-schema.ts b/libs/vscode/webview/src/lib/get-task-execution-schema.ts index f9de5eceab..ddc43668f0 100644 --- a/libs/vscode/webview/src/lib/get-task-execution-schema.ts +++ b/libs/vscode/webview/src/lib/get-task-execution-schema.ts @@ -1,9 +1,9 @@ -import { Option, TaskExecutionSchema } from '@nx-console/schema'; +import { GeneratorType, Option, TaskExecutionSchema } from '@nx-console/schema'; import { getOutputChannel, getTelemetry, readTargetDef, - selectSchematic, + selectGenerator, } from '@nx-console/server'; import { getNxConfig, verifyWorkspace } from '@nx-console/vscode/nx-workspace'; import { verifyBuilderDefinition } from '@nx-console/vscode/verify'; @@ -18,7 +18,8 @@ import { export async function getTaskExecutionSchema( cliTaskProvider: CliTaskProvider, workspaceRouteTitle: WorkspaceRouteTitle = 'Run', - contextMenuUri?: Uri + contextMenuUri?: Uri, + generatorType?: GeneratorType ): Promise { try { if (!cliTaskProvider.getWorkspacePath()) { @@ -112,38 +113,39 @@ export async function getTaskExecutionSchema( }); } case 'Generate': { - return selectSchematic(cliTaskProvider.getWorkspaceJsonPath()).then( - (schematic) => { - if (!schematic) { + return selectGenerator( + cliTaskProvider.getWorkspaceJsonPath(), + generatorType + ).then((generator) => { + if (!generator) { + return; + } + + generator.options.forEach((option) => { + // TODO: mixup between items and enum has been a source for recent bugs, + // util.ts normalizeSchema sets items from enum. + if (option.enum) { return; } - schematic.options.forEach((option) => { - // TODO: mixup between items and enum has been a source for recent bugs, - // util.ts normalizeSchema sets items from enum. - if (option.enum) { - return; - } - - if (isProjectOption(option)) { - option.enum = option.items = cliTaskProvider - .getProjectEntries() - .map((entry) => entry[0]) - .sort(); - } - }); - - const contextValues = contextMenuUri - ? getConfigValuesFromContextMenuUri( - schematic, - contextMenuUri, - cliTaskProvider - ) - : undefined; - - return { ...schematic, cliName: workspaceType, contextValues }; - } - ); + if (isProjectOption(option)) { + option.enum = option.items = cliTaskProvider + .getProjectEntries() + .map((entry) => entry[0]) + .sort(); + } + }); + + const contextValues = contextMenuUri + ? getConfigValuesFromContextMenuUri( + generator, + contextMenuUri, + cliTaskProvider + ) + : undefined; + + return { ...generator, cliName: workspaceType, contextValues }; + }); } } } catch (e) { @@ -166,7 +168,7 @@ export async function getTaskExecutionSchema( // Get information about where the user clicked if invoked through right click in the explorer context menu function getConfigValuesFromContextMenuUri( - schematic: TaskExecutionSchema, + generator: TaskExecutionSchema, contextMenuUri: Uri | undefined, cliTaskProvider: CliTaskProvider ): @@ -190,12 +192,12 @@ function getConfigValuesFromContextMenuUri( const appsDir = nxConfig.workspaceLayout?.appsDir ?? 'apps'; const libsDir = nxConfig.workspaceLayout?.libsDir ?? 'libs'; if ( - (appsDir && schematic.name === 'application') || - schematic.name === 'app' + (appsDir && generator.name === 'application') || + generator.name === 'app' ) { path = path.replace(appsDir, '').replace(/^\//, ''); } - if ((libsDir && schematic.name === 'library') || schematic.name === 'lib') { + if ((libsDir && generator.name === 'library') || generator.name === 'lib') { path = path.replace(libsDir, '').replace(/^\//, ''); } @@ -203,7 +205,7 @@ function getConfigValuesFromContextMenuUri( project: projectName, projectName, path, - ...(!(projectName && schematic.options.some(isProjectOption)) && { + ...(!(projectName && generator.options.some(isProjectOption)) && { directory: path, }), }; diff --git a/libs/vscode/webview/src/lib/webview.ts b/libs/vscode/webview/src/lib/webview.ts index fa461b9d3b..1e8254c0b9 100644 --- a/libs/vscode/webview/src/lib/webview.ts +++ b/libs/vscode/webview/src/lib/webview.ts @@ -35,11 +35,12 @@ export async function revealWebViewPanel({ runTargetTreeView, contextMenuUri, }: RevealWebViewPanelConfig) { - const { label } = runTargetTreeItem; + const { label, generatorType } = runTargetTreeItem; const schema = await getTaskExecutionSchema( cliTaskProvider, label, - contextMenuUri + contextMenuUri, + generatorType ); if (!schema) { From 911a1ccb3a5957c3c9cd8bf6d67548217b64232f Mon Sep 17 00:00:00 2001 From: Jonathan Cammisuli Date: Fri, 3 Sep 2021 11:35:58 -0400 Subject: [PATCH 2/4] better checks for generating on root project --- .vscode/launch.json | 5 ++++- libs/vscode/tasks/src/lib/cli-task-provider.ts | 16 +++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 275d8b03f8..14026ddda9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,7 +17,10 @@ "${workspaceFolder}/node_modules" ], "request": "launch", - "skipFiles": ["/**"], + "skipFiles": [ + "/**", + "/Applications/Visual Studio Code.app/**" + ], "type": "pwa-extensionHost" }, { diff --git a/libs/vscode/tasks/src/lib/cli-task-provider.ts b/libs/vscode/tasks/src/lib/cli-task-provider.ts index d94ab8c38e..116b25cb11 100644 --- a/libs/vscode/tasks/src/lib/cli-task-provider.ts +++ b/libs/vscode/tasks/src/lib/cli-task-provider.ts @@ -1,4 +1,4 @@ -import { join } from 'path'; +import { isAbsolute, join, relative } from 'path'; import { ProviderResult, Task, @@ -141,13 +141,15 @@ export class CliTaskProvider implements TaskProvider { const entry = this.getProjectEntries().find(([, def]) => { const fullProjectPath = join(this.getWorkspacePath(), def.root); + if (fullProjectPath === selectedPath) { + return true; + } + + const relativePath = relative(fullProjectPath, selectedPath); return ( - selectedPath.startsWith(fullProjectPath) && - // check that it's not a partial match - selectedPath - .replace(fullProjectPath, '') - .replace(/\\/g, '/') - .startsWith('/') + relativePath && + !relativePath.startsWith('..') && + !isAbsolute(relativePath) ); }); From 7f5cddb9825b145b5ab5cf02d8b2d3a2035c067b Mon Sep 17 00:00:00 2001 From: Jonathan Cammisuli Date: Fri, 3 Sep 2021 11:54:45 -0400 Subject: [PATCH 3/4] fix when context check for add lib command --- apps/vscode/src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vscode/src/package.json b/apps/vscode/src/package.json index 0cd9fc97d2..9c89a4db2b 100644 --- a/apps/vscode/src/package.json +++ b/apps/vscode/src/package.json @@ -132,7 +132,7 @@ }, { "command": "nx.generate.ui.lib", - "when": "isNxWorkspace && && nx.hasLibraryGenerators" + "when": "isNxWorkspace && nx.hasLibraryGenerators" }, { "command": "ng.lint", From babf086828ff1909599a68fd525c863483fcd890 Mon Sep 17 00:00:00 2001 From: Jonathan Cammisuli Date: Fri, 3 Sep 2021 13:05:12 -0400 Subject: [PATCH 4/4] change add to generate --- apps/vscode/src/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/vscode/src/package.json b/apps/vscode/src/package.json index 9c89a4db2b..91d188c3b4 100644 --- a/apps/vscode/src/package.json +++ b/apps/vscode/src/package.json @@ -390,7 +390,7 @@ }, { "category": "ng", - "title": "ng generate (ui)", + "title": "ng generate...", "command": "ng.generate.ui.fileexplorer" }, { @@ -530,7 +530,7 @@ }, { "category": "Nx", - "title": "Nx generate (ui)", + "title": "Nx generate...", "command": "nx.generate.ui.fileexplorer" }, { @@ -540,22 +540,22 @@ }, { "category": "Nx", - "title": "Add application", + "title": "generate application", "command": "nx.generate.ui.app" }, { "category": "Nx", - "title": "Add library", + "title": "generate library", "command": "nx.generate.ui.lib" }, { "category": "Nx", - "title": "Nx add application", + "title": "Nx generate application", "command": "nx.generate.ui.app.fileexplorer" }, { "category": "Nx", - "title": "Nx add library", + "title": "Nx generate library", "command": "nx.generate.ui.lib.fileexplorer" } ],