Socket
Socket
Sign inDemoInstall

saxes

Package Overview
Dependencies
1
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.1.5 to 3.1.6

10

CHANGELOG.md

@@ -0,1 +1,11 @@

<a name="3.1.6"></a>
## [3.1.6](https://github.com/lddubeau/saxes/compare/v3.1.5...v3.1.6) (2019-01-17)
### Bug Fixes
* detect unclosed tags in fragments ([5642f36](https://github.com/lddubeau/saxes/commit/5642f36))
<a name="3.1.5"></a>

@@ -2,0 +12,0 @@ ## [3.1.5](https://github.com/lddubeau/saxes/compare/v3.1.4...v3.1.5) (2019-01-08)

376

lib/saxes.js

@@ -113,38 +113,47 @@ "use strict";

function nsMappingCheck(parser, mapping) {
const { xml, xmlns } = mapping;
if (xml && xml !== XML_NAMESPACE) {
parser.fail(`xml prefix must be bound to ${XML_NAMESPACE}.`);
function nsPairCheck(parser, prefix, uri) {
switch (prefix) {
case "xml":
if (uri !== XML_NAMESPACE) {
parser.fail(`xml prefix must be bound to ${XML_NAMESPACE}.`);
}
break;
case "xmlns":
if (uri !== XMLNS_NAMESPACE) {
parser.fail(`xmlns prefix must be bound to ${XMLNS_NAMESPACE}.`);
}
break;
default:
}
if (xmlns && xmlns !== XMLNS_NAMESPACE) {
parser.fail(`xmlns prefix must be bound to ${XMLNS_NAMESPACE}.`);
}
for (const local of Object.keys(mapping)) {
const uri = mapping[local];
switch (uri) {
case XMLNS_NAMESPACE:
parser.fail(local === "" ?
`the default namespace may not be set to ${uri}.` :
`may not assign a prefix (even "xmlns") to the URI \
switch (uri) {
case XMLNS_NAMESPACE:
parser.fail(prefix === "" ?
`the default namespace may not be set to ${uri}.` :
`may not assign a prefix (even "xmlns") to the URI \
${XMLNS_NAMESPACE}.`);
break;
case XML_NAMESPACE:
switch (prefix) {
case "xml":
// Assinging the XML namespace to "xml" is fine.
break;
case XML_NAMESPACE:
switch (local) {
case "xml":
// Assinging the XML namespace to "xml" is fine.
break;
case "":
parser.fail(`the default namespace may not be set to ${uri}.`);
break;
default:
parser.fail("may not assign the xml namespace to another prefix.");
}
case "":
parser.fail(`the default namespace may not be set to ${uri}.`);
break;
default:
parser.fail("may not assign the xml namespace to another prefix.");
}
break;
default:
}
}
function nsMappingCheck(parser, mapping) {
for (const local of Object.keys(mapping)) {
nsPairCheck(parser, local, mapping[local]);
}
}
/**

@@ -316,4 +325,4 @@ * Data structure for an XML tag.

// We want these to be all true if we are dealing with a fragment.
this.reportedTextBeforeRoot = this.reportedTextAfterRoot =
this.closedRoot = this.sawRoot = this.inRoot = fragmentOpt;
this.reportedTextBeforeRoot = this.reportedTextAfterRoot = this.closedRoot =
this.sawRoot = fragmentOpt;
// An XML declaration is intially possible only when parsing whole

@@ -345,3 +354,4 @@ // documents.

this.nameCheck = isNCNameChar;
this.processAttributes = this.processAttributesNS;
this.processAttribs = this.processAttribsNS;
this.pushAttrib = this.pushAttribNS;

@@ -358,3 +368,4 @@ this.ns = Object.assign({ __proto__: null }, rootNS);

this.nameCheck = isNameChar;
this.processAttributes = this.processAttributesPlain;
this.processAttribs = this.processAttribsPlain;
this.pushAttrib = this.pushAttribPlain;
}

@@ -557,17 +568,16 @@

getCode() {
const { chunk } = this;
let { i } = this;
const { chunk, i } = this;
// Using charCodeAt and handling the surrogates ourselves is faster
// than using codePointAt.
let code = chunk.charCodeAt(i);
let skip = 1;
if (code === CR) {
switch (code) {
case CR:
// We may get undefined if we read past the end of the chunk, which is
// fine.
const next = chunk.charCodeAt(i + 1);
if (next === NL) {
if (chunk.charCodeAt(i + 1) === NL) {
// A \r\n sequence is converted to \n so we have to skip over the next
// character. We already know it has a size of 1 so ++ is fine here.
i++;
skip++;
}

@@ -579,17 +589,16 @@ // Otherwise, a \r is just converted to \n, so we don't have to skip

code = NL;
}
if (code === NL) {
/* yes, fall through */
case NL:
this.line++;
this.column = 0;
}
else {
break;
default:
this.column++;
if (code >= 0xD800 && code <= 0xDBFF) {
skip = 2;
code = 0x10000 + ((code - 0xD800) * 0x400) +
(chunk.charCodeAt(i + 1) - 0xDC00);
this.column++;
skip++;
}
this.column += skip;
if (!isChar(code)) {

@@ -600,3 +609,3 @@ this.fail("disallowed character.");

this.i = i + skip;
this.i += skip;

@@ -618,32 +627,2 @@ return code;

/**
* Capture characters into a buffer while a condition is true.
*
* @private
*
* @param {CharacterTest} test A test to perform on each character. The
* capture ends when the test returns false.
*
* @param {string} buffer The name of the buffer to save into.
*
* @return {string|undefined} The character that made the test fail, or
* ``undefined`` if we hit the end of the chunk.
*/
captureWhile(test, buffer) {
const { chunk, limit, i: start } = this;
while (this.i < limit) {
const c = this.getCode();
if (!test(c)) {
// This is faster than adding codepoints one by one.
this[buffer] += chunk.substring(start,
this.i - (c <= 0xFFFF ? 1 : 2));
return c;
}
}
// This is faster than adding codepoints one by one.
this[buffer] += chunk.substring(start);
return undefined;
}
/**
* Capture characters into a buffer until encountering one of a set of

@@ -709,3 +688,4 @@ * characters.

/**
* Capture characters that satisfy ``isNameChar`` into a buffer.
* Capture characters that satisfy ``isNameChar`` into the ``name`` field of
* this parser.
*

@@ -717,3 +697,3 @@ * @private

*/
captureName() {
captureNameChars() {
const { chunk, limit, i: start } = this;

@@ -736,2 +716,30 @@ while (this.i < limit) {

/**
* Capture characters into a buffer while ``this.nameCheck`` run on the
* character read returns true.
*
* @private
*
* @param {string} buffer The name of the buffer to save into.
*
* @return {string|undefined} The character that made the test fail, or
* ``undefined`` if we hit the end of the chunk.
*/
captureWhileNameCheck(buffer) {
const { chunk, limit, i: start } = this;
while (this.i < limit) {
const c = this.getCode();
if (!this.nameCheck(c)) {
// This is faster than adding codepoints one by one.
this[buffer] += chunk.substring(start,
this.i - (c <= 0xFFFF ? 1 : 2));
return c;
}
}
// This is faster than adding codepoints one by one.
this[buffer] += chunk.substring(start);
return undefined;
}
/**
* Skip characters while a condition is true.

@@ -802,3 +810,4 @@ *

if (!this.inRoot && (/\S/.test(this.text) || c === AMP)) {
if ((!this.sawRoot || this.closedRoot) &&
(/\S/.test(this.text) || c === AMP)) {
// We use the reportedTextBeforeRoot and reportedTextAfterRoot flags

@@ -913,3 +922,6 @@ // to avoid reporting errors for every single character that is out of

this.state = S_TEXT;
this.emitNode("ondoctype", this.doctype);
if (this.text.length !== 0) {
this.closeText();
}
this.ondoctype(this.doctype);
this.doctype = true; // just remember that we saw it.

@@ -978,3 +990,6 @@ }

this.state = S_COMMENT_ENDED;
this.emitNode("oncomment", this.comment);
if (this.text.length !== 0) {
this.closeText();
}
this.oncomment(this.comment);
this.comment = "";

@@ -1026,3 +1041,6 @@ }

case GREATER:
this.emitNode("oncdata", this.cdata);
if (this.text.length !== 0) {
this.closeText();
}
this.oncdata(this.cdata);
this.cdata = "";

@@ -1060,3 +1078,3 @@ this.state = S_TEXT;

sPIRest() {
const c = this.captureWhile(this.nameCheck, "piTarget");
const c = this.captureWhileNameCheck("piTarget");
if ((c === QUESTION || isS(c))) {

@@ -1266,3 +1284,6 @@ this.piIsXMLDecl = this.piTarget === "xml";

}
this.emitNode("onprocessinginstruction", {
if (this.text.length !== 0) {
this.closeText();
}
this.onprocessinginstruction({
target: this.piTarget,

@@ -1290,3 +1311,3 @@ body: this.piBody,

sOpenTag() {
const c = this.captureName();
const c = this.captureNameChars();
if (!c) {

@@ -1305,3 +1326,10 @@ return;

this.emitNode("onopentagstart", tag);
if (this.text.length !== 0) {
this.closeText();
}
this.onopentagstart(tag);
this.sawRoot = true;
if (!this.fragmentOpt && this.closedRoot) {
this.fail("documents may contain only one root.");
}

@@ -1327,3 +1355,3 @@ switch (c) {

if (c === GREATER) {
this.openTag(true);
this.openSelfClosingTag();
}

@@ -1358,6 +1386,25 @@ else {

/** @private */
pushAttribNS(name, value) {
const { prefix, local } = this.qname(name);
this.attribList.push({ name, prefix, local, value, uri: undefined });
if (prefix === "xmlns") {
const trimmed = value.trim();
this.tag.ns[local] = trimmed;
nsPairCheck(this, local, trimmed);
}
else if (name === "xmlns") {
const trimmed = value.trim();
this.tag.ns[""] = trimmed;
nsPairCheck(this, "", trimmed);
}
}
/** @private */
pushAttribPlain(name, value) {
this.attribList.push({ name, value });
}
/** @private */
sAttribName() {
// We don't need to check with isNameStartChar here because the first
// character of attribute is fed elsewhere, and the check is done there.
const c = this.captureName();
const c = this.captureNameChars();
if (c === EQUAL) {

@@ -1371,3 +1418,3 @@ this.state = S_ATTRIB_VALUE;

this.fail("attribute without value.");
this.attribList.push({ name: this.name, value: this.name });
this.pushAttrib(this.name, this.name);
this.name = this.text = "";

@@ -1435,3 +1482,3 @@ this.openTag();

else if (c) {
this.attribList.push({ name: this.name, value: this.text });
this.pushAttrib(this.name, this.text);
this.name = this.text = "";

@@ -1479,3 +1526,3 @@ this.q = null;

}
this.attribList.push({ name: this.name, value: this.text });
this.pushAttrib(this.name, this.text);
this.name = this.text = "";

@@ -1493,3 +1540,3 @@ if (c === GREATER) {

sCloseTag() {
const c = this.captureName();
const c = this.captureNameChars();
if (c === GREATER) {

@@ -1539,3 +1586,3 @@ this.closeTag();

sEntityRest() {
const c = this.captureWhile(this.nameCheck, "entity");
const c = this.captureWhileNameCheck("entity");

@@ -1579,4 +1626,6 @@ if (c === SEMICOLON) {

}
if (this.sawRoot && !this.closedRoot) {
this.fail("unclosed root tag.");
const { tags } = this;
while (tags.length > 0) {
const tag = tags.pop();
this.fail(`unclosed tag: ${tag.name}`);
}

@@ -1587,3 +1636,3 @@ if ((this.state !== S_BEGIN_WHITESPACE) &&

}
if (this.text) {
if (this.text.length !== 0) {
this.closeText();

@@ -1609,37 +1658,2 @@ }

/**
* Emit any buffered text. Then emit the specified node type.
*
* @param {string} nodeType The node type to emit.
*
* @param {string} data The data associated with the node type.
*
* @private
*/
emitNode(nodeType, data) {
if (this.text) {
this.closeText();
}
this[nodeType](data);
}
/**
* Emit any buffered text. Then emit the specified node types.
*
* @param {string} nodeTypeA The node type to emit.
*
* @param {string} nodeTypeB The node type to emit.
*
* @param {string} data The data associated with the node type.
*
* @private
*/
emitNodes(nodeTypeA, nodeTypeB, data) {
if (this.text) {
this.closeText();
}
this[nodeTypeA](data);
this[nodeTypeB](data);
}
/**
* Resolve a namespace prefix.

@@ -1692,3 +1706,3 @@ *

const prefix = name.substring(0, colon);
if (prefix === "" || local === "" || local.indexOf(":") !== -1) {
if (prefix === "" || local === "" || local.includes(":")) {
this.fail(`malformed name: ${name}.`);

@@ -1701,18 +1715,6 @@ }

/** @private */
processAttributesNS() {
processAttribsNS() {
const { tag, attribList } = this;
// emit namespace binding events
const { name: tagName, attributes, ns } = tag;
for (const { name, value } of attribList) {
const { prefix, local } = this.qname(name);
if (prefix === "xmlns") {
ns[local] = value.trim();
}
else if (name === "xmlns") {
ns[""] = value.trim();
}
}
const { name: tagName, attributes } = tag;
nsMappingCheck(this, ns);
{

@@ -1740,4 +1742,4 @@ // add namespace info to tag

// http://www.w3.org/TR/REC-xml-names/#defaulting
for (const { name, value } of attribList) {
const { prefix, local } = this.qname(name);
for (const attr of attribList) {
const { name, prefix, local } = attr;
let uri;

@@ -1765,9 +1767,4 @@ let eqname;

attributes[name] = {
name,
value,
prefix,
local,
uri,
};
attr.uri = uri;
attributes[name] = attr;
}

@@ -1779,3 +1776,3 @@

/** @private */
processAttributesPlain() {
processAttribsPlain() {
const { attribList, tag: { attributes } } = this;

@@ -1797,30 +1794,39 @@ for (const { name, value } of attribList) {

*
* @param {boolean} [selfClosing=false] Whether the tag is self-closing.
* @private
*/
openTag() {
this.processAttribs();
const { tag, tags } = this;
tag.isSelfClosing = false;
// There cannot be any pending text here due to the onopentagstart that was
// necessarily emitted before we get here. So we do not check text.
this.onopentag(tag);
tags.push(tag);
this.state = S_TEXT;
this.name = "";
}
/**
* Handle a complete self-closing tag. This parser code calls this once it has
* seen the whole tag. This method checks for well-formeness and then emits
* ``onopentag`` and ``onclosetag``.
*
* @private
*/
openTag(selfClosing) {
this.processAttributes();
openSelfClosingTag() {
this.processAttribs();
const { tag } = this;
selfClosing = !!selfClosing;
tag.isSelfClosing = selfClosing;
const { tag, tags } = this;
tag.isSelfClosing = true;
if (!this.fragmentOpt && this.closedRoot) {
this.fail("documents may contain only one root.");
// There cannot be any pending text here due to the onopentagstart that was
// necessarily emitted before we get here. So we do not check text.
this.onopentag(tag);
this.onclosetag(tag);
const top = this.tag = tags[tags.length - 1];
if (!top) {
this.closedRoot = true;
}
this.sawRoot = true;
const { tags } = this;
if (selfClosing) {
this.emitNodes("onopentag", "onclosetag", tag);
const top = this.tag = tags[tags.length - 1];
if (!top) {
this.closedRoot = true;
}
}
else {
this.emitNode("onopentag", tag);
this.inRoot = true;
tags.push(tag);
}
this.state = S_TEXT;

@@ -1854,13 +1860,13 @@ this.name = "";

const tag = this.tag = tags.pop();
this.emitNode("onclosetag", tag);
if (tag.name !== name) {
this.fail("unexpected close tag.");
if (this.text.length !== 0) {
this.closeText();
}
else {
this.onclosetag(tag);
if (tag.name === name) {
break;
}
this.fail("unexpected close tag.");
}
if (l === 0) {
this.inRoot = false;
this.closedRoot = true;

@@ -1867,0 +1873,0 @@ }

@@ -5,3 +5,3 @@ {

"author": "Louis-Dominique Dubeau <ldd@lddubeau.com>",
"version": "3.1.5",
"version": "3.1.6",
"main": "lib/saxes.js",

@@ -8,0 +8,0 @@ "types": "lib/saxes.d.ts",

@@ -37,3 +37,3 @@ # saxes

handler which throws. You can replace it with your own handler if you want. If
your handler does nothing. There is no `resume` method to call.
your handler does nothing, there is no `resume` method to call.

@@ -40,0 +40,0 @@ * There's no `Stream` API. A revamped API may be introduced later. (It is still

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc