diff --git a/src/generator/dts.ts b/src/generator/dts.ts index df172e4..a057119 100644 --- a/src/generator/dts.ts +++ b/src/generator/dts.ts @@ -40,7 +40,9 @@ function _genTypes (schema: Schema, spaces: string): string[] { for (const key in schema.properties) { const val = schema.properties[key] as Schema buff.push(...generateJSDoc(val)) - if (val.type === 'object') { + if (val.tsType) { + buff.push(`${escapeKey(key)}: ${val.tsType},\n`) + } else if (val.type === 'object') { buff.push(`${escapeKey(key)}: {`, ..._genTypes(val, spaces + ' '), '},\n') } else { let type: string diff --git a/src/loader/babel.ts b/src/loader/babel.ts index eaf1c38..8f0f03c 100644 --- a/src/loader/babel.ts +++ b/src/loader/babel.ts @@ -111,7 +111,7 @@ export default function babelPluginUntyped (api: ConfigAPI) { // Extract and apply any manual types schema.tags = schema.tags?.filter((tag) => { if (tag.startsWith('@returns')) { - const { type } = tag.match(/^@returns\s+\{(?.+)\}/)?.groups || {} + const { type } = tag.match(/^@returns\s+\{(?[\S\s]+)\}/)?.groups || {} if (type) { schema.returns = schema.returns || {} Object.assign(schema.returns, getTypeDescriptor(type)) @@ -119,7 +119,7 @@ export default function babelPluginUntyped (api: ConfigAPI) { } } if (tag.startsWith('@param')) { - const { type, param } = tag.match(/^@param\s+\{(?.+)\}\s+(?\w+)/)?.groups || {} + const { type, param } = tag.match(/^@param\s+\{(?[\S\s]+)\}\s+(?\w+)/)?.groups || {} if (type && param) { const arg = schema.args?.find(arg => arg.name === param) if (arg) { @@ -186,14 +186,22 @@ function parseJSDocs (input: string | string[]): Schema { if (firstTag >= 0) { const tags = clumpLines(lines.slice(firstTag), ['@'], '\n') + const typedefs = tags.reduce((typedefs, tag) => { + const { typedef, alias } = tag.match(/@typedef\s+\{(?[\S\s]+)\} (?.*)/)?.groups || {} + if (typedef && alias) { + typedefs[typedef] = alias + } + return typedefs + }, {} as Record) for (const tag of tags) { if (tag.startsWith('@type')) { - const type = tag.match(/@type\s+\{(.+)\}/)?.[1] + const type = tag.match(/@type\s+\{([\S\s]+)\}/)?.[1] + // Skip typedefs + if (!type) { continue } Object.assign(schema, getTypeDescriptor(type)) - const typedef = tags.find(t => t.match(/@typedef\s+\{(.+)\} (.*)/)?.[2] === type) - if (typedef) { + for (const typedef in typedefs) { schema.markdownType = type - schema.tsType = typedef.match(/@typedef\s+\{(.+)\}/)?.[1] + schema.tsType = schema.tsType.replace(new RegExp(typedefs[typedef], 'g'), typedef) } continue } diff --git a/src/utils.ts b/src/utils.ts index 35ce135..c9f8dcd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -120,7 +120,7 @@ export function isJSType (val: unknown): val is JSType { return jsTypes.includes(val as any) } -const FRIENDLY_TYPE_RE = /typeof import\(['"](?[^'"]+)['"]\)(\[['"]|\.)(?[^'"\s]+)(['"]\])?/g +const FRIENDLY_TYPE_RE = /(typeof )?import\(['"](?[^'"]+)['"]\)(\[['"]|\.)(?[^'"\s]+)(['"]\])?/g export function getTypeDescriptor (type: string | JSType): TypeDescriptor { if (!type) { diff --git a/test/transform.test.ts b/test/transform.test.ts index c99c8c1..4248e1c 100644 --- a/test/transform.test.ts +++ b/test/transform.test.ts @@ -188,7 +188,13 @@ describe('transform (jsdoc)', () => { /** * @type {null | typeof import('path').posix | typeof import('net')['Socket']['PassThrough']} */ - posix: null + posix: null, + /** + * @type {null | { + * foo: 'bar' | 'baz' + * }} + */ + multiline: null } `) expectCodeToMatch(result, /export default ([\s\S]*)$/, { @@ -208,6 +214,14 @@ describe('transform (jsdoc)', () => { tsType: "null | typeof import('path').posix | typeof import('net')['Socket']['PassThrough']", markdownType: 'null | PathPosix | NetSocket[\'PassThrough\']' } + }, + multiline: { + $default: null, + $schema: { + title: '', + description: '', + tsType: "null | {\n foo: 'bar' | 'baz'\n}" + } } }) }) @@ -217,7 +231,7 @@ describe('transform (jsdoc)', () => { export default { /** * @typedef {'src' | 'root'} HumanReadable - * @type {HumanReadable} + * @type {Array} */ srcDir: 'src', } @@ -228,8 +242,8 @@ describe('transform (jsdoc)', () => { $schema: { title: '', description: '', - tsType: "'src' | 'root'", - markdownType: 'HumanReadable' + tsType: "Array<'src' | 'root'>", + markdownType: 'Array' } } })