diff --git a/snapshots/input/syntax/src/decorators.ts b/snapshots/input/syntax/src/decorators.ts new file mode 100644 index 00000000..27937bcb --- /dev/null +++ b/snapshots/input/syntax/src/decorators.ts @@ -0,0 +1,12 @@ +import { Configuration } from './reusable-types' + +function MyDecorator(value: Configuration) { + return function (target: Function) { + console.log(`MyDecorator is called with value: ${value}`) + } +} + +@MyDecorator({ property: 42, property2: '42' }) +class MyClass { + //... +} diff --git a/snapshots/input/syntax/src/infer-relationship.ts b/snapshots/input/syntax/src/infer-relationship.ts deleted file mode 100644 index af9521a2..00000000 --- a/snapshots/input/syntax/src/infer-relationship.ts +++ /dev/null @@ -1,60 +0,0 @@ -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/input/syntax/src/inheritance.ts b/snapshots/input/syntax/src/inheritance.ts index ef57aa3e..f0ad8a86 100644 --- a/snapshots/input/syntax/src/inheritance.ts +++ b/snapshots/input/syntax/src/inheritance.ts @@ -1,9 +1,6 @@ +import { Superinterface } from './reusable-types' import { Overloader } from './overload' -export interface Superinterface { - property: string - interfaceMethod(): string -} export interface IntermediateSuperinterface extends Superinterface { intermediateInterfaceMethod(): string } @@ -43,10 +40,3 @@ export const objectLiteralImplementation: Superinterface = { throw new Error('Function not implemented.') }, } -export function consumesInterface(superInterface: Superinterface): void {} -export function infersInterface(): void { - consumesInterface({ - interfaceMethod: (): string => 'inferred', - property: 'inferred', - }) -} diff --git a/snapshots/input/syntax/src/object-literals-arrow-function.ts b/snapshots/input/syntax/src/object-literals-arrow-function.ts new file mode 100644 index 00000000..d914d42d --- /dev/null +++ b/snapshots/input/syntax/src/object-literals-arrow-function.ts @@ -0,0 +1,35 @@ +import { Option } from './reusable-types' + +interface Foobar { + foobar: number +} + +export function hasArrowFunctionParameter( + something: number, + fn: (foobar: Foobar) => Foobar +): Foobar { + return fn({ foobar: 42 + something }) +} + +export function consumesArrowFunction(): number { + return ( + hasArrowFunctionParameter(1, ({ foobar }) => ({ foobar: foobar + 1 })) + .foobar + + hasArrowFunctionParameter(2, foobar => ({ foobar: foobar.foobar + 2 })) + .foobar + ) +} + +export function genericArrow(): Foobar[] { + return [1].map(n => ({ foobar: n + 1 })) +} + +export function genericArrowOption(): Option[] { + return [1].map>(n => ({ value: { foobar: n + 1 } })) +} + +export function genericArrow2(): Foobar[] { + // navigation to `foobar` below does not work with tsserver or scip-java + // because `map` is missing an explicit `map` annotation. + return [1].map(n => ({ foobar: n + 1 })) +} diff --git a/snapshots/input/syntax/src/object-literals-call-signatures.ts b/snapshots/input/syntax/src/object-literals-call-signatures.ts new file mode 100644 index 00000000..3df73103 --- /dev/null +++ b/snapshots/input/syntax/src/object-literals-call-signatures.ts @@ -0,0 +1,73 @@ +import { + Configuration, + GenericClass, + GenericInterface, + Option, + Superinterface, +} from './reusable-types' + +export function consumesInterface(superInterface: Superinterface): void {} +export function consumesArray(superInterface: Superinterface[]): void {} +export function consumesGenericInterface( + genercInterface: GenericInterface +): void {} + +export function infersInterface(): void { + consumesInterface({ + interfaceMethod: (): string => 'inferred', + property: 'inferred', + }) + consumesArray([ + { + interfaceMethod: (): string => 'inferred', + property: 'inferred', + }, + ]) + consumesGenericInterface({ + interfaceMethod: (): string => 'inferred', + property: 123, + }) + consumesGenericInterface[]>({ + interfaceMethod: (): string => 'inferred', + property: [{ value: { property: 42, property2: '42' } }], + }) +} +export function returnStatementInsideArgumentExpression(): Configuration[] { + if (1 == 1) { + return [1].map((number: number): Configuration => { + const incremented = number + 1 + return { + property: incremented, + property2: incremented.toString(), + } + }) + } else { + return [1].map(number => { + const incremented = number + 1 + return { + property: incremented, + property2: incremented.toString(), + } + }) + } +} + +export function createGenericClass(): GenericClass { + return new GenericClass([{ property: 1, property2: '2' }]) +} + +export function handleGenericClass() { + return createGenericClass().map(({ property, property2 }) => ({ + property: property + 1, + property2: property2 + '1', + })) +} + +export function handleShorthand() { + const property = '42' + const interfaceMethod = (): string => 'inferred' + consumesInterface({ + interfaceMethod, + property, + }) +} diff --git a/snapshots/input/syntax/src/object-literals-nested.ts b/snapshots/input/syntax/src/object-literals-nested.ts new file mode 100644 index 00000000..6a8096ff --- /dev/null +++ b/snapshots/input/syntax/src/object-literals-nested.ts @@ -0,0 +1,40 @@ +import { Option } from './reusable-types' + +interface Address { + street: string + people: Person[] +} +interface Person { + name: string + address?: Address +} + +export function handleNestedObjectLiterals(): Person { + return { + name: 'John', + address: { + street: 'Oxford Street', + people: [ + { + name: 'Susan', + }, + ], + }, + } +} + +export function handleNestedTypeVariables(): Option { + return { + value: { + name: 'John', + address: { + street: 'Oxford Street', + people: [ + { + name: 'Susan', + }, + ], + }, + }, + } +} diff --git a/snapshots/input/syntax/src/object-literals.ts b/snapshots/input/syntax/src/object-literals.ts new file mode 100644 index 00000000..c9efaa38 --- /dev/null +++ b/snapshots/input/syntax/src/object-literals.ts @@ -0,0 +1,91 @@ +import { Configuration } from './reusable-types' + +function random(): number { + return Math.random() +} + +export function handleArrayLiteral(): Configuration[] { + return [ + { + property: 41, + property2: '41', + }, + ] +} + +export function returnStatement(): Configuration { + if (random() > 0) { + return { + property: 41, + property2: '41', + } + } + for (let i = 0; i < 9; i++) { + if (random() > i) { + return { + property: 41, + property2: '41', + } + } + } + for (const i of [1, 2, 3]) { + if (random() > i) { + return { + property: 41, + property2: '41', + } + } + } + for (const i in { '1': 2 }) { + if (random() > Number.parseInt(i)) { + return { + property: 41, + property2: '41', + } + } + } + while (random() < 0) { + return { + property: 41, + property2: '41', + } + } + do { + if (random() > 0) { + return { + property: 41, + property2: '41', + } + } + } while (random() < 0) + + return { + property: 42, + property2: '41', + } +} + +export function constDeclaration(): number[] { + var configuration1: Configuration = { + property: 1, + property2: '1', + } + configuration1 = { + property: 2, + property2: '2', + } + let configuration2: Configuration = { + property: 3, + property2: '3', + } + configuration2.property = configuration1.property + const configuration3: Configuration = { + property: 4, + property2: '4', + } + return [ + configuration1.property, + configuration2.property, + configuration3.property, + ] +} diff --git a/snapshots/input/syntax/src/reusable-types.ts b/snapshots/input/syntax/src/reusable-types.ts new file mode 100644 index 00000000..df961834 --- /dev/null +++ b/snapshots/input/syntax/src/reusable-types.ts @@ -0,0 +1,29 @@ +// Reusable types for other snapshot tests + +export interface Option { + value?: A +} + +export interface Numbers { + property: number +} +export interface Strings { + property2: string +} +export type Configuration = Numbers & Strings + +export class GenericClass { + constructor(public readonly values: A[]) {} + public map(fn: (a: A) => A): A[] { + return this.values.map(a => fn(a)) + } +} + +export interface Superinterface { + property: string + interfaceMethod(): string +} +export interface GenericInterface { + property: T + interfaceMethod(): string +} diff --git a/snapshots/input/syntax/tsconfig.json b/snapshots/input/syntax/tsconfig.json index 578d9f4d..bdfe08db 100644 --- a/snapshots/input/syntax/tsconfig.json +++ b/snapshots/input/syntax/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "outDir": "dist", - "target": "ES2015" + "target": "ES2015", + "experimentalDecorators": true } } diff --git a/snapshots/output/syntax/src/decorators.ts b/snapshots/output/syntax/src/decorators.ts new file mode 100644 index 00000000..82bddc29 --- /dev/null +++ b/snapshots/output/syntax/src/decorators.ts @@ -0,0 +1,40 @@ + import { Configuration } from './reusable-types' +// definition syntax 1.0.0 src/`decorators.ts`/ +//documentation ```ts\nmodule "decorators.ts"\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/ + + function MyDecorator(value: Configuration) { +// ^^^^^^^^^^^ definition syntax 1.0.0 src/`decorators.ts`/MyDecorator(). +// documentation ```ts\nfunction MyDecorator(value: Configuration): (target: Function) => void\n``` +// ^^^^^ definition syntax 1.0.0 src/`decorators.ts`/MyDecorator().(value) +// documentation ```ts\n(parameter) value: Configuration\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + return function (target: Function) { +// ^^^^^^ definition local 2 +// documentation ```ts\n(parameter) target: Function\n``` +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Function# +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Function. +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es2015.core.d.ts`/Function# +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es2015.symbol.wellknown.d.ts`/Function# + console.log(`MyDecorator is called with value: ${value}`) +// ^^^^^^^ reference typescript 4.8.4 lib/`lib.dom.d.ts`/console. +// ^^^^^^^ reference @types/node 17.0.14 `globals.d.ts`/console. +// ^^^^^^^ reference @types/node 17.0.14 `console.d.ts`/`'node:console'`/global/console/ +// ^^^^^^^ reference @types/node 17.0.14 `console.d.ts`/`'node:console'`/global/console. +// ^^^ reference typescript 4.8.4 lib/`lib.dom.d.ts`/Console#log(). +// ^^^ reference @types/node 17.0.14 `console.d.ts`/`'node:console'`/global/Console#log(). +// ^^^^^ reference syntax 1.0.0 src/`decorators.ts`/MyDecorator().(value) + } + } + + @MyDecorator({ property: 42, property2: '42' }) +// ^^^^^^^^^^^ reference syntax 1.0.0 src/`decorators.ts`/MyDecorator(). +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + class MyClass { +// ^^^^^^^ definition syntax 1.0.0 src/`decorators.ts`/MyClass# +// documentation ```ts\nclass MyClass\n``` + //... + } + diff --git a/snapshots/output/syntax/src/destructuring.ts b/snapshots/output/syntax/src/destructuring.ts index 5e45830e..86514e17 100644 --- a/snapshots/output/syntax/src/destructuring.ts +++ b/snapshots/output/syntax/src/destructuring.ts @@ -11,9 +11,7 @@ // ^^^^^ definition syntax 1.0.0 src/`destructuring.ts`/props. // documentation ```ts\nvar props: Props\n``` // ^^^^^ reference syntax 1.0.0 src/`destructuring.ts`/Props# -// ^ definition syntax 1.0.0 src/`destructuring.ts`/a0: -// documentation ```ts\n(property) a: number\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`destructuring.ts`/Props#a. +// ^ reference syntax 1.0.0 src/`destructuring.ts`/Props#a. export function objectDestructuring(): number[] { // ^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`destructuring.ts`/objectDestructuring(). diff --git a/snapshots/output/syntax/src/infer-relationship.ts b/snapshots/output/syntax/src/infer-relationship.ts deleted file mode 100644 index 3633c88f..00000000 --- a/snapshots/output/syntax/src/infer-relationship.ts +++ /dev/null @@ -1,136 +0,0 @@ - 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/inheritance.ts b/snapshots/output/syntax/src/inheritance.ts index 35c156e2..e4521dbe 100644 --- a/snapshots/output/syntax/src/inheritance.ts +++ b/snapshots/output/syntax/src/inheritance.ts @@ -1,23 +1,16 @@ - import { Overloader } from './overload' + import { Superinterface } from './reusable-types' // definition syntax 1.0.0 src/`inheritance.ts`/ //documentation ```ts\nmodule "inheritance.ts"\n``` +// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface# +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/ + import { Overloader } from './overload' // ^^^^^^^^^^ reference syntax 1.0.0 src/`overload.d.ts`/Overloader# // ^^^^^^^^^^^^ reference syntax 1.0.0 src/`overload.d.ts`/ - export interface Superinterface { -// ^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/Superinterface# -// documentation ```ts\ninterface Superinterface\n``` - property: string -// ^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/Superinterface#property. -// documentation ```ts\n(property) property: string\n``` - interfaceMethod(): string -// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/Superinterface#interfaceMethod(). -// documentation ```ts\n(method) interfaceMethod() => string\n``` - } export interface IntermediateSuperinterface extends Superinterface { // ^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/IntermediateSuperinterface# // documentation ```ts\ninterface IntermediateSuperinterface\n``` -// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`inheritance.ts`/Superinterface# +// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface# intermediateInterfaceMethod(): string // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/IntermediateSuperinterface#intermediateInterfaceMethod(). // documentation ```ts\n(method) intermediateInterfaceMethod() => string\n``` @@ -50,8 +43,8 @@ // relationship implementation scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/IntermediateSuperclass# // relationship implementation scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/IntermediateSuperinterface# // relationship implementation scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superclass# -// relationship implementation scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface# // relationship implementation scip-typescript npm syntax 1.0.0 src/`overload.d.ts`/Overloader# +// relationship implementation scip-typescript npm syntax 1.0.0 src/`reusable-types.ts`/Superinterface# extends IntermediateSuperclass // ^^^^^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`inheritance.ts`/IntermediateSuperclass# implements IntermediateSuperinterface, Overloader @@ -72,7 +65,7 @@ property = 'property' // ^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/Subclass#property. // documentation ```ts\n(property) property: string\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface#property. +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`reusable-types.ts`/Superinterface#property. public overrideMethod(): string { // ^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/Subclass#overrideMethod(). // documentation ```ts\n(method) overrideMethod(): string\n``` @@ -93,7 +86,7 @@ public interfaceMethod(): string { // ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/Subclass#interfaceMethod(). // documentation ```ts\n(method) interfaceMethod(): string\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface#interfaceMethod(). +// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`reusable-types.ts`/Superinterface#interfaceMethod(). throw new Error('Method not implemented.') // ^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Error# // ^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Error. @@ -110,39 +103,14 @@ export const objectLiteralImplementation: Superinterface = { // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/objectLiteralImplementation. // documentation ```ts\nvar objectLiteralImplementation: Superinterface\n``` -// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`inheritance.ts`/Superinterface# +// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface# property: 'property', -// ^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/property0: -// documentation ```ts\n(property) property: string\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface#property. +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#property. interfaceMethod: (): string => { -// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/interfaceMethod0: -// documentation ```ts\n(property) interfaceMethod: () => string\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface#interfaceMethod(). +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#interfaceMethod(). throw new Error('Function not implemented.') // ^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Error# // ^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Error. }, } - export function consumesInterface(superInterface: Superinterface): void {} -// ^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/consumesInterface(). -// documentation ```ts\nfunction consumesInterface(superInterface: Superinterface): void\n``` -// ^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/consumesInterface().(superInterface) -// documentation ```ts\n(parameter) superInterface: Superinterface\n``` -// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`inheritance.ts`/Superinterface# - export function infersInterface(): void { -// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/infersInterface(). -// documentation ```ts\nfunction infersInterface(): void\n``` - consumesInterface({ -// ^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`inheritance.ts`/consumesInterface(). - interfaceMethod: (): string => 'inferred', -// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/interfaceMethod1: -// documentation ```ts\n(property) interfaceMethod: () => string\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface#interfaceMethod(). - property: 'inferred', -// ^^^^^^^^ definition syntax 1.0.0 src/`inheritance.ts`/property1: -// documentation ```ts\n(property) property: string\n``` -// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`inheritance.ts`/Superinterface#property. - }) - } diff --git a/snapshots/output/syntax/src/interface.ts b/snapshots/output/syntax/src/interface.ts index b49a0882..8d1d56a4 100644 --- a/snapshots/output/syntax/src/interface.ts +++ b/snapshots/output/syntax/src/interface.ts @@ -24,26 +24,20 @@ // ^^^^^^^^^ reference syntax 1.0.0 src/`interface.ts`/Interface# return { 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. +// ^^^^^^^^ reference 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 +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`interface.ts`/Interface#methodSignature(). +// ^^^^^ definition syntax 1.0.0 src/`interface.ts`/Interface#methodSignature().(param) // documentation ```ts\n(parameter) param: string\n``` return param -// ^^^^^ reference local 5 +// ^^^^^ reference syntax 1.0.0 src/`interface.ts`/Interface#methodSignature().(param) }, 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 +// ^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`interface.ts`/Interface#methodSignature2. +// ^^^^^ definition local 3 // documentation ```ts\n(parameter) param: string\n``` return param -// ^^^^^ reference local 7 +// ^^^^^ reference local 3 }, } } diff --git a/snapshots/output/syntax/src/object-literals-arrow-function.ts b/snapshots/output/syntax/src/object-literals-arrow-function.ts new file mode 100644 index 00000000..0b896d65 --- /dev/null +++ b/snapshots/output/syntax/src/object-literals-arrow-function.ts @@ -0,0 +1,104 @@ + import { Option } from './reusable-types' +// definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/ +//documentation ```ts\nmodule "object-literals-arrow-function.ts"\n``` +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/ + + interface Foobar { +// ^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# +// documentation ```ts\ninterface Foobar\n``` + foobar: number +// ^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// documentation ```ts\n(property) foobar: number\n``` + } + + export function hasArrowFunctionParameter( +// ^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter(). +// documentation ```ts\nfunction hasArrowFunctionParameter(something: number, fn: (foobar: Foobar) => Foobar): Foobar\n``` + something: number, +// ^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter().(something) +// documentation ```ts\n(parameter) something: number\n``` + fn: (foobar: Foobar) => Foobar +// ^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter().(fn) +// documentation ```ts\n(parameter) fn: (foobar: Foobar) => Foobar\n``` +// ^^^^^^ definition local 1 +// documentation ```ts\n(parameter) foobar: Foobar\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# + ): Foobar { +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# + return fn({ foobar: 42 + something }) +// ^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter().(fn) +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// ^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter().(something) + } + + export function consumesArrowFunction(): number { +// ^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/consumesArrowFunction(). +// documentation ```ts\nfunction consumesArrowFunction(): number\n``` + return ( + hasArrowFunctionParameter(1, ({ foobar }) => ({ foobar: foobar + 1 })) +// ^^^^^^^^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter(). +// ^^^^^^ definition local 10 +// documentation ```ts\n(parameter) foobar: number\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// ^^^^^^ reference local 10 + .foobar + +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. + hasArrowFunctionParameter(2, foobar => ({ foobar: foobar.foobar + 2 })) +// ^^^^^^^^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/hasArrowFunctionParameter(). +// ^^^^^^ definition local 14 +// documentation ```ts\n(parameter) foobar: Foobar\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// ^^^^^^ reference local 14 +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. + .foobar +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. + ) + } + + export function genericArrow(): Foobar[] { +// ^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/genericArrow(). +// documentation ```ts\nfunction genericArrow(): Foobar[]\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# + return [1].map(n => ({ foobar: n + 1 })) +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# +// ^ definition local 18 +// documentation ```ts\n(parameter) n: number\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// ^ reference local 18 + } + + export function genericArrowOption(): Option[] { +// ^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/genericArrowOption(). +// documentation ```ts\nfunction genericArrowOption(): Option[]\n``` +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# + return [1].map>(n => ({ value: { foobar: n + 1 } })) +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# +// ^ definition local 22 +// documentation ```ts\n(parameter) n: number\n``` +// ^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option#value. +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar#foobar. +// ^ reference local 22 + } + + export function genericArrow2(): Foobar[] { +// ^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/genericArrow2(). +// documentation ```ts\nfunction genericArrow2(): Foobar[]\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-arrow-function.ts`/Foobar# + // navigation to `foobar` below does not work with tsserver or scip-java + // because `map` is missing an explicit `map` annotation. + return [1].map(n => ({ foobar: n + 1 })) +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^ definition local 26 +// documentation ```ts\n(parameter) n: number\n``` +// ^^^^^^ definition syntax 1.0.0 src/`object-literals-arrow-function.ts`/foobar0: +// documentation ```ts\n(property) foobar: number\n``` +// ^ reference local 26 + } + diff --git a/snapshots/output/syntax/src/object-literals-call-signatures.ts b/snapshots/output/syntax/src/object-literals-call-signatures.ts new file mode 100644 index 00000000..6e5d7c60 --- /dev/null +++ b/snapshots/output/syntax/src/object-literals-call-signatures.ts @@ -0,0 +1,178 @@ + import { +// definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/ +//documentation ```ts\nmodule "object-literals-call-signatures.ts"\n``` + Configuration, +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + GenericClass, +// ^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass# + GenericInterface, +// ^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface# + Option, +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# + Superinterface, +// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface# + } from './reusable-types' +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/ + + export function consumesInterface(superInterface: Superinterface): void {} +// ^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesInterface(). +// documentation ```ts\nfunction consumesInterface(superInterface: Superinterface): void\n``` +// ^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesInterface().(superInterface) +// documentation ```ts\n(parameter) superInterface: Superinterface\n``` +// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface# + export function consumesArray(superInterface: Superinterface[]): void {} +// ^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesArray(). +// documentation ```ts\nfunction consumesArray(superInterface: Superinterface[]): void\n``` +// ^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesArray().(superInterface) +// documentation ```ts\n(parameter) superInterface: Superinterface[]\n``` +// ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface# + export function consumesGenericInterface( +// ^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesGenericInterface(). +// documentation ```ts\nfunction consumesGenericInterface(genercInterface: GenericInterface): void\n``` +// ^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesGenericInterface().[T] +// documentation ```ts\nT: T\n``` + genercInterface: GenericInterface +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesGenericInterface().(genercInterface) +// documentation ```ts\n(parameter) genercInterface: GenericInterface\n``` +// ^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface# +// ^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesGenericInterface().[T] + ): void {} + + export function infersInterface(): void { +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/infersInterface(). +// documentation ```ts\nfunction infersInterface(): void\n``` + consumesInterface({ +// ^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesInterface(). + interfaceMethod: (): string => 'inferred', +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#interfaceMethod(). + property: 'inferred', +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#property. + }) + consumesArray([ +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesArray(). + { + interfaceMethod: (): string => 'inferred', +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#interfaceMethod(). + property: 'inferred', +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#property. + }, + ]) + consumesGenericInterface({ +// ^^^^^^^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesGenericInterface(). + interfaceMethod: (): string => 'inferred', +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#interfaceMethod(). + property: 123, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#property. + }) + consumesGenericInterface[]>({ +// ^^^^^^^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesGenericInterface(). +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + interfaceMethod: (): string => 'inferred', +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#interfaceMethod(). + property: [{ value: { property: 42, property2: '42' } }], +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#property. +// ^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option#value. +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + }) + } + export function returnStatementInsideArgumentExpression(): Configuration[] { +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/returnStatementInsideArgumentExpression(). +// documentation ```ts\nfunction returnStatementInsideArgumentExpression(): Configuration[]\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + if (1 == 1) { + return [1].map((number: number): Configuration => { +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# +// ^^^^^^ definition local 3 +// documentation ```ts\n(parameter) number: number\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + const incremented = number + 1 +// ^^^^^^^^^^^ definition local 6 +// documentation ```ts\nvar incremented: number\n``` +// ^^^^^^ reference local 3 + return { + property: incremented, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^^^ reference local 6 + property2: incremented.toString(), +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. +// ^^^^^^^^^^^ reference local 6 +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number#toString(). + } + }) + } else { + return [1].map(number => { +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# +// ^^^^^^ definition local 10 +// documentation ```ts\n(parameter) number: number\n``` + const incremented = number + 1 +// ^^^^^^^^^^^ definition local 13 +// documentation ```ts\nvar incremented: number\n``` +// ^^^^^^ reference local 10 + return { + property: incremented, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^^^ reference local 13 + property2: incremented.toString(), +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. +// ^^^^^^^^^^^ reference local 13 +// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number#toString(). + } + }) + } + } + + export function createGenericClass(): GenericClass { +// ^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/createGenericClass(). +// documentation ```ts\nfunction createGenericClass(): GenericClass\n``` +// ^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass# +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + return new GenericClass([{ property: 1, property2: '2' }]) +// ^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#``(). +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + + export function handleGenericClass() { +// ^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/handleGenericClass(). +// documentation ```ts\nfunction handleGenericClass(): Configuration[]\n``` + return createGenericClass().map(({ property, property2 }) => ({ +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/createGenericClass(). +// ^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#map(). +// ^^^^^^^^ definition local 19 +// documentation ```ts\n(parameter) property: number\n``` +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^ definition local 20 +// documentation ```ts\n(parameter) property2: string\n``` +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + property: property + 1, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^ reference local 19 + property2: property2 + '1', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. +// ^^^^^^^^^ reference local 20 + })) + } + + export function handleShorthand() { +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-call-signatures.ts`/handleShorthand(). +// documentation ```ts\nfunction handleShorthand(): void\n``` + const property = '42' +// ^^^^^^^^ definition local 23 +// documentation ```ts\nvar property: "42"\n``` + const interfaceMethod = (): string => 'inferred' +// ^^^^^^^^^^^^^^^ definition local 26 +// documentation ```ts\nvar interfaceMethod: () => string\n``` + consumesInterface({ +// ^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`object-literals-call-signatures.ts`/consumesInterface(). + interfaceMethod, +// ^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#interfaceMethod(). + property, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Superinterface#property. + }) + } + diff --git a/snapshots/output/syntax/src/object-literals-nested.ts b/snapshots/output/syntax/src/object-literals-nested.ts new file mode 100644 index 00000000..5805348d --- /dev/null +++ b/snapshots/output/syntax/src/object-literals-nested.ts @@ -0,0 +1,77 @@ + import { Option } from './reusable-types' +// definition syntax 1.0.0 src/`object-literals-nested.ts`/ +//documentation ```ts\nmodule "object-literals-nested.ts"\n``` +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/ + + interface Address { +// ^^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/Address# +// documentation ```ts\ninterface Address\n``` + street: string +// ^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/Address#street. +// documentation ```ts\n(property) street: string\n``` + people: Person[] +// ^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/Address#people. +// documentation ```ts\n(property) people: Person[]\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person# + } + interface Person { +// ^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/Person# +// documentation ```ts\ninterface Person\n``` + name: string +// ^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/Person#name. +// documentation ```ts\n(property) name: string\n``` + address?: Address +// ^^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/Person#address. +// documentation ```ts\n(property) address: Address\n``` +// ^^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Address# + } + + export function handleNestedObjectLiterals(): Person { +// ^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/handleNestedObjectLiterals(). +// documentation ```ts\nfunction handleNestedObjectLiterals(): Person\n``` +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person# + return { + name: 'John', +// ^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person#name. + address: { +// ^^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person#address. + street: 'Oxford Street', +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Address#street. + people: [ +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Address#people. + { + name: 'Susan', +// ^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person#name. + }, + ], + }, + } + } + + export function handleNestedTypeVariables(): Option { +// ^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals-nested.ts`/handleNestedTypeVariables(). +// documentation ```ts\nfunction handleNestedTypeVariables(): Option\n``` +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option# +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person# + return { + value: { +// ^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Option#value. + name: 'John', +// ^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person#name. + address: { +// ^^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person#address. + street: 'Oxford Street', +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Address#street. + people: [ +// ^^^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Address#people. + { + name: 'Susan', +// ^^^^ reference syntax 1.0.0 src/`object-literals-nested.ts`/Person#name. + }, + ], + }, + }, + } + } + diff --git a/snapshots/output/syntax/src/object-literals.ts b/snapshots/output/syntax/src/object-literals.ts new file mode 100644 index 00000000..75c7d961 --- /dev/null +++ b/snapshots/output/syntax/src/object-literals.ts @@ -0,0 +1,180 @@ + import { Configuration } from './reusable-types' +// definition syntax 1.0.0 src/`object-literals.ts`/ +//documentation ```ts\nmodule "object-literals.ts"\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# +// ^^^^^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/ + + function random(): number { +// ^^^^^^ definition syntax 1.0.0 src/`object-literals.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 handleArrayLiteral(): Configuration[] { +// ^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals.ts`/handleArrayLiteral(). +// documentation ```ts\nfunction handleArrayLiteral(): Configuration[]\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + return [ + { + property: 41, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + }, + ] + } + + export function returnStatement(): Configuration { +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals.ts`/returnStatement(). +// documentation ```ts\nfunction returnStatement(): Configuration\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + if (random() > 0) { +// ^^^^^^ reference syntax 1.0.0 src/`object-literals.ts`/random(). + return { + property: 41, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + 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/`object-literals.ts`/random(). +// ^ reference local 2 + return { + property: 41, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + } + 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/`object-literals.ts`/random(). +// ^ reference local 5 + return { + property: 41, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + } + for (const i in { '1': 2 }) { +// ^ definition local 8 +// documentation ```ts\nvar i: string\n``` +// ^^^ definition syntax 1.0.0 src/`object-literals.ts`/`'1'0`: +// documentation ```ts\n(property) '1': number\n``` + if (random() > Number.parseInt(i)) { +// ^^^^^^ reference syntax 1.0.0 src/`object-literals.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, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + } + while (random() < 0) { +// ^^^^^^ reference syntax 1.0.0 src/`object-literals.ts`/random(). + return { + property: 41, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + do { + if (random() > 0) { +// ^^^^^^ reference syntax 1.0.0 src/`object-literals.ts`/random(). + return { + property: 41, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + } while (random() < 0) +// ^^^^^^ reference syntax 1.0.0 src/`object-literals.ts`/random(). + + return { + property: 42, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '41', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + } + + export function constDeclaration(): number[] { +// ^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`object-literals.ts`/constDeclaration(). +// documentation ```ts\nfunction constDeclaration(): number[]\n``` + var configuration1: Configuration = { +// ^^^^^^^^^^^^^^ definition local 11 +// documentation ```ts\nvar configuration1: Configuration\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + property: 1, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '1', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + configuration1 = { +// ^^^^^^^^^^^^^^ reference local 11 + property: 2, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '2', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + let configuration2: Configuration = { +// ^^^^^^^^^^^^^^ definition local 14 +// documentation ```ts\nvar configuration2: Configuration\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + property: 3, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '3', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + configuration2.property = configuration1.property +// ^^^^^^^^^^^^^^ reference local 14 +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// ^^^^^^^^^^^^^^ reference local 11 +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + const configuration3: Configuration = { +// ^^^^^^^^^^^^^^ definition local 17 +// documentation ```ts\nvar configuration3: Configuration\n``` +// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Configuration# + property: 4, +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + property2: '4', +// ^^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. + } + return [ + configuration1.property, +// ^^^^^^^^^^^^^^ reference local 11 +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + configuration2.property, +// ^^^^^^^^^^^^^^ reference local 14 +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + configuration3.property, +// ^^^^^^^^^^^^^^ reference local 17 +// ^^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. + ] + } + diff --git a/snapshots/output/syntax/src/reusable-types.ts b/snapshots/output/syntax/src/reusable-types.ts new file mode 100644 index 00000000..61fe3eba --- /dev/null +++ b/snapshots/output/syntax/src/reusable-types.ts @@ -0,0 +1,90 @@ + // Reusable types for other snapshot tests +// definition syntax 1.0.0 src/`reusable-types.ts`/ +//documentation ```ts\nmodule "reusable-types.ts"\n``` + + export interface Option { +// ^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Option# +// documentation ```ts\ninterface Option\n``` +// ^ definition syntax 1.0.0 src/`reusable-types.ts`/Option#[A] +// documentation ```ts\nA: A\n``` + value?: A +// ^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Option#value. +// documentation ```ts\n(property) value: A\n``` +// ^ reference syntax 1.0.0 src/`reusable-types.ts`/Option#[A] + } + + export interface Numbers { +// ^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Numbers# +// documentation ```ts\ninterface Numbers\n``` + property: number +// ^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Numbers#property. +// documentation ```ts\n(property) property: number\n``` + } + export interface Strings { +// ^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Strings# +// documentation ```ts\ninterface Strings\n``` + property2: string +// ^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Strings#property2. +// documentation ```ts\n(property) property2: string\n``` + } + export type Configuration = Numbers & Strings +// ^^^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Configuration# +// documentation ```ts\ntype Configuration\n``` +// ^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Numbers# +// ^^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/Strings# + + export class GenericClass { +// ^^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericClass# +// documentation ```ts\nclass GenericClass\n``` +// ^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericClass#[A] +// documentation ```ts\nA: A\n``` + constructor(public readonly values: A[]) {} +// ^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericClass#``(). +// documentation ```ts\nconstructor(values: A[]): GenericClass\n``` +// ^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericClass#``().(values) +// documentation ```ts\n(property) values: A[]\n``` +// ^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#[A] + public map(fn: (a: A) => A): A[] { +// ^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericClass#map(). +// documentation ```ts\n(method) map(fn: (a: A) => A): A[]\n``` +// ^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericClass#map().(fn) +// documentation ```ts\n(parameter) fn: (a: A) => A\n``` +// ^ definition local 1 +// documentation ```ts\n(parameter) a: A\n``` +// ^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#[A] +// ^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#[A] +// ^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#[A] + return this.values.map(a => fn(a)) +// ^^^^^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#``().(values) +// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map(). +// ^ definition local 5 +// documentation ```ts\n(parameter) a: A\n``` +// ^^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericClass#map().(fn) +// ^ reference local 5 + } + } + + export interface Superinterface { +// ^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Superinterface# +// documentation ```ts\ninterface Superinterface\n``` + property: string +// ^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Superinterface#property. +// documentation ```ts\n(property) property: string\n``` + interfaceMethod(): string +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/Superinterface#interfaceMethod(). +// documentation ```ts\n(method) interfaceMethod() => string\n``` + } + export interface GenericInterface { +// ^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericInterface# +// documentation ```ts\ninterface GenericInterface\n``` +// ^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#[T] +// documentation ```ts\nT: T\n``` + property: T +// ^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#property. +// documentation ```ts\n(property) property: T\n``` +// ^ reference syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#[T] + interfaceMethod(): string +// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`reusable-types.ts`/GenericInterface#interfaceMethod(). +// documentation ```ts\n(method) interfaceMethod() => string\n``` + } + diff --git a/snapshots/output/syntax/src/structural-type.ts b/snapshots/output/syntax/src/structural-type.ts index b061b836..02256898 100644 --- a/snapshots/output/syntax/src/structural-type.ts +++ b/snapshots/output/syntax/src/structural-type.ts @@ -75,6 +75,5 @@ // ^^ definition syntax 1.0.0 src/`structural-type.ts`/fo. // documentation ```ts\nvar fo: OptionsFlags\n``` // ^^^^^^^^^^^^^^ reference syntax 1.0.0 src/`structural-type.ts`/FeatureOptions# -// ^^^^^^^^ definition syntax 1.0.0 src/`structural-type.ts`/darkMode0: -// documentation ```ts\n(property) darkMode: true\n``` +// ^^^^^^^^ reference syntax 1.0.0 src/`structural-type.ts`/FeatureFlags#typeLiteral13:darkMode. diff --git a/src/CommandLineOptions.ts b/src/CommandLineOptions.ts index e8b1a2f9..a028acdd 100644 --- a/src/CommandLineOptions.ts +++ b/src/CommandLineOptions.ts @@ -20,6 +20,7 @@ export interface MultiProjectOptions { cwd: string output: string indexedProjects: Set + shouldIndexFile?: (filename: string) => boolean } /** Configuration options to index a single TypeScript project. */ diff --git a/src/FileIndexer.ts b/src/FileIndexer.ts index 044e8c53..cee896ec 100644 --- a/src/FileIndexer.ts +++ b/src/FileIndexer.ts @@ -19,12 +19,26 @@ import { formatByteSizeAsHumanReadable } from './parseHumanByteSizeIntoNumber' import { Range } from './Range' import * as scip from './scip' import { ScipSymbol } from './ScipSymbol' +import { + TypeMapper, + getMappedType, + getParameterTypes, + getTypeMapper, + newTypeMap, + referenceTypeArguments, +} from './TypeMapper' import * as ts_inline from './TypeScriptInternal' +interface MappedType { + tpe: ts.Type + mapper?: TypeMapper +} + export class FileIndexer { private localCounter = new Counter() private propertyCounters: Map = new Map() private localSymbolTable: Map = new Map() + private assignedType: Map = new Map() private workingDirectoryRegExp: RegExp constructor( public readonly checker: ts.TypeChecker, @@ -39,10 +53,9 @@ export class FileIndexer { this.workingDirectoryRegExp = new RegExp(options.cwd, 'g') } public index(): void { - // Uncomment below if you want to skip certain files for local development. - // if (!this.sourceFile.fileName.includes('constructor')) { - // return - // } + if (this.options.shouldIndexFile?.(this.sourceFile.fileName) === false) { + return + } const byteSize = Buffer.from(this.sourceFile.getText()).length if ( @@ -85,6 +98,8 @@ export class FileIndexer { ) } private visit(node: ts.Node): void { + this.updateAssignedTypeMap(node) + if ( ts.isConstructorDeclaration(node) || ts.isIdentifier(node) || @@ -97,7 +112,121 @@ export class FileIndexer { } } - ts.forEachChild(node, node => this.visit(node)) + ts.forEachChild(node, child => this.visit(child)) + } + + // Given the type of `node`, assigns the types of its children. For example, + // when the node is a function declaration, we take the return type of the + // function and assign it to its body. + // + // The reason we do this is because the TypeScript compiler APIs don't seem to + // expose hooks to register when an object type satisfies a nominal type like + // in the example below: + // + // const x: NominalType = {property: 42} + // + // When asking for the type of the `{property: 42}` expression, we get the + // structal type `{property: number}` instead of `NominalType`. Without this + // manual tracking of types, "Go to definition" on `property` does not go + // anywhere because it's the property of a structural/anonymous type. With + // this manual tracking, we know that `property` goes to + // `NominalType.property`. + private updateAssignedTypeMap(node: ts.Node): void { + if (ts.isVariableDeclaration(node) && node.type && node.initializer) { + this.assignedType.set(node.initializer, { + tpe: this.checker.getTypeAtLocation(node.name), + }) + return + } + + if (ts.isBinaryExpression(node)) { + this.assignedType.set(node.right, { + tpe: this.checker.getTypeAtLocation(node.left), + }) + return + } + + if (ts.isFunctionLike(node) && node.type) { + const body = 'body' in node ? node.body : undefined + if (body) { + const functionType = this.checker.getTypeAtLocation(node) + const [callSignature] = functionType.getCallSignatures() + if (callSignature) { + this.assignedType.set(body, { tpe: callSignature.getReturnType() }) + } + return + } + } + + const callExpression = callLikeExpression(node) + if (callExpression) { + const signature = this.checker.getResolvedSignature(callExpression.node) + if (signature) { + const mapper = getTypeMapper(signature) + const parameterTypes = getParameterTypes(this.checker, signature) + for (const [index, arg] of callExpression.arguments.entries()) { + if (index < signature.getParameters().length) { + const parameterType = parameterTypes[index] + if (parameterType) { + this.assignedType.set(arg, { mapper, tpe: parameterType }) + } + } + } + } + } + + const mapped = this.assignedType.get(node) + if (!mapped) { + return + } + const tpe = getMappedType(this.checker, mapped.tpe, mapped.mapper) + const mapper = newTypeMap(this.checker, mapped.mapper, tpe) + + const hasStatements = onStatement(node, statement => { + this.assignedType.set(statement, mapped) + }) + if (hasStatements) { + return + } + + if (ts.isObjectLiteralExpression(node)) { + for (const element of node.properties) { + if (ts.isPropertyAssignment(element)) { + const property = tpe.getProperty(element.name.getText()) + if (property?.valueDeclaration) { + const propertyType = this.checker.getTypeAtLocation( + property.valueDeclaration + ) + const mappedPropertyType = getMappedType( + this.checker, + propertyType, + mapper + ) + + this.assignedType.set(element.initializer, { + ...mapped, + tpe: mappedPropertyType, + }) + } + } + } + } else if ( + ts.isArrayLiteralExpression(node) && + tpe.flags & ts.TypeFlags.Object + ) { + const [elementType] = referenceTypeArguments(tpe) + if (elementType) { + for (const element of node.elements) { + this.assignedType.set(element, { ...mapped, tpe: elementType }) + } + } + } else if (ts.isArrowFunction(node)) { + const [callSignature] = tpe.getCallSignatures() + if (callSignature) { + const returnType = this.checker.getReturnTypeOfSignature(callSignature) + this.assignedType.set(node.body, { ...mapped, tpe: returnType }) + } + } } // Get the ts.Symbol corresponding to the current node, potentially de-aliasing @@ -181,6 +310,17 @@ export class FileIndexer { ) } + // By default, property assignments on object literals use the meta + // descriptor and define a unique symbol. However, if it's not a meta descriptor + // then it becomes a reference to some other symbol. + // See https://github.com/sourcegraph/scip-typescript/issues/252 for more details. + const declarationRole = + role > 0 && + objectLiteralPropertyName(declaration) && + !scipSymbol.isMetaDescriptor() + ? 0 + : role + if (scipSymbol.isEmpty()) { // Skip empty symbols continue @@ -189,10 +329,10 @@ export class FileIndexer { new scip.scip.Occurrence({ range, symbol: scipSymbol.value, - symbol_roles: role, + symbol_roles: declarationRole, }) ) - if (isDefinitionNode) { + if (declarationRole > 0) { this.addSymbolInformation(node, sym, declaration, scipSymbol) this.handleShorthandPropertyDefinition(declaration, range) this.handleObjectBindingPattern(node, range) @@ -364,6 +504,7 @@ export class FileIndexer { } return relationships } + private scipSymbol(node: ts.Node): ScipSymbol { const fromCache: ScipSymbol | undefined = this.globalSymbolTable.get(node) || this.localSymbolTable.get(node) @@ -380,6 +521,24 @@ export class FileIndexer { } return this.cached(node, package_) } + + const propertyName = objectLiteralPropertyName(node) + if (propertyName) { + const mappedType = this.assignedType.get(node.parent) + if (mappedType) { + const tpe = getMappedType( + this.checker, + mappedType.tpe, + mappedType.mapper + ) + const property = tpe?.getProperty(propertyName.getText()) + const [declaration] = property?.declarations || [] + if (declaration && declaration !== node) { + return this.cached(node, this.scipSymbol(declaration)) + } + } + } + if ( ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node) @@ -626,15 +785,7 @@ export class FileIndexer { ) { onAncestor(declaration) } - if (ts.isObjectLiteralExpression(declaration)) { - const tpe = this.inferredTypeOfObjectLiteral( - declaration.parent, - declaration - ) - for (const symbolDeclaration of tpe.symbol?.declarations || []) { - loop(symbolDeclaration) - } - } else if ( + if ( ts.isClassLike(declaration) || ts.isInterfaceDeclaration(declaration) ) { @@ -652,60 +803,6 @@ export class FileIndexer { } loop(node) } - - // Returns the "inferred" type of the provided object literal, where - // "inferred" is loosely defined as the type that is expected in the position - // where the object literal appears. For example, the object literal in - // `const x: SomeInterface = {y: 42}` has the inferred type `SomeInterface` - // even if `this.checker.getTypeAtLocation({y: 42})` does not return - // `SomeInterface`. The object literal could satisfy many types, but in this - // particular location must only satisfy `SomeInterface`. - private inferredTypeOfObjectLiteral( - node: ts.Node, - literal: ts.ObjectLiteralExpression - ): ts.Type { - 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.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)) { - // Example: return the type of the second parameter of `someMethod` from - // the expression `someMethod(someParameter, {y: 42})`. - 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) - } - } - } - } - - return this.checker.getTypeAtLocation(literal) - } } function isAnonymousContainerOfSymbols(node: ts.Node): boolean { @@ -839,3 +936,105 @@ function isDefinition(node: ts.Node): boolean { declarationName(node.parent) === node || ts.isConstructorDeclaration(node) ) } + +function onStatements( + statements: ts.NodeArray, + handler: (statement: ts.Node) => void +): void { + for (const statement of statements) { + handler(statement) + } +} + +function onStatement( + node: ts.Node, + handler: (statement: ts.Node) => void +): boolean { + if (ts.isBlock(node)) { + onStatements(node.statements, handler) + return true + } + if (ts.isTryStatement(node)) { + handler(node.tryBlock) + if (node.finallyBlock) { + handler(node.finallyBlock) + } + return true + } + if (ts.isCatchClause(node)) { + handler(node.block) + return true + } + if ( + ts.isDoStatement(node) || + ts.isWhileStatement(node) || + ts.isForStatement(node) || + ts.isForInStatement(node) || + ts.isForOfStatement(node) + ) { + handler(node.statement) + return true + } + if (ts.isIfStatement(node)) { + handler(node.thenStatement) + if (node.elseStatement) { + handler(node.elseStatement) + } + return true + } + if (ts.isReturnStatement(node) || ts.isParenthesizedExpression(node)) { + if (node.expression) { + handler(node.expression) + } + } + if (ts.isSwitchStatement(node)) { + for (const kase of node.caseBlock.clauses) { + if (ts.isCaseClause(kase)) { + handler(kase.expression) + } + if (ts.isDefaultClause(kase)) { + onStatements(kase.statements, handler) + } + } + return true + } + + return false +} + +function objectLiteralPropertyName(node: ts.Node): ts.PropertyName | undefined { + if (!node.parent) { + return undefined + } + if (!ts.isObjectLiteralExpression(node.parent)) { + return undefined + } + if ( + ts.isMethodDeclaration(node) || + ts.isPropertyAssignment(node) || + ts.isShorthandPropertyAssignment(node) + ) { + return node.name + } + return undefined +} + +interface CallLikeExpressionWithArguments { + node: ts.CallLikeExpression + arguments: ts.NodeArray +} + +function callLikeExpression( + node: ts.Node +): CallLikeExpressionWithArguments | undefined { + if (ts.isCallExpression(node)) { + return { node, arguments: node.arguments } + } + if (ts.isNewExpression(node)) { + return { + node, + arguments: node.arguments || ts.factory.createNodeArray(), + } + } + return undefined +} diff --git a/src/ScipSymbol.ts b/src/ScipSymbol.ts index 78531c5b..1358cc38 100644 --- a/src/ScipSymbol.ts +++ b/src/ScipSymbol.ts @@ -12,6 +12,10 @@ export class ScipSymbol { return this.value.startsWith('local ') } + public isMetaDescriptor(): boolean { + return this.value.endsWith(':') + } + public static local(counter: number): ScipSymbol { return new ScipSymbol(`local ${counter}`) } diff --git a/src/TypeMapper.ts b/src/TypeMapper.ts new file mode 100644 index 00000000..7cc0543b --- /dev/null +++ b/src/TypeMapper.ts @@ -0,0 +1,215 @@ +// This file is adapted from code inside TypeScript internals. The goal of this +// file is to be access the `TypeMapper`, which is an internal data structure +// that the typechecker uses to map generic type variables like `T` in `T[]` +// into concrete types like `number[]`. +import * as ts from 'typescript' + +export const enum TypeMapKind { + Simple, + Array, + Deferred, + Function, + Composite, + Merged, +} + +export type TypeMapper = + | { kind: TypeMapKind.Simple; source: ts.Type; target: ts.Type } + | { + kind: TypeMapKind.Array + sources: readonly ts.Type[] + targets: readonly ts.Type[] | undefined + } + | { + kind: TypeMapKind.Deferred + sources: readonly ts.Type[] + targets: (() => ts.Type)[] + } + | { + kind: TypeMapKind.Function + func: (t: ts.Type) => ts.Type + debugInfo?: () => string + } + | { + kind: TypeMapKind.Composite | TypeMapKind.Merged + mapper1: TypeMapper + mapper2: TypeMapper + } + +export function typeMapperToString( + checker: ts.TypeChecker, + mapper: TypeMapper | undefined +): string { + if (!mapper) { + return 'undefined' + } + switch (mapper.kind) { + case TypeMapKind.Simple: + return JSON.stringify({ + kind: mapper.kind, + source: checker.typeToString(mapper.source), + target: checker.typeToString(mapper.target), + }) + case TypeMapKind.Array: + return JSON.stringify({ + kind: mapper.kind, + sources: mapper.sources.map(tpe => checker.typeToString(tpe)), + targets: (mapper.targets || []).map(tpe => checker.typeToString(tpe)), + }) + case TypeMapKind.Composite: + return JSON.stringify({ + kind: mapper.kind, + mapper1: typeMapperToString(checker, mapper.mapper1), + mapper2: typeMapperToString(checker, mapper.mapper2), + }) + default: + return JSON.stringify(mapper) + } +} + +export function getMappedType( + checker: ts.TypeChecker, + type: ts.Type, + mapper: TypeMapper | undefined +): ts.Type { + if (!mapper) { + return type + } + switch (mapper.kind) { + case TypeMapKind.Simple: + return type.symbol === mapper.source.symbol ? mapper.target : type + case TypeMapKind.Array: { + const sources = mapper.sources + const targets = mapper.targets + for (let index = 0; index < sources.length; index++) { + if (type.symbol === sources[index].symbol) { + return targets + ? targets[index] + : checker.getTypeFromTypeNode( + ts.factory.createTypeLiteralNode(undefined) + ) + } + } + return type + } + case TypeMapKind.Deferred: { + const sources = mapper.sources + const targets = mapper.targets + for (let index = 0; index < sources.length; index++) { + if (type.symbol === sources[index].symbol) { + return targets[index]() + } + } + return type + } + case TypeMapKind.Function: + return mapper.func(type) + case TypeMapKind.Composite: + case TypeMapKind.Merged: + return getMappedType( + checker, + getMappedType(checker, type, mapper.mapper1), + mapper.mapper2 + ) + } +} + +export function getTypeMapper(signature: ts.Signature): TypeMapper | undefined { + return (signature as any)?.mapper as TypeMapper | undefined +} + +export function getParameterTypes( + checker: ts.TypeChecker, + signature: ts.Signature +): (ts.Type | null)[] { + const mapper = getTypeMapper(signature) + if (!mapper) { + return signature.parameters.flatMap(parameter => + parameter.valueDeclaration + ? [checker.getTypeAtLocation(parameter.valueDeclaration)] + : [] + ) + } + return signature.parameters.map(parameter => + parameter.valueDeclaration + ? getMappedType( + checker, + checker.getTypeAtLocation(parameter.valueDeclaration), + mapper + ) + : null + ) +} + +// In some cases, `tpe.symbol.valueDeclaration` is undefined but we can recover +// the correct value declaration by finding the parent of a property. This may +// be caused by a bug in the tsc API where `valueDeclaration` is not correctly +// forwarded for mapped types. Either way, this function fixes an important test +// case in the snapshots. This approach does not work for alias types where the +// property is not a direct child of the alias, but we guard against this case +// by checking that the symbol of the value declaration is the same as the +// symbol of the type. +function correctedValueDeclaration(tpe: ts.Type): ts.Node | undefined { + if (tpe.symbol?.valueDeclaration) { + return tpe.symbol.valueDeclaration + } + for (const property of tpe.getProperties()) { + const parent = property?.valueDeclaration?.parent + if (parent !== undefined) { + return parent + } + } + return undefined +} + +export function newTypeMap( + checker: ts.TypeChecker, + old: TypeMapper | undefined, + tpe: ts.Type +): TypeMapper | undefined { + const typeReference = asTypeReference(tpe) + if (typeReference?.typeArguments && typeReference.typeArguments.length > 0) { + const valueDeclaration = correctedValueDeclaration(tpe) + if (valueDeclaration) { + const valueDeclarationType = checker.getTypeAtLocation(valueDeclaration) + if (valueDeclarationType.symbol !== tpe.symbol) { + return old + } + const sources = asTypeReference(valueDeclarationType)?.typeArguments || [] + const targets = typeReference.typeArguments.map( + typeArgument => typeArgument + ) + if (targets.length !== sources?.length) { + return old + } + const newMapper: TypeMapper = { + kind: TypeMapKind.Array, + sources, + targets, + } + if (old === undefined) { + return newMapper + } + return { + kind: TypeMapKind.Composite, + mapper1: old, + mapper2: newMapper, + } + } + } + return old +} + +export function asTypeReference(tpe: ts.Type): ts.TypeReference | undefined { + if (tpe.flags & ts.TypeFlags.Object) { + const objectType = tpe as ts.ObjectType + if (objectType.objectFlags & ts.ObjectFlags.Reference) { + return objectType as ts.TypeReference + } + } + return undefined +} + +export function referenceTypeArguments(tpe: ts.Type): readonly ts.Type[] { + return asTypeReference(tpe)?.typeArguments || [] +} diff --git a/src/main.test.ts b/src/main.test.ts index 17b26125..cf7c0d63 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -15,6 +15,9 @@ function isUpdateSnapshot(): boolean { return process.argv.includes('--update-snapshots') } +const onlyFile = process.env.ONLY +const onlyAbsoluteFilename = onlyFile ? join(process.cwd(), onlyFile) : '' + const snapshotNodeModules = join(process.cwd(), 'snapshots', 'node_modules') if (!fs.existsSync(snapshotNodeModules)) { throw new Error( @@ -34,16 +37,12 @@ interface PackageJson { packageManager?: string } for (const snapshotDirectory of snapshotDirectories) { - // Uncomment below if you want to skip certain tests for local development. - // if (!snapshotDirectory.includes('syntax')) { - // continue - // } const inputRoot = join(inputDirectory, snapshotDirectory) const outputRoot = join(outputDirectory, snapshotDirectory) if (!fs.statSync(inputRoot).isDirectory()) { continue } - test(snapshotDirectory, () => { + const testCallback = () => { const packageJsonPath = path.join(inputRoot, 'package.json') const packageJson = JSON.parse( fs.readFileSync(packageJsonPath).toString() @@ -61,6 +60,12 @@ for (const snapshotDirectory of snapshotDirectories) { progressBar: false, indexedProjects: new Set(), globalCaches: true, + shouldIndexFile: filename => { + if (onlyFile) { + return filename === onlyAbsoluteFilename + } + return true + }, }) if (inferTsconfig) { fs.rmSync(tsconfigJsonPath) @@ -106,7 +111,12 @@ for (const snapshotDirectory of snapshotDirectories) { throw new Error(patch) } } - }) + } + if (onlyFile && !onlyAbsoluteFilename.startsWith(inputRoot)) { + test.skip(snapshotDirectory, testCallback) + } else { + test(snapshotDirectory, testCallback) + } } test.run()