speech-rule-engine
Version:
A standalone speech rule engine for XML structures, based on the original engine from ChromeVox.
124 lines (123 loc) • 3.53 kB
JavaScript
import * as SemanticAttr from './semantic_attr.js';
import { reduce } from './semantic_ordering.js';
function key(symbol, font) {
return symbol.match(/^.+:.+$/) || !font ? symbol : symbol + ':' + font;
}
export class SemanticDefault extends Map {
set(symbol, meaning) {
super.set(key(symbol, meaning.font), meaning);
return this;
}
setNode(node) {
this.set(node.textContent, node.meaning());
}
get(symbol, font = null) {
return super.get(key(symbol, font));
}
getNode(node) {
return this.get(node.textContent, node.font);
}
}
class SemanticCollator extends Map {
add(symbol, entry) {
const list = this.get(symbol);
if (list) {
list.push(entry);
}
else {
super.set(symbol, [entry]);
}
}
get(symbol, font = null) {
return super.get(key(symbol, font));
}
getNode(node) {
return this.get(node.textContent, node.font);
}
minimize() {
for (const [key, entry] of this) {
if (entry.length === 1) {
this.delete(key);
}
}
}
isMultiValued() {
for (const value of this.values()) {
if (value.length > 1) {
return true;
}
}
return false;
}
}
export class SemanticNodeCollator extends SemanticCollator {
add(symbol, entry) {
super.add(key(symbol, entry.font), entry);
}
addNode(node) {
this.add(node.textContent, node);
}
toString() {
const outer = [];
for (const [key, nodes] of this) {
const length = Array(key.length + 3).join(' ');
const inner = nodes.map((node) => node.toString()).join('\n' + length);
outer.push(key + ': ' + inner);
}
return outer.join('\n');
}
collateMeaning() {
const collator = new SemanticMeaningCollator();
for (const [key, val] of this) {
collator.set(key, val.map((node) => node.meaning()));
}
return collator;
}
}
export class SemanticMeaningCollator extends SemanticCollator {
add(symbol, entry) {
const list = this.get(symbol, entry.font);
if (!list ||
!list.find(function (x) {
return SemanticAttr.equal(x, entry);
})) {
super.add(key(symbol, entry.font), entry);
}
}
addNode(node) {
this.add(node.textContent, node.meaning());
}
toString() {
const outer = [];
for (const [key, nodes] of this) {
const length = Array(key.length + 3).join(' ');
const inner = nodes
.map((node) => `{type: ${node.type}, role: ${node.role}, font: ${node.font}}`)
.join('\n' + length);
outer.push(key + ': ' + inner);
}
return outer.join('\n');
}
reduce() {
for (const [key, val] of this) {
if (val.length !== 1) {
this.set(key, reduce(val));
}
}
}
default() {
const def = new SemanticDefault();
for (const [key, val] of this) {
if (val.length === 1) {
def.set(key, val[0]);
}
}
return def;
}
newDefault() {
const oldDefault = this.default();
this.reduce();
const newDefault = this.default();
return oldDefault.size !== newDefault.size ? newDefault : null;
}
}