Skip to content
Merged
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
1 change: 1 addition & 0 deletions docs/typescript-parity-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ All test cases in the regression test suite (Corpus Test Suite) have been cross-
| Template Literals (`` `Hello ${name}` ``) | ✅ Full | String concatenation and dynamic interpolation. |
| Tagged Template Expressions (`` tag`Hello ${name}` ``) | ✅ Full | Calls function/closure with `TemplateStringsArray` and interpolated argument list. |
| Optional Chaining & Optional Call (`?.`, `fn?.()`, `obj?.method?.()`, `arr?.[idx]`) | ✅ Full | Short-circuits property access, element indexing, and function calls when receiver is nullish without evaluating argument/index side-effects. Native unboxed number returns IEEE-754 NaN when short-circuited. |
| Computed Property Names (`[expr]`, `[Symbol.xxx]`) | ✅ Full | Supported in object literals, type aliases, union types, and interface definitions; AST extraction gracefully handles computed property expressions without unhandled node panics. |
| `debugger;` Statement | ✅ Full | Breakpoint hook in native runtime (`scriptgo_debugger_break`), instruction-level DWARF location mapping, compliant no-op in headless execution adhering to ECMAScript standard. |

---
Expand Down
11 changes: 11 additions & 0 deletions internal/compiler/testdata/corpus/types/computed_property_types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @expect: ScriptGo
const S: symbol = Symbol("tag");
type WithComputed = {
[S]: string;
name: string;
};
const item: WithComputed = {
[S]: "tag_val",
name: "ScriptGo"
};
console.log(item.name);
28 changes: 28 additions & 0 deletions internal/typescriptgo/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,3 +432,31 @@ console.log(num, str);
}
}
}

func TestCheckSupportsComputedPropertyNameInTypes(t *testing.T) {
entry := filepath.Join(t.TempDir(), "main.ts")
source := `
const S: symbol = Symbol("tag");
type WithComputed = {
[S]: string;
name: string;
};
type UnionWithComputed = { [S]: number } | { name: string };
const obj: WithComputed = {
[S]: "hello",
name: "world",
};
console.log(obj.name);
`
if err := os.WriteFile(entry, []byte(source), 0o644); err != nil {
t.Fatal(err)
}

result, err := Check(entry)
if err != nil {
t.Fatal(err)
}
if len(result.Diagnostics) != 0 {
t.Fatalf("Check returned unexpected diagnostics for computed properties: %+v", result.Diagnostics)
}
}
6 changes: 3 additions & 3 deletions internal/typescriptgo/syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ func syntaxType(node *ast.Node) string {
for _, p := range fnNode.Parameters.Nodes {
pName := ""
if p.Name() != nil {
pName = p.Name().Text()
pName = syntaxMemberName(p.Name())
}
pType := syntaxType(p.Type())
if pName != "" {
Expand Down Expand Up @@ -319,12 +319,12 @@ func syntaxTypeParameters(typeParams []*ast.Node) []string {
if p.Kind == ast.KindTypeParameter {
tp := p.AsTypeParameterDeclaration()
if tp != nil && tp.Name() != nil {
result = append(result, tp.Name().Text())
result = append(result, syntaxMemberName(tp.Name()))
continue
}
}
if p.Name() != nil {
result = append(result, p.Name().Text())
result = append(result, syntaxMemberName(p.Name()))
}
}
return result
Expand Down
16 changes: 8 additions & 8 deletions internal/typescriptgo/syntax_destruct.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ func flattenObjectBinding(nameNode *ast.Node, initExpr *SyntaxExpression, chk *c
if b := elem.AsBindingElement(); b != nil {
pName := ""
if b.PropertyName != nil {
pName = b.PropertyName.Text()
pName = syntaxMemberName(b.PropertyName)
} else if b.Name() != nil {
pName = b.Name().Text()
pName = syntaxMemberName(b.Name())
}
t := resolveInferredType(chk, b.Name())
if t == "" || t == "void" {
Expand Down Expand Up @@ -102,9 +102,9 @@ func flattenObjectBinding(nameNode *ast.Node, initExpr *SyntaxExpression, chk *c

propName := ""
if binding.PropertyName != nil {
propName = binding.PropertyName.Text()
propName = syntaxMemberName(binding.PropertyName)
} else if binding.Name() != nil {
propName = binding.Name().Text()
propName = syntaxMemberName(binding.Name())
}

targetNode := binding.Name()
Expand Down Expand Up @@ -234,9 +234,9 @@ func flattenObjectBinding(nameNode *ast.Node, initExpr *SyntaxExpression, chk *c
if sb := sub.AsBindingElement(); sb != nil {
pName := ""
if sb.PropertyName != nil {
pName = sb.PropertyName.Text()
pName = syntaxMemberName(sb.PropertyName)
} else if sb.Name() != nil {
pName = sb.Name().Text()
pName = syntaxMemberName(sb.Name())
}
st := resolveInferredType(chk, sb.Name())
if st == "" || st == "void" || st == "undefined" {
Expand Down Expand Up @@ -682,7 +682,7 @@ func flattenDestructuringAssignment(leftNode *ast.Node, initExpr *SyntaxExpressi
if objLit != nil && objLit.Properties != nil {
for _, prop := range objLit.Properties.Nodes {
if prop.Kind == ast.KindShorthandPropertyAssignment {
propName := prop.Name().Text()
propName := syntaxMemberName(prop.Name())
stmts = append(stmts, SyntaxStatement{
Span: sourceSpan(prop),
Kind: "assign",
Expand All @@ -696,7 +696,7 @@ func flattenDestructuringAssignment(leftNode *ast.Node, initExpr *SyntaxExpressi
})
} else if prop.Kind == ast.KindPropertyAssignment {
pAssign := prop.AsPropertyAssignment()
propName := pAssign.Name().Text()
propName := syntaxMemberName(pAssign.Name())
if pAssign.Initializer != nil {
if pAssign.Initializer.Kind == ast.KindIdentifier {
stmts = append(stmts, SyntaxStatement{
Expand Down
4 changes: 2 additions & 2 deletions internal/typescriptgo/syntax_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,13 @@ func syntaxExpressionInner(node *ast.Node, chk *checker.Checker) *SyntaxExpressi
result.Arguments = append(result.Arguments, &SyntaxExpression{
Span: sourceSpan(propNode),
Kind: "property_assignment",
Text: prop.Name().Text(),
Text: syntaxMemberName(prop.Name()),
Left: syntaxExpression(prop.Initializer, chk),
InferredType: resolveInferredType(chk, propNode),
})
case ast.KindShorthandPropertyAssignment:
prop := propNode.AsShorthandPropertyAssignment()
name := prop.Name().Text()
name := syntaxMemberName(prop.Name())
result.Arguments = append(result.Arguments, &SyntaxExpression{
Span: sourceSpan(propNode),
Kind: "property_assignment",
Expand Down
10 changes: 2 additions & 8 deletions internal/typescriptgo/syntax_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,10 +698,7 @@ func syntaxStatement(node *ast.Node, chk *checker.Checker) (SyntaxStatement, boo
if alias.Type.Kind == ast.KindTypeLiteral {
for _, member := range alias.Type.Members() {
if member.Kind == ast.KindPropertySignature {
pName := ""
if member.Name() != nil {
pName = member.Name().Text()
}
pName := syntaxMemberName(member.Name())
property := member.AsPropertySignatureDeclaration()
fields = append(fields, SyntaxField{
Span: sourceSpan(member),
Expand All @@ -719,10 +716,7 @@ func syntaxStatement(node *ast.Node, chk *checker.Checker) (SyntaxStatement, boo
if t.Kind == ast.KindTypeLiteral {
for _, member := range t.Members() {
if member.Kind == ast.KindPropertySignature {
pName := ""
if member.Name() != nil {
pName = member.Name().Text()
}
pName := syntaxMemberName(member.Name())
property := member.AsPropertySignatureDeclaration()
fields = append(fields, SyntaxField{
Span: sourceSpan(member),
Expand Down
14 changes: 9 additions & 5 deletions internal/typescriptgo/syntax_stmt_class.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,17 +584,24 @@ func replaceThisWithClassExpr(expr *SyntaxExpression, className string) *SyntaxE
return expr
}

func syntaxMemberName(nameNode *ast.Node) string {
func syntaxMemberName(nameNode *ast.Node) (result string) {
if nameNode == nil {
return ""
}
defer func() {
if r := recover(); r != nil {
result = ""
}
}()
switch nameNode.Kind {
case ast.KindComputedPropertyName:
if expr := nameNode.Expression(); expr != nil {
if expr.Kind == ast.KindPropertyAccessExpression {
return syntaxMemberName(expr.Expression()) + "." + syntaxMemberName(expr.Name())
} else if expr.Kind == ast.KindIdentifier {
return expr.Text()
} else if expr.Kind == ast.KindStringLiteral || expr.Kind == ast.KindNumericLiteral {
return expr.Text()
}
}
return "[computed]"
Expand All @@ -612,9 +619,6 @@ func syntaxMemberName(nameNode *ast.Node) string {
if nameNode.Kind == ast.KindReturnKeyword {
return "return"
}
if nameNode.Text() != "" {
return nameNode.Text()
}
return ""
return nameNode.Text()
}
}
Loading