tracery-es8
Version:
A version of v21/tracery, but classbased and modularized.
102 lines (83 loc) • 2.8 kB
JavaScript
module.exports = class Grammar {
constructor(raw) {
this.modifiers = {};
this.loadFromRawObj(raw);
this.errors = [];
}
clearState() {
const keys = Object.keys(this.symbols);
for (let i = 0; i < keys.length; i++) {
this.symbols[keys[i]].clearState();
}
}
addModifiers(mods) {
for (const key of Object.keys(mods)) this.modifiers[key] = mods[key];
}
loadFromRawObj(raw) {
this.raw = raw;
this.symbols = {};
this.subgrammars = [];
if (this.raw) {
// Add all rules to the grammar
for (const key in this.raw) {
if (this.raw.hasOwnProperty(key)) {
this.symbols[key] = new Symbol(this, key, this.raw[key]);
}
}
}
}
createRoot(rule) {
const root = new TraceryNode(this, 0, {
type: -1,
raw: rule
});
return root;
}
expand(rule, allowEscapeChars) {
const root = this.createRoot(rule);
root.expand();
if (!allowEscapeChars) root.clearEscapeChars();
return root;
}
flatten(rule, allowEscapeChars) {
return this.expand(rule, allowEscapeChars).finishedText;
}
toJSON() {
const keys = Object.keys(this.symbols);
const symbolJSON = [];
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
symbolJSON.push(` "${key}" : ${this.symbols[key].rulesToJSON()}`);
}
return `{\n${symbolJSON.join(',\n')}\n}`;
}
pushRules(key, rawRules, sourceAction) {
if (this.symbols[key] === undefined) {
this.symbols[key] = new Symbol(this, key, rawRules);
if (sourceAction)
this.symbols[key].isDynamic = true;
} else {
this.symbols[key].pushRules(rawRules);
}
}
popRules(key) {
if (!this.symbols[key]) this.errors.push(`Can't pop: no symbol for key ${key}`);
this.symbols[key].popRules();
}
selectRule(key, node, errors) {
if (this.symbols[key]) {
const rule = this.symbols[key].selectRule(node, errors);
return rule;
}
// Failover to alternative subgrammars
for (let i = 0; i < this.subgrammars.length; i++) {
if (this.subgrammars[i].symbols[key])
return this.subgrammars[i].symbols[key].selectRule();
}
// No symbol?
errors.push(`No symbol for '${key}'`);
return `((${key}))`;
}
};
const TraceryNode = require('./TraceryNode');
const Symbol = require('./Symbol');