Skip to content

Commit

Permalink
feat: custom import rewriter
Browse files Browse the repository at this point in the history
closes #25
  • Loading branch information
sxzz committed Nov 22, 2024
1 parent c09718d commit 6406eee
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/core/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function rewriteImports(
)
}

if (final) {
if (final && final !== source.value) {
final = final.replaceAll('\\', '/')
if (!/^\.\.?\//.test(final)) {
final = `./${final}`
Expand Down
7 changes: 6 additions & 1 deletion src/core/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export type Options = {
autoAddExts?: boolean
/** Patch `export default` in `.d.cts` to `export = ` */
patchCjsDefaultExport?: boolean
rewriteImports?: (
id: string,
importer: string,
) => string | void | null | undefined
} & (
| {
/**
Expand All @@ -38,7 +42,7 @@ type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U

export type OptionsResolved = Overwrite<
Required<Options>,
Pick<Options, 'enforce' | 'extraOutdir'>
Pick<Options, 'enforce' | 'extraOutdir' | 'rewriteImports'>
>

export function resolveOptions(options: Options): OptionsResolved {
Expand All @@ -51,5 +55,6 @@ export function resolveOptions(options: Options): OptionsResolved {
extraOutdir: options.extraOutdir,
autoAddExts: options.autoAddExts || false,
patchCjsDefaultExport: options.patchCjsDefaultExport || false,
rewriteImports: options.rewriteImports,
}
}
39 changes: 29 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,34 @@ export const IsolatedDecl: UnpluginInstance<Options | undefined, false> =
const imports = filterImports(program)

const s = new MagicString(dts)
if (options.autoAddExts) {
if (options.autoAddExts || options.rewriteImports) {
for (const i of imports) {
const { source } = i
if (path.basename(source.value).includes('.')) continue

const resolved = await resolve(context, source.value, id)
if (!resolved || resolved.external) continue
if (resolved.id.endsWith('.ts') || resolved.id.endsWith('.tsx')) {
i.suffix = '.js'
source.value = (source.originalValue = source.value) + i.suffix
s.overwrite(source.start + 1, source.end - 1, source.value)
let { value } = source

if (options.rewriteImports) {
const result = options.rewriteImports(value, id)
if (typeof result === 'string') {
value = result
}
}

if (
options.autoAddExts &&
(path.isAbsolute(value) || value[0] === '.') &&
!path.basename(value).includes('.')
) {
const resolved = await resolve(context, value, id)
if (!resolved || resolved.external) continue
if (resolved.id.endsWith('.ts') || resolved.id.endsWith('.tsx')) {
value = value + (i.suffix = '.js')
}
}

if (source.value !== value) {
source.originalValue = source.value
source.value = value
s.overwrite(source.start + 1, source.end - 1, value)
}
}
}
Expand Down Expand Up @@ -339,16 +356,18 @@ export const IsolatedDecl: UnpluginInstance<Options | undefined, false> =

const textEncoder = new TextEncoder()
for (const [filename, { s }] of Object.entries(outputFiles)) {
let source = s.toString()
const outDir = build.initialOptions.outdir
let outFile = `${path.relative(inputBase, filename)}.d.${outExt}`
if (options.extraOutdir) {
outFile = path.join(options.extraOutdir, outFile)
}
const filePath = outDir ? path.resolve(outDir, outFile) : outFile

let source = s.toString()
if (options.patchCjsDefaultExport && filePath.endsWith('.d.cts')) {
source = patchCjsDefaultExport(source)
}

if (write) {
await mkdir(path.dirname(filePath), { recursive: true })
await writeFile(filePath, source)
Expand Down
12 changes: 12 additions & 0 deletions tests/__snapshots__/rollup.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`rollup > custom rewriter 1`] = `
"// index.d.ts
export type * from './test.ts';
// index.js
// test.d.ts
export type Str = string;
"
`;

exports[`rollup > generate basic 1`] = `
"// main.js
function Component() {
Expand Down
2 changes: 2 additions & 0 deletions tests/fixtures/import-rewriter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @ts-ignore
export type * from '~/test.ts'
1 change: 1 addition & 0 deletions tests/fixtures/import-rewriter/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Str = string
45 changes: 39 additions & 6 deletions tests/rollup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ describe('rollup', () => {
const TEST_SANDBOX_FOLDER = path.resolve(__dirname, 'temp/rollup')

test('generate basic', async () => {
const input = path.resolve(__dirname, 'fixtures/basic/main.ts')
const dist = path.resolve(__dirname, `${TEST_SANDBOX_FOLDER}/basic`)
const dir = 'basic'
const input = path.resolve(fixtures, dir, 'main.ts')

const bundle = await rollup({
input,
Expand All @@ -25,10 +25,7 @@ describe('rollup', () => {
],
logLevel: 'silent',
})

const result = await bundle.generate({
dir: dist,
})
const result = await bundle.generate({})

expect(outputToSnapshot(result.output)).toMatchSnapshot()
})
Expand Down Expand Up @@ -80,6 +77,42 @@ describe('rollup', () => {

expect(await getFileSnapshot(dist)).toMatchSnapshot()
})

test('custom rewriter', async () => {
const dir = 'import-rewriter'
const input = path.resolve(fixtures, dir, 'index.ts')

let importer
const bundle = await rollup({
input,
plugins: [
{
name: 'resolver',
resolveId(id, importer, opt) {
if (id[0] === '~') {
id = `.${id.slice(1)}`
return this.resolve(id, importer, opt)
}
},
},
UnpluginIsolatedDecl({
autoAddExts: true,
rewriteImports(id, _importer) {
if (id[0] === '~') {
importer = _importer
return `.${id.slice(1)}`
}
},
}),
esbuild(),
],
logLevel: 'silent',
})
const result = await bundle.generate({})

expect(outputToSnapshot(result.output)).toMatchSnapshot()
expect(importer).toBe(path.resolve(fixtures, dir, 'index.ts'))
})
})

async function getFileSnapshot(dir: string) {
Expand Down

0 comments on commit 6406eee

Please sign in to comment.