511 lines
20 KiB
Go
511 lines
20 KiB
Go
package transformers
|
|
|
|
import (
|
|
"slices"
|
|
"strconv"
|
|
|
|
"github.com/microsoft/typescript-go/internal/ast"
|
|
"github.com/microsoft/typescript-go/internal/core"
|
|
)
|
|
|
|
// FlattenLevel controls how deeply binding/assignment patterns are decomposed.
|
|
type FlattenLevel int
|
|
|
|
const (
|
|
FlattenLevelAll FlattenLevel = iota // Fully decompose all patterns into individual assignments/bindings
|
|
FlattenLevelObjectRest // Only decompose patterns containing object rest elements
|
|
)
|
|
|
|
// CreateAssignmentCallback is a callback used to create custom assignment expressions during destructuring flattening.
|
|
// When provided, the target will always be an Identifier, and the callback can wrap the assignment with additional logic
|
|
// (e.g., export expressions in CJS modules or namespace member assignments).
|
|
type CreateAssignmentCallback func(name *ast.IdentifierNode, value *ast.Expression, location *core.TextRange) *ast.Expression
|
|
|
|
// FlattenDestructuringAssignment flattens a destructuring assignment expression into a sequence of
|
|
// individual property/element access assignments. Supports custom assignment callbacks for module
|
|
// export or namespace member expressions.
|
|
func FlattenDestructuringAssignment(
|
|
tx *Transformer,
|
|
node *ast.Node, // VariableDeclaration | DestructuringAssignment
|
|
needsValue bool,
|
|
level FlattenLevel,
|
|
createAssignmentCallback CreateAssignmentCallback,
|
|
) *ast.Expression {
|
|
f := newFlattener(tx, level)
|
|
f.createAssignmentCallback = createAssignmentCallback
|
|
f.hoistTempVariables = true
|
|
// Assignment mode callbacks
|
|
f.emitBindingOrAssignment = (*flattener).emitAssignment
|
|
f.createArrayBindingOrAssignmentPattern = (*flattener).createArrayAssignmentPattern
|
|
f.createObjectBindingOrAssignmentPattern = (*flattener).createObjectAssignmentPattern
|
|
f.createArrayBindingOrAssignmentElement = (*flattener).createArrayAssignmentElement
|
|
return f.flattenDestructuringAssignment(node, needsValue)
|
|
}
|
|
|
|
// pendingDecl tracks a pending variable declaration during binding flattening.
|
|
type pendingDecl struct {
|
|
pendingExpressions []*ast.Node
|
|
name *ast.Node
|
|
value *ast.Node
|
|
location core.TextRange
|
|
original *ast.Node
|
|
}
|
|
|
|
// FlattenDestructuringBinding flattens a binding pattern in a variable declaration or parameter
|
|
// into individual variable declarations. Returns a single VariableDeclaration, a SyntaxList of
|
|
// declarations, or nil.
|
|
func FlattenDestructuringBinding(
|
|
tx *Transformer,
|
|
node *ast.Node, // VariableDeclaration | ParameterDeclaration | BindingElement
|
|
rval *ast.Node,
|
|
level FlattenLevel,
|
|
hoistTempVariables bool,
|
|
skipInitializer bool,
|
|
) *ast.Node {
|
|
f := newFlattener(tx, level)
|
|
f.hoistTempVariables = hoistTempVariables
|
|
// Binding mode callbacks
|
|
f.emitBindingOrAssignment = (*flattener).emitBinding
|
|
f.createArrayBindingOrAssignmentPattern = (*flattener).createArrayBindingPattern
|
|
f.createObjectBindingOrAssignmentPattern = (*flattener).createObjectBindingPattern
|
|
f.createArrayBindingOrAssignmentElement = (*flattener).createArrayBindingElement
|
|
return f.flattenDestructuringBinding(node, rval, skipInitializer)
|
|
}
|
|
|
|
// flattener encapsulates the state and logic for flattening destructuring patterns.
|
|
// It is equivalent to TypeScript's FlattenContext in destructuring.ts.
|
|
type flattener struct {
|
|
tx *Transformer
|
|
level FlattenLevel
|
|
|
|
createAssignmentCallback CreateAssignmentCallback
|
|
|
|
// State
|
|
expressions []*ast.Node
|
|
declarations []pendingDecl
|
|
hasTransformedPriorElement bool
|
|
hoistTempVariables bool
|
|
|
|
// Mode callbacks (set by FlattenDestructuringAssignment or FlattenDestructuringBinding)
|
|
emitBindingOrAssignment func(f *flattener, target *ast.Node, value *ast.Node, location core.TextRange, original *ast.Node)
|
|
createArrayBindingOrAssignmentPattern func(f *flattener, elements []*ast.Node) *ast.Node
|
|
createObjectBindingOrAssignmentPattern func(f *flattener, elements []*ast.Node) *ast.Node
|
|
createArrayBindingOrAssignmentElement func(f *flattener, expr *ast.Node) *ast.Node
|
|
}
|
|
|
|
func newFlattener(tx *Transformer, level FlattenLevel) *flattener {
|
|
return &flattener{
|
|
tx: tx,
|
|
level: level,
|
|
}
|
|
}
|
|
|
|
// --- Assignment mode callbacks ---
|
|
|
|
func (f *flattener) createArrayAssignmentPattern(elements []*ast.Node) *ast.Node {
|
|
return f.tx.Factory().NewArrayLiteralExpression(f.tx.Factory().NewNodeList(elements), false)
|
|
}
|
|
|
|
func (f *flattener) createObjectAssignmentPattern(elements []*ast.Node) *ast.Node {
|
|
return f.tx.Factory().NewObjectLiteralExpression(f.tx.Factory().NewNodeList(elements), false)
|
|
}
|
|
|
|
func (f *flattener) createArrayAssignmentElement(expr *ast.Node) *ast.Node {
|
|
return expr
|
|
}
|
|
|
|
func (f *flattener) emitAssignment(target *ast.Node, value *ast.Node, location core.TextRange, original *ast.Node) {
|
|
var expression *ast.Expression
|
|
if f.createAssignmentCallback != nil && ast.IsIdentifier(target) {
|
|
expression = f.createAssignmentCallback(target, value, &location)
|
|
} else {
|
|
expression = f.tx.Factory().NewAssignmentExpression(f.tx.Visitor().VisitNode(target), value)
|
|
expression.Loc = location
|
|
}
|
|
f.tx.EmitContext().SetOriginal(expression, original)
|
|
f.emitExpression(expression)
|
|
}
|
|
|
|
// --- Binding mode callbacks ---
|
|
|
|
func (f *flattener) createArrayBindingPattern(elements []*ast.Node) *ast.Node {
|
|
return f.tx.Factory().NewBindingPattern(ast.KindArrayBindingPattern, f.tx.Factory().NewNodeList(elements))
|
|
}
|
|
|
|
func (f *flattener) createObjectBindingPattern(elements []*ast.Node) *ast.Node {
|
|
return f.tx.Factory().NewBindingPattern(ast.KindObjectBindingPattern, f.tx.Factory().NewNodeList(elements))
|
|
}
|
|
|
|
func (f *flattener) createArrayBindingElement(expr *ast.Node) *ast.Node {
|
|
return f.tx.Factory().NewBindingElement(nil, nil, expr, nil)
|
|
}
|
|
|
|
func (f *flattener) emitBinding(target *ast.Node, value *ast.Node, location core.TextRange, original *ast.Node) {
|
|
if len(f.expressions) > 0 {
|
|
value = f.tx.Factory().InlineExpressions(append(f.expressions, value))
|
|
f.expressions = nil
|
|
}
|
|
f.declarations = append(f.declarations, pendingDecl{
|
|
name: target,
|
|
value: value,
|
|
location: location,
|
|
original: original,
|
|
})
|
|
}
|
|
|
|
// --- Shared helpers ---
|
|
|
|
func (f *flattener) emitExpression(expr *ast.Node) {
|
|
f.expressions = append(f.expressions, expr)
|
|
}
|
|
|
|
func (f *flattener) ensureIdentifier(value *ast.Node, reuseIdentifierExpressions bool, location core.TextRange) *ast.Node {
|
|
if reuseIdentifierExpressions && ast.IsIdentifier(value) {
|
|
return value
|
|
}
|
|
temp := f.tx.Factory().NewTempVariable()
|
|
if f.hoistTempVariables {
|
|
f.tx.EmitContext().AddVariableDeclaration(temp)
|
|
assign := f.tx.Factory().NewAssignmentExpression(temp, value)
|
|
assign.Loc = location
|
|
f.emitExpression(assign)
|
|
} else {
|
|
f.emitBindingOrAssignment(f, temp, value, location, nil)
|
|
}
|
|
return temp
|
|
}
|
|
|
|
func (f *flattener) createDefaultValueCheck(value *ast.Expression, defaultValue *ast.Expression, location core.TextRange) *ast.Node {
|
|
value = f.ensureIdentifier(value, true, location)
|
|
return f.tx.Factory().NewConditionalExpression(
|
|
f.tx.Factory().NewTypeCheck(value, "undefined"),
|
|
f.tx.Factory().NewToken(ast.KindQuestionToken),
|
|
defaultValue,
|
|
f.tx.Factory().NewToken(ast.KindColonToken),
|
|
value,
|
|
)
|
|
}
|
|
|
|
func (f *flattener) createDestructuringPropertyAccess(value *ast.Node, propertyName *ast.Node) *ast.Node {
|
|
if ast.IsComputedPropertyName(propertyName) {
|
|
argumentExpression := f.ensureIdentifier(f.tx.Visitor().VisitNode(propertyName.Expression()), false, propertyName.Loc)
|
|
return f.tx.Factory().NewElementAccessExpression(value, nil, argumentExpression, ast.NodeFlagsNone)
|
|
} else if ast.IsStringOrNumericLiteralLike(propertyName) || ast.IsBigIntLiteral(propertyName) {
|
|
argumentExpression := propertyName.Clone(f.tx.Factory())
|
|
return f.tx.Factory().NewElementAccessExpression(value, nil, argumentExpression, ast.NodeFlagsNone)
|
|
} else {
|
|
name := f.tx.Factory().NewIdentifier(propertyName.Text())
|
|
return f.tx.Factory().NewPropertyAccessExpression(value, nil, name, ast.NodeFlagsNone)
|
|
}
|
|
}
|
|
|
|
// --- Entry points ---
|
|
|
|
func (f *flattener) flattenDestructuringAssignment(node *ast.Node, needsValue bool) *ast.Expression {
|
|
location := node.Loc
|
|
var value *ast.Node
|
|
if ast.IsDestructuringAssignment(node) {
|
|
value = node.AsBinaryExpression().Right
|
|
for ast.IsEmptyArrayLiteral(node.AsBinaryExpression().Left) || ast.IsEmptyObjectLiteral(node.AsBinaryExpression().Left) {
|
|
if ast.IsDestructuringAssignment(value) {
|
|
node = value
|
|
location = node.Loc
|
|
value = node.AsBinaryExpression().Right
|
|
} else {
|
|
return f.tx.Visitor().VisitNode(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
if value != nil {
|
|
value = f.tx.Visitor().VisitNode(value)
|
|
if ast.IsIdentifier(value) && BindingOrAssignmentElementAssignsToName(node, value.Text()) || BindingOrAssignmentElementContainsNonLiteralComputedName(node) {
|
|
value = f.ensureIdentifier(value, false, location)
|
|
} else if needsValue {
|
|
value = f.ensureIdentifier(value, true, location)
|
|
} else if ast.NodeIsSynthesized(node) {
|
|
location = value.Loc
|
|
}
|
|
}
|
|
|
|
f.flattenBindingOrAssignmentElement(node, value, location, ast.IsDestructuringAssignment(node))
|
|
|
|
if value != nil && needsValue {
|
|
if len(f.expressions) == 0 {
|
|
return value
|
|
}
|
|
f.expressions = append(f.expressions, value)
|
|
}
|
|
|
|
res := f.tx.Factory().InlineExpressions(f.expressions)
|
|
if res != nil {
|
|
return res
|
|
}
|
|
return f.tx.Factory().NewOmittedExpression()
|
|
}
|
|
|
|
func (f *flattener) flattenDestructuringBinding(node *ast.Node, rval *ast.Node, skipInitializer bool) *ast.Node {
|
|
if ast.IsVariableDeclaration(node) {
|
|
initializer := GetInitializerOfBindingOrAssignmentElement(node)
|
|
if initializer != nil && (ast.IsIdentifier(initializer) && BindingOrAssignmentElementAssignsToName(node, initializer.Text()) || BindingOrAssignmentElementContainsNonLiteralComputedName(node)) {
|
|
initializer = f.ensureIdentifier(f.tx.Visitor().VisitNode(initializer), false, initializer.Loc)
|
|
node = f.tx.Factory().UpdateVariableDeclaration(node.AsVariableDeclaration(), node.Name(), nil, nil, initializer)
|
|
}
|
|
}
|
|
|
|
f.flattenBindingOrAssignmentElement(node, rval, node.Loc, skipInitializer)
|
|
|
|
if len(f.expressions) > 0 {
|
|
temp := f.tx.Factory().NewTempVariable()
|
|
if f.hoistTempVariables {
|
|
value := f.tx.Factory().InlineExpressions(f.expressions)
|
|
f.expressions = nil
|
|
f.emitBindingOrAssignment(f, temp, value, core.TextRange{}, nil)
|
|
} else {
|
|
f.tx.EmitContext().AddVariableDeclaration(temp)
|
|
last := &f.declarations[len(f.declarations)-1]
|
|
last.pendingExpressions = append(last.pendingExpressions, f.tx.Factory().NewAssignmentExpression(temp, last.value))
|
|
last.pendingExpressions = append(last.pendingExpressions, f.expressions...)
|
|
last.value = temp
|
|
}
|
|
}
|
|
|
|
decls := make([]*ast.Node, 0, len(f.declarations))
|
|
for _, pending := range f.declarations {
|
|
expr := pending.value
|
|
if len(pending.pendingExpressions) > 0 {
|
|
expr = f.tx.Factory().InlineExpressions(append(pending.pendingExpressions, pending.value))
|
|
}
|
|
decl := f.tx.Factory().NewVariableDeclaration(pending.name, nil, nil, expr)
|
|
decl.Loc = pending.location
|
|
if pending.original != nil {
|
|
f.tx.EmitContext().SetOriginal(decl, pending.original)
|
|
}
|
|
decls = append(decls, decl)
|
|
}
|
|
|
|
if len(decls) == 1 {
|
|
return decls[0]
|
|
}
|
|
if len(decls) == 0 {
|
|
return nil
|
|
}
|
|
return f.tx.Factory().NewSyntaxList(decls)
|
|
}
|
|
|
|
// --- Core flattening ---
|
|
|
|
func (f *flattener) flattenBindingOrAssignmentElement(element *ast.Node, value *ast.Node, location core.TextRange, skipInitializer bool) {
|
|
bindingTarget := ast.GetTargetOfBindingOrAssignmentElement(element)
|
|
if bindingTarget == nil {
|
|
return
|
|
}
|
|
if !skipInitializer {
|
|
initializer := f.tx.Visitor().VisitNode(GetInitializerOfBindingOrAssignmentElement(element))
|
|
if initializer != nil {
|
|
if value != nil {
|
|
value = f.createDefaultValueCheck(value, initializer, location)
|
|
if !IsSimpleCopiableExpression(initializer) && (ast.IsBindingPattern(bindingTarget) || ast.IsAssignmentPattern(bindingTarget)) {
|
|
value = f.ensureIdentifier(value, true, location)
|
|
}
|
|
} else {
|
|
value = initializer
|
|
}
|
|
} else if value == nil {
|
|
value = f.tx.Factory().NewVoidZeroExpression()
|
|
}
|
|
}
|
|
|
|
if isObjectBindingOrAssignmentPattern(bindingTarget) {
|
|
f.flattenObjectBindingOrAssignmentPattern(element, bindingTarget, value, location)
|
|
} else if isArrayBindingOrAssignmentPattern(bindingTarget) {
|
|
f.flattenArrayBindingOrAssignmentPattern(element, bindingTarget, value, location)
|
|
} else {
|
|
f.emitBindingOrAssignment(f, bindingTarget, value, location, element)
|
|
}
|
|
}
|
|
|
|
func (f *flattener) flattenObjectBindingOrAssignmentPattern(parent *ast.Node, pattern *ast.Node, value *ast.Node, location core.TextRange) {
|
|
elements := ast.GetElementsOfBindingOrAssignmentPattern(pattern)
|
|
numElements := len(elements)
|
|
if numElements != 1 {
|
|
reuseIdentifierExpressions := !ast.IsDeclarationBindingElement(parent) || numElements != 0
|
|
value = f.ensureIdentifier(value, reuseIdentifierExpressions, location)
|
|
}
|
|
var bindingElements []*ast.Node
|
|
var computedTempVariables []*ast.Node
|
|
for i, element := range elements {
|
|
if ast.GetRestIndicatorOfBindingOrAssignmentElement(element) == nil {
|
|
propertyName := ast.TryGetPropertyNameOfBindingOrAssignmentElement(element)
|
|
if f.level >= FlattenLevelObjectRest &&
|
|
element.SubtreeFacts()&(ast.SubtreeContainsRestOrSpread|ast.SubtreeContainsObjectRestOrSpread) == 0 &&
|
|
ast.GetTargetOfBindingOrAssignmentElement(element).SubtreeFacts()&(ast.SubtreeContainsRestOrSpread|ast.SubtreeContainsObjectRestOrSpread) == 0 &&
|
|
!ast.IsComputedPropertyName(propertyName) {
|
|
bindingElements = append(bindingElements, f.tx.Visitor().VisitNode(element))
|
|
} else {
|
|
if len(bindingElements) > 0 {
|
|
f.emitBindingOrAssignment(f, f.createObjectBindingOrAssignmentPattern(f, bindingElements), value, location, pattern)
|
|
bindingElements = nil
|
|
}
|
|
rhsValue := f.createDestructuringPropertyAccess(value, propertyName)
|
|
if ast.IsComputedPropertyName(propertyName) {
|
|
computedTempVariables = append(computedTempVariables, rhsValue.AsElementAccessExpression().ArgumentExpression)
|
|
}
|
|
f.flattenBindingOrAssignmentElement(element, rhsValue, element.Loc, false)
|
|
}
|
|
} else if i == numElements-1 {
|
|
if len(bindingElements) > 0 {
|
|
f.emitBindingOrAssignment(f, f.createObjectBindingOrAssignmentPattern(f, bindingElements), value, location, pattern)
|
|
bindingElements = nil
|
|
}
|
|
rhsValue := f.tx.Factory().NewRestHelper(value, elements, computedTempVariables, pattern.Loc)
|
|
f.flattenBindingOrAssignmentElement(element, rhsValue, element.Loc, false)
|
|
}
|
|
}
|
|
if len(bindingElements) > 0 {
|
|
f.emitBindingOrAssignment(f, f.createObjectBindingOrAssignmentPattern(f, bindingElements), value, location, pattern)
|
|
}
|
|
}
|
|
|
|
type restIdElemPair struct {
|
|
id *ast.Node
|
|
element *ast.Node
|
|
}
|
|
|
|
func (f *flattener) flattenArrayBindingOrAssignmentPattern(parent *ast.Node, pattern *ast.Node, value *ast.Node, location core.TextRange) {
|
|
elements := ast.GetElementsOfBindingOrAssignmentPattern(pattern)
|
|
numElements := len(elements)
|
|
if numElements != 1 && (f.level < FlattenLevelObjectRest || numElements == 0) || core.Every(elements, ast.IsOmittedExpression) {
|
|
reuseIdentifierExpressions := !ast.IsDeclarationBindingElement(parent) || numElements != 0
|
|
value = f.ensureIdentifier(value, reuseIdentifierExpressions, location)
|
|
}
|
|
var bindingElements []*ast.Node
|
|
var restContainingElements []restIdElemPair
|
|
for i, element := range elements {
|
|
if f.level >= FlattenLevelObjectRest {
|
|
if element.SubtreeFacts()&ast.SubtreeContainsObjectRestOrSpread != 0 || f.hasTransformedPriorElement && !isSimpleBindingOrAssignmentElement(element) {
|
|
f.hasTransformedPriorElement = true
|
|
temp := f.tx.Factory().NewTempVariable()
|
|
if f.hoistTempVariables {
|
|
f.tx.EmitContext().AddVariableDeclaration(temp)
|
|
}
|
|
restContainingElements = append(restContainingElements, restIdElemPair{temp, element})
|
|
bindingElements = append(bindingElements, f.createArrayBindingOrAssignmentElement(f, temp))
|
|
} else {
|
|
bindingElements = append(bindingElements, element)
|
|
}
|
|
} else if ast.IsOmittedExpression(element) {
|
|
continue
|
|
} else if ast.GetRestIndicatorOfBindingOrAssignmentElement(element) == nil {
|
|
rhsValue := f.tx.Factory().NewElementAccessExpression(value, nil, f.tx.Factory().NewNumericLiteral(strconv.Itoa(i), ast.TokenFlagsNone), ast.NodeFlagsNone)
|
|
f.flattenBindingOrAssignmentElement(element, rhsValue, element.Loc, false)
|
|
} else if i == numElements-1 {
|
|
rhsValue := f.tx.Factory().NewArraySliceCall(value, i)
|
|
f.flattenBindingOrAssignmentElement(element, rhsValue, element.Loc, false)
|
|
}
|
|
}
|
|
if len(bindingElements) > 0 {
|
|
f.emitBindingOrAssignment(f, f.createArrayBindingOrAssignmentPattern(f, bindingElements), value, location, pattern)
|
|
}
|
|
if len(restContainingElements) > 0 {
|
|
for _, pair := range restContainingElements {
|
|
f.flattenBindingOrAssignmentElement(pair.element, pair.id, pair.element.Loc, false)
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Exported helper functions ---
|
|
|
|
// BindingOrAssignmentElementAssignsToName checks if any target in a binding/assignment pattern assigns to the given name.
|
|
func BindingOrAssignmentElementAssignsToName(element *ast.Node, name string) bool {
|
|
target := ast.GetTargetOfBindingOrAssignmentElement(element)
|
|
if target == nil {
|
|
return false
|
|
}
|
|
if ast.IsBindingPattern(target) || ast.IsAssignmentPattern(target) {
|
|
return bindingOrAssignmentPatternAssignsToName(target, name)
|
|
} else if ast.IsIdentifier(target) {
|
|
return target.Text() == name
|
|
}
|
|
return false
|
|
}
|
|
|
|
func bindingOrAssignmentPatternAssignsToName(pattern *ast.Node, name string) bool {
|
|
elements := ast.GetElementsOfBindingOrAssignmentPattern(pattern)
|
|
for _, element := range elements {
|
|
if BindingOrAssignmentElementAssignsToName(element, name) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// BindingOrAssignmentElementContainsNonLiteralComputedName checks if any element has a non-literal computed property name.
|
|
func BindingOrAssignmentElementContainsNonLiteralComputedName(element *ast.Node) bool {
|
|
propertyName := ast.TryGetPropertyNameOfBindingOrAssignmentElement(element)
|
|
if propertyName != nil && ast.IsComputedPropertyName(propertyName) && !ast.IsLiteralExpression(propertyName.Expression()) {
|
|
return true
|
|
}
|
|
target := ast.GetTargetOfBindingOrAssignmentElement(element)
|
|
return target != nil && (ast.IsBindingPattern(target) || ast.IsAssignmentPattern(target)) && bindingOrAssignmentPatternContainsNonLiteralComputedName(target)
|
|
}
|
|
|
|
func bindingOrAssignmentPatternContainsNonLiteralComputedName(pattern *ast.Node) bool {
|
|
elements := ast.GetElementsOfBindingOrAssignmentPattern(pattern)
|
|
return slices.ContainsFunc(elements, BindingOrAssignmentElementContainsNonLiteralComputedName)
|
|
}
|
|
|
|
// GetInitializerOfBindingOrAssignmentElement returns the initializer/default value of a binding or assignment element.
|
|
func GetInitializerOfBindingOrAssignmentElement(bindingElement *ast.Node) *ast.Node {
|
|
if bindingElement == nil {
|
|
return nil
|
|
}
|
|
if ast.IsDeclarationBindingElement(bindingElement) {
|
|
return bindingElement.Initializer()
|
|
}
|
|
if ast.IsPropertyAssignment(bindingElement) {
|
|
initializer := bindingElement.Initializer()
|
|
if ast.IsAssignmentExpression(initializer, true) {
|
|
return initializer.AsBinaryExpression().Right
|
|
}
|
|
return nil
|
|
}
|
|
if ast.IsShorthandPropertyAssignment(bindingElement) {
|
|
return bindingElement.AsShorthandPropertyAssignment().ObjectAssignmentInitializer
|
|
}
|
|
if ast.IsAssignmentExpression(bindingElement, true) {
|
|
return bindingElement.AsBinaryExpression().Right
|
|
}
|
|
if ast.IsSpreadElement(bindingElement) {
|
|
return GetInitializerOfBindingOrAssignmentElement(bindingElement.Expression())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func isObjectBindingOrAssignmentPattern(node *ast.Node) bool {
|
|
return node != nil && (node.Kind == ast.KindObjectBindingPattern || node.Kind == ast.KindObjectLiteralExpression)
|
|
}
|
|
|
|
func isArrayBindingOrAssignmentPattern(node *ast.Node) bool {
|
|
return node != nil && (node.Kind == ast.KindArrayBindingPattern || node.Kind == ast.KindArrayLiteralExpression)
|
|
}
|
|
|
|
func isSimpleBindingOrAssignmentElement(element *ast.Node) bool {
|
|
target := ast.GetTargetOfBindingOrAssignmentElement(element)
|
|
if target == nil || ast.IsOmittedExpression(target) {
|
|
return true
|
|
}
|
|
propertyName := ast.TryGetPropertyNameOfBindingOrAssignmentElement(element)
|
|
if propertyName != nil && !ast.IsPropertyNameLiteral(propertyName) {
|
|
return false
|
|
}
|
|
initializer := GetInitializerOfBindingOrAssignmentElement(element)
|
|
if initializer != nil && !IsSimpleInlineableExpression(initializer) {
|
|
return false
|
|
}
|
|
if ast.IsBindingPattern(target) || ast.IsAssignmentPattern(target) {
|
|
return core.Every(ast.GetElementsOfBindingOrAssignmentPattern(target), isSimpleBindingOrAssignmentElement)
|
|
}
|
|
return ast.IsIdentifier(target)
|
|
}
|