diff --git a/compiler/Builder.js b/compiler/Builder.js index 4048a24d59..1a79586f70 100644 --- a/compiler/Builder.js +++ b/compiler/Builder.js @@ -23,7 +23,6 @@ var Text = require('./ast/Text'); var ForEach = require('./ast/ForEach'); var ForEachProp = require('./ast/ForEachProp'); var ForRange = require('./ast/ForRange'); -var Slot = require('./ast/Slot'); var HtmlComment = require('./ast/HtmlComment'); var SelfInvokingFunction = require('./ast/SelfInvokingFunction'); var ForStatement = require('./ast/ForStatement'); @@ -72,6 +71,7 @@ var literalUndefined = new Literal({value: undefined}); var literalTrue = new Literal({value: true}); var literalFalse = new Literal({value: false}); var identifierOut = new Identifier({name: 'out'}); +var identifierRequire = new Identifier({name: 'require'}); class Builder { arrayExpression(elements) { @@ -266,6 +266,11 @@ class Builder { } } + htmlLiteral(htmlCode) { + var argument = new Literal({value: htmlCode}); + return new Html({argument}); + } + identifier(name) { ok(typeof name === 'string', '"name" should be a string'); @@ -425,7 +430,7 @@ class Builder { require(path) { path = makeNode(path); - let callee = 'require'; + let callee = identifierRequire; let args = [ path ]; return new FunctionCall({callee, args}); } @@ -462,10 +467,6 @@ class Builder { return new SelfInvokingFunction({params, args, body}); } - slot(onDone) { - return new Slot({onDone}); - } - strictEquality(left, right) { left = makeNode(left); right = makeNode(right); diff --git a/compiler/CodeGenerator.js b/compiler/CodeGenerator.js index 6489bbfd62..437b4ca1f0 100644 --- a/compiler/CodeGenerator.js +++ b/compiler/CodeGenerator.js @@ -5,10 +5,9 @@ const Node = require('./ast/Node'); const Literal = require('./ast/Literal'); const Identifier = require('./ast/Identifier'); const HtmlElement = require('./ast/HtmlElement'); +const Html = require('./ast/Html'); const ok = require('assert').ok; const Container = require('./ast/Container'); -const util = require('util'); -const isValidJavaScriptVarName = require('./util/isValidJavaScriptVarName'); const createError = require('raptor-util/createError'); class GeneratorEvent { @@ -19,93 +18,45 @@ class GeneratorEvent { this.isBefore = true; this.builder = codegen.builder; this.context = codegen.context; + + this.insertedNodes = null; } insertCode(newCode) { - this.codegen.generateStatements(newCode); - - if (this.isBefore) { - if (!this.codegen._code.endsWith(this.codegen.currentIndent)) { - this.codegen.writeLineIndent(); - } - } + this.insertedNodes = newCode; } } -class Slot { - constructor(codegen, slotNode) { - this._content = null; - - this._start = codegen._code.length; - codegen.write('/* slot */'); - - if (slotNode.statement) { - codegen.write('\n'); - } - this._end = codegen._code.length; - - this.currentIndent = codegen.currentIndent; - this._inFunction = codegen.inFunction; - this._statement = slotNode.statement; - } - - setContent(content) { - this._content = content; +class FinalNodes { + constructor() { + this.nodes = []; + this.nodes._finalNode = true; // Mark the array as a collection of final nodes + this.lastNode = null; } - generateCode(codegen) { - let content = this._content; - let slotCode; - - if (content) { - let isStatement = this._statement; - - codegen.currentIndent = this.currentIndent; - codegen.inFunction = this._inFunction; - - let capture = codegen._beginCaptureCode(); - - if (isStatement) { - codegen.generateStatements(content); - } else { - codegen.generateCode(content); - } - - slotCode = capture.end(); - - if (isStatement && slotCode.startsWith(codegen.currentIndent)) { - slotCode = slotCode.substring(codegen.currentIndent.length); - } + push(node) { + if (!node) { + return; } + if (node instanceof Html && this.lastNode instanceof Html) { + this.lastNode.append(node); + return; + } - - let oldCode = codegen._code; - let beforeCode = oldCode.substring(0, this._start); - let afterCode = oldCode.substring(this._end); - - if (slotCode) { - codegen._code = beforeCode + slotCode + afterCode; - } else { - let beforeWhitespaceMatches = beforeCode.match(/[\n]\s*$/); - if (beforeWhitespaceMatches != null) { - let beforeWhitespace = beforeWhitespaceMatches[0]; - - if (afterCode.startsWith(beforeWhitespace)) { - afterCode = afterCode.substring(beforeWhitespace.length); - } - } - codegen._code = beforeCode + afterCode; + if (node.setFinalNode) { + node.setFinalNode(true); } + + this.lastNode = node; + this.nodes.push(node); } } -class Generator { +class CodeGenerator { constructor(context, options) { options = options || {}; this.root = null; - this._indentStr = options.indent != null ? options.indent : ' '; - this._indentSize = this._indentStr.length; this._code = ''; this.currentIndent = ''; @@ -113,7 +64,7 @@ class Generator { this._doneListeners = []; - this._bufferedWrites = null; + this.builder = context.builder; this.outputType = options.output || 'html'; this.context = context; @@ -124,16 +75,6 @@ class Generator { this.outputType.charAt(0).toUpperCase() + this.outputType.substring(1) + 'Code'; - - this._slots = []; - } - - beginSlot(slotNode) { - var addSeparator = slotNode.statement; - this._flushBufferedWrites(addSeparator); - let slot = new Slot(this, slotNode); - this._slots.push(slot); - return slot; } addVar(name, value) { @@ -156,33 +97,63 @@ class Generator { return this.context.importModule(varName, path); } - generateCode(node) { - ok(node != null, '"node" is required'); + _invokeCodeGenerator(func, node, isMethod) { + try { + if (isMethod) { + return func.call(node, this); + } else { + return func.call(node, node, this); + } + } catch(err) { + var errorMessage = 'Generating code for '; - if (typeof node === 'string' || - typeof node === 'number' || - typeof node === 'boolean') { - this.write(node); - return; - } else if (isArray(node)) { - node.forEach(this.generateCode, this); + if (node instanceof HtmlElement) { + errorMessage += '<'+node.tagName+'> tag'; + } else { + errorMessage += node.type + ' node'; + } + + if (node.pos) { + errorMessage += ' ('+this.context.getPosInfo(node.pos)+')'; + } + + errorMessage += ' failed. Error: ' + err; + + throw createError(errorMessage, err /* cause */); + } + } + + _generateCode(node, finalNodes) { + if (isArray(node)) { + node.forEach((child) => { + this._generateCode(child, finalNodes); + }); return; } else if (node instanceof Container) { node.forEach((child) => { if (child.container === node) { - this.generateCode(child); + this._generateCode(child, finalNodes); } }); return; } + if (node == null) { + return; + } + + if (typeof node === 'string' || node._finalNode || !(node instanceof Node)) { + finalNodes.push(node); + return; + } + + if (node._normalizeChildTextNodes) { + node._normalizeChildTextNodes(this.context); + } + let oldCurrentNode = this._currentNode; this._currentNode = node; - let finalNode; - let generateCodeFunc; - var isStatement = node.statement; - var beforeAfterEvent; if (node.listenerCount('beforeGenerateCode') || node.listenerCount('afterGenerateCode')) { @@ -191,83 +162,56 @@ class Generator { var isWhitespacePreserved = node.isPreserveWhitespace(); + if (isWhitespacePreserved) { + this.context.beginPreserveWhitespace(); + } + if (beforeAfterEvent) { beforeAfterEvent.isBefore = true; beforeAfterEvent.node.emit('beforeGenerateCode', beforeAfterEvent); - if (isWhitespacePreserved) { - this.context.beginPreserveWhitespace(); + if (beforeAfterEvent.insertedNodes) { + this._generateCode(beforeAfterEvent.insertedNodes, finalNodes); + beforeAfterEvent.insertedNodes = null; } } + let codeGeneratorFunc; + let generatedCode; + if (node.getCodeGenerator) { - generateCodeFunc = node.getCodeGenerator(this.outputType); - if (generateCodeFunc) { - try { - finalNode = generateCodeFunc(node, this); - } catch(err) { - var errorMessage = 'Generating code for '; - - if (node instanceof HtmlElement) { - errorMessage += '<'+node.tagName+'> tag'; - } else { - errorMessage += node.type + ' node'; - } - - if (node.pos) { - errorMessage += ' ('+this.context.getPosInfo(node.pos)+')'; - } - - errorMessage += ' failed. Error: ' + err; - - throw createError(errorMessage, err /* cause */); - } + codeGeneratorFunc = node.getCodeGenerator(this.outputType); - if (finalNode === node) { - // If the same node was returned then we will generate - // code for the node as normal - finalNode = null; - } else if (finalNode == null) { - // If nothing was returned then don't generate any code + if (codeGeneratorFunc) { + node.setCodeGenerator(null); + + generatedCode = this._invokeCodeGenerator(codeGeneratorFunc, node, false); + if (generatedCode != null && generatedCode !== node) { node = null; + this._generateCode(generatedCode, finalNodes); } } } - if (finalNode) { - if (isStatement) { - this.generateStatements(finalNode); - } else { - this.generateCode(finalNode); - } - } else if (node) { - let generateCodeMethod = node.generateCode; - - if (!generateCodeMethod) { - generateCodeMethod = node[this._codegenCodeMethodName]; + if (node != null) { + codeGeneratorFunc = node.generateCode; - if (!generateCodeMethod) { - throw new Error('No code codegen for node of type "' + - node.type + - '" (output type: "' + this.outputType + '"). Node: ' + util.inspect(node)); - } + if (!codeGeneratorFunc) { + codeGeneratorFunc = node[this._codegenCodeMethodName]; } - // The generateCode function can optionally return either of the following: - // - An AST node - // - An array/cointainer of AST nodes - finalNode = generateCodeMethod.call(node, this); - - if (finalNode != null) { - if (finalNode === node) { - throw new Error('Invalid node returned. Same node returned: ' + util.inspect(node)); - } + if (codeGeneratorFunc) { + generatedCode = this._invokeCodeGenerator(codeGeneratorFunc, node, true); - if (isStatement) { - this.generateStatements(finalNode); + if (generatedCode === undefined || generatedCode === node) { + finalNodes.push(node); + } else if (generatedCode === null) { + // If nothing was returned then don't generate any code } else { - this.generateCode(finalNode); + this._generateCode(generatedCode, finalNodes); } + } else { + finalNodes.push(node); } } @@ -275,263 +219,45 @@ class Generator { beforeAfterEvent.isBefore = false; beforeAfterEvent.node.emit('afterGenerateCode', beforeAfterEvent); - if (isWhitespacePreserved) { - this.context.endPreserveWhitespace(); - } - } - - this._currentNode = oldCurrentNode; - } - - getCode() { - this._flushBufferedWrites(); - - while(this._doneListeners.length || this._slots.length) { - - let doneListeners = this._doneListeners; - if (doneListeners.length) { - this._doneListeners = []; - - for (let i=0; i=0; i--) { - let slot = slots[i]; - slot.generateCode(this); - } - } - } - - return this._code; - } - - generateBlock(body) { - if (!body) { - this.write('{}'); - return; - } - - if (typeof body === 'function') { - body = body(); - } - - if (!isArray(body) && !(body instanceof Container)) { - throw new Error('Invalid body'); - } - - if (body.length === 0) { - this.write('{}'); - return; - } - - this.write('{\n') - .incIndent(); - - let oldCodeLength = this._code.length; - - this.generateStatements(body); - - if (this._bufferedWrites) { - if (this._code.length !== oldCodeLength) { - this._code += '\n'; - } - this._flushBufferedWrites(); - } - - this.decIndent() - .writeLineIndent() - .write('}'); - } - - generateStatements(nodes) { - ok(nodes, '"nodes" expected'); - let firstStatement = true; - - if (nodes instanceof Node) { - nodes = [nodes]; - } - - nodes.forEach((node) => { - if (node instanceof Node) { - node.statement = true; - } - - let startCodeLen = this._code.length; - - let currentIndent = this.currentIndent; - - if (!firstStatement) { - this._write('\n'); - } - - if (!this._code.endsWith(currentIndent)) { - this.writeLineIndent(); - } - - let startPos = this._code.length; - - if (Array.isArray(node) || (node instanceof Container)) { - this.generateStatements(node); - } else { - this.generateCode(node); - } - - if (this._code.length === startPos) { - // No code was generated. Remove any code that was previously added - this._code = this._code.slice(0, startCodeLen); - return; - } - - if (this._code.endsWith('\n')) { - // Do nothing - } else if (this._code.endsWith(';')) { - this._code += '\n'; - } else if (this._code.endsWith('\n' + this.currentIndent)) { - // Do nothing - } else { - this._code += ';\n'; + if (beforeAfterEvent.insertedNodes) { + this._generateCode(beforeAfterEvent.insertedNodes, finalNodes); + beforeAfterEvent.insertedNodes = null; } - - firstStatement = false; - }); - } - - _beginCaptureCode() { - let oldCode = this._code; - this._code = ''; - - return { - codegen: this, - end() { - let newCode = this.codegen._code; - this.codegen._code = oldCode; - return newCode; - } - }; - } - - addWriteLiteral(value) { - if (!(value instanceof Literal)) { - value = new Literal({value}); } - this.addWrite(value); - } - - addWrite(output) { - ok(output, '"output" is required'); - if (output instanceof Literal) { - let lastWrite = this._bufferedWrites ? - this._bufferedWrites[this._bufferedWrites.length-1] : - null; - if (lastWrite instanceof Literal) { - lastWrite.value += output.value; - return; - } - } else { - if (!(output instanceof Node)) { - throw new Error('Invalid write: ' + JSON.stringify(output, null, 2)); - } + if (isWhitespacePreserved) { + this.context.endPreserveWhitespace(); } - if (!this._bufferedWrites) { - this._bufferedWrites = [output]; - } else { - this._bufferedWrites.push(output); - } + this._currentNode = oldCurrentNode; } - _flushBufferedWrites(addSeparator) { - let bufferedWrites = this._bufferedWrites; - - if (!bufferedWrites) { - return; - } - - this._bufferedWrites = null; - - if (!addSeparator && !this._code.endsWith(this.currentIndent)) { - this.writeLineIndent(); + generateCode(node) { + if (!node) { + return null; } - let len = bufferedWrites.length; - - for (let i=0; i { + if (Array.isArray(node) || (node instanceof Container)) { + node.forEach(writeNode); + return; + } else { + if (firstStatement) { + firstStatement = false; + } else { + this._write('\n'); + } + + this.writeLineIndent(); + + if (typeof node === 'string') { + this._write(node); + } else { + node.statement = true; + this.write(node); + } + + if (this._code.endsWith('\n')) { + // Do nothing + } else if (this._code.endsWith(';')) { + this._code += '\n'; + } else if (this._code.endsWith('\n' + this.currentIndent)) { + // Do nothing + } else { + this._code += ';\n'; + } + } + }; + + if (nodes instanceof Node) { + writeNode(nodes); + } else { + nodes.forEach(writeNode); + } + } + + write(code) { + if (code == null || code === '') { + return; + } + + if (code instanceof Node) { + let node = code; + if (!node.writeCode) { + throw new Error('Node does not have a `writeCode` method: ' + JSON.stringify(node, null, 4)); + } + node.writeCode(this); + } else if (isArray(code) || code instanceof Container) { + code.forEach(this.write, this); + return; + } else if (typeof code === 'string') { + this._code += code; + } else if (typeof code === 'boolean' || typeof code === 'number') { + this._code += code.toString(); + } else { + throw new Error('Illegal argument: ' + JSON.stringify(code)); + } + + return this; + } + + _write(code) { + this._code += code; + return this; + } + + incIndent(count) { + if (count != null) { + for (let i=0; i)) - - var loadTemplateVar = this.addStaticVar('loadTemplate', '__helpers.l'); var requireResolveTemplate = requireResolve(builder, builder.literal(relativePath)); - var loadFunctionCall = builder.functionCall(loadTemplateVar, [ requireResolveTemplate ]); + var loadFunctionCall = builder.functionCall(this.helper('loadTemplate'), [ requireResolveTemplate ]); var templateVar = this.addStaticVar(removeExt(relativePath), loadFunctionCall); return templateVar; } @@ -447,6 +470,61 @@ class CompileContext { return pathExpression; } + + getStaticNodes() { + let builder = this.builder; + let staticNodes = []; + let staticVars = this.getStaticVars(); + + let staticVarNodes = Object.keys(staticVars).map((varName) => { + var varInit = staticVars[varName]; + return builder.variableDeclarator(varName, varInit); + }); + + + if (staticVarNodes.length) { + staticNodes.push(this.builder.vars(staticVarNodes)); + } + + var staticCodeArray = this.getStaticCode(); + + if (staticCodeArray) { + staticNodes = staticNodes.concat(staticCodeArray); + } + + return staticNodes; + } + + get helpersIdentifier() { + if (!this._helpersIdentifier) { + if (this.inline) { + this._helpersIdentifier = this.importModule('__markoHelpers', 'marko/runtime/helpers'); + } else { + // The helpers variable is a parameter of the outer create function + this._helpersIdentifier = this.builder.identifier('__markoHelpers'); + } + } + return this._helpersIdentifier; + } + + helper(name) { + var helperIdentifier = this._helpers[name]; + if (!helperIdentifier) { + var methodName = helpers[name]; + if (!methodName) { + throw new Error('Invalid helper: ' + name); + } + var methodIdentifier = this.builder.identifier(methodName); + + helperIdentifier = this.addStaticVar( + 'marko_' + name, + this.builder.memberExpression(this.helpersIdentifier, methodIdentifier)); + + this._helpers[name] = helperIdentifier; + } + + return helperIdentifier; + } } CompileContext.prototype.util = { diff --git a/compiler/Compiler.js b/compiler/Compiler.js index 700b55f7e4..e92066cf07 100644 --- a/compiler/Compiler.js +++ b/compiler/Compiler.js @@ -1,10 +1,8 @@ 'use strict'; var ok = require('assert').ok; var CodeGenerator = require('./CodeGenerator'); -var CompileContext = require('./CompileContext'); +var CodeWriter = require('./CodeWriter'); var createError = require('raptor-util/createError'); -var config = require('./config'); -var extend = require('raptor-util/extend'); const FLAG_TRANSFORMER_APPLIED = 'transformerApply'; @@ -61,8 +59,47 @@ function transformTree(rootNode, context) { return rootNode; } +function handleErrors(context) { + // If there were any errors then compilation failed. + if (context.hasErrors()) { + var errors = context.getErrors(); + + var message = 'An error occurred while trying to compile template at path "' + context.filename + '". Error(s) in template:\n'; + for (var i = 0, len = errors.length; i < len; i++) { + let error = errors[i]; + message += (i + 1) + ') ' + error.toString() + '\n'; + } + var error = new Error(message); + error.errors = errors; + throw error; + } +} + +class CompiledTemplate { + constructor(ast, context, codeGenerator) { + this.ast = ast; + this.context = context; + this.filename = context.filename; + } + + get code() { + // STAGE 3: Generate the code using the final AST + handleErrors(this.context); + + // console.log(module.id, 'FINAL AST:' + JSON.stringify(finalAST, null, 4)); + var codeWriter = new CodeWriter(this.context.options); + codeWriter.write(this.ast); + + handleErrors(this.context); + + // Return the generated code as the compiled output: + var compiledSrc = codeWriter.getCode(); + return compiledSrc; + } +} + class Compiler { - constructor(options) { + constructor(options, userOptions, inline) { ok(options, '"options" is required'); this.builder = options.builder; @@ -72,32 +109,14 @@ class Compiler { ok(this.parser, '"options.parser" is required'); } - compile(src, filename, userOptions) { + compile(src, context) { ok(typeof src === 'string', '"src" argument should be a string'); - ok(filename, '"filename" argument is required'); - ok(typeof filename === 'string', '"filename" argument should be a string'); - - var context = new CompileContext(src, filename, this.builder); - var options = {}; - - extend(options, config); - - if (userOptions) { - extend(options, userOptions); - } - - if (options.preserveWhitespace) { - context.setPreserveWhitespace(true); - } var codeGenerator = new CodeGenerator(context); // STAGE 1: Parse the template to produce the initial AST var ast = this.parser.parse(src, context); - // Trim start and end whitespace for the root node - ast._normalizeChildTextNodes(codeGenerator, true /* trim start and end */, true /* force */); - context.root = ast; // console.log('ROOT', JSON.stringify(ast, null, 2)); @@ -105,30 +124,13 @@ class Compiler { var transformedAST = transformTree(ast, context); // console.log('transformedAST', JSON.stringify(ast, null, 2)); - // Trim start and end whitespace for the root node (again, after the transformation) - transformedAST._normalizeChildTextNodes(codeGenerator, true /* trim start and end */, true /* force */); + handleErrors(context); - // STAGE 3: Generate the code using the final AST - - codeGenerator.generateCode(transformedAST); + var finalAST = codeGenerator.generateCode(transformedAST); - // If there were any errors then compilation failed. - if (context.hasErrors()) { - var errors = context.getErrors(); + handleErrors(context); - var message = 'An error occurred while trying to compile template at path "' + filename + '". Error(s) in template:\n'; - for (var i = 0, len = errors.length; i < len; i++) { - let error = errors[i]; - message += (i + 1) + ') ' + error.toString() + '\n'; - } - var error = new Error(message); - error.errors = errors; - throw error; - } - - // Return the generated code as the compiled output: - var compiledSrc = codeGenerator.getCode(); - return compiledSrc; + return new CompiledTemplate(finalAST, context); } } diff --git a/compiler/InlineCompiler.js b/compiler/InlineCompiler.js new file mode 100644 index 0000000000..3b8d2fe54b --- /dev/null +++ b/compiler/InlineCompiler.js @@ -0,0 +1,84 @@ +'use strict'; + +let CodeWriter = require('./CodeWriter'); + +function fixIndentation(lines) { + let length = lines.length; + let startLine = 0; + let endLine = length; + + for (; startLinestartLine; endLine--) { + let line = lines[endLine-1]; + if (line.trim() !== '') { + break; + } + } + + if (endLine === startLine) { + return ''; + } + + if (startLine !== 0 || endLine !== length) { + lines = lines.slice(startLine, endLine); + } + + let firstLine = lines[0]; + let indentToRemove = /^\s*/.exec(firstLine)[0]; + + if (indentToRemove) { + for (let i=0; i\n' + src + '\n<'); + return this.compiler.compile(src, this.context); + } + + get staticCode() { + let staticNodes = this.context.getStaticNodes(); + + if (!staticNodes || staticNodes.length === 0) { + return null; + } + + let codeWriter = new CodeWriter(this.context.options); + codeWriter.write(staticNodes); + return codeWriter.getCode(); + } +} + +module.exports = InlineCompiler; \ No newline at end of file diff --git a/compiler/Parser.js b/compiler/Parser.js index 606775c54c..a26160f70b 100644 --- a/compiler/Parser.js +++ b/compiler/Parser.js @@ -63,8 +63,8 @@ function mergeShorthandClassNames(el, shorthandClassNames, context) { if (finalClassNames.length === 1) { el.setAttributeValue('class', finalClassNames[0]); } else { - var classListVar = context.addStaticVar('__classList', '__helpers.cl'); - el.setAttributeValue('class', builder.functionCall(classListVar, finalClassNames)); + + el.setAttributeValue('class', builder.functionCall(context.helper('classList'), finalClassNames)); } } @@ -141,6 +141,8 @@ class Parser { if (tagNameExpression) { tagName = builder.parseExpression(tagNameExpression); } else if (tagName === 'marko-compiler-options') { + this.parentNode.setTrimStartEnd(true); + attributes.forEach(function (attr) { let attrName = attr.name; let handler = COMPILER_ATTRIBUTE_HANDLERS[attrName]; @@ -279,6 +281,8 @@ class Parser { this.prevTextNode = null; this.stack.pop(); + + } handleComment(comment) { diff --git a/compiler/ast/ArrayExpression.js b/compiler/ast/ArrayExpression.js index 50b5abff58..716a0efd1c 100644 --- a/compiler/ast/ArrayExpression.js +++ b/compiler/ast/ArrayExpression.js @@ -9,32 +9,37 @@ class ArrayExpression extends Node { } generateCode(codegen) { + this.elements = codegen.generateCode(this.elements); + return this; + } + + writeCode(writer) { var elements = this.elements; if (!elements || !elements.length) { - codegen.write('[]'); + writer.write('[]'); return; } - codegen.incIndent(); - codegen.write('[\n'); - codegen.incIndent(); + writer.incIndent(); + writer.write('[\n'); + writer.incIndent(); elements.forEach((element, i) => { - codegen.writeLineIndent(); - codegen.generateCode(element); + writer.writeLineIndent(); + writer.write(element); if (i < elements.length - 1) { - codegen.write(',\n'); + writer.write(',\n'); } else { - codegen.write('\n'); + writer.write('\n'); } }); - codegen.decIndent(); - codegen.writeLineIndent(); - codegen.write(']'); - codegen.decIndent(); + writer.decIndent(); + writer.writeLineIndent(); + writer.write(']'); + writer.decIndent(); } walk(walker) { diff --git a/compiler/ast/Assignment.js b/compiler/ast/Assignment.js index 7c449130ac..5160475ace 100644 --- a/compiler/ast/Assignment.js +++ b/compiler/ast/Assignment.js @@ -11,23 +11,29 @@ class Assignment extends Node { } generateCode(codegen) { + this.left = codegen.generateCode(this.left); + this.right = codegen.generateCode(this.right); + return this; + } + + writeCode(writer) { var left = this.left; var right = this.right; var operator = this.operator; - codegen.generateCode(left); - codegen.write(' ' + (operator || '=') + ' '); + writer.write(left); + writer.write(' ' + (operator || '=') + ' '); var wrap = right instanceof Assignment; if (wrap) { - codegen.write('('); + writer.write('('); } - codegen.generateCode(right); + writer.write(right); if (wrap) { - codegen.write(')'); + writer.write(')'); } } diff --git a/compiler/ast/AttributePlaceholder.js b/compiler/ast/AttributePlaceholder.js index 495cc7c9d8..eb1702974e 100644 --- a/compiler/ast/AttributePlaceholder.js +++ b/compiler/ast/AttributePlaceholder.js @@ -10,7 +10,12 @@ class AttributePlaceholder extends Node { } generateCode(codegen) { - codegen.generateCode(this.value); + this.value = codegen.generateCode(this.value); + return this; + } + + writeCode(writer) { + writer.write(this.value); } walk(walker) { diff --git a/compiler/ast/BinaryExpression.js b/compiler/ast/BinaryExpression.js index 9634b47bee..bec177cd12 100644 --- a/compiler/ast/BinaryExpression.js +++ b/compiler/ast/BinaryExpression.js @@ -3,17 +3,17 @@ var Node = require('./Node'); var isCompoundExpression = require('../util/isCompoundExpression'); -function generateCodeForOperand(node, codegen) { +function writeCodeForOperand(node, writer) { var wrap = isCompoundExpression(node); if (wrap) { - codegen.write('('); + writer.write('('); } - codegen.generateCode(node); + writer.write(node); if (wrap) { - codegen.write(')'); + writer.write(')'); } } @@ -44,31 +44,48 @@ class BinaryExpression extends Node { } generateCode(codegen) { + this.left = codegen.generateCode(this.left); + this.right = codegen.generateCode(this.right); + var left = this.left; - var operator = this.operator; var right = this.right; + var operator = this.operator; if (!left || !right) { throw new Error('Invalid BinaryExpression: ' + this); } + var builder = codegen.builder; + if (left.type === 'Literal' && right.type === 'Literal') { if (operator === '+') { - return codegen.generateCode(codegen.builder.literal(left.value + right.value)); + return builder.literal(left.value + right.value); } else if (operator === '-') { - return codegen.generateCode(codegen.builder.literal(left.value - right.value)); + return builder.literal(left.value - right.value); } else if (operator === '*') { - return codegen.generateCode(codegen.builder.literal(left.value * right.value)); + return builder.literal(left.value * right.value); } else if (operator === '/') { - return codegen.generateCode(codegen.builder.literal(left.value / right.value)); + return builder.literal(left.value / right.value); } } - generateCodeForOperand(left, codegen); - codegen.write(' '); - codegen.generateCode(operator); - codegen.write(' '); - generateCodeForOperand(right, codegen); + return this; + } + + writeCode(writer) { + var left = this.left; + var operator = this.operator; + var right = this.right; + + if (!left || !right) { + throw new Error('Invalid BinaryExpression: ' + this); + } + + writeCodeForOperand(left, writer); + writer.write(' '); + writer.write(operator); + writer.write(' '); + writeCodeForOperand(right, writer); } isCompoundExpression() { diff --git a/compiler/ast/Code.js b/compiler/ast/Code.js index 18ed639404..94b2524cbe 100644 --- a/compiler/ast/Code.js +++ b/compiler/ast/Code.js @@ -10,15 +10,19 @@ class Code extends Node { } generateCode(codegen) { + return this; + } + + writeCode(writer) { var code = this.value; if (!code) { return; } - code = adjustIndent(code, codegen.currentIndent); + code = adjustIndent(code, writer.currentIndent); - codegen.write(code); + writer.write(code); } } diff --git a/compiler/ast/ConditionalExpression.js b/compiler/ast/ConditionalExpression.js index 93e0145d5d..8329bb2877 100644 --- a/compiler/ast/ConditionalExpression.js +++ b/compiler/ast/ConditionalExpression.js @@ -11,16 +11,22 @@ class ConditionalExpression extends Node { } generateCode(codegen) { + this.test = codegen.generateCode(this.test); + this.consequent = codegen.generateCode(this.consequent); + this.alternate = codegen.generateCode(this.alternate); + return this; + } + + writeCode(writer) { var test = this.test; var consequent = this.consequent; var alternate = this.alternate; - - codegen.generateCode(test); - codegen.write(' ? '); - codegen.generateCode(consequent); - codegen.write(' : '); - codegen.generateCode(alternate); + writer.write(test); + writer.write(' ? '); + writer.write(consequent); + writer.write(' : '); + writer.write(alternate); } isCompoundExpression() { diff --git a/compiler/ast/ContainerNode.js b/compiler/ast/ContainerNode.js index 3a0fc9e916..597514db76 100644 --- a/compiler/ast/ContainerNode.js +++ b/compiler/ast/ContainerNode.js @@ -8,6 +8,10 @@ class ContainerNode extends Node { this.body = this.makeContainer(def.body); } + generateCode(codegen) { + return codegen.genereateCode(this.body); + } + walk(walker) { this.body = walker.walk(this.body); } diff --git a/compiler/ast/CustomTag.js b/compiler/ast/CustomTag.js index fcf09f1eba..07c0a68938 100644 --- a/compiler/ast/CustomTag.js +++ b/compiler/ast/CustomTag.js @@ -230,7 +230,7 @@ class CustomTag extends HtmlElement { let parentTagNode = getNestedTagParentNode(this, parentTagName); if (!parentTagNode) { codegen.addError('Invalid usage of the <' + this.tagName + '> nested tag. Tag not nested within a <' + parentTagName + '> tag.'); - return; + return null; } parentTagVar = parentTagNode.data.nestedTagVar; } @@ -239,9 +239,9 @@ class CustomTag extends HtmlElement { var inputProps = buildInputProps(this, context); var renderBodyFunction; + var body = codegen.generateCode(this.body); - if (this.body && this.body.length) { - + if (body && body.length) { if (tagDef.bodyFunction) { let bodyFunction = tagDef.bodyFunction; let bodyFunctionName = bodyFunction.name; @@ -249,9 +249,9 @@ class CustomTag extends HtmlElement { return builder.identifier(param); }); - inputProps[bodyFunctionName] = builder.functionDeclaration(bodyFunctionName, bodyFunctionParams, this.body); + inputProps[bodyFunctionName] = builder.functionDeclaration(bodyFunctionName, bodyFunctionParams, body); } else { - renderBodyFunction = context.builder.renderBodyFunction(this.body); + renderBodyFunction = context.builder.renderBodyFunction(body); if (nestedTagVar) { renderBodyFunction.params.push(nestedTagVar); } else { @@ -289,7 +289,7 @@ class CustomTag extends HtmlElement { if (Object.keys(inputProps.value).length === 0) { inputProps = argument; } else { - var mergeVar = codegen.addStaticVar('__merge', '__helpers.m'); + var mergeVar = context.helper('merge'); inputProps = builder.functionCall(mergeVar, [ inputProps, // Input props from the attributes take precedence argument @@ -320,8 +320,6 @@ class CustomTag extends HtmlElement { let renderFunctionCall = builder.functionCall(renderMethod, renderArgs); finalNode = renderFunctionCall; } else { - var loadTagVar = codegen.addStaticVar('__loadTag', '__helpers.t'); - var loadTagArgs = [ requireRendererFunctionCall // The first param is the renderer ]; @@ -340,7 +338,7 @@ class CustomTag extends HtmlElement { } } - var loadTag = builder.functionCall(loadTagVar, loadTagArgs); + var loadTag = builder.functionCall(context.helper('loadTag'), loadTagArgs); var tagVar = tagDef.name; if (context.util.isJavaScriptReservedWord(tagVar)) { diff --git a/compiler/ast/Declaration.js b/compiler/ast/Declaration.js index 9eea890630..ff2cf6da13 100644 --- a/compiler/ast/Declaration.js +++ b/compiler/ast/Declaration.js @@ -8,12 +8,13 @@ class Declaration extends Node { } generateHtmlCode(codegen) { - var builder = codegen.builder; - codegen.addWrite(builder.literal('')); + return [ + builder.htmlLiteral('') + ]; } toJSON() { diff --git a/compiler/ast/DocumentType.js b/compiler/ast/DocumentType.js index 4401327649..9e4a34a465 100644 --- a/compiler/ast/DocumentType.js +++ b/compiler/ast/DocumentType.js @@ -8,12 +8,13 @@ class DocumentType extends Node { } generateHtmlCode(codegen) { - var builder = codegen.builder; - codegen.addWrite(builder.literal('')); + return [ + builder.htmlLiteral('') + ]; } toJSON() { diff --git a/compiler/ast/Else.js b/compiler/ast/Else.js index 5a19f93f1c..d1bed7e9b3 100644 --- a/compiler/ast/Else.js +++ b/compiler/ast/Else.js @@ -14,11 +14,15 @@ class Else extends Node { codegen.addError('Unmatched else statement'); return; } - var body = this.body; - codegen.write('else '); - codegen.generateBlock(body); - codegen.write('\n'); + this.body = codegen.generateCode(this.body); + return this; + } + + writeCode(writer) { + var body = this.body; + writer.writeBlock(body); + writer.write('\n'); } walk(walker) { diff --git a/compiler/ast/ElseIf.js b/compiler/ast/ElseIf.js index 0f99aa018d..cb103757eb 100644 --- a/compiler/ast/ElseIf.js +++ b/compiler/ast/ElseIf.js @@ -17,9 +17,7 @@ class ElseIf extends Node { return; } - var ifStatement = codegen.builder.ifStatement(this.test, this.body, this.else); - codegen.write('else '); - codegen.generateCode(ifStatement); + return codegen.builder.ifStatement(this.test, this.body, this.else); } walk(walker) { diff --git a/compiler/ast/Expression.js b/compiler/ast/Expression.js index ccf6f91444..01803a7d97 100644 --- a/compiler/ast/Expression.js +++ b/compiler/ast/Expression.js @@ -11,7 +11,11 @@ class Expression extends Node { } generateCode(codegen) { - codegen.generateCode(this.value); + return this; + } + + writeCode(writer) { + writer.write(this.value); } isCompoundExpression() { diff --git a/compiler/ast/ForEach.js b/compiler/ast/ForEach.js index c1686864af..ff7491ff6b 100644 --- a/compiler/ast/ForEach.js +++ b/compiler/ast/ForEach.js @@ -22,7 +22,7 @@ class ForEach extends Node { var separator = this.separator; var statusVarName = this.statusVarName; var iterator = this.iterator; - + var context = codegen.context; var builder = codegen.builder; if (separator && !statusVarName) { @@ -41,7 +41,7 @@ class ForEach extends Node { builder.functionDeclaration(null, params, this.body) ]); } else if (statusVarName) { - let forEachVarName = codegen.addStaticVar('forEachWithStatusVar', '__helpers.fv'); + let body = this.body; if (separator) { @@ -58,14 +58,12 @@ class ForEach extends Node { ]); } - return builder.functionCall(forEachVarName, [ + return builder.functionCall(context.helper('forEachWithStatusVar'), [ inExpression, builder.functionDeclaration(null, [varName, statusVarName], body) ]); } else { - let forEachVarName = codegen.addStaticVar('forEach', '__helpers.f'); - - return builder.functionCall(forEachVarName, [ + return builder.functionCall(context.helper('forEach'), [ inExpression, builder.functionDeclaration(null, [varName], this.body) ]); diff --git a/compiler/ast/ForEachProp.js b/compiler/ast/ForEachProp.js index b380875e2d..a51d37797d 100644 --- a/compiler/ast/ForEachProp.js +++ b/compiler/ast/ForEachProp.js @@ -18,6 +18,7 @@ class ForEachProp extends Node { } generateCode(codegen) { + var context = codegen.context; var nameVarName = this.nameVarName; var valueVarName = this.valueVarName; var inExpression = this.in; @@ -55,11 +56,12 @@ class ForEachProp extends Node { builder.functionDeclaration(null, [nameVarName, valueVarName, statusVarName], body) ]); } else { - let forEachVarName = codegen.addStaticVar('forEachProp', '__helpers.fp'); - return builder.functionCall(forEachVarName, [ - inExpression, - builder.functionDeclaration(null, [nameVarName, valueVarName], body) - ]); + return builder.functionCall( + context.helper('forEachProp'), + [ + inExpression, + builder.functionDeclaration(null, [nameVarName, valueVarName], body) + ]); } } diff --git a/compiler/ast/ForStatement.js b/compiler/ast/ForStatement.js index fa4738acc7..4e86d13198 100644 --- a/compiler/ast/ForStatement.js +++ b/compiler/ast/ForStatement.js @@ -12,34 +12,42 @@ class ForStatement extends Node { } generateCode(codegen) { + this.init = codegen.generateCode(this.init); + this.test = codegen.generateCode(this.test); + this.update = codegen.generateCode(this.update); + this.body = codegen.generateCode(this.body); + return this; + } + + writeCode(writer) { var init = this.init; var test = this.test; var update = this.update; var body = this.body; - codegen.write('for ('); + writer.write('for ('); if (init) { - codegen.generateCode(init); + writer.write(init); } - codegen.write('; '); + writer.write('; '); if (test) { - codegen.generateCode(test); + writer.write(test); } - codegen.write('; '); + writer.write('; '); if (update) { - codegen.generateCode(update); + writer.write(update); } - codegen.write(') '); + writer.write(') '); - codegen.generateBlock(body); + writer.writeBlock(body); - codegen.write('\n'); + writer.write('\n'); } walk(walker) { diff --git a/compiler/ast/FunctionCall.js b/compiler/ast/FunctionCall.js index a13abf0224..78f3127c98 100644 --- a/compiler/ast/FunctionCall.js +++ b/compiler/ast/FunctionCall.js @@ -2,6 +2,7 @@ var ok = require('assert').ok; var Node = require('./Node'); +var isCompoundExpression = require('../util/isCompoundExpression'); class FunctionCall extends Node { constructor(def) { @@ -27,28 +28,47 @@ class FunctionCall extends Node { } generateCode(codegen) { + this.callee = codegen.generateCode(this.callee); + this.args = codegen.generateCode(this.args); + + return this; + } + + writeCode(writer) { var callee = this.callee; var args = this.args; - codegen.generateCode(callee); + var wrapWithParens = isCompoundExpression(callee); + + if (wrapWithParens) { + writer.write('('); + } + + writer.write(callee); + + if (wrapWithParens) { + writer.write(')'); + } - codegen.write('('); + writer.write('('); if (args && args.length) { for (let i=0, argsLen = args.length; i')); + return [ + builder.htmlLiteral('') + ]; } walk(walker) { diff --git a/compiler/ast/HtmlElement.js b/compiler/ast/HtmlElement.js index 1977a849e1..1c8a5b6816 100644 --- a/compiler/ast/HtmlElement.js +++ b/compiler/ast/HtmlElement.js @@ -21,34 +21,36 @@ class StartTag extends Node { var tagName = this.tagName; var selfClosed = this.selfClosed; var dynamicAttributes = this.dynamicAttributes; + var context = codegen.context; - // Starting tag - codegen.addWriteLiteral('<'); - - codegen.addWrite(tagName); + var nodes = [ + builder.htmlLiteral('<'), + builder.html(tagName), + ]; var attributes = this.attributes; if (attributes) { for (let i=0; i'); + nodes.push(builder.htmlLiteral('/>')); } else { - codegen.addWriteLiteral('>'); + nodes.push(builder.htmlLiteral('>')); } + + return nodes; } } @@ -60,9 +62,13 @@ class EndTag extends Node { generateCode(codegen) { var tagName = this.tagName; - codegen.addWriteLiteral(''); + var builder = codegen.builder; + + return [ + builder.htmlLiteral('') + ]; } } @@ -131,6 +137,10 @@ class HtmlElement extends Node { var builder = codegen.builder; + if (hasBody) { + body = codegen.generateCode(body); + } + if (hasBody || bodyOnlyIf) { openTagOnly = false; selfClosed = false; @@ -170,7 +180,7 @@ class HtmlElement extends Node { ]; } else { if (openTagOnly) { - codegen.generateCode(startTag); + return codegen.generateCode(startTag); } else { return [ startTag, diff --git a/compiler/ast/Identifier.js b/compiler/ast/Identifier.js index c03dca7853..c79acdbd04 100644 --- a/compiler/ast/Identifier.js +++ b/compiler/ast/Identifier.js @@ -9,8 +9,12 @@ class Identifier extends Node { } generateCode(codegen) { + return this; + } + + writeCode(writer) { var name = this.name; - codegen.write(name); + writer.write(name); } toString() { diff --git a/compiler/ast/If.js b/compiler/ast/If.js index 5b2a212eec..b210814072 100644 --- a/compiler/ast/If.js +++ b/compiler/ast/If.js @@ -18,7 +18,6 @@ class If extends Node { } generateCode(codegen) { - if (this.else) { this.else.matched = true; } else { @@ -59,18 +58,26 @@ class If extends Node { }); } + this.test = codegen.generateCode(this.test); + this.body = codegen.generateCode(this.body); + this.else = codegen.generateCode(this.else); + + return this; + } + + writeCode(writer) { var test = this.test; var body = this.body; - codegen.write('if ('); - codegen.generateCode(test); - codegen.write(') '); - codegen.generateBlock(body); + writer.write('if ('); + writer.write(test); + writer.write(') '); + writer.writeBlock(body); if (this.else) { - codegen.write(' '); - codegen.generateCode(this.else); + writer.write(' else '); + writer.write(this.else); } else { - codegen.write('\n'); + writer.write('\n'); } } diff --git a/compiler/ast/Literal.js b/compiler/ast/Literal.js index 4c5b1ccd4d..048aeeed18 100644 --- a/compiler/ast/Literal.js +++ b/compiler/ast/Literal.js @@ -11,8 +11,26 @@ class Literal extends Node { } generateCode(codegen) { + + if (this.value != null) { + if (isArray(this.value)) { + this.value = codegen.generateCode(this.value); + } else if (typeof this.value === 'object') { + var newObject = {}; + for (var k in this.value) { + if (this.value.hasOwnProperty(k)) { + newObject[k] = codegen.generateCode(this.value[k]); + } + } + this.value = newObject; + } + } + return this; + } + + writeCode(writer) { var value = this.value; - codegen.writeLiteral(value); + writer.writeLiteral(value); } toString() { diff --git a/compiler/ast/LogicalExpression.js b/compiler/ast/LogicalExpression.js index b0e106415d..b0531cf31f 100644 --- a/compiler/ast/LogicalExpression.js +++ b/compiler/ast/LogicalExpression.js @@ -3,21 +3,21 @@ var Node = require('./Node'); var isCompoundExpression = require('../util/isCompoundExpression'); -function generateCodeForOperand(node, codegen) { +function generateCodeForOperand(node, writer) { var wrap = isCompoundExpression(node); if (wrap) { - codegen.write('('); + writer.write('('); } - codegen.generateCode(node); + writer.write(node); if (wrap) { - codegen.write(')'); + writer.write(')'); } } -function operandToString(node, codegen) { +function operandToString(node) { var wrap = isCompoundExpression(node); var result = ''; @@ -44,6 +44,12 @@ class LogicalExpression extends Node { } generateCode(codegen) { + this.left = codegen.generateCode(this.left); + this.right = codegen.generateCode(this.right); + return this; + } + + writeCode(writer) { var left = this.left; var operator = this.operator; var right = this.right; @@ -52,11 +58,11 @@ class LogicalExpression extends Node { throw new Error('Invalid LogicalExpression: ' + this); } - generateCodeForOperand(left, codegen); - codegen.write(' '); - codegen.generateCode(operator); - codegen.write(' '); - generateCodeForOperand(right, codegen); + generateCodeForOperand(left, writer); + writer.write(' '); + writer.write(operator); + writer.write(' '); + generateCodeForOperand(right, writer); } isCompoundExpression() { diff --git a/compiler/ast/Macro.js b/compiler/ast/Macro.js index fb7160118f..9ba2082420 100644 --- a/compiler/ast/Macro.js +++ b/compiler/ast/Macro.js @@ -20,13 +20,13 @@ class Macro extends Node { generateCode(codegen) { var name = this.name; var params = this.params || []; - - var body = this.body; - var builder = codegen.builder; - var macroDef = codegen.context.registerMacro(name, params); var functionName = macroDef.functionName; + + // Walk the body after registering the macro + var body = codegen.generateCode(this.body); + return builder.functionDeclaration(functionName, macroDef.params, body); } diff --git a/compiler/ast/MemberExpression.js b/compiler/ast/MemberExpression.js index 756b7a3856..4a42e010a3 100644 --- a/compiler/ast/MemberExpression.js +++ b/compiler/ast/MemberExpression.js @@ -1,6 +1,8 @@ 'use strict'; var Node = require('./Node'); +var isCompoundExpression = require('../util/isCompoundExpression'); +var ok = require('assert').ok; class MemberExpression extends Node { constructor(def) { @@ -8,22 +10,41 @@ class MemberExpression extends Node { this.object = def.object; this.property = def.property; this.computed = def.computed; + + ok(this.object, '"object" is required'); + ok(this.property, '"property" is required'); } generateCode(codegen) { + this.object = codegen.generateCode(this.object); + this.property = codegen.generateCode(this.property); + return this; + } + + writeCode(writer) { var object = this.object; var property = this.property; var computed = this.computed; - codegen.generateCode(object); + var wrapWithParens = isCompoundExpression(object); + + if (wrapWithParens) { + writer.write('('); + } + + writer.write(object); + + if (wrapWithParens) { + writer.write(')'); + } if (computed) { - codegen.write('['); - codegen.generateCode(property); - codegen.write(']'); + writer.write('['); + writer.write(property); + writer.write(']'); } else { - codegen.write('.'); - codegen.generateCode(property); + writer.write('.'); + writer.write(property); } } diff --git a/compiler/ast/NewExpression.js b/compiler/ast/NewExpression.js index d84c0dfcb5..41442ebf43 100644 --- a/compiler/ast/NewExpression.js +++ b/compiler/ast/NewExpression.js @@ -11,40 +11,46 @@ class NewExpression extends Node { } generateCode(codegen) { + this.callee = codegen.generateCode(this.callee); + this.args = codegen.generateCode(this.args); + return this; + } + + writeCode(writer) { var callee = this.callee; var args = this.args; - codegen.write('new '); + writer.write('new '); var wrap = isCompoundExpression(callee); if (wrap) { - codegen.write('('); + writer.write('('); } - codegen.generateCode(callee); + writer.write(callee); if (wrap) { - codegen.write(')'); + writer.write(')'); } - codegen.write('('); + writer.write('('); if (args && args.length) { for (let i=0, argsLen = args.length; i { - codegen.writeLineIndent(); - codegen.generateCode(prop); + writer.writeLineIndent(); + writer.write(prop); if (i < properties.length - 1) { - codegen.write(',\n'); + writer.write(',\n'); } else { - codegen.write('\n'); + writer.write('\n'); } }); - codegen.decIndent(); - codegen.writeLineIndent(); - codegen.write('}'); - codegen.decIndent(); + writer.decIndent(); + writer.writeLineIndent(); + writer.write('}'); + writer.decIndent(); } toJSON() { diff --git a/compiler/ast/Program.js b/compiler/ast/Program.js index 7198ad8faa..d034c56741 100644 --- a/compiler/ast/Program.js +++ b/compiler/ast/Program.js @@ -8,12 +8,12 @@ class Program extends Node { } generateCode(codegen) { - var body = this.body; - codegen.generateStatements(body); - if (codegen._bufferedWrites) { - codegen._write('\n'); - codegen._flushBufferedWrites(); - } + this.body = codegen.generateCode(this.body); + return this; + } + + writeCode(writer) { + writer.writeStatements(this.body); } walk(walker) { diff --git a/compiler/ast/Property.js b/compiler/ast/Property.js index 632e0b3de0..0f015a6489 100644 --- a/compiler/ast/Property.js +++ b/compiler/ast/Property.js @@ -20,9 +20,18 @@ class Property extends Node { } } - codegen.generateCode(key); - codegen.write(': '); - codegen.generateCode(value); + this.key = codegen.generateCode(key); + this.value = codegen.generateCode(value); + + return this; + } + + writeCode(writer) { + var key = this.key; + var value = this.value; + writer.write(key); + writer.write(': '); + writer.write(value); } toJSON() { diff --git a/compiler/ast/Return.js b/compiler/ast/Return.js index 6d6f5eaa60..f0652b0965 100644 --- a/compiler/ast/Return.js +++ b/compiler/ast/Return.js @@ -13,13 +13,18 @@ class Return extends Node { throw new Error('"return" not allowed outside a function body'); } + this.argument = codegen.generateCode(this.argument); + return this; + } + + writeCode(writer) { var argument = this.argument; if (argument) { - codegen.write('return '); - codegen.generateCode(argument); + writer.write('return '); + writer.write(argument); } else { - codegen.write('return'); + writer.write('return'); } } diff --git a/compiler/ast/Scriptlet.js b/compiler/ast/Scriptlet.js index d190f271f5..a47d8280a7 100644 --- a/compiler/ast/Scriptlet.js +++ b/compiler/ast/Scriptlet.js @@ -10,16 +10,20 @@ class Scriptlet extends Node { } generateCode(codegen) { + return this; + } + + writeCode(writer) { var code = this.code; if (!code) { return; } - code = adjustIndent(code, codegen.currentIndent); + code = adjustIndent(code, writer.currentIndent); - codegen.write(code); - codegen.write('\n'); + writer.write(code); + writer.write('\n'); } } diff --git a/compiler/ast/SelfInvokingFunction.js b/compiler/ast/SelfInvokingFunction.js index 0f2b995eb8..4efddb4899 100644 --- a/compiler/ast/SelfInvokingFunction.js +++ b/compiler/ast/SelfInvokingFunction.js @@ -13,14 +13,12 @@ class SelfInvokingFunction extends Node { generateCode(codegen) { var params = this.params || []; var args = this.args || []; - var body = this.body; + var body = codegen.generateCode(this.body); - codegen.write('('); var functionDeclaration = codegen.builder.functionDeclaration(null, params, body); var functionCall = codegen.builder.functionCall(functionDeclaration, args); - codegen.generateCode(functionCall); - codegen.write(')'); + return functionCall; } walk(walker) { diff --git a/compiler/ast/Slot.js b/compiler/ast/Slot.js deleted file mode 100644 index 8e9de778dc..0000000000 --- a/compiler/ast/Slot.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict'; - -var Node = require('./Node'); - -class Slot extends Node { - constructor(def) { - super('Slot'); - this.onDone = def.onDone; - this.codegenSlot = null; - } - - generateCode(codegen) { - if (this.onDone) { - codegen.onDone((codegen) => { - this.onDone(this, codegen); - }); - } - // At the time the code for this node is to be generated we instead - // create a slot. A slot is just a marker in the output code stream - // that we can later inject code into. The injection happens after - // the entire tree has been walked. - this.codegenSlot = codegen.beginSlot(this); - } - - setContent(content) { - this.codegenSlot.setContent(content); - } - - toJSON() { - return { - type: this.type - }; - } -} - -module.exports = Slot; \ No newline at end of file diff --git a/compiler/ast/TemplateRoot.js b/compiler/ast/TemplateRoot.js index 10d3a88d89..3b9b7bd110 100644 --- a/compiler/ast/TemplateRoot.js +++ b/compiler/ast/TemplateRoot.js @@ -11,6 +11,8 @@ function createVarsArray(vars) { }); } +var templateExports = null; + class TemplateRoot extends Node { constructor(def) { super('TemplateRoot'); @@ -20,51 +22,63 @@ class TemplateRoot extends Node { generateCode(codegen) { var context = codegen.context; - var body = this.body; - codegen.addStaticVar('str', '__helpers.s'); - codegen.addStaticVar('empty', '__helpers.e'); - codegen.addStaticVar('notEmpty', '__helpers.ne'); - codegen.addStaticVar('escapeXml', '__helpers.x'); + var body = codegen.generateCode(this.body); var builder = codegen.builder; - var program = builder.program; - var functionDeclaration = builder.functionDeclaration; - - var returnStatement = builder.returnStatement; - var slot = builder.slot; - - var staticsSlot = slot(); - var varsSlot = slot(); - varsSlot.noOutput = true; - - body = [ varsSlot ].concat(body.items); - - var outputNode = program([ - functionDeclaration('create', ['__helpers'], [ - staticsSlot, - returnStatement( - functionDeclaration('render', ['data', 'out'], body)) - ]), - '(module.exports = require("marko").c(__filename)).c(create)' - ]); - - codegen.generateCode(outputNode); - - var staticVars = context.getStaticVars(); - var staticCodeArray = context.getStaticCode(); - - var staticContent = [builder.vars(createVarsArray(staticVars))]; - if (staticCodeArray) { - staticCodeArray.forEach((code) => { - staticContent.push(code); - }); + let renderStatements = []; + var vars = createVarsArray(context.getVars()); + if (vars.length) { + renderStatements.push(builder.vars(vars)); } - staticsSlot.setContent(staticContent); - - var vars = context.getVars(); - varsSlot.setContent(builder.vars(createVarsArray(vars))); + renderStatements = renderStatements.concat(body); + + if (context.inline) { + var createInlineMarkoTemplateVar = context.importModule('marko_createInlineTemplate', 'marko/runtime/inline'); + + return builder.functionCall( + createInlineMarkoTemplateVar, + [ + builder.identifier('__filename'), + builder.functionDeclaration( + null, + [ + builder.identifier('data'), + builder.identifierOut() + ], + renderStatements) + + ]); + + } else { + let createStatements = []; + let staticNodes = context.getStaticNodes(); + if (staticNodes.length) { + createStatements = createStatements.concat(staticNodes); + } + + let renderFunction = builder.functionDeclaration( + 'render', + ['data', builder.identifierOut()], + renderStatements); + + createStatements.push(builder.returnStatement(renderFunction)); + + if (!templateExports) { + templateExports = builder.parseStatement('(module.exports = require("marko").c(__filename)).c(create)'); + } + + return builder.program([ + builder.functionDeclaration( + 'create', + [ + context.helpersIdentifier + ], + createStatements), + templateExports + ]); + } } toJSON(prettyPrinter) { diff --git a/compiler/ast/Text.js b/compiler/ast/Text.js index aae8d7db0f..58077f02ea 100644 --- a/compiler/ast/Text.js +++ b/compiler/ast/Text.js @@ -23,20 +23,16 @@ class Text extends Node { } generateHtmlCode(codegen) { - var parentNode = this.parentNode; - if (parentNode) { - parentNode._normalizeChildTextNodes(codegen); - } - + var context = codegen.context; var argument = this.argument; var escape = this.escape !== false; if (argument instanceof Literal) { if (!argument.value) { - return; + return null; } - if (codegen.context.isFlagSet('SCRIPT_BODY')) { + if (context.isFlagSet('SCRIPT_BODY')) { escape = false; } @@ -47,23 +43,23 @@ class Text extends Node { let builder = codegen.builder; if (escape) { - let escapeFuncVar = 'escapeXml'; + let escapeIdentifier = context.helper('escapeXml'); - if (codegen.context.isFlagSet('SCRIPT_BODY')) { - escapeFuncVar = codegen.addStaticVar('escapeScript', '__helpers.xs'); + if (context.isFlagSet('SCRIPT_BODY')) { + escapeIdentifier = context.helper('escapeScript'); } // TODO Only escape the parts that need to be escaped if it is a compound expression with static // text parts argument = builder.functionCall( - escapeFuncVar, + escapeIdentifier, [argument]); } else { - argument = builder.functionCall(builder.identifier('str'), [ argument ]); + argument = builder.functionCall(context.helper('str'), [ argument ]); } } - codegen.addWrite(argument); + return codegen.builder.html(argument); } isWhitespace() { diff --git a/compiler/ast/ThisExpression.js b/compiler/ast/ThisExpression.js index 93b78fa6d7..590a510548 100644 --- a/compiler/ast/ThisExpression.js +++ b/compiler/ast/ThisExpression.js @@ -8,7 +8,11 @@ class ThisExpression extends Node { } generateCode(codegen) { - codegen.write('this'); + return this; + } + + writeCode(writer) { + writer.write('this'); } toString() { diff --git a/compiler/ast/UnaryExpression.js b/compiler/ast/UnaryExpression.js index ca83a0a565..2d99e85d48 100644 --- a/compiler/ast/UnaryExpression.js +++ b/compiler/ast/UnaryExpression.js @@ -12,32 +12,37 @@ class UnaryExpression extends Node { } generateCode(codegen) { + this.argument = codegen.generateCode(this.argument); + return this; + } + + writeCode(writer) { var argument = this.argument; var operator = this.operator; var prefix = this.prefix; if (prefix) { - codegen.write(operator); + writer.write(operator); if (operator === 'typeof' || operator === 'delete') { - codegen.write(' '); + writer.write(' '); } } var wrap = isCompoundExpression(argument); if (wrap) { - codegen.write('('); + writer.write('('); } - codegen.generateCode(argument); + writer.write(argument); if (wrap) { - codegen.write(')'); + writer.write(')'); } if (!prefix) { - codegen.write(operator); + writer.write(operator); } } diff --git a/compiler/ast/UpdateExpression.js b/compiler/ast/UpdateExpression.js index 497242d563..b661fde7fb 100644 --- a/compiler/ast/UpdateExpression.js +++ b/compiler/ast/UpdateExpression.js @@ -12,28 +12,33 @@ class UpdateExpression extends Node { } generateCode(codegen) { + this.argument = codegen.generateCode(this.argument); + return this; + } + + writeCode(writer) { var argument = this.argument; var operator = this.operator; var prefix = this.prefix; if (prefix) { - codegen.generateCode(operator); + writer.write(operator); } var wrap = isCompoundExpression(argument); if (wrap) { - codegen.write('('); + writer.write('('); } - codegen.generateCode(argument); + writer.write(argument); if (wrap) { - codegen.write(')'); + writer.write(')'); } if (!prefix) { - codegen.generateCode(operator); + writer.write(operator); } } diff --git a/compiler/ast/VariableDeclarator.js b/compiler/ast/VariableDeclarator.js index e395b3a6ba..5dd33b0c1d 100644 --- a/compiler/ast/VariableDeclarator.js +++ b/compiler/ast/VariableDeclarator.js @@ -23,6 +23,12 @@ class VariableDeclarator extends Node { } generateCode(codegen) { + this.id = codegen.generateCode(this.id); + this.init = codegen.generateCode(this.init); + return this; + } + + writeCode(writer) { var id = this.id; var init = this.init; @@ -30,11 +36,11 @@ class VariableDeclarator extends Node { throw new Error('Invalid variable name: ' + id); } - codegen.generateCode(id); + writer.write(id); if (init != null) { - codegen.write(' = '); - codegen.generateCode(init); + writer.write(' = '); + writer.write(init); } } diff --git a/compiler/ast/Vars.js b/compiler/ast/Vars.js index 2c9b8245fe..59257aa87b 100644 --- a/compiler/ast/Vars.js +++ b/compiler/ast/Vars.js @@ -12,51 +12,53 @@ class Vars extends Node { generateCode(codegen) { var declarations = this.declarations; - var kind = this.kind; - var isStatement = this.statement; - var body = this.body; - var hasBody = this.body && this.body.length; - - if(hasBody) { + if (!declarations || !declarations.length) { + return null; + } - var scopedBody = [this].concat(this.body.items); + if (this.body && this.body.length) { + var scopedBody = [this].concat(this.body); this.body = null; - return codegen.builder.selfInvokingFunction(scopedBody); } + return this; + } + + writeCode(writer) { + var declarations = this.declarations; + var kind = this.kind; + var isStatement = this.statement; + + if (!declarations || !declarations.length) { return; } - codegen.incIndent(4); + writer.incIndent(4); for (let i=0; i` tag was wrapped with a new `If` node. After the AST has been transformed it is now time to generate the compiled JavaScript code. +You'll notice in the transformed AST that the `HtmlElement` associated with the `
` tag was wrapped with a new `If` node. During the transform stage, the entire AST might be walked multiple times. Not until there are no more nodes transformed does the transform stage complete. +After the AST has been transformed it is now time to generate the final AST as part of the _generate_ stage. + ## Generate stage -The generate stage is the final stage of the Marko compiler. During the generate stage the Marko compiler will walk the tree to produce the final JavaScript code. Each node in the tree will have an opportunity to generate JavaScript code. The Marko compiler provides a [`CodeGenerator`](../compiler/CodeGenerator.js) class and an API for generating fragments of JavaScript code that makes it easy to produce well-formed and readable JavaScript code as output. +After the AST has been transformed, the final AST consisting of only "final" AST nodes that are capable of writing out JavaScript code must be generated. A final AST node is a node that is capable of writing out JavaScript code and it must have a `writeCode(writer)` method. During this stage, `generateCode` is called on the root node and each node is responsible for recursively calling `generateCode` on children AST nodes to produce the final AST nodes. Every node in the tree must implement one of the following methods: -- `generateCode(generator)` -- `generateCode(generator)` (e.g. `generateHtmlCode(generator)`) +- `generateCode(codegen) : Node` +- `generateCode(codegen) : Node` (e.g. `generateHtmlCode(codegen)`) -The `generator` argument will be an instance of [`CodeGenerator`](../compiler/CodeGenerator.js). +The `codegen` argument will be an instance of [`CodeGenerator`](../compiler/CodeGenerator.js). The Marko compiler supports compiling templates differently based on an "output type". Currently, the only supported output type is "Html". With the "Html" output type, the compiled template will be a program that, when executed, will produce an HTML string as output. In the future we may support other output types such as DOM, Virtual DOM, incremental DOM, etc. For example, with the "DOM" output type, the compiled program could use the web browser's DOM API to produce a DOM tree as output (instead of an HTML string). +Below is the fragment of code used by the `ForStatement` node to generate the final AST node: + +```javascript +generateCode(codegen) { + this.init = codegen.generateCode(this.init); + this.test = codegen.generateCode(this.test); + this.update = codegen.generateCode(this.update); + this.body = codegen.generateCode(this.body); + return this; +} +``` + +In the above example code, the node is returning itself as the final code. Alternatively, a node could return a completely different node that will automatically be made final: + +```javascript +generateCode(codegen) { + let builder = codegen.builder; + + return builder.functionCall( + builder.identifier('console'), + [ + builder.literal('Hello World!') + ]); +} +``` + +## Write stage + +The write stage is the final stage of the Marko compiler. During the write state, each node will have an opportunity to write out JavaScript code to the final output buffer for the compiled template. The Marko compiler provides a [`CodeWriter`](../compiler/CodeWriter.js) class for writing out JavaScript primitives such as blocks and statements and it also provides support controlling indentation. + +Every node in the tree must implement one of the following methods: + +- `writeCode(writer)` +- `writeCode(writer)` (e.g. `writerHtmlCode(writer)`) + +The `writer` argument will be an instance of [`CodeWriter`](../compiler/CodeWriter.js). + Below is the fragment of code used by the `If` node to generate the output JavaScript code: ```javascript -generator.write('if ('); -generator.generateCode(test); -generator.write(') '); -generator.generateBlock(body); -if (elseStatement) { - generator.write(' '); - generator.generateCode(elseStatement); -} else { - generator.write('\n'); +writeCode(writer) { + var test = this.test; + var body = this.body; + + writer.write('if ('); + writer.write(test); + writer.write(') '); + writer.writeBlock(body); + if (this.else) { + writer.write(' else '); + writer.write(this.else); + } else { + writer.write('\n'); + } } ``` diff --git a/runtime/inline.js b/runtime/inline.js new file mode 100644 index 0000000000..656e032f6c --- /dev/null +++ b/runtime/inline.js @@ -0,0 +1 @@ +module.exports = require('./')._inline; \ No newline at end of file diff --git a/runtime/marko-runtime.js b/runtime/marko-runtime.js index 76fe606573..6d6408a090 100644 --- a/runtime/marko-runtime.js +++ b/runtime/marko-runtime.js @@ -310,6 +310,10 @@ function load(templatePath, templateSrc, options) { return template; } +function createInlineMarkoTemplate(filename, renderFunc) { + return new Template(filename, renderFunc); +} + exports.load = load; exports.createWriter = function(writer) { @@ -320,6 +324,8 @@ exports.helpers = helpers; exports.Template = Template; +exports._inline = createInlineMarkoTemplate; + // The loader is used to load templates that have not already been // loaded and cached. On the server, the loader will use // the compiler to compile the template and then load the generated diff --git a/taglibs/async/await-tag-transformer.js b/taglibs/async/await-tag-transformer.js index cba1b7a847..a8551125d6 100644 --- a/taglibs/async/await-tag-transformer.js +++ b/taglibs/async/await-tag-transformer.js @@ -52,7 +52,7 @@ module.exports = function transform(el, context) { if (isObjectEmpty(arg)) { arg = el.getAttributeValue('arg'); } else { - let mergeVar = context.addStaticVar('__merge', '__helpers.m'); + let mergeVar = context.helper('merge'); arg = builder.functionCall(mergeVar, [ builder.literal(arg), // Input props from the attributes take precedence el.getAttributeValue('arg') diff --git a/taglibs/core/include-tag.js b/taglibs/core/include-tag.js index 8551a8dc83..fa9fbbccd7 100644 --- a/taglibs/core/include-tag.js +++ b/taglibs/core/include-tag.js @@ -58,7 +58,7 @@ module.exports = function codeGenerator(el, codegen) { if (Object.keys(templateData).length === 0) { templateData = args[1]; } else { - let mergeVar = codegen.addStaticVar('__merge', '__helpers.m'); + let mergeVar = codegen.context.helper('merge'); templateData = builder.functionCall(mergeVar, [ builder.literal(templateData), // Input props from the attributes take precedence args[1] // The template data object is passed as the second argument: diff --git a/test/.gitignore b/test/.gitignore index 7e309a6817..667a523c3a 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,2 +1,3 @@ /node_modules -/scratch.js \ No newline at end of file +/scratch.js +*.generated.js \ No newline at end of file diff --git a/test/autotests/codegen/attr-no-escape/expected.js b/test/autotests/codegen/attr-no-escape/expected.js index c335fafd9e..b937ded314 100644 --- a/test/autotests/codegen/attr-no-escape/expected.js +++ b/test/autotests/codegen/attr-no-escape/expected.js @@ -1,3 +1,3 @@ out.w("
Hello World
"); + "\">Hello World
") \ No newline at end of file diff --git a/test/autotests/codegen/body-only-if/expected.js b/test/autotests/codegen/body-only-if/expected.js index fa22942109..55768f2711 100644 --- a/test/autotests/codegen/body-only-if/expected.js +++ b/test/autotests/codegen/body-only-if/expected.js @@ -1,7 +1,7 @@ if (true) { if (!(!data.url)) { out.w(""); } diff --git a/test/autotests/codegen/code-before-after-if/expected.js b/test/autotests/codegen/code-before-after-if/expected.js index 9a55d5e543..b480768e11 100644 --- a/test/autotests/codegen/code-before-after-if/expected.js +++ b/test/autotests/codegen/code-before-after-if/expected.js @@ -1,5 +1,6 @@ if (a > b) { before(); + out.w("
Hello World
"); after(); diff --git a/test/autotests/codegen/code-before-after-surrounded/expected.js b/test/autotests/codegen/code-before-after-surrounded/expected.js index c9c00f4cf1..be9c5e996b 100644 --- a/test/autotests/codegen/code-before-after-surrounded/expected.js +++ b/test/autotests/codegen/code-before-after-surrounded/expected.js @@ -2,7 +2,9 @@ if (a > b) { var before; before(); + var foo; + after(); var after; diff --git a/test/autotests/codegen/code-before-after-var/expected.js b/test/autotests/codegen/code-before-after-var/expected.js index 0240fff4a0..2bb84e681e 100644 --- a/test/autotests/codegen/code-before-after-var/expected.js +++ b/test/autotests/codegen/code-before-after-var/expected.js @@ -1,5 +1,7 @@ if (a > b) { before(); + var foo; + after(); } diff --git a/test/autotests/codegen/code-before-after/expected.js b/test/autotests/codegen/code-before-after/expected.js index 270fd7bc94..d797a3ca9d 100644 --- a/test/autotests/codegen/code-before-after/expected.js +++ b/test/autotests/codegen/code-before-after/expected.js @@ -1,4 +1,5 @@ before(); + out.w("
Hello World
"); after(); diff --git a/test/autotests/codegen/code-before-after/index.js b/test/autotests/codegen/code-before-after/index.js index 0f9a001bf1..48d014f25a 100644 --- a/test/autotests/codegen/code-before-after/index.js +++ b/test/autotests/codegen/code-before-after/index.js @@ -21,5 +21,7 @@ module.exports = function(builder) { event.insertCode(builder.functionCall('after', [])); }); - return htmlElement; + return builder.program([ + htmlElement + ]); }; \ No newline at end of file diff --git a/test/autotests/codegen/codegen-addStaticVar/expected.js b/test/autotests/codegen/codegen-addStaticVar/expected.js index 30798c5ff6..d89ea7d326 100644 --- a/test/autotests/codegen/codegen-addStaticVar/expected.js +++ b/test/autotests/codegen/codegen-addStaticVar/expected.js @@ -1,9 +1,5 @@ -function create(__helpers) { - var foo = "Hello World", - str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; +function create(__markoHelpers) { + var foo = "Hello World"; return function render(data, out) { out.w("
"); diff --git a/test/autotests/codegen/codegen-addVar/expected.js b/test/autotests/codegen/codegen-addVar/expected.js index 77a4735e20..15f1380864 100644 --- a/test/autotests/codegen/codegen-addVar/expected.js +++ b/test/autotests/codegen/codegen-addVar/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { var foo = "Hello World"; diff --git a/test/autotests/codegen/combine-writes/expected.js b/test/autotests/codegen/combine-writes/expected.js index 68356d67bf..5431c16fe2 100644 --- a/test/autotests/codegen/combine-writes/expected.js +++ b/test/autotests/codegen/combine-writes/expected.js @@ -1,8 +1,5 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x; return function render(data, out) { out.w("
    "); @@ -11,7 +8,7 @@ function create(__helpers) { foo(); out.w("
  • " + - escapeXml(color) + + marko_escapeXml(color) + "
  • "); bar(); diff --git a/test/autotests/codegen/context-addStaticVar-dedupe/expected.js b/test/autotests/codegen/context-addStaticVar-dedupe/expected.js new file mode 100644 index 0000000000..d89ea7d326 --- /dev/null +++ b/test/autotests/codegen/context-addStaticVar-dedupe/expected.js @@ -0,0 +1,9 @@ +function create(__markoHelpers) { + var foo = "Hello World"; + + return function render(data, out) { + out.w("
    "); + }; +} + +(module.exports = require("marko").c(__filename)).c(create); diff --git a/test/autotests/codegen/context-addStaticVar-dedupe/index.js b/test/autotests/codegen/context-addStaticVar-dedupe/index.js new file mode 100644 index 0000000000..186ef5282d --- /dev/null +++ b/test/autotests/codegen/context-addStaticVar-dedupe/index.js @@ -0,0 +1,15 @@ +'use strict'; + +module.exports = function(builder, codegen) { + + var templateRoot = builder.templateRoot([ + builder.htmlElement( + 'div', + []) + ]); + + codegen.context.addStaticVar('foo', builder.literal('Hello World')); + codegen.context.addStaticVar('foo', builder.literal('Hello World')); + + return templateRoot; +}; \ No newline at end of file diff --git a/test/autotests/codegen/context-addStaticVar/expected.js b/test/autotests/codegen/context-addStaticVar/expected.js index 30798c5ff6..d89ea7d326 100644 --- a/test/autotests/codegen/context-addStaticVar/expected.js +++ b/test/autotests/codegen/context-addStaticVar/expected.js @@ -1,9 +1,5 @@ -function create(__helpers) { - var foo = "Hello World", - str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; +function create(__markoHelpers) { + var foo = "Hello World"; return function render(data, out) { out.w("
    "); diff --git a/test/autotests/codegen/context-addVar-addStaticVar/expected.js b/test/autotests/codegen/context-addVar-addStaticVar/expected.js new file mode 100644 index 0000000000..127b4b2eea --- /dev/null +++ b/test/autotests/codegen/context-addVar-addStaticVar/expected.js @@ -0,0 +1,13 @@ +function create(__markoHelpers) { + var fooStatic = "Hello Foo", + barStatic = "Hello Bar"; + + return function render(data, out) { + var foo = "Hello Foo", + bar = "Hello Bar"; + + out.w("
    "); + }; +} + +(module.exports = require("marko").c(__filename)).c(create); diff --git a/test/autotests/codegen/context-addVar-addStaticVar/index.js b/test/autotests/codegen/context-addVar-addStaticVar/index.js new file mode 100644 index 0000000000..ccdc0cbbca --- /dev/null +++ b/test/autotests/codegen/context-addVar-addStaticVar/index.js @@ -0,0 +1,18 @@ +'use strict'; + +module.exports = function(builder, codegen) { + + var templateRoot = builder.templateRoot([ + builder.htmlElement( + 'div', + []) + ]); + + codegen.context.addVar('foo', builder.literal('Hello Foo')); + codegen.context.addVar('bar', builder.literal('Hello Bar')); + + codegen.context.addStaticVar('fooStatic', builder.literal('Hello Foo')); + codegen.context.addStaticVar('barStatic', builder.literal('Hello Bar')); + + return templateRoot; +}; \ No newline at end of file diff --git a/test/autotests/codegen/context-addVar/expected.js b/test/autotests/codegen/context-addVar/expected.js index 77a4735e20..15f1380864 100644 --- a/test/autotests/codegen/context-addVar/expected.js +++ b/test/autotests/codegen/context-addVar/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { var foo = "Hello World"; diff --git a/test/autotests/codegen/forEach/expected.js b/test/autotests/codegen/forEach/expected.js index 5e355b2341..db8637dfa9 100644 --- a/test/autotests/codegen/forEach/expected.js +++ b/test/autotests/codegen/forEach/expected.js @@ -1,13 +1,10 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - forEach = __helpers.f; +function create(__markoHelpers) { + var marko_forEach = __markoHelpers.f, + marko_escapeXml = __markoHelpers.x; return function render(data, out) { - forEach(data.colors, function(color) { - out.w(escapeXml(color)); + marko_forEach(data.colors, function(color) { + out.w(marko_escapeXml(color)); }); }; } diff --git a/test/autotests/codegen/forEachProps/expected.js b/test/autotests/codegen/forEachProps/expected.js index 8795fe6695..aef6a4153c 100644 --- a/test/autotests/codegen/forEachProps/expected.js +++ b/test/autotests/codegen/forEachProps/expected.js @@ -1,12 +1,8 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - forEachProp = __helpers.fp; +function create(__markoHelpers) { + var marko_forEachProp = __markoHelpers.fp; return function render(data, out) { - forEachProp(myObject, function(k, v) { + marko_forEachProp(myObject, function(k, v) { console.log("k:", k, "v:", v); }); }; diff --git a/test/autotests/codegen/forRange/expected.js b/test/autotests/codegen/forRange/expected.js index 0736273bcc..a7aea1b488 100644 --- a/test/autotests/codegen/forRange/expected.js +++ b/test/autotests/codegen/forRange/expected.js @@ -1,15 +1,10 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { (function() { for (var i = 0; i <= myArray.length; i += 2) { console.log(i); } - }()); + })(); }; } diff --git a/test/autotests/codegen/html/expected.js b/test/autotests/codegen/html/expected.js index 89e171f7c3..978228f999 100644 --- a/test/autotests/codegen/html/expected.js +++ b/test/autotests/codegen/html/expected.js @@ -1 +1 @@ -out.w("
    Hello World
    "); +out.w("
    Hello World
    ") \ No newline at end of file diff --git a/test/autotests/codegen/htmlComment/expected.js b/test/autotests/codegen/htmlComment/expected.js index a335a35d46..f8b192dd4f 100644 --- a/test/autotests/codegen/htmlComment/expected.js +++ b/test/autotests/codegen/htmlComment/expected.js @@ -1 +1 @@ -out.w(""); +out.w("") \ No newline at end of file diff --git a/test/autotests/codegen/htmlElement-addAttribute/expected.js b/test/autotests/codegen/htmlElement-addAttribute/expected.js index c335fafd9e..b937ded314 100644 --- a/test/autotests/codegen/htmlElement-addAttribute/expected.js +++ b/test/autotests/codegen/htmlElement-addAttribute/expected.js @@ -1,3 +1,3 @@ out.w("
    Hello World
    "); + "\">Hello World") \ No newline at end of file diff --git a/test/autotests/codegen/htmlElement-attr-escape/expected.js b/test/autotests/codegen/htmlElement-attr-escape/expected.js index 43458424da..f057e4d607 100644 --- a/test/autotests/codegen/htmlElement-attr-escape/expected.js +++ b/test/autotests/codegen/htmlElement-attr-escape/expected.js @@ -1,3 +1,3 @@ out.w("
    Hello World
    "); + marko_attr("foo", bar) + + ">Hello World") \ No newline at end of file diff --git a/test/autotests/codegen/htmlElement-dynamic/expected.js b/test/autotests/codegen/htmlElement-dynamic/expected.js index eec5571e39..4b94dc8a35 100644 --- a/test/autotests/codegen/htmlElement-dynamic/expected.js +++ b/test/autotests/codegen/htmlElement-dynamic/expected.js @@ -2,4 +2,4 @@ out.w("<" + data.tagName + " class=\"greeting\">Hello World"); + ">") \ No newline at end of file diff --git a/test/autotests/codegen/htmlElement/expected.js b/test/autotests/codegen/htmlElement/expected.js index 155a4a9dd4..3156b74869 100644 --- a/test/autotests/codegen/htmlElement/expected.js +++ b/test/autotests/codegen/htmlElement/expected.js @@ -1 +1 @@ -out.w("
    Hello World
    "); +out.w("
    Hello World
    ") \ No newline at end of file diff --git a/test/autotests/codegen/if-write-if/expected.js b/test/autotests/codegen/if-write-if/expected.js index 165785b098..f92c6347e9 100644 --- a/test/autotests/codegen/if-write-if/expected.js +++ b/test/autotests/codegen/if-write-if/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { if (true) { out.w("A"); diff --git a/test/autotests/codegen/invokeMacro-body/expected.js b/test/autotests/codegen/invokeMacro-body/expected.js index 0522a1fd0d..495d1fc497 100644 --- a/test/autotests/codegen/invokeMacro-body/expected.js +++ b/test/autotests/codegen/invokeMacro-body/expected.js @@ -1,6 +1,6 @@ function macro_greeting(name, age, out, renderBody) { out.w("Hello " + - escapeXml(name)); + marko_escapeXml(name)); } macro_greeting("Frank", 10, out, function renderBody(out) { diff --git a/test/autotests/codegen/invokeMacro/expected.js b/test/autotests/codegen/invokeMacro/expected.js index 8fec7cea58..20131a2f7d 100644 --- a/test/autotests/codegen/invokeMacro/expected.js +++ b/test/autotests/codegen/invokeMacro/expected.js @@ -1,6 +1,6 @@ function macro_greeting(name, age, out, renderBody) { out.w("Hello " + - escapeXml(name)); + marko_escapeXml(name)); } macro_greeting("Frank", 10, out); diff --git a/test/autotests/codegen/invokeMacroFromEl-body-and-argument/expected.js b/test/autotests/codegen/invokeMacroFromEl-body-and-argument/expected.js index 0522a1fd0d..495d1fc497 100644 --- a/test/autotests/codegen/invokeMacroFromEl-body-and-argument/expected.js +++ b/test/autotests/codegen/invokeMacroFromEl-body-and-argument/expected.js @@ -1,6 +1,6 @@ function macro_greeting(name, age, out, renderBody) { out.w("Hello " + - escapeXml(name)); + marko_escapeXml(name)); } macro_greeting("Frank", 10, out, function renderBody(out) { diff --git a/test/autotests/codegen/invokeMacroFromEl/expected.js b/test/autotests/codegen/invokeMacroFromEl/expected.js index 8fec7cea58..20131a2f7d 100644 --- a/test/autotests/codegen/invokeMacroFromEl/expected.js +++ b/test/autotests/codegen/invokeMacroFromEl/expected.js @@ -1,6 +1,6 @@ function macro_greeting(name, age, out, renderBody) { out.w("Hello " + - escapeXml(name)); + marko_escapeXml(name)); } macro_greeting("Frank", 10, out); diff --git a/test/autotests/codegen/macro/expected.js b/test/autotests/codegen/macro/expected.js index c338e2b9d1..aef047fa48 100644 --- a/test/autotests/codegen/macro/expected.js +++ b/test/autotests/codegen/macro/expected.js @@ -1,4 +1,4 @@ function macro_greeting(name, age, out, renderBody) { out.w("Hello " + - escapeXml(name)); + marko_escapeXml(name)); } \ No newline at end of file diff --git a/test/autotests/codegen/marko-template/expected.js b/test/autotests/codegen/marko-template/expected.js index dcaad29ac9..1a36ed8c3a 100644 --- a/test/autotests/codegen/marko-template/expected.js +++ b/test/autotests/codegen/marko-template/expected.js @@ -1,8 +1,5 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x; return function render(data, out) { out.w("Hello" + @@ -14,7 +11,7 @@ function create(__helpers) { forEach(data.colors, function(color) { out.w("
  • " + - escapeXml(color) + + marko_escapeXml(color) + "
  • "); }); diff --git a/test/autotests/codegen/moveChildrenTo/index.js b/test/autotests/codegen/moveChildrenTo/index.js index bab3844ea4..2b902bde6d 100644 --- a/test/autotests/codegen/moveChildrenTo/index.js +++ b/test/autotests/codegen/moveChildrenTo/index.js @@ -17,8 +17,8 @@ module.exports = function(builder) { div.moveChildrenTo(span); - return [ + return builder.program([ div, span - ]; + ]); }; \ No newline at end of file diff --git a/test/autotests/codegen/node/index.js b/test/autotests/codegen/node/index.js index 7c61024681..80bb86ef33 100644 --- a/test/autotests/codegen/node/index.js +++ b/test/autotests/codegen/node/index.js @@ -1,8 +1,10 @@ 'use strict'; module.exports = function(builder) { - return builder.node(function(node, codegen) { - var builder = codegen.builder; - return builder.text(builder.literal('Hello World!')); - }); + return builder.program([ + builder.node(function(node, codegen) { + var builder = codegen.builder; + return builder.text(builder.literal('Hello World!')); + }) + ]); }; \ No newline at end of file diff --git a/test/autotests/codegen/removeAllAttributes/index.js b/test/autotests/codegen/removeAllAttributes/index.js index b1707932e8..4fa86d6975 100644 --- a/test/autotests/codegen/removeAllAttributes/index.js +++ b/test/autotests/codegen/removeAllAttributes/index.js @@ -12,5 +12,5 @@ module.exports = function(builder) { div.removeAllAttributes(); - return div; + return builder.program([div]); }; \ No newline at end of file diff --git a/test/autotests/codegen/selfInvokingFunction-no-args/expected.js b/test/autotests/codegen/selfInvokingFunction-no-args/expected.js index ac0ae8b2bf..197b43c8a8 100644 --- a/test/autotests/codegen/selfInvokingFunction-no-args/expected.js +++ b/test/autotests/codegen/selfInvokingFunction-no-args/expected.js @@ -2,4 +2,4 @@ var foo; foo = "bar"; -}()) \ No newline at end of file +})() \ No newline at end of file diff --git a/test/autotests/codegen/selfInvokingFunction-null-args/expected.js b/test/autotests/codegen/selfInvokingFunction-null-args/expected.js index ac0ae8b2bf..197b43c8a8 100644 --- a/test/autotests/codegen/selfInvokingFunction-null-args/expected.js +++ b/test/autotests/codegen/selfInvokingFunction-null-args/expected.js @@ -2,4 +2,4 @@ var foo; foo = "bar"; -}()) \ No newline at end of file +})() \ No newline at end of file diff --git a/test/autotests/codegen/selfInvokingFunction/expected.js b/test/autotests/codegen/selfInvokingFunction/expected.js index 776dc927bf..1a52eeb29c 100644 --- a/test/autotests/codegen/selfInvokingFunction/expected.js +++ b/test/autotests/codegen/selfInvokingFunction/expected.js @@ -1,3 +1,3 @@ (function(win) { win.foo = "bar"; -}(window)) \ No newline at end of file +})(window) \ No newline at end of file diff --git a/test/autotests/codegen/slot-with-statements/expected.js b/test/autotests/codegen/slot-with-statements/expected.js deleted file mode 100644 index 6fcc4a7db0..0000000000 --- a/test/autotests/codegen/slot-with-statements/expected.js +++ /dev/null @@ -1,6 +0,0 @@ -a = "abc"; - -var foo = "abc", - bar = 123; - -b = "def"; diff --git a/test/autotests/codegen/slot-with-statements/index.js b/test/autotests/codegen/slot-with-statements/index.js deleted file mode 100644 index eda0335474..0000000000 --- a/test/autotests/codegen/slot-with-statements/index.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -module.exports = function(builder) { - var vars = []; - - return builder.program([ - builder.assignment('a', builder.literal('abc')), - builder.slot((slot, codegen) => { - slot.setContent(codegen.builder.vars(vars)); - }), - builder.node(function(node, codegen) { - vars.push({ - id: 'foo', - init: codegen.builder.literal('abc') - }); - }), - builder.node(function(node, codegen) { - vars.push({ - id: 'bar', - init: codegen.builder.literal(123) - }); - }), - builder.assignment('b', builder.literal('def')) - ]); -}; \ No newline at end of file diff --git a/test/autotests/codegen/slot-with-writes-nested/expected.js b/test/autotests/codegen/slot-with-writes-nested/expected.js deleted file mode 100644 index ba56e0159a..0000000000 --- a/test/autotests/codegen/slot-with-writes-nested/expected.js +++ /dev/null @@ -1,8 +0,0 @@ -if (true) { - out.w("BEFORE - Hello World"); - - var foo = "abc", - bar = 123; - - out.w("AFTER - Hello World"); -} diff --git a/test/autotests/codegen/slot-with-writes-nested/index.js b/test/autotests/codegen/slot-with-writes-nested/index.js deleted file mode 100644 index ac7d943949..0000000000 --- a/test/autotests/codegen/slot-with-writes-nested/index.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -module.exports = function(builder) { - var vars = []; - - var varsSlot = builder.slot((slot, codegen) => { - slot.setContent(codegen.builder.vars(vars)); - }); - - return builder.program([ - builder.ifStatement('true', [ - builder.text(builder.literal('BEFORE - Hello World')), - varsSlot, - builder.node(function(node, codegen) { - vars.push({ - id: 'foo', - init: builder.literal('abc') - }); - }), - builder.node(function(node, codegen) { - vars.push({ - id: 'bar', - init: builder.literal(123) - }); - }), - builder.text(builder.literal('AFTER - Hello World')) - ]) - ]); -}; \ No newline at end of file diff --git a/test/autotests/codegen/slot-with-writes/expected.js b/test/autotests/codegen/slot-with-writes/expected.js deleted file mode 100644 index 3cf3af9f9d..0000000000 --- a/test/autotests/codegen/slot-with-writes/expected.js +++ /dev/null @@ -1,6 +0,0 @@ -out.w("BEFORE - Hello World"); - -var foo = "abc", - bar = 123; - -out.w("AFTER - Hello World"); diff --git a/test/autotests/codegen/slot-with-writes/index.js b/test/autotests/codegen/slot-with-writes/index.js deleted file mode 100644 index 9854d189cf..0000000000 --- a/test/autotests/codegen/slot-with-writes/index.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -module.exports = function(builder) { - var vars = []; - - var varsSlot = builder.slot((slot, codegen) => { - slot.setContent(codegen.builder.vars(vars)); - }); - - return builder.program([ - builder.text(builder.literal('BEFORE - Hello World')), - varsSlot, - builder.node(function(node, codegen) { - vars.push({ - id: 'foo', - init: builder.literal('abc') - }); - }), - builder.node(function(node, codegen) { - vars.push({ - id: 'bar', - init: builder.literal(123) - }); - }), - builder.text(builder.literal('AFTER - Hello World')) - ]); -}; \ No newline at end of file diff --git a/test/autotests/codegen/slot/expected.js b/test/autotests/codegen/slot/expected.js deleted file mode 100644 index e40004b127..0000000000 --- a/test/autotests/codegen/slot/expected.js +++ /dev/null @@ -1,2 +0,0 @@ -var foo = "abc", - bar = 123; diff --git a/test/autotests/codegen/slot/index.js b/test/autotests/codegen/slot/index.js deleted file mode 100644 index 79a68bf604..0000000000 --- a/test/autotests/codegen/slot/index.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -module.exports = function(builder) { - var vars = []; - - return builder.program([ - builder.slot((slot, codegen) => { - slot.setContent(codegen.builder.vars(vars)); - }), - builder.node(function(node, codegen) { - vars.push({ - id: 'foo', - init: codegen.builder.literal('abc') - }); - }), - builder.node(function(node, codegen) { - vars.push({ - id: 'bar', - init: codegen.builder.literal(123) - }); - }) - ]); -}; \ No newline at end of file diff --git a/test/autotests/codegen/templateRoot-prependChild/expected.js b/test/autotests/codegen/templateRoot-prependChild/expected.js index 24cc9ac46a..f5177a18d0 100644 --- a/test/autotests/codegen/templateRoot-prependChild/expected.js +++ b/test/autotests/codegen/templateRoot-prependChild/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { var foo = "bar"; diff --git a/test/autotests/codegen/templateRoot/expected.js b/test/autotests/codegen/templateRoot/expected.js new file mode 100644 index 0000000000..8c54365814 --- /dev/null +++ b/test/autotests/codegen/templateRoot/expected.js @@ -0,0 +1,9 @@ +function create(__markoHelpers) { + return function render(data, out) { + var foo = "bar"; + + out.w("
    "); + }; +} + +(module.exports = require("marko").c(__filename)).c(create); diff --git a/test/autotests/codegen/templateRoot/index.js b/test/autotests/codegen/templateRoot/index.js new file mode 100644 index 0000000000..b921cc6f04 --- /dev/null +++ b/test/autotests/codegen/templateRoot/index.js @@ -0,0 +1,21 @@ +'use strict'; + +module.exports = function(builder) { + var templateRoot = builder.templateRoot([ + builder.htmlElement( + 'div', + { class: builder.literal('foo') }, + [ + builder.htmlElement('span', { class: builder.literal('bar')}) + ]) + ]); + + templateRoot.prependChild(builder.vars([ + { + id: 'foo', + init: builder.literal('bar') + } + ])); + + return templateRoot; +}; \ No newline at end of file diff --git a/test/autotests/codegen/var-scoped/expected.js b/test/autotests/codegen/var-scoped/expected.js index 58524372a4..486b1690a0 100644 --- a/test/autotests/codegen/var-scoped/expected.js +++ b/test/autotests/codegen/var-scoped/expected.js @@ -2,4 +2,4 @@ var name = "string"; log(name); -}()) \ No newline at end of file +})() \ No newline at end of file diff --git a/test/autotests/compiler/addNestedVariable/expected.js b/test/autotests/compiler/addNestedVariable/expected.js index 259a9b11b0..bb5465a693 100644 --- a/test/autotests/compiler/addNestedVariable/expected.js +++ b/test/autotests/compiler/addNestedVariable/expected.js @@ -1,16 +1,13 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - test_addNestedVariable = __loadTag(require("./tags/test-addNestedVariable/renderer")); +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x, + marko_loadTag = __markoHelpers.t, + test_addNestedVariable = marko_loadTag(require("./tags/test-addNestedVariable/renderer")); return function render(data, out) { test_addNestedVariable({ renderBody: function renderBody(out, foo) { out.w("Hello " + - escapeXml(foo) + + marko_escapeXml(foo) + "!"); } }, out); diff --git a/test/autotests/compiler/attr-escape/expected.js b/test/autotests/compiler/attr-escape/expected.js index 89519ba48c..faa25431b0 100644 --- a/test/autotests/compiler/attr-escape/expected.js +++ b/test/autotests/compiler/attr-escape/expected.js @@ -1,24 +1,21 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - classAttr = __helpers.ca, - attr = __helpers.a, - escapeXmlAttr = __helpers.xa; +function create(__markoHelpers) { + var marko_classAttr = __markoHelpers.ca, + marko_attr = __markoHelpers.a, + marko_escapeXmlAttr = __markoHelpers.xa, + marko_str = __markoHelpers.s; return function render(data, out) { out.w(""); }; } diff --git a/test/autotests/compiler/attr-placeholder-escapeXml/expected.js b/test/autotests/compiler/attr-placeholder-escapeXml/expected.js index dea510f126..78fcb30072 100644 --- a/test/autotests/compiler/attr-placeholder-escapeXml/expected.js +++ b/test/autotests/compiler/attr-placeholder-escapeXml/expected.js @@ -1,13 +1,9 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - escapeXmlAttr = __helpers.xa; +function create(__markoHelpers) { + var marko_escapeXmlAttr = __markoHelpers.xa; return function render(data, out) { out.w("
    "); var foo = "Hello " + data.name; diff --git a/test/autotests/compiler/createNodeFromEl/expected.js b/test/autotests/compiler/createNodeFromEl/expected.js index ecc5efee51..da25b7b0d0 100644 --- a/test/autotests/compiler/createNodeFromEl/expected.js +++ b/test/autotests/compiler/createNodeFromEl/expected.js @@ -1,10 +1,6 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - test_hello = __loadTag(require("./tags/test-hello/renderer")); +function create(__markoHelpers) { + var marko_loadTag = __markoHelpers.t, + test_hello = marko_loadTag(require("./tags/test-hello/renderer")); return function render(data, out) { test_hello({ diff --git a/test/autotests/compiler/custom-tag-body-function/expected.js b/test/autotests/compiler/custom-tag-body-function/expected.js index f77f08a7b0..da034e7b11 100644 --- a/test/autotests/compiler/custom-tag-body-function/expected.js +++ b/test/autotests/compiler/custom-tag-body-function/expected.js @@ -1,10 +1,6 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - test_body_function = __loadTag(require("./tags/test-body-function/renderer")); +function create(__markoHelpers) { + var marko_loadTag = __markoHelpers.t, + test_body_function = marko_loadTag(require("./tags/test-body-function/renderer")); return function render(data, out) { test_body_function({ diff --git a/test/autotests/compiler/custom-tag-data/expected.js b/test/autotests/compiler/custom-tag-data/expected.js index ee8fd0d070..44f75df648 100644 --- a/test/autotests/compiler/custom-tag-data/expected.js +++ b/test/autotests/compiler/custom-tag-data/expected.js @@ -1,11 +1,7 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - custom_tag_data = __loadTag(require("./custom-tag-data-tag")), - __merge = __helpers.m; +function create(__markoHelpers) { + var marko_loadTag = __markoHelpers.t, + custom_tag_data = marko_loadTag(require("./custom-tag-data-tag")), + marko_merge = __markoHelpers.m; return function render(data, out) { custom_tag_data({ @@ -18,7 +14,7 @@ function create(__helpers) { age: 32 }, out); - custom_tag_data(__merge({ + custom_tag_data(marko_merge({ age: 10 }, { name: "Frank", diff --git a/test/autotests/compiler/custom-tag-import-var/expected.js b/test/autotests/compiler/custom-tag-import-var/expected.js index b814fc3754..6c3925d53f 100644 --- a/test/autotests/compiler/custom-tag-import-var/expected.js +++ b/test/autotests/compiler/custom-tag-import-var/expected.js @@ -1,10 +1,6 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - test_import_var = __loadTag(require("./tags/test-import-var/renderer")); +function create(__markoHelpers) { + var marko_loadTag = __markoHelpers.t, + test_import_var = marko_loadTag(require("./tags/test-import-var/renderer")); return function render(data, out) { test_import_var({ diff --git a/test/autotests/compiler/custom-tag-template/expected.js b/test/autotests/compiler/custom-tag-template/expected.js index decaa1b6a6..f2a691fa69 100644 --- a/test/autotests/compiler/custom-tag-template/expected.js +++ b/test/autotests/compiler/custom-tag-template/expected.js @@ -1,10 +1,6 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - loadTemplate = __helpers.l, - __hello = loadTemplate(require.resolve("./hello.marko")); +function create(__markoHelpers) { + var marko_loadTemplate = __markoHelpers.l, + __hello = marko_loadTemplate(require.resolve("./hello.marko")); return function render(data, out) { __hello.render({ diff --git a/test/autotests/compiler/custom-tag/expected.js b/test/autotests/compiler/custom-tag/expected.js index 501731a610..16eb7d6136 100644 --- a/test/autotests/compiler/custom-tag/expected.js +++ b/test/autotests/compiler/custom-tag/expected.js @@ -1,10 +1,6 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - test_hello = __loadTag(require("./tags/test-hello/renderer")); +function create(__markoHelpers) { + var marko_loadTag = __markoHelpers.t, + test_hello = marko_loadTag(require("./tags/test-hello/renderer")); return function render(data, out) { test_hello({ diff --git a/test/autotests/compiler/entities/expected.js b/test/autotests/compiler/entities/expected.js index f36acf6da9..47de8f2436 100644 --- a/test/autotests/compiler/entities/expected.js +++ b/test/autotests/compiler/entities/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { out.w("Hello John & Suzy Invalid Entity: &b ; Valid Numeric Entity: " Valid Hexadecimal Entity: ¢"); }; diff --git a/test/autotests/compiler/hello-dynamic/expected.js b/test/autotests/compiler/hello-dynamic/expected.js index 00f09f0d25..bc086f9987 100644 --- a/test/autotests/compiler/hello-dynamic/expected.js +++ b/test/autotests/compiler/hello-dynamic/expected.js @@ -1,16 +1,14 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x, + marko_str = __markoHelpers.s; return function render(data, out) { out.w("Hello " + - escapeXml(data.name) + + marko_escapeXml(data.name) + "! Hello " + - str(data.name) + + marko_str(data.name) + "! Hello " + - str(data.missing) + + marko_str(data.missing) + "!"); }; } diff --git a/test/autotests/compiler/importModule/expected.js b/test/autotests/compiler/importModule/expected.js index bf1632cb4b..0f66038106 100644 --- a/test/autotests/compiler/importModule/expected.js +++ b/test/autotests/compiler/importModule/expected.js @@ -1,9 +1,5 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - foo = require("./foo"); +function create(__markoHelpers) { + var foo = require("./foo"); return function render(data, out) { foo(); diff --git a/test/autotests/compiler/include/expected.js b/test/autotests/compiler/include/expected.js index 6ffaac7477..e574dd59ef 100644 --- a/test/autotests/compiler/include/expected.js +++ b/test/autotests/compiler/include/expected.js @@ -1,10 +1,6 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - loadTemplate = __helpers.l, - __target = loadTemplate(require.resolve("./target.marko")); +function create(__markoHelpers) { + var marko_loadTemplate = __markoHelpers.l, + __target = marko_loadTemplate(require.resolve("./target.marko")); return function render(data, out) { __target.render({}, out); diff --git a/test/autotests/compiler/invoke-if/expected.js b/test/autotests/compiler/invoke-if/expected.js index 3991fff8fc..a2b1f63e9e 100644 --- a/test/autotests/compiler/invoke-if/expected.js +++ b/test/autotests/compiler/invoke-if/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { if (true) { console.log("hello"); diff --git a/test/autotests/compiler/invoke/expected.js b/test/autotests/compiler/invoke/expected.js index e4c16a9507..d9051466a0 100644 --- a/test/autotests/compiler/invoke/expected.js +++ b/test/autotests/compiler/invoke/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { data.renderBody(out); }; diff --git a/test/autotests/compiler/macros/expected.js b/test/autotests/compiler/macros/expected.js index 4885a656a3..fe99fcc86e 100644 --- a/test/autotests/compiler/macros/expected.js +++ b/test/autotests/compiler/macros/expected.js @@ -1,20 +1,17 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - forEach = __helpers.f; +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x, + marko_forEach = __markoHelpers.f; return function render(data, out) { function macro_renderTree(node, out, renderBody) { out.w("Name: " + - escapeXml(node.name) + + marko_escapeXml(node.name) + " Children: "); if (node.children) { out.w("
      "); - forEach(node.children, function(child) { + marko_forEach(node.children, function(child) { out.w("
    • "); macro_renderTree(child, out); diff --git a/test/autotests/compiler/marko-init/expected.js b/test/autotests/compiler/marko-init/expected.js index 349e4159fc..198b67434d 100644 --- a/test/autotests/compiler/marko-init/expected.js +++ b/test/autotests/compiler/marko-init/expected.js @@ -1,14 +1,11 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x; var name = '${name}
      '; return function render(data, out) { out.w("Hello " + - escapeXml(name) + + marko_escapeXml(name) + "!"); }; } diff --git a/test/autotests/compiler/nested-tags/expected.js b/test/autotests/compiler/nested-tags/expected.js index af617b7c4c..88b9d427d4 100644 --- a/test/autotests/compiler/nested-tags/expected.js +++ b/test/autotests/compiler/nested-tags/expected.js @@ -1,12 +1,8 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - __loadTag = __helpers.t, - test_nested_tags_overlay = __loadTag(require("./tags/test-nested-tags-overlay/renderer"), 0, 0, 1), - test_nested_tags_overlay_body = __loadTag(null, "body", 0), - test_nested_tags_overlay_footer = __loadTag(null, "footer", 0); +function create(__markoHelpers) { + var marko_loadTag = __markoHelpers.t, + test_nested_tags_overlay_body = marko_loadTag(null, "body", 0), + test_nested_tags_overlay_footer = marko_loadTag(null, "footer", 0), + test_nested_tags_overlay = marko_loadTag(require("./tags/test-nested-tags-overlay/renderer"), 0, 0, 1); return function render(data, out) { test_nested_tags_overlay({ diff --git a/test/autotests/compiler/replaceWith/expected.js b/test/autotests/compiler/replaceWith/expected.js index 01f5030146..bb681f8a7e 100644 --- a/test/autotests/compiler/replaceWith/expected.js +++ b/test/autotests/compiler/replaceWith/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { out.w("
      "); }; diff --git a/test/autotests/compiler/simple/expected.js b/test/autotests/compiler/simple/expected.js index 65111b3c0c..a87c45ce7b 100644 --- a/test/autotests/compiler/simple/expected.js +++ b/test/autotests/compiler/simple/expected.js @@ -1,21 +1,18 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x, - forEach = __helpers.f; +function create(__markoHelpers) { + var marko_escapeXml = __markoHelpers.x, + marko_forEach = __markoHelpers.f; return function render(data, out) { out.w("Hello " + - escapeXml(data.name) + + marko_escapeXml(data.name) + "! "); - if (notEmpty(data.colors)) { + if (data.colors.length) { out.w("
        "); - forEach(data.colors, function(color) { + marko_forEach(data.colors, function(color) { out.w("
      • " + - escapeXml(color) + + marko_escapeXml(color) + "
      • "); }); @@ -24,12 +21,12 @@ function create(__helpers) { out.w("
        No colors!
        "); } - if (notEmpty(data.colors)) { + if (data.colors.length) { out.w("
          "); - forEach(data.colors, function(color) { + marko_forEach(data.colors, function(color) { out.w("
        • " + - escapeXml(color) + + marko_escapeXml(color) + "
        • "); }); diff --git a/test/autotests/compiler/simple/template.marko b/test/autotests/compiler/simple/template.marko index 1da9f7f706..8c83d767c2 100644 --- a/test/autotests/compiler/simple/template.marko +++ b/test/autotests/compiler/simple/template.marko @@ -1,7 +1,7 @@ --- Hello ${data.name}! -
            +
            • ${color}
            • @@ -10,7 +10,7 @@ Hello ${data.name}! No colors! - +
              • diff --git a/test/autotests/compiler/static/expected.js b/test/autotests/compiler/static/expected.js index d0e66fb499..45134cf626 100644 --- a/test/autotests/compiler/static/expected.js +++ b/test/autotests/compiler/static/expected.js @@ -1,9 +1,4 @@ -function create(__helpers) { - var str = __helpers.s, - empty = __helpers.e, - notEmpty = __helpers.ne, - escapeXml = __helpers.x; - +function create(__markoHelpers) { return function render(data, out) { out.w("Hello John"); }; diff --git a/test/autotests/inline/concise/expected.html b/test/autotests/inline/concise/expected.html new file mode 100644 index 0000000000..dccc45d3cb --- /dev/null +++ b/test/autotests/inline/concise/expected.html @@ -0,0 +1 @@ +
                Hello Frank!
                Test \ No newline at end of file diff --git a/test/autotests/inline/concise/index.js b/test/autotests/inline/concise/index.js new file mode 100644 index 0000000000..2105be9ae3 --- /dev/null +++ b/test/autotests/inline/concise/index.js @@ -0,0 +1,10 @@ +module.exports = function() { + var name = 'Frank'; + var template = marko` + div + - Hello ${name}! + span - Test + `; + + return template.renderSync(); +}; \ No newline at end of file diff --git a/test/autotests/inline/layout-template/expected.html b/test/autotests/inline/layout-template/expected.html new file mode 100644 index 0000000000..c11f400b31 --- /dev/null +++ b/test/autotests/inline/layout-template/expected.html @@ -0,0 +1 @@ +Hello World

                Hello World

                Hello Frank! This is the body content!
                \ No newline at end of file diff --git a/test/autotests/inline/layout-template/index.js b/test/autotests/inline/layout-template/index.js new file mode 100644 index 0000000000..de25b912cc --- /dev/null +++ b/test/autotests/inline/layout-template/index.js @@ -0,0 +1,24 @@ +var layout = marko` + + html lang="en" + head + meta charset="UTF-8" + ${data.title} + body + h1 - ${data.title} + div + layout-placeholder name="body" + `; + +module.exports = function() { + var title = 'Hello World'; + var name = 'Frank'; + + var template = marko` + layout-use(layout) title=title + layout-put into="body" + - Hello ${name}! This is the body content! + `; + + return template.renderSync(); +}; \ No newline at end of file diff --git a/test/autotests/inline/local-vars/expected.html b/test/autotests/inline/local-vars/expected.html new file mode 100644 index 0000000000..9258b28172 --- /dev/null +++ b/test/autotests/inline/local-vars/expected.html @@ -0,0 +1 @@ +
                Hello Frank!
                \ No newline at end of file diff --git a/test/autotests/inline/local-vars/index.js b/test/autotests/inline/local-vars/index.js new file mode 100644 index 0000000000..c8a7b29671 --- /dev/null +++ b/test/autotests/inline/local-vars/index.js @@ -0,0 +1,9 @@ +module.exports = function() { + var name = 'Frank'; + var template = marko` +
                + Hello ${name}! +
                `; + + return template.renderSync(); +}; \ No newline at end of file diff --git a/test/autotests/inline/multiple-templates-custom-tags/components/test-bar/template.marko b/test/autotests/inline/multiple-templates-custom-tags/components/test-bar/template.marko new file mode 100644 index 0000000000..a5989693dd --- /dev/null +++ b/test/autotests/inline/multiple-templates-custom-tags/components/test-bar/template.marko @@ -0,0 +1 @@ +div.bar - BAR \ No newline at end of file diff --git a/test/autotests/inline/multiple-templates-custom-tags/components/test-foo/template.marko b/test/autotests/inline/multiple-templates-custom-tags/components/test-foo/template.marko new file mode 100644 index 0000000000..f31fbde730 --- /dev/null +++ b/test/autotests/inline/multiple-templates-custom-tags/components/test-foo/template.marko @@ -0,0 +1 @@ +div.foo - FOO \ No newline at end of file diff --git a/test/autotests/inline/multiple-templates-custom-tags/expected.html b/test/autotests/inline/multiple-templates-custom-tags/expected.html new file mode 100644 index 0000000000..d8de72b3cf --- /dev/null +++ b/test/autotests/inline/multiple-templates-custom-tags/expected.html @@ -0,0 +1,2 @@ +
                FOO
                FOO
                +
                BAR
                BAR
                \ No newline at end of file diff --git a/test/autotests/inline/multiple-templates-custom-tags/index.js b/test/autotests/inline/multiple-templates-custom-tags/index.js new file mode 100644 index 0000000000..56247104d7 --- /dev/null +++ b/test/autotests/inline/multiple-templates-custom-tags/index.js @@ -0,0 +1,13 @@ +module.exports = function() { + var name = 'Frank'; + + var template1 = marko` + test-foo + test-foo`; + + var template2 = marko` + test-bar + test-bar`; + + return template1.renderSync() + '\n' + template2.renderSync(); +}; \ No newline at end of file diff --git a/test/autotests/inline/render-callback/expected.html b/test/autotests/inline/render-callback/expected.html new file mode 100644 index 0000000000..9258b28172 --- /dev/null +++ b/test/autotests/inline/render-callback/expected.html @@ -0,0 +1 @@ +
                Hello Frank!
                \ No newline at end of file diff --git a/test/autotests/inline/render-callback/index.js b/test/autotests/inline/render-callback/index.js new file mode 100644 index 0000000000..ca28c9870d --- /dev/null +++ b/test/autotests/inline/render-callback/index.js @@ -0,0 +1,9 @@ +module.exports = function(done) { + var name = 'Frank'; + var template = marko` +
                + Hello ${name}! +
                `; + + return template.render(null, done); +}; \ No newline at end of file diff --git a/test/autotests/render/body-placeholder-literal2/expected.html b/test/autotests/render/body-placeholder-literal2/expected.html index f0f494161d..96395cd02a 100644 --- a/test/autotests/render/body-placeholder-literal2/expected.html +++ b/test/autotests/render/body-placeholder-literal2/expected.html @@ -1 +1 @@ -A B C \ No newline at end of file + A B C \ No newline at end of file diff --git a/test/autotests/render/include-whitespace/expected.html b/test/autotests/render/include-whitespace/expected.html new file mode 100644 index 0000000000..8bb07f4143 --- /dev/null +++ b/test/autotests/render/include-whitespace/expected.html @@ -0,0 +1 @@ +

                Hello Frank! You have 20 new messages.

                Have a wonderful day!

                \ No newline at end of file diff --git a/test/autotests/render/include-whitespace/include-target.marko b/test/autotests/render/include-whitespace/include-target.marko new file mode 100644 index 0000000000..426ae13f1c --- /dev/null +++ b/test/autotests/render/include-whitespace/include-target.marko @@ -0,0 +1,8 @@ +
                +

                + Hello ${data.name}! You have ${data.count} new messages. +

                +

                + +

                +
                \ No newline at end of file diff --git a/test/autotests/render/include-whitespace/template.marko b/test/autotests/render/include-whitespace/template.marko new file mode 100644 index 0000000000..cc2c6956d5 --- /dev/null +++ b/test/autotests/render/include-whitespace/template.marko @@ -0,0 +1,5 @@ + + Have a + wonderful + day! + \ No newline at end of file diff --git a/test/autotests/render/include-whitespace/test.js b/test/autotests/render/include-whitespace/test.js new file mode 100644 index 0000000000..c4013b3447 --- /dev/null +++ b/test/autotests/render/include-whitespace/test.js @@ -0,0 +1 @@ +exports.templateData = {}; diff --git a/test/autotests/render/preserveWhitespace-global/expected.html b/test/autotests/render/preserveWhitespace-global/expected.html index 39466f6587..567113dc8a 100644 --- a/test/autotests/render/preserveWhitespace-global/expected.html +++ b/test/autotests/render/preserveWhitespace-global/expected.html @@ -1,3 +1,5 @@ + +
                This Whitespace diff --git a/test/autotests/render/simple/template.marko b/test/autotests/render/simple/template.marko index 22ee904ac6..88e4980a09 100644 --- a/test/autotests/render/simple/template.marko +++ b/test/autotests/render/simple/template.marko @@ -6,11 +6,11 @@ ${message}
                -
                  +
                  • ${color}
                  -
                  +
                  No colors!
                  \ No newline at end of file diff --git a/test/autotests/render/syntax-concise/template.marko b/test/autotests/render/syntax-concise/template.marko index 53a778f22e..cc811f856c 100644 --- a/test/autotests/render/syntax-concise/template.marko +++ b/test/autotests/render/syntax-concise/template.marko @@ -20,7 +20,7 @@ html lang="en" li for(feature in ['async', 'streaming', 'custom-tags', 'readable', 'modules']) ${feature} - ul if(notEmpty(data.colors)) + ul if(data.colors && data.colors.length) li for(color in data.colors) - ${color} div else - No colors! diff --git a/test/autotests/render/syntax-mixed/template.marko b/test/autotests/render/syntax-mixed/template.marko index c2df3c5486..c9ff24511b 100644 --- a/test/autotests/render/syntax-mixed/template.marko +++ b/test/autotests/render/syntax-mixed/template.marko @@ -20,7 +20,7 @@ html lang="en" li for(feature in ['async', 'streaming', 'custom-tags', 'readable', 'modules']) ${feature} - ul if(notEmpty(data.colors)) + ul if(data.colors && data.colors.length) li for(color in data.colors) - ${color} div else - No colors! diff --git a/test/autotests/render/syntax-simple-concise/template.marko b/test/autotests/render/syntax-simple-concise/template.marko index 6776125e0b..09ccb9b2e4 100644 --- a/test/autotests/render/syntax-simple-concise/template.marko +++ b/test/autotests/render/syntax-simple-concise/template.marko @@ -4,7 +4,7 @@ html lang="en" title - Marko Templating Engine body h1 - Hello ${data.name}! - ul if(notEmpty(data.colors)) + ul if(data.colors.length) li for(color in data.colors) ${color} div else diff --git a/test/autotests/render/syntax-simple-mixed/template.marko b/test/autotests/render/syntax-simple-mixed/template.marko index b860854411..ca434c1b3b 100644 --- a/test/autotests/render/syntax-simple-mixed/template.marko +++ b/test/autotests/render/syntax-simple-mixed/template.marko @@ -6,7 +6,7 @@ html lang="en"

                  Hello ${data.name}!

                  - ul if(notEmpty(data.colors)) + ul if(data.colors.length) li for(color in data.colors) ${color} div else diff --git a/test/autotests/render/syntax-simple-verbose/template.marko b/test/autotests/render/syntax-simple-verbose/template.marko index 4835a1b7ad..99d7a8abf7 100644 --- a/test/autotests/render/syntax-simple-verbose/template.marko +++ b/test/autotests/render/syntax-simple-verbose/template.marko @@ -8,7 +8,7 @@ Hello ${data.name}! -
                    +
                    • ${color}
                    • diff --git a/test/autotests/render/syntax-verbose/template.marko b/test/autotests/render/syntax-verbose/template.marko index 11eadc515b..cd36f19d70 100644 --- a/test/autotests/render/syntax-verbose/template.marko +++ b/test/autotests/render/syntax-verbose/template.marko @@ -22,7 +22,7 @@ -
                        +
                        • ${color}
                        diff --git a/test/autotests/render/whitespace-div/expected.html b/test/autotests/render/whitespace-div/expected.html new file mode 100644 index 0000000000..85be96f6aa --- /dev/null +++ b/test/autotests/render/whitespace-div/expected.html @@ -0,0 +1 @@ +
                        Hello
                        \ No newline at end of file diff --git a/test/autotests/render/whitespace-div/template.marko b/test/autotests/render/whitespace-div/template.marko new file mode 100644 index 0000000000..327e027b4c --- /dev/null +++ b/test/autotests/render/whitespace-div/template.marko @@ -0,0 +1,3 @@ +
                        + Hello +
                        \ No newline at end of file diff --git a/test/autotests/render/whitespace-div/test.js b/test/autotests/render/whitespace-div/test.js new file mode 100644 index 0000000000..c4013b3447 --- /dev/null +++ b/test/autotests/render/whitespace-div/test.js @@ -0,0 +1 @@ +exports.templateData = {}; diff --git a/test/autotests/render/whitespace-var-scoped/expected.html b/test/autotests/render/whitespace-var-scoped/expected.html new file mode 100644 index 0000000000..f73a71e899 --- /dev/null +++ b/test/autotests/render/whitespace-var-scoped/expected.html @@ -0,0 +1 @@ +Hello Frank \ No newline at end of file diff --git a/test/autotests/render/whitespace-var-scoped/template.marko b/test/autotests/render/whitespace-var-scoped/template.marko new file mode 100644 index 0000000000..0b532bf182 --- /dev/null +++ b/test/autotests/render/whitespace-var-scoped/template.marko @@ -0,0 +1,3 @@ + + Hello ${name} + \ No newline at end of file diff --git a/test/autotests/render/whitespace-var-scoped/test.js b/test/autotests/render/whitespace-var-scoped/test.js new file mode 100644 index 0000000000..c4013b3447 --- /dev/null +++ b/test/autotests/render/whitespace-var-scoped/test.js @@ -0,0 +1 @@ +exports.templateData = {}; diff --git a/test/codegen-test.js b/test/codegen-test.js index 83848f2df7..0b6ce04dd3 100644 --- a/test/codegen-test.js +++ b/test/codegen-test.js @@ -12,34 +12,48 @@ var autotest = require('./autotest'); var CompileContext = require('../compiler/CompileContext'); var CodeGenerator = require('../compiler/CodeGenerator'); +var CodeWriter = require('../compiler/CodeWriter'); -function createCodeGenerator() { - var context = new CompileContext('dummy', 'dummy.marko', builder); +function createCodeGenerator(context) { return new CodeGenerator(context); } +function createCodeWriter(context) { + return new CodeWriter(context); +} + describe('compiler/codegen', function() { var autoTestDir = path.join(__dirname, 'autotests/codegen'); autotest.scanDir(autoTestDir, function run(dir, helpers, done) { var main = require(path.join(dir, 'index.js')); var generateCodeFunc = main; - var codegen = createCodeGenerator(); + + var context = new CompileContext('dummy', 'dummy.marko', builder); + var codegen = createCodeGenerator(context); + var codeWriter = createCodeWriter(context); + var ast = generateCodeFunc(builder, codegen); - codegen.generateCode(ast); - helpers.compare(codegen.getCode(), '.js'); + var finalAST = codegen.generateCode(ast); + + console.log(module.id, 'FINAL AST', JSON.stringify(finalAST, null, 4)); + + codeWriter.write(finalAST); + helpers.compare(codeWriter.getCode(), '.js'); done(); }); it('should not allow a return outside a function', function() { let builder = compiler.createBuilder(); - expect(function() { - var rootNode = builder.program([ - builder.returnStatement('foo') - ]); + var context = new CompileContext('dummy', 'dummy.marko', builder); + var codegen = createCodeGenerator(context); - var codegen = createCodeGenerator(); + var rootNode = builder.program([ + builder.returnStatement('foo') + ]); + + expect(function() { codegen.generateCode(rootNode); }).to.throw('"return" not allowed outside a function body'); }); diff --git a/test/inline-test.js b/test/inline-test.js new file mode 100644 index 0000000000..473fc6a13d --- /dev/null +++ b/test/inline-test.js @@ -0,0 +1,60 @@ +'use strict'; +require('./patch-module'); + +var chai = require('chai'); +chai.config.includeStack = true; +var path = require('path'); +var compiler = require('../compiler'); +var autotest = require('./autotest'); +var fs = require('fs'); + +require('marko/node-require').install(); + +describe('inline', function() { + var autoTestDir = path.join(__dirname, 'autotests/inline'); + + autotest.scanDir(autoTestDir, function run(dir, helpers, done) { + var indexPath = path.join(dir, 'index.js'); + var inlineCompiler = compiler.createInlineCompiler(indexPath); + + var src = fs.readFileSync(indexPath, { encoding: 'utf8' }); + + src = src.replace(/marko`([^`]*)`/g, function(match, templateSrc) { + var compiled = inlineCompiler.compile(templateSrc); + return compiled.code; + }); + + var staticCode = inlineCompiler.staticCode; + + if (staticCode) { + src = staticCode + '\n\n' + src; + } + + var outputFile = path.join(dir, 'index.generated.js'); + fs.writeFileSync(outputFile, src, { encoding: 'utf8' }); + + var func = require(outputFile); + + function handleOutput(html) { + helpers.compare(html, '.html'); + done(); + } + + if (func.length === 1) { + func((err, html) => { + if (err) { + return done(err); + } + + handleOutput(html); + }); + } else { + let outputHtml = func(); + handleOutput(outputHtml); + } + + + + }); + +}); \ No newline at end of file