--- /dev/null
+let assert = require('assert')
+let transform = require('./transform')
+
+let html_body = (node, st, c) => {
+ let tag, arguments
+ if (node.tag.type === 'CallExpression') {
+ tag = node.tag.callee
+ arguments = node.tag.arguments
+ }
+ else {
+ tag = node.tag
+ arguments = []
+ }
+ assert(tag.type === 'Identifier')
+
+ let prefix = '<' + tag.name, expr = undefined, expr1;
+ for (var i = 0; i < arguments.length; ++i) {
+ let name_expr, value_expr
+ if (arguments[i].type === 'AssignmentExpression') {
+ name_expr = arguments[i].left
+ value_expr = arguments[i].right
+ }
+ else {
+ name_expr = arguments[i]
+ value_expr = undefined
+ }
+
+ let name = ''
+ while (
+ name_expr.type === 'BinaryExpression' &&
+ name_expr.operator === '-' &&
+ name_expr.right.type === 'Identifier'
+ ) {
+ name = '-' + name_expr.right.name + name
+ name_expr = name_expr.left
+ }
+ assert(name_expr.type === 'Identifier')
+ name = name_expr.name + name
+ prefix += ' ' + name
+
+ if (value_expr !== undefined) {
+ prefix += '="'
+ if (value_expr.type === 'Literal')
+ prefix += value_expr.value
+ else {
+ expr1 = {
+ type: 'Literal',
+ value: prefix
+ }
+ expr = {
+ type: 'BinaryExpression',
+ left: expr === undefined ? expr1 : {
+ type: 'BinaryExpression',
+ left: expr,
+ operator: '+',
+ right: expr1,
+ start: node.start,
+ end: node.end
+ },
+ operator: '+',
+ right: value_expr
+ }
+ prefix = ''
+ }
+ prefix += '"'
+ }
+ }
+ expr1 = {
+ type: 'Literal',
+ value: prefix + '>',
+ }
+ expr = expr === undefined ? expr1 : {
+ type: 'BinaryExpression',
+ left: expr,
+ operator: '+',
+ right: expr1,
+ }
+ let result = [
+ {
+ type: 'ExpressionStatement',
+ expression: {
+ type: 'CallExpression',
+ callee: {
+ type: 'MemberExpression',
+ object: {
+ type: 'Identifier',
+ name: '_html'
+ },
+ property: {
+ type: 'Identifier',
+ name: 'push'
+ },
+ computed: false
+ },
+ arguments: [
+ expr
+ ]
+ }
+ }
+ ].concat(c(node.body, st, 'Statement').body)
+ if (
+ tag.name !== 'br' &&
+ tag.name !== 'img' &&
+ tag.name !== 'input' &&
+ tag.name !== 'link' &&
+ tag.name !== 'meta'
+ )
+ result.push(
+ {
+ type: 'ExpressionStatement',
+ expression: {
+ type: 'CallExpression',
+ callee: {
+ type: 'MemberExpression',
+ object: {
+ type: 'Identifier',
+ name: '_html'
+ },
+ property: {
+ type: 'Identifier',
+ name: 'push'
+ },
+ computed: false
+ },
+ arguments: [
+ {
+ type: 'Literal',
+ value: '</' + tag.name + '>'
+ }
+ ]
+ }
+ }
+ )
+ return result
+}
+
+let visitors = Object.assign({}, transform.visitors)
+let visitors_ExpressionStatement = visitors.ExpressionStatement
+visitors.ExpressionStatement = (node, st, c) =>
+ node.expression.type === 'Literal' ||
+ node.expression.type === 'TemplateLiteral' ||
+ node.expression.type === 'TaggedTemplateLiteral' ?
+ {
+ type: 'ExpressionStatement',
+ expression: {
+ type: 'CallExpression',
+ callee: {
+ type: 'MemberExpression',
+ object: {
+ type: 'Identifier',
+ name: '_html'
+ },
+ property: {
+ type: 'Identifier',
+ name: 'push'
+ },
+ computed: false
+ },
+ arguments: [
+ c(node.expression, st, 'Expression')
+ ]
+ }
+ } :
+ node.expression.type === 'HTMLExpression' ?
+ {
+ type: 'BlockStatement',
+ body: html_body(node.expression, st, c)
+ } :
+ visitors_ExpressionStatement(node, st, c)
+visitors.HTMLExpression = (node, st, c) => {
+ return {
+ type: 'CallExpression',
+ callee: {
+ type: 'ArrowFunctionExpression',
+ id: null,
+ expression: false,
+ generator: false,
+ async: false,
+ params: [],
+ body: {
+ type: 'BlockStatement',
+ body: [
+ {
+ type: 'VariableDeclaration',
+ declarations: [
+ {
+ type: 'VariableDeclarator',
+ id: {
+ type: 'Identifier',
+ name: '_html'
+ },
+ init: {
+ type: 'ArrayExpression',
+ elements: []
+ }
+ }
+ ],
+ kind: 'let'
+ }
+ ]
+ .concat(html_body(node, st, c))
+ .concat(
+ [
+ {
+ type: 'ReturnStatement',
+ argument: {
+ type: 'CallExpression',
+ callee: {
+ type: 'MemberExpression',
+ object: {
+ type: 'Identifier',
+ name: '_html'
+ },
+ property: {
+ type: 'Identifier',
+ name: 'join'
+ },
+ computed: false
+ },
+ arguments: [
+ {
+ type: 'Literal',
+ value: '',
+ raw: '\'\''
+ }
+ ]
+ }
+ }
+ ]
+ )
+ }
+ },
+ arguments: []
+ }
+}
+
+module.exports = visitors
--- /dev/null
+let transform = (visitors, node, state) => {
+ let c = (node, st, override) =>
+ visitors[override || node.type](node, st, c)
+ return c(node, state, node.type)
+}
+
+let skipThrough = (node, st, c) => c(node, st)
+let ignore = (node, st, c) => node
+
+// Node walkers.
+let visitors = {}
+
+visitors.Program =
+visitors.BlockStatement = (node, st, c) => {
+ for (let i = 0; i < node.body.length; ++i)
+ node.body[i] = c(node.body[i], st, 'Statement')
+ return node
+}
+visitors.Statement = skipThrough
+visitors.EmptyStatement = ignore
+visitors.ExpressionStatement =
+visitors.ParenthesizedExpression = (node, st, c) => {
+ node.expression = c(node.expression, st, 'Expression')
+ return node
+}
+visitors.IfStatement = (node, st, c) => {
+ node.test = c(node.test, st, 'Expression')
+ node.consequent = c(node.consequent, st, 'Statement')
+ if (node.alternate) node.alternate = c(node.alternate, st, 'Statement')
+ return node
+}
+visitors.LabeledStatement = (node, st, c) => {
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+visitors.BreakStatement =
+visitors.ContinueStatement = ignore
+visitors.WithStatement = (node, st, c) => {
+ node.object = c(node.object, st, 'Expression')
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+visitors.SwitchStatement = (node, st, c) => {
+ node.discriminant = c(node.discriminant, st, 'Expression')
+ for (let cs of node.cases) {
+ if (cs.test) cs.test = c(cs.test, st, 'Expression')
+ for (let i = 0; i < cs.consequent.length; ++i)
+ cs.consequent[i] = c(cs.consequent[i], st, 'Statement')
+ }
+ return node
+}
+visitors.SwitchCase = (node, st, c) => {
+ if (node.test) node.test = c(node.test, st, 'Expression')
+ for (let i = 0; i < node.consequent.length; ++i)
+ node.consequent[i] = c(node.consequent[i], st, 'Statement')
+ return node
+}
+visitors.ReturnStatement =
+visitors.YieldExpression =
+visitors.AwaitExpression = (node, st, c) => {
+ if (node.argument) node.argument = c(node.argument, st, 'Expression')
+ return node
+}
+visitors.ThrowStatement =
+visitors.SpreadElement = (node, st, c) =>
+ node.argument = c(node.argument, st, 'Expression')
+visitors.TryStatement = (node, st, c) => {
+ node.block = c(node.block, st, 'Statement')
+ if (node.handler) node.handler = c(node.handler, st)
+ if (node.finalizer) node.finalizer = c(node.finalizer, st, 'Statement')
+ return node
+}
+visitors.CatchClause = (node, st, c) => {
+ if (node.param) node.param = c(node.param, st, 'Pattern')
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+visitors.WhileStatement =
+visitors.DoWhileStatement = (node, st, c) => {
+ node.test = c(node.test, st, 'Expression')
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+visitors.ForStatement = (node, st, c) => {
+ if (node.init) node.init = c(node.init, st, 'ForInit')
+ if (node.test) node.test = c(node.test, st, 'Expression')
+ if (node.update) node.update = c(node.update, st, 'Expression')
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+visitors.ForInStatement =
+visitors.ForOfStatement = (node, st, c) => {
+ node.left = c(node.left, st, 'ForInit')
+ node.right = c(node.right, st, 'Expression')
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+visitors.ForInit = (node, st, c) => {
+ if (node.type === 'VariableDeclaration') return c(node, st)
+ else return c(node, st, 'Expression')
+ return node
+}
+visitors.DebuggerStatement = ignore
+
+visitors.FunctionDeclaration = (node, st, c) => c(node, st, 'Function')
+visitors.VariableDeclaration = (node, st, c) => {
+ for (let i = 0; i < node.declarations.length; ++i)
+ node.declarations[i] = c(node.declarations[i], st)
+ return node
+}
+visitors.VariableDeclarator = (node, st, c) => {
+ node.id = c(node.id, st, 'Pattern')
+ if (node.init) node.init = c(node.init, st, 'Expression')
+ return node
+}
+
+visitors.Function = (node, st, c) => {
+ if (node.id) node.id = c(node.id, st, 'Pattern')
+ for (let i = 0; i < node.params.length; ++i)
+ node.params[i] = c(node.params[i], st, 'Pattern')
+ node.body = c(node.body, st, node.expression ? 'Expression' : 'Statement')
+ return node
+}
+
+visitors.Pattern = (node, st, c) => {
+ if (node.type === 'Identifier')
+ return c(node, st, 'VariablePattern')
+ else if (node.type === 'MemberExpression')
+ return c(node, st, 'MemberPattern')
+ else
+ return c(node, st)
+ return node
+}
+visitors.VariablePattern = ignore
+visitors.MemberPattern = skipThrough
+visitors.RestElement = (node, st, c) =>
+ node.argument = c(node.argument, st, 'Pattern')
+visitors.ArrayPattern = (node, st, c) => {
+ for (let i = 0; i < node.elements.length; ++i) {
+ let elt = node.elements[i]
+ if (elt) node.elements[i] = c(elt, st, 'Pattern')
+ }
+ return node
+}
+visitors.ObjectPattern = (node, st, c) => {
+ for (let prop of node.properties) {
+ if (prop.type === 'Property') {
+ if (prop.computed) prop.key = c(prop.key, st, 'Expression')
+ prop.value = c(prop.value, st, 'Pattern')
+ } else if (prop.type === 'RestElement') {
+ prop.argument = c(prop.argument, st, 'Pattern')
+ }
+ }
+ return node
+}
+
+visitors.Expression = skipThrough
+visitors.ThisExpression =
+visitors.Super =
+visitors.MetaProperty = ignore
+visitors.ArrayExpression = (node, st, c) => {
+ for (let i = 0; i < node.elements.length; ++i) {
+ let elt = node.elements[i]
+ if (elt) node.elements[i] = c(elt, st, 'Expression')
+ }
+ return node
+}
+visitors.ObjectExpression = (node, st, c) => {
+ for (let i = 0; i < node.properties.length; ++i)
+ node.properties[i] = c(node.properties[i], st)
+ return node
+}
+visitors.FunctionExpression =
+visitors.ArrowFunctionExpression = visitors.FunctionDeclaration
+visitors.SequenceExpression = (node, st, c) => {
+ for (let i = 0; i < node.expressions.length; ++i)
+ node.expressions[i] = c(node.expressions[i], st, 'Expression')
+ return node
+}
+visitors.TemplateLiteral = (node, st, c) => {
+ for (let i = 0; i < node.quasis.length; ++i)
+ node.quasis[i] = c(node.quasis[i], st)
+
+ for (let i = 0; i < node.expressions.length; ++i)
+ node.expressions[i] = c(node.expressions[i], st, 'Expression')
+ return node
+}
+visitors.TemplateElement = ignore
+visitors.UnaryExpression =
+visitors.UpdateExpression = (node, st, c) => {
+ node.argument = c(node.argument, st, 'Expression')
+ return node
+}
+visitors.BinaryExpression =
+visitors.LogicalExpression = (node, st, c) => {
+ node.left = c(node.left, st, 'Expression')
+ node.right = c(node.right, st, 'Expression')
+ return node
+}
+visitors.AssignmentExpression =
+visitors.AssignmentPattern = (node, st, c) => {
+ node.left = c(node.left, st, 'Pattern')
+ node.right = c(node.right, st, 'Expression')
+ return node
+}
+visitors.ConditionalExpression = (node, st, c) => {
+ node.test = c(node.test, st, 'Expression')
+ node.consequent = c(node.consequent, st, 'Expression')
+ node.alternate = c(node.alternate, st, 'Expression')
+ return node
+}
+visitors.NewExpression =
+visitors.CallExpression = (node, st, c) => {
+ node.callee = c(node.callee, st, 'Expression')
+ if (node.arguments)
+ for (let i = 0; i < node.arguments.length; ++i)
+ node.arguments[i] = c(node.arguments[i], st, 'Expression')
+ return node
+}
+visitors.MemberExpression = (node, st, c) => {
+ node.object = c(node.object, st, 'Expression')
+ if (node.computed) node.property = c(node.property, st, 'Expression')
+ return node
+}
+visitors.ExportNamedDeclaration =
+visitors.ExportDefaultDeclaration = (node, st, c) => {
+ if (node.declaration)
+ node.declaration = c(node.declaration, st, node.type === 'ExportNamedDeclaration' || node.declaration.id ? 'Statement' : 'Expression')
+ if (node.source) node.source = c(node.source, st, 'Expression')
+ return node
+}
+visitors.ExportAllDeclaration = (node, st, c) => {
+ node.source = c(node.source, st, 'Expression')
+ return node
+}
+visitors.ImportDeclaration = (node, st, c) => {
+ for (let i = 0; i < node.specifiers.length; ++i)
+ node.specifiers[i] = c(node.specifiers[i], st)
+ node.source = c(node.source, st, 'Expression')
+ return node
+}
+visitors.ImportSpecifier =
+visitors.ImportDefaultSpecifier =
+visitors.ImportNamespaceSpecifier =
+visitors.Identifier =
+visitors.Literal = ignore
+
+visitors.TaggedTemplateExpression = (node, st, c) => {
+ node.tag = c(node.tag, st, 'Expression')
+ node.quasi = c(node.quasi, st, 'Expression')
+ return node
+}
+visitors.ClassDeclaration =
+visitors.ClassExpression = (node, st, c) => c(node, st, 'Class')
+visitors.Class = (node, st, c) => {
+ if (node.id) node.id = c(node.id, st, 'Pattern')
+ if (node.superClass) node.superClass = c(node.superClass, st, 'Expression')
+ node.body = c(node.body, st)
+ return node
+}
+visitors.ClassBody = (node, st, c) => {
+ for (let i = 0; i < node.body.length; ++i)
+ node.body[i] = c(node.body[i], st)
+ return node
+}
+visitors.MethodDefinition =
+visitors.Property = (node, st, c) => {
+ if (node.computed) node.key = c(node.key, st, 'Expression')
+ node.value = c(node.value, st, 'Expression')
+ return node
+}
+
+// Nick
+visitors.HTMLExpression = (node, st, c) => {
+ node.tag = c(node.tag, st, 'Expression')
+ node.body = c(node.body, st, 'Statement')
+ return node
+}
+
+exports.transform = transform
+exports.visitors = visitors