UNPKG

@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
"use strict"; 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