UNPKG

fix-dts-default-cjs-exports

Version:

Utility to fix TypeScript declarations when using default exports in CommonJS.

202 lines (198 loc) 6.3 kB
'use strict'; var MagicString = require('magic-string'); var mlly = require('mlly'); function internalFixDefaultCJSExports(code, info, options) { const parsedExports = extractExports(code, info, options); if (!parsedExports) { return; } if (parsedExports.defaultExport.specifier) { const imports = []; for (const imp of mlly.findStaticImports(code)) { if (!imp.imports) { continue; } imports.push(mlly.parseStaticImport(imp)); } const specifier = parsedExports.defaultExport.specifier; const defaultImport = imports.find((i) => i.specifier === specifier); return parsedExports.defaultExport._type === "named" ? handleDefaultNamedCJSExport( code, info, parsedExports, imports, options, defaultImport ) : handleDefaultCJSExportAsDefault( code, parsedExports, imports, defaultImport ) || handleNoSpecifierDefaultCJSExport(code, info, parsedExports); } return handleNoSpecifierDefaultCJSExport(code, info, parsedExports); } function extractExports(code, info, options) { const defaultExport = mlly.findExports(code).find( (e) => e.names.includes("default") ); if (!defaultExport) { options.warn?.( /* c8 ignore next */ `No default export found in ${info.fileName}, it contains default export but cannot be parsed.` ); return; } const match = defaultExport.code.match(/export\s*\{([^}]*)\}/); if (!match?.length) { options.warn?.( `No default export found in ${info.fileName}, it contains default export but cannot be parsed.` ); return; } let defaultAlias; const exportsEntries = []; for (const exp of match[1].split(",").map((e) => e.trim())) { if (exp === "default") { defaultAlias = exp; continue; } const m = exp.match(/\s*as\s+default\s*/); if (m) { defaultAlias = exp.replace(m[0], ""); } else { exportsEntries.push(exp); } } if (!defaultAlias) { options.warn?.( `No default export found in ${info.fileName}, it contains default export but cannot be parsed.` ); return; } return { defaultExport, defaultAlias, exports: exportsEntries }; } function handleDefaultCJSExportAsDefault(code, { defaultExport, exports }, imports, defaultImport) { if (defaultImport) { return exports.length === 0 ? code.replace( defaultExport.code, `export = ${defaultImport.defaultImport}` ) : code.replace( defaultExport.code, `// @ts-ignore export = ${defaultImport.defaultImport}; export { ${exports.join(", ")} } from '${defaultExport.specifier}'` ); } else { const magicString = new MagicString(code); const lastImportPosition = imports.length > 0 ? imports.at(-1)?.end || 0 : 0; if (lastImportPosition > 0) { magicString.appendRight( lastImportPosition, ` import _default from '${defaultExport.specifier}'; ` ); } else { magicString.prepend( `import _default from '${defaultExport.specifier}'; ` ); } return exports.length > 0 ? magicString.replace( defaultExport.code, `// @ts-ignore export = _default; export { ${exports.join(", ")} } from '${defaultExport.specifier}'` ).toString() : magicString.replace(defaultExport.code, "export = _default").toString(); } } function handleDefaultNamedCJSExport(code, info, parsedExports, imports, options, defaultImport) { const { defaultAlias, defaultExport, exports } = parsedExports; if (defaultAlias === "default") { if (defaultImport && !defaultImport.defaultImport) { options.warn?.( `Cannot parse default export name from ${defaultImport.specifier} import at ${info.fileName}!.` ); return; } return handleDefaultCJSExportAsDefault( code, parsedExports, imports, defaultImport ); } if (defaultImport) { const namedExports = defaultImport.namedImports; if (namedExports?.[defaultAlias] === defaultAlias) { return exports.length === 0 ? code.replace(defaultExport.code, `export = ${defaultAlias}`) : code.replace( defaultExport.code, `// @ts-ignore export = ${defaultAlias}; export { ${exports.join(", ")} }` ); } else { options.warn?.( `Cannot parse "${defaultAlias}" named export from ${defaultImport.specifier} import at ${info.fileName}!.` ); return void 0; } } const magicString = new MagicString(code); const lastImportPosition = imports.length > 0 ? imports.at(-1)?.end || 0 : 0; if (lastImportPosition > 0) { magicString.appendRight( lastImportPosition, ` import { ${defaultAlias} } from '${defaultExport.specifier}'; ` ); } else { magicString.prepend( `import { ${defaultAlias} } from '${defaultExport.specifier}'; ` ); } return exports.length > 0 ? magicString.replace( defaultExport.code, `// @ts-ignore export = ${defaultAlias}; export { ${exports.join(", ")} } from '${defaultExport.specifier}'` ).toString() : magicString.replace(defaultExport.code, `export = ${defaultAlias}`).toString(); } function handleNoSpecifierDefaultCJSExport(code, info, { defaultAlias, defaultExport, exports }) { let exportStatement = exports.length > 0 ? void 0 : ""; if (exportStatement === void 0) { let someExternalExport = false; const typeExportRegexp = /\s*type\s+/; const allRemainingExports = exports.map((exp) => { if (someExternalExport) { return [exp, ""]; } if (!info.imports.includes(exp)) { const m = exp.match(typeExportRegexp); if (m) { const name = exp.replace(m[0], "").trim(); if (!info.imports.includes(name)) { return [exp, name]; } } } someExternalExport = true; return [exp, ""]; }); exportStatement = someExternalExport ? `; export { ${allRemainingExports.map(([e, _]) => e).join(", ")} }` : `; export type { ${allRemainingExports.map(([_, t]) => t).join(", ")} }`; } return code.replace( defaultExport.code, `${exportStatement.length > 0 ? "// @ts-ignore\n" : ""}export = ${defaultAlias}${exportStatement}` ); } exports.internalFixDefaultCJSExports = internalFixDefaultCJSExports;