makit
Version:
Make in JavaScript done right!
129 lines (128 loc) • 4.82 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Makefile = void 0;
const rule_1 = require("./rule");
const make_1 = require("../make");
const logger_1 = require("../utils/logger");
const prerequisites_1 = require("./prerequisites");
const rude_1 = require("./rude");
const target_1 = require("./target");
const process_1 = require("process");
const recipe_1 = require("./recipe");
const dot_reporter_1 = require("../reporters/dot-reporter");
const defaultRecipe = () => void (0);
const logger = logger_1.Logger.getOrCreate();
/**
* 给最终使用者的 makefile.js 中暴露的全局变量 makit 即为 Makefile 实例
*/
class Makefile {
constructor(root = process_1.cwd(), reporter = new dot_reporter_1.DotReporter()) {
this.disableCheckCircular = false;
this.ruleMap = new Map();
this.fileTargetRules = new Map();
this.matchingRules = [];
this.root = root;
this.reporter = reporter;
this.makeImpl = new make_1.Make({
root: this.root,
reporter: this.reporter,
matchRule: target => this.matchRule(target),
disableCheckCircular: this.disableCheckCircular
});
}
updateOrAddRule(targetDecl, prerequisitesDecl = [], recipeDecl = defaultRecipe) {
if (this.ruleMap.has(targetDecl)) {
this.updateRule(targetDecl, prerequisitesDecl, recipeDecl);
}
else {
this.addRule(targetDecl, prerequisitesDecl, recipeDecl);
}
}
addRule(targetDecl, prerequisitesDecl = [], recipeDecl = defaultRecipe) {
const target = new target_1.Target(targetDecl);
const prerequisites = new prerequisites_1.Prerequisites(prerequisitesDecl);
const recipe = new recipe_1.Recipe(recipeDecl);
const rule = new rule_1.Rule(target, prerequisites, recipe);
logger.verbose('RULE', 'adding rule', rule);
if (target.isFilePath()) {
this.fileTargetRules.set(target.decl, rule);
}
else {
this.matchingRules.push(rule);
}
this.ruleMap.set(target.decl, rule);
return rule;
}
addRude(targetDecl, prerequisitesDecl = [], recipeDecl = defaultRecipe) {
if (targetDecl instanceof RegExp)
throw new Error('rude() for RegExp not supported yet');
const rule = this.addRule(targetDecl, [prerequisitesDecl, '$0' + rude_1.rudeExtname], recipeDecl);
rule.hasDynamicDependencies = true;
this.addRule(rude_1.getDependencyFromTarget(targetDecl), rude_1.dynamicPrerequisites, rude_1.clearDynamicDependencies);
}
updateRule(targetDecl, prerequisitesDecl = [], recipeDecl = defaultRecipe) {
const rule = this.ruleMap.get(targetDecl);
if (!rule) {
throw new Error(`rule for "${targetDecl}" not found`);
}
rule.prerequisites = new prerequisites_1.Prerequisites(prerequisitesDecl);
rule.recipe = new recipe_1.Recipe(recipeDecl);
}
/**
* makit 命令入口
*
* 命令行调用 makit <target> 由本方法处理,具体的依赖递归解决由 Make 对象处理。
*/
async make(target) {
logger.resume();
if (!target) {
target = this.findFirstTargetOrThrow();
}
try {
return await this.makeImpl.make(target);
}
catch (err) {
// logger.suspend()
if (err.target) {
const chain = this.makeImpl.dependencyGraph.findPathToRoot(err.target);
const target = chain.shift();
err.message = `${err.message} while making "${target}"`;
for (const dep of chain)
err.message += `\n required by "${dep}"`;
}
throw err;
}
}
invalidate(target) {
this.makeImpl.invalidate(target);
}
dependencyGraphString() {
return this.makeImpl.dependencyGraph.toString();
}
matchRule(target) {
if (this.fileTargetRules.has(target)) {
const match = [target];
match.input = target;
match.index = 0;
return [this.fileTargetRules.get(target), match];
}
for (let i = this.matchingRules.length - 1; i >= 0; i--) {
const rule = this.matchingRules[i];
const match = rule.match(target);
if (match) {
return [rule, match];
}
}
return null;
}
findFirstTarget() {
return this.fileTargetRules.keys().next().value;
}
findFirstTargetOrThrow() {
const target = this.findFirstTarget();
if (!target)
throw new Error('target not found');
return target;
}
}
exports.Makefile = Makefile;