Skip to content

Commit b6977b5

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/typescript-go into fix/1374
2 parents 37935cf + 96c0688 commit b6977b5

File tree

325 files changed

+2668
-2871
lines changed

Some content is hidden

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

325 files changed

+2668
-2871
lines changed

.github/ISSUE_TEMPLATE/01-crash.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
name: Crash
3+
about: Using tsgo or the language server caused a panic
4+
title: ''
5+
labels: Crash
6+
assignees: ''
7+
8+
---
9+
10+
## Stack trace
11+
12+
```
13+
[paste stack trace here]
14+
```
15+
16+
## Steps to reproduce
17+
18+
1.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
name: Behavior Difference
3+
about: tsgo produces different results than TypeScript 5.8
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
## Steps to reproduce
11+
12+
<!-- Share a repository link or a code sample -->
13+
14+
## Behavior with `[email protected]`
15+
16+
## Behavior with `tsgo`

.github/ISSUE_TEMPLATE/03-other.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
name: Other
3+
about: Something else
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
name: '[TypeScript Team Use] Copilot PR porting'
3+
about: Instructions for Copilot to port a PR from microsoft/TypeScript
4+
title: 'Port TypeScript PR #[NNNNN]'
5+
labels: Porting PR
6+
assignees: ''
7+
8+
---
9+
10+
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.
11+
12+
## PR to port
13+
14+
- PR link: <!-- https://github.com/microsoft/TypeScript/pull/NNNNN -->
15+
- Squash commit diff: <!-- Copy the squash commit link and append ".patch", e.g. https://github.com/microsoft/TypeScript/commit/a271797c1a95494e5f7aa8075c01941ad25cad08.patch -->
16+
17+
## Instructions
18+
19+
1. Use `playwright` to view the PR listed above
20+
2. Apply the edits made in that PR to this codebase, translating them from TypeScript to Go.
21+
- 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.
22+
- 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.
23+
- 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.
24+
3. Refer to your copilot_instructions.md for guidance on how to build and test your change. Note the following differences to the typical development workflow:
25+
- Since you are porting the implementation for a behavior that already has tests in the submodule, you don't need to add new tests. Instead, your change should change existing baselines.
26+
- If done correctly, you should see removals in `.diff` baselines. These `.diff` removals are your ultimate source of truth: your change is not correct unless diffs are reduced.

internal/ast/ast.go

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,20 @@ func (n *Node) Elements() []*Node {
879879
return nil
880880
}
881881

882+
func (n *Node) QuestionDotToken() *Node {
883+
switch n.Kind {
884+
case KindElementAccessExpression:
885+
return n.AsElementAccessExpression().QuestionDotToken
886+
case KindPropertyAccessExpression:
887+
return n.AsPropertyAccessExpression().QuestionDotToken
888+
case KindCallExpression:
889+
return n.AsCallExpression().QuestionDotToken
890+
case KindTaggedTemplateExpression:
891+
return n.AsTaggedTemplateExpression().QuestionDotToken
892+
}
893+
panic("Unhandled case in Node.QuestionDotToken: " + n.Kind.String())
894+
}
895+
882896
// Determines if `n` contains `descendant` by walking up the `Parent` pointers from `descendant`. This method panics if
883897
// `descendant` or one of its ancestors is not parented except when that node is a `SourceFile`.
884898
func (n *Node) Contains(descendant *Node) bool {
@@ -1673,6 +1687,10 @@ func (n *Node) AsSyntaxList() *SyntaxList {
16731687
return n.data.(*SyntaxList)
16741688
}
16751689

1690+
func (n *Node) AsSyntheticReferenceExpression() *SyntheticReferenceExpression {
1691+
return n.data.(*SyntheticReferenceExpression)
1692+
}
1693+
16761694
// NodeData
16771695

16781696
type nodeData interface {
@@ -2767,6 +2785,10 @@ func (node *SwitchStatement) computeSubtreeFacts() SubtreeFacts {
27672785
propagateSubtreeFacts(node.CaseBlock)
27682786
}
27692787

2788+
func IsSwitchStatement(node *Node) bool {
2789+
return node.Kind == KindSwitchStatement
2790+
}
2791+
27702792
// CaseBlock
27712793

27722794
type CaseBlock struct {
@@ -4127,6 +4149,53 @@ func IsNotEmittedTypeElement(node *Node) bool {
41274149
return node.Kind == KindNotEmittedTypeElement
41284150
}
41294151

4152+
// SyntheticReferenceExpression
4153+
// Used by optional chaining transform to shuffle a `this` arg expression between steps of a chain.
4154+
// While this does implement the full expected interface of a node, and is used in place of a node in transforms,
4155+
// it generally shouldn't be treated or visited like a normal node.
4156+
4157+
type SyntheticReferenceExpression struct {
4158+
ExpressionBase
4159+
Expression *Expression
4160+
ThisArg *Expression
4161+
}
4162+
4163+
func (f *NodeFactory) NewSyntheticReferenceExpression(expr *Expression, thisArg *Expression) *Node {
4164+
data := &SyntheticReferenceExpression{Expression: expr, ThisArg: thisArg}
4165+
return newNode(KindSyntheticReferenceExpression, data, f.hooks)
4166+
}
4167+
4168+
func (f *NodeFactory) UpdateSyntheticReferenceExpression(node *SyntheticReferenceExpression, expr *Expression, thisArg *Expression) *Node {
4169+
if expr != node.Expression || thisArg != node.ThisArg {
4170+
return updateNode(f.NewSyntheticReferenceExpression(expr, thisArg), node.AsNode(), f.hooks)
4171+
}
4172+
return node.AsNode()
4173+
}
4174+
4175+
func (node *SyntheticReferenceExpression) ForEachChild(v Visitor) bool {
4176+
return visit(v, node.Expression)
4177+
}
4178+
4179+
func (node *SyntheticReferenceExpression) VisitEachChild(v *NodeVisitor) *Node {
4180+
return v.Factory.UpdateSyntheticReferenceExpression(node, v.visitNode(node.Expression), node.ThisArg)
4181+
}
4182+
4183+
func (node *SyntheticReferenceExpression) Clone(f NodeFactoryCoercible) *Node {
4184+
return cloneNode(f.AsNodeFactory().NewSyntheticReferenceExpression(node.Expression, node.ThisArg), node.AsNode(), f.AsNodeFactory().hooks)
4185+
}
4186+
4187+
func (node *SyntheticReferenceExpression) computeSubtreeFacts() SubtreeFacts {
4188+
return propagateSubtreeFacts(node.Expression)
4189+
}
4190+
4191+
func (node *SyntheticReferenceExpression) propagateSubtreeFacts() SubtreeFacts {
4192+
return node.SubtreeFacts()
4193+
}
4194+
4195+
func IsSyntheticReferenceExpression(node *Node) bool {
4196+
return node.Kind == KindSyntheticReferenceExpression
4197+
}
4198+
41304199
// ImportEqualsDeclaration
41314200

41324201
type ImportEqualsDeclaration struct {
@@ -8855,6 +8924,10 @@ func (node *JSDoc) Clone(f NodeFactoryCoercible) *Node {
88558924
return cloneNode(f.AsNodeFactory().NewJSDoc(node.Comment, node.Tags), node.AsNode(), f.AsNodeFactory().hooks)
88568925
}
88578926

8927+
func (node *Node) IsJSDoc() bool {
8928+
return node.Kind == KindJSDoc
8929+
}
8930+
88588931
type JSDocTagBase struct {
88598932
NodeBase
88608933
TagName *IdentifierNode
@@ -8994,7 +9067,6 @@ func (node *JSDocLinkCode) Name() *DeclarationName {
89949067

89959068
type JSDocTypeExpression struct {
89969069
TypeNodeBase
8997-
Host *Node
89989070
Type *TypeNode
89999071
}
90009072

@@ -9252,7 +9324,6 @@ type JSDocTemplateTag struct {
92529324
JSDocTagBase
92539325
Constraint *Node
92549326
TypeParameters *TypeParameterList
9255-
Host *Node
92569327
}
92579328

92589329
func (f *NodeFactory) NewJSDocTemplateTag(tagName *IdentifierNode, constraint *Node, typeParameters *TypeParameterList, comment *NodeList) *Node {
@@ -9747,10 +9818,9 @@ func (node *JSDocThisTag) Clone(f NodeFactoryCoercible) *Node {
97479818
// JSDocImportTag
97489819
type JSDocImportTag struct {
97499820
JSDocTagBase
9750-
JSImportDeclaration *ImportDeclaration
9751-
ImportClause *Declaration
9752-
ModuleSpecifier *Expression
9753-
Attributes *Node
9821+
ImportClause *Declaration
9822+
ModuleSpecifier *Expression
9823+
Attributes *Node
97549824
}
97559825

97569826
func (f *NodeFactory) NewJSDocImportTag(tagName *IdentifierNode, importClause *Declaration, moduleSpecifier *Node, attributes *Node, comment *NodeList) *Node {
@@ -10095,7 +10165,7 @@ type SourceFile struct {
1009510165
}
1009610166

1009710167
func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, statements *NodeList, endOfFileToken *TokenNode) *Node {
10098-
if (tspath.GetEncodedRootLength(opts.FileName) == 0 && !strings.HasPrefix(opts.FileName, "^/")) || opts.FileName != tspath.NormalizePath(opts.FileName) {
10168+
if tspath.GetEncodedRootLength(opts.FileName) == 0 || opts.FileName != tspath.NormalizePath(opts.FileName) {
1009910169
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", opts.FileName))
1010010170
}
1010110171
data := &SourceFile{}

internal/ast/deepclone.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package ast
33
import "github.com/microsoft/typescript-go/internal/core"
44

55
// Ideally, this would get cached on the node factory so there's only ever one set of closures made per factory
6-
func getDeepCloneVisitor(f *NodeFactory) *NodeVisitor {
6+
func getDeepCloneVisitor(f *NodeFactory, syntheticLocation bool) *NodeVisitor {
77
var visitor *NodeVisitor
88
visitor = NewNodeVisitor(
99
func(node *Node) *Node {
@@ -15,7 +15,9 @@ func getDeepCloneVisitor(f *NodeFactory) *NodeVisitor {
1515
// In strada, `factory.cloneNode` was dynamic and did _not_ clone positions for any "special cases", meanwhile
1616
// Node.Clone in corsa reliably uses `Update` calls for all nodes and so copies locations by default.
1717
// Deep clones are done to copy a node across files, so here, we explicitly make the location range synthetic on all cloned nodes
18-
c.Loc = core.NewTextRange(-1, -1)
18+
if syntheticLocation {
19+
c.Loc = core.NewTextRange(-1, -1)
20+
}
1921
return c
2022
},
2123
f,
@@ -46,5 +48,18 @@ func getDeepCloneVisitor(f *NodeFactory) *NodeVisitor {
4648
}
4749

4850
func (f *NodeFactory) DeepCloneNode(node *Node) *Node {
49-
return getDeepCloneVisitor(f).VisitNode(node)
51+
return getDeepCloneVisitor(f, true /*syntheticLocation*/).VisitNode(node)
52+
}
53+
54+
func (f *NodeFactory) DeepCloneReparse(node *Node) *Node {
55+
if node != nil {
56+
node = getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitNode(node)
57+
SetParentInChildren(node)
58+
node.Flags |= NodeFlagsReparsed
59+
}
60+
return node
61+
}
62+
63+
func (f *NodeFactory) DeepCloneReparseModifiers(modifiers *ModifierList) *ModifierList {
64+
return getDeepCloneVisitor(f, false /*syntheticLocation*/).VisitModifiers(modifiers)
5065
}

internal/ast/utilities.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -867,17 +867,6 @@ func WalkUpParenthesizedTypes(node *TypeNode) *Node {
867867
return node
868868
}
869869

870-
func GetEffectiveTypeParent(parent *Node) *Node {
871-
if parent != nil && IsInJSFile(parent) {
872-
if parent.Kind == KindJSDocTypeExpression && parent.AsJSDocTypeExpression().Host != nil {
873-
parent = parent.AsJSDocTypeExpression().Host
874-
} else if parent.Kind == KindJSDocTemplateTag && parent.AsJSDocTemplateTag().Host != nil {
875-
parent = parent.AsJSDocTemplateTag().Host
876-
}
877-
}
878-
return parent
879-
}
880-
881870
// Walks up the parents of a node to find the containing SourceFile
882871
func GetSourceFileOfNode(node *Node) *SourceFile {
883872
for node != nil {
@@ -1466,6 +1455,8 @@ func getAssignedName(node *Node) *Node {
14661455
}
14671456
}
14681457
}
1458+
case KindCommonJSExport:
1459+
return parent.AsCommonJSExport().Name()
14691460
case KindVariableDeclaration:
14701461
name := parent.AsVariableDeclaration().Name()
14711462
if IsIdentifier(name) {

internal/binder/binder.go

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,8 +1639,6 @@ func (b *Binder) bindChildren(node *ast.Node) {
16391639
case ast.KindObjectLiteralExpression, ast.KindArrayLiteralExpression, ast.KindPropertyAssignment, ast.KindSpreadElement:
16401640
b.inAssignmentPattern = saveInAssignmentPattern
16411641
b.bindEachChild(node)
1642-
case ast.KindJSExportAssignment, ast.KindCommonJSExport:
1643-
// Reparsed nodes do not double-bind children, which are not reparsed
16441642
default:
16451643
b.bindEachChild(node)
16461644
}
@@ -2746,7 +2744,7 @@ func (b *Binder) errorOrSuggestionOnRange(isError bool, startNode *ast.Node, end
27462744
// If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node)
27472745
// This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations.
27482746
func (b *Binder) createDiagnosticForNode(node *ast.Node, message *diagnostics.Message, args ...any) *ast.Diagnostic {
2749-
return ast.NewDiagnostic(b.file, GetErrorRangeForNode(b.file, node), message, args...)
2747+
return ast.NewDiagnostic(b.file, scanner.GetErrorRangeForNode(b.file, node), message, args...)
27502748
}
27512749

27522750
func (b *Binder) addDiagnostic(diagnostic *ast.Diagnostic) {
@@ -2843,83 +2841,3 @@ func isAssignmentDeclaration(decl *ast.Node) bool {
28432841
func isEffectiveModuleDeclaration(node *ast.Node) bool {
28442842
return ast.IsModuleDeclaration(node) || ast.IsIdentifier(node)
28452843
}
2846-
2847-
func getErrorRangeForArrowFunction(sourceFile *ast.SourceFile, node *ast.Node) core.TextRange {
2848-
pos := scanner.SkipTrivia(sourceFile.Text(), node.Pos())
2849-
body := node.AsArrowFunction().Body
2850-
if body != nil && body.Kind == ast.KindBlock {
2851-
startLine, _ := scanner.GetLineAndCharacterOfPosition(sourceFile, body.Pos())
2852-
endLine, _ := scanner.GetLineAndCharacterOfPosition(sourceFile, body.End())
2853-
if startLine < endLine {
2854-
// The arrow function spans multiple lines,
2855-
// make the error span be the first line, inclusive.
2856-
return core.NewTextRange(pos, scanner.GetEndLinePosition(sourceFile, startLine))
2857-
}
2858-
}
2859-
return core.NewTextRange(pos, node.End())
2860-
}
2861-
2862-
func GetErrorRangeForNode(sourceFile *ast.SourceFile, node *ast.Node) core.TextRange {
2863-
errorNode := node
2864-
switch node.Kind {
2865-
case ast.KindSourceFile:
2866-
pos := scanner.SkipTrivia(sourceFile.Text(), 0)
2867-
if pos == len(sourceFile.Text()) {
2868-
return core.NewTextRange(0, 0)
2869-
}
2870-
return scanner.GetRangeOfTokenAtPosition(sourceFile, pos)
2871-
// This list is a work in progress. Add missing node kinds to improve their error spans
2872-
case ast.KindFunctionDeclaration, ast.KindMethodDeclaration:
2873-
if node.Flags&ast.NodeFlagsReparsed != 0 {
2874-
errorNode = node
2875-
break
2876-
}
2877-
fallthrough
2878-
case ast.KindVariableDeclaration, ast.KindBindingElement, ast.KindClassDeclaration, ast.KindClassExpression, ast.KindInterfaceDeclaration,
2879-
ast.KindModuleDeclaration, ast.KindEnumDeclaration, ast.KindEnumMember, ast.KindFunctionExpression,
2880-
ast.KindGetAccessor, ast.KindSetAccessor, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindPropertyDeclaration,
2881-
ast.KindPropertySignature, ast.KindNamespaceImport:
2882-
errorNode = ast.GetNameOfDeclaration(node)
2883-
case ast.KindArrowFunction:
2884-
return getErrorRangeForArrowFunction(sourceFile, node)
2885-
case ast.KindCaseClause, ast.KindDefaultClause:
2886-
start := scanner.SkipTrivia(sourceFile.Text(), node.Pos())
2887-
end := node.End()
2888-
statements := node.AsCaseOrDefaultClause().Statements.Nodes
2889-
if len(statements) != 0 {
2890-
end = statements[0].Pos()
2891-
}
2892-
return core.NewTextRange(start, end)
2893-
case ast.KindReturnStatement, ast.KindYieldExpression:
2894-
pos := scanner.SkipTrivia(sourceFile.Text(), node.Pos())
2895-
return scanner.GetRangeOfTokenAtPosition(sourceFile, pos)
2896-
case ast.KindSatisfiesExpression:
2897-
pos := scanner.SkipTrivia(sourceFile.Text(), node.AsSatisfiesExpression().Expression.End())
2898-
return scanner.GetRangeOfTokenAtPosition(sourceFile, pos)
2899-
case ast.KindConstructor:
2900-
if node.Flags&ast.NodeFlagsReparsed != 0 {
2901-
errorNode = node
2902-
break
2903-
}
2904-
scanner := scanner.GetScannerForSourceFile(sourceFile, node.Pos())
2905-
start := scanner.TokenStart()
2906-
for scanner.Token() != ast.KindConstructorKeyword && scanner.Token() != ast.KindStringLiteral && scanner.Token() != ast.KindEndOfFile {
2907-
scanner.Scan()
2908-
}
2909-
return core.NewTextRange(start, scanner.TokenEnd())
2910-
// !!!
2911-
// case KindJSDocSatisfiesTag:
2912-
// pos := scanner.SkipTrivia(sourceFile.Text(), node.tagName.pos)
2913-
// return scanner.GetRangeOfTokenAtPosition(sourceFile, pos)
2914-
}
2915-
if errorNode == nil {
2916-
// If we don't have a better node, then just set the error on the first token of
2917-
// construct.
2918-
return scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos())
2919-
}
2920-
pos := errorNode.Pos()
2921-
if !ast.NodeIsMissing(errorNode) && !ast.IsJsxText(errorNode) {
2922-
pos = scanner.SkipTrivia(sourceFile.Text(), pos)
2923-
}
2924-
return core.NewTextRange(pos, errorNode.End())
2925-
}

0 commit comments

Comments
 (0)