Skip to content

Instantly share code, notes, and snippets.

@linstantnoodles
Last active August 29, 2015 14:21
Show Gist options
  • Save linstantnoodles/176d232b10579ec7503c to your computer and use it in GitHub Desktop.
Save linstantnoodles/176d232b10579ec7503c to your computer and use it in GitHub Desktop.
compiler
(function (window, undefined) {
var directiveFactories = {};
/**
* @description Register directive factory functions
*
* @param {String} name Name of the directive
* @param {Function} factory The factory function
*/
function directive (name, factory) {
directiveFactories[name] = factory;
}
/**
* @description Compile directives
*
* @param {Node} node The root HTML node on which compilation starts
* @returns {Function} The final combined linking function
*/
function compile (node) {
// Kick off with the root node
return compileNodes([node]);
/**
* @description Compile a list of nodes
*
* @param {Array|HTMLCollection} nodeList A list of HTML nodes
* @returns {Function} A combined linking function
*/
function compileNodes (nodeList) {
// Stack for holding parent-child linker pairs
var linkers = [];
for (var i = 0; i < nodeList.length; i++) {
var node = nodeList[i];
var directives = collectDirectives(node);
var linker = compileDirectives(node, directives);
// Recursively get combined linking function for its children
var childLinker = compileNodes(node.children);
linkers.push(linker);
linkers.push(childLinker);
}
return combinedLinker;
/**
* @description Invoke all the linkers
*/
function combinedLinker () {
for (var i = 0; i < linkers.length; i += 2) {
var currLinker = linkers[i];
var childLinker = linkers[i+1];
currLinker(childLinker);
}
}
}
/**
* @description Get and sort directives on node
*
* @param {Node} node A HTML node
* @return {Array.<Object>} A list of directives
*/
function collectDirectives (node) {
var suffix = "-dir";
var directives = [];
for (var i = 0; i < node.attributes.length; i++) {
var attrName = node.attributes[i].name;
if (attrName.indexOf(suffix) >= 0) {
var directiveFactory = directiveFactories[attrName];
if (directiveFactory) {
var directive = directiveFactory();
// Set default priority
directive['priority'] = directive['priority'] || 0;
directives.push(directive);
}
}
}
// Higher priority directives come first
directives.sort(function (directiveA, directiveB) {
return directiveB.priority - directiveA.priority;
});
return directives;
}
/**
* @description Compile the directives to get linking functions (pre and post)
*
* @param {Node} node A HTML node
* @param {Array} directives A list of directives
* @return {Function} Linking function
*/
function compileDirectives (node, directives) {
var preLinks = [];
var postLinks = [];
for (var i = 0; i < directives.length; i++) {
var links = directives[i].compile();
preLinks.push(links.pre);
postLinks.push(links.post);
}
return linker;
/**
* @description Executes the current nodes linking functions as well as
* the linking functions of its children
*
* @param {Function} childLinker The combined linking function
* from the compilation of the current nodes children
*/
function linker (childLinker) {
// Run prelink functions in pre-order stage
for (var i = 0; i < preLinks.length; i++) {
preLinks[i](node);
}
// Run child links
childLinker();
// Run postlink functions in post-order stage
for (var i = 0; i < postLinks.length; i++) {
postLinks[i](node);
}
}
}
}
// Define API
window.Compiler = {
directive: directive,
compile: compile
};
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment