speech-rule-engine
Version:
A standalone speech rule engine for XML structures, based on the original engine from ChromeVox.
390 lines • 13.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SemanticNode = void 0;
const DomUtil = __importStar(require("../common/dom_util.js"));
const semantic_attr_js_1 = require("./semantic_attr.js");
const semantic_meaning_js_1 = require("./semantic_meaning.js");
const SemanticUtil = __importStar(require("./semantic_util.js"));
var Attribute;
(function (Attribute) {
Attribute["EMBELLISHED"] = "embellished";
Attribute["FENCEPOINTER"] = "fencepointer";
Attribute["FONT"] = "font";
Attribute["ID"] = "id";
Attribute["ANNOTATION"] = "annotation";
Attribute["ROLE"] = "role";
Attribute["TYPE"] = "type";
Attribute["CHILDREN"] = "children";
Attribute["CONTENT"] = "content";
Attribute["TEXT"] = "$t";
})(Attribute || (Attribute = {}));
class SemanticNode {
static fromXml(xml) {
const id = parseInt(xml.getAttribute('id'), 10);
const node = new SemanticNode(id);
node.type = xml.tagName;
SemanticNode.setAttribute(node, xml, 'role');
SemanticNode.setAttribute(node, xml, 'font');
SemanticNode.setAttribute(node, xml, 'embellished');
SemanticNode.setAttribute(node, xml, 'fencepointer', 'fencePointer');
if (xml.getAttribute('annotation')) {
node.parseAnnotation(xml.getAttribute('annotation'));
}
SemanticUtil.addAttributes(node, xml);
SemanticNode.processChildren(node, xml);
return node;
}
static setAttribute(node, xml, attribute, opt_name) {
opt_name = opt_name || attribute;
const value = xml.getAttribute(attribute);
if (value) {
node[opt_name] = value;
}
}
static processChildren(node, xml) {
for (const child of DomUtil.toArray(xml.childNodes)) {
if (child.nodeType === DomUtil.NodeType.TEXT_NODE) {
node.textContent = child.textContent;
continue;
}
const children = DomUtil.toArray(child.childNodes).map(SemanticNode.fromXml);
children.forEach((x) => (x.parent = node));
if (DomUtil.tagName(child) === 'CONTENT') {
node.contentNodes = children;
}
else {
node.childNodes = children;
}
}
}
constructor(id) {
this.id = id;
this.mathml = [];
this.parent = null;
this.type = semantic_meaning_js_1.SemanticType.UNKNOWN;
this.role = semantic_meaning_js_1.SemanticRole.UNKNOWN;
this.font = semantic_meaning_js_1.SemanticFont.UNKNOWN;
this.embellished = null;
this.fencePointer = '';
this.childNodes = [];
this.textContent = '';
this.mathmlTree = null;
this.contentNodes = [];
this.annotation = {};
this.attributes = {};
this.nobreaking = false;
}
querySelectorAll(pred) {
let result = [];
for (let i = 0, child; (child = this.childNodes[i]); i++) {
result = result.concat(child.querySelectorAll(pred));
}
for (let i = 0, content; (content = this.contentNodes[i]); i++) {
result = result.concat(content.querySelectorAll(pred));
}
if (pred(this)) {
result.unshift(this);
}
return result;
}
xml(xml, brief) {
const xmlNodeList = function (tag, nodes) {
const xmlNodes = nodes.map(function (x) {
return x.xml(xml, brief);
});
const tagNode = xml.createElementNS('', tag);
for (let i = 0, child; (child = xmlNodes[i]); i++) {
tagNode.appendChild(child);
}
return tagNode;
};
const node = xml.createElementNS('', this.type);
if (!brief) {
this.xmlAttributes(node);
}
node.textContent = this.textContent;
if (this.contentNodes.length > 0) {
node.appendChild(xmlNodeList(Attribute.CONTENT, this.contentNodes));
}
if (this.childNodes.length > 0) {
node.appendChild(xmlNodeList(Attribute.CHILDREN, this.childNodes));
}
return node;
}
toString(brief = false) {
const xml = DomUtil.parseInput('<snode/>');
return DomUtil.serializeXml(this.xml(xml.ownerDocument, brief));
}
allAttributes() {
const attributes = [];
attributes.push([Attribute.ROLE, this.role]);
if (this.font !== semantic_meaning_js_1.SemanticFont.UNKNOWN) {
attributes.push([Attribute.FONT, this.font]);
}
if (Object.keys(this.annotation).length) {
attributes.push([Attribute.ANNOTATION, this.annotationXml()]);
}
if (this.embellished) {
attributes.push([Attribute.EMBELLISHED, this.embellished]);
}
if (this.fencePointer) {
attributes.push([Attribute.FENCEPOINTER, this.fencePointer]);
}
attributes.push([Attribute.ID, this.id.toString()]);
return attributes;
}
annotationXml() {
const result = [];
for (const [key, val] of Object.entries(this.annotation)) {
val.forEach((mean) => result.push(key + ':' + mean));
}
return result.join(';');
}
attributesXml() {
const result = [];
for (const [key, value] of Object.entries(this.attributes)) {
result.push(key + ':' + SemanticNode.escapeValue(value));
}
return result.join(';');
}
toJson() {
const json = {};
json[Attribute.TYPE] = this.type;
const attributes = this.allAttributes();
for (let i = 0, attr; (attr = attributes[i]); i++) {
json[attr[0]] = attr[1].toString();
}
if (this.textContent) {
json[Attribute.TEXT] = this.textContent;
}
if (this.childNodes.length) {
json[Attribute.CHILDREN] = this.childNodes.map(function (child) {
return child.toJson();
});
}
if (this.contentNodes.length) {
json[Attribute.CONTENT] = this.contentNodes.map(function (child) {
return child.toJson();
});
}
return json;
}
updateContent(content, text) {
const newContent = text
? content
.replace(/^[ \f\n\r\t\v\u200b]*/, '')
.replace(/[ \f\n\r\t\v\u200b]*$/, '')
: content.trim();
content = content && !newContent ? content : newContent;
if (this.textContent === content) {
return;
}
const meaning = semantic_attr_js_1.SemanticMap.Meaning.get(content.replace(/\s/g, ' '));
this.textContent = content;
this.role = meaning.role;
this.type = meaning.type;
this.font = meaning.font;
}
addMathmlNodes(mmlNodes) {
for (let i = 0, mml; (mml = mmlNodes[i]); i++) {
if (this.mathml.indexOf(mml) === -1) {
this.mathml.push(mml);
}
}
}
appendChild(child) {
this.childNodes.push(child);
this.addMathmlNodes(child.mathml);
child.parent = this;
}
replaceChild(oldNode, newNode) {
const index = this.childNodes.indexOf(oldNode);
if (index === -1) {
return;
}
oldNode.parent = null;
newNode.parent = this;
this.childNodes[index] = newNode;
const removeMathml = oldNode.mathml.filter(function (x) {
return newNode.mathml.indexOf(x) === -1;
});
const addMathml = newNode.mathml.filter(function (x) {
return oldNode.mathml.indexOf(x) === -1;
});
this.removeMathmlNodes(removeMathml);
this.addMathmlNodes(addMathml);
}
appendContentNode(node) {
if (node) {
this.contentNodes.push(node);
this.addMathmlNodes(node.mathml);
node.parent = this;
}
}
removeContentNode(node) {
if (node) {
const index = this.contentNodes.indexOf(node);
if (index !== -1) {
this.contentNodes.slice(index, 1);
}
}
}
equals(node) {
if (!node) {
return false;
}
if (this.type !== node.type ||
this.role !== node.role ||
this.textContent !== node.textContent ||
this.childNodes.length !== node.childNodes.length ||
this.contentNodes.length !== node.contentNodes.length) {
return false;
}
for (let i = 0, node1, node2; (node1 = this.childNodes[i]), (node2 = node.childNodes[i]); i++) {
if (!node1.equals(node2)) {
return false;
}
}
for (let i = 0, node1, node2; (node1 = this.contentNodes[i]), (node2 = node.contentNodes[i]); i++) {
if (!node1.equals(node2)) {
return false;
}
}
return true;
}
displayTree() {
console.info(this.displayTree_(0));
}
addAnnotation(domain, annotation) {
if (annotation) {
this.addAnnotation_(domain, annotation);
}
}
getAnnotation(domain) {
const content = this.annotation[domain];
return content ? content : [];
}
hasAnnotation(domain, annotation) {
const content = this.annotation[domain];
if (!content) {
return false;
}
return content.indexOf(annotation) !== -1;
}
parseAnnotation(stateStr) {
const annotations = stateStr.split(';');
for (let i = 0, l = annotations.length; i < l; i++) {
const annotation = annotations[i].split(':');
this.addAnnotation(annotation[0], annotation[1]);
}
}
meaning() {
return { type: this.type, role: this.role, font: this.font };
}
xmlAttributes(node) {
const attributes = this.allAttributes();
for (let i = 0, attr; (attr = attributes[i]); i++) {
node.setAttribute(attr[0], attr[1]);
}
this.addExternalAttributes(node);
}
addExternalAttributes(node) {
for (const [attr, val] of Object.entries(this.attributes)) {
node.setAttribute(attr, val);
}
}
static escapeValue(value) {
return value.replace(/;/g, '\\0003B');
}
parseAttributes(stateStr) {
if (!stateStr)
return;
const attributes = stateStr.split(';');
for (let i = 0, l = attributes.length; i < l; i++) {
const [key, ...values] = attributes[i].split(':');
if (key) {
this.attributes[key] = values.join('').replace(/\\0003B/g, ';');
}
}
}
removeMathmlNodes(mmlNodes) {
const mmlList = this.mathml;
for (let i = 0, mml; (mml = mmlNodes[i]); i++) {
const index = mmlList.indexOf(mml);
if (index !== -1) {
mmlList.splice(index, 1);
}
}
this.mathml = mmlList;
}
displayTree_(depth) {
depth++;
const depthString = Array(depth).join(' ');
let result = '';
result += '\n' + depthString + this.toString();
result += '\n' + depthString + 'MathmlTree:';
result += '\n' + depthString + this.mathmlTreeString();
result += '\n' + depthString + 'MathML:';
for (let i = 0, mml; (mml = this.mathml[i]); i++) {
result += '\n' + depthString + mml.toString();
}
result += '\n' + depthString + 'Begin Content';
this.contentNodes.forEach(function (x) {
result += x.displayTree_(depth);
});
result += '\n' + depthString + 'End Content';
result += '\n' + depthString + 'Begin Children';
this.childNodes.forEach(function (x) {
result += x.displayTree_(depth);
});
result += '\n' + depthString + 'End Children';
return result;
}
mathmlTreeString() {
return this.mathmlTree ? this.mathmlTree.toString() : 'EMPTY';
}
addAnnotation_(domain, annotation) {
const content = this.annotation[domain];
if (content && !content.includes(annotation)) {
content.push(annotation);
}
else {
this.annotation[domain] = [annotation];
}
}
}
exports.SemanticNode = SemanticNode;
//# sourceMappingURL=semantic_node.js.map