From 3fa881d4493d9a0c3dfbfa465aff05d4b0c49fcb Mon Sep 17 00:00:00 2001 From: driesva Date: Fri, 24 Nov 2023 19:43:56 +0100 Subject: [PATCH] feat: support tag names wich are static class properties --- src/analyze/util/ast-util.ts | 8 ++++++-- src/analyze/util/resolve-node-value.ts | 8 +++++--- test/util/resolve-node-value.spec.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/analyze/util/ast-util.ts b/src/analyze/util/ast-util.ts index fa3f3fb1..e643dda7 100644 --- a/src/analyze/util/ast-util.ts +++ b/src/analyze/util/ast-util.ts @@ -197,12 +197,16 @@ export function getInterfaceKeys( if (resolvedKey == null) { continue; } - + let keyNode = resolvedKey.node; let identifier: Node | undefined; let declaration: Node | undefined; if (ts.isTypeReferenceNode(member.type)) { // { ____: MyButton; } or { ____: namespace.MyButton; } identifier = member.type.typeName; + if (ts.isComputedPropertyName(member.name)) { + // e.g. [MyButton.TAG] : MyButton -> use initial member name node instead of resolved node + keyNode = member.name.expression; + } } else if (ts.isTypeLiteralNode(member.type)) { identifier = undefined; declaration = member.type; @@ -211,7 +215,7 @@ export function getInterfaceKeys( } if (declaration != null || identifier != null) { - extensions.push({ key: String(resolvedKey.value), keyNode: resolvedKey.node, declaration, identifier }); + extensions.push({ key: String(resolvedKey.value), keyNode: keyNode, declaration, identifier }); } } } diff --git a/src/analyze/util/resolve-node-value.ts b/src/analyze/util/resolve-node-value.ts index 1fdb6ab8..f28841ce 100644 --- a/src/analyze/util/resolve-node-value.ts +++ b/src/analyze/util/resolve-node-value.ts @@ -77,12 +77,14 @@ export function resolveNodeValue(node: Node | undefined, context: Context): { va return resolveNodeValue(node.expression, { ...context, depth }); } - // Resolve initializer value of enum members. - else if (ts.isEnumMember(node)) { + // Resolve initializer value of enum members or class properties. + else if (ts.isEnumMember(node) || ts.isPropertyDeclaration(node)) { if (node.initializer != null) { return resolveNodeValue(node.initializer, { ...context, depth }); - } else { + } else if (node.parent.name) { return { value: `${node.parent.name.text}.${node.name.getText()}`, node }; + } else { + return { value: `${node.name.getText()}`, node }; } } diff --git a/test/util/resolve-node-value.spec.ts b/test/util/resolve-node-value.spec.ts index c1d27264..ccc5e738 100644 --- a/test/util/resolve-node-value.spec.ts +++ b/test/util/resolve-node-value.spec.ts @@ -52,3 +52,29 @@ type AliasedLiteral = StringLiteral; t.is(actualValue, "popsicles", `Resolved value for '${name.getText()}' is invalid`); }); }); + +test("resolveNodeValue resolves class properties", t => { + const { + analyzedSourceFiles: [sourceFile], + program + } = analyzeText(` +class FooClass { + static readonly FOO_BAR = "foo-bar"; + readonly barBaz = "bar-baz"; + fooBaz = "foo-baz"; +} + `); + + const checker = program.getTypeChecker(); + + const assertPropertyNodeValue = (node: ts.ClassElement, expectedValue: string) => { + const propertyNodeValue = resolveNodeValue(node, { checker, ts })?.value; + t.is(propertyNodeValue, expectedValue, `Resolved value for '${node.name?.getText()}' is invalid`); + }; + + findChildren(sourceFile, ts.isClassDeclaration, ({ name, members }) => { + assertPropertyNodeValue(members[0], "foo-bar"); + assertPropertyNodeValue(members[1], "bar-baz"); + assertPropertyNodeValue(members[2], "foo-baz"); + }); +});