Skip to content

Commit c4cab96

Browse files
committed
Connect prototype members across files
Amp-Thread-ID: https://ampcode.com/threads/T-01a029e2-5095-710a-9cce-0c6d8645c173
1 parent 8b501f5 commit c4cab96

7 files changed

Lines changed: 90 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "prototype-members",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module"
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function Connection() {}
2+
3+
Connection.prototype = {
4+
getSchemaVersion() {
5+
return 0
6+
},
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** @import { Connection } from './connection.mjs' */
2+
3+
/** @param {Connection} connection */
4+
export function schemaVersion(connection) {
5+
return connection.getSchemaVersion()
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true,
4+
"checkJs": true,
5+
"module": "NodeNext",
6+
"moduleResolution": "NodeNext",
7+
"noEmit": true,
8+
"target": "ES2022"
9+
},
10+
"include": ["src/**/*.mjs"]
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// language JavaScript
2+
// < definition prototype-members 1.0.0 src/`connection.mjs`/
3+
4+
export function Connection() {}
5+
// ^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().
6+
7+
Connection.prototype = {
8+
//^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().
9+
//^^^^^^^^^ reference local 3
10+
// ^^^^^^^^^ reference local 2
11+
getSchemaVersion() {
12+
//^^^^^^^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
13+
return 0
14+
},
15+
}
16+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// language JavaScript
2+
// < definition prototype-members 1.0.0 src/`use.mjs`/
3+
4+
/** @import { Connection } from './connection.mjs' */
5+
6+
/** @param {Connection} connection */
7+
export function schemaVersion(connection) {
8+
// ^^^^^^^^^^^^^ definition prototype-members 1.0.0 src/`use.mjs`/schemaVersion().
9+
// ^^^^^^^^^^ definition prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
10+
return connection.getSchemaVersion()
11+
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
12+
// ^^^^^^^^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
13+
}
14+

src/FileIndexer.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,28 @@ export class FileIndexer {
424424
}
425425
return relationships
426426
}
427+
428+
private prototypeAssignmentOwner(node: ts.Node): ts.Declaration | undefined {
429+
if (!ts.isObjectLiteralExpression(node)) {
430+
return
431+
}
432+
const assignment = node.parent
433+
if (
434+
!ts.isBinaryExpression(assignment) ||
435+
assignment.operatorToken.kind !== ts.SyntaxKind.EqualsToken ||
436+
assignment.right !== node ||
437+
!ts.isPropertyAccessExpression(assignment.left) ||
438+
assignment.left.name.text !== 'prototype'
439+
) {
440+
return
441+
}
442+
let symbol = this.checker.getSymbolAtLocation(assignment.left.expression)
443+
if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
444+
symbol = this.checker.getAliasedSymbol(symbol)
445+
}
446+
return symbol?.valueDeclaration ?? symbol?.declarations?.[0]
447+
}
448+
427449
private scipSymbol(node: ts.Node): ScipSymbol {
428450
const fromCache: ScipSymbol | undefined =
429451
this.globalSymbolTable.get(node) || this.localSymbolTable.get(node)
@@ -490,6 +512,14 @@ export class FileIndexer {
490512
}
491513
}
492514

515+
const prototypeOwner = this.prototypeAssignmentOwner(node)
516+
if (prototypeOwner) {
517+
// Methods in `Constructor.prototype = { ... }` belong to the constructor,
518+
// not to an anonymous object local to this file. Giving that object the
519+
// constructor's identity makes its members stable across files.
520+
return this.cached(node, this.scipSymbol(prototypeOwner))
521+
}
522+
493523
const owner = this.scipSymbol(node.parent)
494524
if (owner.isEmpty() || owner.isLocal()) {
495525
return this.newLocalSymbol(node)

0 commit comments

Comments
 (0)