From 115e2c3a356219db94931c37b6aa367db2d06994 Mon Sep 17 00:00:00 2001 From: Ben Kuster Date: Thu, 29 Oct 2020 13:50:53 +0100 Subject: [PATCH 1/2] converts "module:foo~bar" to import --- src/type_resolve_helpers.ts | 41 ++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/type_resolve_helpers.ts b/src/type_resolve_helpers.ts index 85d37e5..0ea8224 100644 --- a/src/type_resolve_helpers.ts +++ b/src/type_resolve_helpers.ts @@ -17,6 +17,7 @@ enum ENodeType { TUPLE, // [a,b] has types for children TYPE, // string, X has no children OBJECT, // {a:b, c:d} has name value pairs for children + MODULE, // module:foo/bar~baz } export class StringTreeNode { children: StringTreeNode[] = []; @@ -59,12 +60,19 @@ export class StringTreeNode { return 'TYPE'; case ENodeType.OBJECT: return 'OBJECT'; + case ENodeType.MODULE: + return 'MODULE'; default: return 'UNKNOWN' } } } +export class ModuleTreeNode extends StringTreeNode { + constructor(public name: string, public type: ENodeType, public parent: StringTreeNode | null, public qualifier?: string) + { super(name, type, parent); } +} + export function resolveComplexTypeName(name: string, doclet?: TTypedDoclet): ts.TypeNode { // parse the string into a tree of tsNodeType's @@ -80,6 +88,14 @@ export function resolveComplexTypeName(name: string, doclet?: TTypedDoclet): ts. return resolveTree(root); } +export function createModuleImport(name: string, qualifier?: string | null): ts.ImportTypeNode +{ + const nameLiteral: ts.StringLiteral = ts.createStringLiteral(name); + const nameNode: ts.LiteralTypeNode = ts.createLiteralTypeNode(nameLiteral); + const qualifierIdentifier: ts.Identifier = ts.createIdentifier(qualifier || 'default'); + return ts.createImportTypeNode(nameNode, qualifierIdentifier); +} + export function generateTree(name: string, parent: StringTreeNode | null = null) : StringTreeNode | null { const anyNode = new StringTreeNode('any', ENodeType.TYPE, parent); @@ -189,6 +205,17 @@ export function generateTree(name: string, parent: StringTreeNode | null = null) continue; } + if (partUpper === 'MODULE') { + const [name, qualifier] = parts.slice(i + 2).join('').split('~'); + const node = new ModuleTreeNode(name, ENodeType.MODULE, parent, qualifier); + if (!parent) + return node; + + parent.children.push(node); + i = parts.length; + continue; + } + // TODO: Tuples? // skip separators, our handling below takes them into account @@ -236,7 +263,7 @@ function findMatchingBracket(parts: string[], startIndex: number, openBracket: s return -1; } -function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = null) : ts.TypeNode +function resolveTree(node: StringTreeNode | ModuleTreeNode, parentTypes: ts.TypeNode[] | null = null) : ts.TypeNode { // this nodes resolved child types const childTypes: ts.TypeNode[] = []; @@ -372,7 +399,14 @@ function resolveTree(node: StringTreeNode, parentTypes: ts.TypeNode[] | null = n parentTypes.push(genericNode); break; + case ENodeType.MODULE: + const moduleNode: ModuleTreeNode = node; + const importNode: ts.ImportTypeNode = createModuleImport(moduleNode.name, moduleNode.qualifier); + if (!parentTypes) + return importNode; + parentTypes.push(importNode); + break; case ENodeType.UNION: if (childTypes.length === 0 ) { @@ -717,6 +751,11 @@ export function resolveTypeName(name: string, doclet?: TTypedDoclet): ts.TypeNod } } + if (/^module:/.test(name)) { + const [moduleName, qualifier] = name.replace(/^module:/, '').split('~'); + return createModuleImport(moduleName, qualifier); + } + return resolveComplexTypeName(name); } From c703d96dc7b449cc7d9480ec6afddafe84d05fb9 Mon Sep 17 00:00:00 2001 From: Ben Kuster Date: Tue, 3 Nov 2020 09:34:35 +0100 Subject: [PATCH 2/2] generic module handling --- src/type_resolve_helpers.ts | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/type_resolve_helpers.ts b/src/type_resolve_helpers.ts index 0ea8224..b3546f0 100644 --- a/src/type_resolve_helpers.ts +++ b/src/type_resolve_helpers.ts @@ -88,12 +88,13 @@ export function resolveComplexTypeName(name: string, doclet?: TTypedDoclet): ts. return resolveTree(root); } -export function createModuleImport(name: string, qualifier?: string | null): ts.ImportTypeNode +export function createModuleImport(name: string, qualifier?: string | null, typeArguments?: ts.TypeNode[] | null): ts.ImportTypeNode { const nameLiteral: ts.StringLiteral = ts.createStringLiteral(name); const nameNode: ts.LiteralTypeNode = ts.createLiteralTypeNode(nameLiteral); const qualifierIdentifier: ts.Identifier = ts.createIdentifier(qualifier || 'default'); - return ts.createImportTypeNode(nameNode, qualifierIdentifier); + const innerTypeArguments: ts.TypeNode[] = Array.isArray(typeArguments) ? typeArguments.slice() : []; + return ts.createImportTypeNode(nameNode, qualifierIdentifier, innerTypeArguments); } export function generateTree(name: string, parent: StringTreeNode | null = null) : StringTreeNode | null @@ -206,8 +207,20 @@ export function generateTree(name: string, parent: StringTreeNode | null = null) } if (partUpper === 'MODULE') { - const [name, qualifier] = parts.slice(i + 2).join('').split('~'); - const node = new ModuleTreeNode(name, ENodeType.MODULE, parent, qualifier); + let generic; + const templateIndex = parts.indexOf('<'); + if (templateIndex > -1) { + const genericClosingIndex = findMatchingBracket(parts, templateIndex, '<', '>'); + if (genericClosingIndex > -1) { + generic = parts.slice(templateIndex + 1, genericClosingIndex).join('') + } + } + + const endAt = templateIndex < 0 ? parts.length : templateIndex; + const [name, qualifier] = parts.slice(i + 2, endAt).join('').split('~'); + const node = new ModuleTreeNode(name, ENodeType.MODULE, parent, qualifier.replace(/\.$/, '')); + if (generic) + generateTree(generic, node); if (!parent) return node; @@ -401,7 +414,7 @@ function resolveTree(node: StringTreeNode | ModuleTreeNode, parentTypes: ts.Type break; case ENodeType.MODULE: const moduleNode: ModuleTreeNode = node; - const importNode: ts.ImportTypeNode = createModuleImport(moduleNode.name, moduleNode.qualifier); + const importNode: ts.ImportTypeNode = createModuleImport(moduleNode.name, moduleNode.qualifier, childTypes); if (!parentTypes) return importNode; @@ -750,12 +763,7 @@ export function resolveTypeName(name: string, doclet?: TTypedDoclet): ts.TypeNod ); } } - - if (/^module:/.test(name)) { - const [moduleName, qualifier] = name.replace(/^module:/, '').split('~'); - return createModuleImport(moduleName, qualifier); - } - + return resolveComplexTypeName(name); }