You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.6 KiB
146 lines
3.6 KiB
const parseSax = require('../../utils/parse-sax');
|
|
const XmlStream = require('../../utils/xml-stream');
|
|
|
|
/* 'virtual' methods used as a form of documentation */
|
|
/* eslint-disable class-methods-use-this */
|
|
|
|
// Base class for Xforms
|
|
class BaseXform {
|
|
// constructor(/* model, name */) {}
|
|
|
|
// ============================================================
|
|
// Virtual Interface
|
|
prepare(/* model, options */) {
|
|
// optional preparation (mutation) of model so it is ready for write
|
|
}
|
|
|
|
render(/* xmlStream, model */) {
|
|
// convert model to xml
|
|
}
|
|
|
|
parseOpen(node) {
|
|
// XML node opened
|
|
}
|
|
|
|
parseText(text) {
|
|
// chunk of text encountered for current node
|
|
}
|
|
|
|
parseClose(name) {
|
|
// XML node closed
|
|
}
|
|
|
|
reconcile(model, options) {
|
|
// optional post-parse step (opposite to prepare)
|
|
}
|
|
|
|
// ============================================================
|
|
reset() {
|
|
// to make sure parses don't bleed to next iteration
|
|
this.model = null;
|
|
|
|
// if we have a map - reset them too
|
|
if (this.map) {
|
|
Object.values(this.map).forEach(xform => {
|
|
if (xform instanceof BaseXform) {
|
|
xform.reset();
|
|
} else if (xform.xform) {
|
|
xform.xform.reset();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
mergeModel(obj) {
|
|
// set obj's props to this.model
|
|
this.model = Object.assign(this.model || {}, obj);
|
|
}
|
|
|
|
async parse(saxParser) {
|
|
for await (const events of saxParser) {
|
|
for (const {eventType, value} of events) {
|
|
if (eventType === 'opentag') {
|
|
this.parseOpen(value);
|
|
} else if (eventType === 'text') {
|
|
this.parseText(value);
|
|
} else if (eventType === 'closetag') {
|
|
if (!this.parseClose(value.name)) {
|
|
return this.model;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this.model;
|
|
}
|
|
|
|
async parseStream(stream) {
|
|
return this.parse(parseSax(stream));
|
|
}
|
|
|
|
get xml() {
|
|
// convenience function to get the xml of this.model
|
|
// useful for manager types that are built during the prepare phase
|
|
return this.toXml(this.model);
|
|
}
|
|
|
|
toXml(model) {
|
|
const xmlStream = new XmlStream();
|
|
this.render(xmlStream, model);
|
|
return xmlStream.xml;
|
|
}
|
|
|
|
// ============================================================
|
|
// Useful Utilities
|
|
static toAttribute(value, dflt, always = false) {
|
|
if (value === undefined) {
|
|
if (always) {
|
|
return dflt;
|
|
}
|
|
} else if (always || value !== dflt) {
|
|
return value.toString();
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
static toStringAttribute(value, dflt, always = false) {
|
|
return BaseXform.toAttribute(value, dflt, always);
|
|
}
|
|
|
|
static toStringValue(attr, dflt) {
|
|
return attr === undefined ? dflt : attr;
|
|
}
|
|
|
|
static toBoolAttribute(value, dflt, always = false) {
|
|
if (value === undefined) {
|
|
if (always) {
|
|
return dflt;
|
|
}
|
|
} else if (always || value !== dflt) {
|
|
return value ? '1' : '0';
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
static toBoolValue(attr, dflt) {
|
|
return attr === undefined ? dflt : attr === '1';
|
|
}
|
|
|
|
static toIntAttribute(value, dflt, always = false) {
|
|
return BaseXform.toAttribute(value, dflt, always);
|
|
}
|
|
|
|
static toIntValue(attr, dflt) {
|
|
return attr === undefined ? dflt : parseInt(attr, 10);
|
|
}
|
|
|
|
static toFloatAttribute(value, dflt, always = false) {
|
|
return BaseXform.toAttribute(value, dflt, always);
|
|
}
|
|
|
|
static toFloatValue(attr, dflt) {
|
|
return attr === undefined ? dflt : parseFloat(attr);
|
|
}
|
|
}
|
|
|
|
module.exports = BaseXform;
|