Skip to content

Commit

Permalink
feat: support package.json projects (#1287)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cammisuli authored Jun 3, 2022
1 parent 027e281 commit 6838052
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 56 deletions.
23 changes: 16 additions & 7 deletions apps/vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
teardownTelemetry,
watchFile,
fileExists,
checkIsNxWorkspace,
} from '@nx-console/server';
import {
GlobalConfigurationStore,
Expand Down Expand Up @@ -115,7 +116,8 @@ export async function activate(c: ExtensionContext) {
manuallySelectWorkspaceDefinitionCommand
);

// registers itself as a CodeLensProvider and watches config to dispose/re-register
// registers itself as a CodeLensProvider and watches config to dispose/re-register

const { WorkspaceCodeLensProvider } = await import(
'@nx-console/vscode/nx-workspace'
);
Expand Down Expand Up @@ -193,6 +195,9 @@ async function scanForWorkspace(vscodeWorkspacePath: string) {
if (await fileExists(join(currentDirectory, 'nx.json'))) {
return setWorkspace(currentDirectory);
}
if (await fileExists(join(currentDirectory, 'lerna.json'))) {
return setWorkspace(currentDirectory);
}
currentDirectory = dirname(currentDirectory);
}
}
Expand All @@ -203,12 +208,16 @@ async function setWorkspace(workspacePath: string) {
}

WorkspaceConfigurationStore.instance.set('nxWorkspacePath', workspacePath);
const { verifyWorkspace } = await import('@nx-console/vscode/nx-workspace');

const { validWorkspaceJson } = await verifyWorkspace();
if (!validWorkspaceJson) {
return;
}
// Set the NX_WORKSPACE_ROOT_PATH as soon as possible so that the nx utils can get this.
process.env.NX_WORKSPACE_ROOT_PATH = workspacePath;

// const { verifyWorkspace } = await import('@nx-console/vscode/nx-workspace');

// const { validWorkspaceJson } = await verifyWorkspace();
// if (!validWorkspaceJson) {
// return;
// // }

if (!cliTaskProvider) {
cliTaskProvider = new CliTaskProvider();
Expand Down Expand Up @@ -237,7 +246,7 @@ async function setWorkspace(workspacePath: string) {

setApplicationAndLibraryContext(workspacePath);

const isNxWorkspace = existsSync(join(workspacePath, 'nx.json'));
const isNxWorkspace = await checkIsNxWorkspace(workspacePath);
const isAngularWorkspace = existsSync(join(workspacePath, 'angular.json'));

commands.executeCommand(
Expand Down
1 change: 1 addition & 0 deletions libs/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export { watchFile } from './lib/utils/watch-file';
export { buildProjectPath } from './lib/utils/build-project-path';
export { findConfig } from './lib/utils/find-config';
export { getShellExecutionForConfig } from './lib/utils/shell-execution';
export { checkIsNxWorkspace } from './lib/check-is-nx-workspace';
15 changes: 15 additions & 0 deletions libs/server/src/lib/check-is-nx-workspace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { join } from 'path';
import { fileExists, readAndCacheJsonFile } from './utils/utils';

export async function checkIsNxWorkspace(
workspacePath: string
): Promise<boolean> {
let isNxWorkspace = await fileExists(join(workspacePath, 'nx.json'));

if (!isNxWorkspace) {
const lerna = await readAndCacheJsonFile('lerna.json', workspacePath);
isNxWorkspace = lerna.json.useNx ?? false;
}

return isNxWorkspace;
}
15 changes: 12 additions & 3 deletions libs/server/src/lib/utils/build-project-path.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { join } from 'path';
import { fileExists } from './utils';

/**
* Builds the project path from the given project name.
* @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(
export async function buildProjectPath(
workspacePath: string,
projectPath: string
): string {
return join(workspacePath, projectPath, 'project.json');
): Promise<string | undefined> {
const basePath = join(workspacePath, projectPath);

const projectJsonPath = join(basePath, 'project.json');
const packageJsonPath = join(basePath, 'package.json');
if (await fileExists(projectJsonPath)) {
return projectJsonPath;
} else if (await fileExists(packageJsonPath)) {
return packageJsonPath;
}
}
76 changes: 68 additions & 8 deletions libs/vscode/nx-workspace/src/lib/get-nx-workspace-config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import type {
import {
NxJsonConfiguration,
WorkspaceJsonConfiguration,
ProjectGraph,
} from '@nrwl/devkit';
import { readAndCacheJsonFile } from '@nx-console/server';
import { join } from 'path';
import { getNxWorkspacePackageFileUtils } from './get-nx-workspace-package';
import {
getNxProjectGraph,
getNxWorkspacePackageFileUtils,
} from './get-nx-workspace-package';
import { nxVersion } from './nx-version';

export type NxWorkspaceConfiguration = WorkspaceJsonConfiguration &
NxJsonConfiguration;

/**
* There's a couple things that we need to handle here.
*
Expand All @@ -19,23 +27,60 @@ export async function getNxWorkspaceConfig(
basedir: string,
format: 'nx' | 'angularCli'
): Promise<{
workspaceConfiguration: WorkspaceJsonConfiguration & NxJsonConfiguration;
workspaceConfiguration: NxWorkspaceConfiguration;
configPath: string;
}> {
const version = nxVersion();

if (version && version < 12) {
if (version < 12) {
return readWorkspaceConfigs(format, basedir);
}

try {
const nxWorkspacePackage = await getNxWorkspacePackageFileUtils();
const [nxWorkspacePackage, nxProjectGraph] = await Promise.all([
getNxWorkspacePackageFileUtils(),
getNxProjectGraph(),
]);
const configFile = nxWorkspacePackage.workspaceFileName();
return {
workspaceConfiguration: nxWorkspacePackage.readWorkspaceConfig({

let projectGraph: ProjectGraph | null = null;
try {
if (format === 'angularCli') {
throw 'No project graph support';
}

if (version < 13) {
projectGraph = (nxProjectGraph as any).readCurrentProjectGraph();
} else {
projectGraph = nxProjectGraph.readCachedProjectGraph();
}

if (!projectGraph) {
if (version < 13) {
projectGraph = (nxProjectGraph as any).createProjectGraph();
} else {
projectGraph = await nxProjectGraph.createProjectGraphAsync();
}
}
} catch {
//noop
}

let workspaceConfiguration: NxWorkspaceConfiguration;
try {
workspaceConfiguration = nxWorkspacePackage.readWorkspaceConfig({
format,
path: basedir,
}),
});
} catch {
workspaceConfiguration = (await readWorkspaceConfigs(format, basedir))
.workspaceConfiguration;
}

addProjectTargets(workspaceConfiguration, projectGraph);

return {
workspaceConfiguration,
configPath: join(basedir, configFile),
};
} catch (e) {
Expand Down Expand Up @@ -74,3 +119,18 @@ async function readWorkspaceConfigs(
: join(basedir, 'angular.json'),
};
}

function addProjectTargets(
workspaceConfiguration: NxWorkspaceConfiguration,
projectGraph: ProjectGraph | null
) {
if (!projectGraph) {
return;
}

for (const [projectName, configuration] of Object.entries(
workspaceConfiguration.projects
)) {
configuration.targets = projectGraph.nodes[projectName].data.targets;
}
}
84 changes: 61 additions & 23 deletions libs/vscode/nx-workspace/src/lib/get-nx-workspace-package.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,75 @@
import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration';
import { join } from 'path';
import * as NxFileUtils from '@nrwl/workspace/src/core/file-utils';
import { workspaceDependencyPath } from '@nx-console/npm';
import { fileExists, getOutputChannel } from '@nx-console/server';
import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration';
import * as NxFileUtils from 'nx/src/project-graph/file-utils';
import * as NxProjectGraph from 'nx/src/project-graph/project-graph';
import { platform } from 'os';
import { workspaceDependencyPath } from '@nx-console/npm';
import { join } from 'path';

declare function __non_webpack_require__(importPath: string): any;

let RESOLVED_IMPORT: typeof NxFileUtils;
let RESOLVED_FILEUTILS_IMPORT: typeof NxFileUtils;
let RESOLVED_PROJECTGRAPH_IMPORT: typeof NxProjectGraph;

export async function getNxProjectGraph(): Promise<typeof NxProjectGraph> {
if (RESOLVED_PROJECTGRAPH_IMPORT) {
return RESOLVED_PROJECTGRAPH_IMPORT;
}

const workspacePath = WorkspaceConfigurationStore.instance.get(
'nxWorkspacePath',
''
);
let importPath = await findNxPackagePath(
workspacePath,
join('src', 'project-graph', 'project-graph.js')
);

if (!importPath) {
importPath = await findNxPackagePath(
workspacePath,
join('src', 'core', 'project-graph', 'project-graph.js')
);
}

return getNxPackage(importPath, NxProjectGraph, RESOLVED_PROJECTGRAPH_IMPORT);
}

/**
* Get the local installed version of @nrwl/workspace
*/
export async function getNxWorkspacePackageFileUtils(): Promise<
typeof NxFileUtils
> {
if (RESOLVED_IMPORT) {
return RESOLVED_IMPORT;
if (RESOLVED_FILEUTILS_IMPORT) {
return RESOLVED_FILEUTILS_IMPORT;
}

const workspacePath = WorkspaceConfigurationStore.instance.get(
'nxWorkspacePath',
''
);

let importPath = await findNxPackage(workspacePath);
let importPath = await findNxPackagePath(
workspacePath,
join('src', 'project-graph', 'file-utils.js')
);

if (!importPath) {
importPath = await findNxPackagePath(
workspacePath,
join('src', 'core', 'file-utils.js')
);
}

return getNxPackage(importPath, NxFileUtils, RESOLVED_FILEUTILS_IMPORT);
}

async function getNxPackage<T>(
importPath: string | undefined,
backupPackage: T,
cache: T
): Promise<T> {
try {
if (!importPath) {
throw 'local Nx dependency not found';
Expand All @@ -37,39 +81,33 @@ export async function getNxWorkspacePackageFileUtils(): Promise<

const imported = __non_webpack_require__(importPath);

if (!('readWorkspaceConfig' in imported)) {
throw new Error(
'Workspace tools does not have `readWorkspaceConfig` function'
);
}

getOutputChannel().appendLine(`Using local Nx package at ${importPath}`);

RESOLVED_IMPORT = imported;
cache = imported;
return imported;
} catch (error) {
getOutputChannel().appendLine(
`Error loading Nx from the workspace. Falling back to extension dependency
`Unable to load the ${importPath} dependency from the workspace. Falling back to extension dependency
${error}
`
);
RESOLVED_IMPORT = NxFileUtils;
return NxFileUtils;
cache = backupPackage;
return backupPackage;
}
}

/**
* Finds the local Nx package in the workspace.
*
* It will try to look for the `nx` package, with the specific file `src/core/file-utils.js`. If it does not exist, it will try to look for the `@nrwl/workspace` package, with the specific file `src/core/file-utils.js`
* It will try to look for the `nx` package, with the specific file. If it does not exist, it will try to look for the `@nrwl/workspace` package, with the specific file
* @param workspacePath
* @returns
*/
async function findNxPackage(
workspacePath: string
async function findNxPackagePath(
workspacePath: string,
filePath: string
): Promise<string | undefined> {
const buildPath = (base: string) =>
join(base, 'src', 'core', 'file-utils.js');
const buildPath = (base: string) => join(base, filePath);

const nxWorkspaceDepPath = await workspaceDependencyPath(workspacePath, 'nx');
if (nxWorkspaceDepPath) {
Expand Down
17 changes: 12 additions & 5 deletions libs/vscode/nx-workspace/src/lib/nx-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration';
declare function __non_webpack_require__(importPath: string): any;

let nxWorkspacePackageJson: { version: string };
let loadedNxWorkspacePackage = false;
export function nxVersion(): number | null {
if (!loadedNxWorkspacePackage) {
let loadedNxPackage = false;
export function nxVersion(): number {
if (!loadedNxPackage) {
const workspacePath = WorkspaceConfigurationStore.instance.get(
'nxWorkspacePath',
''
Expand All @@ -14,9 +14,16 @@ export function nxVersion(): number | null {
nxWorkspacePackageJson = __non_webpack_require__(
`${workspacePath}/node_modules/@nrwl/workspace/package.json`
);
loadedNxWorkspacePackage = true;
loadedNxPackage = true;
} catch (e) {
return null;
try {
nxWorkspacePackageJson = __non_webpack_require__(
`${workspacePath}/node_modules/nx/package.json`
);
loadedNxPackage = true;
} catch {
return 0;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions libs/vscode/nx-workspace/src/lib/reveal-workspace-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ export async function revealNxProject(
'nxWorkspacePath',
''
);
const projectPath = buildProjectPath(workspacePath, root);
const projectPath = await buildProjectPath(workspacePath, root);
const workspaceJsonPath = join(workspacePath, 'workspace.json');
const angularJsonPath = join(workspacePath, 'angular.json');

let path = workspacePath;
if (await fileExists(projectPath)) {
if (projectPath) {
path = projectPath;
} else if (await fileExists(workspaceJsonPath)) {
path = workspaceJsonPath;
Expand Down
Loading

0 comments on commit 6838052

Please sign in to comment.