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

349 lines (348 loc) 16.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { clearCache: function() { return clearCache; }, getCacheStats: function() { return getCacheStats; }, hasImportSpecifier: function() { return hasImportSpecifier; }, hasImportSpecifierMatching: function() { return hasImportSpecifierMatching; }, updateImportSpecifier: function() { return updateImportSpecifier; }, updateImportSpecifierPattern: function() { return updateImportSpecifierPattern; } }); const _devkit = require("@nx/devkit"); const _astcache = require("./ast-cache"); /** * Quick check if content might contain imports/requires before expensive parsing. * This is a fast pre-filter to avoid parsing files with no imports. */ function mightContainImports(content) { // Check for common import/require patterns return content.includes('import') || content.includes('require') || content.includes('export'); } /** * Quick check if content might contain a specific specifier before expensive parsing. * This is a fast pre-filter to avoid parsing files that definitely don't contain the specifier. */ function mightContainSpecifier(content, specifier) { // Simple string search - if the specifier doesn't appear anywhere in the file, // it definitely won't be in an import return content.includes(specifier); } function updateImportSpecifier(tree, filePath, oldSpecifier, newSpecifier) { // Get content from cache or read from tree const content = _astcache.astCache.getContent(tree, filePath); if (!content || content.trim().length === 0) { return false; } // Early exit: quick string check before expensive parsing if (!mightContainSpecifier(content, oldSpecifier)) { return false; } // Get parsed AST from cache or parse content const root = _astcache.astCache.getAST(tree, filePath); if (!root) { return false; } try { let hasChanges = false; // Optimized: Filter to only relevant node types before traversal // This reduces the number of nodes we need to check dramatically const relevantNodes = root.find(_astcache.j.Node, (node)=>{ return _astcache.j.ImportDeclaration.check(node) || _astcache.j.ExportNamedDeclaration.check(node) || _astcache.j.ExportAllDeclaration.check(node) || _astcache.j.CallExpression.check(node); }); relevantNodes.forEach((path)=>{ const node = path.node; // Handle ImportDeclaration: import ... from 'oldSpecifier' if (_astcache.j.ImportDeclaration.check(node)) { if (node.source.value === oldSpecifier) { node.source.value = newSpecifier; hasChanges = true; } } else if (_astcache.j.ExportNamedDeclaration.check(node)) { if (node.source?.value === oldSpecifier) { node.source.value = newSpecifier; hasChanges = true; } } else if (_astcache.j.ExportAllDeclaration.check(node)) { if (node.source.value === oldSpecifier) { node.source.value = newSpecifier; hasChanges = true; } } else if (_astcache.j.CallExpression.check(node)) { const { callee, arguments: args } = node; // Check if first argument matches oldSpecifier if (args.length > 0 && _astcache.j.StringLiteral.check(args[0]) && args[0].value === oldSpecifier) { // Dynamic import: import('oldSpecifier') if (_astcache.j.Import.check(callee)) { args[0].value = newSpecifier; hasChanges = true; } else if (_astcache.j.Identifier.check(callee) && callee.name === 'require') { args[0].value = newSpecifier; hasChanges = true; } else if (_astcache.j.MemberExpression.check(callee) && _astcache.j.Identifier.check(callee.object) && callee.object.name === 'require' && _astcache.j.Identifier.check(callee.property) && callee.property.name === 'resolve') { args[0].value = newSpecifier; hasChanges = true; } } } }); if (hasChanges) { const updatedContent = root.toSource({ quote: 'single' }); tree.write(filePath, updatedContent); // Invalidate cache since file was modified _astcache.astCache.invalidate(filePath); _devkit.logger.verbose(`Updated imports in ${filePath} using jscodeshift`); } return hasChanges; } catch (error) { // If parsing fails, log warning and return false _devkit.logger.warn(`Unable to parse ${filePath}. Import updates may not be applied. Error: ${error}`); return false; } } function updateImportSpecifierPattern(tree, filePath, matcher, getNewSpecifier) { // Get content from cache or read from tree const content = _astcache.astCache.getContent(tree, filePath); if (!content || content.trim().length === 0) { return false; } // Early exit: quick check if file contains any imports/requires at all if (!mightContainImports(content)) { return false; } // Get parsed AST from cache or parse content const root = _astcache.astCache.getAST(tree, filePath); if (!root) { return false; } try { let hasChanges = false; // Optimized: Filter to only relevant node types before traversal const relevantNodes = root.find(_astcache.j.Node, (node)=>{ return _astcache.j.ImportDeclaration.check(node) || _astcache.j.ExportNamedDeclaration.check(node) || _astcache.j.ExportAllDeclaration.check(node) || _astcache.j.CallExpression.check(node); }); relevantNodes.forEach((path)=>{ const node = path.node; // Handle ImportDeclaration: import ... from 'specifier' if (_astcache.j.ImportDeclaration.check(node)) { const source = node.source.value; if (typeof source === 'string' && matcher(source)) { node.source.value = getNewSpecifier(source); hasChanges = true; } } else if (_astcache.j.ExportNamedDeclaration.check(node)) { if (node.source && typeof node.source.value === 'string') { const source = node.source.value; if (matcher(source)) { node.source.value = getNewSpecifier(source); hasChanges = true; } } } else if (_astcache.j.ExportAllDeclaration.check(node)) { const source = node.source.value; if (typeof source === 'string' && matcher(source)) { node.source.value = getNewSpecifier(source); hasChanges = true; } } else if (_astcache.j.CallExpression.check(node)) { const { callee, arguments: args } = node; // Check if first argument is a string literal if (args.length > 0 && _astcache.j.StringLiteral.check(args[0]) && typeof args[0].value === 'string') { const specifier = args[0].value; // Dynamic import: import('specifier') if (_astcache.j.Import.check(callee) && matcher(specifier)) { args[0].value = getNewSpecifier(specifier); hasChanges = true; } else if (_astcache.j.Identifier.check(callee) && callee.name === 'require' && matcher(specifier)) { args[0].value = getNewSpecifier(specifier); hasChanges = true; } else if (_astcache.j.MemberExpression.check(callee) && _astcache.j.Identifier.check(callee.object) && callee.object.name === 'require' && _astcache.j.Identifier.check(callee.property) && callee.property.name === 'resolve' && matcher(specifier)) { args[0].value = getNewSpecifier(specifier); hasChanges = true; } } } }); if (hasChanges) { const updatedContent = root.toSource({ quote: 'single' }); tree.write(filePath, updatedContent); // Invalidate cache since file was modified _astcache.astCache.invalidate(filePath); _devkit.logger.verbose(`Updated imports in ${filePath} using jscodeshift pattern matcher`); } return hasChanges; } catch (error) { // If parsing fails, log warning and return false _devkit.logger.warn(`Unable to parse ${filePath}. Import updates may not be applied. Error: ${error}`); return false; } } function hasImportSpecifier(tree, filePath, specifier) { // Get content from cache or read from tree const content = _astcache.astCache.getContent(tree, filePath); if (!content || content.trim().length === 0) { return false; } // Early exit: quick string check before expensive parsing if (!mightContainSpecifier(content, specifier)) { return false; } // Get parsed AST from cache or parse content const root = _astcache.astCache.getAST(tree, filePath); if (!root) { return false; } try { // Optimized: Filter to only relevant node types and use early termination let found = false; const relevantNodes = root.find(_astcache.j.Node, (node)=>{ return _astcache.j.ImportDeclaration.check(node) || _astcache.j.ExportNamedDeclaration.check(node) || _astcache.j.ExportAllDeclaration.check(node) || _astcache.j.CallExpression.check(node); }); relevantNodes.forEach((path)=>{ if (found) return; // Early termination if already found const node = path.node; // Check ImportDeclaration if (_astcache.j.ImportDeclaration.check(node)) { if (node.source.value === specifier) { found = true; return; } } else if (_astcache.j.ExportNamedDeclaration.check(node)) { if (node.source?.value === specifier) { found = true; return; } } else if (_astcache.j.ExportAllDeclaration.check(node)) { if (node.source.value === specifier) { found = true; return; } } else if (_astcache.j.CallExpression.check(node)) { const { callee, arguments: args } = node; if (args.length > 0 && _astcache.j.StringLiteral.check(args[0]) && args[0].value === specifier) { // Dynamic import: import('specifier') if (_astcache.j.Import.check(callee)) { found = true; return; } // require('specifier') if (_astcache.j.Identifier.check(callee) && callee.name === 'require') { found = true; return; } // require.resolve('specifier') if (_astcache.j.MemberExpression.check(callee) && _astcache.j.Identifier.check(callee.object) && callee.object.name === 'require' && _astcache.j.Identifier.check(callee.property) && callee.property.name === 'resolve') { found = true; return; } } } }); return found; } catch (error) { // If parsing fails, log warning and return false _devkit.logger.warn(`Unable to parse ${filePath}. Import check may be inaccurate. Error: ${error}`); return false; } } function hasImportSpecifierMatching(tree, filePath, matcher) { // Get content from cache or read from tree const content = _astcache.astCache.getContent(tree, filePath); if (!content || content.trim().length === 0) { return false; } // Early exit: quick check if file contains any imports/requires at all if (!mightContainImports(content)) { return false; } // Get parsed AST from cache or parse content const root = _astcache.astCache.getAST(tree, filePath); if (!root) { return false; } try { let found = false; // Optimized: Filter to only relevant node types and use early termination const relevantNodes = root.find(_astcache.j.Node, (node)=>{ return _astcache.j.ImportDeclaration.check(node) || _astcache.j.ExportNamedDeclaration.check(node) || _astcache.j.ExportAllDeclaration.check(node) || _astcache.j.CallExpression.check(node); }); relevantNodes.forEach((path)=>{ if (found) { return; // Early termination if already found } const node = path.node; // Handle ImportDeclaration: import ... from 'specifier' if (_astcache.j.ImportDeclaration.check(node)) { const source = node.source.value; if (typeof source === 'string' && matcher(source)) { found = true; return; } } else if (_astcache.j.ExportNamedDeclaration.check(node)) { if (node.source && typeof node.source.value === 'string') { const source = node.source.value; if (matcher(source)) { found = true; return; } } } else if (_astcache.j.ExportAllDeclaration.check(node)) { const source = node.source.value; if (typeof source === 'string' && matcher(source)) { found = true; return; } } else if (_astcache.j.CallExpression.check(node)) { const { callee, arguments: args } = node; // Check if first argument is a string literal if (args.length > 0 && _astcache.j.StringLiteral.check(args[0]) && typeof args[0].value === 'string') { const specifier = args[0].value; // Dynamic import: import('specifier') if (_astcache.j.Import.check(callee) && matcher(specifier)) { found = true; return; } else if (_astcache.j.Identifier.check(callee) && callee.name === 'require' && matcher(specifier)) { found = true; return; } else if (_astcache.j.MemberExpression.check(callee) && _astcache.j.Identifier.check(callee.object) && callee.object.name === 'require' && _astcache.j.Identifier.check(callee.property) && callee.property.name === 'resolve' && matcher(specifier)) { found = true; return; } } } }); return found; } catch (error) { // If parsing fails, log warning and return false _devkit.logger.warn(`Unable to parse ${filePath}. Import check may be inaccurate. Error: ${error}`); return false; } } function clearCache() { _astcache.astCache.clear(); } function getCacheStats() { return _astcache.astCache.getStats(); } //# sourceMappingURL=jscodeshift-utils.js.map