Comparing version 0.0.1 to 0.1.0
30
index.js
'use strict' | ||
const ExtDate = require('./src/date') | ||
const Year = require('./src/year') | ||
const Decade = require('./src/decade') | ||
const Century = require('./src/century') | ||
const Season = require('./src/season') | ||
const Interval = require('./src/interval') | ||
const List = require('./src/list') | ||
const Set = require('./src/set') | ||
const Bitmask = require('./src/bitmask') | ||
const types = require('./src/types') | ||
const { sample, gen } = require('./src/sample') | ||
const { parse } = require('./src/parser') | ||
@@ -10,3 +19,10 @@ | ||
function edtf(...args) { | ||
return new ExtDate(...args) | ||
if (!args.length) | ||
return new ExtDate() | ||
if (args.length === 1 && typeof args[0] === 'object') | ||
return new (edtf[args[0].type] || ExtDate)(args[0]) | ||
const res = parse(...args) | ||
return new edtf[res.type](res) | ||
} | ||
@@ -17,4 +33,14 @@ | ||
Date: ExtDate, | ||
Year, | ||
Decade, | ||
Century, | ||
Season, | ||
Interval, | ||
List, | ||
Set, | ||
Bitmask, | ||
parse | ||
parse, | ||
sample, | ||
gen, | ||
types | ||
}) |
{ | ||
"name": "edtf", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"description": "Extended Date Time Format (EDTF) / ISO 8601-2 Parser and Library", | ||
@@ -26,3 +26,6 @@ "main": "index.js", | ||
], | ||
"author": "Sylvester Keil <sylvester@keil.or.at>", | ||
"author": "Center for History and New Media, George Mason University", | ||
"contributors": [ | ||
"Sylvester Keil <sylvester@keil.or.at>" | ||
], | ||
"license": "AGPL-3.0", | ||
@@ -34,3 +37,4 @@ "bugs": { | ||
"dependencies": { | ||
"nearley": "^2.4.1" | ||
"nearley": "^2.4.1", | ||
"randexp": "^0.4.2" | ||
}, | ||
@@ -37,0 +41,0 @@ "devDependencies": { |
# EDTF.js | ||
[![Build Status](https://travis-ci.org/inukshuk/edtf.js.svg?branch=master)](https://travis-ci.org/inukshuk/edtf.js) | ||
[![license:agpl](https://img.shields.io/badge/license-AGPL%203.0-blue.svg)](https://opensource.org/licenses/AGPL-3.0) | ||
[![dependencies:?](https://img.shields.io/npm/dm/edtf.svg)](https://www.npmjs.com/packages/edtf) | ||
[![Coverage Status](https://coveralls.io/repos/github/inukshuk/edtf.js/badge.svg?branch=master)](https://coveralls.io/github/inukshuk/edtf.js?branch=master) | ||
[![NPM version](https://img.shields.io/npm/v/edtf.svg)](https://www.npmjs.com/packages/edtf) | ||
[![License AGPL-3.0](https://img.shields.io/npm/l/edtf.svg)](https://opensource.org/licenses/AGPL-3.0) | ||
Extended Date Time Format (EDTF) / ISO 8601-2 parser and library for | ||
Javascript. | ||
An Extended Date Time Format (EDTF) / ISO 8601-2 parser and toolkit for | ||
date/time hackers and enthusiasts. | ||
## Compatibility | ||
### EDFT / ISO 8601-2 | ||
EDTF.js fully implements [EDTF](http://www.loc.gov/standards/datetime) | ||
levels 0, 1, and 2 as specified by WD 2016-02-16 of ISO 8601-2. | ||
## Installation | ||
### Node.js | ||
$ npm install edtf | ||
EDTF.js is written in ES6 and therefore requires Node.js 6+. You should | ||
be able to use it in Node 4 or 5 when setting the appropriate | ||
`--harmony` flags or by using your favourite transpiler. | ||
### Browser | ||
EDTF.js was written for Node.js. While we don't currently provide a | ||
browser package, it should be easily possible to create one using | ||
browserify or similar tools. | ||
## Parser | ||
## Generator | ||
## API | ||
## Credits | ||
The EDTF.js parser is based on the awesome | ||
[nearley](https://github.com/Hardmath123/nearley) parser generator. | ||
The EDTF.js generator uses the ingenious | ||
[randexp](https://github.com/fent/randexp.js). | ||
## License | ||
AGPL-3.0 |
@@ -8,3 +8,3 @@ 'use strict' | ||
const SYMBOLS = /[xX]/g | ||
const PATTERN = /^[0-9xX]{8}$/ | ||
const PATTERN = /^[0-9xXdDmMyY]{8}$/ | ||
const YYYYMMDD = 'YYYYMMDD'.split('') | ||
@@ -38,16 +38,18 @@ const MAXDAYS = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] | ||
if (value instanceof Bitmask) return value.value | ||
switch (typeof value) { | ||
case 'number': return value | ||
case 'number': return value | ||
case 'boolean': return value ? Bitmask.YMD : 0 | ||
case 'boolean': return value ? Bitmask.YMD : 0 | ||
case 'string': | ||
if (DAY.test(value)) return Bitmask.DAY | ||
if (MONTH.test(value)) return Bitmask.MONTH | ||
if (YEAR.test(value)) return Bitmask.YEAR | ||
if (PATTERN.test(value)) return Bitmask.compute(value) | ||
// fall through! | ||
case 'string': | ||
if (DAY.test(value)) return Bitmask.DAY | ||
if (MONTH.test(value)) return Bitmask.MONTH | ||
if (YEAR.test(value)) return Bitmask.YEAR | ||
if (PATTERN.test(value)) return Bitmask.compute(value) | ||
// fall through! | ||
default: | ||
throw new Error(`invalid value: ${value}`) | ||
default: | ||
throw new Error(`invalid value: ${value}`) | ||
} | ||
@@ -76,9 +78,7 @@ } | ||
static normalize(values) { | ||
if (values.length > 1) { | ||
if (values.length > 1) | ||
values[1] = Math.min(11, Math.max(0, values[1] - 1)) | ||
} | ||
if (values.length > 2) { | ||
if (values.length > 2) | ||
values[2] = Math.min(MAXDAYS[values[1]] || NaN, Math.max(1, values[2])) | ||
} | ||
@@ -120,2 +120,42 @@ return values | ||
masks(values, symbol = 'X') { | ||
let offset = 0 | ||
return values.map(value => { | ||
let mask = this.mask(value.split(''), offset, symbol) | ||
offset = offset + mask.length | ||
return mask.join('') | ||
}) | ||
} | ||
marks(values, symbol = '?') { | ||
return values | ||
.map((value, idx) => [ | ||
this.qualified(idx * 2) ? symbol : '', | ||
value, | ||
this.qualified(idx * 2 + 1) ? symbol : '' | ||
].join('')) | ||
} | ||
qualified(idx) { // eslint-disable-line complexity | ||
switch (idx) { | ||
case 1: | ||
return this.value === Bitmask.YEAR || | ||
(this.value & Bitmask.YEAR) && !(this.value & Bitmask.MONTH) | ||
case 2: | ||
return this.value === Bitmask.MONTH || | ||
(this.value & Bitmask.MONTH) && !(this.value & Bitmask.YEAR) | ||
case 3: | ||
return this.value === Bitmask.YM | ||
case 4: | ||
return this.value === Bitmask.DAY || | ||
(this.value & Bitmask.DAY) && (this.value !== Bitmask.YMD) | ||
case 5: | ||
return this.value === Bitmask.YMD | ||
default: | ||
return false | ||
} | ||
} | ||
qualify(idx) { | ||
@@ -130,7 +170,3 @@ return (this.value = this.value | Bitmask.UA[idx]), this | ||
toString(symbol = 'X') { | ||
return [ | ||
this.mask(['Y', 'Y', 'Y', 'Y'], 0, symbol).join(''), | ||
this.mask(['M', 'M'], 4, symbol).join(''), | ||
this.mask(['D', 'D'], 6, symbol).join('') | ||
].join('-') | ||
return this.masks(['YYYY', 'MM', 'DD'], symbol).join('-') | ||
} | ||
@@ -157,3 +193,3 @@ } | ||
* | ||
* ~YYYY~-2MM3-4DD5 | ||
* ~YYYY~-~MM~-~DD~ | ||
* 0 1 2 3 4 5 | ||
@@ -163,6 +199,6 @@ */ | ||
Bitmask.YEAR, | ||
Bitmask.YEAR, | ||
Bitmask.YEAR, // YEAR !DAY | ||
Bitmask.MONTH, | ||
Bitmask.YM, | ||
Bitmask.DAY, | ||
Bitmask.DAY, // YEARDAY | ||
Bitmask.YMD | ||
@@ -169,0 +205,0 @@ ] |
276
src/date.js
'use strict' | ||
const assert = require('assert') | ||
const Bitmask = require('./bitmask') | ||
const { parse } = require('./parser') | ||
const { abs } = Math | ||
const { isArray } = Array | ||
const P = new WeakMap() | ||
const U = new WeakMap() | ||
const A = new WeakMap() | ||
const X = new WeakMap() | ||
class ExtDate extends Date { | ||
constructor(...args) { | ||
if (args.length === 1 && typeof args[0] === 'object') { | ||
// TODO | ||
static parse(input) { | ||
return parse(input, { types: ['Date'] }) | ||
} | ||
static from(input) { | ||
return (input instanceof ExtDate) ? input : new ExtDate(input) | ||
} | ||
constructor(...args) { // eslint-disable-line complexity | ||
let precision = 0 | ||
let uncertain, approximate, unspecified | ||
switch (args.length) { | ||
case 0: | ||
break | ||
case 1: | ||
switch (typeof args[0]) { | ||
case 'number': | ||
break | ||
case 'string': | ||
args = [ExtDate.parse(args[0])] | ||
// eslint-disable-line no-fallthrough | ||
case 'object': | ||
if (isArray(args[0])) | ||
args[0] = { values: args[0] } | ||
{ | ||
let obj = args[0] | ||
assert(obj != null) | ||
if (obj.type) assert.equal('Date', obj.type) | ||
if (obj.values && obj.values.length) { | ||
precision = obj.values.length | ||
args = obj.values.slice() | ||
// ECMA Date constructor needs at least two date parts! | ||
if (args.length < 2) args.push(0) | ||
if (obj.offset) { | ||
if (args.length < 3) args.push(1) | ||
while (args.length < 5) args.push(0) | ||
// ECMA Date constructor handles overflows so we | ||
// simply add the offset! | ||
args[4] = args[4] + obj.offset | ||
} | ||
args = [Date.UTC(...args)] | ||
// ECMA Date constructor converts 0-99 to 1900-1999! | ||
if (obj.values[0] >= 0 && obj.values[0] < 100) | ||
args[0] = adj(new Date(args[0])) | ||
} | ||
({ uncertain, approximate, unspecified } = obj) | ||
} | ||
break | ||
default: | ||
throw new RangeError('Invalid time value') | ||
} | ||
break | ||
default: | ||
precision = args.length | ||
} | ||
super(...args) | ||
this.precision = precision | ||
this.uncertain = uncertain | ||
this.approximate = approximate | ||
this.unspecified = unspecified | ||
} | ||
set precision(value) { | ||
P.set(this, Number(value) % 4) | ||
} | ||
get precision() { | ||
return P.get(this) | ||
} | ||
set uncertain(value) { | ||
U.set(this, new Bitmask(value)) | ||
} | ||
get uncertain() { | ||
return U.get(this) | ||
} | ||
set approximate(value) { | ||
A.set(this, new Bitmask(value)) | ||
} | ||
get approximate() { | ||
return A.get(this) | ||
} | ||
set unspecified(value) { | ||
X.set(this, new Bitmask(value)) | ||
} | ||
get unspecified() { | ||
return X.get(this) | ||
} | ||
get type() { | ||
return 'Date' | ||
} | ||
get edtf() { | ||
return this.toEDTF() | ||
} | ||
get min() { | ||
return this.getTime() | ||
} | ||
get max() { // todo | ||
return this.getTime() | ||
} | ||
get year() { | ||
return this.getUTCFullYear() | ||
} | ||
get month() { | ||
return this.getUTCMonth() | ||
} | ||
get date() { | ||
return this.getUTCDate() | ||
} | ||
get hours() { | ||
return this.getUTCHours() | ||
} | ||
get minutes() { | ||
return this.getUTCMinutes() | ||
} | ||
get seconds() { | ||
return this.getUTCSeconds() | ||
} | ||
get values() { | ||
switch (this.precision) { | ||
case 1: | ||
return [this.year] | ||
case 2: | ||
return [this.year, this.month] | ||
case 3: | ||
return [this.year, this.month, this.date] | ||
default: | ||
return [ | ||
this.year, this.month, this.date, this.hours, this.minutes, this.seconds | ||
] | ||
} | ||
} | ||
next(k = 1) { | ||
let { values, unspecified, uncertain, approximate } = this | ||
values = values.slice(0, 3) | ||
values.push(values.pop() + k) | ||
return new ExtDate({ values, unspecified, uncertain, approximate }) | ||
} | ||
prev(k = 1) { | ||
return this.next(-k) | ||
} | ||
*until(then) { | ||
yield this | ||
if (!this.compare(then)) return | ||
yield* this.between(then) | ||
yield then | ||
} | ||
*between(then) { | ||
let cur = this | ||
let dir = this.compare(then) | ||
for (;;) { | ||
cur = cur.next(-dir) | ||
dir = cur.compare(then) | ||
if (!dir) break | ||
yield cur | ||
} | ||
} | ||
compare(other) { | ||
let [a, x, b, y] = [this.min, this.max, other.min, other.max] | ||
if (a !== b) | ||
return a < b ? -1 : 1 | ||
if (x !== y) | ||
return x < y ? -1 : 1 | ||
return 0 | ||
} | ||
toEDTF() { | ||
if (!this.precision) return this.toISOString() | ||
let values = this.values.map(ExtDate.pad) | ||
if (this.unspecified.value) | ||
return this.unspecified.masks(values).join('-') | ||
if (this.uncertain.value) | ||
values = this.uncertain.marks(values, '?') | ||
if (this.approximate.value) { | ||
values = this.approximate.marks(values, '~') | ||
.map(value => value.replace(/(~\?)|(\?~)/, '%')) | ||
} | ||
return values.join('-') | ||
} | ||
[Symbol.toPrimitive](hint) { | ||
return (hint === 'number') ? this.valueOf() : this.toISOString() | ||
} | ||
static pad(number, idx = 0) { // idx 0 = year, 1 = month, ... | ||
if (!idx) { | ||
let k = abs(number) | ||
let sign = (k === number) ? '' : '-' | ||
if (k < 10) return `${sign}000${k}` | ||
if (k < 100) return `${sign}00${k}` | ||
if (k < 1000) return `${sign}0${k}` | ||
return `${number}` | ||
} | ||
if (idx === 1) number = number + 1 | ||
return (number < 10) ? `0${number}` : `${number}` | ||
} | ||
} | ||
ExtDate.prototype.toJSON = ExtDate.prototype.toEDTF | ||
function adj(date, by = 1900) { | ||
date.setUTCFullYear(date.getUTCFullYear() - by) | ||
return date.getTime() | ||
} | ||
module.exports = ExtDate |
@@ -7,4 +7,4 @@ // Generated automatically by nearley | ||
const { | ||
num, zero, nothing, pick, pluck, join, concat, merge, unknown, open, | ||
interval, list, masked, date, datetime, season, qualify | ||
num, zero, nothing, pick, pluck, join, concat, merge, century, | ||
interval, list, masked, date, datetime, season, qualify, year, decade | ||
} = require('./util') | ||
@@ -24,3 +24,6 @@ | ||
{"name": "L0i", "symbols": ["date_time", {"literal":"/"}, "date_time"], "postprocess": interval(0)}, | ||
{"name": "century", "symbols": ["d2"], "postprocess": data => ({ values: [num(data[0])], type: 'century', level: 0 })}, | ||
{"name": "century", "symbols": ["positive_century"], "postprocess": data => century(data[0])}, | ||
{"name": "century", "symbols": [{"literal":"-"}, "positive_century"], "postprocess": data => century(-data[1])}, | ||
{"name": "positive_century", "symbols": ["positive_digit", "digit"], "postprocess": num}, | ||
{"name": "positive_century", "symbols": [{"literal":"0"}, "positive_digit"], "postprocess": num}, | ||
{"name": "date_time", "symbols": ["date"], "postprocess": id}, | ||
@@ -82,7 +85,8 @@ {"name": "date_time", "symbols": ["datetime"], "postprocess": id}, | ||
{"name": "offset", "symbols": ["d01_12"], "postprocess": data => num(data[0]) * 60}, | ||
{"name": "L1", "symbols": ["date_ua"], "postprocess": id}, | ||
{"name": "L1", "symbols": ["L1X"], "postprocess": merge(0, { type: 'date', level: 1 })}, | ||
{"name": "L1", "symbols": ["L1d"], "postprocess": id}, | ||
{"name": "L1", "symbols": ["L1Y"], "postprocess": id}, | ||
{"name": "L1", "symbols": ["L1S"], "postprocess": id}, | ||
{"name": "L1", "symbols": ["L1i"], "postprocess": id}, | ||
{"name": "L1d", "symbols": ["date_ua"], "postprocess": id}, | ||
{"name": "L1d", "symbols": ["L1X"], "postprocess": merge(0, { type: 'Date', level: 1 })}, | ||
{"name": "date_ua", "symbols": ["date", "UA"], "postprocess": merge(0, 1, { level: 1 })}, | ||
@@ -92,5 +96,6 @@ {"name": "L1i", "symbols": ["L1i_date", {"literal":"/"}, "L1i_date"], "postprocess": interval(1)}, | ||
{"name": "L1i", "symbols": ["L1i_date", {"literal":"/"}, "date_time"], "postprocess": interval(1)}, | ||
{"name": "L1i_date", "symbols": [], "postprocess": unknown}, | ||
{"name": "L1i_date", "symbols": [], "postprocess": nothing}, | ||
{"name": "L1i_date", "symbols": ["date_ua"], "postprocess": id}, | ||
{"name": "L1i_date", "symbols": [{"literal":"*"}], "postprocess": open}, | ||
{"name": "L1i_date", "symbols": ["INFINITY"], "postprocess": id}, | ||
{"name": "INFINITY", "symbols": [{"literal":"*"}], "postprocess": () => Infinity}, | ||
{"name": "L1X$string$1", "symbols": [{"literal":"-"}, {"literal":"X"}, {"literal":"X"}], "postprocess": function joiner(d) {return d.join('');}}, | ||
@@ -111,5 +116,5 @@ {"name": "L1X", "symbols": ["d4", {"literal":"-"}, "md", "L1X$string$1"], "postprocess": masked()}, | ||
{"name": "L1X", "symbols": ["L1X$string$7"], "postprocess": masked()}, | ||
{"name": "L1Y", "symbols": [{"literal":"Y"}, "d5+"], "postprocess": data => date([num(data[1])], 1)}, | ||
{"name": "L1Y", "symbols": [{"literal":"Y"}, "d5+"], "postprocess": data => year([num(data[1])], 1)}, | ||
{"name": "L1Y$string$1", "symbols": [{"literal":"Y"}, {"literal":"-"}], "postprocess": function joiner(d) {return d.join('');}}, | ||
{"name": "L1Y", "symbols": ["L1Y$string$1", "d5+"], "postprocess": data => date([-num(data[1])], 1)}, | ||
{"name": "L1Y", "symbols": ["L1Y$string$1", "d5+"], "postprocess": data => year([-num(data[1])], 1)}, | ||
{"name": "UA", "symbols": [{"literal":"?"}], "postprocess": () => ({ uncertain: true })}, | ||
@@ -119,10 +124,13 @@ {"name": "UA", "symbols": [{"literal":"~"}], "postprocess": () => ({ approximate: true })}, | ||
{"name": "L1S", "symbols": ["year", {"literal":"-"}, "d21_24"], "postprocess": data => season(data, 1)}, | ||
{"name": "L2", "symbols": ["ua_date"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["L2d"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["L2Y"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["L2X"], "postprocess": merge(0, { type: 'date', level: 2 })}, | ||
{"name": "L2", "symbols": ["L2S"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["decade"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["decade", "UA"], "postprocess": merge(0, 1)}, | ||
{"name": "L2", "symbols": ["L2D"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["L2i"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["dates"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["set"], "postprocess": id}, | ||
{"name": "L2", "symbols": ["list"], "postprocess": id}, | ||
{"name": "L2d", "symbols": ["ua_date"], "postprocess": id}, | ||
{"name": "L2d", "symbols": ["L2X"], "postprocess": merge(0, { type: 'Date', level: 2 })}, | ||
{"name": "L2D", "symbols": ["decade"], "postprocess": id}, | ||
{"name": "L2D", "symbols": ["decade", "UA"], "postprocess": merge(0, 1)}, | ||
{"name": "ua_date", "symbols": ["ua_year"], "postprocess": qualify}, | ||
@@ -202,23 +210,30 @@ {"name": "ua_date", "symbols": ["ua_year_month"], "postprocess": qualify}, | ||
{"name": "L2i", "symbols": ["L2i_date", {"literal":"/"}, "date_time"], "postprocess": interval(2)}, | ||
{"name": "L2i_date", "symbols": [], "postprocess": unknown}, | ||
{"name": "L2i_date", "symbols": [], "postprocess": nothing}, | ||
{"name": "L2i_date", "symbols": ["ua_date"], "postprocess": id}, | ||
{"name": "L2i_date", "symbols": ["L2X"], "postprocess": id}, | ||
{"name": "L2i_date", "symbols": [{"literal":"*"}], "postprocess": open}, | ||
{"name": "L2i_date", "symbols": ["INFINITY"], "postprocess": id}, | ||
{"name": "L2Y", "symbols": ["exp_year"], "postprocess": id}, | ||
{"name": "L2Y", "symbols": ["exp_year", "significant_digits"], "postprocess": merge(0, 1)}, | ||
{"name": "L2Y", "symbols": ["L1Y", "significant_digits"], "postprocess": merge(0, 1, { level: 2 })}, | ||
{"name": "L2Y", "symbols": ["year", "significant_digits"], "postprocess": data => date([data[0]], 2, data[1])}, | ||
{"name": "L2Y", "symbols": ["year", "significant_digits"], "postprocess": data => year([data[0]], 2, data[1])}, | ||
{"name": "significant_digits", "symbols": [{"literal":"S"}, "positive_digit"], "postprocess": data => ({ significant: num(data[1]) })}, | ||
{"name": "exp_year", "symbols": [{"literal":"Y"}, "exp"], "postprocess": data => date([data[1]], 2)}, | ||
{"name": "exp_year", "symbols": [{"literal":"Y"}, "exp"], "postprocess": data => year([data[1]], 2)}, | ||
{"name": "exp_year$string$1", "symbols": [{"literal":"Y"}, {"literal":"-"}], "postprocess": function joiner(d) {return d.join('');}}, | ||
{"name": "exp_year", "symbols": ["exp_year$string$1", "exp"], "postprocess": data => date([-data[1]], 2)}, | ||
{"name": "exp_year", "symbols": ["exp_year$string$1", "exp"], "postprocess": data => year([-data[1]], 2)}, | ||
{"name": "exp", "symbols": ["digits", {"literal":"E"}, "digits"], "postprocess": data => num(data[0]) * Math.pow(10, num(data[2]))}, | ||
{"name": "L2S", "symbols": ["year", {"literal":"-"}, "d25_41"], "postprocess": data => season(data, 2)}, | ||
{"name": "decade", "symbols": ["d3"], "postprocess": data => ({ values: [num(data)], type: 'decade', level: 2 })}, | ||
{"name": "dates", "symbols": ["LSB", "OL", "RSB"], "postprocess": list}, | ||
{"name": "dates", "symbols": ["LLB", "OL", "RLB"], "postprocess": list}, | ||
{"name": "LSB", "symbols": [{"literal":"["}], "postprocess": () => ({ type: 'set' })}, | ||
{"name": "decade", "symbols": ["positive_decade"], "postprocess": data => decade(data[0])}, | ||
{"name": "decade$string$1", "symbols": [{"literal":"0"}, {"literal":"0"}, {"literal":"0"}], "postprocess": function joiner(d) {return d.join('');}}, | ||
{"name": "decade", "symbols": ["decade$string$1"], "postprocess": () => decade(0)}, | ||
{"name": "decade", "symbols": [{"literal":"-"}, "positive_decade"], "postprocess": data => decade(-data[1])}, | ||
{"name": "positive_decade", "symbols": ["positive_digit", "digit", "digit"], "postprocess": num}, | ||
{"name": "positive_decade", "symbols": [{"literal":"0"}, "positive_digit", "digit"], "postprocess": num}, | ||
{"name": "positive_decade$string$1", "symbols": [{"literal":"0"}, {"literal":"0"}], "postprocess": function joiner(d) {return d.join('');}}, | ||
{"name": "positive_decade", "symbols": ["positive_decade$string$1", "positive_digit"], "postprocess": num}, | ||
{"name": "set", "symbols": ["LSB", "OL", "RSB"], "postprocess": list}, | ||
{"name": "list", "symbols": ["LLB", "OL", "RLB"], "postprocess": list}, | ||
{"name": "LSB", "symbols": [{"literal":"["}], "postprocess": () => ({ type: 'Set' })}, | ||
{"name": "LSB$string$1", "symbols": [{"literal":"["}, {"literal":"."}, {"literal":"."}], "postprocess": function joiner(d) {return d.join('');}}, | ||
{"name": "LSB", "symbols": ["LSB$string$1"], "postprocess": () => ({ type: 'set', earlier: true })}, | ||
{"name": "LLB", "symbols": [{"literal":"{"}], "postprocess": () => ({ type: 'list' })}, | ||
{"name": "LSB", "symbols": ["LSB$string$1"], "postprocess": () => ({ type: 'Set', earlier: true })}, | ||
{"name": "LLB", "symbols": [{"literal":"{"}], "postprocess": () => ({ type: 'List' })}, | ||
{"name": "RSB", "symbols": [{"literal":"]"}], "postprocess": nothing}, | ||
@@ -228,8 +243,8 @@ {"name": "RSB$string$1", "symbols": [{"literal":"."}, {"literal":"."}, {"literal":"]"}], "postprocess": function joiner(d) {return d.join('');}}, | ||
{"name": "RLB", "symbols": [{"literal":"}"}], "postprocess": nothing}, | ||
{"name": "OL", "symbols": ["LI"], "postprocess": pluck(0)}, | ||
{"name": "OL", "symbols": ["OL", "_", {"literal":","}, "_", "LI"], "postprocess": pick(0, 4)}, | ||
{"name": "OL", "symbols": ["LI"], "postprocess": data => [data[0]]}, | ||
{"name": "OL", "symbols": ["OL", "_", {"literal":","}, "_", "LI"], "postprocess": data => [...data[0], data[4]]}, | ||
{"name": "LI", "symbols": ["date"], "postprocess": id}, | ||
{"name": "LI", "symbols": ["ua_date"], "postprocess": id}, | ||
{"name": "LI", "symbols": ["L2X"], "postprocess": id}, | ||
{"name": "LI", "symbols": ["consecutives"]}, | ||
{"name": "LI", "symbols": ["consecutives"], "postprocess": id}, | ||
{"name": "consecutives$string$1", "symbols": [{"literal":"."}, {"literal":"."}], "postprocess": function joiner(d) {return d.join('');}}, | ||
@@ -267,3 +282,4 @@ {"name": "consecutives", "symbols": ["year_month_day", "consecutives$string$1", "year_month_day"], "postprocess": d => [date(d[0]), date(d[2])]}, | ||
{"name": "m30x", "symbols": ["m30x$string$1"], "postprocess": join}, | ||
{"name": "d29x", "symbols": [/[0-2X]/, "dx"], "postprocess": join}, | ||
{"name": "d29x", "symbols": [{"literal":"0"}, "d1x"], "postprocess": join}, | ||
{"name": "d29x", "symbols": [/[1-2X]/, "dx"], "postprocess": join}, | ||
{"name": "d30x", "symbols": ["d29x"], "postprocess": join}, | ||
@@ -270,0 +286,0 @@ {"name": "d30x$string$1", "symbols": [{"literal":"3"}, {"literal":"0"}], "postprocess": function joiner(d) {return d.join('');}}, |
@@ -10,5 +10,12 @@ 'use strict' | ||
function limit(results, { level, types }) { | ||
if (!results.length) return results | ||
if (typeof level !== 'number') level = 2 | ||
return results.filter(res => | ||
(level >= res.level) && (!types || types.includes(res.type))) | ||
} | ||
function best(results) { | ||
if (!results || !results.length) return undefined | ||
if (results.length === 1) return results[0] | ||
if (results.length < 2) return results[0] | ||
@@ -22,9 +29,15 @@ // If there are multiple results, pick the first | ||
parse(input) { | ||
let nep = module.exports.parser() | ||
let res = best(nep.feed(input).results) | ||
parse(input, constraints = {}) { | ||
try { | ||
let nep = module.exports.parser() | ||
let res = best(limit(nep.feed(input).results, constraints)) | ||
if (!res) throw new Error('edtf: No possible parsings (@EOS)') | ||
if (!res) throw new Error('edtf: No possible parsings (@EOS)') | ||
return res | ||
return res | ||
} catch (error) { | ||
error.message += ` for "${input}"` | ||
throw error | ||
} | ||
}, | ||
@@ -31,0 +44,0 @@ |
@@ -36,5 +36,4 @@ 'use strict' | ||
merge(...args) { | ||
if (typeof args[args.length - 1] === 'object') { | ||
if (typeof args[args.length - 1] === 'object') | ||
var extra = args.pop() | ||
} | ||
@@ -47,3 +46,3 @@ return data => assign(args.reduce((a, i) => assign(a, data[i]), {}), extra) | ||
values: [data[0], data[2]], | ||
type: 'interval', | ||
type: 'Interval', | ||
level | ||
@@ -66,3 +65,3 @@ }) | ||
return assign({ | ||
type: 'date', | ||
type: 'Date', | ||
level, | ||
@@ -73,2 +72,26 @@ values: Bitmask.normalize(values.map(Number)) | ||
year(values, level = 1, extra = null) { | ||
return assign({ | ||
type: 'Year', | ||
level, | ||
values: values.map(Number) | ||
}, extra) | ||
}, | ||
century(century, level = 0) { | ||
return { | ||
type: 'Century', | ||
level, | ||
values: [century] | ||
} | ||
}, | ||
decade(decade, level = 2) { | ||
return { | ||
type: 'Decade', | ||
level, | ||
values: [decade] | ||
} | ||
}, | ||
datetime(data) { | ||
@@ -78,3 +101,3 @@ return { | ||
offset: data[3], | ||
type: 'datetime', | ||
type: 'Date', | ||
level: 0 | ||
@@ -86,3 +109,3 @@ } | ||
return { | ||
type: 'season', | ||
type: 'Season', | ||
level, | ||
@@ -93,10 +116,2 @@ values: [Number(data[0]), Number(data[2])] | ||
unknown() { | ||
return { type: 'unknown', level: 1, values: [] } | ||
}, | ||
open() { | ||
return { type: 'open', level: 1, values: [] } | ||
}, | ||
list(data) { | ||
@@ -103,0 +118,0 @@ return assign({ values: data[1], level: 2 }, data[0], data[2]) |
@@ -10,4 +10,25 @@ 'use strict' | ||
it('returns dates', () => | ||
it('returns dates by default', () => | ||
expect(edtf()).to.be.a.date.and.an.edtf) | ||
it('parses strings', () => { | ||
expect(edtf('2016-03')).to.be.an.edtf.and.produce([2016, 2]) | ||
expect(edtf('[2016-03]')).to.be.instanceof(edtf.Set) | ||
expect(edtf('{2016..2020}')).to.be.instanceof(edtf.List) | ||
expect(edtf('2016/2019')).to.be.instanceof(edtf.Interval) | ||
expect(edtf('2016-21')).to.be.instanceof(edtf.Season) | ||
expect(edtf('Y210001')).to.be.instanceof(edtf.Year) | ||
}) | ||
it('creates new extended date objects', () => { | ||
expect(edtf([2016, 2])).to.be.an.edtf.and.produce([2016, 2]) | ||
let a = new edtf.Date([2016]) | ||
expect(edtf(a)) | ||
.to.be.an.edtf | ||
.and.produce([2016]) | ||
.and.not.equal(a) | ||
}) | ||
}) |
@@ -5,3 +5,3 @@ 'use strict' | ||
describe('ISO 8601', () => { | ||
describe('ISO 8601-1', () => { | ||
@@ -11,6 +11,48 @@ it('YYYY-MM-DD', () => | ||
it('YYYY-MM-DDTHH:MM:SS', () => | ||
it('YYYY-MM-DDTHH:MM:SS', () => { | ||
expect(edtf('2014-12-08T11:46:42')) | ||
.to.have.ymd([2014, 11, 8]).and.hms([11, 46, 42])) | ||
.to.have.ymd([2014, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('1914-12-08T11:46:42')) | ||
.to.have.ymd([1914, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('0014-12-08T11:46:42')) | ||
.to.have.ymd([14, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('1970-12-08T11:46:42')) | ||
.to.have.ymd([1970, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('0070-12-08T11:46:42')) | ||
.to.have.ymd([70, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('1974-12-08T11:46:42')) | ||
.to.have.ymd([1974, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('0074-12-08T11:46:42')) | ||
.to.have.ymd([74, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('1899-12-31T23:59:59')) | ||
.to.have.ymd([1899, 11, 31]).and.hms([23, 59, 59]) | ||
expect(edtf('1899-12-31T24:00:00')) | ||
.to.have.ymd([1900, 0, 1]).and.hms([0, 0, 0]) | ||
expect(edtf('1900-01-01T00:00:00')) | ||
.to.have.ymd([1900, 0, 1]).and.hms([0, 0, 0]) | ||
expect(edtf('-0001-12-31T23:59:59')) | ||
.to.have.ymd([-1, 11, 31]).and.hms([23, 59, 59]) | ||
expect(edtf('-0001-12-31T24:00:00')) | ||
.to.have.ymd([0, 0, 1]).and.hms([0, 0, 0]) | ||
expect(edtf('0000-01-01T00:00:00')) | ||
.to.have.ymd([0, 0, 1]).and.hms([0, 0, 0]) | ||
expect(edtf('0000-03-01T11:46:42')) | ||
.to.have.ymd([0, 2, 1]).and.hms([11, 46, 42]) | ||
expect(edtf('0001-12-08T11:46:42')) | ||
.to.have.ymd([1, 11, 8]).and.hms([11, 46, 42]) | ||
expect(edtf('1999-12-31T23:59:59')) | ||
.to.have.ymd([1999, 11, 31]).and.hms([23, 59, 59]) | ||
expect(edtf('1999-12-31T24:00:00')) | ||
.to.have.ymd([2000, 0, 1]).and.hms([0, 0, 0]) | ||
expect(edtf('2000-01-01T00:00:00')) | ||
.to.have.ymd([2000, 0, 1]).and.hms([0, 0, 0]) | ||
}) | ||
it('YYYY-MM-DDTHH:MM:SS.sss', () => | ||
@@ -22,4 +64,8 @@ expect(edtf('2014-12-08T11:46:42.123')) | ||
it('YYYY-MM-DDTHH:MM:SSZ', () => | ||
expect(edtf('2014-12-08T11:46:42Z')) | ||
.to.have.ymd([2014, 11, 8]).and.hms([11, 46, 42])) | ||
expect(edtf('0014-12-08T11:46:42Z')) | ||
.to.have.ymd([14, 11, 8]).and.hms([11, 46, 42])) | ||
it('YYYY-MM-DDTHH:MM:SS+02:00', () => | ||
expect(edtf('2014-12-08T11:46:42+02:00')) | ||
.to.have.ymd([2014, 11, 8]).and.hms([13, 46, 42])) | ||
}) |
@@ -114,5 +114,12 @@ 'use strict' | ||
it('YY', () => | ||
expect(p('19')).to.produce([19]).at.level(0).and.be.a.century) | ||
it('YY', () => { | ||
expect(p('19')).to.produce([19]).at.level(0).and.be.a.century | ||
expect(() => p('00')).to.be.rejected | ||
}) | ||
it('-YY', () => { | ||
expect(p('-04')).to.produce([-4]).at.level(0).and.be.a.century | ||
expect(() => p('-00')).to.be.rejected | ||
}) | ||
it('YYYY/YYYY', () => | ||
@@ -237,4 +244,10 @@ expect(p('1980/1994')) | ||
it('"Y"YYYYY...', () => { | ||
expect(p('Y170002')).to.produce([170002]).at.level(1) | ||
expect(p('Y10000')).to.produce([10000]).at.level(1) | ||
expect(p('Y170002')) | ||
.to.produce([170002]).at.level(1) | ||
.and.have.type('Year') | ||
expect(p('Y10000')) | ||
.to.produce([10000]).at.level(1) | ||
.and.have.type('Year') | ||
expect(() => p('Y9999')).to.be.rejected | ||
@@ -245,4 +258,10 @@ expect(() => p('Y00001')).to.be.rejected | ||
it('"Y"-YYYYY...', () => { | ||
expect(p('Y-170002')).to.produce([-170002]).at.level(1) | ||
expect(p('Y-10000')).to.produce([-10000]).at.level(1) | ||
expect(p('Y-170002')) | ||
.to.produce([-170002]).at.level(1) | ||
.and.have.type('Year') | ||
expect(p('Y-10000')) | ||
.to.produce([-10000]).at.level(1) | ||
.and.have.type('Year') | ||
expect(() => p('Y-9999')).to.be.rejected | ||
@@ -272,11 +291,15 @@ expect(() => p('Y-00001')).to.be.rejected | ||
expect(p('/')) | ||
.to.be.an.interval.from([]).until([]).at.level(1)) | ||
.to.be.an.interval.at.level(1).and.produce([null, null])) | ||
it('*/*', () => | ||
expect(p('*/*')) | ||
.to.be.an.interval.at.level(1).and.produce([Infinity, Infinity])) | ||
it('YYYY-MM/*', () => | ||
expect(p('2016-05/*')) | ||
.to.be.an.interval.from([2016, 4]).until([]).at.level(1)) | ||
.to.be.an.interval.from([2016, 4]).at.level(1)) | ||
it('/YYYY-MM', () => | ||
expect(p('/2016-05')) | ||
.to.be.an.interval.from([]).until([2016, 4]).at.level(1)) | ||
.to.be.an.interval.until([2016, 4]).at.level(1)) | ||
}) | ||
@@ -384,5 +407,10 @@ | ||
it('YKEK', () => | ||
expect(p('Y17E7')).to.produce([170000000]).at.level(2)) | ||
expect(p('Y17E7')) | ||
.to.produce([170000000]).at.level(2) | ||
.and.have.type('Year')) | ||
it('Y-KEK', () => | ||
expect(p('Y-17E7')).to.produce([-170000000]).at.level(2)) | ||
expect(p('Y-17E7')) | ||
.to.produce([-170000000]).at.level(2) | ||
.and.have.type('Year')) | ||
@@ -392,2 +420,3 @@ it('YYYYS2', () => | ||
.to.produce([1950]).at.level(2) | ||
.and.have.type('Year') | ||
.and.have.property('significant', 2)) | ||
@@ -398,2 +427,3 @@ | ||
.to.produce([17101000]).at.level(2) | ||
.and.have.type('Year') | ||
.and.have.property('significant', 3)) | ||
@@ -404,2 +434,3 @@ | ||
.to.produce([-17101000]).at.level(2) | ||
.and.have.type('Year') | ||
.and.have.property('significant', 3)) | ||
@@ -418,5 +449,15 @@ | ||
it('YYY', () => | ||
expect(p('193')).to.produce([193]).at.level(2).and.be.a.decade) | ||
it('YYY', () => { | ||
expect(p('193')).to.produce([193]).at.level(2).and.be.a.decade | ||
expect(p('019')).to.produce([19]).at.level(2).and.be.a.decade | ||
expect(p('009')).to.produce([9]).at.level(2).and.be.a.decade | ||
expect(p('000')).to.produce([0]).at.level(2).and.be.a.decade | ||
}) | ||
it('-YYY', () => { | ||
expect(p('-193')).to.produce([-193]).at.level(2).and.be.a.decade | ||
expect(p('-019')).to.produce([-19]).at.level(2).and.be.a.decade | ||
expect(() => p('-000')).to.be.rejected | ||
}) | ||
it('YYY~', () => | ||
@@ -468,2 +509,6 @@ expect(p('197~')).to.produce([197]).at.level(2) | ||
it('[YYYY..]', () => | ||
expect(p('[1760..]')) | ||
.to.be.a.set.at.level(2).and.have.property('later', true)) | ||
it('[YYYY,YYYY-MM]', () => | ||
@@ -480,4 +525,34 @@ expect(p('[1667, 1672-12]')) | ||
.from([1960]).until([1961, 11])) | ||
it('{YYYY..}', () => | ||
expect(() => p('{1760..}')).to.be.rejected) | ||
}) | ||
describe('constrain', () => { | ||
it('by type', () => { | ||
expect(p('[1760..]', { types: ['List', 'Set'] })) | ||
.to.be.a.set.at.level(2).and.have.property('later', true) | ||
expect(() => p('[1760..]', { types: [] })).to.be.rejected | ||
expect(() => p('[1760..]', { types: ['List'] })).to.be.rejected | ||
}) | ||
it('by level', () => { | ||
expect(p('[1760..]', { level: 2 })) | ||
.to.be.a.set.at.level(2).and.have.property('later', true) | ||
expect(() => p('[1760..]', { level: 1 })).to.be.rejected | ||
expect(() => p('[1760..]', { level: 0 })).to.be.rejected | ||
}) | ||
it('by level and type', () => { | ||
expect(p('1800/1X01', { level: 2, types: ['Interval'] })) | ||
.to.be.an.interval.at.level(2) | ||
expect(() => p('1800/1X01', { level: 2, types: ['Date'] })).to.be.rejected | ||
expect(() => p('1800/1X01', { level: 1, types: ['Interval'] })) | ||
.to.be.rejected | ||
}) | ||
}) | ||
}) | ||
@@ -81,5 +81,4 @@ 'use strict' | ||
if (neg) { | ||
if (obj.hasOwnProperty(name)) { | ||
if (obj.hasOwnProperty(name)) | ||
expect(Bitmask.test(obj[name], expected)).to.eql(0) | ||
} | ||
@@ -155,24 +154,24 @@ } else { | ||
Assertion.addProperty('season', function () { | ||
expect(utils.flag(this, 'object')).to.have.type('season') | ||
expect(utils.flag(this, 'object')).to.have.type('Season') | ||
}) | ||
Assertion.addProperty('century', function () { | ||
expect(utils.flag(this, 'object')).to.have.type('century') | ||
expect(utils.flag(this, 'object')).to.have.type('Century') | ||
}) | ||
Assertion.addProperty('decade', function () { | ||
expect(utils.flag(this, 'object')).to.have.type('decade') | ||
expect(utils.flag(this, 'object')).to.have.type('Decade') | ||
}) | ||
Assertion.addProperty('interval', function () { | ||
expect(utils.flag(this, 'object')).to.have.type('interval') | ||
expect(utils.flag(this, 'object')).to.have.type('Interval') | ||
}) | ||
Assertion.addProperty('list', function () { | ||
expect(utils.flag(this, 'object')).to.have.type('list') | ||
expect(utils.flag(this, 'object')).to.have.type('List') | ||
}) | ||
Assertion.addProperty('set', function () { | ||
expect(utils.flag(this, 'object')).to.have.type('set') | ||
expect(utils.flag(this, 'object')).to.have.type('Set') | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
153862
41
2602
48
2
+ Addedrandexp@^0.4.2
+ Addeddrange@1.1.1(transitive)
+ Addedrandexp@0.4.9(transitive)
+ Addedret@0.2.2(transitive)