@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
JavaScript
"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