Files
low-code-react-app-b/packages/spark-tools/dist/vitePhosphorIconProxyPlugin.js
2026-01-17 22:16:42 +00:00

154 lines
7.3 KiB
JavaScript

import fs from 'fs';
import path from 'path';
function createIconImportProxy() {
const packageName = '@phosphor-icons/react';
const fallbackIcon = 'Question';
const packagePath = 'node_modules/@phosphor-icons/react';
// Cache to avoid redundant filesystem checks
const existingExportsCache = new Set();
let hasLoadedExports = false;
const proxiedImports = new Map();
// Function to load all available exports from the package
const loadExports = () => {
if (hasLoadedExports)
return;
try {
const packageDir = path.resolve(packagePath);
console.log(`[icon-proxy] Checking for exports in directory: ${packageDir}`);
const filesToCheck = [
path.join(packageDir, 'dist', 'index.js'),
path.join(packageDir, 'dist', 'index.mjs'),
path.join(packageDir, 'dist', 'index.d.ts'),
path.join(packageDir, 'index.js'),
path.join(packageDir, 'index.d.ts'),
];
// Find the first file that exists
const existingFile = filesToCheck.find((file) => fs.existsSync(file));
if (existingFile) {
console.log(`[icon-proxy] Found package file: ${existingFile}`);
const content = fs.readFileSync(existingFile, 'utf-8');
// Extract export names with multiple regex patterns to catch different export styles
const exportPatterns = [
/export\s+\{\s*([^}]+)\s*\}/g, // export { Name1, Name2 }
/export\s+const\s+(\w+)/g, // export const Name
/export\s+function\s+(\w+)/g, // export function Name
/export\s+type\s+(\w+)/g, // export type Name
/export\s+\*\s+from\s+'.*\/csr\/(\w+)'/g, // export * from './csr/Name'
];
exportPatterns.forEach((pattern) => {
let match;
while ((match = pattern.exec(content)) !== null) {
if (pattern.source.includes('\\{')) {
// Multiple exports in braces
const exports$1 = match[1].split(',').map((e) => {
const parts = e.trim().split(/\s+as\s+/);
return parts[parts.length - 1].trim();
});
exports$1.forEach((name) => existingExportsCache.add(name));
}
else {
// Single export
existingExportsCache.add(match[1]);
}
}
});
console.log(`[icon-proxy] Loaded ${existingExportsCache.size} exports from ${existingFile}`);
}
else {
console.warn(`[icon-proxy] Could not find any index files for ${packageName}`);
}
hasLoadedExports = true;
}
catch (error) {
console.error(`[icon-proxy] Error analyzing package exports:`, error);
}
};
return {
name: 'vite-icon-import-proxy',
enforce: 'pre',
configResolved() {
loadExports();
},
transform(code, id) {
// Skip if not a JS/TS file or is in node_modules
if (!/\.(jsx?|tsx?)$/.test(id) || id.includes('node_modules')) {
return null;
}
// Ensure exports are loaded
if (!hasLoadedExports) {
loadExports();
}
if (!existingExportsCache.has(fallbackIcon)) {
// If we don't find the fallback icon, then there is no sense in trying to proxy icons to it.
// It's actually more likely that the icons *do* exist than not, so we should avoid proxying anything to prevent breaking the App's icons.
console.warn('[icon-proxy] Warning: Fallback icon not found. Not proxying any icons');
return null;
}
// No need to process files that don't import from our package
if (!code.includes(packageName)) {
return null;
}
// Regular expression to find imports from the package
// This matches both these patterns:
// import { IconA, IconB } from '@phosphor-icons/react';
// import { IconA as RenamedA, IconB } from '@phosphor-icons/react';
const importRegex = new RegExp(`import\\s+{([^}]+)}\\s+from\\s+['"]${packageName}['"]`, 'g');
let match;
let hasChanges = false;
let modifiedCode = code;
// Process each import statement
while ((match = importRegex.exec(code)) !== null) {
// Extract the imports section { IconA, IconB as AliasB, ... }
const importSection = match[1];
// Split into individual imports and process each
const imports = importSection
.split(',')
.map((item) => item.trim())
.filter((item) => item.length > 0);
let newImports = [...imports];
let needsQuestion = false;
// Process each imported icon
for (let i = 0; i < imports.length; i++) {
const importItem = imports[i];
// Handle aliased imports: IconName as AliasName
const parts = importItem.trim().split(/\s+as\s+/);
const iconName = parts[0].trim();
const aliasName = parts.length > 1 ? parts[1].trim() : iconName;
// Check if this icon exists in the package
if (!existingExportsCache.has(iconName)) {
console.log(`[icon-proxy] Proxying non-existent icon: ${iconName} -> ${fallbackIcon}`);
proxiedImports.set(iconName, fallbackIcon);
// Replace with Question as AliasName
newImports[i] = `${fallbackIcon} as ${aliasName}`;
needsQuestion = true;
hasChanges = true;
}
}
// Make sure Question is included if we need it
if (needsQuestion && !imports.some((imp) => imp === fallbackIcon || imp.startsWith(`${fallbackIcon} `))) {
newImports.push(fallbackIcon);
}
// Construct the new import statement
const originalImport = match[0];
const newImport = `import { ${newImports.join(', ')} } from '${packageName}'`;
// Replace in the code
modifiedCode = modifiedCode.replace(originalImport, newImport);
}
return hasChanges ? modifiedCode : null;
},
// At the end of the build, report which icons were proxied
closeBundle() {
if (proxiedImports.size > 0) {
console.log('\n[icon-proxy] Proxied imports:');
proxiedImports.forEach((fallback, original) => {
console.log(` - "${original}" -> "${fallback}"`);
});
}
},
};
}
export { createIconImportProxy as default };
//# sourceMappingURL=vitePhosphorIconProxyPlugin.js.map