diff --git a/apps/vscode/src/main.ts b/apps/vscode/src/main.ts index ecd1ec3aed..7782fb7a04 100644 --- a/apps/vscode/src/main.ts +++ b/apps/vscode/src/main.ts @@ -24,6 +24,7 @@ import { getGenerators, teardownTelemetry, watchFile, + directoryExists, } from '@nx-console/server'; import { GlobalConfigurationStore, @@ -85,13 +86,13 @@ export async function activate(c: ExtensionContext) { const revealWebViewPanelCommand = commands.registerCommand( 'nxConsole.revealWebViewPanel', async (runTargetTreeItem: RunTargetTreeItem, contextMenuUri?: Uri) => { - if ( - !existsSync( - join(runTargetTreeItem.workspaceJsonPath, '..', 'node_modules') - ) - ) { - const { validNodeModules: hasNodeModules } = verifyNodeModules( - join(runTargetTreeItem.workspaceJsonPath, '..') + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', + '' + ); + if (!(await directoryExists(join(workspacePath, 'node_modules')))) { + const { validNodeModules: hasNodeModules } = await verifyNodeModules( + workspacePath ); if (!hasNodeModules) { return; @@ -116,6 +117,7 @@ export async function activate(c: ExtensionContext) { const vscodeWorkspacePath = workspace.workspaceFolders && workspace.workspaceFolders[0].uri.fsPath; + debugger; if (vscodeWorkspacePath) { scanForWorkspace(vscodeWorkspacePath); } @@ -168,14 +170,7 @@ function manuallySelectWorkspaceDefinition() { .then((value) => { if (value && value[0]) { const selectedDirectory = value[0].fsPath; - return setWorkspace( - join( - selectedDirectory, - existsSync(join(selectedDirectory, 'angular.json')) - ? 'angular.json' - : 'workspace.json' - ) - ); + return setWorkspace(selectedDirectory); } }); } else { @@ -188,32 +183,20 @@ function manuallySelectWorkspaceDefinition() { function scanForWorkspace(vscodeWorkspacePath: string) { let currentDirectory = vscodeWorkspacePath; - const { root } = parse(vscodeWorkspacePath); - - const workspaceJsonPath = WorkspaceConfigurationStore.instance.get( - 'nxWorkspaceJsonPath', + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', '' ); - if (workspaceJsonPath) { - currentDirectory = dirname(workspaceJsonPath); - } - while (currentDirectory !== root) { - if (existsSync(join(currentDirectory, 'angular.json'))) { - setWorkspace(join(currentDirectory, 'angular.json')); - } - if (existsSync(join(currentDirectory, 'workspace.json'))) { - setWorkspace(join(currentDirectory, 'workspace.json')); - } - currentDirectory = dirname(currentDirectory); + if (workspacePath) { + currentDirectory = workspacePath; } + + setWorkspace(currentDirectory); } -async function setWorkspace(workspaceJsonPath: string) { - WorkspaceConfigurationStore.instance.set( - 'nxWorkspaceJsonPath', - workspaceJsonPath - ); +async function setWorkspace(workspacePath: string) { + WorkspaceConfigurationStore.instance.set('nxWorkspacePath', workspacePath); const { verifyWorkspace } = await import('@nx-console/vscode/nx-workspace'); const { validWorkspaceJson } = await verifyWorkspace(); @@ -243,16 +226,13 @@ async function setWorkspace(workspaceJsonPath: string) { context.subscriptions.push(nxCommandsTreeView, nxProjectTreeView); } else { - WorkspaceConfigurationStore.instance.set( - 'nxWorkspaceJsonPath', - workspaceJsonPath - ); + WorkspaceConfigurationStore.instance.set('nxWorkspacePath', workspacePath); } - await setApplicationAndLibraryContext(workspaceJsonPath); + await setApplicationAndLibraryContext(workspacePath); - const isNxWorkspace = existsSync(join(workspaceJsonPath, '..', 'nx.json')); - const isAngularWorkspace = workspaceJsonPath.endsWith('angular.json'); + const isNxWorkspace = existsSync(join(workspacePath, 'nx.json')); + const isAngularWorkspace = existsSync(join(workspacePath, 'angular.json')); commands.executeCommand( 'setContext', @@ -261,7 +241,7 @@ async function setWorkspace(workspaceJsonPath: string) { ); commands.executeCommand('setContext', 'isNxWorkspace', isNxWorkspace); - registerWorkspaceFileWatcher(context, workspaceJsonPath); + registerWorkspaceFileWatcher(context, workspacePath); currentRunTargetTreeProvider.refresh(); nxProjectsTreeProvider.refresh(); @@ -278,30 +258,24 @@ async function setWorkspace(workspaceJsonPath: string) { getTelemetry().record('WorkspaceType', { workspaceType }); } -async function setApplicationAndLibraryContext(workspaceJsonPath: string) { +async function setApplicationAndLibraryContext(workspacePath: string) { const { getNxConfig } = await import('@nx-console/vscode/nx-workspace'); let nxConfig: Awaited>; try { - nxConfig = await getNxConfig(dirname(workspaceJsonPath)); + nxConfig = await getNxConfig(workspacePath); } catch { return; } commands.executeCommand('setContext', 'nxAppsDir', [ - join( - dirname(workspaceJsonPath), - nxConfig.workspaceLayout?.appsDir ?? 'apps' - ), + join(workspacePath, nxConfig.workspaceLayout?.appsDir ?? 'apps'), ]); commands.executeCommand('setContext', 'nxLibsDir', [ - join( - dirname(workspaceJsonPath), - nxConfig.workspaceLayout?.libsDir ?? 'libs' - ), + join(workspacePath, nxConfig.workspaceLayout?.libsDir ?? 'libs'), ]); - const generatorCollections = await getGenerators(workspaceJsonPath); + const generatorCollections = await getGenerators(workspacePath); let hasApplicationGenerators = false; let hasLibraryGenerators = false; diff --git a/libs/server/src/index.ts b/libs/server/src/index.ts index 507949bedc..4bf115d637 100644 --- a/libs/server/src/index.ts +++ b/libs/server/src/index.ts @@ -7,7 +7,8 @@ export * from './lib/utils/get-generators'; export * from './lib/utils/get-executors'; export * from './lib/utils/read-collections'; export { - fileExistsSync, + fileExists, + directoryExists, readAndParseJson, readAndCacheJsonFile, normalizeSchema, diff --git a/libs/server/src/lib/utils/build-project-path.ts b/libs/server/src/lib/utils/build-project-path.ts index e46901d939..9ef8f19724 100644 --- a/libs/server/src/lib/utils/build-project-path.ts +++ b/libs/server/src/lib/utils/build-project-path.ts @@ -1,15 +1,14 @@ -import { dirname, join } from 'path'; +import { join } from 'path'; /** * Builds the project path from the given project name. - * @param workspaceJsonPath The full path to the workspace.json file - * @param projectPath The path to the project relative to the workspace.json file + * @param workspacePath The full path to the configured workspace + * @param projectPath The path to the project relative to the workspace * @returns The full path to the project.json file */ export function buildProjectPath( - workspaceJsonPath: string, + workspacePath: string, projectPath: string ): string { - const workspaceRootDir = dirname(workspaceJsonPath); - return join(workspaceRootDir, projectPath, 'project.json'); + return join(workspacePath, projectPath, 'project.json'); } diff --git a/libs/server/src/lib/utils/get-executors.ts b/libs/server/src/lib/utils/get-executors.ts index 8fc6a85029..4043c38c9f 100644 --- a/libs/server/src/lib/utils/get-executors.ts +++ b/libs/server/src/lib/utils/get-executors.ts @@ -2,13 +2,10 @@ import { CollectionInfo } from '@nx-console/schema'; import { readCollectionsFromNodeModules } from './read-collections'; export async function getExecutors( - workspaceJsonPath: string, + workspacePath: string, clearPackageJsonCache: boolean ): Promise { return ( - await readCollectionsFromNodeModules( - workspaceJsonPath, - clearPackageJsonCache - ) + await readCollectionsFromNodeModules(workspacePath, clearPackageJsonCache) ).filter((collection) => collection.type === 'executor'); } diff --git a/libs/server/src/lib/utils/get-generators.ts b/libs/server/src/lib/utils/get-generators.ts index a18c578abb..3df891a3d5 100644 --- a/libs/server/src/lib/utils/get-generators.ts +++ b/libs/server/src/lib/utils/get-generators.ts @@ -3,7 +3,7 @@ import { basename, join } from 'path'; import { directoryExists, - fileExistsSync, + fileExists, listFiles, normalizeSchema, readAndCacheJsonFile, @@ -14,11 +14,11 @@ import { } from './read-collections'; export async function getGenerators( - workspaceJsonPath: string + workspacePath: string ): Promise { - const basedir = join(workspaceJsonPath, '..'); + const basedir = workspacePath; const collections = await readCollectionsFromNodeModules( - workspaceJsonPath, + workspacePath, false ); let generatorCollections = collections.filter( @@ -62,7 +62,7 @@ async function readWorkspaceGeneratorsCollection( const collectionDir = join(basedir, workspaceGeneratorsPath); const collectionName = 'workspace-generator'; const collectionPath = join(collectionDir, 'collection.json'); - if (fileExistsSync(collectionPath)) { + if (await fileExists(collectionPath)) { const collection = await readAndCacheJsonFile( 'collection.json', collectionDir diff --git a/libs/server/src/lib/utils/read-collections.ts b/libs/server/src/lib/utils/read-collections.ts index da9a30925a..e3a479dceb 100644 --- a/libs/server/src/lib/utils/read-collections.ts +++ b/libs/server/src/lib/utils/read-collections.ts @@ -8,14 +8,13 @@ import { } from './utils'; export async function readCollectionsFromNodeModules( - workspaceJsonPath: string, + workspacePath: string, clearPackageJsonCache: boolean ): Promise { - const basedir = dirname(workspaceJsonPath); - const nodeModulesDir = join(basedir, 'node_modules'); + const nodeModulesDir = join(workspacePath, 'node_modules'); if (clearPackageJsonCache) { - clearJsonCache('package.json', basedir); + clearJsonCache('package.json', workspacePath); } const packages = await listOfUnnestedNpmPackages(nodeModulesDir); diff --git a/libs/server/src/lib/utils/utils.ts b/libs/server/src/lib/utils/utils.ts index 60d84b1e09..816abd5eae 100644 --- a/libs/server/src/lib/utils/utils.ts +++ b/libs/server/src/lib/utils/utils.ts @@ -1,6 +1,9 @@ import { Schema } from '@nrwl/tao/src/shared/params'; import * as path from 'path'; -import type { WorkspaceJsonConfiguration } from '@nrwl/devkit'; +import type { + WorkspaceJsonConfiguration, + NxJsonConfiguration, +} from '@nrwl/devkit'; import { ItemsWithEnum, @@ -119,9 +122,9 @@ export async function directoryExists(filePath: string): Promise { } } -export function fileExistsSync(filePath: string): boolean { +export async function fileExists(filePath: string): Promise { try { - return statSync(filePath).isFile(); + return (await stat(filePath)).isFile(); } catch { return false; } @@ -347,7 +350,9 @@ function renameProperty(obj: any, from: string, to: string) { delete obj[from]; } -export function toWorkspaceFormat(w: any): WorkspaceJsonConfiguration { +export function toWorkspaceFormat( + w: any +): WorkspaceJsonConfiguration & NxJsonConfiguration { Object.values(w.projects || {}).forEach((project: any) => { if (project.architect) { renameProperty(project, 'architect', 'targets'); diff --git a/libs/typescript-plugin/src/lib/typescript-plugin.ts b/libs/typescript-plugin/src/lib/typescript-plugin.ts index 48594a2d00..35be63393a 100644 --- a/libs/typescript-plugin/src/lib/typescript-plugin.ts +++ b/libs/typescript-plugin/src/lib/typescript-plugin.ts @@ -34,8 +34,9 @@ export async function enableTypeScriptPlugin(context: vscode.ExtensionContext) { return; } - const workspaceRoot = dirname( - WorkspaceConfigurationStore.instance.get('nxWorkspaceJsonPath', '') + const workspaceRoot = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', + '' ); vscode.workspace.onDidOpenTextDocument( diff --git a/libs/vscode/configuration/src/lib/configuration-keys.ts b/libs/vscode/configuration/src/lib/configuration-keys.ts index 436764e311..394deec281 100644 --- a/libs/vscode/configuration/src/lib/configuration-keys.ts +++ b/libs/vscode/configuration/src/lib/configuration-keys.ts @@ -11,7 +11,7 @@ export const GLOBAL_CONFIG_KEYS = [ */ export type GlobalConfigKeys = typeof GLOBAL_CONFIG_KEYS[number]; -export const WORKSPACE_CONFIG_KEYS = ['nxWorkspaceJsonPath'] as const; +export const WORKSPACE_CONFIG_KEYS = ['nxWorkspacePath'] as const; /** * configuration Keys used for NxConsole on a vscode workspace level */ diff --git a/libs/vscode/json-schema/src/lib/project-json-schema.ts b/libs/vscode/json-schema/src/lib/project-json-schema.ts index d5dc57bf11..97004cf8fa 100644 --- a/libs/vscode/json-schema/src/lib/project-json-schema.ts +++ b/libs/vscode/json-schema/src/lib/project-json-schema.ts @@ -1,7 +1,7 @@ import { CollectionInfo } from '@nx-console/schema'; import { getExecutors, watchFile } from '@nx-console/server'; import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; -import { dirname, join } from 'path'; +import { join } from 'path'; import * as vscode from 'vscode'; let FILE_WATCHER: vscode.FileSystemWatcher; @@ -9,7 +9,7 @@ let FILE_WATCHER: vscode.FileSystemWatcher; export class ProjectJsonSchema { constructor(context: vscode.ExtensionContext) { const workspacePath = WorkspaceConfigurationStore.instance.get( - 'nxWorkspaceJsonPath', + 'nxWorkspacePath', '' ); @@ -21,12 +21,9 @@ export class ProjectJsonSchema { * Whenever a new package is added to the package.json, we recreate the schema. * This allows newly added plugins to be added */ - FILE_WATCHER = watchFile( - join(dirname(workspacePath), 'package.json'), - () => { - this.setupSchema(workspacePath, context.extensionUri, true); - } - ); + FILE_WATCHER = watchFile(join(workspacePath, 'package.json'), () => { + this.setupSchema(workspacePath, context.extensionUri, true); + }); context.subscriptions.push(FILE_WATCHER); this.setupSchema(workspacePath, context.extensionUri); diff --git a/libs/vscode/json-schema/src/lib/workspace-json-schema.ts b/libs/vscode/json-schema/src/lib/workspace-json-schema.ts index 5edacf1c05..87882e08ff 100644 --- a/libs/vscode/json-schema/src/lib/workspace-json-schema.ts +++ b/libs/vscode/json-schema/src/lib/workspace-json-schema.ts @@ -9,7 +9,7 @@ let FILE_WATCHER: vscode.FileSystemWatcher; export class WorkspaceJsonSchema { constructor(context: vscode.ExtensionContext) { const workspacePath = WorkspaceConfigurationStore.instance.get( - 'nxWorkspaceJsonPath', + 'nxWorkspacePath', '' ); @@ -21,12 +21,9 @@ export class WorkspaceJsonSchema { * Whenever a new package is added to the package.json, we recreate the schema. * This allows newly added plugins to be added */ - FILE_WATCHER = watchFile( - join(dirname(workspacePath), 'package.json'), - () => { - this.setupSchema(workspacePath, context.extensionUri, true); - } - ); + FILE_WATCHER = watchFile(join(workspacePath, 'package.json'), () => { + this.setupSchema(workspacePath, context.extensionUri, true); + }); context.subscriptions.push(FILE_WATCHER); this.setupSchema(workspacePath, context.extensionUri); diff --git a/libs/vscode/nx-project-view/src/lib/nx-project-tree-item.ts b/libs/vscode/nx-project-view/src/lib/nx-project-tree-item.ts index eb768a1439..9dafa2cc0b 100644 --- a/libs/vscode/nx-project-view/src/lib/nx-project-tree-item.ts +++ b/libs/vscode/nx-project-view/src/lib/nx-project-tree-item.ts @@ -12,6 +12,7 @@ export class NxProjectTreeItem extends TreeItem { export interface NxProject { project: string; + root: string; target?: { name: string; configuration?: string; diff --git a/libs/vscode/nx-project-view/src/lib/nx-project-tree-provider.ts b/libs/vscode/nx-project-view/src/lib/nx-project-tree-provider.ts index 111147ab73..9dd3f68212 100644 --- a/libs/vscode/nx-project-view/src/lib/nx-project-tree-provider.ts +++ b/libs/vscode/nx-project-view/src/lib/nx-project-tree-provider.ts @@ -1,19 +1,16 @@ +import { AbstractTreeProvider, clearJsonCache } from '@nx-console/server'; +import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; +import { revealNxProject } from '@nx-console/vscode/nx-workspace'; +import { CliTaskProvider } from '@nx-console/vscode/tasks'; import { join } from 'path'; import { commands, ExtensionContext, - ProviderResult, TreeItemCollapsibleState, Uri, } from 'vscode'; - -import { AbstractTreeProvider, clearJsonCache } from '@nx-console/server'; -import { CliTaskProvider } from '@nx-console/vscode/tasks'; import { NxProject, NxProjectTreeItem } from './nx-project-tree-item'; -import { revealNxProject } from '@nx-console/vscode/nx-workspace'; -import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; - /** * Provides data for the "Projects" tree view */ @@ -41,16 +38,16 @@ export class NxProjectTreeProvider extends AbstractTreeProvider { - const { project, target } = element.nxProject; + const { project, target, root } = element.nxProject; if (target) { if (target.configuration) { return this.createNxProjectTreeItem( - { project, target: { name: target.name } }, + { project, target: { name: target.name }, root }, target.name ); } else { - return this.createNxProjectTreeItem({ project }, project); + return this.createNxProjectTreeItem({ project, root }, project); } } else { return null; @@ -58,20 +55,20 @@ export class NxProjectTreeProvider extends AbstractTreeProvider => this.createNxProjectTreeItem( - { project: name }, + { project: name, root: def.root }, name, Boolean(def.targets) ) @@ -117,7 +114,7 @@ export class NxProjectTreeProvider extends AbstractTreeProvider => this.createNxProjectTreeItem( - { target: { name }, project }, + { target: { name }, project, root: projectDef.root }, name, Boolean(projectDef.targets?.[name].configurations) ) @@ -141,7 +138,11 @@ export class NxProjectTreeProvider extends AbstractTreeProvider this.createNxProjectTreeItem( - { target: { ...target, configuration: name }, project }, + { + target: { ...target, configuration: name }, + project, + root: projectDef.root, + }, name ) ) @@ -176,13 +177,14 @@ export class NxProjectTreeProvider extends AbstractTreeProvider { private scanning = Boolean( - WorkspaceConfigurationStore.instance.get('nxWorkspaceJsonPath', '') + WorkspaceConfigurationStore.instance.get('nxWorkspacePath', '') ); /** @@ -53,12 +53,12 @@ export class RunTargetTreeProvider extends AbstractTreeProvider< } getChildren() { - const workspaceJsonPath = WorkspaceConfigurationStore.instance.get( - 'nxWorkspaceJsonPath', + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', '' ); - if (!workspaceJsonPath) { + if (!workspacePath) { if (this.scanning) { return [SCANNING_FOR_WORKSPACE]; } else { @@ -66,12 +66,12 @@ export class RunTargetTreeProvider extends AbstractTreeProvider< } } - CHANGE_WORKSPACE.description = "Current: " + dirname(workspaceJsonPath); + CHANGE_WORKSPACE.description = 'Current: ' + workspacePath; return [ ...ROUTE_LIST.map( (route) => - new RunTargetTreeItem(workspaceJsonPath, route, this.extensionPath) + new RunTargetTreeItem(workspacePath, route, this.extensionPath) ), CHANGE_WORKSPACE, ]; diff --git a/libs/vscode/nx-workspace/src/lib/get-nx-workspace-config.ts b/libs/vscode/nx-workspace/src/lib/get-nx-workspace-config.ts index ac2ae5971c..71d6b69737 100644 --- a/libs/vscode/nx-workspace/src/lib/get-nx-workspace-config.ts +++ b/libs/vscode/nx-workspace/src/lib/get-nx-workspace-config.ts @@ -1,40 +1,26 @@ -import { readAndCacheJsonFile, cacheJson } from '@nx-console/server'; import { getNxWorkspacePackageFileUtils } from './get-nx-workspace-package'; -import type { WorkspaceJsonConfiguration } from '@nrwl/devkit'; +import type { + WorkspaceJsonConfiguration, + NxJsonConfiguration, +} from '@nrwl/devkit'; +import { join } from 'path'; export async function getNxWorkspaceConfig( basedir: string, - workspaceJsonPath: string -): Promise { - // try and use the workspace version of nx - try { - let cachedWorkspaceJson = cacheJson(workspaceJsonPath).json; - if (!cachedWorkspaceJson || hasNxProject(cachedWorkspaceJson)) { - const workspace = ( - await getNxWorkspacePackageFileUtils() - ).readWorkspaceConfig({ - format: 'nx', - path: basedir, - }); - cachedWorkspaceJson = cacheJson(workspaceJsonPath, '', workspace).json; - } - return cachedWorkspaceJson; - } catch (e) { - return (await readAndCacheJsonFile(workspaceJsonPath)).json; - } -} + format: 'nx' | 'angularCli' +): Promise<{ + workspaceConfiguration: WorkspaceJsonConfiguration & NxJsonConfiguration; + configPath: string; +}> { + const nxWorkspacePackage = await getNxWorkspacePackageFileUtils(); + + const configFile = nxWorkspacePackage.workspaceFileName(); -/** - * There are points in time where the async nature of the nx-workspace package is still in being resolved. - * This function will check if the projects are strings - * @param cachedWorkspaceJson - * @returns - */ -function hasNxProject( - cachedWorkspaceJson?: WorkspaceJsonConfiguration -): boolean { - const projects = cachedWorkspaceJson?.projects ?? {}; - return Object.entries(projects).some( - ([, project]) => typeof project === 'string' - ); + return { + workspaceConfiguration: nxWorkspacePackage.readWorkspaceConfig({ + format, + path: basedir, + }), + configPath: join(basedir, configFile), + }; } diff --git a/libs/vscode/nx-workspace/src/lib/get-nx-workspace-package.ts b/libs/vscode/nx-workspace/src/lib/get-nx-workspace-package.ts index 8ddfde9bd7..b85d10e5a4 100644 --- a/libs/vscode/nx-workspace/src/lib/get-nx-workspace-package.ts +++ b/libs/vscode/nx-workspace/src/lib/get-nx-workspace-package.ts @@ -1,5 +1,5 @@ import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; -import { dirname, join } from 'path'; +import { join } from 'path'; import * as NxWorkspaceFileUtils from '@nrwl/workspace/src/core/file-utils'; import { getOutputChannel } from '@nx-console/server'; import { platform } from 'os'; @@ -12,8 +12,9 @@ declare function __non_webpack_require__(importPath: string): any; export async function getNxWorkspacePackageFileUtils(): Promise< typeof NxWorkspaceFileUtils > { - const workspacePath = dirname( - WorkspaceConfigurationStore.instance.get('nxWorkspaceJsonPath', '') + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', + '' ); let importPath = join( diff --git a/libs/vscode/nx-workspace/src/lib/get-raw-workspace.ts b/libs/vscode/nx-workspace/src/lib/get-raw-workspace.ts index f636b7ade3..c7528b6e6f 100644 --- a/libs/vscode/nx-workspace/src/lib/get-raw-workspace.ts +++ b/libs/vscode/nx-workspace/src/lib/get-raw-workspace.ts @@ -1,18 +1,27 @@ import type { WorkspaceJsonConfiguration } from '@nrwl/devkit'; -import { readAndParseJson } from '@nx-console/server'; +import { fileExists, readAndParseJson } from '@nx-console/server'; import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; +import { join } from 'path'; /** * Get the raw workspace file that hasn't been normalized by nx + * + * This is only used for certain operations that need the raw workspace file. + * This shouldn't be used unless absolutely necessary. + * + * @deprecated */ export async function getRawWorkspace() { - const workspaceJsonPath = WorkspaceConfigurationStore.instance.get( - 'nxWorkspaceJsonPath', + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', '' ); + const workspaceJsonPath = join(workspacePath, 'workspace.json'); - const rawWorkspace = (await readAndParseJson( - workspaceJsonPath - )) as WorkspaceJsonConfiguration; - return { rawWorkspace, workspaceJsonPath }; + if (await fileExists(workspaceJsonPath)) { + const rawWorkspace = (await readAndParseJson( + workspacePath + )) as WorkspaceJsonConfiguration; + return { rawWorkspace, workspaceJsonPath }; + } } diff --git a/libs/vscode/nx-workspace/src/lib/reveal-workspace-json.ts b/libs/vscode/nx-workspace/src/lib/reveal-workspace-json.ts index c8a8dd41b9..70c6d44967 100644 --- a/libs/vscode/nx-workspace/src/lib/reveal-workspace-json.ts +++ b/libs/vscode/nx-workspace/src/lib/reveal-workspace-json.ts @@ -1,28 +1,27 @@ -import { buildProjectPath } from '@nx-console/server'; +import { buildProjectPath, fileExists } from '@nx-console/server'; +import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; import { Selection, TextDocument, Uri, window, workspace } from 'vscode'; + import { getProjectLocations } from './find-workspace-json-target'; -import { getRawWorkspace } from './get-raw-workspace'; export async function revealNxProject( projectName: string, + root: string, target?: { name: string; configuration?: string } ) { - const raw = await getRawWorkspace(); - const rawWorkspace = raw.rawWorkspace; - let workspaceJsonPath = raw.workspaceJsonPath; - - /** - * if the project is a split config, just use the project.json as the "workspace.json" - */ - if (typeof rawWorkspace.projects[projectName] === 'string') { - workspaceJsonPath = buildProjectPath( - workspaceJsonPath, - rawWorkspace.projects[projectName] as unknown as string - ); + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', + '' + ); + const projectPath = buildProjectPath(workspacePath, root); + + let path = workspacePath; + if (await fileExists(projectPath)) { + path = projectPath; } const document: TextDocument = await workspace.openTextDocument( - Uri.file(workspaceJsonPath) + Uri.file(path) ); const projectLocations = getProjectLocations(document, projectName); diff --git a/libs/vscode/nx-workspace/src/lib/verify-workspace.ts b/libs/vscode/nx-workspace/src/lib/verify-workspace.ts index abcb749e03..c81ab3b241 100644 --- a/libs/vscode/nx-workspace/src/lib/verify-workspace.ts +++ b/libs/vscode/nx-workspace/src/lib/verify-workspace.ts @@ -1,54 +1,42 @@ +import { NxJsonConfiguration, WorkspaceJsonConfiguration } from '@nrwl/devkit'; import { - fileExistsSync, + fileExists, getOutputChannel, getTelemetry, toWorkspaceFormat, } from '@nx-console/server'; -import { window } from 'vscode'; -import { dirname, join } from 'path'; import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; -import { WorkspaceJsonConfiguration } from '@nrwl/devkit'; +import { join } from 'path'; +import { window } from 'vscode'; import { getNxWorkspaceConfig } from './get-nx-workspace-config'; -export async function verifyWorkspace(): Promise<{ +interface Workspace { validWorkspaceJson: boolean; - json: WorkspaceJsonConfiguration; + json: WorkspaceJsonConfiguration & NxJsonConfiguration; workspaceType: 'ng' | 'nx'; configurationFilePath: string; -}> { - const workspacePath = dirname( - WorkspaceConfigurationStore.instance.get('nxWorkspaceJsonPath', '') - ); +} - const workspaceJsonPath = join(workspacePath, 'workspace.json'); - const angularJsonPath = join(workspacePath, 'angular.json'); +export async function verifyWorkspace(): Promise { + const workspacePath = WorkspaceConfigurationStore.instance.get( + 'nxWorkspacePath', + '' + ); + const isAngularWorkspace = await fileExists( + join(workspacePath, 'angularCli') + ); + const config = await getNxWorkspaceConfig( + workspacePath, + isAngularWorkspace ? 'angularCli' : 'nx' + ); try { - if (fileExistsSync(workspaceJsonPath)) { - return { - validWorkspaceJson: true, - // TODO(cammisuli): change all instances to use the new version - basically reverse this to the new format - json: toWorkspaceFormat( - await getNxWorkspaceConfig(workspacePath, workspaceJsonPath) - ), - workspaceType: 'nx', - configurationFilePath: workspaceJsonPath, - }; - } else if (fileExistsSync(angularJsonPath)) { - return { - validWorkspaceJson: true, - json: toWorkspaceFormat( - await getNxWorkspaceConfig(workspacePath, angularJsonPath) - ), - workspaceType: 'ng', - configurationFilePath: angularJsonPath, - }; - } else { - // Handles below along with other runtime errors. - throw new Error( - `Could not find configuration file in selected directory: ${workspacePath}` - ); - } + return { + validWorkspaceJson: true, + workspaceType: isAngularWorkspace ? 'ng' : 'nx', + json: toWorkspaceFormat(config.workspaceConfiguration), + configurationFilePath: config.configPath, + }; } catch (e) { const humanReadableError = 'Invalid workspace: ' + workspacePath; window.showErrorMessage(humanReadableError, 'Show Error').then((value) => { @@ -67,6 +55,7 @@ export async function verifyWorkspace(): Promise<{ validWorkspaceJson: false, workspaceType: 'nx', json: { + npmScope: '@nx-console', projects: {}, version: 2, }, diff --git a/libs/vscode/nx-workspace/src/lib/workspace-codelens-provider.ts b/libs/vscode/nx-workspace/src/lib/workspace-codelens-provider.ts index f849c3643f..62c2b321ad 100644 --- a/libs/vscode/nx-workspace/src/lib/workspace-codelens-provider.ts +++ b/libs/vscode/nx-workspace/src/lib/workspace-codelens-provider.ts @@ -16,7 +16,10 @@ import { getProjectLocations, ProjectLocations, } from './find-workspace-json-target'; -import { GlobalConfigurationStore } from '@nx-console/vscode/configuration'; +import { + GlobalConfigurationStore, + WorkspaceConfigurationStore, +} from '@nx-console/vscode/configuration'; import { getRawWorkspace } from './get-raw-workspace'; import { buildProjectPath } from '@nx-console/server'; @@ -69,18 +72,14 @@ export class WorkspaceCodeLensProvider implements CodeLensProvider { const lens: CodeLens[] = []; let projectName = ''; + const { json } = await verifyWorkspace(); - /** - * Find the project name of the corresponding project.json file - */ - const { rawWorkspace, workspaceJsonPath } = await getRawWorkspace(); if (document.uri.path.endsWith('project.json')) { - for (const [key, project] of Object.entries(rawWorkspace.projects)) { + for (const [key, project] of Object.entries(json.projects)) { if ( - typeof project === 'string' && document.uri.path .replace(/\\/g, '/') - .endsWith(`${project}/project.json`) + .endsWith(`${project.root}/project.json`) ) { projectName = key; break; @@ -102,7 +101,7 @@ export class WorkspaceCodeLensProvider implements CodeLensProvider { document, lens, projectName, - workspaceJsonPath + WorkspaceConfigurationStore.instance.get('nxWorkspacePath', '') ); this.buildTargetLenses( @@ -120,7 +119,7 @@ export class WorkspaceCodeLensProvider implements CodeLensProvider { document: TextDocument, lens: CodeLens[], projectName: string, - workspaceJsonPath: string + workspacePath: string ) { if (!project.projectPath) { return; @@ -130,7 +129,7 @@ export class WorkspaceCodeLensProvider implements CodeLensProvider { new ProjectCodeLens( new Range(position, position), projectName, - buildProjectPath(workspaceJsonPath, project.projectPath) + buildProjectPath(workspacePath, project.projectPath) ) ); } diff --git a/libs/vscode/tasks/src/lib/cli-task-commands.ts b/libs/vscode/tasks/src/lib/cli-task-commands.ts index c0624e6e83..fabce4f68f 100644 --- a/libs/vscode/tasks/src/lib/cli-task-commands.ts +++ b/libs/vscode/tasks/src/lib/cli-task-commands.ts @@ -276,13 +276,19 @@ export async function selectCliProject( ) { const items = (await cliTaskProvider.getProjectEntries(json)) .filter(([, { targets }]) => Boolean(targets)) - .flatMap(([project, { targets }]) => ({ project, targets })) + .flatMap(([project, { targets, root }]) => ({ project, targets, root })) .filter( ({ targets }) => Boolean(targets && targets[command]) || command === 'run' ) .map( - ({ project, targets }) => - new CliTaskQuickPickItem(project, targets![command]!, command, project) + ({ project, targets, root }) => + new CliTaskQuickPickItem( + project, + root, + targets![command]!, + command, + project + ) ); if (!items.length) { diff --git a/libs/vscode/tasks/src/lib/cli-task-provider.ts b/libs/vscode/tasks/src/lib/cli-task-provider.ts index e554c806dd..5e85ac4475 100644 --- a/libs/vscode/tasks/src/lib/cli-task-provider.ts +++ b/libs/vscode/tasks/src/lib/cli-task-provider.ts @@ -36,24 +36,28 @@ export class CliTaskProvider implements TaskProvider { } getWorkspacePath() { - return join(this.getWorkspaceJsonPath(), '..'); + return WorkspaceConfigurationStore.instance.get('nxWorkspacePath', ''); } + /** + * + * @deprecated + */ getWorkspaceJsonPath() { - return WorkspaceConfigurationStore.instance.get('nxWorkspaceJsonPath', ''); + return WorkspaceConfigurationStore.instance.get('nxWorkspacePath', ''); } provideTasks(): ProviderResult { return null; } - resolveTask(task: Task): Task | undefined { + async resolveTask(task: Task): Promise { if ( - this.getWorkspaceJsonPath() && + this.getWorkspacePath() && task.definition.command && task.definition.project ) { - const cliTask = this.createTask({ + const cliTask = await this.createTask({ command: task.definition.command, positional: task.definition.project, flags: Array.isArray(task.definition.flags) @@ -66,12 +70,12 @@ export class CliTaskProvider implements TaskProvider { } } - createTask(definition: CliTaskDefinition) { - return CliTask.create(definition, this.getWorkspaceJsonPath()); + async createTask(definition: CliTaskDefinition) { + return CliTask.create(definition, this.getWorkspacePath()); } - executeTask(definition: CliTaskDefinition) { - const { validNodeModules: hasNodeModules } = verifyNodeModules( + async executeTask(definition: CliTaskDefinition) { + const { validNodeModules: hasNodeModules } = await verifyNodeModules( this.getWorkspacePath() ); if (!hasNodeModules) { @@ -102,7 +106,7 @@ export class CliTaskProvider implements TaskProvider { cliTaskProvider.getWorkspacePath() ); } else { - task = this.createTask(definition); + task = await this.createTask(definition); } const telemetry = getTelemetry(); diff --git a/libs/vscode/tasks/src/lib/cli-task-quick-pick-item.ts b/libs/vscode/tasks/src/lib/cli-task-quick-pick-item.ts index 03e2ae749b..3752461f9a 100644 --- a/libs/vscode/tasks/src/lib/cli-task-quick-pick-item.ts +++ b/libs/vscode/tasks/src/lib/cli-task-quick-pick-item.ts @@ -4,6 +4,7 @@ import { QuickPickItem } from 'vscode'; export class CliTaskQuickPickItem implements QuickPickItem { constructor( readonly projectName: string, + readonly projectRoot: string, readonly targetDef: TargetConfiguration, readonly command: string, readonly label: string diff --git a/libs/vscode/tasks/src/lib/cli-task.ts b/libs/vscode/tasks/src/lib/cli-task.ts index 616ff31e03..08ec0ec560 100644 --- a/libs/vscode/tasks/src/lib/cli-task.ts +++ b/libs/vscode/tasks/src/lib/cli-task.ts @@ -1,21 +1,21 @@ +import { fileExists } from '@nx-console/server'; import { join } from 'path'; import { Task, TaskGroup, TaskScope } from 'vscode'; import { CliTaskDefinition } from './cli-task-definition'; import { getShellExecutionForConfig } from './shell-execution'; export class CliTask extends Task { - static create( + static async create( definition: CliTaskDefinition, - workspaceJsonPath: string - ): CliTask { - const workspacePath = join(workspaceJsonPath, '..'); + workspacePath: string + ): Promise { const { command } = definition; // Using `run [project]:[command]` is more backwards compatible in case different // versions of CLI does not handle `[command] [project]` args. const args = getArgs(definition); - const useNxCli = workspaceJsonPath.endsWith('workspace.json'); + const useNxCli = await fileExists(join(workspacePath, 'nx.json')); const displayCommand = useNxCli ? `nx ${args.join(' ')}` diff --git a/libs/vscode/tasks/src/lib/select-generator.ts b/libs/vscode/tasks/src/lib/select-generator.ts index eaa512ed8e..58008344c3 100644 --- a/libs/vscode/tasks/src/lib/select-generator.ts +++ b/libs/vscode/tasks/src/lib/select-generator.ts @@ -11,14 +11,13 @@ import { normalizeSchema, readAndCacheJsonFile, } from '@nx-console/server'; -import { getNxConfig } from '@nx-console/vscode/nx-workspace'; +import { getNxConfig, verifyWorkspace } from '@nx-console/vscode/nx-workspace'; import { dirname, join } from 'path'; -async function readWorkspaceJsonDefaults( - workspaceJsonPath: string -): Promise { - const workspaceJson = await readAndCacheJsonFile(workspaceJsonPath); - let defaults = workspaceJson.json.schematics || workspaceJson.json.generators; +async function readWorkspaceJsonDefaults(workspacePath: string): Promise { + const { json } = await verifyWorkspace(); + + let defaults = json.generators; if (!defaults) { try { @@ -26,8 +25,7 @@ async function readWorkspaceJsonDefaults( * This could potentially fail if we're in an Angular CLI project without schematics being part of angular.json * Default the default to {} on the catch */ - defaults = - (await getNxConfig(dirname(workspaceJsonPath))).generators || {}; + defaults = (await getNxConfig(dirname(workspacePath))).generators || {}; } catch (e) { defaults = {}; } @@ -40,16 +38,18 @@ async function readWorkspaceJsonDefaults( if (!collectionDefaultsMap[collectionName]) { collectionDefaultsMap[collectionName] = {}; } - collectionDefaultsMap[collectionName][generatorName] = defaults[key]; + collectionDefaultsMap[collectionName][generatorName] = defaults?.[key]; } else { const collectionName = key; if (!collectionDefaultsMap[collectionName]) { collectionDefaultsMap[collectionName] = {}; } - Object.keys(defaults[collectionName]).forEach((generatorName) => { - collectionDefaultsMap[collectionName][generatorName] = - defaults[collectionName][generatorName]; - }); + Object.keys(defaults?.[collectionName] ?? {}).forEach( + (generatorName) => { + collectionDefaultsMap[collectionName][generatorName] = + defaults?.[collectionName][generatorName]; + } + ); } return collectionDefaultsMap; }, @@ -59,12 +59,11 @@ async function readWorkspaceJsonDefaults( } export async function readGeneratorOptions( - workspaceJsonPath: string, + workspacePath: string, collectionName: string, generatorName: string ): Promise { - const basedir = join(workspaceJsonPath, '..'); - const nodeModulesDir = join(basedir, 'node_modules'); + const nodeModulesDir = join(workspacePath, 'node_modules'); const collectionPackageJson = await readAndCacheJsonFile( join(collectionName, 'package.json'), nodeModulesDir @@ -84,7 +83,7 @@ export async function readGeneratorOptions( generators[generatorName].schema, dirname(collectionJson.path) ); - const workspaceDefaults = await readWorkspaceJsonDefaults(workspaceJsonPath); + const workspaceDefaults = await readWorkspaceJsonDefaults(workspacePath); const defaults = workspaceDefaults && workspaceDefaults[collectionName] && @@ -93,7 +92,7 @@ export async function readGeneratorOptions( } export async function selectGenerator( - workspaceJsonPath: string, + workspacePath: string, workspaceType: 'nx' | 'ng', generatorType?: GeneratorType ): Promise { @@ -102,7 +101,7 @@ export async function selectGenerator( generator: Generator; } - const generators = await getGenerators(workspaceJsonPath); + const generators = await getGenerators(workspacePath); let generatorsQuickPicks = generators .map((c) => c.data) .filter( @@ -129,7 +128,7 @@ export async function selectGenerator( const options = selection.generator.options || (await readGeneratorOptions( - workspaceJsonPath, + workspacePath, selection.collectionName, selection.generator.name )); diff --git a/libs/vscode/verify/src/lib/verify-builder-definition.ts b/libs/vscode/verify/src/lib/verify-builder-definition.ts index b930d96696..3187bfa1bf 100644 --- a/libs/vscode/verify/src/lib/verify-builder-definition.ts +++ b/libs/vscode/verify/src/lib/verify-builder-definition.ts @@ -1,11 +1,13 @@ import { Option, OptionType } from '@nx-console/schema'; -import { readBuilderSchema, getTelemetry } from '@nx-console/server'; -import { window } from 'vscode'; -import { dirname, join } from 'path'; -import { existsSync } from 'fs'; -import { revealNxProject } from '@nx-console/vscode/nx-workspace'; -import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; import { WorkspaceJsonConfiguration } from '@nrwl/devkit'; +import { + fileExists, + getTelemetry, + readBuilderSchema, +} from '@nx-console/server'; +import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration'; +import { join } from 'path'; +import { window } from 'vscode'; const RUN_ONE_OPTIONS = [ { @@ -71,18 +73,10 @@ export async function verifyBuilderDefinition( const executorName = commandDef.executor; if (!executorName) { - window - .showErrorMessage( - `Please update ${project}'s ${command} definition to specify a builder.`, - 'See definition' - ) - .then((value) => { - if (value) { - revealNxProject(project, { - name: command, - }); - } - }); + window.showErrorMessage( + `Please update ${project}'s ${command} definition to specify a builder.`, + 'See definition' + ); getTelemetry().exception('Builder part of architect definition not found'); return { validBuilder: false, @@ -99,18 +93,10 @@ export async function verifyBuilderDefinition( ); if (!options) { - window - .showErrorMessage( - `Builder specified for ${project} ${command} was not found in your node_modules. Check that specified builder is correct and has a corresponding entry in package.json`, - 'Show definition' - ) - .then((value) => { - if (value) { - revealNxProject(project, { - name: command, - }); - } - }); + window.showErrorMessage( + `Builder specified for ${project} ${command} was not found in your node_modules. Check that specified builder is correct and has a corresponding entry in package.json`, + 'Show definition' + ); getTelemetry().exception('Specified builder not found in node_modules'); return { @@ -121,7 +107,7 @@ export async function verifyBuilderDefinition( }; } - const isNxWorkspace = existsSync(join(workspacePath(), 'nx.json')); + const isNxWorkspace = await fileExists(join(workspacePath(), 'nx.json')); return { validBuilder: true, builderName: executorName, @@ -131,7 +117,5 @@ export async function verifyBuilderDefinition( } function workspacePath() { - return dirname( - WorkspaceConfigurationStore.instance.get('nxWorkspaceJsonPath', '') - ); + return WorkspaceConfigurationStore.instance.get('nxWorkspacePath', ''); } diff --git a/libs/vscode/verify/src/lib/verify-node-modules.ts b/libs/vscode/verify/src/lib/verify-node-modules.ts index 18da94dc08..a5f8c39134 100644 --- a/libs/vscode/verify/src/lib/verify-node-modules.ts +++ b/libs/vscode/verify/src/lib/verify-node-modules.ts @@ -1,11 +1,12 @@ -import { existsSync } from 'fs'; +import { directoryExists } from '@nx-console/server'; + import { join } from 'path'; import { window } from 'vscode'; -export function verifyNodeModules( - workspacePath: string -): { validNodeModules: boolean } { - if (!existsSync(join(workspacePath, 'node_modules'))) { +export async function verifyNodeModules(workspacePath: string): Promise<{ + validNodeModules: boolean; +}> { + if (!(await directoryExists(join(workspacePath, 'node_modules')))) { window.showErrorMessage( 'Could not execute task since node_modules directory is missing. Run npm install at: ' + workspacePath 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 c39602d36c..2584b50758 100644 --- a/libs/vscode/webview/src/lib/get-task-execution-schema.ts +++ b/libs/vscode/webview/src/lib/get-task-execution-schema.ts @@ -66,18 +66,24 @@ export async function getTaskExecutionSchema( case 'Run': { const runnableItems = (await cliTaskProvider.getProjectEntries()) .filter(([, { targets }]) => Boolean(targets)) - .flatMap(([project, { targets }]) => ({ project, targets })) - .flatMap(({ project, targets }) => [ + .flatMap(([project, { targets, root }]) => ({ + project, + targets, + root, + })) + .flatMap(({ project, targets, root }) => [ ...Object.entries(targets || {}).map(([targetName, targetDef]) => ({ project, targetName, targetDef, + root, })), ]) .map( - ({ project, targetName, targetDef }) => + ({ project, targetName, targetDef, root }) => new CliTaskQuickPickItem( project, + root, targetDef, targetName, `${project}:${targetName}` @@ -113,7 +119,7 @@ export async function getTaskExecutionSchema( } case 'Generate': { const generator = await selectGenerator( - cliTaskProvider.getWorkspaceJsonPath(), + cliTaskProvider.getWorkspacePath(), workspaceType, generatorType );