@nxworker/workspace
Version:
Nx plugin providing generators for managing workspace files, including the move-file generator for safely moving files between projects while updating all imports
122 lines (121 loc) • 6.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "resolveAndValidate", {
enumerable: true,
get: function() {
return resolveAndValidate;
}
});
const _nodepath = require("node:path");
const _sanitizepath = require("../security-utils/sanitize-path");
const _isvalidpathinput = require("../security-utils/is-valid-path-input");
const _treecache = require("../tree-cache");
const _buildtargetpath = require("../path-utils/build-target-path");
const _findprojectforfile = require("../project-analysis/find-project-for-file");
const _deriveprojectdirectoryfromsource = require("../project-analysis/derive-project-directory-from-source");
const _getprojectimportpath = require("../project-analysis/get-project-import-path");
const _isfileexported = require("../export-management/is-file-exported");
const _checkforimportsinproject = require("./check-for-imports-in-project");
const _checkforrelativeimportsinproject = require("./check-for-relative-imports-in-project");
function resolveAndValidate(tree, options, projects, cachedTreeExists, getProjectSourceFiles) {
// Check if the file input contains glob characters
const isGlobPattern = /[*?[\]{}]/.test(options.file);
// Validate user input to avoid accepting regex-like patterns or dangerous characters
if (!(0, _isvalidpathinput.isValidPathInput)(options.file, {
allowUnicode: !!options.allowUnicode,
allowGlobPatterns: isGlobPattern
})) {
throw new Error(`Invalid path input for 'file': contains disallowed characters: "${options.file}"`);
}
// Validate project name
if (!(0, _isvalidpathinput.isValidPathInput)(options.project, {
allowUnicode: !!options.allowUnicode
})) {
throw new Error(`Invalid project name: contains disallowed characters: "${options.project}"`);
}
// Validate project name exists
const targetProject = projects.get(options.project);
if (!targetProject) {
throw new Error(`Target project "${options.project}" not found in workspace`);
}
// Validate that deriveProjectDirectory and projectDirectory are not both set
if (options.deriveProjectDirectory && options.projectDirectory) {
throw new Error('Cannot use both "deriveProjectDirectory" and "projectDirectory" options at the same time');
}
// Validate projectDirectory if provided
if (options.projectDirectory && !(0, _isvalidpathinput.isValidPathInput)(options.projectDirectory, {
allowUnicode: !!options.allowUnicode
})) {
throw new Error(`Invalid path input for 'projectDirectory': contains disallowed characters: "${options.projectDirectory}"`);
}
const normalizedSource = (0, _sanitizepath.sanitizePath)(options.file);
// Verify source file exists before deriving directory
if (!cachedTreeExists(tree, normalizedSource)) {
throw new Error(`Source file "${normalizedSource}" not found`);
}
// Find which project the source file belongs to (needed for deriving directory)
const sourceProjectInfo = (0, _findprojectforfile.findProjectForFile)(projects, normalizedSource);
if (!sourceProjectInfo) {
throw new Error(`Could not determine source project for file "${normalizedSource}"`);
}
const { project: sourceProject, name: sourceProjectName } = sourceProjectInfo;
// Derive or use provided projectDirectory
let sanitizedProjectDirectory;
if (options.deriveProjectDirectory) {
// Derive the directory from the source file path
const derivedDirectory = (0, _deriveprojectdirectoryfromsource.deriveProjectDirectoryFromSource)(normalizedSource, sourceProject);
sanitizedProjectDirectory = derivedDirectory ? (0, _sanitizepath.sanitizePath)(derivedDirectory) : undefined;
} else if (options.projectDirectory) {
// Sanitize projectDirectory to prevent path traversal
sanitizedProjectDirectory = (0, _sanitizepath.sanitizePath)(options.projectDirectory);
}
// Construct target path from project and optional directory
const normalizedTarget = (0, _buildtargetpath.buildTargetPath)(targetProject, normalizedSource, sanitizedProjectDirectory);
// Verify target file does not exist
if (cachedTreeExists(tree, normalizedTarget)) {
throw new Error(`Target file "${normalizedTarget}" already exists`);
}
const targetProjectName = options.project;
// Read the file content using cached read for better performance
const fileContent = _treecache.treeReadCache.read(tree, normalizedSource, 'utf-8');
if (!fileContent) {
throw new Error(`Could not read file "${normalizedSource}"`);
}
// Get the relative path within the source project to check if it's exported
const sourceRoot = sourceProject.sourceRoot || sourceProject.root;
const relativeFilePathInSource = _nodepath.posix.relative(sourceRoot, normalizedSource);
// Check if file is exported from source project entrypoint
const isExported = (0, _isfileexported.isFileExported)(tree, sourceProject, relativeFilePathInSource, cachedTreeExists);
// Get import paths for both projects
const sourceImportPath = (0, _getprojectimportpath.getProjectImportPath)(tree, sourceProjectName, sourceProject);
const targetImportPath = (0, _getprojectimportpath.getProjectImportPath)(tree, targetProjectName, targetProject);
// Check if moving within the same project
const isSameProject = sourceProjectName === targetProjectName;
// Check if target project already has imports to this file
const hasImportsInTarget = !!targetImportPath && (0, _checkforimportsinproject.checkForImportsInProject)(tree, targetProject, sourceImportPath || normalizedSource, getProjectSourceFiles);
// Check if source project has imports to this file (for cross-project moves)
// This is important when moving from application to library - the application
// files that import this file need the target library to export it
// We check for relative imports within the source project to the file being moved
const hasImportsInSource = !isSameProject && (0, _checkforrelativeimportsinproject.checkForRelativeImportsInProject)(tree, sourceProject, normalizedSource, getProjectSourceFiles);
return {
normalizedSource,
normalizedTarget,
sourceProject,
sourceProjectName,
targetProject,
targetProjectName,
fileContent,
sourceRoot,
relativeFilePathInSource,
isExported,
sourceImportPath,
targetImportPath,
hasImportsInTarget,
hasImportsInSource,
isSameProject
};
}
//# sourceMappingURL=resolve-and-validate.js.map