Geschäftsregeln als Text mit NEWMACRO()
NEWMACRO(text, [nocompile], [isasync]) macht aus ein paar Zeilen einer kleinen Sprache eine Funktion function(model, helpers). Es ist für Regeln gedacht, die sich häufiger ändern als der Code: ein Rabatt, ein Preis, eine Berechtigungsprüfung, eine Validierung, die jemand ohne JavaScript-Kenntnisse in einer Datei oder einer Datenbank pflegt.
Die Sprache, wie sie geprüft wurde:
IF condition,ELSE IF condition,ELSEundFI(das Ende der Bedingung) funktionieren wie in einer textbasierten Regel. Bedingungen verwenden>,<,>=,<=,=undAND/OR.RETURN valuebeendet das Makro mit einem Wert.YESundNO(auchTRUE,FALSE,OK) sind Booleans, Text in Anführungszeichen ist Text und Zahlen sind Zahlen.- Ein Wort ist eine Eigenschaft des Modells, in Kleinbuchstaben geschrieben:
ageliestmodel.age, undtotal = price * qtyschreibtmodel.total. NAME(arguments)ruft einen Helper auf, die Funktion mit diesem Namen (in Kleinbuchstaben) im übergebenen Objekthelpers; darin istthisdas Modell. Mitisasyncauftrueist das Makro eine async-Funktion und wartet auf die Helper.#nameist eine temporäre Variable des Laufs:#temp = num + 1undRETURN #temp.- Verwende Namen aus mehreren Buchstaben: Eine Eigenschaft oder Variable aus einem Buchstaben wurde bei den Prüfungen nicht erkannt.
NEWMACRO() kompiliert den Text mit new Function, ein Makro ist also Code: Kompiliere nur Text, den du selbst geschrieben hast oder den eine vertrauenswürdige Person pflegt, niemals Text, den ein Besucher gesendet hat. Mit nocompile auf true gibt es statt der Funktion das erzeugte JavaScript zurück, was nützlich ist, um zu sehen, was eine Regel tut.
const helpers = {
percent: function(value, rate) {
return value * rate / 100;
}
};
const age = NEWMACRO("IF age >= 18\n\tRETURN 'adult'\nELSE\n\tRETURN 'minor'\nFI");
const level = NEWMACRO("IF points > 100\n\tRETURN 'gold'\nELSE IF points > 50\n\tRETURN 'silver'\nELSE\n\tRETURN 'bronze'\nFI");
const access = NEWMACRO("IF active AND score >= 5\n\tRETURN yes\nFI\nRETURN no");
const total = NEWMACRO("total = price * qty\nIF qty >= 10\n\ttotal = total - PERCENT(total, 10)\nFI\nRETURN total");
const temporary = NEWMACRO("#next = count + 1\nRETURN #next");
const slow = NEWMACRO("RETURN LOOKUP(code)", false, true);
exports.install = function() {
ROUTE('POST /rules/', rules);
ROUTE('GET /source/', source);
};
async function rules($) {
const model = $.body;
$.json({
age: age(model, helpers),
level: level(model, helpers),
access: access(model, helpers),
total: total(model, helpers),
model_total: model.total,
temporary: temporary(model, helpers),
slow: await slow(model, { lookup: async code => 'found ' + code })
});
}
function source($) {
$.plain(NEWMACRO("IF points > 100\n\tRETURN 'gold'\nFI", true));
}