import { directoryExists } from '@nx-console/shared-file-system';
import { workspaceDependencyPath } from '@nx-console/shared-npm';
import { gte } from '@nx-console/nx-version';
import { PDVData } from '@nx-console/shared-types';
import type {
ProjectConfiguration,
ProjectGraphProjectNode,
} from 'nx/src/devkit-exports';
import { join, relative } from 'path';
import { getNxCloudStatus } from './get-nx-cloud-status';
import {
getNxVersion,
nxWorkspace,
} from '@nx-console/shared-nx-workspace-info';
import { getProjectByPath } from './get-project-by-path';
import { getSourceMapFilesToProjectsMap } from './get-source-map';
import { lspLogger } from '@nx-console/language-server-utils';
import { readNxJson } from '@nx-console/shared-npm';
export async function getPDVData(
workspacePath: string,
filePath: string,
): Promise<PDVData> {
const graphBasePath = await getGraphBasePath(workspacePath);
if (!graphBasePath) {
return {
resultType: 'NO_GRAPH_ERROR',
graphBasePath: undefined,
pdvDataSerialized: undefined,
pdvDataSerializedMulti: undefined,
errorsSerialized: undefined,
errorMessage: undefined,
};
}
const nxVersion = await getNxVersion(workspacePath);
if (!gte(nxVersion, '19.8.0')) {
return {
resultType: 'OLD_NX_VERSION',
graphBasePath,
pdvDataSerialized: undefined,
pdvDataSerializedMulti: undefined,
errorsSerialized: undefined,
errorMessage: undefined,
};
}
const workspace = await nxWorkspace(workspacePath, lspLogger);
const hasProjects = Object.keys(workspace.projectGraph.nodes).length > 0;
if (!hasProjects || (workspace.errors && workspace.isPartial != true)) {
let errorMessage = '';
if (!hasProjects) {
errorMessage = 'No projects found in the workspace.';
}
return {
resultType: 'ERROR',
graphBasePath,
pdvDataSerialized: undefined,
pdvDataSerializedMulti: undefined,
errorsSerialized: JSON.stringify(workspace.errors),
errorMessage,
};
}
const relativePath = relative(workspacePath, filePath);
const sourceMapsFilesToProjectsMap =
await getSourceMapFilesToProjectsMap(workspacePath);
const projectRootsForConfigFile = sourceMapsFilesToProjectsMap[relativePath];
const nxCloudStatus = await getNxCloudStatus(workspacePath);
const disabledTaskSyncGenerators =
await getDisabledTaskSyncGenerators(workspacePath);
if (!projectRootsForConfigFile || projectRootsForConfigFile.length <= 1) {
const project = await getProjectByPath(filePath, workspacePath);
if (!isCompleteProjectConfiguration(project)) {
return {
resultType: 'ERROR',
graphBasePath,
pdvDataSerialized: undefined,
pdvDataSerializedMulti: undefined,
errorsSerialized: JSON.stringify(workspace.errors),
errorMessage: `No project found at ${filePath}`,
};
}
const projectNode = workspace.projectGraph.nodes[project.name];
return {
resultType: 'SUCCESS',
graphBasePath,
pdvDataSerialized: JSON.stringify({
project: projectNode,
sourceMap: workspace.sourceMaps?.[project.root],
errors: workspace.errors,
connectedToCloud: nxCloudStatus.isConnected,
disabledTaskSyncGenerators,
}),
pdvDataSerializedMulti: undefined,
errorsSerialized: undefined,
errorMessage: undefined,
};
} else {
const projectNodes: ProjectGraphProjectNode[] = [];
for (const project of Object.values(workspace.projectGraph.nodes)) {
if (
projectRootsForConfigFile.includes(project.data.root) &&
isCompleteProjectConfiguration(project.data)
) {
projectNodes.push(project);
}
}
const pdvDataSerializedMulti: Record<string, string> = {};
for (const project of projectNodes) {
pdvDataSerializedMulti[project.name] = JSON.stringify({
project,
sourceMap: workspace.sourceMaps?.[project.data.root],
errors: workspace.errors,
connectedToCloud: nxCloudStatus.isConnected,
disabledTaskSyncGenerators,
});
}
return {
resultType: 'SUCCESS_MULTI',
graphBasePath,
pdvDataSerializedMulti,
pdvDataSerialized: undefined,
errorsSerialized: undefined,
errorMessage: undefined,
};
}
}
async function getGraphBasePath(
workspacePath: string,
): Promise<string | undefined> {
const nxWorkspaceDepPath = await workspaceDependencyPath(workspacePath, 'nx');
if (!nxWorkspaceDepPath) {
return undefined;
}
const graphBasePath = join(nxWorkspaceDepPath, 'src', 'core', 'graph');
if (await directoryExists(graphBasePath)) {
return graphBasePath;
} else {
return undefined;
}
}
function isCompleteProjectConfiguration(
project: ProjectConfiguration | undefined,
): project is ProjectConfiguration & { name: string } {
return !!project && !!project.name;
}
async function getDisabledTaskSyncGenerators(
workspacePath: string,
): Promise<string[] | undefined> {
try {
const nxJson = await readNxJson(workspacePath);
return nxJson.sync?.disabledTaskSyncGenerators;
} catch (e) {
return undefined;
}
}