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.
218 lines • 7.32 kB
JavaScript
;
/**
* This module contains utilities for reading salve's internal schema format.
*
* @author Louis-Dominique Dubeau
* @license MPL 2.0
* @copyright Mangalam Research Center for Buddhist Languages
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.readTreeFromJSON = readTreeFromJSON;
const tools_1 = require("../tools");
const common_1 = require("./common");
class OldFormatError extends Error {
constructor() {
super("your schema file must be recreated with a newer " +
"version of salve-convert");
(0, tools_1.fixPrototype)(this, OldFormatError);
}
}
/**
* A class for walking the JSON object representing a schema.
*/
class V2JSONWalker {
/**
*
* @param options The options object from the file that contains the
* schema.
*/
constructor(options) {
this.options = options;
// tslint:disable-next-line:no-bitwise
this.addPath = (this.options & common_1.OPTION_NO_PATHS) !== 0;
}
/**
* Walks a V2 representation of a JavaScript object.
*
* @param array The array representing the object.
*
* @throws {Error} If the object is malformed.
*
* @returns The return value of [[V2JSONWalker._processObject]].
*/
walkObject(array) {
const kind = array[0];
const ctor = common_1.codeToConstructor[kind];
if (ctor === undefined) {
if (array.length < 1) {
throw new Error("array too small to contain object");
}
throw new Error(`undefined type: ${kind}`);
}
if (ctor === Array) {
throw new Error("trying to build array with walkObject");
}
// This can happen for Empty, Text, notAllowed when the JSON was generated
// without path information.
if (array.length === 1) {
return this._processObject(kind, ctor, [""]);
}
const args = array.slice(1);
this._transformArray(args);
return this._processObject(kind, ctor, this.addPath ? ["", ...args] :
args);
}
/**
* Processes an object. Derived classes will want to override this method to
* perform their work.
*
* @param kind The object "kind". A numeric code.
*
* @param ctor The object's constructor.
*
* @param args The arguments that should be passed to the constructor.
*
* @returns If the ``V2JSONWalker`` instance is meant to convert the JSON
* data, then this method should return an Object. If the ``V2JSONWalker``
* instance is meant to check the JSON data, then it should return
* ``undefined``.
*/
_processObject(kind, ctor, args) {
return undefined; // Do nothing
}
_transformArray(arr) {
const limit = arr.length;
for (let elIx = 0; elIx < limit; elIx++) {
let el = arr[elIx];
if (el instanceof Array) {
if (el[0] !== 0) {
arr[elIx] = this.walkObject(el);
}
else {
arr[elIx] = el = el.slice(1);
this._transformArray(el);
}
}
}
}
}
function namedOnePatternFilter(args) {
// Same thing as for OneOrMore, but for these elements the array of patterns
// is at index 2 rather than index 1 because index 1 contains a name.
if (args[2].length !== 1) {
throw new Error("PatternOnePattern with an array of patterns that " +
"contains other than 1 pattern");
}
return [args[0], args[1], args[2][0]];
}
function twoPatternFilter(args) {
if (args[1].length !== 2) {
throw new Error("PatternTwoPatterns with an array of patterns that " +
"contains other than 2 pattern");
}
return [args[0], args[1][0], args[1][1]];
}
const kindToArgFilter = [
undefined, // Array
undefined, // Empty,
// Data
(args) => {
if (args.length >= 4) {
// Parameters are represented as an array of strings in the file.
// Transform this array of strings into an array of objects.
const params = args[3];
if (params.length % 2 !== 0) {
throw new Error("parameter array length not a multiple of 2");
}
// tslint:disable-next-line: prefer-array-literal
const newParams = new Array(params.length / 2);
const limit = params.length;
for (let i = 0; i < limit; i += 2) {
newParams[i / 2] = { name: params[i], value: params[i + 1] };
}
args[3] = newParams;
}
return args;
},
undefined, // List,
undefined, // Param,
undefined, // Value,
undefined, // NotAllowed,
undefined, // Text,
undefined, // Ref,
// OneOrMore
(args) => {
//
// In the file we have two arguments: the XML path, an array of length 1
// that contains the one subpattern.
//
// Here we ditch the array and replace it with its lone subpattern.
//
if (args[1].length !== 1) {
throw new Error("OneOrMore with an array of patterns that " +
"contains other than 1 pattern");
}
return [args[0], args[1][0]];
},
twoPatternFilter, // Choice,
twoPatternFilter, // Group,
namedOnePatternFilter, // Attribute
namedOnePatternFilter, // Element,
namedOnePatternFilter, // Define,
undefined, // Grammar,
undefined, // EName,
twoPatternFilter, // Interleave,
//
// The name pattern filters all drop the path information.
//
// Name,
(args) => args.slice(1),
// NameChoice,
(args) => {
if (args[1].length !== 2) {
throw new Error("NameChoice with an array of patterns that " +
"contains other than 2 pattern");
}
return args[1];
},
// NsName,
(args) => args.slice(1),
// AnyName,
(args) => args.slice(1),
];
/**
* A JSON walker that constructs a pattern tree as it walks the JSON object.
*
* @private
*/
class V2Constructor extends V2JSONWalker {
_processObject(kind, ctor, args) {
const filter = kindToArgFilter[kind];
return new ctor(...(filter === undefined ? args : filter(args)));
}
}
/**
* Constructs a tree of patterns from the data structure produced by running
* ``salve-convert`` on an RNG file.
*
* @param code The JSON representation (a string) or the deserialized JSON.
*
* @throws {Error} When the version of the data is not supported.
*
* @returns The tree.
*/
function readTreeFromJSON(code) {
const parsed = (typeof code === "string" ? JSON.parse(code) : code);
if (typeof parsed === "object" && parsed.v === undefined) {
throw new OldFormatError(); // version 0
}
const { v: version, o: options, d: data } = parsed;
if (version === 3) {
return new V2Constructor(options).walkObject(data);
}
throw new Error(`unknown version: ${version}`);
}
// LocalWords: deserialized PatternTwoPatterns PatternOnePattern OneOrMore js
// LocalWords: codeToConstructor nameToConstructor RNG subpattern JSON xsl
// LocalWords: rng MPL
//# sourceMappingURL=read.js.map