ForgeTotal.js 5
nl

Total.js 5

Bedrijfsregels als tekst met NEWMACRO()

Total.js 5 · total5@0.0.19 macrosrulesscripting Uitgevoerd met Total.js 5

NEWMACRO(text, [nocompile], [isasync]) maakt van enkele regels van een kleine taal een functie function(model, helpers). Het is bedoeld voor regels die vaker veranderen dan de code: een korting, een prijs, een rechtencontrole, een validatie die iemand die geen JavaScript schrijft in een bestand of database onderhoudt.

De taal, zoals die is gecontroleerd:

  • IF condition, ELSE IF condition, ELSE en FI (het einde van de voorwaarde) werken zoals in een tekstgebaseerde regel. Voorwaarden gebruiken >, <, >=, <=, = en AND / OR.
  • RETURN value beëindigt de macro met een waarde. YES en NO (ook TRUE, FALSE, OK) zijn booleans, tekst tussen aanhalingstekens is tekst en getallen zijn getallen.
  • Een woord is een eigenschap van het model, in kleine letters geschreven: age leest model.age, en total = price * qty schrijft model.total.
  • NAME(arguments) roept een helper aan, de functie met die naam (in kleine letters) in het helpers-object dat je meegeeft; daarin is this het model. Met isasync op true is de macro een async-functie en wacht hij op de helpers.
  • #name is een tijdelijke variabele van de run: #temp = num + 1 en RETURN #temp.
  • Gebruik namen van meerdere letters: een eigenschap of variabele van één letter werd bij de controles niet herkend.

NEWMACRO() compileert de tekst met new Function, dus een macro is code: compileer alleen tekst die je zelf hebt geschreven of die een vertrouwde persoon onderhoudt, nooit tekst die een bezoeker heeft gestuurd. Met nocompile op true geeft het in plaats van de functie het JavaScript terug dat het genereert, handig om te zien wat een regel doet.

controllers/rules.js
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));
}