Skip to content

Commit

Permalink
breaking: Template Compilation
Browse files Browse the repository at this point in the history
- generator state
  - `staticNodes` -> static node code
  - `dependencies` -> method and prop dependencies
  - `exclude` -> global variables and keywords
  - `locals` -> local variables
- `on` directive
  - `event` variable is available, but not by default
  • Loading branch information
kbrsh committed Oct 21, 2017
1 parent 99d361b commit dc36037
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 52 deletions.
38 changes: 22 additions & 16 deletions dist/moon.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,17 +643,20 @@
}

// Global Variables/Keywords
var globals = ["instance", "staticNodes", "event", "true", "false", "undefined", "null", "NaN", "typeof", "in"];
var globals = ["instance", "staticNodes", "true", "false", "undefined", "null", "NaN", "typeof", "in"];

// Void and SVG Elements
var VOID_ELEMENTS = ["area", "base", "br", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];
var SVG_ELEMENTS = ["animate", "circle", "clippath", "cursor", "defs", "desc", "ellipse", "filter", "font-face", "foreignObject", "g", "glyph", "image", "line", "marker", "mask", "missing-glyph", "path", "pattern", "polygon", "polyline", "rect", "svg", "switch", "symbol", "text", "textpath", "tspan", "use", "view"];

var compileTemplateExpression = function(expression, state) {
var dependencies = state.dependencies;
var exclude = state.exclude;
var props = dependencies.props;
var methods = dependencies.methods;

var exclude = state.exclude;
var locals = state.locals;

var dynamic = false;
var info;

Expand All @@ -666,10 +669,10 @@
methods.push(name);
}
} else {
if(props.indexOf(name) === -1) {
if(locals.indexOf(name) === -1 && props.indexOf(name) === -1) {
props.push(name);
}

dynamic = true;
}
}
Expand Down Expand Up @@ -1202,11 +1205,12 @@
var generate = function(tree) {
var state = {
staticNodes: [],
exclude: globals,
dependencies: {
props: [],
methods: []
}
},
exclude: globals,
locals: []
};

var treeOutput = generateNode(tree, undefined, state);
Expand Down Expand Up @@ -1673,18 +1677,18 @@

// Save information
var iteratable = parts[1];
var exclude = state.exclude;
attr.data.forInfo = [iteratable, aliases, exclude];
state.exclude = exclude.concat(aliases.split(','));
var locals = state.locals;
attr.data.forInfo = [iteratable, aliases, locals];
state.locals = locals.concat(aliases.split(','));

return compileTemplateExpression(iteratable, state);
},
after: function(attr, output, node, parentNode, state) {
// Get information about parameters
var forInfo = attr.data.forInfo;

// Restore globals to exclude
state.exclude = forInfo[2];
// Restore locals
state.locals = forInfo[2];

// Use the renderLoop runtime helper
return ("m.renderLoop(" + (forInfo[0]) + ", function(" + (forInfo[1]) + ") {return " + output + ";})");
Expand All @@ -1693,20 +1697,22 @@

specialDirectives["m-on"] = {
before: function(attr, node, parentNode, state) {
// Get event type
var eventType = attr.argument;
var exclude = state.exclude;

// Get method call
var methodCall = attr.value;
if(methodCall.indexOf('(') === -1) {
methodCall += "(event)";
methodCall += "()";
}

// Add event handler
addEventToNode(eventType, ("function(event) {" + methodCall + ";}"), node);
addEventToNode(attr.argument, ("function(event) {" + methodCall + ";}"), node);

// Compile method call
return compileTemplateExpression(methodCall, state);
exclude.push("event");
var dynamic = compileTemplateExpression(methodCall, state);
exclude.pop();
return dynamic;
}
};

Expand Down
2 changes: 1 addition & 1 deletion dist/moon.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/compiler/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const escapeMap = {
}

// Global Variables/Keywords
const globals = ["instance", "staticNodes", "event", "true", "false", "undefined", "null", "NaN", "typeof", "in"];
const globals = ["instance", "staticNodes", "true", "false", "undefined", "null", "NaN", "typeof", "in"];

// Void and SVG Elements
const VOID_ELEMENTS = ["area", "base", "br", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,12 @@ const generateNode = function(node, parentNode, state) {
const generate = function(tree) {
let state = {
staticNodes: [],
exclude: globals,
dependencies: {
props: [],
methods: []
}
},
exclude: globals,
locals: []
};

let treeOutput = generateNode(tree, undefined, state);
Expand Down
11 changes: 7 additions & 4 deletions src/compiler/template.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
const compileTemplateExpression = function(expression, state) {
let dependencies = state.dependencies;
let exclude = state.exclude;
const dependencies = state.dependencies;
let props = dependencies.props;
let methods = dependencies.methods;

const exclude = state.exclude;
const locals = state.locals;

let dynamic = false;
let info;

Expand All @@ -15,10 +18,10 @@ const compileTemplateExpression = function(expression, state) {
methods.push(name);
}
} else {
if(props.indexOf(name) === -1) {
if(locals.indexOf(name) === -1 && props.indexOf(name) === -1) {
props.push(name);
}

dynamic = true;
}
}
Expand Down
22 changes: 12 additions & 10 deletions src/directives/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,18 @@ specialDirectives["m-for"] = {

// Save information
const iteratable = parts[1];
const exclude = state.exclude;
attr.data.forInfo = [iteratable, aliases, exclude];
state.exclude = exclude.concat(aliases.split(','));
const locals = state.locals;
attr.data.forInfo = [iteratable, aliases, locals];
state.locals = locals.concat(aliases.split(','));

return compileTemplateExpression(iteratable, state);
},
after: function(attr, output, node, parentNode, state) {
// Get information about parameters
const forInfo = attr.data.forInfo;

// Restore globals to exclude
state.exclude = forInfo[2];
// Restore locals
state.locals = forInfo[2];

// Use the renderLoop runtime helper
return `m.renderLoop(${forInfo[0]}, function(${forInfo[1]}) {return ${output};})`;
Expand All @@ -115,20 +115,22 @@ specialDirectives["m-for"] = {

specialDirectives["m-on"] = {
before: function(attr, node, parentNode, state) {
// Get event type
const eventType = attr.argument;
let exclude = state.exclude;

// Get method call
let methodCall = attr.value;
if(methodCall.indexOf('(') === -1) {
methodCall += "(event)";
methodCall += "()";
}

// Add event handler
addEventToNode(eventType, `function(event) {${methodCall};}`, node);
addEventToNode(attr.argument, `function(event) {${methodCall};}`, node);

// Compile method call
return compileTemplateExpression(methodCall, state);
exclude.push("event");
const dynamic = compileTemplateExpression(methodCall, state);
exclude.pop();
return dynamic;
}
};

Expand Down
36 changes: 18 additions & 18 deletions test/core/directives/on.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
describe('On Directive', function() {
var on = createTestElement("on", '<p>{{count}}</p><button m-on:click="increment">Increment</button><button m-on:click="changeCustomIgnored(true)"></button>');
describe("On Directive", function() {
var on = createTestElement("on", '<p>{{count}}</p><button m-on:click="increment">Increment</button><button m-on:click="changeCustomIgnored(true, event)"></button>');
var p = on.firstChild;
var button = p.nextSibling;
var customIgnoredButton = button.nextSibling
Expand All @@ -13,43 +13,43 @@ describe('On Directive', function() {
count: 0
},
methods: {
increment: function(e) {
this.set('count', this.get('count') + 1);
evt = e;
increment: function() {
this.set("count", this.get("count") + 1);
},
changeCustomIgnored: function(condition) {
changeCustomIgnored: function(condition, e) {
customIgnoredParameters = condition;
evt = e;
}
}
});

it('should call a method', function() {
it("should call a method", function() {
button.click();

return wait(function() {
expect(app.get('count')).to.equal(1);
expect(app.get("count")).to.equal(1);
});
});

it('should update DOM', function() {
it("should update DOM", function() {
button.click();
return wait(function() {
expect(p.innerHTML).to.equal('2');
expect(p.innerHTML).to.equal("2");
});
});

it('should pass an event object', function() {
expect(evt.target.tagName).to.equal('BUTTON');
});

it('should call with ignored custom parameters', function() {
it("should call with ignored custom parameters", function() {
customIgnoredButton.click();
return wait(function() {
expect(customIgnoredParameters).to.be['true'];
expect(customIgnoredParameters).to.be["true"];
});
});

it('should not be present at runtime', function() {
expect(button.getAttribute("m-on")).to.be['null'];
it("should pass an event object", function() {
expect(evt.target.tagName).to.equal("BUTTON");
});

it("should not be present at runtime", function() {
expect(button.getAttribute("m-on")).to.be["null"];
});
});

0 comments on commit dc36037

Please sign in to comment.