@nrwl/workspace
Version:
307 lines • 13.1 kB
JavaScript
;
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