UNPKG

knip

Version:

Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects

100 lines (99 loc) 4.74 kB
import ts from 'typescript'; import { findDescendants, getDefaultImportName, getImportMap, stripQuotes } from "../../typescript/ast-helpers.js"; import { isFile, loadFile } from "../../util/fs.js"; import { toProductionEntry } from "../../util/input.js"; import { join } from "../../util/path.js"; export const getReactBabelPlugins = (sourceFile) => { const babelPlugins = []; const importMap = getImportMap(sourceFile); const reactPluginNames = new Set(); for (const [importName, importPath] of importMap) { if (importPath.includes('@vitejs/plugin-react')) { reactPluginNames.add(importName); } } if (reactPluginNames.size === 0) { const defaultImportName = getDefaultImportName(importMap, '@vitejs/plugin-react'); if (defaultImportName) { reactPluginNames.add(defaultImportName); } else { reactPluginNames.add('react'); } } const callExpressions = findDescendants(sourceFile, node => ts.isCallExpression(node)); const defineConfigCall = callExpressions.find(node => ts.isIdentifier(node.expression) && node.expression.text === 'defineConfig'); if (!defineConfigCall || defineConfigCall.arguments.length === 0) { return babelPlugins; } const configObject = defineConfigCall.arguments[0]; if (!ts.isObjectLiteralExpression(configObject)) { return babelPlugins; } const pluginsProperty = configObject.properties.find(prop => ts.isPropertyAssignment(prop) && prop.name.getText() === 'plugins'); if (!pluginsProperty || !ts.isPropertyAssignment(pluginsProperty) || !ts.isArrayLiteralExpression(pluginsProperty.initializer)) { return babelPlugins; } const pluginsArray = pluginsProperty.initializer; for (const pluginElement of pluginsArray.elements) { let isReactPlugin = false; if (ts.isCallExpression(pluginElement)) { if (ts.isIdentifier(pluginElement.expression)) { isReactPlugin = reactPluginNames.has(pluginElement.expression.text); } if (isReactPlugin) { if (pluginElement.arguments.length === 0 || !ts.isObjectLiteralExpression(pluginElement.arguments[0])) { continue; } const reactConfig = pluginElement.arguments[0]; const babelProperty = reactConfig.properties.find(prop => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'babel'); if (!babelProperty || !ts.isPropertyAssignment(babelProperty) || !ts.isObjectLiteralExpression(babelProperty.initializer)) { continue; } const babelObject = babelProperty.initializer; const babelPluginsProperty = babelObject.properties.find(prop => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'plugins'); if (!babelPluginsProperty || !ts.isPropertyAssignment(babelPluginsProperty) || !ts.isArrayLiteralExpression(babelPluginsProperty.initializer)) { continue; } const pluginsArray = babelPluginsProperty.initializer; for (const element of pluginsArray.elements) { if (ts.isStringLiteral(element)) { babelPlugins.push(stripQuotes(element.text)); } else if (ts.isArrayLiteralExpression(element) && element.elements.length > 0 && ts.isStringLiteral(element.elements[0])) { babelPlugins.push(stripQuotes(element.elements[0].text)); } } } } } return babelPlugins; }; const moduleScriptPattern = /<script\b(?=[^>]*\btype\s*=\s*["']?module["']?)(?=[^>]*\bsrc\s*=\s*["']?([^"' >]+)["']?)[^>]*>/gi; const normalizeModuleScriptSrc = (value) => value.trim().replace(/^\//, ''); const getModuleScriptSources = (html) => { const matches = html.matchAll(moduleScriptPattern); const sources = []; for (const match of matches) { const src = normalizeModuleScriptSrc(match[1]); if (src) sources.push(src); } return sources; }; export const getIndexHtmlEntries = async (rootDir) => { const indexPath = join(rootDir, 'index.html'); if (!isFile(indexPath)) return []; const html = await loadFile(indexPath); const entries = getModuleScriptSources(html).map(src => join(rootDir, src)); return entries.map(entry => toProductionEntry(entry)); };