|
|
@@ -36,6 +36,7 @@ import {
|
|
|
CallExpression,
|
|
|
RestElement,
|
|
|
TSInterfaceBody,
|
|
|
+ TSTypeElement,
|
|
|
AwaitExpression,
|
|
|
Program,
|
|
|
ObjectMethod,
|
|
|
@@ -558,6 +559,82 @@ export function compileScript(
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
+ function getAstBody(): Statement[] {
|
|
|
+ return scriptAst
|
|
|
+ ? [...scriptSetupAst.body, ...scriptAst.body]
|
|
|
+ : scriptSetupAst.body
|
|
|
+ }
|
|
|
+
|
|
|
+ function resolveExtendsType(
|
|
|
+ node: Node,
|
|
|
+ qualifier: (node: Node) => boolean,
|
|
|
+ cache: Array<Node> = []
|
|
|
+ ): Array<Node> {
|
|
|
+ if (node.type === 'TSInterfaceDeclaration' && node.extends) {
|
|
|
+ node.extends.forEach(extend => {
|
|
|
+ if (
|
|
|
+ extend.type === 'TSExpressionWithTypeArguments' &&
|
|
|
+ extend.expression.type === 'Identifier'
|
|
|
+ ) {
|
|
|
+ const body = getAstBody()
|
|
|
+ for (const node of body) {
|
|
|
+ const qualified = isQualifiedType(
|
|
|
+ node,
|
|
|
+ qualifier,
|
|
|
+ extend.expression.name
|
|
|
+ )
|
|
|
+ if (qualified) {
|
|
|
+ cache.push(qualified)
|
|
|
+ resolveExtendsType(node, qualifier, cache)
|
|
|
+ return cache
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return cache
|
|
|
+ }
|
|
|
+
|
|
|
+ function isQualifiedType(
|
|
|
+ node: Node,
|
|
|
+ qualifier: (node: Node) => boolean,
|
|
|
+ refName: String
|
|
|
+ ): Node | undefined {
|
|
|
+ if (node.type === 'TSInterfaceDeclaration' && node.id.name === refName) {
|
|
|
+ return node.body
|
|
|
+ } else if (
|
|
|
+ node.type === 'TSTypeAliasDeclaration' &&
|
|
|
+ node.id.name === refName &&
|
|
|
+ qualifier(node.typeAnnotation)
|
|
|
+ ) {
|
|
|
+ return node.typeAnnotation
|
|
|
+ } else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
|
+ return isQualifiedType(node.declaration, qualifier, refName)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // filter all extends types to keep the override declaration
|
|
|
+ function filterExtendsType(extendsTypes: Node[], bodies: TSTypeElement[]) {
|
|
|
+ extendsTypes.forEach(extend => {
|
|
|
+ const body = (extend as TSInterfaceBody).body
|
|
|
+ body.forEach(newBody => {
|
|
|
+ if (
|
|
|
+ newBody.type === 'TSPropertySignature' &&
|
|
|
+ newBody.key.type === 'Identifier'
|
|
|
+ ) {
|
|
|
+ const name = newBody.key.name
|
|
|
+ const hasOverride = bodies.some(
|
|
|
+ seenBody =>
|
|
|
+ seenBody.type === 'TSPropertySignature' &&
|
|
|
+ seenBody.key.type === 'Identifier' &&
|
|
|
+ seenBody.key.name === name
|
|
|
+ )
|
|
|
+ if (!hasOverride) bodies.push(newBody)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
function resolveQualifiedType(
|
|
|
node: Node,
|
|
|
qualifier: (node: Node) => boolean
|
|
|
@@ -570,28 +647,20 @@ export function compileScript(
|
|
|
node.typeName.type === 'Identifier'
|
|
|
) {
|
|
|
const refName = node.typeName.name
|
|
|
- const isQualifiedType = (node: Node): Node | undefined => {
|
|
|
- if (
|
|
|
- node.type === 'TSInterfaceDeclaration' &&
|
|
|
- node.id.name === refName
|
|
|
- ) {
|
|
|
- return node.body
|
|
|
- } else if (
|
|
|
- node.type === 'TSTypeAliasDeclaration' &&
|
|
|
- node.id.name === refName &&
|
|
|
- qualifier(node.typeAnnotation)
|
|
|
- ) {
|
|
|
- return node.typeAnnotation
|
|
|
- } else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
|
- return isQualifiedType(node.declaration)
|
|
|
- }
|
|
|
- }
|
|
|
- const body = scriptAst
|
|
|
- ? [...scriptSetupAst.body, ...scriptAst.body]
|
|
|
- : scriptSetupAst.body
|
|
|
+ const body = getAstBody()
|
|
|
for (const node of body) {
|
|
|
- const qualified = isQualifiedType(node)
|
|
|
+ let qualified = isQualifiedType(
|
|
|
+ node,
|
|
|
+ qualifier,
|
|
|
+ refName
|
|
|
+ ) as TSInterfaceBody
|
|
|
if (qualified) {
|
|
|
+ const extendsTypes = resolveExtendsType(node, qualifier)
|
|
|
+ if (extendsTypes.length) {
|
|
|
+ const bodies: TSTypeElement[] = [...qualified.body]
|
|
|
+ filterExtendsType(extendsTypes, bodies)
|
|
|
+ qualified.body = bodies
|
|
|
+ }
|
|
|
return qualified
|
|
|
}
|
|
|
}
|