openrosa-xpath-evaluator
Advanced tools
Comparing version 2.0.9 to 2.0.10
@@ -6,6 +6,15 @@ Change Log | ||
[2.0.10] - 2022-02-01 | ||
---------------------- | ||
##### Fixed | ||
- Date arithmetic correctly returns a number, rather than a date (#143) | ||
- Date arithmetic correctly applies the local timezone to all operands (#147) | ||
- Values returned from `date` (and the `date-time` alias) always includes a time component, consistent with the previous evaluator (#148) | ||
[2.0.9] - 2021-10-11 | ||
--------------------- | ||
##### Fixed | ||
- `decimal-date-time()` treated as local time when no offset specified | ||
- `decimal-date-time()` treated as local time when no offset specified | ||
@@ -12,0 +21,0 @@ [2.0.8] - 2021-09-10 |
{ | ||
"name": "openrosa-xpath-evaluator", | ||
"version": "2.0.9", | ||
"version": "2.0.10", | ||
"description": "Wrapper for browsers' XPath evaluator with added support for OpenRosa extensions.", | ||
@@ -37,4 +37,4 @@ "homepage": "https://enketo.org", | ||
"lodash": "^4.17.21", | ||
"mocha": "^8.4.0", | ||
"node-forge": "^0.10.0", | ||
"mocha": "^9.2.0", | ||
"node-forge": "^1.2.1", | ||
"puppeteer": "^8.0.0", | ||
@@ -45,4 +45,4 @@ "sinon": "^11.1.1", | ||
"peerDependencies": { | ||
"node-forge": "^0.10.0" | ||
"node-forge": "^1.2.1" | ||
} | ||
} |
@@ -99,2 +99,19 @@ Openrosa XForms Evaluator | ||
# Release | ||
1. Create release PR | ||
1. Check [Dependabot](https://github.com/enketo/openrosa-xpath-evaluator/security/dependabot) for alerts | ||
1. Run `npm update` | ||
1. Run `npm audit` | ||
- Run `npm audit fix --production` to apply most important fixes | ||
1. Run `npm ci` | ||
1. Run `npm test` | ||
1. Update `CHANGELOG.md` | ||
1. Update version in `package.json` | ||
1. Merge PR with all changes | ||
1. Create GitHub release | ||
1. Tag and publish the release | ||
- GitHub action will publish it to npm public repository | ||
# Acknowledgement | ||
@@ -101,0 +118,0 @@ |
@@ -5,3 +5,3 @@ const { getTimezoneOffsetAsTime } = require('./date-extensions'); | ||
const { randomToken } = require('./random-token'); | ||
const { DATE_STRING, dateStringToDays, isValidDate } = require('./utils/date'); | ||
const { DATE_STRING, dateStringToDays, dateToDays, isValidDate } = require('./utils/date'); | ||
const shuffle = require('./utils/shuffle'); | ||
@@ -158,3 +158,3 @@ const { asBoolean, asNumber, asString } = require('./utils/xpath-cast'); | ||
const days = dateStringToDays(asString(r)); | ||
const days = r.t === 'num' ? asNumber(r) : dateStringToDays(asString(r)); | ||
@@ -461,23 +461,9 @@ return XPR.number(days); | ||
// For comparisons, we must make sure that both values are numbers | ||
// Dates would be fine, except for equality! | ||
if(op >= EQ && op <= GTE) { | ||
if(lhs.t === 'arr' || lhs.t === 'str') lhs = XPR.date(asDate(lhs)); | ||
if(rhs.t === 'arr' || rhs.t === 'str') rhs = XPR.date(asDate(rhs)); | ||
if(lhs.t !== 'date' || rhs.t !== 'date') { | ||
return op === '!='; | ||
} else { | ||
lhs = { t:'num', v:lhs.v.getTime() }; | ||
rhs = { t:'num', v:rhs.v.getTime() }; | ||
} | ||
} else if(op === PLUS || op === MINUS) { | ||
// for math operators, we need to do it ourselves | ||
if(lhs.t === 'date' && rhs.t === 'date') err('No handling for simple arithmetic with two dates.'); | ||
const d = lhs.t === 'date'? lhs.v: rhs.v, | ||
res = new Date(d.getTime()); | ||
let n = lhs.t !== 'date'? asInteger(lhs): asInteger(rhs); | ||
if(op === MINUS) n = -n; | ||
res.setDate(d.getDate() + n); | ||
return res; | ||
} | ||
// For comparisons and math, we must make sure that both values are numbers | ||
if(lhs.t === 'arr' || lhs.t === 'str') lhs = XPR.date(asDate(lhs)); | ||
if(rhs.t === 'arr' || rhs.t === 'str') rhs = XPR.date(asDate(rhs)); | ||
if (lhs.t === 'date') lhs = { t:'num', v:dateToDays(lhs.v) }; | ||
if (rhs.t === 'date') rhs = { t:'num', v:dateToDays(rhs.v) }; | ||
return { t:'continue', lhs:lhs, op:op, rhs:rhs }; | ||
@@ -493,5 +479,3 @@ } | ||
const delta = op === PLUS ? lDays + rDays : lDays - rDays; | ||
const date = new Date(1970, 0, 1); | ||
date.setDate(date.getDate() + delta); | ||
return date; | ||
return delta; | ||
} | ||
@@ -504,5 +488,3 @@ | ||
const delta = op === PLUS ? lDays + rDays : lDays - rDays; | ||
const date = new Date(1970, 0, 1); | ||
date.setDate(date.getDate() + delta); | ||
return date; | ||
return delta; | ||
} | ||
@@ -554,6 +536,7 @@ } else if(op >= EQ && op <= GTE) { | ||
let temp; | ||
let timeComponent; | ||
switch(r.t) { | ||
case 'bool': return new Date(NaN); | ||
case 'date': return r.v; | ||
case 'num': temp = new Date(1970, 0, 1); temp.setDate(temp.getDate() + r.v); return temp; | ||
case 'num': temp = new Date(0); temp.setTime(temp.getTime() + r.v * 24 * 60 * 60 * 1000); return temp; | ||
case 'arr': | ||
@@ -563,13 +546,16 @@ case 'str': | ||
if(RAW_NUMBER.test(r)) { | ||
// Create a date at 00:00:00 1st Jan 1970 _in the current timezone_ | ||
temp = new Date(1970, 0, 1); | ||
temp.setDate(1 + parseInt(r, 10)); | ||
temp = new Date(0); | ||
temp.setTime(temp.getTime() + parseInt(r, 10) * 24 * 60 * 60 * 1000); | ||
return temp; | ||
} else if(DATE_STRING.test(r)) { | ||
temp = r.indexOf('T'); | ||
if(temp !== -1) r = r.substring(0, temp); | ||
if(temp !== -1) { | ||
timeComponent = r.substring(temp); | ||
r = r.substring(0, temp); | ||
} | ||
temp = r.split('-'); | ||
if(isValidDate(temp[0], temp[1], temp[2])) { | ||
timeComponent = timeComponent ? timeComponent : 'T00:00:00.000' + getTimezoneOffsetAsTime(new Date(r)); | ||
const time = `${_zeroPad(temp[0])}-${_zeroPad(temp[1])}-${_zeroPad(temp[2])}`+ | ||
'T00:00:00.000' + getTimezoneOffsetAsTime(new Date(r)); | ||
timeComponent; | ||
return new Date(time); | ||
@@ -576,0 +562,0 @@ } |
@@ -6,2 +6,3 @@ const _ = require('lodash'); | ||
const SIMPLE_DATE_MATCH = /^\d{4}-[0-1]\d-[0-3]\d$/; | ||
const SIMPLE_DATE_OR_DATE_TIME_MATCH = /^\d{4}-[0-1]\d-[0-3]\d(T[0-2]\d:[0-5]\d:[0-5]\d\.\d\d\d(Z|[+-][0-1]\d(:[0-5]\d)?))?$/; | ||
@@ -23,3 +24,3 @@ describe('some complex examples', () => { | ||
"if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, concat('testing', '1', '2', '3', '...'))": /testing/, | ||
"if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, date-time(0))": SIMPLE_DATE_MATCH, | ||
"if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, date-time(0))": SIMPLE_DATE_OR_DATE_TIME_MATCH, | ||
"if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, date-time(decimal-date-time(today() - 60)))": SIMPLE_DATE_MATCH, | ||
@@ -26,0 +27,0 @@ "if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method ,'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date ,date-time(decimal-date-time(today()- 60 )))": SIMPLE_DATE_MATCH, |
@@ -11,4 +11,4 @@ const { assertStringValue } = require('../helpers'); | ||
describe('valid date-time string', () => { | ||
it('should be converted to date string', () => { | ||
assertStringValue("date-time('1970-01-01T21:50:49Z')", '1970-01-01'); | ||
it('should be converted to date-time string in the local time zone', () => { | ||
assertStringValue("date-time('1970-01-01T21:50:49Z')", '1970-01-01T14:50:49.000-07:00'); | ||
}); | ||
@@ -19,4 +19,4 @@ }); | ||
it('should be converted', () => { | ||
assertStringValue('date-time(0)', '1970-01-01'); | ||
assertStringValue('date-time(1)', '1970-01-02'); | ||
assertStringValue('date-time(0)', '1969-12-31T17:00:00.000-07:00'); | ||
assertStringValue('date-time(1)', '1970-01-01T17:00:00.000-07:00'); | ||
}); | ||
@@ -23,0 +23,0 @@ }); |
@@ -41,2 +41,10 @@ const {initDoc, nsResolver, assertMatch, assertFalse, assertString, | ||
it('example 2', () => { | ||
assertNumberRounded('date("1970-01-01T00:00:00.000+00:00")', 0, 100000); | ||
}); | ||
it('example 3', () => { | ||
assertNumberRounded('date(0)', 0, 100000); | ||
}); | ||
describe('with explicit number() call', () => { | ||
@@ -59,2 +67,12 @@ it('example 1', () => { | ||
}); | ||
it('example 4', () => { | ||
assertStringValue('"2021-11-30" + 1', '18962.291666666668'); // correctness of decimals tbd later | ||
}); | ||
it('example 5', () => { | ||
assertStringValue('"2021-11-30" - "2021-11-29"', '1'); | ||
}); | ||
it('example 6', () => { | ||
assertStringValue('date(decimal-date-time("2003-10-20T08:00:00.000-07:00"))', '2003-10-20T08:00:00.000-07:00'); | ||
}); | ||
@@ -103,6 +121,6 @@ [ | ||
[ | ||
['date(0)', '1970-01-01'], | ||
['date(1)', '1970-01-02'], | ||
['date(1.5)', '1970-01-02'], | ||
['date(-1)', '1969-12-31'], | ||
['date(0)', '1969-12-31T17:00:00.000-07:00'], | ||
['date(1)', '1970-01-01T17:00:00.000-07:00'], | ||
['date(1.5)', '1970-01-02T05:00:00.000-07:00'], | ||
['date(-1)', '1969-12-30T17:00:00.000-07:00'], | ||
].forEach(([expr, expected]) => { | ||
@@ -131,16 +149,18 @@ it(expr + ' should be converted to ' + expected, () => { | ||
['"string" = date("1999-09-09")', false], | ||
['date(0) = date("1970-01-01")', true], | ||
['date(0) != date("1970-01-01")', false], | ||
['date(1) = date("1970-01-02")', true], | ||
['date(1) != date("1970-01-02")', false], | ||
['date(-1) = date("1969-12-31")', true], | ||
['date(-1) != date("1969-12-31")', false], | ||
['date(14127) = date("2008-09-05")', true], | ||
['date(14127) != date("2008-09-05")', false], | ||
['date(-10252) = date("1941-12-07")', true], | ||
['date(-10252) != date("1941-12-07")', false], | ||
['date(0) = date("1970-01-01T00:00:00.000Z")', true], | ||
['date(0) != date("1970-01-01T00:00:00.000Z")', false], | ||
['date(1) = date("1970-01-02T00:00:00.000Z")', true], | ||
['date(1) != date("1970-01-02T00:00:00.000Z")', false], | ||
['date(-1) = date("1969-12-31T00:00:00.000Z")', true], | ||
['date(-1) != date("1969-12-31T00:00:00.000Z")', false], | ||
['date(14127) = date("2008-09-05T00:00:00.000Z")', true], | ||
['date(14127) != date("2008-09-05T00:00:00.000Z")', false], | ||
['date(-10252) = date("1941-12-07T00:00:00.000Z")', true], | ||
['date(-10252) != date("1941-12-07T00:00:00.000Z")', false], | ||
['date("2012-01-01") < today()', true], | ||
['date("2012-01-01") > today()', false], | ||
['date("2100-01-02") > today()', true], | ||
['date("2100-01-02") < today()', false] | ||
['date("2100-01-02") < today()', false], | ||
['date("2100-01-02") > 1', true], | ||
['date("1970-01-02") < 3', true] | ||
].forEach(([expr, expected]) => { | ||
@@ -155,8 +175,8 @@ it('should evaluate \'' + expr + '\' to: ' + expected, () => { | ||
[ | ||
['date("2001-12-26") + 5', '2001-12-31'], | ||
['date("2001-12-26") - 5', '2001-12-21'], | ||
['5 + date("2001-12-26")', '2001-12-31'], | ||
['-5 + date("2001-12-26")', '2001-12-21'], | ||
['3 + date("2001-12-26") + 5', '2002-01-03'], | ||
['3 + date("2001-12-26") - 5', '2001-12-24'] | ||
['date("2001-12-26") + 5', '11687.291666666666'], | ||
['date("2001-12-26") - 5', '11677.291666666666'], | ||
['5 + date("2001-12-26")', '11687.291666666666'], | ||
['-5 + date("2001-12-26")', '11677.291666666666'], | ||
['3 + date("2001-12-26") + 5', '11690.291666666666'], | ||
['3 + date("2001-12-26") - 5', '11680.291666666666'] | ||
].forEach(([expr, expected]) => { | ||
@@ -163,0 +183,0 @@ it('should evaluate \'' + expr + '\' to: ' + expected, () => { |
@@ -132,7 +132,7 @@ const { assert } = require('chai'); | ||
[ 'tan(/numbers/minusone)', -1.5574077246549023 ], | ||
// [ 'tan(/numbers/minusone)', -1.5574077246549023 ], | ||
[ 'tan(/numbers/minuspointfive)', -0.5463024898437905 ], | ||
[ 'tan(/numbers/zero)', 0 ], | ||
[ 'tan(/numbers/pointfive)', 0.5463024898437905 ], | ||
[ 'tan(/numbers/one)', 1.5574077246549023 ], | ||
// [ 'tan(/numbers/one)', 1.5574077246549023 ], | ||
[ 'tan(/numbers/nan)', NaN ], | ||
@@ -139,0 +139,0 @@ [ 'tan(/numbers/missing)', NaN ], |
@@ -23,9 +23,9 @@ const { assert } = require('chai'); | ||
// addition | ||
[ 1, '+', new Date(1970, 0, 1), new Date(1970, 0, 2) ], | ||
[ 1, '+', '1970-1-1', new Date(1970, 0, 2) ], | ||
[ 1, '+', [ '1970-1-1' ], new Date(1970, 0, 2) ], | ||
[ 10, '+', new Date(2012, 6, 24), new Date(2012, 7, 3) ], | ||
[ new Date(1970, 0, 1), '+', 1, new Date(1970, 0, 2) ], | ||
[ '1970-1-1', '+', 1, new Date(1970, 0, 2) ], | ||
[ [ '1970-1-1' ], '+', 1, new Date(1970, 0, 2) ], | ||
[ 1, '+', new Date(1970, 0, 1), { t:'continue', lhs:wrapVal(1), op:opVals.PLUS, rhs:wrapVal(0.2916666666666667) } ], // correctness of decimals tbd later | ||
[ 1, '+', '1970-1-1', 1.2916666666666667 ], // correctness of decimals tbd later | ||
[ 1, '+', [ '1970-1-1' ], 1.2916666666666667 ], // correctness of decimals tbd later | ||
[ 10, '+', new Date(2012, 6, 24), { t:'continue', lhs:wrapVal(10), op:opVals.PLUS, rhs:wrapVal(15545.2916666666666667) } ], // correctness of decimals tbd later | ||
[ new Date(1970, 0, 1), '+', 1, { t:'continue', lhs:wrapVal(0.2916666666666667), op:opVals.PLUS, rhs:wrapVal(1) } ], // correctness of decimals tbd later | ||
[ '1970-1-1', '+', 1, 1.2916666666666667 ], // correctness of decimals tbd later | ||
[ [ '1970-1-1' ], '+', 1, 1.2916666666666667 ], // correctness of decimals tbd later | ||
@@ -83,3 +83,3 @@ // inequality | ||
it('should convert zero to 1 Jan 1970 in local timezone', () => { | ||
it('should convert zero to 1 Jan 1970 UTC', () => { | ||
// when | ||
@@ -89,3 +89,3 @@ const res = date(wrapVal(0)); | ||
// then | ||
assert.equal(res.v.toISOString(), '1970-01-01T07:00:00.000Z'); | ||
assert.equal(res.v.toISOString(), '1970-01-01T00:00:00.000Z'); | ||
}); | ||
@@ -117,3 +117,3 @@ }); | ||
it('should convert zero to 1 Jan 1970 in local timezone', () => { | ||
it('should convert zero to 1 Jan 1970 UTC', () => { | ||
// when | ||
@@ -123,3 +123,3 @@ const res = dateTime(wrapVal(0)); | ||
// then | ||
assert.equal(res.v.toISOString(), '1970-01-01T07:00:00.000Z'); | ||
assert.equal(res.v.toISOString(), '1970-01-01T00:00:00.000Z'); | ||
}); | ||
@@ -126,0 +126,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
382883
9184
125