jashkenas--coffeescript/test/abstract_syntax_tree.coffee

3162 lines
63 KiB
CoffeeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Astract Syntax Tree generation
# ------------------------------
# Recursively compare all values of enumerable properties of `expected` with
# those of `actual`. Use `looseArray` helper function to skip array length
# comparison.
deepStrictIncludeExpectedProperties = (actual, expected) ->
eq actual.length, expected.length if expected instanceof Array and not expected.loose
for key, val of expected
if val? and typeof val is 'object'
fail "Property #{reset}#{key}#{red} expected, but was missing" unless actual[key]
deepStrictIncludeExpectedProperties actual[key], val
else
eq actual[key], val, """
Property #{reset}#{key}#{red}: expected #{reset}#{actual[key]}#{red} to equal #{reset}#{val}#{red}
Expected AST output to include:
#{reset}#{inspect expected}#{red}
but instead it was:
#{reset}#{inspect actual}#{red}
"""
actual
# Flag array for loose comparison. See reference to `.loose` in
# `deepStrictIncludeExpectedProperties` above.
looseArray = (arr) ->
Object.defineProperty arr, 'loose',
value: yes
enumerable: no
arr
testAgainstExpected = (ast, expected) ->
if expected?
deepStrictIncludeExpectedProperties ast, expected
else
# Convenience for creating new tests; call `testExpression` with no second
# parameter to see what the current AST generation is for your input code.
console.log inspect ast
testExpression = (code, expected) ->
ast = getAstExpression code
testAgainstExpected ast, expected
testStatement = (code, expected) ->
ast = getAstStatement code
testAgainstExpected ast, expected
test 'Confirm functionality of `deepStrictIncludeExpectedProperties`', ->
actual =
name: 'Name'
a:
b: 1
c: 2
x: [1, 2, 3]
check = (message, test, expected) ->
test (-> deepStrictIncludeExpectedProperties actual, expected), message
check 'Expected property does not match', throws,
name: '"Name"'
check 'Array length mismatch', throws,
x: [1, 2]
check 'Skip array length check', doesNotThrow,
x: looseArray [
1
2
]
check 'Array length matches', doesNotThrow,
x: [1, 2, 3]
check 'Array prop mismatch', throws,
x: [3, 2, 1]
check 'Partial object comparison', doesNotThrow,
a:
c: 2
forbidden: undefined
check 'Actual has forbidden prop', throws,
a:
b: 1
c: undefined
check 'Check prop for existence only', doesNotThrow,
name: {}
a: {}
x: {}
check 'Prop is missing', throws,
missingProp: {}
# Shorthand helpers for common AST patterns.
EMPTY_BLOCK =
type: 'BlockStatement'
body: []
directives: []
ID = (name) -> {
type: 'Identifier'
name
}
NUMBER = (value) -> {
type: 'NumericLiteral'
value
}
STRING = (value) -> {
type: 'StringLiteral'
value
}
# Check each node type in the same order as they appear in `nodes.coffee`.
# For nodes that have equivalents in Babels AST spec, were checking that
# the type and properties match. When relevant, also check that values of
# properties are as expected.
test "AST as expected for Block node", ->
deepStrictIncludeExpectedProperties CoffeeScript.compile('a', ast: yes),
type: 'File'
program:
type: 'Program'
# sourceType: 'module'
body: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
]
directives: []
comments: []
test "AST as expected for NumberLiteral node", ->
testExpression '42',
type: 'NumericLiteral'
value: 42
extra:
rawValue: 42
raw: '42'
testExpression '0xE1',
type: 'NumericLiteral'
value: 225
extra:
rawValue: 225
raw: '0xE1'
test "AST as expected for InfinityLiteral node", ->
testExpression 'Infinity',
type: 'Identifier'
name: 'Infinity'
testExpression '2e308',
type: 'NumericLiteral'
value: Infinity
extra:
raw: '2e308'
rawValue: Infinity
test "AST as expected for NaNLiteral node", ->
testExpression 'NaN',
type: 'Identifier'
name: 'NaN'
# test "AST as expected for StringLiteral node", ->
# testExpression '"string cheese"',
# type: 'StringLiteral'
# value: '"string cheese"'
# quote: '"'
# testExpression "'cheese string'",
# type: 'StringLiteral'
# value: "'cheese string'"
# quote: "'"
# test "AST as expected for RegexLiteral node", ->
# testExpression '/^(?!.*(.).*\\1)[gimsuy]*$/',
# type: 'RegexLiteral'
# value: '/^(?!.*(.).*\\1)[gimsuy]*$/'
# test "AST as expected for PassthroughLiteral node", ->
# code = 'const CONSTANT = "unreassignable!"'
# testExpression "`#{code}`",
# type: 'PassthroughLiteral'
# value: code
# originalValue: code
# here: no
# code = '\nconst CONSTANT = "unreassignable!"\n'
# testExpression "```#{code}```",
# type: 'PassthroughLiteral'
# value: code
# originalValue: code
# here: yes
test "AST as expected for IdentifierLiteral node", ->
testExpression 'id',
type: 'Identifier'
name: 'id'
test "AST as expected for JSXTag node", ->
testExpression '<CSXY />',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXIdentifier'
name: 'CSXY'
attributes: []
selfClosing: yes
closingElement: null
children: []
testExpression '<div></div>',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXIdentifier'
name: 'div'
attributes: []
selfClosing: no
closingElement:
type: 'JSXClosingElement'
name:
type: 'JSXIdentifier'
name: 'div'
children: []
testExpression '<A.B />',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXMemberExpression'
object:
type: 'JSXIdentifier'
name: 'A'
property:
type: 'JSXIdentifier'
name: 'B'
attributes: []
selfClosing: yes
closingElement: null
children: []
testExpression '<Tag.Name.Here></Tag.Name.Here>',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXMemberExpression'
object:
type: 'JSXMemberExpression'
object:
type: 'JSXIdentifier'
name: 'Tag'
property:
type: 'JSXIdentifier'
name: 'Name'
property:
type: 'JSXIdentifier'
name: 'Here'
attributes: []
selfClosing: no
closingElement:
type: 'JSXClosingElement'
name:
type: 'JSXMemberExpression'
object:
type: 'JSXMemberExpression'
object:
type: 'JSXIdentifier'
name: 'Tag'
property:
type: 'JSXIdentifier'
name: 'Name'
property:
type: 'JSXIdentifier'
name: 'Here'
children: []
testExpression '<></>',
type: 'JSXFragment'
openingFragment:
type: 'JSXOpeningFragment'
closingFragment:
type: 'JSXClosingFragment'
children: []
testExpression '<div a b="c" d={e} {...f} />',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXIdentifier'
name: 'div'
attributes: [
type: 'JSXAttribute'
name:
type: 'JSXIdentifier'
name: 'a'
,
type: 'JSXAttribute'
name:
type: 'JSXIdentifier'
name: 'b'
value:
type: 'StringLiteral'
value: 'c'
,
type: 'JSXAttribute'
name:
type: 'JSXIdentifier'
name: 'd'
value:
type: 'JSXExpressionContainer'
expression:
type: 'Identifier'
name: 'e'
,
type: 'JSXSpreadAttribute'
argument:
type: 'Identifier'
name: 'f'
postfix: no
]
selfClosing: yes
closingElement: null
children: []
testExpression '<div {f...} />',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
attributes: [
type: 'JSXSpreadAttribute'
argument:
type: 'Identifier'
name: 'f'
postfix: yes
]
testExpression '<div>abc</div>',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXIdentifier'
name: 'div'
attributes: []
selfClosing: no
closingElement:
type: 'JSXClosingElement'
name:
type: 'JSXIdentifier'
name: 'div'
children: [
type: 'JSXText'
extra:
raw: 'abc'
value: 'abc'
]
testExpression '''
<a>
{b}
<c />
</a>
''',
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXIdentifier'
name: 'a'
attributes: []
selfClosing: no
closingElement:
type: 'JSXClosingElement'
name:
type: 'JSXIdentifier'
name: 'a'
children: [
type: 'JSXText'
extra:
raw: '\n '
value: '\n '
,
type: 'JSXExpressionContainer'
expression: ID 'b'
,
type: 'JSXText'
extra:
raw: '\n '
value: '\n '
,
type: 'JSXElement'
openingElement:
type: 'JSXOpeningElement'
name:
type: 'JSXIdentifier'
name: 'c'
selfClosing: true
closingElement: null
children: []
,
type: 'JSXText'
extra:
raw: '\n'
value: '\n'
]
testExpression '<>abc{}</>',
type: 'JSXFragment'
openingFragment:
type: 'JSXOpeningFragment'
closingFragment:
type: 'JSXClosingFragment'
children: [
type: 'JSXText'
extra:
raw: 'abc'
value: 'abc'
,
type: 'JSXEmptyExpression'
]
# test "AST as expected for PropertyName node", ->
# testExpression 'Object.assign',
# properties: [
# name:
# type: 'PropertyName'
# value: 'assign'
# ]
test "AST as expected for ComputedPropertyName node", ->
testExpression '[fn]: ->',
type: 'ObjectExpression'
properties: [
type: 'ObjectProperty'
key:
type: 'Identifier'
name: 'fn'
value:
type: 'FunctionExpression'
computed: yes
shorthand: no
method: no
]
implicit: yes
testExpression '[a]: b',
type: 'ObjectExpression'
properties: [
type: 'ObjectProperty'
key:
type: 'Identifier'
name: 'a'
value:
type: 'Identifier'
name: 'b'
computed: yes
shorthand: no
method: no
]
implicit: yes
test "AST as expected for StatementLiteral node", ->
testStatement 'break',
type: 'BreakStatement'
testStatement 'continue',
type: 'ContinueStatement'
testStatement 'debugger',
type: 'DebuggerStatement'
test "AST as expected for ThisLiteral node", ->
testExpression 'this',
type: 'ThisExpression'
shorthand: no
testExpression '@',
type: 'ThisExpression'
shorthand: yes
# TODO: `@prop` property access isn't covered yet in these tests.
test "AST as expected for UndefinedLiteral node", ->
testExpression 'undefined',
type: 'Identifier'
name: 'undefined'
test "AST as expected for NullLiteral node", ->
testExpression 'null',
type: 'NullLiteral'
test "AST as expected for BooleanLiteral node", ->
testExpression 'true',
type: 'BooleanLiteral'
value: true
name: 'true'
testExpression 'off',
type: 'BooleanLiteral'
value: false
name: 'off'
testExpression 'yes',
type: 'BooleanLiteral'
value: true
name: 'yes'
test "AST as expected for Return node", ->
testStatement 'return no',
type: 'ReturnStatement'
argument:
type: 'BooleanLiteral'
testExpression '''
(a, b) ->
return a + b
''',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'ReturnStatement'
argument:
type: 'BinaryExpression'
]
testExpression '-> return',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'ReturnStatement'
argument: null
]
test "AST as expected for YieldReturn node", ->
testExpression '-> yield return 1',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'YieldExpression'
argument:
type: 'ReturnStatement'
argument: NUMBER 1
delegate: no
]
test "AST as expected for AwaitReturn node", ->
testExpression '-> await return 2',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'AwaitExpression'
argument:
type: 'ReturnStatement'
argument: NUMBER 2
]
# test "AST as expected for Value node", ->
# testExpression 'for i in [] then i',
# body:
# type: 'Value'
# isDefaultValue: no
# base:
# value: 'i'
# properties: []
# testExpression 'if 1 then 1 else 2',
# body:
# type: 'Value'
# isDefaultValue: no
# elseBody:
# type: 'Value'
# isDefaultValue: no
# # TODO: Figgure out the purpose of `isDefaultValue`. It's not set in `Switch` either.
# # Comments arent nodes, so they shouldnt appear in the AST.
test "AST as expected for Call node", ->
testExpression 'fn()',
type: 'CallExpression'
callee:
type: 'Identifier'
name: 'fn'
arguments: []
optional: no
implicit: no
testExpression 'new Date()',
type: 'NewExpression'
callee:
type: 'Identifier'
name: 'Date'
arguments: []
optional: no
implicit: no
testExpression 'new Date?()',
type: 'NewExpression'
callee:
type: 'Identifier'
name: 'Date'
arguments: []
optional: yes
implicit: no
testExpression 'new Old',
type: 'NewExpression'
callee:
type: 'Identifier'
name: 'Old'
arguments: []
optional: no
implicit: no
testExpression 'new Old(1)',
type: 'NewExpression'
callee:
type: 'Identifier'
name: 'Old'
arguments: [
type: 'NumericLiteral'
value: 1
]
optional: no
implicit: no
testExpression 'new Old 1',
type: 'NewExpression'
callee:
type: 'Identifier'
name: 'Old'
arguments: [
type: 'NumericLiteral'
value: 1
]
optional: no
implicit: yes
testExpression 'maybe?()',
type: 'CallExpression'
optional: yes
implicit: no
testExpression 'maybe?(1 + 1)',
type: 'CallExpression'
arguments: [
type: 'BinaryExpression'
]
optional: yes
implicit: no
testExpression 'maybe? 1 + 1',
type: 'CallExpression'
arguments: [
type: 'BinaryExpression'
]
optional: yes
implicit: yes
testExpression 'goDo this, that',
type: 'CallExpression'
arguments: [
type: 'ThisExpression'
,
type: 'Identifier'
name: 'that'
]
implicit: yes
optional: no
# test "AST as expected for SuperCall node", ->
# testExpression 'class child extends parent then constructor: -> super()',
# body:
# base:
# properties: [
# value:
# body:
# base:
# type: 'SuperCall'
# ]
# test "AST as expected for Super node", ->
# testExpression 'class child extends parent then func: -> super.prop',
# body:
# base:
# properties: [
# value:
# body:
# base:
# type: 'Super'
# accessor:
# type: 'Access'
# ]
test "AST as expected for RegexWithInterpolations node", ->
testExpression '///^#{flavor}script$///',
type: 'InterpolatedRegExpLiteral'
interpolatedPattern:
type: 'TemplateLiteral'
expressions: [
ID 'flavor'
]
quasis: [
type: 'TemplateElement'
value:
raw: '^'
tail: no
,
type: 'TemplateElement'
value:
raw: 'script$'
tail: yes
]
quote: '///'
flags: ''
testExpression '''
///
a
#{b}///ig
''',
type: 'InterpolatedRegExpLiteral'
interpolatedPattern:
type: 'TemplateLiteral'
expressions: [
ID 'b'
]
quasis: [
type: 'TemplateElement'
value:
raw: '\n a\n '
tail: no
,
type: 'TemplateElement'
value:
raw: ''
tail: yes
]
quote: '///'
flags: 'ig'
test "AST as expected for TaggedTemplateCall node", ->
testExpression 'func"tagged"',
type: 'TaggedTemplateExpression'
tag: ID 'func'
quasi:
type: 'TemplateLiteral'
expressions: []
quasis: [
type: 'TemplateElement'
value:
raw: 'tagged'
tail: yes
]
testExpression 'a"b#{c}"',
type: 'TaggedTemplateExpression'
tag: ID 'a'
quasi:
type: 'TemplateLiteral'
expressions: [
ID 'c'
]
quasis: [
type: 'TemplateElement'
value:
raw: 'b'
tail: no
,
type: 'TemplateElement'
value:
raw: ''
tail: yes
]
testExpression '''
a"""
b#{c}
"""
''',
type: 'TaggedTemplateExpression'
tag: ID 'a'
quasi:
type: 'TemplateLiteral'
expressions: [
ID 'c'
]
quasis: [
type: 'TemplateElement'
value:
raw: '\n b'
tail: no
,
type: 'TemplateElement'
value:
raw: '\n'
tail: yes
]
testExpression """
a'''
b
'''
""",
type: 'TaggedTemplateExpression'
tag: ID 'a'
quasi:
type: 'TemplateLiteral'
expressions: []
quasis: [
type: 'TemplateElement'
value:
raw: '\n b\n'
tail: yes
]
# test "AST as expected for Extends node", ->
# testExpression 'class child extends parent',
# type: 'Class'
# variable:
# value: 'child'
# parent:
# value: 'parent'
# # TODO: Is there no Extends node?
test "AST as expected for Access node", ->
testExpression 'obj.prop',
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'obj'
property:
type: 'Identifier'
name: 'prop'
computed: no
optional: no
shorthand: no
testExpression 'obj?.prop',
# TODO: support Babel 7-style OptionalMemberExpression type
# type: 'OptionalMemberExpression'
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'obj'
property:
type: 'Identifier'
name: 'prop'
computed: no
optional: yes
shorthand: no
testExpression 'a::b',
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'prototype'
computed: no
optional: no
shorthand: yes
property:
type: 'Identifier'
name: 'b'
computed: no
optional: no
shorthand: no
testExpression 'a.prototype.b',
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'prototype'
computed: no
optional: no
shorthand: no
property:
type: 'Identifier'
name: 'b'
computed: no
optional: no
shorthand: no
testExpression 'a?.b.c',
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'b'
computed: no
optional: yes
shorthand: no
property:
type: 'Identifier'
name: 'c'
computed: no
optional: no
shorthand: no
test "AST as expected for Index node", ->
testExpression 'a[b]',
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'b'
computed: yes
optional: no
shorthand: no
testExpression 'a?[b]',
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'b'
computed: yes
optional: yes
shorthand: no
testExpression 'a::[b]',
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'prototype'
computed: no
optional: no
shorthand: yes
property:
type: 'Identifier'
name: 'b'
computed: yes
optional: no
shorthand: no
testExpression 'a[b][3]',
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'Identifier'
name: 'a'
property:
type: 'Identifier'
name: 'b'
computed: yes
optional: no
shorthand: no
property:
type: 'NumericLiteral'
value: 3
computed: yes
optional: no
shorthand: no
testExpression 'a[if b then c]',
type: 'MemberExpression'
object: ID 'a'
property:
type: 'ConditionalExpression'
test: ID 'b'
consequent: ID 'c'
computed: yes
optional: no
shorthand: no
test "AST as expected for Range node", ->
testExpression '[x..y]',
type: 'Range'
exclusive: no
from:
name: 'x'
to:
name: 'y'
testExpression '[4...2]',
type: 'Range'
exclusive: yes
from:
value: 4
to:
value: 2
# testExpression 'for x in [42...43] then',
# range: yes
# source:
# type: 'Range'
# exclusive: yes
# equals: ''
# from:
# value: '42'
# to:
# value: '43'
# testExpression 'for x in [y..z] then',
# range: yes
# source:
# type: 'Range'
# exclusive: no
# equals: '='
# from:
# value: 'y'
# to:
# value: 'z'
test "AST as expected for Slice node", ->
testExpression 'x[..y]',
property:
type: 'Range'
exclusive: no
from: null
to:
name: 'y'
testExpression 'x[y...]',
property:
type: 'Range'
exclusive: yes
from:
name: 'y'
to: null
testExpression 'x[...]',
property:
type: 'Range'
exclusive: yes
from: null
to: null
# testExpression '"abc"[...2]',
# type: 'MemberExpression'
# property:
# type: 'Range'
# from: null
# to:
# type: 'NumericLiteral'
# value: 2
# exclusive: yes
# computed: yes
# optional: no
# shorthand: no
testExpression 'x[...][a..][b...][..c][...d]',
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'MemberExpression'
object:
type: 'MemberExpression'
property:
type: 'Range'
from: null
to: null
exclusive: yes
property:
type: 'Range'
from:
name: 'a'
to: null
exclusive: no
property:
type: 'Range'
from:
name: 'b'
to: null
exclusive: yes
property:
type: 'Range'
from: null
to:
name: 'c'
exclusive: no
property:
type: 'Range'
from: null
to:
name: 'd'
exclusive: yes
test "AST as expected for Obj node", ->
testExpression "{a: 1, b, [c], @d, [e()]: f, 'g': 2, ...h, i...}",
type: 'ObjectExpression'
properties: [
type: 'ObjectProperty'
key:
type: 'Identifier'
name: 'a'
value:
type: 'NumericLiteral'
value: 1
computed: no
shorthand: no
,
type: 'ObjectProperty'
key:
type: 'Identifier'
name: 'b'
value:
type: 'Identifier'
name: 'b'
computed: no
shorthand: yes
,
type: 'ObjectProperty'
key:
type: 'Identifier'
name: 'c'
value:
type: 'Identifier'
name: 'c'
computed: yes
shorthand: yes
,
type: 'ObjectProperty'
key:
type: 'MemberExpression'
object:
type: 'ThisExpression'
property:
type: 'Identifier'
name: 'd'
value:
type: 'MemberExpression'
object:
type: 'ThisExpression'
property:
type: 'Identifier'
name: 'd'
computed: no
shorthand: yes
,
type: 'ObjectProperty'
key:
type: 'CallExpression'
callee:
type: 'Identifier'
name: 'e'
arguments: []
value:
type: 'Identifier'
name: 'f'
computed: yes
shorthand: no
,
type: 'ObjectProperty'
key:
type: 'StringLiteral'
value: 'g'
value:
type: 'NumericLiteral'
value: 2
computed: no
shorthand: no
,
type: 'SpreadElement'
argument:
type: 'Identifier'
name: 'h'
postfix: no
,
type: 'SpreadElement'
argument:
type: 'Identifier'
name: 'i'
postfix: yes
]
implicit: no
testExpression 'a: 1',
type: 'ObjectExpression'
properties: [
type: 'ObjectProperty'
key:
type: 'Identifier'
name: 'a'
value:
type: 'NumericLiteral'
value: 1
shorthand: no
computed: no
]
implicit: yes
# # TODO: Test destructuring.
# # console.log JSON.stringify expression, ["type", "generated", "lhs", "value", "properties", "variable"], 2
test "AST as expected for Arr node", ->
testExpression '[]',
type: 'ArrayExpression'
elements: []
testExpression '[3, tables, !1]',
type: 'ArrayExpression'
elements: [
{value: 3}
{name: 'tables'}
{operator: '!'}
]
# # TODO: Test destructuring.
# test "AST as expected for Class node", ->
# testExpression 'class Klass',
# type: 'Class'
# variable:
# value: 'Klass'
# body:
# type: 'Block'
# expressions: []
# testExpression 'class child extends parent',
# type: 'Class'
# variable:
# value: 'child'
# parent:
# value: 'parent'
# body:
# type: 'Block'
# expressions: []
# testExpression 'class Klass then constructor: ->',
# type: 'Class'
# variable:
# value: 'Klass'
# parent: undefined
# body:
# type: 'Value'
# properties: []
# base:
# type: 'Obj'
# generated: yes
# properties: [
# variable:
# value: 'constructor'
# value:
# type: 'Code'
# ]
# test "AST as expected for ExecutableClassBody node", ->
# code = """
# class Klass
# privateStatic = if 42 then yes else no
# getPrivateStatic: -> privateStatic
# """
# testExpression code,
# type: 'Class'
# variable:
# value: 'Klass'
# body:
# type: 'Block'
# expressions: [
# type: 'Assign'
# variable:
# value: 'privateStatic'
# value:
# type: 'If'
# ,
# type: 'Obj'
# generated: yes
# properties: [
# type: 'Assign'
# variable:
# value: 'getPrivateStatic'
# value:
# type: 'Code'
# body:
# type: 'Value'
# properties: []
# ]
# ]
test "AST as expected for ModuleDeclaration node", ->
testStatement 'export {X}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'X'
exported:
type: 'Identifier'
name: 'X'
]
source: null
exportKind: 'value'
testStatement 'import X from "."',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
local:
type: 'Identifier'
name: 'X'
]
importKind: 'value'
source:
type: 'StringLiteral'
value: '.'
test "AST as expected for ImportDeclaration node", ->
testStatement 'import React, {Component} from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
local:
type: 'Identifier'
name: 'React'
,
type: 'ImportSpecifier'
imported:
type: 'Identifier'
name: 'Component'
importKind: null
local:
type: 'Identifier'
name: 'Component'
]
importKind: 'value'
source:
type: 'StringLiteral'
value: 'react'
extra:
raw: '"react"'
test "AST as expected for ExportNamedDeclaration node", ->
testStatement 'export {}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: []
source: null
exportKind: 'value'
testStatement 'export fn = ->',
type: 'ExportNamedDeclaration'
declaration:
type: 'AssignmentExpression'
left:
type: 'Identifier'
right:
type: 'FunctionExpression'
specifiers: []
source: null
exportKind: 'value'
# testStatement 'export class A',
testStatement 'export {x as y, z as default}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'x'
exported:
type: 'Identifier'
name: 'y'
,
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'z'
exported:
type: 'Identifier'
name: 'default'
]
source: null
exportKind: 'value'
testStatement 'export {default, default as b} from "./abc"',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'default'
exported:
type: 'Identifier'
name: 'default'
,
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'default'
exported:
type: 'Identifier'
name: 'b'
]
source:
type: 'StringLiteral'
value: './abc'
extra:
raw: '"./abc"'
exportKind: 'value'
test "AST as expected for ExportDefaultDeclaration node", ->
# testStatement 'export default class',
# type: 'ExportDefaultDeclaration'
# clause:
# type: 'Class'
testStatement 'export default "abc"',
type: 'ExportDefaultDeclaration'
declaration:
type: 'StringLiteral'
value: 'abc'
extra:
raw: '"abc"'
test "AST as expected for ExportAllDeclaration node", ->
testStatement 'export * from "module-name"',
type: 'ExportAllDeclaration'
source:
type: 'StringLiteral'
value: 'module-name'
extra:
raw: '"module-name"'
exportKind: 'value'
test "AST as expected for ExportSpecifierList node", ->
testStatement 'export {a, b, c}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'a'
exported:
type: 'Identifier'
name: 'a'
,
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'b'
exported:
type: 'Identifier'
name: 'b'
,
type: 'ExportSpecifier'
local:
type: 'Identifier'
name: 'c'
exported:
type: 'Identifier'
name: 'c'
]
test "AST as expected for ImportDefaultSpecifier node", ->
testStatement 'import React from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
local:
type: 'Identifier'
name: 'React'
]
importKind: 'value'
source:
type: 'StringLiteral'
value: 'react'
test "AST as expected for ImportNamespaceSpecifier node", ->
testStatement 'import * as React from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportNamespaceSpecifier'
local:
type: 'Identifier'
name: 'React'
]
importKind: 'value'
source:
type: 'StringLiteral'
value: 'react'
testStatement 'import React, * as ReactStar from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
local:
type: 'Identifier'
name: 'React'
,
type: 'ImportNamespaceSpecifier'
local:
type: 'Identifier'
name: 'ReactStar'
]
importKind: 'value'
source:
type: 'StringLiteral'
value: 'react'
test "AST as expected for Assign node", ->
testExpression 'a = b',
type: 'AssignmentExpression'
left:
type: 'Identifier'
name: 'a'
right:
type: 'Identifier'
name: 'b'
operator: '='
testExpression 'a += b',
type: 'AssignmentExpression'
left:
type: 'Identifier'
name: 'a'
right:
type: 'Identifier'
name: 'b'
operator: '+='
testExpression '[@a = 2, {b: {c = 3} = {}, d...}, ...e] = f',
type: 'AssignmentExpression'
left:
type: 'ArrayPattern'
elements: [
type: 'AssignmentPattern'
left:
type: 'MemberExpression'
object:
type: 'ThisExpression'
property:
name: 'a'
right:
type: 'NumericLiteral'
,
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key:
name: 'b'
value:
type: 'AssignmentPattern'
left:
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key:
name: 'c'
value:
type: 'AssignmentPattern'
left:
name: 'c'
right:
value: 3
shorthand: yes
]
right:
type: 'ObjectExpression'
properties: []
,
type: 'RestElement'
postfix: yes
]
,
type: 'RestElement'
postfix: no
]
right:
name: 'f'
testExpression '{a: [...b]} = c',
type: 'AssignmentExpression'
left:
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key:
name: 'a'
value:
type: 'ArrayPattern'
elements: [
type: 'RestElement'
]
]
right:
name: 'c'
# # `FuncGlyph` node isn't exported.
test "AST as expected for Code node", ->
testExpression '=>',
type: 'ArrowFunctionExpression'
params: []
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '''
(a, b = 1) ->
c
d()
''',
type: 'FunctionExpression'
params: [
type: 'Identifier'
name: 'a'
,
type: 'AssignmentPattern'
left:
type: 'Identifier'
name: 'b'
right:
type: 'NumericLiteral'
value: 1
]
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
name: 'c'
,
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
directives: []
generator: no
async: no
id: null
testExpression '({a}) ->',
type: 'FunctionExpression'
params: [
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key: ID('a')
value: ID('a')
shorthand: yes
]
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '([a]) ->',
type: 'FunctionExpression'
params: [
type: 'ArrayPattern'
elements: [
ID('a')
]
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '({a = 1} = {}) ->',
type: 'FunctionExpression'
params: [
type: 'AssignmentPattern'
left:
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key: ID('a')
value:
type: 'AssignmentPattern'
left: ID('a')
right: NUMBER(1)
shorthand: yes
]
right:
type: 'ObjectExpression'
properties: []
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '([a = 1] = []) ->',
type: 'FunctionExpression'
params: [
type: 'AssignmentPattern'
left:
type: 'ArrayPattern'
elements: [
type: 'AssignmentPattern'
left: ID('a')
right: NUMBER(1)
]
right:
type: 'ArrayExpression'
elements: []
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '() ->',
type: 'FunctionExpression'
params: []
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '(@a) ->',
type: 'FunctionExpression'
params: [
type: 'MemberExpression'
object:
type: 'ThisExpression'
shorthand: yes
property: ID 'a'
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '(@a = 1) ->',
type: 'FunctionExpression'
params: [
type: 'AssignmentPattern'
left:
type: 'MemberExpression'
right: NUMBER 1
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '({@a}) ->',
type: 'FunctionExpression'
params: [
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key:
type: 'MemberExpression'
value:
type: 'MemberExpression'
shorthand: yes
computed: no
]
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '({[a]}) ->',
type: 'FunctionExpression'
params: [
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key: ID 'a'
value: ID 'a'
shorthand: yes
computed: yes
]
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '(...a) ->',
type: 'FunctionExpression'
params: [
type: 'RestElement'
argument: ID 'a'
postfix: no
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '(a...) ->',
type: 'FunctionExpression'
params: [
type: 'RestElement'
argument: ID 'a'
postfix: yes
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '(..., a) ->',
type: 'FunctionExpression'
params: [
type: 'RestElement'
argument: null
,
ID 'a'
]
body: EMPTY_BLOCK
generator: no
async: no
id: null
testExpression '-> a',
type: 'FunctionExpression'
params: []
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'a'
]
generator: no
async: no
id: null
testExpression '-> await 3',
type: 'FunctionExpression'
params: []
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'AwaitExpression'
argument: NUMBER 3
]
generator: no
async: yes
id: null
testExpression '-> yield 4',
type: 'FunctionExpression'
params: []
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'YieldExpression'
argument: NUMBER 4
delegate: no
]
generator: yes
async: no
id: null
testExpression '-> yield',
type: 'FunctionExpression'
params: []
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'YieldExpression'
argument: null
delegate: no
]
generator: yes
async: no
id: null
test "AST as expected for Splat node", ->
testExpression '[a...]',
type: 'ArrayExpression'
elements: [
type: 'SpreadElement'
argument:
type: 'Identifier'
name: 'a'
postfix: yes
]
testExpression '[b, ...c]',
type: 'ArrayExpression'
elements: [
name: 'b'
,
type: 'SpreadElement'
argument:
type: 'Identifier'
name: 'c'
postfix: no
]
# testExpression '(a...) ->',
# params: [
# type: 'Param'
# splat: yes
# name:
# value: 'a'
# ]
# # TODO: Test object splats.
test "AST as expected for Expansion node", ->
# testExpression '(...) ->',
# type: 'Code'
# params: [
# {type: 'Expansion'}
# ]
testExpression '[..., b] = c',
type: 'AssignmentExpression'
left:
type: 'ArrayPattern'
elements: [
type: 'RestElement'
argument: null
,
type: 'Identifier'
]
test "AST as expected for Elision node", ->
testExpression '[,,,a,,,b]',
type: 'ArrayExpression'
elements: [
null, null, null
name: 'a'
null, null
name: 'b'
]
testExpression '[,,,a,,,b] = "asdfqwer"',
type: 'AssignmentExpression'
left:
type: 'ArrayPattern'
elements: [
null, null, null
,
type: 'Identifier'
name: 'a'
,
null, null
,
type: 'Identifier'
name: 'b'
]
right:
type: 'StringLiteral'
value: 'asdfqwer'
test "AST as expected for While node", ->
testStatement 'loop 1',
type: 'WhileStatement'
test:
type: 'BooleanLiteral'
value: true
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: NUMBER 1
]
guard: null
inverted: no
postfix: no
loop: yes
testStatement 'while 1 < 2 then',
type: 'WhileStatement'
test:
type: 'BinaryExpression'
body:
type: 'BlockStatement'
body: []
guard: null
inverted: no
postfix: no
loop: no
testStatement 'while 1 < 2 then fn()',
type: 'WhileStatement'
test:
type: 'BinaryExpression'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
guard: null
inverted: no
postfix: no
loop: no
testStatement '''
x() until y
''',
type: 'WhileStatement'
test: ID 'y'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
guard: null
inverted: yes
postfix: yes
loop: no
testStatement '''
until x when y
z++
''',
type: 'WhileStatement'
test: ID 'x'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'UpdateExpression'
]
guard: ID 'y'
inverted: yes
postfix: no
loop: no
testStatement '''
x while y when z
''',
type: 'WhileStatement'
test: ID 'y'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'x'
]
guard: ID 'z'
inverted: no
postfix: yes
loop: no
testStatement '''
loop
a()
b++
''',
type: 'WhileStatement'
test:
type: 'BooleanLiteral'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
,
type: 'ExpressionStatement'
expression:
type: 'UpdateExpression'
]
guard: null
inverted: no
postfix: no
loop: yes
test "AST as expected for Op node", ->
testExpression 'a <= 2',
type: 'BinaryExpression'
operator: '<='
left:
type: 'Identifier'
name: 'a'
right:
type: 'NumericLiteral'
value: 2
testExpression 'a is 2',
type: 'BinaryExpression'
operator: 'is'
left:
type: 'Identifier'
name: 'a'
right:
type: 'NumericLiteral'
value: 2
testExpression 'a // 2',
type: 'BinaryExpression'
operator: '//'
left:
type: 'Identifier'
name: 'a'
right:
type: 'NumericLiteral'
value: 2
testExpression 'a << 2',
type: 'BinaryExpression'
operator: '<<'
left:
type: 'Identifier'
name: 'a'
right:
type: 'NumericLiteral'
value: 2
testExpression 'typeof x',
type: 'UnaryExpression'
operator: 'typeof'
prefix: yes
argument:
type: 'Identifier'
name: 'x'
testExpression 'delete x.y',
type: 'UnaryExpression'
operator: 'delete'
prefix: yes
argument:
type: 'MemberExpression'
testExpression 'do x',
type: 'UnaryExpression'
operator: 'do'
prefix: yes
argument:
type: 'Identifier'
name: 'x'
testExpression 'do ->',
type: 'UnaryExpression'
operator: 'do'
prefix: yes
argument:
type: 'FunctionExpression'
testExpression '!x',
type: 'UnaryExpression'
operator: '!'
prefix: yes
argument:
type: 'Identifier'
name: 'x'
testExpression 'not x',
type: 'UnaryExpression'
operator: 'not'
prefix: yes
argument:
type: 'Identifier'
name: 'x'
testExpression '--x',
type: 'UpdateExpression'
operator: '--'
prefix: yes
argument:
type: 'Identifier'
name: 'x'
testExpression 'x++',
type: 'UpdateExpression'
operator: '++'
prefix: no
argument:
type: 'Identifier'
name: 'x'
testExpression 'x && y',
type: 'LogicalExpression'
operator: '&&'
left:
type: 'Identifier'
name: 'x'
right:
type: 'Identifier'
name: 'y'
testExpression 'x or y',
type: 'LogicalExpression'
operator: 'or'
left:
type: 'Identifier'
name: 'x'
right:
type: 'Identifier'
name: 'y'
testExpression 'x ? y',
type: 'LogicalExpression'
operator: '?'
left:
type: 'Identifier'
name: 'x'
right:
type: 'Identifier'
name: 'y'
testExpression 'x in y',
type: 'BinaryExpression'
operator: 'in'
left:
type: 'Identifier'
name: 'x'
right:
type: 'Identifier'
name: 'y'
testExpression 'x not in y',
type: 'BinaryExpression'
operator: 'not in'
left:
type: 'Identifier'
name: 'x'
right:
type: 'Identifier'
name: 'y'
testExpression 'x + y * z',
type: 'BinaryExpression'
operator: '+'
left:
type: 'Identifier'
name: 'x'
right:
type: 'BinaryExpression'
operator: '*'
left:
type: 'Identifier'
name: 'y'
right:
type: 'Identifier'
name: 'z'
testExpression '(x + y) * z',
type: 'BinaryExpression'
operator: '*'
left:
type: 'BinaryExpression'
operator: '+'
left:
type: 'Identifier'
name: 'x'
right:
type: 'Identifier'
name: 'y'
right:
type: 'Identifier'
name: 'z'
test "AST as expected for Try node", ->
testStatement 'try cappuccino',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
name: 'cappuccino'
]
handler: null
finalizer: null
testStatement '''
try
x = 1
y()
catch e
d()
finally
f + g
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'AssignmentExpression'
,
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
handler:
type: 'CatchClause'
param:
type: 'Identifier'
name: 'e'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
finalizer:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'BinaryExpression'
]
testStatement '''
try
catch
finally
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: []
handler:
type: 'CatchClause'
param: null
body:
type: 'BlockStatement'
body: []
finalizer:
type: 'BlockStatement'
body: []
testStatement '''
try
catch {e}
f
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: []
handler:
type: 'CatchClause'
param:
type: 'ObjectPattern'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
]
finalizer: null
test "AST as expected for Throw node", ->
testStatement 'throw new BallError "catch"',
type: 'ThrowStatement'
argument:
type: 'NewExpression'
test "AST as expected for Existence node", ->
testExpression 'Ghosts?',
type: 'UnaryExpression',
argument:
name: 'Ghosts'
operator: '?'
prefix: no
# # NOTE: Soaking is covered in `Call` and `Access` nodes.
test "AST as expected for Parens node", ->
testExpression '(hmmmmm)',
type: 'Identifier'
name: 'hmmmmm'
# testExpression '(a + b) / c',
# type: 'Op'
# operator: '/'
# first:
# type: 'Parens'
# body:
# type: 'Op'
# operator: '+'
testExpression '(((1)))',
type: 'NumericLiteral'
value: 1
test "AST as expected for StringWithInterpolations node", ->
testExpression '"a#{b}c"',
type: 'TemplateLiteral'
expressions: [
ID 'b'
]
quasis: [
type: 'TemplateElement'
value:
raw: 'a'
tail: no
,
type: 'TemplateElement'
value:
raw: 'c'
tail: yes
]
quote: '"'
testExpression '"""a#{b}c"""',
type: 'TemplateLiteral'
expressions: [
ID 'b'
]
quasis: [
type: 'TemplateElement'
value:
raw: 'a'
tail: no
,
type: 'TemplateElement'
value:
raw: 'c'
tail: yes
]
quote: '"""'
testExpression '"#{b}"',
type: 'TemplateLiteral'
expressions: [
ID 'b'
]
quasis: [
type: 'TemplateElement'
value:
raw: ''
tail: no
,
type: 'TemplateElement'
value:
raw: ''
tail: yes
]
quote: '"'
testExpression '''
" a
#{b}
c
"
''',
type: 'TemplateLiteral'
expressions: [
ID 'b'
]
quasis: [
type: 'TemplateElement'
value:
raw: ' a\n '
tail: no
,
type: 'TemplateElement'
value:
raw: '\n c\n'
tail: yes
]
quote: '"'
testExpression '''
"""
a
b#{
c
}d
"""
''',
type: 'TemplateLiteral'
expressions: [
ID 'c'
]
quasis: [
type: 'TemplateElement'
value:
raw: '\n a\n b'
tail: no
,
type: 'TemplateElement'
value:
raw: 'd\n'
tail: yes
]
quote: '"""'
test "AST as expected for For node", ->
testStatement 'for x, i in arr when x? then return',
type: 'For'
name: ID 'x'
index: ID 'i'
guard:
type: 'UnaryExpression'
source: ID 'arr'
body:
type: 'BlockStatement'
body: [
type: 'ReturnStatement'
]
style: 'in'
own: no
postfix: no
await: no
step: null
testStatement 'for k, v of obj then return',
type: 'For'
name: ID 'v'
index: ID 'k'
guard: null
source: ID 'obj'
body:
type: 'BlockStatement'
body: [
type: 'ReturnStatement'
]
style: 'of'
own: no
postfix: no
await: no
step: null
testStatement 'for x from iterable then',
type: 'For'
name: ID 'x'
index: null
guard: null
body: EMPTY_BLOCK
source: ID 'iterable'
style: 'from'
own: no
postfix: no
await: no
step: null
testStatement 'for i in [0...42] by step when not (i % 2) then',
type: 'For'
name: ID 'i'
index: null
body: EMPTY_BLOCK
source:
type: 'Range'
guard:
type: 'UnaryExpression'
step: ID 'step'
style: 'in'
own: no
postfix: no
await: no
testExpression 'a = (x for x in y)',
type: 'AssignmentExpression'
right:
type: 'For'
name: ID 'x'
index: null
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'x'
]
source: ID 'y'
guard: null
step: null
style: 'in'
own: no
postfix: yes
await: no
testStatement 'x for [0...1]',
type: 'For'
name: null
index: null
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'x'
]
source:
type: 'Range'
guard: null
step: null
style: 'range'
own: no
postfix: yes
await: no
testStatement '''
for own x, y of z
c()
d
''',
type: 'For'
name: ID 'y'
index: ID 'x'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
,
type: 'ExpressionStatement'
expression: ID 'd'
]
source: ID 'z'
guard: null
step: null
style: 'of'
own: yes
postfix: no
await: no
testExpression '''
->
for await x from y
z
''',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'For'
name: ID 'x'
index: null
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'z'
]
source: ID 'y'
guard: null
step: null
style: 'from'
own: no
postfix: no
await: yes
]
testStatement '''
for {x} in y
z
''',
type: 'For'
name:
type: 'ObjectPattern'
properties: [
type: 'ObjectProperty'
key: ID 'x'
value: ID 'x'
shorthand: yes
computed: no
]
index: null
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'z'
]
source: ID 'y'
guard: null
step: null
style: 'in'
postfix: no
await: no
testStatement '''
for [x] in y
z
''',
type: 'For'
name:
type: 'ArrayPattern'
elements: [
ID 'x'
]
index: null
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'z'
]
source: ID 'y'
guard: null
step: null
style: 'in'
postfix: no
await: no
# # TODO: Figure out the purpose of `pattern` and `returns`.
test "AST as expected for Switch node", ->
testStatement '''
switch x
when a then a
when b, c then c
else 42
''',
type: 'SwitchStatement'
discriminant:
type: 'Identifier'
name: 'x'
cases: [
type: 'SwitchCase'
test:
type: 'Identifier'
name: 'a'
consequent: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
name: 'a'
]
trailing: yes
,
type: 'SwitchCase'
test:
type: 'Identifier'
name: 'b'
consequent: []
trailing: no
,
type: 'SwitchCase'
test:
type: 'Identifier'
name: 'c'
consequent: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
name: 'c'
]
trailing: yes
,
type: 'SwitchCase'
test: null
consequent: [
type: 'ExpressionStatement'
expression:
type: 'NumericLiteral'
value: 42
]
]
testStatement '''
switch
when some(condition)
doSomething()
andThenSomethingElse
''',
type: 'SwitchStatement'
discriminant: null
cases: [
type: 'SwitchCase'
test:
type: 'CallExpression'
consequent: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
,
type: 'ExpressionStatement'
expression:
type: 'Identifier'
]
trailing: yes
]
testStatement '''
switch a
when 1, 2, 3, 4
b
else
c
d
''',
type: 'SwitchStatement'
discriminant:
type: 'Identifier'
cases: [
type: 'SwitchCase'
test:
type: 'NumericLiteral'
value: 1
consequent: []
trailing: no
,
type: 'SwitchCase'
test:
type: 'NumericLiteral'
value: 2
consequent: []
trailing: no
,
type: 'SwitchCase'
test:
type: 'NumericLiteral'
value: 3
consequent: []
trailing: no
,
type: 'SwitchCase'
test:
type: 'NumericLiteral'
value: 4
consequent: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
]
trailing: yes
,
type: 'SwitchCase'
test: null
consequent: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
,
type: 'ExpressionStatement'
expression:
type: 'Identifier'
]
]
# # TODO: File issue for compile error when using `then` or `;` where `\n` is rn.
test "AST as expected for If node", ->
testStatement 'if maybe then yes',
type: 'IfStatement'
test: ID 'maybe'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'BooleanLiteral'
]
alternate: null
postfix: no
inverted: no
testStatement 'yes if maybe',
type: 'IfStatement'
test: ID 'maybe'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'BooleanLiteral'
]
alternate: null
postfix: yes
inverted: no
testStatement 'unless x then x else if y then y else z',
type: 'IfStatement'
test: ID 'x'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'x'
]
alternate:
type: 'IfStatement'
test: ID 'y'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'y'
]
alternate:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'z'
]
postfix: no
inverted: no
postfix: no
inverted: yes
testStatement '''
if a
b
else
if c
d
''',
type: 'IfStatement'
test: ID 'a'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'b'
]
alternate:
type: 'BlockStatement'
body: [
type: 'IfStatement'
test: ID 'c'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'd'
]
alternate: null
postfix: no
inverted: no
]
postfix: no
inverted: no
testExpression '''
a =
if b then c else if d then e
''',
type: 'AssignmentExpression'
right:
type: 'ConditionalExpression'
test: ID 'b'
consequent: ID 'c'
alternate:
type: 'ConditionalExpression'
test: ID 'd'
consequent: ID 'e'
alternate: null
postfix: no
inverted: no
postfix: no
inverted: no
testExpression '''
f(
if b
c
d
)
''',
type: 'CallExpression'
arguments: [
type: 'ConditionalExpression'
test: ID 'b'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
ID 'c'
,
type: 'ExpressionStatement'
expression:
ID 'd'
]
alternate: null
postfix: no
inverted: no
]
testStatement 'a unless b',
type: 'IfStatement'
test: ID 'b'
consequent:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression: ID 'a'
]
alternate: null
postfix: yes
inverted: yes
testExpression '''
f(
if b
c
else
d
)
''',
type: 'CallExpression'
arguments: [
type: 'ConditionalExpression'
test: ID 'b'
consequent: ID 'c'
alternate: ID 'd'
postfix: no
inverted: no
]
test "AST as expected for MetaProperty node", ->
testExpression '''
-> new.target
''',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'MetaProperty'
meta: ID 'new'
property: ID 'target'
]
testExpression '''
-> new.target.name
''',
type: 'FunctionExpression'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'MemberExpression'
object:
type: 'MetaProperty'
meta: ID 'new'
property: ID 'target'
property: ID 'name'
computed: no
]
test "AST as expected for dynamic import", ->
testExpression '''
import('a')
''',
type: 'CallExpression'
callee:
type: 'Import'
arguments: [STRING 'a']
test "AST as expected for RegexLiteral node", ->
testExpression '/a/ig',
type: 'RegExpLiteral'
pattern: 'a'
originalPattern: 'a'
flags: 'ig'
delimiter: '/'
value: undefined
extra:
raw: "/a/ig"
originalRaw: "/a/ig"
rawValue: undefined
testExpression '''
///
a
///i
''',
type: 'RegExpLiteral'
pattern: 'a'
originalPattern: '\n a\n'
flags: 'i'
delimiter: '///'
value: undefined
extra:
raw: "/a/i"
originalRaw: "///\n a\n///i"
rawValue: undefined
testExpression '/a\\w\\u1111\\u{11111}/',
type: 'RegExpLiteral'
pattern: 'a\\w\\u1111\\ud804\\udd11'
originalPattern: 'a\\w\\u1111\\u{11111}'
flags: ''
delimiter: '/'
value: undefined
extra:
raw: "/a\\w\\u1111\\ud804\\udd11/"
originalRaw: "/a\\w\\u1111\\u{11111}/"
rawValue: undefined
testExpression '''
///
a
\\w\\u1111\\u{11111}
///
''',
type: 'RegExpLiteral'
pattern: 'a\\w\\u1111\\ud804\\udd11'
originalPattern: '\n a\n \\w\\u1111\\u{11111}\n'
flags: ''
delimiter: '///'
value: undefined
extra:
raw: "/a\\w\\u1111\\ud804\\udd11/"
originalRaw: "///\n a\n \\w\\u1111\\u{11111}\n///"
rawValue: undefined
testExpression '''
///
/
(.+)
/
///
''',
type: 'RegExpLiteral'
pattern: '\\/(.+)\\/'
originalPattern: '\n /\n (.+)\n /\n'
flags: ''
delimiter: '///'
value: undefined
extra:
raw: "/\\/(.+)\\//"
originalRaw: "///\n /\n (.+)\n /\n///"
rawValue: undefined