Skip to content

Commit

Permalink
Merge pull request #13 from codemix/speed
Browse files Browse the repository at this point in the history
prepare 0.0.7
  • Loading branch information
phpnode committed Dec 19, 2014
2 parents 10b80cd + 98968cc commit 8bb6a50
Show file tree
Hide file tree
Showing 11 changed files with 548 additions and 374 deletions.
201 changes: 201 additions & 0 deletions lib/optimiser.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exports.optimise = function (ast) {
ast = hoistFunctions(ast);
ast = removeUnusedAssignmentExpressions(ast);
ast = replaceContextReferences(ast);
ast = cacheDuplicateReferences(ast);
ast = removeUnusedVariableDeclarators(ast);
ast = combineContiguousOutputStatements(ast);
ast = combineContiguousLiterals(ast);
Expand Down Expand Up @@ -470,3 +471,203 @@ function directReturnWherePossible (ast) {
}});
return ast;
}


function cacheDuplicateReferences (ast) {

traverse.traverse(ast, { enter: function (node, parent) {
if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') {
findDuplicateReferences(node);
}
}});
return ast;
}

function findDuplicateReferences (ast) {
var markers = [],
markedNodes = {};
traverse.traverse(ast, { enter: function (node, parent) {
if (node !== ast && (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression')) {
return this.skip();
}
else if (node.type !== 'SequenceExpression' ||
!node.marker ||
node.expressions[0].type !== 'AssignmentExpression' ||
(node.expressions[0].right.type !== 'Identifier' &&
(node.expressions[0].right.type !== 'MemberExpression' ||
node.expressions[0].right.object.name === 'ref'))
) {
return;
}
var marker;
if (node.expressions[0].right.type === 'Identifier') {
marker = node.expressions[0].right.name + '.' + node.marker;
}
else {
marker = node.expressions[0].right.object.name + '.' + node.marker;
}
if (!markedNodes[marker]) {
markedNodes[marker] = [];
}
markedNodes[marker].push(node);
markers.push(marker);
}});
if (markers.length) {
markers = collateMarkers(markers);
markers.forEach(function (item) {
var nodes = item[1].reduce(function (nodes, marker) {
return nodes.concat(markedNodes[marker]);
}, []);
var first;
/*traverse.replace(ast, {enter: function (n, p) {
if (~nodes.indexOf(n)) {
if (!first) {
if (n.type === 'AssignmentExpression') {
traverse.traverse(n, {enter: function (node, parent) {
if (node.type === 'Identifier' && node.name === n.) {
}
});
}
}
else {
return replaceSequenceExpression(item[0], n);
}
}
}});*/

});

}
return ast;
}

function replaceSequenceExpression (marker, node) {
var markerNoPrefix = marker.match(/^[A-Z0-9_$]+\.(.*)/i)[1];
if (node.marker === markerNoPrefix) {
return markerToIdentifier(marker);
}
else if (node.marker.slice(0, markerNoPrefix.length + 1) === markerNoPrefix + '.') {
var remaining = node.marker.slice(markerNoPrefix.length + 1).split('.');
if (remaining.length === 1) {
return {
type: 'ConditionalExpression',
test: {
type: 'BinaryExpression',
operator: '!=',
left: {
type: 'MemberExpression',
object: markerToIdentifier(marker),
property: {
type: 'Identifier',
name: remaining[0]
}
},
right: {
type: 'Literal',
value: null,
raw: 'null'
}
},
consequent: {
type: 'MemberExpression',
object: markerToIdentifier(marker),
property: {
type: 'Identifier',
name: remaining[0]
}
},
alternate: {
type: 'Literal',
value: '',
raw: '""'
}
};
}
else {
return node;
}
}
else {
return node;
}
}

function markerToIdentifier (marker) {
return {
type: 'Identifier',
name: "__" + marker.replace(/(\.)/g, '_')
};
}


function collateMarkers (markers) {
markers.sort();
var prefixes = markers.reduce(function (prefixes, marker) {
marker.split('.').reduce(function (collected, part) {
if (collected) {
collected += '.' + part;
}
else {
collected = part;
}
prefixes[collected] = prefixes[collected] || [];
prefixes[collected].push(marker);
return collected;
}, '');
return prefixes;
}, {});

var collated = [];
for (var prefix in prefixes) {
if (prefixes[prefix].length > 1) {
collated.push([prefix, prefixes[prefix]]);
}
}

collated.sort(function (a, b) {
if (a[0] > b[0]) {
return -1;
}
else if (a[0] < b[0]) {
return 1;
}
else {
return 0;
}
});

// if every reference to an identifier has already been seen, omit it

var seen = {};


collated = collated.reduce(function (collated, item) {
var filtered = item[1].filter(function (a) {
if (!seen[a]) {
seen[a] = true;
return true;
}
else {
return false;
}
});
if (filtered.length) {
collated.push([item[0], filtered]);
}
return collated;
}, []);

collated = collated.reduceRight(function (collated, item) {
var last = collated[collated.length - 1];
if (last && item[0].slice(0, last[0].length + 1) === last[0] + '.') {
last[1] = last[1].concat(item[1]);
}
else {
collated.push(item);
}
return collated;
}, []);

return collated;
}
585 changes: 250 additions & 335 deletions lib/parser.js

Large diffs are not rendered by default.

43 changes: 27 additions & 16 deletions lib/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ module.exports = Classing.create('Template', {
name: {
default: ''
},
/**
* The state of the template, used for protected properties.
*
* @type {Object}
*/
__state__: {
default: function () {
return {paths: {}};
}
},
/**
* Configure the template.
*
Expand Down Expand Up @@ -57,7 +67,13 @@ module.exports = Classing.create('Template', {
* @return {String} The rendered content.
*/
include: function (name, object, content) {
var include = this.collection.get(this.resolvePath(name));
if (typeof name === 'function') {
return name(object, content);
}
if (!this.__state__.paths[name]) {
this.__state__.paths[name] = this.resolvePath(name);
}
var include = this.collection.get(this.__state__.paths[name]);
if (!include) {
return content || '';
}
Expand All @@ -76,19 +92,13 @@ module.exports = Classing.create('Template', {
* @return {Object} The cloned scope.
*/
rescope: function (object, alias, value) {
var keys = Object.keys(object),
length = keys.length,
cloned = {},
key, i;

for (i = 0; i < length; i++) {
key = keys[i];
cloned[key] = object[key];
}
if (alias) {
cloned[alias] = value;
function Cloned () {
if (alias) {
this[alias] = value;
}
}
return cloned;
Cloned.prototype = object;
return new Cloned();
},
/**
* Escape HTML entities in a string to prevent XSS.
Expand Down Expand Up @@ -124,14 +134,15 @@ module.exports = Classing.create('Template', {
* @return {String} The rendered content.
*/
customElement: function (name, attributes, body, context, object) {
var resolved = this.resolveElementPath(name);
if (!body) {
return this.include(this.resolveElementPath(name), attributes);
return this.include(resolved, attributes);
}
else if (typeof body === 'function') {
return this.include(this.resolveElementPath(name), attributes, body(context, object));
return this.include(resolved, attributes, body(context, object));
}
else {
return this.include(this.resolveElementPath(name), attributes, body);
return this.include(resolved, attributes, body);
}
},
/**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "htmling",
"version": "0.0.6",
"version": "0.0.7",
"description": "Polymer compatible HTML5 based templating syntax for node.js.",
"main": "lib/index.js",
"directories": {
Expand Down
31 changes: 11 additions & 20 deletions src/parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ MarkedIdentifier
return {
type: 'MemberExpression',
computed: false,
marker: name,
object: {
type: 'Identifier',
name: 'object'
Expand Down Expand Up @@ -671,6 +672,14 @@ MemberExpression
= head:MarkedIdentifier tail:Accessor+ {
return {
type: 'SequenceExpression',
marker: tail.reduce(function (marker, item) {
if (!marker || !item.marker) {
return false;
}
else {
return marker + '.' + item.marker;
}
}, head.marker),
expressions: [
{
type: 'AssignmentExpression',
Expand Down Expand Up @@ -710,6 +719,7 @@ Accessor
= "." v:Identifier {
return {
type: 'SequenceExpression',
marker: v.name,
expressions: [
{
type: 'AssignmentExpression',
Expand Down Expand Up @@ -767,6 +777,7 @@ Accessor
/ "[" _ v:Expression _ "]" {
return {
type: 'SequenceExpression',
marker: false,
expressions: [
{
type: 'AssignmentExpression',
Expand Down Expand Up @@ -823,26 +834,6 @@ Accessor
}


SubMemberExpression
= left:Identifier "." right:SubMemberExpression {
return {
type: 'MemberExpression',
computed: false,
object: left,
property: right
};
}
/ left:Identifier "[" right:Expression "]" {
return {
type: 'MemberExpression',
computed: true,
object: left,
property: right
};
}
/ Identifier


Literal
= StringLiteral
/ Number
Expand Down
16 changes: 16 additions & 0 deletions test/expected/cache-references.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div class="item">
<h1>First Item</h1>
<span>en</span>
<address>
United Kingdom<br>
UK
</address>
</div>
<div class="item">
<h1>Second Item</h1>
<span>de</span>
<address>
Germany<br>
DE
</address>
</div>
1 change: 1 addition & 0 deletions test/expected/custom-element.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ <h1>Title Here</h1>
<nested-element>
<p>Hello World</p>
</nested-element>
<strong>hello world</strong>
</some-element>
<p class="lead">Foo</p>
Loading

0 comments on commit 8bb6a50

Please sign in to comment.