Skip to content

Commit

Permalink
Add operator nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
Emyrk committed Dec 9, 2024
1 parent e72f1f1 commit 3fbd5df
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 39 deletions.
9 changes: 4 additions & 5 deletions bindings/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import (
type Node interface {
isNode()
}
type isTypescriptNode struct{}

func (isTypescriptNode) isNode() {}

type Identifier struct {
Name string
Expand Down Expand Up @@ -57,9 +54,10 @@ const (
type HeritageClause struct {
Token HeritageType
Args []ExpressionType
isTypescriptNode
}

func (h *HeritageClause) isNode() {}

func HeritageClauseExtends(args ...ExpressionType) *HeritageClause {
return &HeritageClause{
Token: HeritageTypeExtends,
Expand All @@ -83,9 +81,10 @@ type Comment struct {
TrailingNewLine bool

Node *goja.Object
isTypescriptNode
}

func (c *Comment) isNode() {}

type Modifier string

const (
Expand Down
20 changes: 20 additions & 0 deletions bindings/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ func (b *Bindings) ToTypescriptExpressionNode(ety ExpressionType) (*goja.Object,
}
case *ArrayLiteralType:
siObj, err = b.ArrayLiteral(ety)
case *OperatorNodeType:
siObj, err = b.OperatorNode(ety)
default:
return nil, xerrors.Errorf("unsupported type for field type: %T", ety)
}
Expand Down Expand Up @@ -606,3 +608,21 @@ func (b *Bindings) VariableDeclaration(decl *VariableDeclaration) (*goja.Object,

return res.ToObject(b.vm), nil
}

func (b *Bindings) OperatorNode(value *OperatorNodeType) (*goja.Object, error) {
literalF, err := b.f("typeOperatorNode")
if err != nil {
return nil, err
}

obj, err := b.ToTypescriptExpressionNode(value.Type)
if err != nil {
return nil, fmt.Errorf("operator type: %w", err)
}

res, err := literalF(goja.Undefined(), b.vm.ToValue(value.Keyword), obj)
if err != nil {
return nil, xerrors.Errorf("call numericLiteral: %w", err)
}
return res.ToObject(b.vm), nil
}
17 changes: 7 additions & 10 deletions bindings/declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ type Interface struct {
// Comments maybe should be its own AST node?
Comments []string
Source

isTypescriptNode
}

func (*Interface) isNode() {}
func (*Interface) isDeclarationType() {}

type PropertySignature struct {
Expand All @@ -35,20 +34,19 @@ type PropertySignature struct {
Type ExpressionType
// FieldComments maybe should be its own AST node?
FieldComments []string

isTypescriptNode
}

func (*PropertySignature) isNode() {}

type Alias struct {
Name Identifier
Modifiers []Modifier
Type ExpressionType
Parameters []*TypeParameter
Source

isTypescriptNode
}

func (*Alias) isNode() {}
func (*Alias) isDeclarationType() {}

// TypeParameter are generics in Go
Expand All @@ -64,10 +62,10 @@ type TypeParameter struct {
// DefaultType does not map to any Golang concepts and will never be
// used.
DefaultType ExpressionType

isTypescriptNode
}

func (h *TypeParameter) isNode() {}

// Simplify removes duplicate type parameters
func Simplify(p []*TypeParameter) ([]*TypeParameter, error) {
params := make([]*TypeParameter, 0, len(p))
Expand All @@ -91,8 +89,7 @@ type VariableStatement struct {
Modifiers []Modifier
Declarations *VariableDeclarationList
Source

isTypescriptNode
}

func (*VariableStatement) isNode() {}
func (*VariableStatement) isDeclarationType() {}
42 changes: 27 additions & 15 deletions bindings/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const (
KeywordUndefined LiteralKeyword = "UndefinedKeyword"
KeywordUnknown LiteralKeyword = "UnknownKeyword"
KeywordBigInt LiteralKeyword = "BigIntKeyword"
KeywordReadonly LiteralKeyword = "ReadonlyKeyword"
KeywordUnique LiteralKeyword = "UniqueKeyword"
KeywordKeyOf LiteralKeyword = "KeyOfKeyword"
)

func ToTypescriptLiteralKeyword(word string) (LiteralKeyword, error) {
Expand All @@ -44,32 +47,30 @@ func ToTypescriptLiteralKeyword(word string) (LiteralKeyword, error) {

type LiteralType struct {
Value any // should be some constant value
isTypescriptNode
}

func (*LiteralType) isNode() {}
func (*LiteralType) isExpressionType() {}

// ReferenceType can be used to reference another type by name
type ReferenceType struct {
Name Identifier `json:"name"`
// TODO: Generics
Arguments []ExpressionType `json:"arguments"`

isTypescriptNode
}

func Reference(name Identifier, args ...ExpressionType) *ReferenceType {
return &ReferenceType{Name: name, Arguments: args}
}

func (*ReferenceType) isNode() {}
func (*ReferenceType) isExpressionType() {}

type ArrayType struct {
Node ExpressionType

isTypescriptNode
}

func (*ArrayType) isNode() {}
func (*ArrayType) isExpressionType() {}

func Array(node ExpressionType) *ArrayType {
Expand All @@ -80,54 +81,65 @@ func Array(node ExpressionType) *ArrayType {

type ArrayLiteralType struct {
Elements []ExpressionType
isTypescriptNode
}

func (*ArrayLiteralType) isNode() {}
func (*ArrayLiteralType) isExpressionType() {}

type UnionType struct {
Types []ExpressionType

isTypescriptNode
}

func (*UnionType) isNode() {}
func (*UnionType) isExpressionType() {}

func Union(types ...ExpressionType) *UnionType {
return &UnionType{Types: types}
}

type Null struct {
isTypescriptNode
}

func (*Null) isNode() {}
func (*Null) isExpressionType() {}

type ExpressionWithTypeArguments struct {
Expression ExpressionType
Arguments []ExpressionType

isTypescriptNode
}

func (*ExpressionWithTypeArguments) isNode() {}
func (*ExpressionWithTypeArguments) isExpressionType() {}

type VariableDeclarationList struct {
Declarations []*VariableDeclaration
Flags NodeFlags

isTypescriptNode
}

func (*VariableDeclarationList) isNode() {}
func (*VariableDeclarationList) isExpressionType() {}

type VariableDeclaration struct {
Name Identifier
ExclamationMark bool
Type ExpressionType
Initializer ExpressionType

isTypescriptNode
}

func (*VariableDeclaration) isNode() {}
func (*VariableDeclaration) isExpressionType() {}

type OperatorNodeType struct {
Keyword LiteralKeyword
Type ExpressionType
}

func OperatorNode(keyword LiteralKeyword, node ExpressionType) *OperatorNodeType {
return &OperatorNodeType{
Keyword: keyword,
Type: node,
}
}

func (*OperatorNodeType) isNode() {}
func (*OperatorNodeType) isExpressionType() {}
4 changes: 3 additions & 1 deletion bindings/walk/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ func Walk(v Visitor, node bindings.Node) {
case *bindings.LiteralType:
// noop
case *bindings.Null:
// noop
// noop
case *bindings.HeritageClause:
walkList(v, n.Args)
default:
panic(fmt.Sprintf("convert.Walk: unexpected node type %T", n))
}
Expand Down
5 changes: 4 additions & 1 deletion config/mutations.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func ExportTypes(ts *guts.Typescript) {
case *bindings.VariableStatement:
node.Modifiers = append(node.Modifiers, bindings.ModifierExport)
default:
panic("unexpected node type for exporting")
panic(fmt.Sprintf("unexpected node type %T for exporting", node))
}
})
}
Expand All @@ -32,6 +32,9 @@ func ReadOnly(ts *guts.Typescript) {
case *bindings.Interface:
for _, prop := range node.Fields {
prop.Modifiers = append(prop.Modifiers, bindings.ModifierReadonly)
if _, isArray := prop.Type.(*bindings.ArrayType); isArray {
prop.Type = bindings.OperatorNode(bindings.KeywordReadonly, prop.Type)
}
}
case *bindings.VariableStatement:
default:
Expand Down
10 changes: 7 additions & 3 deletions convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,17 @@ func (ts *Typescript) parseGolangIdentifiers() error {
return nil
}

func (ts *Typescript) ReplaceNode(key string, node bindings.Node) {
ts.typescriptNodes[key] = &typescriptNode{
Node: node,
}
}

func (ts *Typescript) SetNode(key string, node bindings.Node) error {
if _, ok := ts.typescriptNodes[key]; ok {
return fmt.Errorf("node %q already exists", key)
}
ts.typescriptNodes[key] = &typescriptNode{
Node: node,
}
ts.ReplaceNode(key, node)
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion testdata/genericmap/genericmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ export interface Foo {

// From codersdk/genericmap.go
export interface FooBuzz<R extends Custom> {
readonly something: R[];
readonly something: readonly R[];
}
4 changes: 2 additions & 2 deletions testdata/genericslice/genericslice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ export interface Bar {

// From codersdk/genericslice.go
export interface Foo<R extends any> {
readonly Slice: R[];
readonly TwoD: R[][];
readonly Slice: readonly R[];
readonly TwoD: readonly R[][];
}
2 changes: 1 addition & 1 deletion typescript-engine/dist/main.js

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions typescript-engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ export function arrayLiteral(
return ts.factory.createArrayLiteralExpression(elements);
}

export function typeOperatorNode(
operator: "KeyOfKeyword" | "UniqueKeyword" | "ReadonlyKeyword",
node: ts.TypeNode
): ts.TypeOperatorNode {
return ts.factory.createTypeOperatorNode(ts.SyntaxKind[operator], node);
}

module.exports = {
modifier: modifier,
identifier: identifier,
Expand All @@ -258,4 +265,5 @@ module.exports = {
variableDeclaration: variableDeclaration,
variableDeclarationList: variableDeclarationList,
arrayLiteral: arrayLiteral,
typeOperatorNode: typeOperatorNode,
};

0 comments on commit 3fbd5df

Please sign in to comment.