diff --git a/src/analyze/util/ast-util.ts b/src/analyze/util/ast-util.ts index fa3f3fb..e643dda 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 1fdb6ab..f28841c 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 c1d2726..ccc5e73 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"); + }); +});