Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

openrosa-xpath-evaluator

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openrosa-xpath-evaluator - npm Package Compare versions

Comparing version 2.0.1 to 2.0.2

8

CHANGELOG.md

@@ -6,2 +6,10 @@ Change Log

[2.0.2] - 2021-01-18
------------------------
##### Changed
- The uuid() function implementation has improved with a reduced chance of collisions.
##### Fixed
- Nested expressions with dead branches cause an exception.
[2.0.1] - 2021-01-07

@@ -8,0 +16,0 @@ ------------------------

6

package.json
{
"name": "openrosa-xpath-evaluator",
"version": "2.0.1",
"version": "2.0.2",
"description": "Wrapper for browsers' XPath evaluator with added support for OpenRosa extensions.",

@@ -30,3 +30,3 @@ "homepage": "https://enketo.org",

"chai": "^4.2.0",
"eslint": "^7.17.0",
"eslint": "^7.18.0",
"karma": "^5.2.3",

@@ -41,3 +41,3 @@ "karma-chrome-launcher": "^3.1.0",

"puppeteer": "^5.5.0",
"webpack": "^4.39.3"
"webpack": "^4.46.0"
},

@@ -44,0 +44,0 @@ "peerDependencies": {

@@ -27,23 +27,23 @@ Openrosa XForms Evaluator

```js
const orxe = require('openrosa-xpath-evaluator');
const evaluate = orxe();
```
```js
const orxe = require('openrosa-xpath-evaluator');
const evaluate = orxe();
```
## Querying
```js
var result = evaluate(
'//ul/li/text()', // XPath expression
document, // context node
null, // namespace resolver
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
);
```js
var result = evaluate(
'//ul/li/text()', // XPath expression
document, // context node
null, // namespace resolver
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
);
// loop through results
for (var i = 0; i < result.snapshotLength; i++) {
var node = result.snapshotItem(i);
alert(node.nodeValue);
}
```
// loop through results
for (var i = 0; i < result.snapshotLength; i++) {
var node = result.snapshotItem(i);
alert(node.nodeValue);
}
```

@@ -50,0 +50,0 @@

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

"browser": true,
"commonjs": true
"commonjs": true,
"es6": true
},

@@ -8,0 +9,0 @@ "parserOptions": {

@@ -124,8 +124,18 @@ const { handleOperation } = require('./utils/operation');

pushOp = function(t) {
const peeked = peek();
const { tokens } = peeked;
let prev;
if(t <= AND) {
evalOps(t);
const prev = asBoolean(prevToken());
if(t === OR ? prev : !prev) peek().dead = true;
prev = asBoolean(tokens[tokens.length-1]);
if((t === OR ? prev : !prev) && peeked.t !== 'fn') peeked.dead = true;
}
peek().tokens.push({ t:'op', v:t });
tokens.push({ t:'op', v:t });
if(t <= AND) {
if(t === OR ? prev : !prev) tokens.push(D);
}
newCurrent();

@@ -193,11 +203,9 @@ },

if(peek().dead) {
if(tokens[2] === D) {
const nextComma = tokens.indexOf(',');
tokens.splice(0, nextComma === -1 ? tokens.length : nextComma, { t:'bool', v:asBoolean(tokens[0]) });
}
if(tokens.length < 2) return;
if(tokens[2] === D && tokens[1].v >= lastOp) {
const endExpr = tokens.indexOf(',', 2);
tokens.splice(0, endExpr === -1 ? tokens.length : endExpr, { t:'bool', v:asBoolean(tokens[0]) });
}
if(tokens.length < 2) return;
for(let j=UNION; j>=lastOp; j-=0b100) {

@@ -216,3 +224,2 @@ let i = 1;

if(peek().dead) {
peek().tokens.push(D);
newCurrent();

@@ -252,2 +259,13 @@ return;

},
isDeadFnArg = () => {
const peeked = peek();
if(peeked.t === 'fn') {
const { tokens } = peeked;
for(let i=tokens.length-1; i>=0 && tokens[i] !== ','; --i) {
if(tokens[i] === D) {
return true;
}
}
}
},
isNum = function(c) {

@@ -287,7 +305,7 @@ return c >= '0' && c <= '9';

const head = peek();
if(head.dead) {
const { tokens } = head;
if(head.dead || tokens[2] === D) {
newCurrent();
continue;
}
const { tokens } = head;
let contextNodes;

@@ -369,2 +387,4 @@ if(tokens.length && tokens[tokens.length-1].t === 'arr') {

peek().tokens.push(D);
} else if(isDeadFnArg()) {
/* do nothing */
} else if(cur.v) {

@@ -371,0 +391,0 @@ peek().tokens.push(callFn(cur.v, cur.tokens));

@@ -30,11 +30,2 @@ require('./date-extensions');

},
_uuid_part = function(c) {
const r = Math.random()*16|0,
v = c == 'x' ? r : r&0x3|0x8;
return v.toString(16);
},
uuid = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replace(/[xy]/g, _uuid_part);
},
format_date = function(date, format) {

@@ -280,3 +271,2 @@ date = asDate(date);

// I think we should just be able to return: XPR.string(asString(r || this.cN).replace(/[\t\r\n ]+/g, ' ').trim());
// TODO check XPath 3.0 spec for normalize-space()? https://www.w3.org/TR/xpath-functions-30/#func-normalize-space
if(arguments.length > 1) throw new Error('too many args');

@@ -633,1 +623,12 @@

}
/**
* Implementation from https://stackoverflow.com/a/2117523, added in revision
* https://stackoverflow.com/revisions/2117523/11, licensed under CC by SA 3.0
* (https://creativecommons.org/licenses/by-sa/3.0/), see
* https://stackoverflow.com/posts/2117523/timeline. Formatting may have been
* changed.
*/
function uuid() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16));
}

@@ -16,3 +16,3 @@ const { initDoc, assertStringValue } = require('../helpers');

describe('should evaluate node', () => {
describe('with node evaluation', () => {
const doc = initDoc(`

@@ -58,3 +58,3 @@ <div id="FunctionChecklistCase">

});
it(`should evaluate an "or" expression that checks values of nodes (3)`, () => {

@@ -69,4 +69,76 @@ const node = doc.getElementById('FunctionChecklistCase0');

});
});
describe('should deal with nesting and lengthy or/and clauses (with booleans)', ()=> {
[
[ 'if( false() and true(), "A", if(false(), "B", "C") )',
'C' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", "C") )',
'C' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", true() or false()) )',
'true' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", false() or true()) )',
'true' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", false() and true()) )',
'false' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", true() and false()) )',
'false' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", false() and false()) )',
'false' ],
[ 'if( false() and explode-a(), "A", if(false() and explode-b(), "B", true() and true()) )',
'true' ],
[ 'if( false() and explode-a(), "A", if(true() or explode-b(), false() and explode-c(), true() or explode-d()) )',
'false' ],
[ 'if( true() or true() and false(), "A", if(true() or true() and false(), true() or true() and false(), "B") )',
'A' ],
[ 'if( true() or true() and false(), "A", if(true() or true() and false(), true() or true() and false(), true() or true() and explode-d()) )',
'A' ],
[ 'if( true() or true() and false(), "A", if(true() or true() and false(), true() or true() and explode-c(), true() or true() and explode-d()) )',
'A' ],
[ 'if( true() or true() and false(), "A", if(true() or true() and explode-b(), true() or true() and explode-c(), true() or true() and explode-d()) )',
'A' ],
[ 'if( true() or true() and explode-a(), "A", if(true() or true() and explode-b(), true() or true() and explode-c(), true() or true() and explode-d()) )',
'A' ],
].forEach(([ expr, expected ]) => {
it(`should evaluate "${expr}" as "${expected}"`, () => {
assertStringValue(expr, expected);
});
});
});
describe('should deal with nesting and lengthy or/and clauses (with derived values)', ()=> {
const doc = initDoc(`
<data>
<a/>
<b/>
<c>1</c>
<d>0</d>
</data>`);
// TODO: this is a lazy test taken directly from a real form. It probably should be removed the minimal test cases below it seem to be sufficient, but it will be helpful during bug fixing. None of these nodes exist in the doc.
it(`long sequence of "and" clauses and nested if() with long sequence of "or clauses" (non-minimized test case)`, () => {
assertStringValue(doc, null, 'if( /model/instance[1]/data/page-welcome/GRP_ELIG/AGE_IC ="1" and /model/instance[1]/data/page-welcome/GRP_ELIG/INC_TEMP ="1" and /model/instance[1]/data/page-welcome/GRP_ELIG/NO_SEV_ILLNESS ="1" and /model/instance[1]/data/page-welcome/GRP_ELIG/FU_POSSIBLE ="1" and /model/instance[1]/data/page-welcome/GRP_ELIG/SAMPLE_COL_POSSIBLE ="1" and /model/instance[1]/data/page-welcome/GRP_ELIG/PROVIDE_INFORM_CONSENT ="1" and /model/instance[1]/data/page-welcome/GRP_ELIG/FEVER_RESP ="1", "Eligible", if( /model/instance[1]/data/page-welcome/GRP_ELIG/AGE_IC ="0" or /model/instance[1]/data/page-welcome/GRP_ELIG/INC_TEMP ="0" or /model/instance[1]/data/page-welcome/GRP_ELIG/NO_SEV_ILLNESS ="0" or /model/instance[1]/data/page-welcome/GRP_ELIG/FU_POSSIBLE ="0" or /model/instance[1]/data/page-welcome/GRP_ELIG/SAMPLE_COL_POSSIBLE ="0" or /model/instance[1]/data/page-welcome/GRP_ELIG/PROVIDE_INFORM_CONSENT ="0" or /model/instance[1]/data/page-welcome/GRP_ELIG/FEVER_RESP ="0", "Not-Eligible", "nothing"))', 'nothing');
});
it(`sequence of "and" clauses and nested if() with sequence of "or" clauses (1)`, () => {
assertStringValue(doc, null, 'if( /data/a ="1" and /data/b ="1", "Eligible", if( /data/a ="0" or /data/b ="0", "Not-Eligible", "nothing"))', 'nothing');
});
it(`sequence of "and" clauses and nested if() with sequence of "or" clauses (2)`, () => {
assertStringValue(doc, null, 'if( /data/a ="1" and /data/c ="1", "Eligible", if( /data/a ="0" or /data/b ="0", "Not-Eligible", "nothing"))', 'nothing');
});
it(`sequence of "and" clauses and nested if() with sequence of "or" clauses (3)`, () => {
assertStringValue(doc, null, 'if( /data/c ="1" and /data/b ="1", "Eligible", if( /data/a ="0" or /data/b ="0", "Not-Eligible", "nothing"))', 'nothing');
});
it(`sequence of "and" clauses and nested if() with sequence of "or" clauses (4)`, () => {
assertStringValue(doc, null, 'if( /data/a ="1" and /data/b ="1", "Eligible", if( /data/a ="0" or /data/d ="0", "Not-Eligible", "nothing"))', 'Not-Eligible');
});
it(`sequence of "and" clauses and nested if() with sequence of "or" clauses (5)`, () => {
assertStringValue(doc, null, 'if( /data/a ="1" and /data/b ="1", "Eligible", if( /data/d ="0" or /data/b ="0", "Not-Eligible", "nothing"))', 'Not-Eligible');
});
});
});

@@ -179,2 +179,8 @@ // TODO this can be moved to test/unit

false,
'1 or 0 and /explode':
true,
'1 and 0 or 0 or 1 and 1 or 0 or 0 or 0 and /explode or /explode or /explode and /explode':
true,
'1 and 0 or 0 or 1 and 1 or 0 or 0 or 0 and ([/explode]) or /explode or /explode and /explode':
true,
'0 and concat(/explode)':

@@ -244,3 +250,3 @@ false,

_.map(examples, function(expected, expr) {
it(expr + ' should be evaluated', function() {
it(`${expr} should evaluate to ${expected}`, function() {
switch(typeof expected) {

@@ -247,0 +253,0 @@ case 'boolean': return assert.equal(extendedXPathEvaluator.evaluate(expr).booleanValue, expected);

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc