UNPKG

@yolkai/nx-workspace

Version:

Extensible Dev Tools for Monorepos

98 lines (97 loc) 4.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = require("fs"); const project_graph_builder_1 = require("./project-graph-builder"); const app_root_1 = require("../../utils/app-root"); const fileutils_1 = require("../../utils/fileutils"); const file_utils_1 = require("../file-utils"); const file_graph_1 = require("../file-graph"); const build_nodes_1 = require("./build-nodes"); const build_dependencies_1 = require("./build-dependencies"); const assert_workspace_validity_1 = require("../assert-workspace-validity"); function createProjectGraph(workspaceJson = file_utils_1.readWorkspaceJson(), nxJson = file_utils_1.readNxJson(), workspaceFiles = file_utils_1.readWorkspaceFiles(), fileRead = defaultFileRead, cache = readCache()) { assert_workspace_validity_1.assertWorkspaceValidity(workspaceJson, nxJson); if (!cache || maxMTime(workspaceFiles) > cache.mtime) { const builder = new project_graph_builder_1.ProjectGraphBuilder(cache ? cache.data.projectGraph : undefined); const buildNodesFns = [build_nodes_1.buildWorkspaceProjectNodes]; const buildDependenciesFns = [ build_dependencies_1.buildExplicitTypeScriptDependencies, build_dependencies_1.buildImplicitProjectDependencies ]; // TODO: File graph needs to be handled separately from project graph, or // we need a way to support project extensions (e.g. npm project). const fileMap = file_graph_1.createFileMap(workspaceJson, workspaceFiles); const ctx = { workspaceJson, nxJson, fileMap: modifiedSinceCache(fileMap, cache) }; buildNodesFns.forEach(f => f(ctx, builder.addNode.bind(builder), fileRead)); buildDependenciesFns.forEach(f => f(ctx, builder.nodes, builder.addDependency.bind(builder), fileRead)); const projectGraph = builder.build(); writeCache({ projectGraph, fileMap }); return projectGraph; } else { // Cache file was modified _after_ all workspace files. // Safe to return the cached graph. return cache.data.projectGraph; } } exports.createProjectGraph = createProjectGraph; function defaultFileRead(filePath) { return fs_1.readFileSync(`${app_root_1.appRootPath}/${filePath}`, 'UTF-8'); } const nxDepsPath = `${app_root_1.appRootPath}/dist/nxdeps.json`; function readCache() { if (!fileutils_1.directoryExists(`${app_root_1.appRootPath}/dist`)) { fs_1.mkdirSync(`${app_root_1.appRootPath}/dist`); } const data = getValidCache(fileutils_1.fileExists(nxDepsPath) ? fileutils_1.readJsonFile(nxDepsPath) : null); return data ? { data, mtime: file_utils_1.mtime(nxDepsPath) } : false; } function getValidCache(cache) { if (!cache) { return null; } return cache.projectGraph && cache.fileMap ? cache : null; } function writeCache(cache) { fileutils_1.writeJsonFile(nxDepsPath, cache); } function maxMTime(files) { return Math.max(...files.map(f => f.mtime)); } function modifiedSinceCache(fileMap, c) { // No cache -> compute entire graph if (!c) { return fileMap; } const currentProjects = Object.keys(fileMap).sort(); const previousProjects = Object.keys(c.data.fileMap).sort(); // Projects changed -> compute entire graph if (currentProjects.length !== previousProjects.length || currentProjects.some((val, idx) => val !== previousProjects[idx])) { return fileMap; } // Projects are same, only compute changed projects const modifiedSince = currentProjects.reduce((acc, k) => { acc[k] = []; return acc; }, {}); currentProjects.forEach(p => { for (const f of fileMap[p]) { const fromCache = c.data.fileMap[p].find(x => x.file === f.file); if (!fromCache) { modifiedSince[p].push(f); } else if (f.mtime > fromCache.mtime) { modifiedSince[p].push(f); } } }); return modifiedSince; }