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

openrosa-xpath-evaluator

Package Overview
Dependencies
Maintainers
8
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 1.4.2 to 1.5.0

3

karma.config.js

@@ -77,5 +77,6 @@ // Karma configuration

if (process.env.TRAVIS) cfg.browsers = ['Chrome_travis_ci'];
// TODO Chrome currently fails to launch on Travis. Ideally we'd run both.
if (process.env.TRAVIS) cfg.browsers = ['Firefox', /*'Chrome_travis_ci'*/];
config.set(cfg);
}
{
"name": "openrosa-xpath-evaluator",
"version": "1.4.2",
"version": "1.5.0",
"description": "Wrapper for browsers' XPath evaluator with added support for OpenRosa extensions.",

@@ -18,4 +18,4 @@ "main": "src/openrosa-xpath.js",

"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^0.2.0",
"karma-firefox-launcher": "^0.1.7",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.0.1",
"karma-mocha": "^0.2.2",

@@ -22,0 +22,0 @@ "karma-requirejs": "^0.2.6",

@@ -23,8 +23,9 @@ /*

toInternalResult = function(r) {
var n;
var n, v;
if(r.resultType === XPathResult.NUMBER_TYPE) return { t:'num', v:r.numberValue };
if(r.resultType === XPathResult.BOOLEAN_TYPE) return { t:'bool', v:r.booleanValue };
if(r.resultType === XPathResult.UNORDERED_NODE_ITERATOR_TYPE) {
n = r.iterateNext();
return { t:'str', v:n? n.textContent: '' };
v = [];
while((n = r.iterateNext())) v.push(n.textContent);
return { t:'arr', v:v };
}

@@ -50,3 +51,3 @@ return { t:'str', v:r.stringValue };

var argVals = [], res, i;
for(i=0; i<args.length; ++i) argVals.push(args[i].v);
for(i=0; i<args.length; ++i) argVals.push(args[i]);
res = extendedFuncs[name].apply(null, argVals);

@@ -53,0 +54,0 @@ return res;

@@ -21,4 +21,9 @@ var openrosa_xpath_extensions = function(translate) {

},
_num = function(o) {
return Math.round(o.t === 'num'? o.v: parseFloat(o.v));
_bool = function(r) { return r.t === 'bool' ? r.v : _str(r); },
_int = function(r) { return Math.round(_float(r)); },
_float = function(r) { return r.t === 'num'? r.v: parseFloat(_str(r)); },
_str = function(r) {
return r.t === 'arr' ?
r.v.length ? r.v[0].toString() : '' :
r.v.toString();
},

@@ -41,7 +46,12 @@ _dateToString = function(d) {

},
_parseDate = function(it) {
_date = function(it) {
var temp, t;
if(it instanceof Date) {
return new Date(it);
} else if(RAW_NUMBER.test(it)) {
if(it.v instanceof Date) {
return new Date(it.v);
}
it = _str(it);
if(RAW_NUMBER.test(it)) {
// Create a date at 00:00:00 1st Jan 1970 _in the current timezone_

@@ -64,3 +74,3 @@ temp = new Date(1970, 0, 1);

date = function(it) {
it = _parseDate(it);
it = _date(it);
if(!it) return XPR.string('Invalid Date');

@@ -70,3 +80,4 @@ return XPR.date(it);

format_date = function(date, format) {
date = _parseDate(date);
date = _date(date);
format = _str(format);
if(!date) return '';

@@ -133,3 +144,3 @@ var c, i, sb = '', f = {

},
func,
func, process, ret = {},
now_and_today = function() { return XPR.date(new Date()); };

@@ -139,7 +150,8 @@

'boolean-from-string': function(string) {
string = _str(string);
return XPR.boolean(string === '1' || string === 'true');
},
coalesce: function(a, b) { return XPR.string(a || b); },
coalesce: function(a, b) { return XPR.string(_str(a) || _str(b)); },
'count-selected': function(s) {
var parts = s.split(' '),
var parts = _str(s).split(' '),
i = parts.length,

@@ -152,3 +164,3 @@ count = 0;

'decimal-date': function(date) {
return XPR.number(Date.parse(date) / MILLIS_PER_DAY); },
return XPR.number(Date.parse(_str(date)) / MILLIS_PER_DAY); },
'difference-in-months': function(d1, d2) {

@@ -158,4 +170,4 @@ // FIXME this is a medic mobile extension, and should be in a corresponding

var months;
d1 = _parseDate(d1);
d2 = _parseDate(d2);
d1 = _date(d1);
d2 = _date(d2);

@@ -173,4 +185,21 @@ if(!d1 || !d2) return XPR.string('');

return XPR.string(format_date(date, format)); },
'if': function(con, a, b) { return XPR.string(con? a: b); },
int: function(v) { return XPR.number(parseInt(v, 10)); },
'if': function(con, a, b) { return XPR.string(_bool(con)? a.v: b.v); },
int: function(v) { return XPR.number(parseInt(_str(v), 10)); },
join: function(delim, arr) { return XPR.string(arr.v.join(_str(delim))); },
max: function(r) {
var max, i;
r = r.v;
if(!(i=r.length)) return XPR.number(NaN);
max = parseFloat(r[0]);
while(--i) max = Math.max(max, parseFloat(r[i]));
return XPR.number(max);
},
min: function(r) {
var min, i;
r = r.v;
if(!(i=r.length)) return XPR.number(NaN);
min = parseFloat(r[0]);
while(--i) min = Math.min(min, parseFloat(r[i]));
return XPR.number(min);
},
/*

@@ -184,14 +213,14 @@ * As per https://github.com/alxndrsn/openrosa-xpath-evaluator/issues/15,

*/
not: function(v) { return XPR.boolean(!v); },
not: function(r) { return XPR.boolean(!r.v); },
now: now_and_today,
pow: function(x, y) { return XPR.number(Math.pow(x, y)); },
pow: function(x, y) { return XPR.number(Math.pow(_float(x), _float(y))); },
random: function() { return XPR.number(Math.random()); },
regex: function(haystack, pattern) {
return XPR.boolean(new RegExp(pattern).test(haystack)); },
return XPR.boolean(new RegExp(_str(pattern)).test(_str(haystack))); },
round: function(number, num_digits) {
number = parseFloat(number);
num_digits = num_digits ? parseInt(num_digits) : 0;
number = _float(number);
if(!num_digits) {
return XPR.number(_round(number));
}
num_digits = _int(num_digits);
var pow = Math.pow(10, Math.abs(num_digits));

@@ -205,6 +234,13 @@ if(num_digits > 0) {

selected: function(haystack, needle) {
return XPR.boolean(haystack.split(' ').indexOf(needle) !== -1);
return XPR.boolean(_str(haystack).split(' ').indexOf(_str(needle)) !== -1);
},
'selected-at': function(list, index) {
if(!index) throw new Error(JSON.stringify(list));
return XPR.string(_str(list).split(' ')[_int(index)] || '');
},
substr: function(string, startIndex, endIndex) {
return XPR.string(string.slice(startIndex, endIndex)); },
return XPR.string(_str(string).slice(
_int(startIndex),
endIndex && _int(endIndex)));
},
today: now_and_today,

@@ -220,5 +256,3 @@ 'true': function() { return XPR.boolean(true); },

return {
func:func,
process: {
process = {
toExternalResult: function(r) {

@@ -250,4 +284,4 @@ if(r.t === 'date') return {

op.v === '!=') {
if(lhs.t === 'str') lhs = date(lhs.v);
if(rhs.t === 'str') rhs = date(rhs.v);
if(lhs.t === 'arr' || lhs.t === 'str') lhs = date(lhs);
if(rhs.t === 'arr' || rhs.t === 'str') rhs = date(rhs);
if(lhs.t !== 'date' || rhs.t !== 'date') {

@@ -263,3 +297,3 @@ return op.v === '!=';

var d = lhs.t === 'date'? lhs.v: rhs.v,
n = lhs.t !== 'date'? _num(lhs): _num(rhs),
n = lhs.t !== 'date'? _int(lhs): _int(rhs),
res = new Date(d.getTime());

@@ -273,4 +307,8 @@ if(op.v === '-') n = -n;

},
},
};
ret.func = func;
ret.process = process;
return ret;
};

@@ -277,0 +315,0 @@

@@ -72,5 +72,5 @@ define(['src/extended-xpath', 'chai', 'lodash'], function(ExtendedXpathEvaluator, chai, _) {

'random()':
/^0.\d+$/,
/^(0\.\d+)|(\d\.\d+e-\d)$/,
'random() div 10':
/^0.0\d+$/,
/^(0\.0\d+)|(\d\.\d+e-\d)$/,
'12 mod 5':

@@ -210,12 +210,12 @@ /^2$/,

func: {
upcase: function(it) { return xp.str(it.toUpperCase()); },
downcase: function(it) { return xp.str(it.toLowerCase()); },
upcase: function(it) { return xp.str(it.v.toUpperCase()); },
downcase: function(it) { return xp.str(it.v.toLowerCase()); },
date: function() { return xp.str(new Date().toString()); },
concat: function() {
var i, acc = '';
for(i=0; i<arguments.length; ++i) acc += arguments[i];
for(i=0; i<arguments.length; ++i) acc += arguments[i].v;
return xp.str(acc);
},
random: function() { return xp.num(Math.random()); },
reverse: function(it) { return xp.str(it.split('').reverse().join('')); },
reverse: function(it) { return xp.str(it.v.split('').reverse().join('')); },
},

@@ -222,0 +222,0 @@ }

define(['src/openrosa-xpath-extensions', 'src/extended-xpath', 'src/translate', 'chai', 'lodash'],
function(openRosaXpathExtensions, ExtendedXpathEvaluator, translate, chai, _) {
var TODO = function() { if(false) assert.notOk('TODO'); },
SIMPLE_DATE_MATCH = /^\d{4}-\d\d-\d\d$/,
FULL_DATE_MATCH = /(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d \d{4} \d\d:\d\d:\d\d GMT([+-]\d\d\d\d \(.+\))?/,
assert = chai.assert,
doc, xEval,
extendedXpathEvaluator = new ExtendedXpathEvaluator(
function wrappedXpathEvaluator(v) {
return doc.evaluate.call(doc, v, doc, null,
XPathResult.ANY_TYPE, null);
},
openRosaXpathExtensions(translate)),
simpleValueIs = function(textValue) {
var xml = '<simple><xpath><to><node>' + textValue +
'</node></to></xpath><empty/></simple>';
doc = new DOMParser().parseFromString(xml, 'application/xml');
xEval = function(e) {
return extendedXpathEvaluator.evaluate(e);
};
},
initBasicXmlDoc = function() { simpleValueIs(''); };
const SIMPLE_DATE_MATCH = /^\d{4}-\d\d-\d\d$/;
const FULL_DATE_MATCH = /(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d \d{4} \d\d:\d\d:\d\d GMT([+-]\d\d\d\d \(.+\))?/;
const assert = chai.assert;
function TODO() { if(false) assert.notOk('TODO'); }
let doc, xEval, extendedXpathEvaluator;
function initDoc(xml) {
doc = new DOMParser().parseFromString(xml, 'application/xml');
extendedXpathEvaluator = new ExtendedXpathEvaluator(
v => {
const result = doc.evaluate.call(doc, v, doc, null, XPathResult.ANY_TYPE, null);
//console.log(`${v} => ${result.resultType}`);
return result;
},
openRosaXpathExtensions(translate, doc));
xEval = function(e) {
return extendedXpathEvaluator.evaluate(e);
};
}
function simpleValueIs(textValue) {
initDoc(`<simple><xpath><to>
<node>${textValue}</node>
</to></xpath><empty/></simple>`);
}
const initBasicXmlDoc = () => simpleValueIs('');
beforeEach(function() {

@@ -243,2 +250,25 @@ initBasicXmlDoc();

describe('#number()', function() {
describe('called on a boolean', function() {
_.forEach({
'number(true())': '1',
'number(false())': '0',
'number(1 = 1)': '1',
'number(1 = 2)': '0',
}, function(expectedResult, expr) {
it(`${expr} should be ${expectedResult}`, function() {
assert.equal(xEval(expr).numberValue, expectedResult);
});
});
});
describe('called on a number', function() {
_.forEach({
'number("0")': '0',
'number("1")': '1',
'number("-1")': '-1',
}, function(expectedResult, expr) {
it(`${expr} should be ${expectedResult}`, function() {
assert.equal(xEval(expr).numberValue, expectedResult);
});
});
});
describe('called on a date string', function() {

@@ -254,2 +284,3 @@ _.forEach({

TODO();
// assert.equal(xEval(expr).numberValue, expectedResult);
});

@@ -373,6 +404,136 @@ });

describe('#join()', function() { it('should have tests', function() { TODO(); }); });
describe('#max()', function() { it('should have tests', function() { TODO(); }); });
describe('#min()', function() { it('should have tests', function() { TODO(); }); });
describe('#join()', function() {
it('should join a list of strings with supplied separator', function() {
// given
initDoc(`
<root>
<item>one</item>
<item>two</item>
<item>three</item>
</root>`);
// when
const joined = xEval(`join(' :: ', //item)`).stringValue;
// expect
assert.equal(joined, 'one :: two :: three');
});
});
describe('#max()', function() {
it('should return NaN if no numerical nodes are matched', function() {
// given
simpleValueIs('');
// expect
assert.isNaN(xEval('max(/simple)').numberValue);
});
it('should return value of a single node if only one matches', function() {
// given
simpleValueIs('3');
// expect
assert.equal(xEval('max(/simple/xpath/to/node)').numberValue, 3);
});
it('should return NaN if any node evaluates to NaN', function() {
// given
initDoc(`
<root>
<item>3</item>
<item>17</item>
<item>-32</item>
<item>cheese</item>
</root>`);
// expect
assert.isNaN(xEval('max(/root/item)').numberValue);
});
it('should return the max value in a node set', function() {
// given
initDoc(`
<root>
<item>3</item>
<item>17</item>
<item>-32</item>
</root>`);
// expect
assert.equal(xEval('max(/root/item)').numberValue, 17);
});
it('should return the max value in a node set of negative numbers', function() {
// given
initDoc(`
<root>
<item>-3</item>
<item>-17</item>
<item>-32</item>
</root>`);
// expect
assert.equal(xEval('max(/root/item)').numberValue, -3);
});
});
describe('#min()', function() {
it('should return NaN if no numerical nodes are matched', function() {
// given
simpleValueIs('');
// expect
assert.isNaN(xEval('min(/simple)').numberValue);
});
it('should return value of a single node if only one matches', function() {
// given
simpleValueIs('3');
// expect
assert.equal(xEval('min(/simple/xpath/to/node)').numberValue, 3);
});
it('should return NaN if any node evaluates to NaN', function() {
// given
initDoc(`
<root>
<item>3</item>
<item>17</item>
<item>-32</item>
<item>cheese</item>
</root>`);
// expect
assert.isNaN(xEval('min(/root/item)').numberValue);
});
it('should return the min value in a node set', function() {
// given
initDoc(`
<root>
<item>3</item>
<item>-17</item>
<item>32</item>
</root>`);
// expect
assert.equal(xEval('min(/root/item)').numberValue, -17);
});
it('should return the min value in a node set of negative numbers', function() {
// given
initDoc(`
<root>
<item>-3</item>
<item>-17</item>
<item>-32</item>
</root>`);
// expect
assert.equal(xEval('min(/root/item)').numberValue, -32);
});
});
describe('#random()', function() {

@@ -562,4 +723,19 @@ it('should return a number', function() {

describe('#selected-at()', function() { it('should have tests', function() { TODO(); }); });
describe('#selected-at()', function() {
[
{ from:'zero one two three', index:1, expected:'one' },
{ from:'zero one two three', index:4, expected:'' },
{ from:'zero one two three', index:-1, expected:'' },
{ from:'', index:0, expected:'' },
].forEach(({ from, index, expected }) => {
it(`should select ${expected} from "${from}" at index ${index}`, function() {
// when
const actual = xEval(`selected-at('${from}', '${index}')`).stringValue;
// expect
assert.equal(actual, expected);
});
});
});
describe('#round()', function() {

@@ -566,0 +742,0 @@ describe('with a single argument', function() {

@@ -23,6 +23,9 @@ define(['src/openrosa-xpath-extensions', 'src/translate', 'chai', 'lodash'],

'one-1 two,2 three==3': 3,
}, function(expected, expr) {
it('should return ' + expected + ' when called with <<' + expr + '>>', function() {
}, function(expected, v) {
it(`should return ${expected} when called with <<${v}>>`, function() {
// given
const r = { t:'str', v };
// when
var result = f['count-selected'](expr);
var result = f['count-selected'](r);

@@ -38,8 +41,14 @@ // then

it('should return a date type', function() {
// given
const r = { t:'str', v:0 };
// expect
assert.equal(f.date(0).t, 'date');
assert.equal(f.date(r).t, 'date');
});
it('should return a value of type Date', function() {
// given
const r = { t:'str', v:0 };
// expect
assert.ok(f.date(0).v instanceof Date);
assert.ok(f.date(r).v instanceof Date);
});

@@ -52,6 +61,9 @@

'1971-02-05': 400,
}, function(arg, expected) {
it('should convert ' + arg + ' to ' + expected, function() {
}, function(v, expected) {
// given
const r = { t:'str', v };
it('should convert ' + r + ' to ' + expected, function() {
// expect
assert.equal(simpleDateString(f.date(arg).v), expected);
assert.equal(simpleDateString(f.date(r).v), expected);
});

@@ -63,8 +75,14 @@ });

it('should return a date type', function() {
// given
const r = { t:'num', v:1.11596 };
// expect
assert.equal(f.date(1.11596).t, 'date');
assert.equal(f.date(r).t, 'date');
});
it('should return a value of type Date', function() {
// given
const r = { t:'num', v:1.11596 };
// expect
assert.ok(f.date(1.11596).v instanceof Date);
assert.ok(f.date(r).v instanceof Date);
});

@@ -77,6 +95,9 @@

'1971-02-05': 400.5,
}, function(arg, expected) {
it('should convert ' + arg + ' to ' + expected, function() {
}, function(v, expected) {
// given
const r = { t:'num', v };
it('should convert ' + r + ' to ' + expected, function() {
// expect
assert.equal(simpleDateString(f.date(arg).v), expected);
assert.equal(simpleDateString(f.date(r).v), expected);
});

@@ -92,11 +113,17 @@ });

'1971-02-05',
], function(arg) {
], function(v) {
// given
const r = { t:'str', v };
it('should return a date type', function() {
assert.equal(f.date(arg).t, 'date');
// expect
assert.equal(f.date(r).t, 'date');
});
it('should return a value of type Date', function() {
assert.ok(f.date(arg).v instanceof Date);
// expect
assert.ok(f.date(r).v instanceof Date);
});
it('should return the correct date, in the local format', function() {
assert.equal(simpleDateString(f.date(arg).v), arg);
// expect
assert.equal(simpleDateString(f.date(r).v), r.v);
});

@@ -110,8 +137,13 @@ });

'99-12-31',
], function(arg) {
], function(v) {
// given
const r = { t:'string', v };
it('should return a string type', function() {
assert.equal(f.date(arg).t, 'str');
// expect
assert.equal(f.date(r).t, 'str');
});
it('should convert "' + arg + '" to "Invalid Date"', function() {
assert.equal(f.date(arg).v, 'Invalid Date');
it(`should convert "${v}" to "Invalid Date"`, function() {
// expect
assert.equal(f.date(r).v, 'Invalid Date');
});

@@ -124,4 +156,8 @@ });

it("should return empty string if it can't parse a date", function() {
// given
const badDateString = { type:'str', v:'abc' };
const format = { type:'str', v:'%Y' };
// when
var formattedDate = f['format-date']('abc', '%Y');
const formattedDate = f['format-date'](badDateString, format);

@@ -175,4 +211,4 @@ // then

].forEach(function(example) {
var d1 = example[0],
d2 = example[1],
var d1 = { t:'str', v:example[0] },
d2 = { t:'str', v:example[1] },
expectedDifference = example[2];

@@ -187,4 +223,4 @@

// given
var d1 = 'nonsense',
d2 = '2015-09-22';
const d1 = { t:'str', v:'nonsense' };
const d2 = { t:'str', v:'2015-09-22' };

@@ -191,0 +227,0 @@ // expect

Sorry, the diff of this file is not supported yet

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