77 lines
3 KiB
TypeScript
77 lines
3 KiB
TypeScript
|
|
import type { RolldownPlugin } from 'rolldown'
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Transforms `// @as-require` comments above supported import statements into `require` calls.
|
||
|
|
*
|
||
|
|
* Supported statements:
|
||
|
|
* - Static side-effect imports: `import 'module'`
|
||
|
|
* - Dynamic side-effect imports: `import('module')` and `await import('module')`
|
||
|
|
* - Dynamic imports with .then(): `import('module').then(mod => ...)`
|
||
|
|
*/
|
||
|
|
export default function asRequire() {
|
||
|
|
return {
|
||
|
|
name: 'as-require',
|
||
|
|
transform(code, id) {
|
||
|
|
if (!code.includes('// @as-require')) return null
|
||
|
|
|
||
|
|
const asRequireRegex =
|
||
|
|
/(?:\s*\/\/\s*@as-require\s*[\r\n]+)([^\r\n]*)/g
|
||
|
|
|
||
|
|
let hasChanged = false
|
||
|
|
const newCode = code.replace(asRequireRegex, (match, statement) => {
|
||
|
|
const trimmedStatement = statement.trim()
|
||
|
|
|
||
|
|
// import('./mod').then(mod => mod.do()) -> ((mod => mod.do()))(require('./mod'))
|
||
|
|
const importThenRegex =
|
||
|
|
/^import\((['"])(.+?)\1\)\s*\.then\(([\s\S]+)\);?$/
|
||
|
|
const thenMatch = trimmedStatement.match(importThenRegex)
|
||
|
|
if (thenMatch) {
|
||
|
|
hasChanged = true
|
||
|
|
const modulePath = `${thenMatch[1]}${thenMatch[2]}${thenMatch[1]}`
|
||
|
|
const callback = thenMatch[3].trim()
|
||
|
|
return `\n((${callback}))(require(${modulePath}));`
|
||
|
|
}
|
||
|
|
|
||
|
|
// import './mod' -> require('./mod')
|
||
|
|
const staticSideEffectRegex = /^import\s+(['"])(.+?)\1;?$/
|
||
|
|
const staticMatch = trimmedStatement.match(
|
||
|
|
staticSideEffectRegex,
|
||
|
|
)
|
||
|
|
if (staticMatch) {
|
||
|
|
hasChanged = true
|
||
|
|
const modulePath = `${staticMatch[1]}${staticMatch[2]}${staticMatch[1]}`
|
||
|
|
return `\nrequire(${modulePath});`
|
||
|
|
}
|
||
|
|
|
||
|
|
// import('./mod') -> require('./mod')
|
||
|
|
// await import('./mod') -> require('./mod')
|
||
|
|
const dynamicSideEffectRegex =
|
||
|
|
/^(?:await\s+)?import\((['"])(.+?)\1\);?$/
|
||
|
|
const dynamicMatch = trimmedStatement.match(
|
||
|
|
dynamicSideEffectRegex,
|
||
|
|
)
|
||
|
|
if (dynamicMatch) {
|
||
|
|
hasChanged = true
|
||
|
|
const modulePath = `${dynamicMatch[1]}${dynamicMatch[2]}${dynamicMatch[1]}`
|
||
|
|
return `\nrequire(${modulePath});`
|
||
|
|
}
|
||
|
|
|
||
|
|
this.warn(
|
||
|
|
`[${this.pluginName}] Warning: Could not transform statement in ${id}:\n${statement}\n` +
|
||
|
|
`The line after the comment must be a side-effect import or a dynamic import with .then().`,
|
||
|
|
)
|
||
|
|
|
||
|
|
return match
|
||
|
|
})
|
||
|
|
|
||
|
|
if (hasChanged)
|
||
|
|
return {
|
||
|
|
code: newCode,
|
||
|
|
map: null, // Sourcemaps are broken by this transform
|
||
|
|
}
|
||
|
|
|
||
|
|
return null
|
||
|
|
},
|
||
|
|
} satisfies RolldownPlugin
|
||
|
|
}
|