diff --git a/snapshots/input/syntax/src/infer-relationship.ts b/snapshots/input/syntax/src/infer-relationship.ts new file mode 100644 index 00000000..af9521a2 --- /dev/null +++ b/snapshots/input/syntax/src/infer-relationship.ts @@ -0,0 +1,60 @@ +interface Configuration { + property: number +} + +function random(): number { + return Math.random() +} +export function returnStatement(): Configuration { + if (random() > 0) { + return { + property: 41, + } + } + for (let i = 0; i < 9; i++) { + if (random() > i) { + return { + property: 41, + } + } + } + for (const i of [1, 2, 3]) { + if (random() > i) { + return { + property: 41, + } + } + } + for (const i in { '1': 2 }) { + if (random() > Number.parseInt(i)) { + return { + property: 41, + } + } + } + while (random() < 0) { + return { + property: 41, + } + } + do { + if (random() > 0) { + return { + property: 41, + } + } + } while (random() < 0) + + return { + property: 42, + } +} + +export function returnStatementInsideArgumentExpression(): Configuration[] { + return [1].map(number => { + const incremented = number + 1 + return { + property: incremented, + } + }) +} diff --git a/snapshots/output/syntax/src/infer-relationship.ts b/snapshots/output/syntax/src/infer-relationship.ts new file mode 100644 index 00000000..3633c88f --- /dev/null +++ b/snapshots/output/syntax/src/infer-relationship.ts @@ -0,0 +1,136 @@ + interface Configuration { +// definition syntax 1.0.0 src/`infer-relationship.ts`/ +//documentation ```ts\nmodule "infer-relationship.ts"\n``` +// ^^^^^^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/Configuration# +// documentation ```ts\ninterface Configuration\n``` + property: number +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. +// documentation ```ts\n(property) property: number\n``` + } + + function random(): number { +// ^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/random(). +// documentation ```ts\nfunction random(): number\n``` + return Math.random() +// ^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Math# +// ^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Math. +// ^^^^ reference typescript 4.8.4 lib/`lib.es2015.core.d.ts`/Math# +// ^^^^ reference typescript 4.8.4 lib/`lib.es2015.symbol.wellknown.d.ts`/Math# +// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Math#random(). + } + export function returnStatement(): Configuration { +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/returnStatement(). +// documentation ```ts\nfunction returnStatement(): Configuration\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/Configuration# + if (random() > 0) { +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). + return { + property: 41, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property0: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + for (let i = 0; i < 9; i++) { +// ^ definition local 2 +// documentation ```ts\nvar i: number\n``` +// ^ reference local 2 +// ^ reference local 2 + if (random() > i) { +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). +// ^ reference local 2 + return { + property: 41, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property1: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + } + for (const i of [1, 2, 3]) { +// ^ definition local 5 +// documentation ```ts\nvar i: number\n``` + if (random() > i) { +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). +// ^ reference local 5 + return { + property: 41, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property2: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + } + for (const i in { '1': 2 }) { +// ^ definition local 8 +// documentation ```ts\nvar i: string\n``` +// ^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/`'1'0`: +// documentation ```ts\n(property) '1': number\n``` + if (random() > Number.parseInt(i)) { +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). +// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number# +// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number. +// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number# +// ^^^^^^ reference typescript 4.8.4 lib/`lib.es2020.number.d.ts`/Number# +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es2015.core.d.ts`/NumberConstructor#parseInt(). +// ^ reference local 8 + return { + property: 41, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property3: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + } + while (random() < 0) { +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). + return { + property: 41, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property4: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + do { + if (random() > 0) { +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). + return { + property: 41, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property5: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + } while (random() < 0) +// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random(). + + return { + property: 42, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property6: +// documentation ```ts\n(property) property: number\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property. + } + } + + export function returnStatementInsideArgumentExpression(): Configuration[] { +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/returnStatementInsideArgumentExpression(). +// documentation ```ts\nfunction returnStatementInsideArgumentExpression(): Configuration[]\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/Configuration# + return [1].map(number => { +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/Configuration# +// ^^^^^^ definition local 12 +// documentation ```ts\n(parameter) number: number\n``` + const incremented = number + 1 +// ^^^^^^^^^^^ definition local 15 +// documentation ```ts\nvar incremented: number\n``` +// ^^^^^^ reference local 12 + return { + property: incremented, +// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property7: +// documentation ```ts\n(property) property: number\n``` +// ^^^^^^^^^^^ reference local 15 + } + }) + } + diff --git a/snapshots/output/syntax/src/interface.ts b/snapshots/output/syntax/src/interface.ts index 6c72fe01..b49a0882 100644 --- a/snapshots/output/syntax/src/interface.ts +++ b/snapshots/output/syntax/src/interface.ts @@ -26,9 +26,11 @@ property: 'a', // ^^^^^^^^ definition syntax 1.0.0 src/`interface.ts`/property0: // documentation ```ts\n(property) property: string\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`interface.ts`/Interface#property. methodSignature(param: string): string { // ^^^^^^^^^^^^^^^ definition local 4 // documentation ```ts\n(method) methodSignature(param: string): string\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`interface.ts`/Interface#methodSignature(). // ^^^^^ definition local 5 // documentation ```ts\n(parameter) param: string\n``` return param @@ -37,6 +39,7 @@ methodSignature2: (param: string): string => { // ^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`interface.ts`/methodSignature20: // documentation ```ts\n(property) methodSignature2: (param: string) => string\n``` +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`interface.ts`/Interface#methodSignature2. // ^^^^^ definition local 7 // documentation ```ts\n(parameter) param: string\n``` return param diff --git a/src/FileIndexer.ts b/src/FileIndexer.ts index e67640c6..a8ec4e3e 100644 --- a/src/FileIndexer.ts +++ b/src/FileIndexer.ts @@ -38,7 +38,7 @@ export class FileIndexer { } public index(): void { // Uncomment below if you want to skip certain files for local development. - // if (!this.sourceFile.fileName.includes('ClassWithPrivate')) { + // if (!this.sourceFile.fileName.includes('infer-relationship')) { // return // } this.emitSourceFileOccurrence() @@ -561,7 +561,10 @@ export class FileIndexer { onAncestor(declaration) } if (ts.isObjectLiteralExpression(declaration)) { - const tpe = this.inferredTypeOfObjectLiteral(declaration) + const tpe = this.inferredTypeOfObjectLiteral( + declaration.parent, + declaration + ) for (const symbolDeclaration of tpe.symbol?.declarations || []) { loop(symbolDeclaration) } @@ -592,19 +595,41 @@ export class FileIndexer { // `SomeInterface`. The object literal could satisfy many types, but in this // particular location must only satisfy `SomeInterface`. private inferredTypeOfObjectLiteral( - node: ts.ObjectLiteralExpression + node: ts.Node, + literal: ts.ObjectLiteralExpression ): ts.Type { - if (ts.isVariableDeclaration(node.parent)) { + if ( + ts.isIfStatement(node) || + ts.isForStatement(node) || + ts.isForInStatement(node) || + ts.isForOfStatement(node) || + ts.isWhileStatement(node) || + ts.isDoStatement(node) || + ts.isReturnStatement(node) || + ts.isBlock(node) + ) { + return this.inferredTypeOfObjectLiteral(node.parent, literal) + } + + if (ts.isVariableDeclaration(node)) { // Example, return `SomeInterface` from `const x: SomeInterface = {y: 42}`. - return this.checker.getTypeAtLocation(node.parent.name) + return this.checker.getTypeAtLocation(node.name) + } + + if (ts.isFunctionLike(node)) { + const functionType = this.checker.getTypeAtLocation(node) + const callSignatures = functionType.getCallSignatures() + if (callSignatures.length > 0) { + return callSignatures[0].getReturnType() + } } - if (ts.isCallOrNewExpression(node.parent)) { + if (ts.isCallOrNewExpression(node)) { // Example: return the type of the second parameter of `someMethod` from // the expression `someMethod(someParameter, {y: 42})`. - const signature = this.checker.getResolvedSignature(node.parent) - for (const [index, argument] of (node.parent.arguments || []).entries()) { - if (argument === node) { + const signature = this.checker.getResolvedSignature(node) + for (const [index, argument] of (node.arguments || []).entries()) { + if (argument === literal) { const parameterSymbol = signature?.getParameters()[index] if (parameterSymbol) { return this.checker.getTypeOfSymbolAtLocation(parameterSymbol, node) @@ -613,7 +638,7 @@ export class FileIndexer { } } - return this.checker.getTypeAtLocation(node) + return this.checker.getTypeAtLocation(literal) } }