UNPKG

@nrwl/workspace

Version:

The Workspace plugin contains executors and generators that are useful for any Nx workspace. It should be present in every Nx workspace and other plugins build on it.

307 lines • 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isAngularSecondaryEntrypoint = exports.groupImports = exports.isTerminalRun = exports.mapProjectGraphFiles = exports.hasBuildExecutor = exports.isDirectDependency = exports.hasBannedDependencies = exports.findTransitiveExternalDependencies = exports.hasBannedImport = exports.getSourceFilePath = exports.onlyLoadChildren = exports.findConstraintsFor = exports.findProjectUsingImport = exports.isAbsoluteImportIntoAnotherProject = exports.findTargetProject = exports.findSourceProject = exports.findProjectUsingFile = exports.getTargetProjectBasedOnRelativeImport = exports.isRelative = exports.matchImportWithWildcard = exports.removeExt = exports.findDependenciesWithTags = exports.hasNoneOfTheseTags = exports.stringifyTags = void 0; const path = require("path"); const devkit_1 = require("@nrwl/devkit"); const path_1 = require("path"); const app_root_1 = require("./app-root"); const graph_utils_1 = require("./graph-utils"); const fs_1 = require("fs"); const file_utils_1 = require("nx/src/project-graph/file-utils"); function stringifyTags(tags) { return tags.map((t) => `"${t}"`).join(', '); } exports.stringifyTags = stringifyTags; function hasNoneOfTheseTags(proj, tags) { return tags.filter((tag) => hasTag(proj, tag)).length === 0; } exports.hasNoneOfTheseTags = hasNoneOfTheseTags; /** * Check if any of the given tags is included in the project * @param proj ProjectGraphProjectNode * @param tags * @returns */ function findDependenciesWithTags(targetProject, tags, graph) { // find all reachable projects that have one of the tags and // are reacheable from the targetProject (including self) const allReachableProjects = Object.keys(graph.nodes).filter((projectName) => (0, graph_utils_1.pathExists)(graph, targetProject.name, projectName) && tags.some((tag) => hasTag(graph.nodes[projectName], tag))); // return path from targetProject to reachable project return allReachableProjects.map((project) => targetProject.name === project ? [targetProject] : (0, graph_utils_1.getPath)(graph, targetProject.name, project)); } exports.findDependenciesWithTags = findDependenciesWithTags; function hasTag(proj, tag) { return tag === '*' || (proj.data.tags || []).indexOf(tag) > -1; } function removeExt(file) { return file.replace(/(?<!(^|\/))\.[^/.]+$/, ''); } exports.removeExt = removeExt; function matchImportWithWildcard( // This may or may not contain wildcards ("*") allowableImport, extractedImport) { if (allowableImport.endsWith('/**')) { const prefix = allowableImport.substring(0, allowableImport.length - 2); return extractedImport.startsWith(prefix); } else if (allowableImport.endsWith('/*')) { const prefix = allowableImport.substring(0, allowableImport.length - 1); if (!extractedImport.startsWith(prefix)) return false; return extractedImport.substring(prefix.length).indexOf('/') === -1; } else if (allowableImport.indexOf('/**/') > -1) { const [prefix, suffix] = allowableImport.split('/**/'); return (extractedImport.startsWith(prefix) && extractedImport.endsWith(suffix)); } else { return new RegExp(allowableImport).test(extractedImport); } } exports.matchImportWithWildcard = matchImportWithWildcard; function isRelative(s) { return s.startsWith('.'); } exports.isRelative = isRelative; function getTargetProjectBasedOnRelativeImport(imp, projectPath, projectGraph, sourceFilePath) { if (!isRelative(imp)) { return undefined; } const sourceDir = path.join(projectPath, path.dirname(sourceFilePath)); const targetFile = (0, devkit_1.normalizePath)(path.resolve(sourceDir, imp)).substring(projectPath.length + 1); return findTargetProject(projectGraph, targetFile); } exports.getTargetProjectBasedOnRelativeImport = getTargetProjectBasedOnRelativeImport; function findProjectUsingFile(projectGraph, file) { return projectGraph.nodes[projectGraph.allFiles[file]]; } exports.findProjectUsingFile = findProjectUsingFile; function findSourceProject(projectGraph, sourceFilePath) { const targetFile = removeExt(sourceFilePath); return findProjectUsingFile(projectGraph, targetFile); } exports.findSourceProject = findSourceProject; function findTargetProject(projectGraph, targetFile) { let targetProject = findProjectUsingFile(projectGraph, targetFile); if (!targetProject) { targetProject = findProjectUsingFile(projectGraph, (0, devkit_1.normalizePath)(path.join(targetFile, 'index'))); } if (!targetProject) { targetProject = findProjectUsingFile(projectGraph, (0, devkit_1.normalizePath)(path.join(targetFile, 'src', 'index'))); } return targetProject; } exports.findTargetProject = findTargetProject; function isAbsoluteImportIntoAnotherProject(imp, workspaceLayout = { libsDir: 'libs', appsDir: 'apps' }) { return (imp.startsWith(`${workspaceLayout.libsDir}/`) || imp.startsWith(`/${workspaceLayout.libsDir}/`) || imp.startsWith(`${workspaceLayout.appsDir}/`) || imp.startsWith(`/${workspaceLayout.appsDir}/`)); } exports.isAbsoluteImportIntoAnotherProject = isAbsoluteImportIntoAnotherProject; function findProjectUsingImport(projectGraph, targetProjectLocator, filePath, imp) { var _a; const target = targetProjectLocator.findProjectWithImport(imp, filePath); return projectGraph.nodes[target] || ((_a = projectGraph.externalNodes) === null || _a === void 0 ? void 0 : _a[target]); } exports.findProjectUsingImport = findProjectUsingImport; function findConstraintsFor(depConstraints, sourceProject) { return depConstraints.filter((f) => hasTag(sourceProject, f.sourceTag)); } exports.findConstraintsFor = findConstraintsFor; function onlyLoadChildren(graph, sourceProjectName, targetProjectName, visited) { if (visited.indexOf(sourceProjectName) > -1) return false; return ((graph.dependencies[sourceProjectName] || []).filter((d) => { if (d.type !== devkit_1.DependencyType.dynamic) return false; if (d.target === targetProjectName) return true; return onlyLoadChildren(graph, d.target, targetProjectName, [ ...visited, sourceProjectName, ]); }).length > 0); } exports.onlyLoadChildren = onlyLoadChildren; function getSourceFilePath(sourceFileName, projectPath) { const relativePath = sourceFileName.slice(projectPath.length + 1); return (0, devkit_1.normalizePath)(relativePath); } exports.getSourceFilePath = getSourceFilePath; /** * Find constraint (if any) that explicitly banns the given target npm project * @param externalProject * @param depConstraints * @returns */ function isConstraintBanningProject(externalProject, constraint) { return constraint.bannedExternalImports.some((importDefinition) => parseImportWildcards(importDefinition).test(externalProject.data.packageName)); } function hasBannedImport(source, target, depConstraints) { // return those constraints that match source project and have `bannedExternalImports` defined depConstraints = depConstraints.filter((c) => (source.data.tags || []).includes(c.sourceTag) && c.bannedExternalImports && c.bannedExternalImports.length); return depConstraints.find((constraint) => isConstraintBanningProject(target, constraint)); } exports.hasBannedImport = hasBannedImport; /** * Find all unique (transitive) external dependencies of given project * @param graph * @param source * @returns */ function findTransitiveExternalDependencies(graph, source) { if (!graph.externalNodes) { return []; } const allReachableProjects = []; const allProjects = Object.keys(graph.nodes); for (let i = 0; i < allProjects.length; i++) { if ((0, graph_utils_1.pathExists)(graph, source.name, allProjects[i])) { allReachableProjects.push(allProjects[i]); } } const externalDependencies = []; for (let i = 0; i < allReachableProjects.length; i++) { const dependencies = graph.dependencies[allReachableProjects[i]]; if (dependencies) { for (let d = 0; d < dependencies.length; d++) { const dependency = dependencies[d]; if (graph.externalNodes[dependency.target]) { externalDependencies.push(dependency); } } } } return externalDependencies; } exports.findTransitiveExternalDependencies = findTransitiveExternalDependencies; /** * Check if * @param externalDependencies * @param graph * @param depConstraint * @returns */ function hasBannedDependencies(externalDependencies, graph, depConstraint) { return externalDependencies .filter((dependency) => isConstraintBanningProject(graph.externalNodes[dependency.target], depConstraint)) .map((dep) => [ graph.externalNodes[dep.target], graph.nodes[dep.source], depConstraint, ]); } exports.hasBannedDependencies = hasBannedDependencies; function isDirectDependency(target) { const fileName = 'package.json'; const content = (0, file_utils_1.readFileIfExisting)((0, path_1.join)(app_root_1.workspaceRoot, fileName)); if (content) { const { dependencies, devDependencies, peerDependencies } = (0, devkit_1.parseJson)(content); if (dependencies && dependencies[target.data.packageName]) { return true; } if (peerDependencies && peerDependencies[target.data.packageName]) { return true; } if (devDependencies && devDependencies[target.data.packageName]) { return true; } return false; } return true; } exports.isDirectDependency = isDirectDependency; /** * Maps import with wildcards to regex pattern * @param importDefinition * @returns */ function parseImportWildcards(importDefinition) { const mappedWildcards = importDefinition.split('*').join('.*'); return new RegExp(`^${new RegExp(mappedWildcards).source}$`); } /** * Verifies whether the given node has an architect builder attached * @param projectGraph the node to verify */ function hasBuildExecutor(projectGraph) { return ( // can the architect not be defined? real use case? projectGraph.data.targets && projectGraph.data.targets.build && projectGraph.data.targets.build.executor !== ''); } exports.hasBuildExecutor = hasBuildExecutor; function mapProjectGraphFiles(projectGraph) { if (!projectGraph) { return null; } const allFiles = {}; Object.entries(projectGraph.nodes).forEach(([name, node]) => { node.data.files.forEach(({ file }) => { const fileName = removeExt(file); allFiles[fileName] = name; }); }); return Object.assign(Object.assign({}, projectGraph), { allFiles }); } exports.mapProjectGraphFiles = mapProjectGraphFiles; const ESLINT_REGEX = /node_modules.*[\/\\]eslint$/; const NRWL_CLI_REGEX = /nx[\/\\]bin[\/\\]run-executor\.js$/; function isTerminalRun() { return (process.argv.length > 1 && (!!process.argv[1].match(NRWL_CLI_REGEX) || !!process.argv[1].match(ESLINT_REGEX))); } exports.isTerminalRun = isTerminalRun; /** * Takes an array of imports and tries to group them, so rather than having * `import { A } from './some-location'` and `import { B } from './some-location'` you get * `import { A, B } from './some-location'` * @param importsToRemap * @returns */ function groupImports(importsToRemap) { const importsToRemapGrouped = importsToRemap.reduce((acc, curr) => { const existing = acc.find((i) => i.importPath === curr.importPath && i.member !== curr.member); if (existing) { if (existing.member) { existing.member += `, ${curr.member}`; } } else { acc.push({ importPath: curr.importPath, member: curr.member, }); } return acc; }, []); return importsToRemapGrouped .map((entry) => `import { ${entry.member} } from '${entry.importPath}';`) .join('\n'); } exports.groupImports = groupImports; /** * Checks if import points to a secondary entry point in Angular project * @param targetProjectLocator * @param importExpr * @returns */ function isAngularSecondaryEntrypoint(targetProjectLocator, importExpr) { const targetFiles = targetProjectLocator.findPaths(importExpr); return (targetFiles && targetFiles.some((file) => // The `ng-packagr` defaults to the `src/public_api.ts` entry file to // the public API if the `lib.entryFile` is not specified explicitly. (file.endsWith('src/public_api.ts') || file.endsWith('src/index.ts')) && (0, fs_1.existsSync)((0, devkit_1.joinPathFragments)(file, '../../', 'ng-package.json')))); } exports.isAngularSecondaryEntrypoint = isAngularSecondaryEntrypoint; //# sourceMappingURL=runtime-lint-utils.js.map