Skip to content

Commit b681451

Browse files
committed
Merge branch 'main' into guyllian.gomez/yarn-pnp-support
2 parents 5588157 + 49e5285 commit b681451

File tree

946 files changed

+11911
-29852
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

946 files changed

+11911
-29852
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
name: Strada to Corsa Port Expert
3+
description: A Go and TypeScript expert who can easily figure out how to port PRs from one language to another
4+
---
5+
6+
This repository is a port of `microsoft/TypeScript` from TypeScript to Go. Since the port began, the following pull request was applied to microsoft/TypeScript. An equivalent change now needs to be applied here. The user will give you a link to the PR and you will need to try to port it to this repo.
7+
8+
Instructions
9+
- Use `curl` to fetch e.g. `https://api.github.com/repos/microsoft/typescript/pulls/59767` to view the merge commit SHA
10+
- Then use `curl` to fetch e.g. `https://github.com/microsoft/TypeScript/commit/bd3d70058c30253209199cc9dfeb85e72330d79b.patch` to download the diff patch
11+
- Use Playwright MCP if you have other information from github you need, since you won't have MCP access to the TypeScript repo
12+
- Apply the edits made in that PR to this codebase, translating them from TypeScript to Go.
13+
- The change may or may not be applicable. It may have already been ported. Do not make any significant changes outside the scope of the diff. If the change cannot be applied without significant out-of-scope changes, explain why and stop working.
14+
- Tip: search for functions and identifiers from the diff to find the right location to apply edits. Some files in microsoft/TypeScript have been split into multiple.
15+
- Tip: some changes have already been ported, like changes to diagnostic message text. Tests do not need to be ported as they are imported from the submodule.
16+
- Check that the code builds by running npx hereby build in the terminal.
17+
- Run tests. It is expected that tests will fail due to baseline changes.
18+
- Run `npx hereby test` in a terminal. They should fail with messages about baseline changes.
19+
- Tip: to run a single baseline test from the submodule, run go test ./internal/testrunner -run '^TestSubmodule/NAME_OF_TEST_FILE'
20+
- Run npx hereby baseline-accept to adopt the baseline changes.
21+
- Run git diff 'testdata/**/*.diff'. If your change is correct, these diff files will be reduced or completely deleted.
22+
- Iterate until you are satisfied with your change. Commit everything, including the baseline changes in testdata, and open a PR.

.github/copilot-instructions.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ go test -run='TestLocal/<test name>' ./internal/testrunner # For new "local
2424

2525
Always make sure code is formatted, linted, and tested before sending a pull request.
2626

27+
<critical>
28+
YOU MUST RUN THESE COMMANDS AT THE END OF YOUR SESSION!
29+
IF THESE COMMANDS FAIL, CI WILL FAIL, AND YOUR PR WILL BE REJECTED OUT OF HAND.
30+
FIXING ERRORS FROM THESE COMMANDS IS YOUR HIGHEST PRIORITY.
31+
ENSURE YOU DO THE RIGHT THINGS TO MAKE THEM PASS.
32+
```sh
33+
npx hereby build # Build the project
34+
npx hereby test # Run tests
35+
npx hereby lint # Run linters
36+
npx hereby format # Format the code
37+
```
38+
</critical>
39+
2740
## Compiler Features, Fixes, and Tests
2841

2942
When fixing a bug or implementing a new feature, at least one minimal test case should always be added in advance to verify the fix.
@@ -96,4 +109,4 @@ The TypeScript submodule serves as the reference implementation for behavior and
96109
# Other Instructions
97110

98111
- Do not add or change existing dependencies unless asked to.
99-
112+
- Do not remove any debug assertions or panic calls. Existing assertions are never too strict or incorrect.

Herebyfile.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,7 @@ export const buildNativePreviewPackages = task({
11271127
const readme = [
11281128
`# \`${npmPackageName}\``,
11291129
"",
1130-
`This package provides ${nodeOs}-${nodeArch} support for [${packageJson.name}](https://www.npmjs.com/package/${packageJson.name}).`,
1130+
`This package provides ${nodeOs}-${nodeArch} support for [${mainNativePreviewPackage.npmPackageName}](https://www.npmjs.com/package/${mainNativePreviewPackage.npmPackageName}).`,
11311131
];
11321132

11331133
fs.promises.writeFile(path.join(npmDir, "README.md"), readme.join("\n") + "\n");

_extension/src/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async function updateUseTsgoSetting(enable: boolean): Promise<void> {
5050
useTsgo.globalValue !== undefined ? vscode.ConfigurationTarget.Global : undefined;
5151
}
5252
// Update the setting and restart the extension host (needed to change the state of the built-in TS extension)
53-
await tsConfig.update("experimental.useTsgo", enable, target);
53+
await tsConfig.update("experimental.useTsgo", enable, target ?? vscode.ConfigurationTarget.Global);
5454
await restartExtHostOnChangeIfNeeded();
5555
}
5656

internal/ast/utilities.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ func IsBindableStaticElementAccessExpression(node *Node, excludeThisKeyword bool
13401340
return IsLiteralLikeElementAccess(node) &&
13411341
((!excludeThisKeyword && node.Expression().Kind == KindThisKeyword) ||
13421342
IsEntityNameExpression(node.Expression()) ||
1343-
IsBindableStaticAccessExpression(node.Expression() /*excludeThisKeyword*/, true))
1343+
IsBindableStaticAccessExpression(node.Expression(), true /*excludeThisKeyword*/))
13441344
}
13451345

13461346
func IsLiteralLikeElementAccess(node *Node) bool {
@@ -2641,7 +2641,7 @@ func GetNodeAtPosition(file *SourceFile, position int, includeJSDoc bool) *Node
26412641
}
26422642
if child == nil {
26432643
current.ForEachChild(func(node *Node) bool {
2644-
if nodeContainsPosition(node, position) {
2644+
if nodeContainsPosition(node, position) && node.Kind != KindJSExportAssignment && node.Kind != KindCommonJSExport {
26452645
child = node
26462646
return true
26472647
}
@@ -2822,10 +2822,6 @@ func IsModuleExportsAccessExpression(node *Node) bool {
28222822
return false
28232823
}
28242824

2825-
func isLiteralLikeElementAccess(node *Node) bool {
2826-
return node.Kind == KindElementAccessExpression && IsStringOrNumericLiteralLike(node.AsElementAccessExpression().ArgumentExpression)
2827-
}
2828-
28292825
func IsCheckJSEnabledForFile(sourceFile *SourceFile, compilerOptions *core.CompilerOptions) bool {
28302826
if sourceFile.CheckJsDirective != nil {
28312827
return sourceFile.CheckJsDirective.Enabled
@@ -3866,6 +3862,31 @@ func IsImportOrImportEqualsDeclaration(node *Node) bool {
38663862
return IsImportDeclaration(node) || IsImportEqualsDeclaration(node)
38673863
}
38683864

3865+
func IsKeyword(token Kind) bool {
3866+
return KindFirstKeyword <= token && token <= KindLastKeyword
3867+
}
3868+
3869+
func IsNonContextualKeyword(token Kind) bool {
3870+
return IsKeyword(token) && !IsContextualKeyword(token)
3871+
}
3872+
3873+
func HasModifier(node *Node, flags ModifierFlags) bool {
3874+
return node.ModifierFlags()&flags != 0
3875+
}
3876+
3877+
func IsExpandoInitializer(initializer *Node) bool {
3878+
if initializer == nil {
3879+
return false
3880+
}
3881+
if IsFunctionExpressionOrArrowFunction(initializer) {
3882+
return true
3883+
}
3884+
if IsInJSFile(initializer) {
3885+
return IsClassExpression(initializer) || (IsObjectLiteralExpression(initializer) && len(initializer.AsObjectLiteralExpression().Properties.Nodes) == 0)
3886+
}
3887+
return false
3888+
}
3889+
38693890
func GetContainingFunction(node *Node) *Node {
38703891
return FindAncestor(node.Parent, IsFunctionLike)
38713892
}

internal/astnav/tokens.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ func getTokenAtPosition(
6565
// `left` tracks the lower boundary of the node/token that could be returned,
6666
// and is eventually the scanner's start position, if the scanner is used.
6767
left := 0
68+
// `allowReparsed` is set when we're navigating inside an AsExpression or
69+
// SatisfiesExpression, which allows visiting their reparsed children to reach
70+
// the actual identifier from JSDoc type assertions.
71+
allowReparsed := false
6872

6973
testNode := func(node *ast.Node) int {
7074
if node.Kind != ast.KindEndOfFile && node.End() == position && includePrecedingTokenAtEndPosition != nil {
@@ -74,7 +78,8 @@ func getTokenAtPosition(
7478
if node.End() < position || node.Kind != ast.KindEndOfFile && node.End() == position {
7579
return -1
7680
}
77-
if getPosition(node, sourceFile, allowPositionInLeadingTrivia) > position {
81+
nodePos := getPosition(node, sourceFile, allowPositionInLeadingTrivia)
82+
if nodePos > position {
7883
return 1
7984
}
8085
return 0
@@ -86,18 +91,29 @@ func getTokenAtPosition(
8691
visitNode := func(node *ast.Node, _ *ast.NodeVisitor) *ast.Node {
8792
// We can't abort visiting children, so once a match is found, we set `next`
8893
// and do nothing on subsequent visits.
89-
if node != nil && node.Flags&ast.NodeFlagsReparsed == 0 && next == nil {
90-
switch testNode(node) {
91-
case -1:
92-
if !ast.IsJSDocKind(node.Kind) {
93-
// We can't move the left boundary into or beyond JSDoc,
94-
// because we may end up returning the token after this JSDoc,
95-
// constructing it with the scanner, and we need to include
96-
// all its leading trivia in its position.
97-
left = node.End()
94+
if node != nil && next == nil {
95+
// Skip reparsed nodes unless:
96+
// 1. The node itself is AsExpression or SatisfiesExpression, OR
97+
// 2. We're already inside an AsExpression or SatisfiesExpression (allowReparsed=true)
98+
// These are special cases where reparsed nodes from JSDoc type assertions
99+
// should still be navigable to reach identifiers.
100+
isSpecialReparsed := node.Flags&ast.NodeFlagsReparsed != 0 &&
101+
(node.Kind == ast.KindAsExpression || node.Kind == ast.KindSatisfiesExpression)
102+
103+
if node.Flags&ast.NodeFlagsReparsed == 0 || isSpecialReparsed || allowReparsed {
104+
result := testNode(node)
105+
switch result {
106+
case -1:
107+
if !ast.IsJSDocKind(node.Kind) {
108+
// We can't move the left boundary into or beyond JSDoc,
109+
// because we may end up returning the token after this JSDoc,
110+
// constructing it with the scanner, and we need to include
111+
// all its leading trivia in its position.
112+
left = node.End()
113+
}
114+
case 0:
115+
next = node
98116
}
99-
case 0:
100-
next = node
101117
}
102118
}
103119
return node
@@ -194,6 +210,11 @@ func getTokenAtPosition(
194210
current = next
195211
left = current.Pos()
196212
next = nil
213+
// When navigating into AsExpression or SatisfiesExpression, allow visiting
214+
// their reparsed children to reach identifiers from JSDoc type assertions.
215+
if current.Kind == ast.KindAsExpression || current.Kind == ast.KindSatisfiesExpression {
216+
allowReparsed = true
217+
}
197218
}
198219
}
199220

internal/astnav/tokens_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,52 @@ func TestGetTokenAtPosition(t *testing.T) {
4343
)
4444
})
4545

46+
t.Run("JSDoc type assertion", func(t *testing.T) {
47+
t.Parallel()
48+
fileText := `function foo(x) {
49+
const s = /**@type {string}*/(x)
50+
}`
51+
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
52+
FileName: "/test.js",
53+
Path: "/test.js",
54+
}, fileText, core.ScriptKindJS)
55+
56+
// Position of 'x' inside the parenthesized expression (position 52)
57+
position := 52
58+
59+
// This should not panic - it previously panicked with:
60+
// "did not expect KindParenthesizedExpression to have KindIdentifier in its trivia"
61+
token := astnav.GetTouchingPropertyName(file, position)
62+
if token == nil {
63+
t.Fatal("Expected to get a token, got nil")
64+
}
65+
66+
// The function may return either the identifier itself or the containing
67+
// parenthesized expression, depending on how the AST is structured
68+
if token.Kind != ast.KindIdentifier && token.Kind != ast.KindParenthesizedExpression {
69+
t.Errorf("Expected identifier or parenthesized expression, got %s", token.Kind)
70+
}
71+
})
72+
73+
t.Run("JSDoc type assertion with comment", func(t *testing.T) {
74+
t.Parallel()
75+
// Exact code from the issue report
76+
fileText := `function foo(x) {
77+
const s = /**@type {string}*/(x) // Go-to-definition on x causes panic
78+
}`
79+
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
80+
FileName: "/test.js",
81+
Path: "/test.js",
82+
}, fileText, core.ScriptKindJS)
83+
84+
// Find position of 'x' in the type assertion
85+
xPos := 52 // Position of 'x' in (x)
86+
87+
// This should not panic
88+
token := astnav.GetTouchingPropertyName(file, xPos)
89+
assert.Assert(t, token != nil, "Expected to get a token")
90+
})
91+
4692
t.Run("pointer equality", func(t *testing.T) {
4793
t.Parallel()
4894
fileText := `

internal/binder/binder.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,30 +1018,18 @@ func getInitializerSymbol(symbol *ast.Symbol) *ast.Symbol {
10181018
case ast.IsVariableDeclaration(declaration) &&
10191019
(declaration.Parent.Flags&ast.NodeFlagsConst != 0 || ast.IsInJSFile(declaration)):
10201020
initializer := declaration.Initializer()
1021-
if isExpandoInitializer(initializer) {
1021+
if ast.IsExpandoInitializer(initializer) {
10221022
return initializer.Symbol()
10231023
}
10241024
case ast.IsBinaryExpression(declaration) && ast.IsInJSFile(declaration):
10251025
initializer := declaration.AsBinaryExpression().Right
1026-
if isExpandoInitializer(initializer) {
1026+
if ast.IsExpandoInitializer(initializer) {
10271027
return initializer.Symbol()
10281028
}
10291029
}
10301030
return nil
10311031
}
10321032

1033-
func isExpandoInitializer(initializer *ast.Node) bool {
1034-
if initializer == nil {
1035-
return false
1036-
}
1037-
if ast.IsFunctionExpressionOrArrowFunction(initializer) {
1038-
return true
1039-
} else if ast.IsInJSFile(initializer) {
1040-
return ast.IsClassExpression(initializer) || (ast.IsObjectLiteralExpression(initializer) && len(initializer.AsObjectLiteralExpression().Properties.Nodes) == 0)
1041-
}
1042-
return false
1043-
}
1044-
10451033
func (b *Binder) bindThisPropertyAssignment(node *ast.Node) {
10461034
if !ast.IsInJSFile(node) {
10471035
return

internal/binder/referenceresolver.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type ReferenceResolver interface {
1111
GetReferencedImportDeclaration(node *ast.IdentifierNode) *ast.Declaration
1212
GetReferencedValueDeclaration(node *ast.IdentifierNode) *ast.Declaration
1313
GetReferencedValueDeclarations(node *ast.IdentifierNode) []*ast.Declaration
14+
GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string
1415
}
1516

1617
type ReferenceResolverHooks struct {
@@ -21,6 +22,7 @@ type ReferenceResolverHooks struct {
2122
GetSymbolOfDeclaration func(*ast.Declaration) *ast.Symbol
2223
GetTypeOnlyAliasDeclaration func(symbol *ast.Symbol, include ast.SymbolFlags) *ast.Declaration
2324
GetExportSymbolOfValueSymbolIfExported func(*ast.Symbol) *ast.Symbol
25+
GetElementAccessExpressionName func(*ast.ElementAccessExpression) (string, bool)
2426
}
2527

2628
var _ ReferenceResolver = &referenceResolver{}
@@ -236,3 +238,14 @@ func (r *referenceResolver) GetReferencedValueDeclarations(node *ast.IdentifierN
236238
}
237239
return declarations
238240
}
241+
242+
func (r *referenceResolver) GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string {
243+
if expression != nil {
244+
if r.hooks.GetElementAccessExpressionName != nil {
245+
if name, ok := r.hooks.GetElementAccessExpressionName(expression); ok {
246+
return name
247+
}
248+
}
249+
}
250+
return ""
251+
}

0 commit comments

Comments
 (0)