From 5627ac99e0681d28962e32342478a20e80d1bb6d Mon Sep 17 00:00:00 2001 From: Matthew Mueller Date: Fri, 14 Oct 2016 11:10:50 +0700 Subject: [PATCH] use standard formatting --- lib/date.js | 194 ++++++++--------- lib/norm.js | 374 +++++++++++++++++---------------- lib/parser.js | 542 ++++++++++++++++++++++++------------------------ lib/subdash.js | 27 ++- lib/symbol.js | 95 ++++----- lib/tokenize.js | 107 +++++----- lib/util.js | 259 ++++++++++++----------- 7 files changed, 793 insertions(+), 805 deletions(-) diff --git a/lib/date.js b/lib/date.js index 3716ca8..f49d534 100644 --- a/lib/date.js +++ b/lib/date.js @@ -8,19 +8,19 @@ var debug = require('debug')('date:date') * Time constants */ -var _second = 1000; -var _minute = 60 * _second; -var _hour = 60 * _minute; -var _day = 24 * _hour; -var _week = 7 * _day; -var _year = 56 * _week; -var _daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; +var _second = 1000 +var _minute = 60 * _second +var _hour = 60 * _minute +var _day = 24 * _hour +var _week = 7 * _day +var _year = 56 * _week +var _daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] /** * Expose `date` */ -module.exports = date; +module.exports = date /** * Initialize `date` @@ -30,18 +30,18 @@ module.exports = date; * @api publics */ -function date(offset) { - if(!(this instanceof date)) return new date(offset); - this._changed = {}; - this.date = new Date(offset); -}; +function date (offset) { + if (!(this instanceof date)) return new date(offset) + this._changed = {} + this.date = new Date(offset) +} /** * Clone the current date */ -date.prototype.clone = function() { - return new Date(this.date); +date.prototype.clone = function () { + return new Date(this.date) } /** @@ -51,10 +51,10 @@ date.prototype.clone = function() { * @return {Boolean} */ -date.prototype.changed = function(str) { - if (this._changed[str] === undefined) return false; - return this._changed[str]; -}; +date.prototype.changed = function (str) { + if (this._changed[str] === undefined) return false + return this._changed[str] +} /** * add or subtract seconds @@ -63,11 +63,11 @@ date.prototype.changed = function(str) { * @return {date} */ -date.prototype.second = function(n) { - var seconds = +n * _second; - this.update(seconds); - this._changed['seconds'] = true; - return this; +date.prototype.second = function (n) { + var seconds = +n * _second + this.update(seconds) + this._changed['seconds'] = true + return this } /** @@ -77,11 +77,11 @@ date.prototype.second = function(n) { * @return {date} */ -date.prototype.minute = function(n) { - var minutes = +n * _minute; - this.update(minutes); - this._changed['minutes'] = true; - return this; +date.prototype.minute = function (n) { + var minutes = +n * _minute + this.update(minutes) + this._changed['minutes'] = true + return this } /** @@ -91,11 +91,11 @@ date.prototype.minute = function(n) { * @return {date} */ -date.prototype.hour = function(n) { - var hours = +n * _hour; - this.update(hours); - this._changed['hours'] = true; - return this; +date.prototype.hour = function (n) { + var hours = +n * _hour + this.update(hours) + this._changed['hours'] = true + return this } /** @@ -105,11 +105,11 @@ date.prototype.hour = function(n) { * @return {date} */ -date.prototype.day = function(n) { - var days = +n * _day; - this.update(days); - this._changed['days'] = true; - return this; +date.prototype.day = function (n) { + var days = +n * _day + this.update(days) + this._changed['days'] = true + return this } /** @@ -119,11 +119,11 @@ date.prototype.day = function(n) { * @return {date} */ -date.prototype.week = function(n) { - var weeks = +n * _week; - this.update(weeks); - this._changed['weeks'] = true; - return this; +date.prototype.week = function (n) { + var weeks = +n * _week + this.update(weeks) + this._changed['weeks'] = true + return this } /** @@ -133,28 +133,28 @@ date.prototype.week = function(n) { * @return {Date} */ -date.prototype.month = function(n) { - var d = this.date; - var day = d.getDate(); - d.setDate(1); - var month = +n + d.getMonth(); - d.setMonth(month); +date.prototype.month = function (n) { + var d = this.date + var day = d.getDate() + d.setDate(1) + var month = +n + d.getMonth() + d.setMonth(month) // Handle dates with less days var dim = this.daysInMonth(month) - d.setDate(Math.min(dim, day)); - return this; -}; + d.setDate(Math.min(dim, day)) + return this +} /** * get the days in the month */ -date.prototype.daysInMonth = function(m) { - var dim = _daysInMonth[m]; - var leap = leapyear(this.date.getFullYear()); - return (1 == m && leap) ? 29 : 28; -}; +date.prototype.daysInMonth = function (m) { + var dim = _daysInMonth[m] + var leap = leapyear(this.date.getFullYear()) + return (1 == m && leap) ? 29 : 28 +} /** * add or subtract years @@ -163,12 +163,12 @@ date.prototype.daysInMonth = function(m) { * @return {date} */ -date.prototype.year = function(n) { - var yr = this.date.getFullYear(); - yr += +n; - this.date.setFullYear(yr); - this._changed['years'] = true; - return this; +date.prototype.year = function (n) { + var yr = this.date.getFullYear() + yr += +n + this.date.setFullYear(yr) + this._changed['years'] = true + return this } /** @@ -180,43 +180,43 @@ date.prototype.year = function(n) { * @return {date} */ -date.prototype.time = function(h, m, s, meridiem) { +date.prototype.time = function (h, m, s, meridiem) { if (h === false) { - h = this.date.getHours(); + h = this.date.getHours() } else { - h = +h || 0; - this._changed['hours'] = h; + h = +h || 0 + this._changed['hours'] = h } if (m === false) { - m = this.date.getMinutes(); + m = this.date.getMinutes() } else { - m = +m || 0; - this._changed['minutes'] = m; + m = +m || 0 + this._changed['minutes'] = m } if (s === false) { - s = this.date.getSeconds(); + s = this.date.getSeconds() } else { - s = +s || 0; - this._changed['seconds'] = s; + s = +s || 0 + this._changed['seconds'] = s } - this.date.setHours(h, m, s); - return this; -}; + this.date.setHours(h, m, s) + return this +} /** * Dynamically create day functions (sunday(n), monday(n), etc.) */ -var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; -days.forEach(function(day, i) { - date.prototype[days[i]] = function(n) { - this._changed['days'] = true; - this.updateDay(i, n); - }; -}); +var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] +days.forEach(function (day, i) { + date.prototype[days[i]] = function (n) { + this._changed['days'] = true + this.updateDay(i, n) + } +}) /** * go to day of week @@ -226,13 +226,13 @@ days.forEach(function(day, i) { * @return {date} */ -date.prototype.updateDay = function(d, n) { - n = +(n || 1); - var diff = (d - this.date.getDay() + 7) % 7; - if (n > 0) --n; - diff += (7 * n); - this.update(diff * _day); - return this; +date.prototype.updateDay = function (d, n) { + n = +(n || 1) + var diff = (d - this.date.getDay() + 7) % 7 + if (n > 0) --n + diff += (7 * n) + this.update(diff * _day) + return this } /** @@ -243,10 +243,10 @@ date.prototype.updateDay = function(d, n) { * @api private */ -date.prototype.update = function(ms) { - this.date = new Date(this.date.getTime() + ms); - return this; -}; +date.prototype.update = function (ms) { + this.date = new Date(this.date.getTime() + ms) + return this +} /** * leap year @@ -255,6 +255,6 @@ date.prototype.update = function(ms) { * @return {Boolean} */ -function leapyear(yr) { - return (yr % 4 === 0 && yr % 100 !== 0) || yr % 400 === 0; +function leapyear (yr) { + return (yr % 4 === 0 && yr % 100 !== 0) || yr % 400 === 0 } diff --git a/lib/norm.js b/lib/norm.js index 69e51d0..a1a1ffb 100644 --- a/lib/norm.js +++ b/lib/norm.js @@ -21,22 +21,22 @@ module.exports = norm /** * Preprocess a string using the human language for time CFG, return a triple of original str, preprocessed tokens, and the normal forms (extracted dates in normal forms) */ -function norm(str, offset) { +function norm (str, offset) { try { - // Production rules: CFG algorithm for human language for time - var tokObj = tokenize(str); - // console.log('p#0: parse normal forms', tokObj); - var syms = pickTokens(tokObj.symbols) || []; - // console.log('p#0: remove nulls, pick tokens', syms); - syms = reduce(syms, ['n', 'n']); - // console.log('p#1: arithmetics: [] ~ , + if n1 > n2, * else', syms); - syms = nTnRedistribute(syms); - // console.log('p#2: redistribute, [] ~ [] ', syms); - syms = reduce(syms, ['o', 'o']); - // console.log('p#3: ~ *', syms); + // Production rules: CFG algorithm for human language for time + var tokObj = tokenize(str) + // console.log('p#0: parse normal forms', tokObj) + var syms = pickTokens(tokObj.symbols) || [] + // console.log('p#0: remove nulls, pick tokens', syms) + syms = reduce(syms, ['n', 'n']) + // console.log('p#1: arithmetics: [] ~ , + if n1 > n2, * else', syms) + syms = nTnRedistribute(syms) + // console.log('p#2: redistribute, [] ~ [] ', syms) + syms = reduce(syms, ['o', 'o']) + // console.log('p#3: ~ *', syms) // preprocessing ends, now format output - var restored = restoreTokens(syms, tokObj); + var restored = restoreTokens(syms, tokObj) return restored } catch (e) { return { @@ -51,29 +51,29 @@ function norm(str, offset) { /** * format a preprocessed array of symbols back into string, using some info from tokObj */ -function restoreTokens(syms, tokObj) { +function restoreTokens (syms, tokObj) { var tokens = [], normals = [], tokensOut = tokObj.tokensOut, - tokensIn = tokObj.tokensIn; + tokensIn = tokObj.tokensIn syms = util.removeTnPlus(syms) for (var i = 0; i < syms.length; i++) { var s = syms[i], sName = util.sName(s), - token = ''; + token = '' switch (sName) { case 'n': // if token is already numeric, use it - token = (s.token.match(/^\s*[\d\.\-\+]+\s*$/)) ? s.token.trim() : s.value.toString(); - break; + token = (s.token.match(/^\s*[\d\.\-\+]+\s*$/)) ? s.token.trim() : s.value.toString() + break case 'T': // handles shits like 1 am ~ t:1h00m,dt:, am (token returned) token = restoreNormal(s) - break; + break default: // the other cases like op, o, cron, range - token = s.token.toString(); + token = s.token.toString() } // extract the protected normal string @@ -94,8 +94,8 @@ function restoreTokens(syms, tokObj) { /** * Given a T symbol, try to restore its normal form (return wrapped in JSON if it's a complete date string {normal: }), or just return the plain string as token */ -function restoreNormal(T) { - var token = T.token; +function restoreNormal (T) { + var token = T.token if (token.match(util.reT)) { // if it is normal form, convert back into the normal1 or normal2 strings var split = util.splitT(token) @@ -103,7 +103,7 @@ function restoreNormal(T) { // if it's normal2 form // either it's a date or time var dateArr = split.slice(0, 3), - timeArr = split.slice(3); + timeArr = split.slice(3) if (timeArr[0] != undefined) { // check time first, it's first signature (hour) is defined // return hh:mm @@ -122,16 +122,16 @@ function restoreNormal(T) { // handle pure dt: T that are purel displacement, e.g. week, fortnight var dtStr = '', units = _.keys(T.dt), - dt = T.dt; + dt = T.dt // accumulate dtStr for (var i = 0; i < units.length; i++) { var u = units[i], kval = parseFloat(dt[u]), // set number has default, or is 0, 1 - numStr = (kval != dt[u] || kval == 0 || Math.abs(kval) == 1) ? '' : dt[u].toString() + ' '; + numStr = (kval != dt[u] || kval == 0 || Math.abs(kval) == 1) ? '' : dt[u].toString() + ' ' // set canon from lemma only if it exists, and key is word, else use u - var canon = u; + var canon = u if (T.canon != undefined) { // and if it's also a timeUnit canon = T.canon @@ -139,11 +139,11 @@ function restoreNormal(T) { // get the lemma for u, its canon and key var lemma = util.lemma(u), lemmaCanon = lemma.canon, - lemmaKey = lemma.value; - if (lemmaKey && lemmaKey.match(/^\w+$/)) { canon = lemmaCanon }; + lemmaKey = lemma.value + if (lemmaKey && lemmaKey.match(/^\w+$/)) { canon = lemmaCanon } } // set the units, number, and canonical form of the unit - dtStr = dtStr + numStr + canon + ' '; + dtStr = dtStr + numStr + canon + ' ' } return dtStr } else { @@ -155,7 +155,6 @@ function restoreNormal(T) { // var fakes = { t: { M: '12', d: '25', m: '00' }, dt: {}, token: 't:12M25d00m,dt:' } // console.log(restoreNormal(fakes)) - /** * !Backburner for future extension: Main method: Run the CFG algorithm to parse the string, return JSON of {input, output, diffStr}. Normalize the string before Matt's algorithm runs it. * @example @@ -165,56 +164,56 @@ function restoreNormal(T) { * output: '2016-03-04T05:00:09Z', * difference: 'having lunch' } */ -function CFGproduce(str, offset) { +function CFGproduce (str, offset) { // try all the below till all is elegantly fixed var diffStr = str, finalStr = null, - output = str; - // Production rules: CFG algorithm for human language for time + output = str + // Production rules: CFG algorithm for human language for time // p#0: tokenize, remove nulls, pick tokens - var tokObj = tokenize(str); - var syms = pickTokens(tokObj.symbols); - // console.log('p#0: parse normal forms, remove nulls, pick tokens', tokObj); + var tokObj = tokenize(str) + var syms = pickTokens(tokObj.symbols) + // console.log('p#0: parse normal forms, remove nulls, pick tokens', tokObj) try { - syms = reduce(syms, ['n', 'n']); - // console.log('p#1: arithmetics: [] ~ , + if n1 > n2, * else', syms); - syms = nTnRedistribute(syms); - // console.log('p#2: redistribute, [] ~ [] ', syms); - output = util.tokenToStr(syms); + syms = reduce(syms, ['n', 'n']) + // console.log('p#1: arithmetics: [] ~ , + if n1 > n2, * else', syms) + syms = nTnRedistribute(syms) + // console.log('p#2: redistribute, [] ~ [] ', syms) + output = util.tokenToStr(syms) // !okay replace back the normal forms in the str // // !Till future completion: Mute from below - // syms = reduce(syms, ['n', 'T']); - // // console.log('p#3: [] ~ , * if dt, + if t', syms); - // syms = reduce(syms, ['T', 'T']); - // // console.log('p#4: [] ~ ', syms); - // syms = nDefTSyms(syms); - // // console.log('p#5: defaulter ~ , d defaults to t:h', syms); - // syms = reduce(syms, ['o', 'o']); - // // console.log('p#6: ~ *', syms); - // syms = autoHourModding(syms); - // syms = weekModding(syms, offset); - // // console.log('p#7: modding: meridiem, weeks', syms); - // syms = optReduce(syms, ['T', 'T'], ['o'], null, symbol(util.nowT(offset))); - // // console.log('p#8: ~ ', syms); + // syms = reduce(syms, ['n', 'T']) + // // console.log('p#3: [] ~ , * if dt, + if t', syms) + // syms = reduce(syms, ['T', 'T']) + // // console.log('p#4: [] ~ ', syms) + // syms = nDefTSyms(syms) + // // console.log('p#5: defaulter ~ , d defaults to t:h', syms) + // syms = reduce(syms, ['o', 'o']) + // // console.log('p#6: ~ *', syms) + // syms = autoHourModding(syms) + // syms = weekModding(syms, offset) + // // console.log('p#7: modding: meridiem, weeks', syms) + // syms = optReduce(syms, ['T', 'T'], ['o'], null, symbol(util.nowT(offset))) + // // console.log('p#8: ~ ', syms) // // !future: // // syms = reduce(syms, ['T'], ['r']) // // syms = reduce(syms, ['f', 'T', 'rT'], ['c']) // console.log('tokObj', tokObj) - syms = finalizeT(syms, offset); - // console.log('p#9: finalizeT with origin', syms); + syms = finalizeT(syms, offset) + // console.log('p#9: finalizeT with origin', syms) - finalStr = symsToStdT(syms, offset); - // console.log('finalStr', finalStr); + finalStr = symsToStdT(syms, offset) + // console.log('finalStr', finalStr) } catch (e) {} // extract the tokens for difference string later - // diffStr = util.unparsedStr(tokObj.str, tokObj.symbols); - // console.log('diffStr', diffStr); + // diffStr = util.unparsedStr(tokObj.str, tokObj.symbols) + // console.log('diffStr', diffStr) // !convert dt into proper terms return { @@ -235,11 +234,11 @@ function CFGproduce(str, offset) { * 3.3 pull and push the chunks containing into candidate * 4. pick the last candidate */ -function pickTokens(syms) { +function pickTokens (syms) { // 1. 2. 3. var delimited = util.delimSyms(syms), chunks = util.splitSyms(delimited, 'trinull'), - candidates = util.orderChunks(chunks); + candidates = util.orderChunks(chunks) // 4. return candidates.pop() } @@ -251,20 +250,20 @@ function pickTokens(syms) { * @param {Array} opArr String names of permissible operations. * @return {Array} The reduced result. */ -function reduce(syms, varArr, opArr) { +function reduce (syms, varArr, opArr) { if (syms.length < 2) { return syms } // the operator arrays - var opArr = opArr || ['op']; + var opArr = opArr || ['op'] // endmark for handling last symbol - syms.push('null'); + syms.push('null') // the result, past-pointer(previous non-null symbol), default-op, current-op, and whether current-op is inter-symbol op, i.e. will not be used up var res = [], past = null, defOp = null, op = defOp, - interOp = false; + interOp = false for (var i = 0; i < syms.length; i++) { var s = syms[i] if (!past || !s) { @@ -272,33 +271,33 @@ function reduce(syms, varArr, opArr) { if (i == 0) { past = s; } } else if (util.isSym(s, opArr)) { // s is an op. mark op as won't be used yet - op = s; - interOp = true; - // the nDefT for when past = 'n', s = 'o' + op = s + interOp = true + // the nDefT for when past = 'n', s = 'o' } else if (util.isSym(past, [varArr[0]]) && util.isSym(s, [varArr[1]])) { // s and past are operable variables specified by varArr - past = execOp(past, op, s); + past = execOp(past, op, s) // reset after op is used - op = defOp; - interOp = false; + op = defOp + interOp = false } else { // no further legal operation made, push and continue // change of class, past is finalized, push to res - res.push(past); + res.push(past) if (Array.isArray(past)) { // if past was returned from execOp as array (not executed), then flatten it and dont push op to res, since it's already included in op res = _.flatten(res) } else { // if inter-op (not used), push a clone (prevent overwrite later) - if (interOp) { res.push(symbol(op.value)) }; + if (interOp) { res.push(symbol(op.value)) } } // reset - op = defOp; - interOp = false; - past = s; + op = defOp + interOp = false + past = s } } - return res; + return res } /** @@ -314,7 +313,7 @@ function reduce(syms, varArr, opArr) { * @param {symbol} Rdef default for right argument * @return {Array} The reduced result. */ -function optReduce(syms, varArr, opArr, Ldef, Rdef) { +function optReduce (syms, varArr, opArr, Ldef, Rdef) { if (syms.length < 2) { return syms } @@ -322,25 +321,25 @@ function optReduce(syms, varArr, opArr, Ldef, Rdef) { var res = [], sum = null, L = null, - R = null; + R = null for (var i = 0; i < syms.length; i++) { - var s = syms[i]; + var s = syms[i] if (util.isSym(s, opArr)) { if (sum == null) { - L = syms[i - 1]; - sum = (util.isSym(L, [varArr[0]])) ? L : Ldef; - }; - R = syms[i + 1]; + L = syms[i - 1] + sum = (util.isSym(L, [varArr[0]])) ? L : Ldef + } + R = syms[i + 1] // if is var skip it since will be consumed if (util.isSym(R, [varArr[1]])) { i++; } // else reset to default else { R = Rdef; } // compute: - sum = execOp(sum, s, R); + sum = execOp(sum, s, R) // before loop quits due to possible i++, push the last if (i == syms.length - 1) { res.push(sum) - }; + } } else { // s is not opArr, can't have been varArr either // edge case: at first dont push @@ -351,7 +350,7 @@ function optReduce(syms, varArr, opArr, Ldef, Rdef) { } } } - return res; + return res } /** @@ -362,25 +361,25 @@ function optReduce(syms, varArr, opArr, Ldef, Rdef) { * @param {str} offset The time origin offset * @return {symbol} Result */ -function execOp(L, op, R, offset) { +function execOp (L, op, R, offset) { var otype = util.opType(L, op, R), - res = null; + res = null if (_.includes(['nn'], otype)) { res = nnOp(L, op, R) } else if (_.includes(['nT'], otype)) { - res = nTOp(L, op, R); + res = nTOp(L, op, R) } else if (_.includes(['TT'], otype)) { - res = TTOp(L, op, R); + res = TTOp(L, op, R) } else if (_.includes(['ToT', 'oT', 'To'], otype)) { - res = ToTOp(L, op, R, offset); + res = ToTOp(L, op, R, offset) } else if (_.includes(['oo'], otype)) { - res = ooOp(L, R); + res = ooOp(L, R) } else if (_.includes(['rT', 'TrT'], otype)) { // has optional arg - res = rTOp(L, R); + res = rTOp(L, R) } else if (_.includes(['cT', 'fcT', 'crT', 'fcrT'], otype)) { // has optional arg - res = cTOp(L, R); + res = cTOp(L, R) } else { // not executable, e.g. not in the right order, return fully res = (op == null) ? [L, R] : [L, op, R] @@ -395,26 +394,25 @@ function execOp(L, op, R, offset) { * @param {string|Number} Rval The right argument value. * @return {Number} Result from the operation. */ -function atomicOp(Lval, op, Rval, dontOp) { - dontOp = dontOp || false; - var oName = op.value; +function atomicOp (Lval, op, Rval, dontOp) { + dontOp = dontOp || false + var oName = op.value if (Lval == undefined) { // if L is missing, R must exist tho - return (oName == 'minus') ? Rval.toString().replace(/(\d)/, '-$1') : Rval; + return (oName == 'minus') ? Rval.toString().replace(/(\d)/, '-$1') : Rval } else if (Rval == undefined) { // if L exists, be it def or not, R missing - return Lval; + return Lval } else { // or R exist or is default (parse to NaN), L can be default too but ignore then var defL = Lval.toString().match(/^=/), - defR = Rval.toString().match(/^=/); + defR = Rval.toString().match(/^=/) var l = parseFloat(Lval.toString().replace(/^=/, '')), - r = parseFloat(Rval.toString().replace(/^=/, '')); + r = parseFloat(Rval.toString().replace(/^=/, '')) if (defL && defR) { // if both are default, return r 'last come last serve' return r - } else - if (defL && !defR) { + } else if (defL && !defR) { // if either default, return the non-default return r } else if (!defL && defR) { @@ -444,16 +442,16 @@ function atomicOp(Lval, op, Rval, dontOp) { /** * p#1: arithmetics: [] ~ , + if n1 > n2, * else */ -function nnOp(L, op, R) { +function nnOp (L, op, R) { var l = L.value, - r = R.value; + r = R.value // set the default op according to value in nn op if (l > r) { op = op || symbol('plus') } else { op = op || symbol('times') } - var res = atomicOp(l, op, r); + var res = atomicOp(l, op, r) return symbol(res) } @@ -461,15 +459,15 @@ function nnOp(L, op, R) { * p#2: redistribute, [] ~ [] * algorithm: note that from previous steps no 's can occur adjacently * 1. scan array L to R, on each found: - * 2.1 if its R is , continue; + * 2.1 if its R is , continue * 2.2 else, this is the target. do: * 3.1 init carry = []. remove and push into carry, * 3.2 if its L is , remove and prepend into carry, - * 4.1 find the first to the left, if not , drop the carry and continue; + * 4.1 find the first to the left, if not , drop the carry and continue * 4.2 else merge the carry after the * 5. At the end of loop, rerun production rule #1 */ -function nTnRedistribute(syms) { +function nTnRedistribute (syms) { if (syms.length < 2) { return syms } @@ -477,40 +475,40 @@ function nTnRedistribute(syms) { for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.sName(s) != 'n') { - continue; - }; + continue + } // 1. var R = syms[i + 1] if (util.sName(R) == 'T') { - continue; - }; + continue + } // 2.2 // 3.1 prepare the carry - var carry = []; + var carry = [] // 3.2 the Left symbol var L = syms[i - 1], - Li = -1; + Li = -1 if (util.sName(L) == 'op') { // if L is an 'op', remember to pull it later - Li = i - 1; - }; + Li = i - 1 + } // 4.1 // find L...L of L that is 'n' - var LLi = _.findLastIndex(syms.slice(0, i - 1), function(Ls) { + var LLi = _.findLastIndex(syms.slice(0, i - 1), function (Ls) { return util.sName(Ls) == 'n' - }); + }) if (!syms[LLi] || util.sName(syms[LLi + 1]) != 'T') { // if can't find 'n' (index = -1), or the R of 'n' isn't T, abort mission - // syms.splice(i, 0, carry); + // syms.splice(i, 0, carry) } else { // 4.2 // else, pull s at [i], optional L at [Li], and push at LLi+1 carry.push(_.pullAt(syms, i)[0]) if (Li != -1) { carry.unshift(_.pullAt(syms, Li)[0]) - }; + } syms.splice(LLi + 1, 0, carry) syms = _.flatten(syms) } @@ -518,7 +516,7 @@ function nTnRedistribute(syms) { // 5. redo the op syms = reduce(syms, ['n', 'n']) - return syms; + return syms } /** @@ -527,8 +525,8 @@ function nTnRedistribute(syms) { * 2. otherwise, if
not empty,
= *
, then return * 3. else, if not empty, = +, then return */ -function nTOp(nL, op, TR) { - var tOverrideUnit = util.highestOverride(TR.t); +function nTOp (nL, op, TR) { + var tOverrideUnit = util.highestOverride(TR.t) if (tOverrideUnit) { // 1. TR.t[tOverrideUnit] = nL.value @@ -538,7 +536,7 @@ function nTOp(nL, op, TR) { for (var k in TR.dt) { if (k == 'wd') { continue - }; + } TR.dt[k] = atomicOp(nL.value, op, TR.dt[k]) } } else if (_.keys(TR.t).length) { @@ -547,16 +545,16 @@ function nTOp(nL, op, TR) { for (var k in TR.t) { TR.t[k] = atomicOp(nL.value, op, TR.t[k]) } - }; + } return TR } /** * p#4: [] ~ */ -function TTOp(TL, op, TR) { +function TTOp (TL, op, TR) { // set the default op - op = op || symbol('plus'); + op = op || symbol('plus') // util.sName // mutate into TL for (var k in TR.t) { @@ -567,7 +565,7 @@ function TTOp(TL, op, TR) { for (var k in TR.dt) { if (k == 'wd') { continue - }; + } TL.dt[k] = atomicOp(TL.dt[k], op, TR.dt[k]) } return TL @@ -576,24 +574,24 @@ function TTOp(TL, op, TR) { /** * p#5: defaulter ~ , d defaults to t:h */ -function nDefTSyms(syms) { +function nDefTSyms (syms) { var res = [] for (var i = 0; i < syms.length; i++) { var s = syms[i] res.push(util.isSym(s, ['n']) ? nDefT(s) : s) } - return res; + return res } /** * Helper: default a singlet n to T, i.e. next available hour */ -function nDefT(n) { - var deft = symbol('t:1h,dt:'); - var nVal = n.value; - var currentHour = new Date().getHours(); - var nextnVal = Math.floor(currentHour / 12) * 12 + nVal; - var tHour = execOp(symbol(nextnVal), symbol('times'), deft); +function nDefT (n) { + var deft = symbol('t:1h,dt:') + var nVal = n.value + var currentHour = new Date().getHours() + var nextnVal = Math.floor(currentHour / 12) * 12 + nVal + var tHour = execOp(symbol(nextnVal), symbol('times'), deft) return tHour } @@ -601,17 +599,17 @@ function nDefT(n) { * ~ * * To handle 'before next' etc. */ -function ooOp(L, R) { +function ooOp (L, R) { var Lsign = (L.value == 'plus') ? +1 : -1, Rsign = (R.value == 'plus') ? +1 : -1, - LRsign = Lsign * Rsign; + LRsign = Lsign * Rsign return (LRsign > 0) ? symbol('after') : symbol('before') } /** * Next available T', given an offset, by incrementing in dt the next unit ++1 from the current largest unit in t. */ -function nextAvailable(T, offset) { +function nextAvailable (T, offset) { // find the current largest and next largest unit var nextUnit = util.nextLargestUnit(T) @@ -620,10 +618,10 @@ function nextAvailable(T, offset) { stdStr1 = util.TtoStdT(finT1), UTC1 = Date.parse(stdStr1), UTCnow = Date.parse(new Date()), - UTCdiff = UTC1 - UTCnow; + UTCdiff = UTC1 - UTCnow // if UTC1 is not in the future, add next unit if (UTCdiff < 0) { - T.dt[nextUnit] = (T.dt[nextUnit] || 0) + 1; + T.dt[nextUnit] = (T.dt[nextUnit] || 0) + 1 var finT2 = finalizeT([T], offset)[0] return finT2 } else { @@ -634,7 +632,7 @@ function nextAvailable(T, offset) { /** * p#6: ~ */ -function ToTOp(L, op, R, offset) { +function ToTOp (L, op, R, offset) { if (L && !R) { // if R is missing, set to now R = symbol(util.nowT(offset)) @@ -642,9 +640,9 @@ function ToTOp(L, op, R, offset) { // if L missing if (util.has_t(R)) { // if R has t => part of origin, so L shd be the according dt - var nextUnit = util.nextLargestUnit(R); + var nextUnit = util.nextLargestUnit(R) R = nextAvailable(R, offset) - // so arbitrarily set as 0.5 * next largest unit + // so arbitrarily set as 0.5 * next largest unit L = execOp(symbol(0.5), symbol('times'), symbol(nextUnit)) } else { // R has dt only, make L an origin then @@ -659,11 +657,11 @@ function ToTOp(L, op, R, offset) { for (var i = 0; i < Ttype.length; i++) { var _Ttype = Ttype[i], // the dontOp for 't' - dontOp = (_Ttype == 't'); + dontOp = (_Ttype == 't') var concatKeys = _.keys(L[_Ttype]).concat(_.keys(R[_Ttype])) var keys = _.unique(concatKeys) for (var j = 0; j < keys.length; j++) { - var k = keys[j]; + var k = keys[j] // run atomic op, note the reversed order of R op L R[_Ttype][k] = atomicOp(R[_Ttype][k], op, L[_Ttype][k], dontOp) } @@ -675,25 +673,25 @@ function ToTOp(L, op, R, offset) { * p#7: auto-hour-modding: t:h mod 12 * then add the meridiem to t:h if exist */ -function autoHourModding(syms) { +function autoHourModding (syms) { for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.isSym(s, ['T'])) { if (syms[i]['t']['h']) { // if t has 'h', mod it var value = syms[i]['t']['h'].toString() - var isDefault = (value.match(/^=/) || [])[0] || ''; - value = parseFloat(value.replace(/^=/, '')); - value = value > 12 ? value % 12 : value; - syms[i]['t']['h'] = isDefault + value; - }; + var isDefault = (value.match(/^=/) || [])[0] || '' + value = parseFloat(value.replace(/^=/, '')) + value = value > 12 ? value % 12 : value + syms[i]['t']['h'] = isDefault + value + } // apply the non-0 meridiem after modding: if (syms[i]['t']['mer']) { - var dt_h = (syms[i]['dt']['h'] || '0').toString(); + var dt_h = (syms[i]['dt']['h'] || '0').toString() // dump default at last dt_h = dt_h.replace(/^=/, '') if (syms[i]['t']['mer'] == 1) { - syms[i]['dt']['h'] = parseFloat(dt_h) + 12; + syms[i]['dt']['h'] = parseFloat(dt_h) + 12 } // delete mer delete syms[i]['t']['mer'] @@ -704,20 +702,20 @@ function autoHourModding(syms) { } // do it at last, to use like '2nd week of march' -function weekModding(syms, offset) { +function weekModding (syms, offset) { // weekday of the offset to calculate dt:d - var offsetWD = new Date(util.TtoStdT(util.nowT())).getDay(); + var offsetWD = new Date(util.TtoStdT(util.nowT())).getDay() for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.isSym(s, ['T'])) { if (syms[i]['dt']['wd']) { // if dt has 'wd', mod it and turn into dt:d + %wd var WD = parseInt(syms[i]['dt']['wd']) - var diffWD = (WD - offsetWD) % 7; - if (diffWD < 0) { diffWD = diffWD + 7 }; + var diffWD = (WD - offsetWD) % 7 + if (diffWD < 0) { diffWD = diffWD + 7 } syms[i]['dt']['d'] = (syms[i]['dt']['d'] || 0) + diffWD delete syms[i]['dt']['wd'] - }; + } } } return syms @@ -729,20 +727,20 @@ function weekModding(syms, offset) { * 2. add origin symbol.nowT() with given T.t, override missing units * 3. add t and dt */ -function finalizeT(syms, offset) { +function finalizeT (syms, offset) { // remove defaults for (var i = 0; i < syms.length; i++) { syms[i] = removeDefaults(syms[i]) } // default with origin at end - syms.push(symbol(util.nowT(offset))); - syms = reduce(syms, ['T', 'T']); + syms.push(symbol(util.nowT(offset))) + syms = reduce(syms, ['T', 'T']) // combine t and dt - var newSyms = []; + var newSyms = [] for (var i = 0; i < syms.length; i++) { var s = syms[i], sum = tdtAdd(s) - sum.token = util.TtoStr(sum); + sum.token = util.TtoStr(sum) newSyms.push(tdtAdd(s)) } return syms @@ -751,12 +749,12 @@ function finalizeT(syms, offset) { /** * remove the defaults before adding with origin */ -function removeDefaults(T) { +function removeDefaults (T) { for (var k in T.dt) { - T.dt[k] = T.dt[k].toString().replace(/^=/, ''); + T.dt[k] = T.dt[k].toString().replace(/^=/, '') } for (var k in T.t) { - T.t[k] = T.t[k].toString().replace(/^=/, ''); + T.t[k] = T.t[k].toString().replace(/^=/, '') } // delete meridiem too delete T['t']['mer'] @@ -767,19 +765,19 @@ function removeDefaults(T) { /** * add t and dt within a T together, delete the dt keys */ -function tdtAdd(T) { +function tdtAdd (T) { // guard for non-T if (!util.isSym(T, ['T'])) { - return T; + return T } for (var k in T.dt) { // absolute add, disregard defaults var t_k = (T.t[k] == undefined) ? 0 : T.t[k], - dt_k = T.dt[k]; + dt_k = T.dt[k] // cleanup the default - t_k = t_k.toString().replace(/^=/, ''); - dt_k = dt_k.toString().replace(/^=/, ''); - var sum = parseFloat(t_k) + parseFloat(dt_k); + t_k = t_k.toString().replace(/^=/, '') + dt_k = dt_k.toString().replace(/^=/, '') + var sum = parseFloat(t_k) + parseFloat(dt_k) // set the result, remove used dt T.t[k] = sum delete T.dt[k] @@ -793,19 +791,19 @@ function tdtAdd(T) { * if is n: return n.value * else return org token */ -function symsToStdT(syms, offset) { - var tokens = []; +function symsToStdT (syms, offset) { + var tokens = [] for (var i = 0; i < syms.length; i++) { var s = syms[i], - token = s.token.toString(); + token = s.token.toString() // default, don't switch unless: if (util.isSym(s, ['n'])) { token = s.value } else if (token.match(util.reT)) { // is normal T form token = util.TtoStdT(token, offset) - }; - tokens.push(token); + } + tokens.push(token) } return tokens.join(' ') } @@ -813,14 +811,14 @@ function symsToStdT(syms, offset) { /** * !to be implemented for range */ -function rTOp(L, R) { - var start, end; +function rTOp (L, R) { + var start, end if (!R) { - start = symbol(util.nowT()); - end = L; + start = symbol(util.nowT()) + end = L } else { - start = L; - end = R; + start = L + end = R } return symbol({ start: start, end: end }) } @@ -828,4 +826,4 @@ function rTOp(L, R) { /** * !to be implemented for cron */ -function cTOp(L, R) {} +function cTOp (L, R) {} diff --git a/lib/parser.js b/lib/parser.js index 2f55b5c..b0df8b3 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -10,7 +10,7 @@ var norm = require('./norm') * Days */ -var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; +var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] var months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ] @@ -20,20 +20,20 @@ var months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'a */ // 5, 05, 5:30, 5.30, 05:30:10, 05:30.10, 05.30.10, at 5 -var rMeridiem = /^(\d{1,2})([:.](\d{1,2}))?([:.](\d{1,2}))?\s*([ap]m)/; -var rHourMinute = /^(\d{1,2})([:.](\d{1,2}))([:.](\d{1,2}))?/; -var rAtHour = /^at\s?(\d{1,2})$/; -var rDays = /\b(sun(day)?|mon(day)?|tues(day)?|wed(nesday)?|thur(sday|s)?|fri(day)?|sat(urday)?)s?\b/; -var rMonths = /^((\d{1,2})\s*(st|nd|rd|th))\s(day\s)?(of\s)?(january|february|march|april|may|june|july|august|september|october|november|december)/i; -var rPast = /\b(last|yesterday|ago)\b/; -var rDayMod = /\b(morning|noon|afternoon|night|evening|midnight)\b/; -var rAgo = /^(\d*)\s?\b(second|minute|hour|day|week|month|year)[s]?\b\s?ago$/; +var rMeridiem = /^(\d{1,2})([:.](\d{1,2}))?([:.](\d{1,2}))?\s*([ap]m)/ +var rHourMinute = /^(\d{1,2})([:.](\d{1,2}))([:.](\d{1,2}))?/ +var rAtHour = /^at\s?(\d{1,2})$/ +var rDays = /\b(sun(day)?|mon(day)?|tues(day)?|wed(nesday)?|thur(sday|s)?|fri(day)?|sat(urday)?)s?\b/ +var rMonths = /^((\d{1,2})\s*(st|nd|rd|th))\s(day\s)?(of\s)?(january|february|march|april|may|june|july|august|september|october|november|december)/i +var rPast = /\b(last|yesterday|ago)\b/ +var rDayMod = /\b(morning|noon|afternoon|night|evening|midnight)\b/ +var rAgo = /^(\d*)\s?\b(second|minute|hour|day|week|month|year)[s]?\b\s?ago$/ /** * Expose `parser` */ -module.exports = parser; +module.exports = parser /** * Initialize `parser` @@ -43,48 +43,47 @@ module.exports = parser; * @api publics */ -function parser(str, offset) { - if (!(this instanceof parser)) return new parser(str, offset); - if (typeof offset == 'string') offset = parser(offset); +function parser (str, offset) { + if (!(this instanceof parser)) return new parser(str, offset) + if (typeof offset == 'string') offset = parser(offset) // CFG preprocessing into normalized format, // get {str, tokens, normals} // !future: return multiple parsed times, some from it - var prepro = norm(str, offset); + var prepro = norm(str, offset) // console.log(prepro) // reset the str to prepro str - str = prepro.str; + str = prepro.str // if proprocessed doesn't leave any str to be processed (non-date-time) format, check normals if (!str) { if (prepro.normals.length) { - // if there's normal date parsed already, + // if there's normal date parsed already, // !return the first return new Date(prepro.normals[0]) } else { // otherwise go back to below to return proper Error str = str } - }; - + } - var d = offset || new Date; - this.date = new date(d); - this.original = str; - this.str = str.toLowerCase(); - this.stash = []; - this.tokens = []; - while (this.advance() !== 'eos'); + var d = offset || new Date + this.date = new date(d) + this.original = str + this.str = str.toLowerCase() + this.stash = [] + this.tokens = [] + while (this.advance() !== 'eos') debug('tokens %j', this.tokens) - this.nextTime(d); - if (this.date.date == d) throw new Error('Invalid date'); - return this.date.date; -}; + this.nextTime(d) + if (this.date.date == d) throw new Error('Invalid date') + return this.date.date +} /** * Advance a token */ -parser.prototype.advance = function() { +parser.prototype.advance = function () { var tok = this.eos() || this.space() || this._next() @@ -114,11 +113,11 @@ parser.prototype.advance = function() { || this.day() || this.number() || this.string() - || this.other(); + || this.other() - this.tokens.push(tok); - return tok; -}; + this.tokens.push(tok) + return tok +} /** * Lookahead `n` tokens. @@ -128,12 +127,12 @@ parser.prototype.advance = function() { * @api private */ -parser.prototype.lookahead = function(n) { - var fetch = n - this.stash.length; - if (fetch == 0) return this.lookahead(++n); - while (fetch-- > 0) this.stash.push(this.advance()); - return this.stash[--n]; -}; +parser.prototype.lookahead = function (n) { + var fetch = n - this.stash.length + if (fetch == 0) return this.lookahead(++n) + while (fetch-- > 0) this.stash.push(this.advance()) + return this.stash[--n] +} /** * Lookahead a single token. @@ -142,9 +141,9 @@ parser.prototype.lookahead = function(n) { * @api private */ -parser.prototype.peek = function() { - return this.lookahead(1); -}; +parser.prototype.peek = function () { + return this.lookahead(1) +} /** * Fetch next token including those stashed by peek. @@ -153,10 +152,10 @@ parser.prototype.peek = function() { * @api private */ -parser.prototype.next = function() { - var tok = this.stashed() || this.advance(); - return tok; -}; +parser.prototype.next = function () { + var tok = this.stashed() || this.advance() + return tok +} /** * Return the next possibly stashed token. @@ -165,10 +164,10 @@ parser.prototype.next = function() { * @api private */ -parser.prototype.stashed = function() { - var stashed = this.stash.shift(); - return stashed; -}; +parser.prototype.stashed = function () { + var stashed = this.stash.shift() + return stashed +} /** * Consume the given `len`. @@ -177,207 +176,205 @@ parser.prototype.stashed = function() { * @api private */ -parser.prototype.skip = function(len) { - this.str = this.str.substr(Array.isArray(len) ? len[0].length : len); -}; +parser.prototype.skip = function (len) { + this.str = this.str.substr(Array.isArray(len) ? len[0].length : len) +} /** * EOS */ -parser.prototype.eos = function() { - if (this.str.length) return; - return 'eos'; -}; +parser.prototype.eos = function () { + if (this.str.length) return + return 'eos' +} /** * Space */ -parser.prototype.space = function() { - var captures; +parser.prototype.space = function () { + var captures if (captures = /^([ \t]+)/.exec(this.str)) { - this.skip(captures); - return this.advance(); + this.skip(captures) + return this.advance() } -}; +} /** * Second */ -parser.prototype.second = function() { - var captures; +parser.prototype.second = function () { + var captures if (captures = /^s(ec|econd)?s?/.exec(this.str)) { - this.skip(captures); - return 'second'; + this.skip(captures) + return 'second' } -}; +} /** * Minute */ -parser.prototype.minute = function() { - var captures; +parser.prototype.minute = function () { + var captures if (captures = /^m(in|inute)?s?/.exec(this.str)) { - this.skip(captures); - return 'minute'; + this.skip(captures) + return 'minute' } -}; +} /** * Hour */ -parser.prototype.hour = function() { - var captures; +parser.prototype.hour = function () { + var captures if (captures = /^h(r|our)s?/.exec(this.str)) { - this.skip(captures); - return 'hour'; + this.skip(captures) + return 'hour' } -}; +} /** * Day */ -parser.prototype.day = function() { - var captures; +parser.prototype.day = function () { + var captures if (captures = /^d(ay)?s?/.exec(this.str)) { - this.skip(captures); - return 'day'; + this.skip(captures) + return 'day' } -}; +} /** * Day by name */ -parser.prototype.dayByName = function() { - var captures; - var r = new RegExp('^' + rDays.source); +parser.prototype.dayByName = function () { + var captures + var r = new RegExp('^' + rDays.source) if (captures = r.exec(this.str)) { - var day = captures[1]; - this.skip(captures); - this.date[day](1); - return captures[1]; + var day = captures[1] + this.skip(captures) + this.date[day](1) + return captures[1] } -}; - +} /** * Month by name */ -parser.prototype.monthByName = function() { - var captures; +parser.prototype.monthByName = function () { + var captures if (captures = rMonths.exec(this.str)) { var day = captures[2] - var month = captures[6]; - this.date.date.setMonth((months.indexOf(month))); - if (day) this.date.date.setDate(parseInt(day)); - this.skip(captures); - return captures[0]; + var month = captures[6] + this.date.date.setMonth((months.indexOf(month))) + if (day) this.date.date.setDate(parseInt(day)) + this.skip(captures) + return captures[0] } -}; +} - -parser.prototype.timeAgo = function() { - var captures; +parser.prototype.timeAgo = function () { + var captures if (captures = rAgo.exec(this.str)) { - var num = captures[1]; - var mod = captures[2]; - this.date[mod](-num); - this.skip(captures); - return 'timeAgo'; + var num = captures[1] + var mod = captures[2] + this.date[mod](-num) + this.skip(captures) + return 'timeAgo' } -}; +} /** * Week */ -parser.prototype.week = function() { - var captures; +parser.prototype.week = function () { + var captures if (captures = /^w(k|eek)s?/.exec(this.str)) { - this.skip(captures); - return 'week'; + this.skip(captures) + return 'week' } -}; +} /** * Month */ -parser.prototype.month = function() { - var captures; +parser.prototype.month = function () { + var captures if (captures = /^mon(th)?(es|s)?\b/.exec(this.str)) { - this.skip(captures); - return 'month'; + this.skip(captures) + return 'month' } -}; +} /** * Week */ -parser.prototype.year = function() { - var captures; +parser.prototype.year = function () { + var captures if (captures = /^y(r|ear)s?/.exec(this.str)) { - this.skip(captures); - return 'year'; + this.skip(captures) + return 'year' } -}; +} /** * Meridiem am/pm */ -parser.prototype.meridiem = function() { - var captures; +parser.prototype.meridiem = function () { + var captures if (captures = rMeridiem.exec(this.str)) { - this.skip(captures); - this.time(captures[1], captures[3], captures[5], captures[6]); - return 'meridiem'; + this.skip(captures) + this.time(captures[1], captures[3], captures[5], captures[6]) + return 'meridiem' } -}; +} /** * Hour Minute (ex. 12:30) */ -parser.prototype.hourminute = function() { - var captures; +parser.prototype.hourminute = function () { + var captures if (captures = rHourMinute.exec(this.str)) { - this.skip(captures); - this.time(captures[1], captures[3], captures[5], this._meridiem); - return 'hourminute'; + this.skip(captures) + this.time(captures[1], captures[3], captures[5], this._meridiem) + return 'hourminute' } -}; +} /** * At Hour (ex. at 5) */ -parser.prototype.athour = function() { - var captures; +parser.prototype.athour = function () { + var captures if (captures = rAtHour.exec(this.str)) { - this.skip(captures); - this.time(captures[1], 0, 0, this._meridiem); - this._meridiem = null; - return 'athour'; + this.skip(captures) + this.time(captures[1], 0, 0, this._meridiem) + this._meridiem = null + return 'athour' } -}; +} /** * Time set helper */ -parser.prototype.time = function(h, m, s, meridiem) { - var d = this.date; - var before = d.clone(); +parser.prototype.time = function (h, m, s, meridiem) { + var d = this.date + var before = d.clone() if (meridiem) { // convert to 24 hour @@ -385,10 +382,10 @@ parser.prototype.time = function(h, m, s, meridiem) { h = ('am' == meridiem && 12 == h) ? 0 : h; // 12am => 0 } - m = (!m && d.changed('minutes')) ? false : m; - s = (!s && d.changed('seconds')) ? false : s; - d.time(h, m, s); -}; + m = (!m && d.changed('minutes')) ? false : m + s = (!s && d.changed('seconds')) ? false : s + d.time(h, m, s) +} /** * Best attempt to pick the next time this date will occur @@ -396,268 +393,267 @@ parser.prototype.time = function(h, m, s, meridiem) { * TODO: place at the end of the parsing */ -parser.prototype.nextTime = function(before) { - var d = this.date; - var orig = this.original; +parser.prototype.nextTime = function (before) { + var d = this.date + var orig = this.original - if (before <= d.date || rPast.test(orig)) return this; + if (before <= d.date || rPast.test(orig)) return this // If time is in the past, we need to guess at the next time if (rDays.test(orig)) { - d.day(7); + d.day(7) } else if ((before - d.date) / 1000 > 60) { // If it is a month in the past, don't add a day if (rMonths.test(orig)) { - d.day(0); + d.day(0) } else { - d.day(1); + d.day(1) } } - return this; -}; + return this +} /** * Yesterday */ -parser.prototype.yesterday = function() { - var captures; +parser.prototype.yesterday = function () { + var captures if (captures = /^(yes(terday)?)/.exec(this.str)) { - this.skip(captures); - this.date.day(-1); - return 'yesterday'; + this.skip(captures) + this.date.day(-1) + return 'yesterday' } -}; +} /** * Tomorrow */ -parser.prototype.tomorrow = function() { - var captures; +parser.prototype.tomorrow = function () { + var captures if (captures = /^tom(orrow)?/.exec(this.str)) { - this.skip(captures); - this.date.day(1); - return 'tomorrow'; + this.skip(captures) + this.date.day(1) + return 'tomorrow' } -}; +} /** * Noon */ -parser.prototype.noon = function() { - var captures; +parser.prototype.noon = function () { + var captures if (captures = /^noon\b/.exec(this.str)) { - this.skip(captures); - var before = this.date.clone(); - this.date.date.setHours(12, 0, 0); - return 'noon'; + this.skip(captures) + var before = this.date.clone() + this.date.date.setHours(12, 0, 0) + return 'noon' } -}; +} /** * Midnight */ -parser.prototype.midnight = function() { - var captures; +parser.prototype.midnight = function () { + var captures if (captures = /^midnight\b/.exec(this.str)) { - this.skip(captures); - var before = this.date.clone(); - this.date.date.setHours(0, 0, 0); - return 'midnight'; + this.skip(captures) + var before = this.date.clone() + this.date.date.setHours(0, 0, 0) + return 'midnight' } -}; +} /** * Night (arbitrarily set at 7pm) */ -parser.prototype.night = function() { - var captures; +parser.prototype.night = function () { + var captures if (captures = /^night\b/.exec(this.str)) { - this.skip(captures); - this._meridiem = 'pm'; - var before = this.date.clone(); - this.date.date.setHours(19, 0, 0); + this.skip(captures) + this._meridiem = 'pm' + var before = this.date.clone() + this.date.date.setHours(19, 0, 0) return 'night' } -}; +} /** * Evening (arbitrarily set at 5pm) */ -parser.prototype.evening = function() { - var captures; +parser.prototype.evening = function () { + var captures if (captures = /^evening\b/.exec(this.str)) { - this.skip(captures); - this._meridiem = 'pm'; - var before = this.date.clone(); - this.date.date.setHours(17, 0, 0); + this.skip(captures) + this._meridiem = 'pm' + var before = this.date.clone() + this.date.date.setHours(17, 0, 0) return 'evening' } -}; +} /** * Afternoon (arbitrarily set at 2pm) */ -parser.prototype.afternoon = function() { - var captures; +parser.prototype.afternoon = function () { + var captures if (captures = /^afternoon\b/.exec(this.str)) { - this.skip(captures); - this._meridiem = 'pm'; - var before = this.date.clone(); + this.skip(captures) + this._meridiem = 'pm' + var before = this.date.clone() - if (this.date.changed('hours')) return 'afternoon'; + if (this.date.changed('hours')) return 'afternoon' - this.date.date.setHours(14, 0, 0); - return 'afternoon'; + this.date.date.setHours(14, 0, 0) + return 'afternoon' } -}; - +} /** * Morning (arbitrarily set at 8am) */ -parser.prototype.morning = function() { - var captures; +parser.prototype.morning = function () { + var captures if (captures = /^morning\b/.exec(this.str)) { - this.skip(captures); - this._meridiem = 'am'; - var before = this.date.clone(); - if (!this.date.changed('hours')) this.date.date.setHours(8, 0, 0); - return 'morning'; + this.skip(captures) + this._meridiem = 'am' + var before = this.date.clone() + if (!this.date.changed('hours')) this.date.date.setHours(8, 0, 0) + return 'morning' } -}; +} /** * Tonight */ -parser.prototype.tonight = function() { - var captures; +parser.prototype.tonight = function () { + var captures if (captures = /^tonight\b/.exec(this.str)) { - this.skip(captures); - this._meridiem = 'pm'; - return 'tonight'; + this.skip(captures) + this._meridiem = 'pm' + return 'tonight' } -}; +} /** * Next time */ -parser.prototype._next = function() { - var captures; +parser.prototype._next = function () { + var captures if (captures = /^next/.exec(this.str)) { - this.skip(captures); - var d = new Date(this.date.date); - var mod = this.peek(); + this.skip(captures) + var d = new Date(this.date.date) + var mod = this.peek() // If we have a defined modifier, then update if (this.date[mod]) { - this.next(); + this.next() // slight hack to modify already modified - this.date = date(d); - this.date[mod](1); + this.date = date(d) + this.date[mod](1) } else if (rDayMod.test(mod)) { - this.date.day(1); + this.date.day(1) } - return 'next'; + return 'next' } -}; +} /** * Last time */ -parser.prototype.last = function() { - var captures; +parser.prototype.last = function () { + var captures if (captures = /^last/.exec(this.str)) { - this.skip(captures); - var d = new Date(this.date.date); - var mod = this.peek(); + this.skip(captures) + var d = new Date(this.date.date) + var mod = this.peek() // If we have a defined modifier, then update if (this.date[mod]) { - this.next(); + this.next() // slight hack to modify already modified - this.date = date(d); - this.date[mod](-1); + this.date = date(d) + this.date[mod](-1) } else if (rDayMod.test(mod)) { - this.date.day(-1); + this.date.day(-1) } - return 'last'; + return 'last' } -}; +} /** * Ago */ -parser.prototype.ago = function() { - var captures; +parser.prototype.ago = function () { + var captures if (captures = /^ago\b/.exec(this.str)) { - this.skip(captures); - return 'ago'; + this.skip(captures) + return 'ago' } -}; +} /** * Number */ -parser.prototype.number = function() { - var captures; +parser.prototype.number = function () { + var captures if (captures = /^(\d+)/.exec(this.str)) { - var n = captures[1]; - this.skip(captures); - var mod = this.peek(); + var n = captures[1] + this.skip(captures) + var mod = this.peek() // If we have a defined modifier, then update if (this.date[mod]) { - if ('ago' == this.peek()) n = -n; - this.date[mod](n); + if ('ago' == this.peek()) n = -n + this.date[mod](n) } else if (this._meridiem) { // when we don't have meridiem, possibly use context to guess - this.time(n, 0, 0, this._meridiem); - this._meridiem = null; + this.time(n, 0, 0, this._meridiem) + this._meridiem = null } else if (this.original.indexOf('at') > -1) { - this.time(n, 0, 0, this._meridiem); - this._meridiem = null; + this.time(n, 0, 0, this._meridiem) + this._meridiem = null } - return 'number'; + return 'number' } -}; +} /** * String */ -parser.prototype.string = function() { - var captures; +parser.prototype.string = function () { + var captures if (captures = /^\w+/.exec(this.str)) { - this.skip(captures); - return 'string'; + this.skip(captures) + return 'string' } -}; +} /** * Other */ -parser.prototype.other = function() { - var captures; +parser.prototype.other = function () { + var captures if (captures = /^./.exec(this.str)) { - this.skip(captures); - return 'other'; + this.skip(captures) + return 'other' } -}; +} diff --git a/lib/subdash.js b/lib/subdash.js index 8b8eabc..cb6074d 100644 --- a/lib/subdash.js +++ b/lib/subdash.js @@ -2,7 +2,7 @@ * Substitutes for lodash methods */ -exports.difference = function(bigArr, smallArr) { +exports.difference = function (bigArr, smallArr) { var diff = [] for (var i = 0; i < bigArr.length; i++) { var ele = bigArr[i] @@ -13,11 +13,11 @@ exports.difference = function(bigArr, smallArr) { return diff } -exports.flatten = function(arr) { +exports.flatten = function (arr) { return [].concat.apply([], arr) } -exports.find = function(arr, fn) { +exports.find = function (arr, fn) { var found = null for (var i = 0; i < arr.length; i++) { if (fn(arr[i])) { @@ -28,7 +28,7 @@ exports.find = function(arr, fn) { return found } -exports.findLastIndex = function(arr, fn) { +exports.findLastIndex = function (arr, fn) { var found = -1 for (var i = arr.length - 1; i >= 0; i--) { if (fn(arr[i])) { @@ -39,10 +39,10 @@ exports.findLastIndex = function(arr, fn) { return found } -exports.includes = function(arr, item) { +exports.includes = function (arr, item) { var found = false for (var i = 0; i < arr.length; i++) { - if (arr[i] == item) { + if (arr[i] === item) { found = true break } @@ -50,22 +50,21 @@ exports.includes = function(arr, item) { return found } -exports.isNaN = function(n) { +exports.isNaN = function (n) { return Number.isNaN(n) } -exports.keys = function(obj) { +exports.keys = function (obj) { return Object.keys(obj) } -exports.pullAt = function(arr, i) { +exports.pullAt = function (arr, i) { var res = arr.splice(i, 1) return res } -exports.unique = function(arr, i) { - return arr.filter(function(elem, pos) { - return arr.indexOf(elem) == pos; - }) +exports.unique = function (arr, i) { + return arr.filter(function (elem, pos) { + return arr.indexOf(elem) == pos + }) } - diff --git a/lib/symbol.js b/lib/symbol.js index 98b61cb..65153a6 100644 --- a/lib/symbol.js +++ b/lib/symbol.js @@ -51,11 +51,11 @@ module.exports = symbol * // an unrecognized string yields the null symbol ∅ * // => null */ -function symbol(str) { - var s; +function symbol (str) { + var s if (str == null) { // null gets null - s = null; + s = null } else if (str['start'] && str['end']) { // range: with 'start' and 'end' s = new symbolConstructors['rT'](str) @@ -66,13 +66,13 @@ function symbol(str) { // if is of the T string format t:,dt: s = str.match(/\s+/g) ? null : new symbolConstructors['T'](str) } else { - var lem = util.lemma(str); - s = lem.name ? new symbolConstructors[lem.name](lem.value, lem.name) : null; + var lem = util.lemma(str) + s = lem.name ? new symbolConstructors[lem.name](lem.value, lem.name) : null // set the canonical word from lemma - if (s) { s.canon = lem.canon }; - // set the original token for reference + if (s) { s.canon = lem.canon } + // set the original token for reference } - if (s) { s.token = str }; + if (s) { s.token = str } return s } @@ -82,45 +82,43 @@ function symbol(str) { // console.log(symbol('t:=9h,dt:12h')) // console.log(symbol('unrecognized')) - -///////////////////// +// /////////////////// // the CFG symbols // -///////////////////// - +// /////////////////// /** * The op for arithmetic operator. * note that since scaling(*,/) is very rare, we omit its implementation for now. */ -function op(value) { +function op (value) { this.value = value } /** * The origin operator. */ -function o(value) { - this.value = value; +function o (value) { + this.value = value } /** * The range operator. */ -function r(value) { +function r (value) { this.value = value } /** * The cron operator. */ -function c(value) { +function c (value) { this.value = value } /** * The n number. Calls parseFloat. */ -function n(value) { +function n (value) { this.value = parseFloat(value) } @@ -137,21 +135,21 @@ function n(value) { * new t("7h=30m") * // => t { h: '7', m: '=30' } */ -function t(value) { +function t (value) { // guard against falsy input if (!value) { - return null; + return null } // 1. see if unit is prepended with "=" for default, or set to '' // 2. then consume chunks of like "30m" while (value) { - var isDefault = (value.match(/^=/) || [])[0] || ''; - value = value.replace(/^=/, ''); + var isDefault = (value.match(/^=/) || [])[0] || '' + value = value.replace(/^=/, '') // default number is "1" - var number = (value.match(/^\-?\d+(\.\d+)?/) || [])[0] || "1"; - value = value.replace(/^\-?\d+(\.\d+)?/, ''); - var unit = (value.match(/^[a-zA-Z]+/) || [])[0]; - value = value.replace(/^[a-zA-Z]+/, ''); + var number = (value.match(/^\-?\d+(\.\d+)?/) || [])[0] || '1' + value = value.replace(/^\-?\d+(\.\d+)?/, '') + var unit = (value.match(/^[a-zA-Z]+/) || [])[0] + value = value.replace(/^[a-zA-Z]+/, '') // prepend the number (string) with isDefault, i.e. "=" or "" this[unit] = isDefault + number } @@ -163,21 +161,21 @@ function t(value) { * All values are string, to represent the "=" default in the units. so when performing numerical operation, use parseFloat. * Same keys as to allow for component-wise operation, e.g. t + dt = { ms+(d)ms, s+(d)s, ... } */ -function dt(value) { +function dt (value) { // guard against falsy input if (!value) { - return null; + return null } // 1. see if unit is prepended with "=" for default, or set to '' // 2. then consume chunks of like "30m" while (value) { - var isDefault = (value.match(/^=/) || [])[0] || ''; - value = value.replace(/^=/, ''); + var isDefault = (value.match(/^=/) || [])[0] || '' + value = value.replace(/^=/, '') // default number is "1" - var number = (value.match(/^\-?\d+(\.\d+)?/) || [])[0] || "1"; - value = value.replace(/^\-?\d+(\.\d+)?/, ''); - var unit = (value.match(/^[a-zA-Z]+/) || [])[0]; - value = value.replace(/^[a-zA-Z]+/, ''); + var number = (value.match(/^\-?\d+(\.\d+)?/) || [])[0] || '1' + value = value.replace(/^\-?\d+(\.\d+)?/, '') + var unit = (value.match(/^[a-zA-Z]+/) || [])[0] + value = value.replace(/^[a-zA-Z]+/, '') // prepend the number (string) with isDefault, i.e. "=" or "" this[unit] = isDefault + number } @@ -189,7 +187,6 @@ function dt(value) { // console.log(new t("=7h30m")) // console.log(new t().constructor.name) - /** * The T, implementation-specific, is a linear combination of and
. * Used to capture the human Ts, e.g. noon, afternoon, dawn, evening, today, tonight, Sunday, fortnight, weekdays, weekends, christmas, spring, summer, holidays etc. @@ -208,19 +205,19 @@ function dt(value) { * T.dt * // => t { h: '0' } */ -function T(value, name) { +function T (value, name) { if (name == 't') { - this.t = new t(value); - this.dt = new dt(); + this.t = new t(value) + this.dt = new dt() } else if (name == 'dt') { - this.t = new t(); - this.dt = new dt(value); + this.t = new t() + this.dt = new dt(value) } else { var split = value.split(','), _t = split[0].split(':').pop(), - _dt = split[1].split(':').pop(); - this.t = new t(_t); - this.dt = new dt(_dt); + _dt = split[1].split(':').pop() + this.t = new t(_t) + this.dt = new dt(_dt) } } @@ -231,21 +228,21 @@ function T(value, name) { /** * The product of , gives a time interval */ -function rT(interval) { - this.start = interval.start; - this.end = interval.end; +function rT (interval) { + this.start = interval.start + this.end = interval.end } /** * The f to capture frequency for . */ -function f(value) { - this.value = value; +function f (value) { + this.value = value } /** * The product of or , gives a cron time */ -function cT(cron) { +function cT (cron) { this.cron = cron } diff --git a/lib/tokenize.js b/lib/tokenize.js index 77edae4..f1cbede 100644 --- a/lib/tokenize.js +++ b/lib/tokenize.js @@ -36,23 +36,23 @@ module.exports = tokenize * @param {string} str The input string. * @return {JSON} {str, tokensIn, tokensOut, symbols} */ -function tokenize(str) { +function tokenize (str) { // split num from alphabets str = (' ' + str) .replace(/\s+(\d+)([a-zA-Z]+)/g, ' $1 $2') .replace(/\s+([a-zA-Z]+)(\d+)/g, ' $1 $2') .replace(/\s+/g, ' ') - .replace(/^\s+/, ''); + .replace(/^\s+/, '') // 1. 2. parse normal and subnormal forms var p = parseNormal12(str), pStr = p.str, tokens = pStr.split(' '), - symbols = []; + symbols = [] // clean the non-normal tokens a bit, allow to be wrapped by words only for (var i = 0; i < tokens.length; i++) { if (!tokens[i].match(util.reT)) { tokens[i] = tokens[i].replace(/^\W+/, '').replace(/\W+$/, '') - }; + } } // 3. parse english forms @@ -61,15 +61,15 @@ function tokenize(str) { var oneGram = tok, twoGram = tok + ' ' + (tokens[i + 1] || ''), oneSym = symbol(oneGram), - twoSym = symbol(twoGram); + twoSym = symbol(twoGram) if (twoSym && twoSym.value == oneSym.value) { // if lemmatization must happen for both, // pick the longer, skip next token // skip this once, reset skip - i++; - symbols.push(symbol(twoGram)); + i++ + symbols.push(symbol(twoGram)) } else { - symbols.push(symbol(oneGram)); + symbols.push(symbol(oneGram)) } } return { @@ -86,14 +86,14 @@ function tokenize(str) { * @param {string} str The input string * @return {JSON} Parsed string */ -function parseNormal12(str) { - var p1 = parseNormal1(str); +function parseNormal12 (str) { + var p1 = parseNormal1(str) // find tokens that are purely normal, and reinject into string - var p1TokensOut = p1.tokensOut.filter(notSubnormal); - var p1Str = injectNormal(str, p1TokensOut); + var p1TokensOut = p1.tokensOut.filter(notSubnormal) + var p1Str = injectNormal(str, p1TokensOut) // now parse the subnormal var p2 = parseNormal2(p1Str, [], []) - // the tokens that taken out, and their replacements, in order + // the tokens that taken out, and their replacements, in order var pTokensOut = p1.tokensOut.concat(p2.tokensOut) var pTokensIn = p1.tokensIn.concat(p2.tokensIn) return { @@ -110,40 +110,40 @@ function parseNormal12(str) { * @param {string} str The input string. * @return {string} A Date in stdT string, or null. */ -function parseNormal1(str) { +function parseNormal1 (str) { // keep chopping off tail until either get a valid date, or string runs out // array of parsed date and the string consumed var tokensIn = [], - tokensOut = []; + tokensOut = [] // ensure single spacing - str = str.replace(/\s+/g, ' '); + str = str.replace(/\s+/g, ' ') // tokenize by space - var strArr = str.split(/\s+/g); + var strArr = str.split(/\s+/g) // init the normalDate and head string used var normalDate = null, - head = ''; + head = '' // do while there's still string to go while (strArr.length) { - head = (head + ' ' + strArr.shift()).trim(); + head = (head + ' ' + strArr.shift()).trim() try { - normalDate = util.stdT(new Date(head)); + normalDate = util.stdT(new Date(head)) // Extend head: if parse successful, extend continuously until failure, then that's the longest parseable head string, ... var advanceHead = head + ' ' + strArr[0] while (1) { try { - var advanceDate = util.stdT(new Date(advanceHead)); + var advanceDate = util.stdT(new Date(advanceHead)) if (advanceDate != 'Invalid Date') { // if advanceDate is parseable, set to current, update heads - var normalDate = advanceDate; + var normalDate = advanceDate head = head + ' ' + strArr.shift() advanceHead = advanceHead + ' ' + strArr[0] } else { - break; + break } } catch (e) { // when fail, just break - break; + break } } // Shrink head: from the whole parseable head ..., trim front till we get @@ -151,46 +151,46 @@ function parseNormal1(str) { try { if (util.stdT(new Date(head.replace(/^\s*\S+\s*/, ''))) != normalDate) { // front token eaten causes change, dont update head - break; + break } else { // update head - head = head.replace(/^\s*\S+\s*/, ''); + head = head.replace(/^\s*\S+\s*/, '') } } catch (e) { - break; + break } } // only consider a valid parse if the parsed str is long enough if (head.length > 6) { - tokensIn.push(normalDate); + tokensIn.push(normalDate) // get head = only, then reset tokensOut.push(head) } head = '' } catch (e) {} } - return { tokensIn: tokensIn, tokensOut: tokensOut }; + return { tokensIn: tokensIn, tokensOut: tokensOut } } /** * 2. Parse subnormal forms after parseNormal. Gradually replace tokens of the input string while parseable. * @private */ -function parseNormal2(str, tokensIn, tokensOut) { - var m, res; +function parseNormal2 (str, tokensIn, tokensOut) { + var m, res if (m = re.MMsDDdMMsDD.exec(str)) { // 12/20 - 12/21 - var yMd1 = yMdParse(m[1], m[2]); - var yMd2 = yMdParse(m[3], m[4]); + var yMd1 = yMdParse(m[1], m[2]) + var yMd2 = yMdParse(m[3], m[4]) res = ' t:' + yMd1 + ',dt: - t:' + yMd2 + ',dt: ' } else if (m = re.MMsDDdDD.exec(str)) { // 12/22 - 23 - var yMd1 = yMdParse(m[1], m[2]); - var yMd2 = yMdParse(m[1], m[3]); + var yMd1 = yMdParse(m[1], m[2]) + var yMd2 = yMdParse(m[1], m[3]) res = ' t:' + yMd1 + ',dt: - t:' + yMd2 + ',dt: ' } else if (m = re.MMsDD.exec(str)) { // if year - var yMd = yMdParse(m[1], m[2]); + var yMd = yMdParse(m[1], m[2]) // 12/24 res = ' t:' + yMd + ',dt: ' } else if (m = re.hhcmm.exec(str)) { @@ -215,39 +215,38 @@ function parseNormal2(str, tokensIn, tokensOut) { } } - -////////////////////// +// //////////////////// // Helper functions // -////////////////////// +// //////////////////// /** * Try to parse two tokens for T form into MM/dd, or MM/yyyy if either token hsa length 4. * @private - * @param {string} token1 - * @param {string} token2 + * @param {string} token1 + * @param {string} token2 * @return {string} in the form */ -function yMdParse(token1, token2) { - var part0 = [token1, token2].filter(function(token) { +function yMdParse (token1, token2) { + var part0 = [token1, token2].filter(function (token) { return token.length == 4 }) - var part1 = [token1, token2].filter(function(token) { + var part1 = [token1, token2].filter(function (token) { return token.length != 4 }) - var y = part0[0] ? part0[0] + 'y' : ''; - var M = part1[0] + 'M'; - var d = part1[1] ? part1[1] + 'd' : ''; + var y = part0[0] ? part0[0] + 'y' : '' + var M = part1[0] + 'M' + var d = part1[1] ? part1[1] + 'd' : '' return y + M + d } /** * Check if the dateStr is strictly normal and not subnormal. Used to extract parseNormal2 overrides. * @private - * @param {string} dateStr - * @return {Boolean} + * @param {string} dateStr + * @return {Boolean} */ -function notSubnormal(dateStr) { - var subnormalStr = parseNormal2(dateStr, [], []).str; +function notSubnormal (dateStr) { + var subnormalStr = parseNormal2(dateStr, [], []).str // remove T and see if still has words var noT = subnormalStr.replace(/t\:\S*,dt\:\S*(\s*-\s*t\:\S*,dt\:\S*)?/, '') return /\w+/g.exec(noT) != null @@ -259,16 +258,16 @@ function notSubnormal(dateStr) { * @param {string} str The original string. * @param {Array} parsedArr The parsed phrases from the string. * @return {string} The string with parsed phrases replaced in T format. - * + * * @example * injectNormal('05 October 2011 14:48 UTC 08/11 2020', [ '05 October 2011 14:48 UTC', '08/11 2020' ]) * // => 't:2011y10M05d14h48m00.000s,dt: t:2020y08M11d04h00m00.000s,dt: ' */ -function injectNormal(str, parsedArr) { +function injectNormal (str, parsedArr) { for (var i = 0; i < parsedArr.length; i++) { var parsed = parsedArr[i] var T = util.stdTtoT(util.stdT(new Date(parsed))) str = str.replace(parsed, T) } - return str; + return str } diff --git a/lib/util.js b/lib/util.js index 4fe91ec..a354cd6 100644 --- a/lib/util.js +++ b/lib/util.js @@ -12,13 +12,13 @@ var maps = require('./maps.json') var reT = /t\:\S*,dt\:\S*/g /** - * The ordering of time units, large to small, + * The ordering of time units, large to small, * 'mer' is the meridiem, 0 for am, 1 for pm * and the units used for carrying */ var timeUnitOrder = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms'] -var canonTimeUnitOrder = []; +var canonTimeUnitOrder = [] for (var i = 0; i < timeUnitOrder.length; i++) { var unit = timeUnitOrder[i] canonTimeUnitOrder.push(lemma(unit).canon) @@ -30,7 +30,7 @@ var tFactor = [365, 30, 24, 60, 60] * Delimiters for stdT string */ -var stdTdelim = ['-', '-', ' ', ':', ':', '']; +var stdTdelim = ['-', '-', ' ', ':', ':', ''] /** * Export `util` @@ -74,26 +74,26 @@ module.exports = { * TtoStdT('t:10M05d14h48m00.000s,dt:') * // => 2016-10-05 14:48:00 */ -function TtoStdT(str, offset) { +function TtoStdT (str, offset) { if (typeof str != 'string') { str = TtoStr(str) - }; + } var nowStr = nowT(offset), nowArr = splitT(nowStr), - strArr = splitT(str); - var resArr = []; + strArr = splitT(str) + var resArr = [] for (var i = 0; i < nowArr.length; i++) { var val = parseFloat(strArr[i]) - if (Number.isNaN(val)) { val = parseFloat(nowArr[i]) }; + if (Number.isNaN(val)) { val = parseFloat(nowArr[i]) } resArr.push(val) } - var resStr = ''; + var resStr = '' for (var i = 0; i < stdTdelim.length; i++) { - var num = resArr[i].toString(); + var num = resArr[i].toString() // e.g. '5.123' tends to be '05.123', fix it var predecimal = /(\d+)(\.\d+)?/.exec(num)[1], postdecimal = /(\d+)\.?(\d+)?/.exec(num)[2] - if (predecimal.length == 1) { num = '0' + num }; + if (predecimal.length == 1) { num = '0' + num } if (postdecimal != null) { for (var j = 0; j < 3 - postdecimal.length; j++) { num = num + '0' @@ -109,18 +109,18 @@ function TtoStdT(str, offset) { /** * Convert a T symbol into its T string. */ -function TtoStr(T) { +function TtoStr (T) { var tStr = 't:', - dtStr = ',dt:'; + dtStr = ',dt:' for (var i = 0; i < timeUnitOrder.length; i++) { - var tUnit = timeUnitOrder[i]; + var tUnit = timeUnitOrder[i] // if unit exist, write to str if (T['t'][tUnit] != undefined) { - tStr += T['t'][tUnit] + tUnit; - }; + tStr += T['t'][tUnit] + tUnit + } if (T['dt'][tUnit] != undefined) { - dtStr += T['dt'][tUnit] + tUnit; - }; + dtStr += T['dt'][tUnit] + tUnit + } } return tStr + dtStr } @@ -130,21 +130,21 @@ function TtoStr(T) { * @param {Array} syms Of parsed symbols aka time chunks. * @return {Array} symbols delimited by 'trinull' */ -function delimSyms(syms) { +function delimSyms (syms) { // 1. // contract the nulls into trinulls in a single array var newSyms = [], - count = 0; + count = 0 for (var i = 0; i < syms.length; i++) { - var s = syms[i]; + var s = syms[i] if (s == null) { - count++; + count++ } else { if (count > 2) { newSyms.push('trinull') - }; - newSyms.push(s); - count = 0; + } + newSyms.push(s) + count = 0 } } return newSyms @@ -155,64 +155,64 @@ function delimSyms(syms) { * Check if arr has symbol whose name is listen in symArr. * @param {Array} arr Array of symbols. * @param {Array} symArr Array of symbol names. - * @return {Boolean} + * @return {Boolean} */ -function hasSym(syms, symArr) { - var found = false; +function hasSym (syms, symArr) { + var found = false for (var i = 0; i < syms.length; i++) { if (isSym(syms[i], symArr)) { found = true break - }; + } } - return found; + return found } /** * Check if T.dt is not empty */ -function has_dt(T) { +function has_dt (T) { return _.keys(T.dt).length > 0 } /** * Check if T has only t, dt with units from timeUnitOrder */ -function has_pureTimeUnit(T) { +function has_pureTimeUnit (T) { var dt = T.dt, - t = T.t; - var pure = true; + t = T.t + var pure = true for (var k in dt) { if (!_.includes(timeUnitOrder, k)) { - pure = false; - break; - }; + pure = false + break + } } for (var k in t) { if (!_.includes(timeUnitOrder, k)) { - pure = false; - break; - }; + pure = false + break + } } - return pure; + return pure } /** * Check if T.t is not empty */ -function has_t(T) { +function has_t (T) { return _.keys(T.t).length > 0 } /** * find the lowest overridable unit in t or dt */ -function highestOverride(t) { - var lowestOverable = null; +function highestOverride (t) { + var lowestOverable = null for (var i = 0; i < tOrdering.length; i++) { var unit = tOrdering[i] if (/^=/.exec(t[unit])) { - lowestOverable = unit; + lowestOverable = unit break } } @@ -223,24 +223,24 @@ function highestOverride(t) { * Check if arr has the symbol name of s. * @param {symbol} s symbol object * @param {Array} arr Of string symbol names - * @return {Boolean} + * @return {Boolean} */ -function isSym(s, arr) { +function isSym (s, arr) { return _.includes(arr, sName(s)) } /** * Find the largest enumerated unit in T.t, or if none, in T.dt */ -function largestUnit(T) { - var lu = _.find(tOrdering, function(unit) { +function largestUnit (T) { + var lu = _.find(tOrdering, function (unit) { return T.t[unit] - }); + }) if (lu == null) { - lu = _.find(tOrdering, function(unit) { + lu = _.find(tOrdering, function (unit) { return T.dt[unit] - }); - }; + }) + } return lu } @@ -253,36 +253,36 @@ function largestUnit(T) { * lemma('zero') * // => { value: '0', name: 'n' } */ -function lemma(str) { +function lemma (str) { // change all to lower case except for 'M' for month str = (str == 'M') ? str : str.toLowerCase() var lem = {}, name = null, value = null, - canon = str; - var mapsKeys = _.keys(maps); + canon = str + var mapsKeys = _.keys(maps) for (var i = 0; i < mapsKeys.length; i++) { var sMap = maps[mapsKeys[i]], - sMapKeys = _.keys(sMap); + sMapKeys = _.keys(sMap) for (var j = 0; j < sMapKeys.length; j++) { - var inflectionArr = sMap[sMapKeys[j]]; + var inflectionArr = sMap[sMapKeys[j]] if (_.includes(inflectionArr, str)) { // set the canonical form as the first in inflectionArr canon = inflectionArr[0] - // if str is in inflections + // if str is in inflections value = sMapKeys[j] break - }; + } } if (value != null) { name = mapsKeys[i] break - }; + } } // set value - lem['name'] = name; - lem['value'] = value; - lem['canon'] = canon; + lem['name'] = name + lem['value'] = value + lem['canon'] = canon return lem } // console.log(lemma('zero')) @@ -290,62 +290,62 @@ function lemma(str) { /** * Find the next largest enumerated unit in T.t, or if none, in T.dt */ -function nextLargestUnit(T) { - var lu = largestUnit(T); - return tOrdering[tOrdering.indexOf(lu) - 1]; +function nextLargestUnit (T) { + var lu = largestUnit(T) + return tOrdering[tOrdering.indexOf(lu) - 1] } /** * Convenient method to get current time in T format. * @return {string} T format string. */ -function nowT(offset) { - var dateStr = (offset == undefined) ? stdT(new Date()) : stdT(offset); +function nowT (offset) { + var dateStr = (offset == undefined) ? stdT(new Date()) : stdT(offset) return stdTtoT(dateStr) } /** * Determine the op type based on arguments */ -function opType(L, op, R) { +function opType (L, op, R) { var LsName = sName(L) || '', - RsName = sName(R) || ''; - var opsName = sName(op); - if (opsName != 'o' && opsName != 'r' && opsName != 'c') { opsName = '' }; + RsName = sName(R) || '' + var opsName = sName(op) + if (opsName != 'o' && opsName != 'r' && opsName != 'c') { opsName = '' } return LsName + opsName + RsName } /** * Order time chunks by not containing T, short to long, then containing T, short to long. Used for .pop() to get the candidate timechunk for parsing. */ -function orderChunks(matrix) { +function orderChunks (matrix) { // 2. // ok partition first then sort - var hasNoT = matrix.filter(function(row) { + var hasNoT = matrix.filter(function (row) { return !hasSym(row, ['T']) }) - var hasT = matrix.filter(function(row) { - return hasSym(row, ['T']) - }) - // matrix, sorted short to long - var lengthSortedNotTMat = hasNoT.sort(function(a, b) { + var hasT = matrix.filter(function (row) { + return hasSym(row, ['T']) + }) + // matrix, sorted short to long + var lengthSortedNotTMat = hasNoT.sort(function (a, b) { return a.length - b.length }) - var lengthSortedTMat = hasT.sort(function(a, b) { - return a.length - b.length - }) - // 3.1 3.2 3.3 + var lengthSortedTMat = hasT.sort(function (a, b) { + return a.length - b.length + }) + // 3.1 3.2 3.3 return lengthSortedNotTMat.concat(lengthSortedTMat) } /** * !remove the defaul that is 'plus' between , for defaulting to plus. - * !is a quickfix for mat + * !is a quickfix for mat */ -function removeTnPlus(syms) { +function removeTnPlus (syms) { for (var i = 0; i < syms.length; i++) { var s = syms[i] - if (isSym(s, ['op']) && s.value == 'plus' && isSym(syms[i+1], ['n'])) { + if (isSym(s, ['op']) && s.value == 'plus' && isSym(syms[i + 1], ['n'])) { syms.splice(i, 1) } } @@ -357,8 +357,8 @@ function removeTnPlus(syms) { * @param {Symbol} symbol A CFG symbol. * @return {string} name of the symbol. */ -function sName(symbol) { - return symbol ? symbol.constructor.name : null; +function sName (symbol) { + return symbol ? symbol.constructor.name : null } /** @@ -367,11 +367,11 @@ function sName(symbol) { * @param {Array} tokenArr Array of tokens to split the string by. * @return {Array} The split string array. */ -function splitByArr(str, tokenArr) { - var delim = '#{REPLACE}'; +function splitByArr (str, tokenArr) { + var delim = '#{REPLACE}' // inject into tokens for (var i = 0; i < tokenArr.length; i++) { - var token = tokenArr[i]; + var token = tokenArr[i] str = str.replace(token, delim) } // split into arr @@ -385,16 +385,16 @@ function splitByArr(str, tokenArr) { * @param {string|symbol} delimiter To split the array by * @return {matrix} delimited arrays. */ -function splitSyms(syms, delimiter) { +function splitSyms (syms, delimiter) { // split the single array into matrix var matrix = [], - newRow = []; + newRow = [] for (var i = 0; i < syms.length; i++) { - var s = syms[i]; + var s = syms[i] if (s == delimiter || sName(s) == delimiter) { // delimit and push to matrix matrix.push(newRow) - newRow = []; + newRow = [] } else if (i == syms.length - 1) { // edge case, push res newRow.push(s) @@ -410,12 +410,11 @@ function splitSyms(syms, delimiter) { /** * Split a T string into array of [_y, _M, _d, _h, _m, _s] */ -function splitT(str) { +function splitT (str) { if (!str.match(reT)) { - return null; + return null } - var - _y = (/(\d+(\.\d+)?)y/.exec(str) || [])[1], + var _y = (/(\d+(\.\d+)?)y/.exec(str) || [])[1], _M = (/(\d+(\.\d+)?)M/.exec(str) || [])[1], _w = (/(\d+(\.\d+)?)w/.exec(str) || [])[1], _d = (/(\d+(\.\d+)?)d/.exec(str) || [])[1], @@ -432,7 +431,7 @@ function splitT(str) { h: _h, m: _m, s: _s - }; + } // do the carries TO = carry(TO) @@ -449,17 +448,17 @@ function splitT(str) { * Function to properly down- and up- carry Time Object * 1. dumpweek, 2. carryDown, 3. carryUp */ -function carry(TO) { +function carry (TO) { TO = dumpWeek(TO) TO = carryDown(TO) TO = carryUp(TO) - return TO; + return TO } /** * 1. dumpWeek */ -function dumpWeek(TO) { +function dumpWeek (TO) { var _w = parseFloat(TO['w'] || '0'), _d = parseFloat(TO['d'] || '0') TO['d'] = _d + (_w * 7) @@ -470,29 +469,29 @@ function dumpWeek(TO) { /** * 2. carryDown */ -function carryDown(TO) { +function carryDown (TO) { // shall reverse the ordering and factors for opp direction var ordering = tOrdering, - factor = tFactor; - var carry = 0; + factor = tFactor + var carry = 0 for (var i = 0; i < ordering.length; i++) { // the time unit in the ordering - var u = ordering[i]; + var u = ordering[i] // skip the rest of loopbody if this unit is undefined and nothing to carry if (TO[u] == undefined && carry == 0) { - continue; + continue } // carry - TO[u] = parseFloat(TO[u] || '0') + carry; + TO[u] = parseFloat(TO[u] || '0') + carry // dont go in after the last one if (i == ordering.length - 1) { // overlong s decimal will be fixed in TtoStdT - break; - }; - var decimal = parseFloat(TO[u] || '0') - parseInt(TO[u] || '0'); + break + } + var decimal = parseFloat(TO[u] || '0') - parseInt(TO[u] || '0') if (decimal > 0) { // set next carry - carry = decimal * factor[i]; + carry = decimal * factor[i] // update current u TO[u] = parseInt(TO[u]) } else { @@ -506,28 +505,28 @@ function carryDown(TO) { /** * 3. carryUp */ -function carryUp(TO) { +function carryUp (TO) { // shall reverse the ordering and factors for opp direction var ordering = tOrdering.slice().reverse(), - factor = tFactor.slice().reverse(); - var carry = 0; + factor = tFactor.slice().reverse() + var carry = 0 for (var i = 0; i < ordering.length; i++) { // the time unit in the ordering - var u = ordering[i]; + var u = ordering[i] // skip the rest of loopbody if this unit is undefined and nothing to carry if (TO[u] == undefined && carry == 0) { - continue; + continue } // carry - TO[u] = parseFloat(TO[u] || '0') + carry; + TO[u] = parseFloat(TO[u] || '0') + carry // dont go in after the last one if (i == ordering.length - 1) { - break; - }; + break + } var deci = parseInt(parseFloat(TO[u] || '0') / factor[i]) if (deci > 0) { // set next carry - carry = deci; + carry = deci // update current u TO[u] = parseFloat(TO[u] || '0') % factor[i] } else { @@ -541,7 +540,7 @@ function carryUp(TO) { /** * Take a date or string, parse it into standard format as yyyy-MM-dd hh:mm:ss.sss */ -function stdT(date) { +function stdT (date) { if (typeof date == 'string') { date = new Date(date) } @@ -550,7 +549,7 @@ function stdT(date) { _d = date.getDate(), _date = [_y, _M, _d].join('-') _time = /(\d\S+)/.exec(date.toTimeString())[1], - format = _date + ' ' + _time + format = _date + ' ' + _time return format } @@ -560,10 +559,10 @@ function stdT(date) { * stdTtoT('2011-10-05T14:48:00.000') * // => 't:2011y10M05d14h48m00.000s,dt:' */ -function stdTtoT(str) { +function stdTtoT (str) { var datetime = str.split(' ') var date = datetime[0].split('-'), - time = datetime[1].split(':'); + time = datetime[1].split(':') return 't:' + date[0] + 'y' + date[1] + 'M' + date[2] + 'd' + time[0] + 'h' + time[1] + 'm' + time[2] + 's,dt:' } // console.log(stdTtoT('2011-10-05T14:48:00.000Z')) @@ -571,7 +570,7 @@ function stdTtoT(str) { /** * Recombine array of symbols back into str */ -function tokenToStr(syms) { +function tokenToStr (syms) { var tokens = [] for (var i = 0; i < syms.length; i++) { tokens.push(syms[i].token) @@ -582,13 +581,13 @@ function tokenToStr(syms) { /** * Extract unparsedTokens from str and parsed syms then join them */ -function unparsedStr(str, syms) { +function unparsedStr (str, syms) { var inputTokens = str.split(/\s+/) var tokens = [] for (var i = 0; i < syms.length; i++) { if (syms[i] == null) { tokens.push(inputTokens[i]) - }; + } } return tokens.join(' ') }