Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions snapshots/input/prototype-members/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "prototype-members",
"version": "1.0.0",
"private": true,
"type": "module"
}
11 changes: 11 additions & 0 deletions snapshots/input/prototype-members/src/connection.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export function Connection() {}

Connection.prototype = {
getSchemaVersion() {
return 0
},
getVersion: function () {
return 1
},
version: 1,
}
10 changes: 10 additions & 0 deletions snapshots/input/prototype-members/src/use.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @import { Connection } from './connection.mjs' */

/** @param {Connection} connection */
export function schemaVersion(connection) {
return [
connection.getSchemaVersion(),
connection.getVersion(),
connection.version,
]
}
11 changes: 11 additions & 0 deletions snapshots/input/prototype-members/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"target": "ES2022"
},
"include": ["src/**/*.mjs"]
}
21 changes: 21 additions & 0 deletions snapshots/output/prototype-members/src/connection.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// language JavaScript
// < definition prototype-members 1.0.0 src/`connection.mjs`/

export function Connection() {}
// ^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().

Connection.prototype = {
//^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().
// ^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().
getSchemaVersion() {
//^^^^^^^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
return 0
},
getVersion: function () {
//^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().getVersion.
return 1
},
version: 1,
//^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().version.
}

22 changes: 22 additions & 0 deletions snapshots/output/prototype-members/src/use.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// language JavaScript
// < definition prototype-members 1.0.0 src/`use.mjs`/

/** @import { Connection } from './connection.mjs' */

/** @param {Connection} connection */
export function schemaVersion(connection) {
// ^^^^^^^^^^^^^ definition prototype-members 1.0.0 src/`use.mjs`/schemaVersion().
// ^^^^^^^^^^ definition prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
return [
connection.getSchemaVersion(),
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
// ^^^^^^^^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
connection.getVersion(),
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().getVersion.
connection.version,
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
// ^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().version.
]
}

46 changes: 46 additions & 0 deletions src/FileIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,38 @@ export class FileIndexer {
}
return relationships
}

private prototypeAssignmentOwner(node: ts.Node): ts.Declaration | undefined {
const assignment = ts.isBinaryExpression(node)
? node
: ts.isObjectLiteralExpression(node)
? node.parent
: ts.isPropertyAccessExpression(node)
? node.parent
: ts.isIdentifier(node) && ts.isPropertyAccessExpression(node.parent)
? node.parent.parent
: (ts.isPropertyAssignment(node) ||
ts.isShorthandPropertyAssignment(node)) &&
ts.isObjectLiteralExpression(node.parent)
? node.parent.parent
: undefined
if (
!assignment ||
!ts.isBinaryExpression(assignment) ||
assignment.operatorToken.kind !== ts.SyntaxKind.EqualsToken ||
!ts.isObjectLiteralExpression(assignment.right) ||
!ts.isPropertyAccessExpression(assignment.left) ||
assignment.left.name.text !== 'prototype'
) {
return
}
let symbol = this.checker.getSymbolAtLocation(assignment.left.expression)
if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
symbol = this.checker.getAliasedSymbol(symbol)
}
return symbol?.valueDeclaration ?? symbol?.declarations?.[0]
}

private scipSymbol(node: ts.Node): ScipSymbol {
const fromCache: ScipSymbol | undefined =
this.globalSymbolTable.get(node) || this.localSymbolTable.get(node)
Expand All @@ -440,6 +472,20 @@ export class FileIndexer {
}
return this.cached(node, package_)
}

const prototypeOwner = this.prototypeAssignmentOwner(node)
if (prototypeOwner) {
// Declarations attached to the assignment and its object literal belong
// to the constructor. Property assignments need their own stable member
// descriptor instead of the counter-based object-property fallback.
const owner = this.scipSymbol(prototypeOwner)
const symbol =
ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)
? ScipSymbol.global(owner, termDescriptor(node.name.getText()))
: owner
return this.cached(node, symbol)
}

if (
ts.isPropertyAssignment(node) ||
ts.isShorthandPropertyAssignment(node)
Expand Down
Loading