UNPKG

mist

Version:
472 lines (426 loc) 12.4 kB
var Globber, Hasher, MistResolver, path; path = require('path'); Globber = require('./globber'); Hasher = require('./hasher'); module.exports = MistResolver = (function() { function MistResolver(rootDir, rootMist) { this.rootDir = rootDir; this.rootMist = rootMist; this.groupRefs = {}; this.compileCommands(); this.setupTargets(); this.generateTemplates(); this.generateTargets(); } /* * Compiles all commands */ MistResolver.prototype.compileCommands = function() { var j, len1, ref, results1, rule; ref = this.rootMist.rules; results1 = []; for (j = 0, len1 = ref.length; j < len1; j++) { rule = ref[j]; results1.push(rule.command = { hash: Hasher.hash(rule.src.command), command: MistResolver.delimitCommand(rule.src.command) }); } return results1; }; /* * Creates a targets object for each rule */ MistResolver.prototype.setupTargets = function() { var j, len1, ref, results1, rule; ref = this.rootMist.rules; results1 = []; for (j = 0, len1 = ref.length; j < len1; j++) { rule = ref[j]; results1.push(rule.targets = {}); } return results1; }; /* * Generates templates for dependencies and outputs */ MistResolver.prototype.generateTemplates = function() { var j, len1, mktm, ref, results1, rule; mktm = (function(_this) { return function(i) { return _this.makeTemplate(i); }; })(this); ref = this.rootMist.rules; results1 = []; for (j = 0, len1 = ref.length; j < len1; j++) { rule = ref[j]; results1.push(rule.templates = { dependencies: rule.src.dependencies.map(mktm), orderDependencies: rule.src.orderDependencies.map(mktm), outputs: rule.src.outputs.map(mktm), auxOutputs: rule.src.auxOutputs.map(mktm) }); } return results1; }; /* * Transforms a source input into a template function * * input: * The input pair generated from the parser * rule: * The rule for this input */ MistResolver.prototype.makeTemplate = function(input, rule) { switch (input.type) { case 'glob': return (function(_this) { return function(path, group) { if (group != null) { []; } path = MistResolver.delimitPath(path, input.value); return Globber.performGlob(path, _this.rootDir); }; })(this); case 'group': return this.groupRefs[input.value] = this.groupRefs[input.value] || []; case 'simple': return function(path, group) { if (group != null) { []; } return MistResolver.delimitPath(path, input.value); }; default: throw "unknown template type: " + input.type; } }; /* * Iterates all inputs and generates target outputs, * supplying groups with targets as well */ MistResolver.prototype.generateTargets = function() { var groupSubs, input, j, l, len1, len2, len3, n, ref, ref1, ref2, result, results, results1, rule; groupSubs = {}; ref = this.rootMist.rules; for (j = 0, len1 = ref.length; j < len1; j++) { rule = ref[j]; ref1 = rule.src.inputs; for (l = 0, len2 = ref1.length; l < len2; l++) { input = ref1[l]; if (input.type === 'group') { (groupSubs[input.value] = groupSubs[input.value] || []).push(rule); } } } ref2 = this.rootMist.rules; results1 = []; for (n = 0, len3 = ref2.length; n < len3; n++) { rule = ref2[n]; results1.push((function() { var len4, o, ref3, results2; ref3 = rule.src.inputs; results2 = []; for (o = 0, len4 = ref3.length; o < len4; o++) { input = ref3[o]; switch (input.type) { case 'glob': results = Globber.performGlob(input.value, this.rootDir); results2.push((function() { var len5, q, results3; results3 = []; for (q = 0, len5 = results.length; q < len5; q++) { result = results[q]; results3.push(this.processInput(rule, result, null, groupSubs)); } return results3; }).call(this)); break; case 'group': break; default: throw "unknown input type: " + input.type; } } return results2; }).call(this)); } return results1; }; /* * Gives a single input to a rule for processing * * rule: * The rule for which to create a target based on the input * input: * The input for which to create a target * group: * A group, if any, that triggered the input * groupSubs: * A dictionary of group=>rules that are subscribed to receive * target outputs as inputs to process */ MistResolver.prototype.processInput = function(rule, input, group, groupSubs) { var a, j, k, l, len1, len2, len3, n, output, processor, ref, ref1, ref2, ref3; if (groupSubs == null) { groupSubs = {}; } if (input in rule.targets) { return; } processor = function(fn) { if (fn instanceof Function) { return fn(input, group); } else { return fn; } }; rule.targets[input] = { dependencies: rule.templates.dependencies.map(processor), orderDependencies: rule.templates.orderDependencies.map(processor), outputs: rule.templates.outputs.map(processor), auxOutputs: rule.templates.auxOutputs.map(processor) }; ref = rule.targets[input]; for (k in ref) { a = ref[k]; rule.targets[input][k] = a.flatten(); } ref1 = rule.src.groups; for (j = 0, len1 = ref1.length; j < len1; j++) { group = ref1[j]; ref2 = rule.targets[input].outputs; for (l = 0, len2 = ref2.length; l < len2; l++) { output = ref2[l]; (this.groupRefs[group] = this.groupRefs[group] || []).push(output); if (group in groupSubs) { ref3 = groupSubs[group]; for (n = 0, len3 = ref3.length; n < len3; n++) { rule = ref3[n]; this.processInput(rule, output, group, groupSubs); } } } } return null; }; /* * Compiles the resolved tree into a raw target list */ MistResolver.prototype.compile = function() { var input, inputs, j, k, len1, outputs, ref, ref1, result, rule, target, v; result = { targets: [], commands: {} }; ref = this.rootMist.rules; for (j = 0, len1 = ref.length; j < len1; j++) { rule = ref[j]; result.commands[rule.command.hash] = { command: rule.command.command }; if (rule.src.foreach) { ref1 = rule.targets; for (input in ref1) { target = ref1[input]; outputs = target.outputs.compile(); inputs = [input]; result.targets.push({ command: { name: rule.command.hash, vars: MistResolver.compileVars(inputs, outputs) }, inputs: inputs, dependencies: target.dependencies.compile(), orderDependencies: target.orderDependencies.compile(), outputs: outputs, auxOutputs: target.auxOutputs.compile() }); } } else { inputs = ((function() { var results1; results1 = []; for (k in rule.targets) { results1.push(k); } return results1; })()).compile(); outputs = ((function() { var ref2, results1; ref2 = rule.targets; results1 = []; for (k in ref2) { v = ref2[k]; results1.push(v.outputs); } return results1; })()).compile(); result.targets.push({ command: { name: rule.command.hash, vars: MistResolver.compileVars(inputs, outputs) }, inputs: inputs, dependencies: ((function() { var ref2, results1; ref2 = rule.targets; results1 = []; for (k in ref2) { v = ref2[k]; results1.push(v.dependencies); } return results1; })()).compile(), orderDependencies: ((function() { var ref2, results1; ref2 = rule.targets; results1 = []; for (k in ref2) { v = ref2[k]; results1.push(v.orderDependencies); } return results1; })()).compile(), outputs: outputs, auxOutputs: ((function() { var ref2, results1; ref2 = rule.targets; results1 = []; for (k in ref2) { v = ref2[k]; results1.push(v.auxOutputs); } return results1; })()).compile() }); } } return result; }; return MistResolver; })(); /* * Make sure to always include `$1` in the replacement */ MistResolver.delimiterPattern = /%(-?\d+-?(?:,-?\d+-?)*(?=d))?([%fFbBoOd])/g; /* * Returns whether or not a string has filename delimiters present * * str: * The string to check */ MistResolver.hasDelimiters = function(str) { return !!(str.match(MistResolver.delimiterPattern)); }; /* * Delimits a template given a pathname * * pathname: * The pathname to use when expanding the templates * template: * A delimited template */ MistResolver.delimitPath = function(pathname, template) { var dict; dict = MistResolver.generateDict(pathname); return template.replace(MistResolver.delimiterPattern, function(m, p, c) { c = (p || '') + c; if (c in dict) { return dict[c]; } else { throw "unknown file delimiter: " + c; } }); }; /* * Generates a delimiter dictionary for a given pathname. * * Implemented with memoization for slightly better performance. * * pathname; * The pathname for which to build up a dictionary */ MistResolver.generateDict = function(pathname) { var dict, i, ii, j, leaf, leafs, len, len1, ni, pathJoinArray; dict = {}; if (pathname in this) { dict = this[pathname]; } else { dict['%'] = '%'; dict['x'] = path.extname(pathname); dict['b'] = path.basename(pathname); dict['X'] = dict['b'].replace(/.+?(\..+)$/, '$1'); dict['B'] = path.basename(dict['b'], dict['x']); dict['f'] = pathname; dict['F'] = path.basename(dict['f'], dict['x']); dict['o'] = '%o'; dict['O'] = '%O'; leafs = path.dirname(pathname).split(path.sep); len = leafs.length; pathJoinArray = function(arr) { return path.join.apply(path, arr); }; for (i = j = 0, len1 = leafs.length; j < len1; i = ++j) { leaf = leafs[i]; ii = i + 1; ni = len - ii; dict[ii + "d"] = leaf; dict[ii + "-d"] = pathJoinArray(leafs.slice(i)); dict["-" + ii + "d"] = leafs[ni]; dict["-" + ii + "-d"] = pathJoinArray(leafs.slice(ni)); } } return dict; }; MistResolver.generateDict = MistResolver.generateDict.bind({}); /* * Delimits a command * * command: * The command to delimit */ MistResolver.delimitCommand = function(command) { return command.replace(MistResolver.delimiterPattern, function(m, c, d) { if (d === '%') { '%'; } c = (c || '').replace('-', '_'); return "${D_" + c + d + "}"; }); }; MistResolver.compileVars = function(inputs, outputs) { var input, j, k, len1, outputDirs, ref, result, v; result = {}; outputDirs = outputs.map(path.dirname); ref = inputs.map(MistResolver.generateDict); for (j = 0, len1 = ref.length; j < len1; j++) { input = ref[j]; for (k in input) { v = input[k]; if (k === '%') { continue; } if (k === 'o') { v = outputs; } if (k === 'O') { v = outputDirs; } k = k.replace('-', '_'); k = "D_" + k; if (!(k in result)) { result[k] = []; } result[k] = result[k].concat(v); } } for (k in result) { v = result[k]; result[k] = v.unique().linearize(); } return result; }; //# sourceMappingURL=mist-resolver.js.map