projen
Version:
CDK for software projects
240 lines • 11.9 kB
JavaScript
;
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
var XMLStringLexer_1 = require("./XMLStringLexer");
var interfaces_1 = require("./interfaces");
var infra_1 = require("@oozcitak/infra");
var algorithm_1 = require("../algorithm");
var LocalNameSet_1 = require("../serializer/LocalNameSet");
/**
* Represents a parser for XML content.
*
* See: https://html.spec.whatwg.org/#xml-parser
*/
var XMLParserImpl = /** @class */ (function () {
function XMLParserImpl() {
}
/**
* Parses XML content.
*
* @param source - a string containing XML content
*/
XMLParserImpl.prototype.parse = function (source) {
var e_1, _a, e_2, _b;
var lexer = new XMLStringLexer_1.XMLStringLexer(source, { skipWhitespaceOnlyText: true });
var doc = algorithm_1.create_document();
var context = doc;
var token = lexer.nextToken();
while (token.type !== interfaces_1.TokenType.EOF) {
switch (token.type) {
case interfaces_1.TokenType.Declaration:
var declaration = token;
if (declaration.version !== "1.0") {
throw new Error("Invalid xml version: " + declaration.version);
}
break;
case interfaces_1.TokenType.DocType:
var doctype = token;
if (!algorithm_1.xml_isPubidChar(doctype.pubId)) {
throw new Error("DocType public identifier does not match PubidChar construct.");
}
if (!algorithm_1.xml_isLegalChar(doctype.sysId) ||
(doctype.sysId.indexOf('"') !== -1 && doctype.sysId.indexOf("'") !== -1)) {
throw new Error("DocType system identifier contains invalid characters.");
}
context.appendChild(doc.implementation.createDocumentType(doctype.name, doctype.pubId, doctype.sysId));
break;
case interfaces_1.TokenType.CDATA:
var cdata = token;
if (!algorithm_1.xml_isLegalChar(cdata.data) ||
cdata.data.indexOf("]]>") !== -1) {
throw new Error("CDATA contains invalid characters.");
}
context.appendChild(doc.createCDATASection(cdata.data));
break;
case interfaces_1.TokenType.Comment:
var comment = token;
if (!algorithm_1.xml_isLegalChar(comment.data) ||
comment.data.indexOf("--") !== -1 || comment.data.endsWith("-")) {
throw new Error("Comment data contains invalid characters.");
}
context.appendChild(doc.createComment(comment.data));
break;
case interfaces_1.TokenType.PI:
var pi = token;
if (pi.target.indexOf(":") !== -1 || (/^xml$/i).test(pi.target)) {
throw new Error("Processing instruction target contains invalid characters.");
}
if (!algorithm_1.xml_isLegalChar(pi.data) || pi.data.indexOf("?>") !== -1) {
throw new Error("Processing instruction data contains invalid characters.");
}
context.appendChild(doc.createProcessingInstruction(pi.target, pi.data));
break;
case interfaces_1.TokenType.Text:
var text = token;
if (!algorithm_1.xml_isLegalChar(text.data)) {
throw new Error("Text data contains invalid characters.");
}
context.appendChild(doc.createTextNode(this._decodeText(text.data)));
break;
case interfaces_1.TokenType.Element:
var element = token;
// inherit namespace from parent
var _c = __read(algorithm_1.namespace_extractQName(element.name), 2), prefix = _c[0], localName = _c[1];
if (localName.indexOf(":") !== -1 || !algorithm_1.xml_isName(localName)) {
throw new Error("Node local name contains invalid characters.");
}
if (prefix === "xmlns") {
throw new Error("An element cannot have the 'xmlns' prefix.");
}
var namespace = context.lookupNamespaceURI(prefix);
// override namespace if there is a namespace declaration
// attribute
// also lookup namespace declaration attributes
var nsDeclarations = {};
try {
for (var _d = (e_1 = void 0, __values(element.attributes)), _e = _d.next(); !_e.done; _e = _d.next()) {
var _f = __read(_e.value, 2), attName = _f[0], attValue = _f[1];
if (attName === "xmlns") {
namespace = attValue;
}
else {
var _g = __read(algorithm_1.namespace_extractQName(attName), 2), attPrefix = _g[0], attLocalName = _g[1];
if (attPrefix === "xmlns") {
if (attLocalName === prefix) {
namespace = attValue;
}
nsDeclarations[attLocalName] = attValue;
}
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
// create the DOM element node
var elementNode = (namespace !== null ?
doc.createElementNS(namespace, element.name) :
doc.createElement(element.name));
context.appendChild(elementNode);
// assign attributes
var localNameSet = new LocalNameSet_1.LocalNameSet();
try {
for (var _h = (e_2 = void 0, __values(element.attributes)), _j = _h.next(); !_j.done; _j = _h.next()) {
var _k = __read(_j.value, 2), attName = _k[0], attValue = _k[1];
var _l = __read(algorithm_1.namespace_extractQName(attName), 2), attPrefix = _l[0], attLocalName = _l[1];
var attNamespace = null;
if (attPrefix === "xmlns" || (attPrefix === null && attLocalName === "xmlns")) {
// namespace declaration attribute
attNamespace = infra_1.namespace.XMLNS;
}
else {
attNamespace = elementNode.lookupNamespaceURI(attPrefix);
if (attNamespace !== null && elementNode.isDefaultNamespace(attNamespace)) {
attNamespace = null;
}
else if (attNamespace === null && attPrefix !== null) {
attNamespace = nsDeclarations[attPrefix] || null;
}
}
if (localNameSet.has(attNamespace, attLocalName)) {
throw new Error("Element contains duplicate attributes.");
}
localNameSet.set(attNamespace, attLocalName);
if (attNamespace === infra_1.namespace.XMLNS) {
if (attValue === infra_1.namespace.XMLNS) {
throw new Error("XMLNS namespace is reserved.");
}
}
if (attLocalName.indexOf(":") !== -1 || !algorithm_1.xml_isName(attLocalName)) {
throw new Error("Attribute local name contains invalid characters.");
}
if (attPrefix === "xmlns" && attValue === "") {
throw new Error("Empty XML namespace is not allowed.");
}
if (attNamespace !== null)
elementNode.setAttributeNS(attNamespace, attName, this._decodeAttributeValue(attValue));
else
elementNode.setAttribute(attName, this._decodeAttributeValue(attValue));
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
}
finally { if (e_2) throw e_2.error; }
}
if (!element.selfClosing) {
context = elementNode;
}
break;
case interfaces_1.TokenType.ClosingTag:
var closingTag = token;
if (closingTag.name !== context.nodeName) {
throw new Error('Closing tag name does not match opening tag name.');
}
/* istanbul ignore else */
if (context._parent) {
context = context._parent;
}
break;
}
token = lexer.nextToken();
}
return doc;
};
/**
* Decodes serialized text.
*
* @param text - text value to serialize
*/
XMLParserImpl.prototype._decodeText = function (text) {
return text == null ? text : text.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
};
/**
* Decodes serialized attribute value.
*
* @param text - attribute value to serialize
*/
XMLParserImpl.prototype._decodeAttributeValue = function (text) {
return text == null ? text : text.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&');
};
return XMLParserImpl;
}());
exports.XMLParserImpl = XMLParserImpl;
//# sourceMappingURL=XMLParserImpl.js.map