ambit
Advanced tools
Comparing version 1.1.1 to 1.1.2
398
ambit.js
@@ -0,1 +1,6 @@ | ||
'use strict'; | ||
// Ambit.js | ||
// (c) 2014 Michael Garvin | ||
// Ambit may be freely distributed under the MIT license. | ||
// | ||
var moment = require('moment'); | ||
@@ -10,11 +15,12 @@ var moonbeams = require('moonbeams'); | ||
moment.createFromInputFallback = function (config) { | ||
config._d = new Date(config._i); | ||
config._d = new Date(config._i); | ||
}; | ||
var SEASONS = { | ||
spring: 0, | ||
summer: 1, | ||
fall: 2, | ||
autumn: 2, | ||
winter: 3 | ||
spring: 0, | ||
summer: 1, | ||
fall: 2, | ||
autumn: 2, | ||
winter: 3 | ||
}; | ||
@@ -26,199 +32,231 @@ | ||
function getSeason(now, season, year, guessYear) { | ||
var start, end, endSeason, endYear, cal, hms; | ||
endSeason = season + 1; | ||
endYear = year; | ||
if (endSeason == 4) { | ||
endSeason = 0; | ||
endYear = Number(endYear) + 1; | ||
} | ||
cal = moonbeams.jdToCalendar(moonbeams.season(endSeason, endYear)); | ||
var getSeason = function getSeason (now, season, year, guessYear) { | ||
var start; | ||
var end; | ||
var endSeason; | ||
var endYear; | ||
var cal; | ||
var hms; | ||
endSeason = season + 1; | ||
endYear = year; | ||
if (endSeason === 4) { | ||
endSeason = 0; | ||
endYear = Number(endYear) + 1; | ||
} | ||
cal = moonbeams.jdToCalendar(moonbeams.season(endSeason, endYear)); | ||
hms = moonbeams.dayToHms(cal.day); | ||
end = moment(new Date(cal.year, cal.month - 1, cal.day, hms.hour, hms.minute, hms.second)); | ||
if (guessYear && end <= now) { | ||
cal = moonbeams.jdToCalendar(moonbeams.season(endSeason, endYear + 1)); | ||
hms = moonbeams.dayToHms(cal.day); | ||
end = moment(new Date(cal.year, cal.month - 1, cal.day, hms.hour, hms.minute, hms.second)); | ||
if (guessYear && end <= now) { | ||
cal = moonbeams.jdToCalendar(moonbeams.season(endSeason, endYear + 1)); | ||
hms = moonbeams.dayToHms(cal.day); | ||
end = moment(new Date(cal.year, cal.month - 1, cal.day, hms.hour, hms.minute, hms.second)); | ||
year = year + 1; | ||
} | ||
cal = moonbeams.jdToCalendar(moonbeams.season(season, year)); | ||
hms = moonbeams.dayToHms(cal.day); | ||
start = moment(new Date(cal.year, cal.month - 1, cal.day, hms.hour, hms.minute, hms.second)); | ||
end.subtract('seconds', 1); | ||
return { | ||
start: start, | ||
end: end | ||
}; | ||
} | ||
year = year + 1; | ||
} | ||
cal = moonbeams.jdToCalendar(moonbeams.season(season, year)); | ||
hms = moonbeams.dayToHms(cal.day); | ||
start = moment(new Date(cal.year, cal.month - 1, cal.day, hms.hour, hms.minute, hms.second)); | ||
end.subtract(1, 'seconds'); | ||
return { | ||
start: start, | ||
end: end | ||
}; | ||
}; | ||
//Very specific parser for tokens only ending in a year and nothing else | ||
function parseYear(tokens) { | ||
var result, start, end, year; | ||
tokens.forEach(function findSeason(token) { | ||
if (MONTHS.indexOf(token.slice(0, 3)) > -1) { | ||
result = true; | ||
} | ||
}); | ||
if (result) { | ||
return; //Let date parser try it next | ||
var parseYear = function parseYear (tokens) { | ||
var year; | ||
var end; | ||
var result; | ||
var start; | ||
tokens.forEach(function findSeason (token) { | ||
if (MONTHS.indexOf(token.slice(0, 3)) > -1) { | ||
result = true; | ||
} | ||
//Make sure it doesn't have a season or month in it | ||
year = tokens.slice(-1)[0]; | ||
if (!year || !year.match(YEAR_MATCH)) { | ||
return; | ||
} | ||
if (year < 100) { | ||
year = Number(year) + 2000; | ||
} | ||
start = moment(new Date(Number(year), 0, 1)); | ||
end = moment(start).add('years', 1).subtract('seconds', 1); | ||
result = { | ||
start: start, | ||
end: end | ||
}; | ||
return result; | ||
} | ||
}); | ||
if (result) { | ||
return; //Let date parser try it next | ||
} | ||
//Make sure it doesn't have a season or month in it | ||
year = tokens.slice(-1)[0]; | ||
if (!year || !year.match(YEAR_MATCH)) { | ||
return; | ||
} | ||
if (year < 100) { | ||
year = Number(year) + 2000; | ||
} | ||
start = moment(new Date(Number(year), 0, 1)); | ||
end = moment(start).add(1, 'years').subtract(1, 'seconds'); | ||
result = { | ||
start: start, | ||
end: end | ||
}; | ||
return result; | ||
}; | ||
//Actual month/day parser | ||
function monthDay(month, day, now) { | ||
var start, end; | ||
var year = new Date().getFullYear(); | ||
month = MONTHS.indexOf(month.slice(0, 3)); | ||
start = moment(new Date(year, month, day)); | ||
end = moment(start).add('days', 1).subtract('seconds', 1); | ||
if (end <= now) { | ||
start.add('years', 1); | ||
end.add('years', 1); | ||
} | ||
return {start: start, end: end}; | ||
} | ||
var monthDay = function monthDay (month, day, now) { | ||
var year = new Date().getFullYear(); | ||
month = MONTHS.indexOf(month.slice(0, 3)); | ||
var start = moment(new Date(year, month, day)); | ||
var end = moment(start).add(1, 'days').subtract(1, 'seconds'); | ||
if (end <= now) { | ||
start.add(1, 'years'); | ||
end.add(1, 'years'); | ||
} | ||
return { start: start, end: end }; | ||
}; | ||
//Very specific parser for tokens ending in either a month or a month/year or month/day | ||
function parseMonth(tokens, now) { | ||
var parsed, start, end, month, year, guessYear; | ||
year = tokens.slice(-1)[0]; | ||
if (year.match(YEAR_MATCH)) { | ||
month = tokens.slice(-2)[0]; | ||
if (year[0] === '\'') { | ||
year = year.slice(1); | ||
} else if (String(Number(year)) === year && year < 32) { | ||
return monthDay(month, year, now); | ||
} | ||
if (year < 100) { | ||
year = Number(year) + 2000; | ||
} | ||
} else { | ||
month = year; | ||
year = new Date().getFullYear(); | ||
guessYear = true; | ||
var parseMonth = function parseMonth (tokens, now) { | ||
var parsed; | ||
var start; | ||
var end; | ||
var month; | ||
var year; | ||
var guessYear; | ||
year = tokens.slice(-1)[0]; | ||
if (year.match(YEAR_MATCH)) { | ||
month = tokens.slice(-2)[0]; | ||
if (year[0] === '\'') { | ||
year = year.slice(1); | ||
} | ||
month = MONTHS.indexOf(month.slice(0, 3)); | ||
if (month === -1) { | ||
return; | ||
else if (String(Number(year)) === year && year < 32) { | ||
return monthDay(month, year, now); | ||
} | ||
start = moment(new Date(Number(year), month)); | ||
end = moment(start).add('months', 1).subtract('seconds', 1); | ||
if (guessYear && end <= now) { | ||
start.add('years', 1); | ||
end.add('years', 1); | ||
if (year < 100) { | ||
year = Number(year) + 2000; | ||
} | ||
parsed = { | ||
start: start, | ||
end: end | ||
}; | ||
return parsed; | ||
} | ||
} | ||
else { | ||
month = year; | ||
year = new Date().getFullYear(); | ||
guessYear = true; | ||
} | ||
month = MONTHS.indexOf(month.slice(0, 3)); | ||
if (month === -1) { | ||
return; | ||
} | ||
start = moment(new Date(Number(year), month)); | ||
end = moment(start).add(1, 'months').subtract(1, 'seconds'); | ||
if (guessYear && end <= now) { | ||
start.add(1, 'years'); | ||
end.add(1, 'years'); | ||
} | ||
parsed = { | ||
start: start, | ||
end: end | ||
}; | ||
return parsed; | ||
}; | ||
function parseSeason(tokens, now) { | ||
var parsed, season, year, guessYear; | ||
//Needs to end in a season or a season/year | ||
year = tokens.slice(-1)[0]; | ||
if (year.match(YEAR_MATCH)) { | ||
season = tokens.slice(-2)[0]; | ||
if (year < 100) { | ||
year = year + 2000; | ||
} | ||
} else { | ||
season = year; | ||
year = new Date().getFullYear(); | ||
guessYear = true; | ||
} | ||
season = SEASONS[season]; | ||
if (season === undefined) { | ||
return; | ||
} | ||
parsed = getSeason(now, season, year, guessYear); | ||
return parsed; | ||
} | ||
var parseSeason = function parseSeason (tokens, now) { | ||
function parseDate(tokens) { | ||
var parsed = {}; | ||
parsed.start = moment(tokens.join(' ')); | ||
if (parsed.start.toJSON() === 'Invalid date') { | ||
return; | ||
var guessYear; | ||
var parsed; | ||
var season; | ||
var year; | ||
//Needs to end in a season or a season/year | ||
year = tokens.slice(-1)[0]; | ||
if (year.match(YEAR_MATCH)) { | ||
season = tokens.slice(-2)[0]; | ||
if (year < 100) { | ||
year = year + 2000; | ||
} | ||
parsed.end = moment(parsed.start).add('days', 1).subtract('seconds', 1); | ||
return parsed; | ||
} | ||
} | ||
else { | ||
season = year; | ||
year = new Date().getFullYear(); | ||
guessYear = true; | ||
} | ||
season = SEASONS[season]; | ||
if (season === undefined) { | ||
return; | ||
} | ||
parsed = getSeason(now, season, year, guessYear); | ||
return parsed; | ||
}; | ||
function tryAll(tokens, now) { | ||
return parseSeason(tokens, now) || | ||
parseMonth(tokens, now) || | ||
parseYear(tokens, now) || | ||
parseDate(tokens); //parseDate always last | ||
} | ||
var parseDate = function parseDate (tokens) { | ||
moment.ambit = function ambit(str, format) { | ||
var result, startRange, endRange; | ||
var now = new Date(); | ||
var tokens = str.trim().toLowerCase().split(/[,\s]+/); | ||
var direction = 'right'; | ||
var current = []; | ||
var lastAttempt, currentAttempt; | ||
var parsed = {}; | ||
parsed.start = moment(tokens.join(' ')); | ||
if (parsed.start.toJSON() === 'Invalid date') { | ||
return; | ||
} | ||
parsed.end = moment(parsed.start).add(1, 'days').subtract(1, 'seconds'); | ||
return parsed; | ||
}; | ||
//Come at it left to right, once we've parsed something wait till we get an error then back up one (assumes the error was from separator language) | ||
while (direction === 'right' && tokens.length > 0) { | ||
current.push(tokens.shift()); | ||
currentAttempt = tryAll(current, now); | ||
if (currentAttempt) { | ||
lastAttempt = currentAttempt; | ||
startRange = currentAttempt; | ||
} else { | ||
if (lastAttempt) { //We don't parse now but we used to, assume we're into the separator | ||
//We're either still processing or are done | ||
tokens.unshift(current.pop()); //Undo the last shift | ||
direction = 'left'; | ||
startRange = lastAttempt; | ||
} | ||
} | ||
var tryAll = function tryAll (tokens, now) { | ||
return parseSeason(tokens, now) || | ||
parseMonth(tokens, now) || | ||
parseYear(tokens, now) || | ||
parseDate(tokens); //parseDate always last | ||
}; | ||
moment.ambit = function ambit (str, format) { | ||
var currentAttempt; | ||
var endRange; | ||
var lastAttempt; | ||
var result; | ||
var startRange; | ||
var now = new Date(); | ||
var tokens = str.trim().toLowerCase().split(/[,\s]+/); | ||
var direction = 'right'; | ||
var current = []; | ||
//Come at it left to right, once we've parsed something wait till we get an error then back up one (assumes the error was from separator language) | ||
while (direction === 'right' && tokens.length > 0) { | ||
current.push(tokens.shift()); | ||
currentAttempt = tryAll(current, now); | ||
if (currentAttempt) { | ||
lastAttempt = currentAttempt; | ||
startRange = currentAttempt; | ||
} | ||
//We go till our first match and that's that | ||
while (direction !== 'done' && tokens.length > 0) { | ||
endRange = tryAll(tokens); | ||
if (endRange) { | ||
direction = 'done'; | ||
} else { | ||
tokens.pop(); | ||
} | ||
else { | ||
if (lastAttempt) { //We don't parse now but we used to, assume we're into the separator | ||
//We're either still processing or are done | ||
tokens.unshift(current.pop()); //Undo the last shift | ||
direction = 'left'; | ||
startRange = lastAttempt; | ||
} | ||
} | ||
if (startRange) { | ||
result = { | ||
start: startRange.start, | ||
end: startRange.end | ||
}; | ||
if (endRange) { | ||
result.end = endRange.end; | ||
} | ||
if (format) { | ||
result.start = result.start.format(format); | ||
result.end = result.end.format(format); | ||
} | ||
//This should currently only happen w/ two un-yeared months | ||
if (result.start > result.end) { | ||
result.end = result.end.add('years', 1); | ||
} | ||
return result; | ||
} | ||
//We go till our first match and that's that | ||
while (direction !== 'done' && tokens.length > 0) { | ||
endRange = tryAll(tokens, now); | ||
if (endRange) { | ||
direction = 'done'; | ||
} | ||
else { | ||
tokens.pop(); | ||
} | ||
} | ||
if (startRange) { | ||
result = { | ||
start: startRange.start, | ||
end: startRange.end | ||
}; | ||
if (endRange) { | ||
result.end = endRange.end; | ||
} | ||
if (format) { | ||
result.start = result.start.format(format); | ||
result.end = result.end.format(format); | ||
} | ||
//This should currently only happen w/ two un-yeared months | ||
if (result.start > result.end) { | ||
result.end = result.end.add(1, 'years'); | ||
} | ||
return result; | ||
} | ||
}; | ||
module.exports = moment; |
{ | ||
"name": "ambit", | ||
"description": "Date parser that returns a range instead of a single value", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"author": "Michael Garvin <gar@comrade.us>", | ||
@@ -14,5 +14,8 @@ "bugs": { | ||
"devDependencies": { | ||
"jshint": "^2.5.1", | ||
"lab": "^3.2.1", | ||
"precommit-hook": "^1.0.2" | ||
"code": "^2.0.1", | ||
"eslint": "^1.10.3", | ||
"eslint-config-andyet": "^1.0.0", | ||
"eslint-plugin-hapi": "^4.0.0", | ||
"git-validate": "^2.1.2", | ||
"lab": "^8.0.0" | ||
}, | ||
@@ -33,4 +36,5 @@ "homepage": "https://github.com/wraithgar/ambit", | ||
"scripts": { | ||
"test": "make test" | ||
"test": "lab -L", | ||
"lint": "eslint ." | ||
} | ||
} |
9245
6
236
6