Skip to content

Commit

Permalink
feat: merging with an existing import declaration, close #7
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Feb 22, 2022
1 parent 96b44b6 commit b42ad88
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 14 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
},
"dependencies": {
"escape-string-regexp": "^5.0.0",
"magic-string": "^0.25.7",
"mlly": "^0.4.3"
},
"devDependencies": {
Expand Down
13 changes: 5 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { detectSyntax } from 'mlly'
import escapeRE from 'escape-string-regexp'
import type { Import, UnimportOptions } from './types'
import { excludeRE, stripCommentsAndStrings, toImports, separatorRE, importAsRE, toTypeDeclrationFile } from './utils'
import { excludeRE, stripCommentsAndStrings, separatorRE, importAsRE, toTypeDeclrationFile, addImportToCode } from './utils'
import { resolvePreset } from './preset'
export * from './types'

Expand Down Expand Up @@ -52,7 +52,7 @@ export function createUnimport (opts: Partial<UnimportOptions>): Unimport {

return {
detectImports: (code: string) => detectImports(code, ctx),
addImports: (code: string) => addImports(code, ctx),
addImports: (code: string, mergeExisting?: boolean) => addImports(code, ctx, mergeExisting),
generateTypeDecarations: () => toTypeDeclrationFile(ctx.imports)
}
}
Expand Down Expand Up @@ -89,11 +89,8 @@ function detectImports (code: string, ctx: Context) {
}
}

function addImports (code: string, ctx: Context) {
function addImports (code: string, ctx: Context, mergeExisting?: boolean) {
const { isCJSContext, matchedImports } = detectImports(code, ctx)
if (!matchedImports.length) {
return { code }
}
const imports = toImports(matchedImports, isCJSContext)
return { code: imports + code }

return addImportToCode(code, matchedImports, isCJSContext, mergeExisting)
}
43 changes: 42 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

import { findStaticImports, parseStaticImport, StaticImport } from 'mlly'
import MagicString from 'magic-string'
import type { Import } from './types'

export const excludeRE = [
Expand Down Expand Up @@ -86,7 +89,7 @@ export function toTypeDeclrationFile (imports: Import[]) {
}

function stringifyImportAlias (item: Import, isCJS = false) {
return item.name === item.as
return (item.as === undefined || item.name === item.as)
? item.name
: isCJS
? `${item.name}: ${item.as}`
Expand All @@ -103,3 +106,41 @@ function toImportModuleMap (imports: Import[]) {
}
return map
}

export function addImportToCode (code: string, imports: Import[], isCJS = false, mergeExisting = false) {
let newImports: Import[] = []
const s = new MagicString(code)

if (mergeExisting && !isCJS) {
const existing = findStaticImports(code).map(i => parseStaticImport(i))
const map = new Map<StaticImport, Import[]>()

imports.forEach((i) => {
const target = existing.find(e => e.specifier === i.from && e.imports.startsWith('{'))
if (!target) {
return newImports.push(i)
}
if (!map.has(target)) {
map.set(target, [])
}
map.get(target).push(i)
})

for (const [target, items] of map.entries()) {
const strings = items.map(i => stringifyImportAlias(i) + ', ')
s.appendLeft(target.start + target.code.match(/^\s*import\s*{/)[0].length, ' ' + strings.join('').trim())
}
} else {
newImports = imports
}

const newEntries = toImports(newImports, isCJS)
if (newEntries) {
s.prepend(newEntries)
}

return {
s,
code: s.toString()
}
}
57 changes: 57 additions & 0 deletions test/add-import.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { test, expect, describe } from 'vitest'
import { Import } from '../src/types'
import { addImportToCode } from '../src/utils'

describe('add-import', () => {
const code = `
import { foo } from 'specifier1'
import { bar } from 'specifier1'
import defaultFoo from 'specifier2'
import{compact}from'specifier3'
import * as importAll from 'specifier4'
import { } from 'specifier5'
`
const imports: Import[] = [
{ name: 'import1', from: 'specifier1' },
{ name: 'import2', from: 'specifier2' },
{ name: 'import3', from: 'specifier3' },
{ name: 'import4', from: 'specifier4' },
{ name: 'foo', as: 'import5', from: 'specifier5' },
{ name: 'import10', from: 'specifier10' }
]

test('no merge', () => {
expect(addImportToCode(code, imports, false, false).code)
.toMatchInlineSnapshot(`
"import { import1 } from 'specifier1';
import { import2 } from 'specifier2';
import { import3 } from 'specifier3';
import { import4 } from 'specifier4';
import { foo as import5 } from 'specifier5';
import { import10 } from 'specifier10';
import { foo } from 'specifier1'
import { bar } from 'specifier1'
import defaultFoo from 'specifier2'
import{compact}from'specifier3'
import * as importAll from 'specifier4'
import { } from 'specifier5'
"
`)
})

test('merge existing', () => {
expect(addImportToCode(code, imports, false, true).code)
.toMatchInlineSnapshot(`
"import { import2 } from 'specifier2';
import { import4 } from 'specifier4';
import { import10 } from 'specifier10';
import { import1, foo } from 'specifier1'
import { bar } from 'specifier1'
import defaultFoo from 'specifier2'
import{ import3,compact}from'specifier3'
import * as importAll from 'specifier4'
import { foo as import5, } from 'specifier5'
"
`)
})
})
7 changes: 2 additions & 5 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ describe('unimport', () => {
const { addImports } = createUnimport({
imports: [{ name: 'fooBar', from: 'test-id' }]
})
expect(addImports('console.log(fooBar())')).toMatchInlineSnapshot(`
{
"code": "import { fooBar } from 'test-id';console.log(fooBar())",
}
`)
expect(addImports('console.log(fooBar())').code)
.toMatchInlineSnapshot('"import { fooBar } from \'test-id\';console.log(fooBar())"')
})
})

0 comments on commit b42ad88

Please sign in to comment.