vendor tsgo
This commit is contained in:
390
tools/tsgo/internal/transformers/tstransforms/metadata.go
Normal file
390
tools/tsgo/internal/transformers/tstransforms/metadata.go
Normal file
@@ -0,0 +1,390 @@
|
||||
package tstransforms
|
||||
|
||||
import (
|
||||
"github.com/microsoft/typescript-go/internal/ast"
|
||||
"github.com/microsoft/typescript-go/internal/core"
|
||||
"github.com/microsoft/typescript-go/internal/printer"
|
||||
"github.com/microsoft/typescript-go/internal/transformers"
|
||||
)
|
||||
|
||||
const USE_NEW_TYPE_METADATA_FORMAT = false
|
||||
|
||||
type MetadataTransformer struct {
|
||||
transformers.Transformer
|
||||
legacyDecorators bool
|
||||
resolver printer.EmitResolver
|
||||
|
||||
serializer *metadataSerializer
|
||||
languageVersion core.ScriptTarget
|
||||
strictNullChecks bool
|
||||
parent *ast.Node
|
||||
currentLexicalScope *ast.Node
|
||||
}
|
||||
|
||||
func NewMetadataTransformer(opt *transformers.TransformOptions) *transformers.Transformer {
|
||||
tx := &MetadataTransformer{
|
||||
legacyDecorators: opt.CompilerOptions.ExperimentalDecorators.IsTrue(),
|
||||
resolver: opt.EmitResolver,
|
||||
languageVersion: opt.CompilerOptions.GetEmitScriptTarget(),
|
||||
strictNullChecks: opt.CompilerOptions.GetStrictOptionValue(opt.CompilerOptions.StrictNullChecks),
|
||||
}
|
||||
return tx.NewTransformer(tx.visit, opt.Context)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visit(node *ast.Node) *ast.Node {
|
||||
if (node.SubtreeFacts() & ast.SubtreeContainsDecorators) == 0 {
|
||||
return node
|
||||
}
|
||||
|
||||
switch node.Kind {
|
||||
case ast.KindClassDeclaration:
|
||||
return tx.visitClassDeclaration(node.AsClassDeclaration())
|
||||
case ast.KindClassExpression:
|
||||
return tx.visitClassExpression(node.AsClassExpression())
|
||||
case ast.KindPropertyDeclaration:
|
||||
return tx.visitPropertyDeclaration(node.AsPropertyDeclaration())
|
||||
case ast.KindMethodDeclaration:
|
||||
return tx.visitMethodDeclaration(node.AsMethodDeclaration())
|
||||
case ast.KindSetAccessor:
|
||||
return tx.visitSetAccessor(node.AsSetAccessorDeclaration())
|
||||
case ast.KindGetAccessor:
|
||||
return tx.visitGetAccessor(node.AsGetAccessorDeclaration())
|
||||
case ast.KindSourceFile:
|
||||
tx.parent = nil
|
||||
defer tx.setParent(nil)
|
||||
tx.currentLexicalScope = node
|
||||
defer tx.setCurrentLexicalScope(nil)
|
||||
tx.serializer = newMetadataSerializer(tx.resolver, tx.Factory(), tx.EmitContext(), tx.languageVersion, tx.strictNullChecks)
|
||||
updated := tx.Visitor().VisitEachChild(node)
|
||||
tx.EmitContext().AddEmitHelper(updated, tx.EmitContext().ReadEmitHelpers()...)
|
||||
return updated
|
||||
case ast.KindModuleBlock, ast.KindBlock, ast.KindCaseBlock:
|
||||
oldScope := tx.currentLexicalScope
|
||||
tx.currentLexicalScope = node
|
||||
defer tx.setCurrentLexicalScope(oldScope)
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
default:
|
||||
return tx.Visitor().VisitEachChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) setParent(node *ast.Node) {
|
||||
tx.parent = node
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) setCurrentLexicalScope(node *ast.Node) {
|
||||
tx.currentLexicalScope = node
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visitClassExpression(node *ast.ClassExpression) *ast.Node {
|
||||
oldParent := tx.parent
|
||||
tx.parent = node.AsNode()
|
||||
defer tx.setParent(oldParent)
|
||||
|
||||
if !ast.ClassOrConstructorParameterIsDecorated(tx.legacyDecorators, node.AsNode()) {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
modifiers := tx.injectClassTypeMetadata(tx.Visitor().VisitModifiers(node.Modifiers()), node.AsNode())
|
||||
return tx.Factory().UpdateClassExpression(
|
||||
node,
|
||||
modifiers,
|
||||
tx.Visitor().VisitNode(node.Name()),
|
||||
tx.Visitor().VisitNodes(node.TypeParameters),
|
||||
tx.Visitor().VisitNodes(node.HeritageClauses),
|
||||
tx.Visitor().VisitNodes(node.Members),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visitClassDeclaration(node *ast.ClassDeclaration) *ast.Node {
|
||||
oldParent := tx.parent
|
||||
tx.parent = node.AsNode()
|
||||
defer tx.setParent(oldParent)
|
||||
|
||||
if !ast.ClassOrConstructorParameterIsDecorated(tx.legacyDecorators, node.AsNode()) {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
modifiers := tx.injectClassTypeMetadata(tx.Visitor().VisitModifiers(node.Modifiers()), node.AsNode())
|
||||
return tx.Factory().UpdateClassDeclaration(
|
||||
node,
|
||||
modifiers,
|
||||
tx.Visitor().VisitNode(node.Name()),
|
||||
tx.Visitor().VisitNodes(node.TypeParameters),
|
||||
tx.Visitor().VisitNodes(node.HeritageClauses),
|
||||
tx.Visitor().VisitNodes(node.Members),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visitPropertyDeclaration(node *ast.PropertyDeclaration) *ast.Node {
|
||||
if !ast.HasDecorators(node.AsNode()) {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
modifiers := tx.injectClassElementTypeMetadata(tx.Visitor().VisitModifiers(node.Modifiers()), node.AsNode(), tx.parent)
|
||||
return tx.Factory().UpdatePropertyDeclaration(
|
||||
node,
|
||||
modifiers,
|
||||
tx.Visitor().VisitNode(node.Name()),
|
||||
tx.Visitor().VisitNode(node.PostfixToken),
|
||||
tx.Visitor().VisitNode(node.Type),
|
||||
tx.Visitor().VisitNode(node.Initializer),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visitMethodDeclaration(node *ast.MethodDeclaration) *ast.Node {
|
||||
if !ast.HasDecorators(node.AsNode()) && len(getDecoratorsOfParameters(node.AsNode())) == 0 {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
modifiers := tx.injectClassElementTypeMetadata(tx.Visitor().VisitModifiers(node.Modifiers()), node.AsNode(), tx.parent)
|
||||
return tx.Factory().UpdateMethodDeclaration(
|
||||
node,
|
||||
modifiers,
|
||||
tx.Visitor().VisitNode(node.AsteriskToken),
|
||||
tx.Visitor().VisitNode(node.Name()),
|
||||
tx.Visitor().VisitNode(node.PostfixToken),
|
||||
tx.Visitor().VisitNodes(node.TypeParameters),
|
||||
tx.Visitor().VisitNodes(node.Parameters),
|
||||
tx.Visitor().VisitNode(node.Type),
|
||||
tx.Visitor().VisitNode(node.FullSignature),
|
||||
tx.Visitor().VisitNode(node.Body),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visitSetAccessor(node *ast.SetAccessorDeclaration) *ast.Node {
|
||||
if !ast.HasDecorators(node.AsNode()) && len(getDecoratorsOfParameters(node.AsNode())) == 0 {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
modifiers := tx.injectClassElementTypeMetadata(tx.Visitor().VisitModifiers(node.Modifiers()), node.AsNode(), tx.parent)
|
||||
return tx.Factory().UpdateSetAccessorDeclaration(
|
||||
node,
|
||||
modifiers,
|
||||
tx.Visitor().VisitNode(node.Name()),
|
||||
tx.Visitor().VisitNodes(node.TypeParameters),
|
||||
tx.Visitor().VisitNodes(node.Parameters),
|
||||
tx.Visitor().VisitNode(node.Type),
|
||||
tx.Visitor().VisitNode(node.FullSignature),
|
||||
tx.Visitor().VisitNode(node.Body),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) visitGetAccessor(node *ast.GetAccessorDeclaration) *ast.Node {
|
||||
if !ast.HasDecorators(node.AsNode()) {
|
||||
return tx.Visitor().VisitEachChild(node.AsNode())
|
||||
}
|
||||
|
||||
modifiers := tx.injectClassElementTypeMetadata(tx.Visitor().VisitModifiers(node.Modifiers()), node.AsNode(), tx.parent)
|
||||
return tx.Factory().UpdateGetAccessorDeclaration(
|
||||
node,
|
||||
modifiers,
|
||||
tx.Visitor().VisitNode(node.Name()),
|
||||
tx.Visitor().VisitNodes(node.TypeParameters),
|
||||
tx.Visitor().VisitNodes(node.Parameters),
|
||||
tx.Visitor().VisitNode(node.Type),
|
||||
tx.Visitor().VisitNode(node.FullSignature),
|
||||
tx.Visitor().VisitNode(node.Body),
|
||||
)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) injectClassTypeMetadata(list *ast.ModifierList, node *ast.Node) *ast.ModifierList {
|
||||
metadata := tx.getTypeMetadata(node, node)
|
||||
if len(metadata) > 0 {
|
||||
var originalNodes []*ast.Node
|
||||
if list != nil {
|
||||
originalNodes = list.Nodes
|
||||
}
|
||||
if len(originalNodes) == 0 {
|
||||
res := tx.Factory().NewModifierList(metadata)
|
||||
if list != nil {
|
||||
res.Loc = list.Loc
|
||||
}
|
||||
return res
|
||||
}
|
||||
var modifiersArray []*ast.Node
|
||||
if ast.IsModifier(originalNodes[0]) && (originalNodes[0].Kind == ast.KindDefaultKeyword || originalNodes[0].Kind == ast.KindExportKeyword) {
|
||||
modifiersArray = append(modifiersArray, originalNodes[0])
|
||||
if len(originalNodes) > 1 && (originalNodes[1].Kind == ast.KindDefaultKeyword || originalNodes[1].Kind == ast.KindExportKeyword) {
|
||||
modifiersArray = append(modifiersArray, originalNodes[1])
|
||||
}
|
||||
}
|
||||
restStart := len(modifiersArray)
|
||||
decos := core.Filter(originalNodes, ast.IsDecorator)
|
||||
modifiersArray = append(modifiersArray, decos...)
|
||||
modifiersArray = append(modifiersArray, metadata...)
|
||||
otherModifiers := core.Filter(originalNodes[restStart:], ast.IsModifier)
|
||||
modifiersArray = append(modifiersArray, otherModifiers...)
|
||||
res := tx.Factory().NewModifierList(modifiersArray)
|
||||
res.Loc = list.Loc
|
||||
return res
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) injectClassElementTypeMetadata(list *ast.ModifierList, node *ast.Node, container *ast.Node) *ast.ModifierList {
|
||||
if !ast.IsClassLike(container) {
|
||||
return list
|
||||
}
|
||||
if !ast.ClassElementOrClassElementParameterIsDecorated(tx.legacyDecorators, node, container) {
|
||||
return list
|
||||
}
|
||||
metadata := tx.getTypeMetadata(node, container)
|
||||
if len(metadata) > 0 {
|
||||
var originalNodes []*ast.Node
|
||||
if list != nil {
|
||||
originalNodes = list.Nodes
|
||||
}
|
||||
if len(originalNodes) == 0 {
|
||||
res := tx.Factory().NewModifierList(metadata)
|
||||
if list != nil {
|
||||
res.Loc = list.Loc
|
||||
}
|
||||
return res
|
||||
}
|
||||
var modifiersArray []*ast.Node
|
||||
decos := core.Filter(originalNodes, ast.IsDecorator)
|
||||
modifiersArray = append(modifiersArray, decos...)
|
||||
modifiersArray = append(modifiersArray, metadata...)
|
||||
modifiers := core.Filter(originalNodes, ast.IsModifier)
|
||||
modifiersArray = append(modifiersArray, modifiers...)
|
||||
res := tx.Factory().NewModifierList(modifiersArray)
|
||||
res.Loc = list.Loc
|
||||
return res
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets optional type metadata for a declaration.
|
||||
*
|
||||
* @param node The declaration node.
|
||||
*/
|
||||
func (tx *MetadataTransformer) getTypeMetadata(node *ast.Node, container *ast.Node) []*ast.Node {
|
||||
// Decorator metadata is not yet supported for ES decorators.
|
||||
if !tx.legacyDecorators {
|
||||
return nil
|
||||
}
|
||||
if USE_NEW_TYPE_METADATA_FORMAT {
|
||||
return tx.getNewTypeMetadata(node, container)
|
||||
}
|
||||
return tx.getOldTypeMetadata(node, container)
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) getOldTypeMetadata(node *ast.Node, container *ast.Node) []*ast.Node {
|
||||
var decorators []*ast.Node
|
||||
if tx.shouldAddTypeMetadata(node) {
|
||||
typeMetadata := tx.Factory().NewMetadataHelper("design:type", tx.serializer.SerializeTypeOfNode(metadataSerializerContext{currentLexicalScope: tx.currentLexicalScope, currentNameScope: container}, node, container))
|
||||
decorators = append(decorators, tx.Factory().NewDecorator(typeMetadata))
|
||||
}
|
||||
if tx.shouldAddParamTypesMetadata(node) {
|
||||
paramTypesMetadata := tx.Factory().NewMetadataHelper("design:paramtypes", tx.serializer.SerializeParameterTypesOfNode(metadataSerializerContext{currentLexicalScope: tx.currentLexicalScope, currentNameScope: container}, node, container))
|
||||
decorators = append(decorators, tx.Factory().NewDecorator(paramTypesMetadata))
|
||||
}
|
||||
if tx.shouldAddReturnTypeMetadata(node) {
|
||||
returnTypeMetadata := tx.Factory().NewMetadataHelper("design:returntype", tx.serializer.SerializeReturnTypeOfNode(metadataSerializerContext{currentLexicalScope: tx.currentLexicalScope, currentNameScope: container}, node))
|
||||
decorators = append(decorators, tx.Factory().NewDecorator(returnTypeMetadata))
|
||||
}
|
||||
return decorators
|
||||
}
|
||||
|
||||
func (tx *MetadataTransformer) getNewTypeMetadata(node *ast.Node, container *ast.Node) []*ast.Node {
|
||||
var properties []*ast.Node
|
||||
if tx.shouldAddTypeMetadata(node) {
|
||||
properties = append(properties, tx.Factory().NewPropertyAssignment(
|
||||
nil,
|
||||
tx.Factory().NewIdentifier("type"),
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewArrowFunction(
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewNodeList([]*ast.Node{}),
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewToken(ast.KindEqualsGreaterThanToken),
|
||||
tx.serializer.SerializeTypeOfNode(metadataSerializerContext{currentLexicalScope: tx.currentLexicalScope, currentNameScope: container}, node, container),
|
||||
),
|
||||
))
|
||||
}
|
||||
if tx.shouldAddParamTypesMetadata(node) {
|
||||
properties = append(properties, tx.Factory().NewPropertyAssignment(
|
||||
nil,
|
||||
tx.Factory().NewIdentifier("paramTypes"),
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewArrowFunction(
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewNodeList([]*ast.Node{}),
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewToken(ast.KindEqualsGreaterThanToken),
|
||||
tx.serializer.SerializeParameterTypesOfNode(metadataSerializerContext{currentLexicalScope: tx.currentLexicalScope, currentNameScope: container}, node, container),
|
||||
),
|
||||
))
|
||||
}
|
||||
if tx.shouldAddReturnTypeMetadata(node) {
|
||||
properties = append(properties, tx.Factory().NewPropertyAssignment(
|
||||
nil,
|
||||
tx.Factory().NewIdentifier("returnType"),
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewArrowFunction(
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewNodeList([]*ast.Node{}),
|
||||
nil,
|
||||
nil,
|
||||
tx.Factory().NewToken(ast.KindEqualsGreaterThanToken),
|
||||
tx.serializer.SerializeReturnTypeOfNode(metadataSerializerContext{currentLexicalScope: tx.currentLexicalScope, currentNameScope: container}, node),
|
||||
),
|
||||
))
|
||||
}
|
||||
if len(properties) > 0 {
|
||||
typeInfoMetadata := tx.Factory().NewMetadataHelper("design:typeinfo", tx.Factory().NewObjectLiteralExpression(tx.Factory().NewNodeList(properties), true))
|
||||
return []*ast.Node{tx.Factory().NewDecorator(typeInfoMetadata)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to emit the "design:type" metadata based on the node's kind.
|
||||
* The caller should have already tested whether the node has decorators and whether the
|
||||
* emitDecoratorMetadata compiler option is set.
|
||||
*
|
||||
* @param node The node to test.
|
||||
*/
|
||||
func (tx *MetadataTransformer) shouldAddTypeMetadata(node *ast.Node) bool {
|
||||
switch node.Kind {
|
||||
case ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindPropertyDeclaration:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to emit the "design:returntype" metadata based on the node's kind.
|
||||
* The caller should have already tested whether the node has decorators and whether the
|
||||
* emitDecoratorMetadata compiler option is set.
|
||||
*
|
||||
* @param node The node to test.
|
||||
*/
|
||||
func (tx *MetadataTransformer) shouldAddReturnTypeMetadata(node *ast.Node) bool {
|
||||
return node.Kind == ast.KindMethodDeclaration
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to emit the "design:paramtypes" metadata based on the node's kind.
|
||||
* The caller should have already tested whether the node has decorators and whether the
|
||||
* emitDecoratorMetadata compiler option is set.
|
||||
*
|
||||
* @param node The node to test.
|
||||
*/
|
||||
func (tx *MetadataTransformer) shouldAddParamTypesMetadata(node *ast.Node) bool {
|
||||
switch node.Kind {
|
||||
case ast.KindClassDeclaration, ast.KindClassExpression:
|
||||
return ast.GetFirstConstructorWithBody(node) != nil
|
||||
case ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user