Skip to content

Commit

Permalink
feat!: extract top-level type imports (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielroe authored Nov 18, 2021
1 parent 696214d commit 33c76fc
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 4 deletions.
30 changes: 29 additions & 1 deletion src/generator/dts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,36 @@ const SCHEMA_KEYS = [
'returns'
]

const DECLARATION_RE = /typeof import\(['"](?<source>[^)]+)['"]\)(\.(?<type>\w+)|\[['"](?<type1>\w+)['"]\])/g

function extractTypeImports (declarations: string) {
const typeImports: Record<string, Set<string>> = {}
const aliases = new Set<string>()
const imports = []
for (const match of declarations.matchAll(DECLARATION_RE)) {
const { source, type1, type = type1 } = match.groups || {}
typeImports[source] = typeImports[source] || new Set()
typeImports[source].add(type)
}
for (const source in typeImports) {
const sourceImports = []
for (const type of typeImports[source]) {
let count = 0
let alias = type
while (aliases.has(alias)) {
alias = `${type}${count++}`
}
aliases.add(alias)
sourceImports.push(alias === type ? type : `${type} as ${alias}`)
declarations = declarations.replace(new RegExp(`typeof import\\(['"]${source}['"]\\)(\\.${type}|\\[['"]${type}['"]\\])`, 'g'), alias)
}
imports.push(`import type { ${sourceImports.join(', ')} } from '${source}'`)
}
return [...imports, declarations].join('\n')
}

export function generateTypes (schema: Schema, name: string = 'Untyped') {
return `interface ${name} {\n ` + _genTypes(schema, ' ').join('\n ') + '\n}'
return extractTypeImports(`export interface ${name} {\n ` + _genTypes(schema, ' ').join('\n ') + '\n}')
}

function _genTypes (schema: Schema, spaces: string): string[] {
Expand Down
48 changes: 45 additions & 3 deletions test/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('resolveSchema', () => {
}
}))
expect(types).toBe(`
interface Untyped {
export interface Untyped {
test: {
/**
* Test
Expand All @@ -35,7 +35,7 @@ interface Untyped {
}))

expect(types).toBe(`
interface Untyped {
export interface Untyped {
empty: Array<any>,
/** @default [1,2,3] */
Expand Down Expand Up @@ -74,9 +74,51 @@ interface Untyped {
}))

expect(types).toBe(`
interface Untyped {
export interface Untyped {
add: (test?: Array<string | number>, append?: false) => any,
}
`.trim())
})

it('extracts type imports to top-level', () => {
const types = generateTypes(resolveSchema({
test: {
foo: {
$schema: {
tsType: 'typeof import("vue").VueConfig'
}
},
bar: {
$schema: {
tsType: 'typeof import("vue")["VueConfig"]'
}
},
baz: {
$schema: {
tsType: 'typeof import("vue").OtherImport'
}
},
quf: {
$schema: {
tsType: 'typeof import("other-lib").VueConfig'
}
}
}
}))
expect(types).toBe(`
import type { VueConfig, OtherImport } from 'vue'
import type { VueConfig as VueConfig0 } from 'other-lib'
export interface Untyped {
test: {
foo: VueConfig,
bar: VueConfig,
baz: OtherImport,
quf: VueConfig0,
},
}
`.trim())
})
})

0 comments on commit 33c76fc

Please sign in to comment.