salve-annos
Version:
A fork with support for documentation of Salve, a Javascript library which implements a validator able to validate an XML document on the basis of a subset of RelaxNG.
102 lines • 3.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.step18 = step18;
/**
* Simplification step 18.
* @author Louis-Dominique Dubeau
* @license MPL 2.0
* @copyright 2013, 2014 Mangalam Research Center for Buddhist Languages
*/
const parser_1 = require("../parser");
// These are elements that cannot contain empty.
const skip = new Set(["name", "anyName", "nsName", "param", "empty",
"text", "value", "notAllowed", "ref"]);
function walk(el, ix) {
const { local, children } = el;
if (children.length === 0 || skip.has(local)) {
return;
}
let [first, second] = children;
walk(first, 0);
if (second !== undefined) {
walk(second, 1);
}
// The children may have changed.
([first, second] = children);
const firstEmpty = first.local === "empty";
const secondEmpty = second !== undefined && second.local === "empty";
if (!(firstEmpty || secondEmpty)) {
return;
}
switch (local) {
case "choice":
if (secondEmpty) {
if (!firstEmpty) {
// If a choice has empty in the 2nd position, the children are
// swapped.
children[0] = second;
children[1] = first;
}
else {
// A choice with two empty elements is replaced with empty.
el.parent.replaceChildAt(ix, parser_1.Element.makeElement("empty", []));
}
}
break;
case "group":
case "interleave":
el.parent.replaceChildAt(ix, firstEmpty && secondEmpty ?
// A group (or interleave) with two empty
// elements is replaced with empty.
parser_1.Element.makeElement("empty", []) :
// A group (or interleave) with only one empty
// element is replaced with the non-empty one.
(firstEmpty ? second : first));
break;
case "oneOrMore":
// A oneOrMore with an empty element is replaced with empty.
el.parent.replaceChildAt(ix, parser_1.Element.makeElement("empty", []));
break;
default:
}
}
/**
* Implements step 18 of the XSL pipeline. Namely:
*
* - All ``group``, ``interleave`` and ``choice`` elements with two ``empty``
* children are replaced with ``empty``.
*
* - All ``group`` and ``interleave`` elements with one ``empty`` child
* are transformed into their other child.
*
* - All ``choice`` elements with ``empty`` as the second child have their
* children swapped.
*
* - All ``oneOrMore`` elements with an ``empty`` child are replaced with
* ``empty``.
*
* These transformations are repeated until they no longer modify the tree. (The
* way we apply the transformations obviates the need to repeat them.)
*
* Note that none of the transformations above remove ``ref`` elements from the
* schema. So it is not necessary to check for unreferenced ``define``
* elements. (To ascertain that this is the case, you need to take into account
* the previous transformations. For instance, ``oneOrMore`` by this stage has
* only one possible child so replacing ``oneOrMore`` with ``empty`` if it has
* an ``empty`` child **cannot** remove a ``ref`` element from the tree. Similar
* reasoning applies to the other transformations.)
*
* @param tree The tree to process. It is modified in-place.
*
* @returns The new root of the tree.
*/
function step18(tree) {
// The top element is necessarily <grammar>, and it has only element children.
let ix = 0;
for (const child of tree.children) {
walk(child, ix++);
}
return tree;
}
// LocalWords: XSL oneOrMore
//# sourceMappingURL=step18.js.map