From d27b72a68f04d6af72acd34520ff0d3c0a4a661b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:20:26 +0000 Subject: [PATCH 1/2] Initial plan From cb2513cbec121631638c7041448273029e1b0d54 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Aug 2026 17:00:36 +0000 Subject: [PATCH 2/2] Fix invalid JSDoc link name access Co-authored-by: andrewbranch <3277153+andrewbranch@users.noreply.github.com> --- .../typescript/src/api/node/node.generated.ts | 1 + packages/typescript/test/sync/ast.test.ts | 25 +++++++++++++++++++ tools/scripts/tsc/generate-encoder.ts | 1 + 3 files changed, 27 insertions(+) diff --git a/packages/typescript/src/api/node/node.generated.ts b/packages/typescript/src/api/node/node.generated.ts index 035c8d308e737..a601319e3d9b0 100644 --- a/packages/typescript/src/api/node/node.generated.ts +++ b/packages/typescript/src/api/node/node.generated.ts @@ -369,6 +369,7 @@ export class RemoteNode extends RemoteNodeBase implements Node { } private getChildAtOrder(order: number): RemoteNode | RemoteNodeList | undefined { + if (!this.hasChildren()) return undefined; const mask = this.childMask; if (!(mask & (1 << order))) { // Property is not present diff --git a/packages/typescript/test/sync/ast.test.ts b/packages/typescript/test/sync/ast.test.ts index 7754f97972a2c..254e8d6c63d31 100644 --- a/packages/typescript/test/sync/ast.test.ts +++ b/packages/typescript/test/sync/ast.test.ts @@ -1,6 +1,7 @@ import type { ExpressionStatement, Identifier, + JSDoc, Node, NodeArray, SourceFile, @@ -12,6 +13,7 @@ import { isClassDeclaration, isImportDeclaration, isInterfaceDeclaration, + isJSDocLink, isNamedImports, isValidTypeOnlyAliasUseSite, SyntaxKind, @@ -579,6 +581,29 @@ function getRemoteSourceFile(api: API, configPath: string, filePath: string) { } describe("RemoteNode + cloneNode", () => { + test("does not read a sibling as an invalid JSDoc link name", () => { + const api = spawnAPI({ + "/tsconfig.json": "{}", + "/src/index.ts": `/** + * {@link #toggled} property + */ +export const x = 1;`, + }); + try { + const sf = getRemoteSourceFile(api, "/tsconfig.json", "/src/index.ts"); + const jsDoc = sf.statements[0].jsDoc?.[0] as JSDoc | undefined; + assert.ok(jsDoc?.kind === SyntaxKind.JSDoc); + const comment = jsDoc.comment; + assert.ok(typeof comment !== "string"); + const link = comment?.[1]; + assert.ok(link && isJSDocLink(link)); + assert.strictEqual(link.name, undefined); + } + finally { + api.close(); + } + }); + test("uses distinct nodes for expression and type heritage", () => { const api = spawnAPI({ "/tsconfig.json": "{}", diff --git a/tools/scripts/tsc/generate-encoder.ts b/tools/scripts/tsc/generate-encoder.ts index fc1a67022a39d..239ab7021b193 100644 --- a/tools/scripts/tsc/generate-encoder.ts +++ b/tools/scripts/tsc/generate-encoder.ts @@ -1806,6 +1806,7 @@ function emitRemoteNodeClassOpen(w: CodeWriter) { w.write(` }`); w.write(``); w.write(` private getChildAtOrder(order: number): RemoteNode | RemoteNodeList | undefined {`); + w.write(` if (!this.hasChildren()) return undefined;`); w.write(` const mask = this.childMask;`); w.write(` if (!(mask & (1 << order))) {`); w.write(` // Property is not present`);