Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
protected parseEachUnit(text: string): DateTimeResolutionResult {
let ret = new DateTimeResolutionResult();
// handle "each month"
let match = RegExpUtility.getMatches(this.config.eachUnitRegex, text).pop();
if (!match || match.length !== text.length) {
return ret;
}
let sourceUnit = match.groups("unit").value;
if (StringUtility.isNullOrEmpty(sourceUnit) || !this.config.unitMap.has(sourceUnit)) {
return ret;
}
let getMatchedUnitTimex = this.config.getMatchedUnitTimex(sourceUnit);
if (!getMatchedUnitTimex.matched) {
return ret;
}
ret.timex = getMatchedUnitTimex.timex;
ret.futureValue = "Set: " + ret.timex;
ret.pastValue = "Set: " + ret.timex;
ret.success = true;
return ret;
}
chars.forEach(c => {
let codePoint = c.codePointAt(0) || c.charAt(0);
if (codePoint > 0xFFFF) {
// Character is in a Supplementary Unicode Plane. This is where emoji live so
// we're going to just break each character in this range out as its own token.
tokens.push(c);
if (!StringUtility.isNullOrWhitespace(token)) {
tokens.push(token);
token = '';
}
}
else if (!(this.config.tokenRegex.test(c) || StringUtility.isWhitespace(c))) {
token = token.concat(c);
}
else if (!StringUtility.isNullOrWhitespace(token)) {
tokens.push(token);
token = '';
}
});
chars.forEach(c => {
let codePoint = c.codePointAt(0) || c.charAt(0);
if (codePoint > 0xFFFF) {
// Character is in a Supplementary Unicode Plane. This is where emoji live so
// we're going to just break each character in this range out as its own token.
tokens.push(c);
if (!StringUtility.isNullOrWhitespace(token)) {
tokens.push(token);
token = '';
}
}
else if (!(this.config.tokenRegex.test(c) || StringUtility.isWhitespace(c))) {
token = token.concat(c);
}
else if (!StringUtility.isNullOrWhitespace(token)) {
tokens.push(token);
token = '';
}
});
pastDate.setMonth(pastDate.getMonth() - 1);
}
}
else {
futureDate = DateUtils.safeCreateFromMinValue(year, month + 1, day);
pastDate = DateUtils.safeCreateFromMinValue(year, month - 1, day);
}
result.futureValue = futureDate;
result.pastValue = pastDate;
result.success = true;
return result;
}
// handle "today", "the day before yesterday"
match = RegExpUtility.getMatches(this.config.specialDayRegex, trimmedSource).pop();
if (match && match.index === 0 && match.length === trimmedSource.length) {
let swift = this.config.getSwiftDay(match.value);
let today = DateUtils.safeCreateFromMinValue(referenceDate.getFullYear(), referenceDate.getMonth(), referenceDate.getDate());
let value = DateUtils.addDays(today, swift);
result.timex = DateTimeFormatUtil.luisDateFromDate(value);
result.futureValue = value;
result.pastValue = value;
result.success = true;
return result;
}
// handle "two days from tomorrow"
match = RegExpUtility.getMatches(this.config.specialDayWithNumRegex, trimmedSource).pop();
if (match && match.index === 0 && match.length === trimmedSource.length) {
let swift = this.config.getSwiftDay(match.groups('day').value);
let numErs = this.config.integerExtractor.extract(trimmedSource);
er.forEach(result => {
let num = toNumber(this.config.numberParser.parse(result).value);
if (num < 1 || num > 31) {
return;
}
if (result.start >= 0) {
let frontString = source.substring(0, result.start | 0);
let match = RegExpUtility.getMatches(this.config.monthEnd, frontString)[0];
if (match && match.length) {
ret.push(new Token(match.index, match.index + match.length + result.length));
return;
}
// handling cases like 'for the 25th'
let matches = RegExpUtility.getMatches(this.config.forTheRegex, source);
let isFound = false;
matches.forEach(matchCase => {
if (matchCase) {
let ordinalNum = matchCase.groups('DayOfMonth').value;
if (ordinalNum === result.text) {
let length = matchCase.groups('end').value.length;
ret.push(new Token(matchCase.index, matchCase.index + matchCase.length - length));
isFound = true;
}
}
});
if (isFound) {
return;
}
if (descCaptureIndex >= time1StartIndex && descCaptureIndex + descCapture.length <= time1EndIndex && StringUtility.isNullOrEmpty(leftDesc)) {
leftDesc = descCapture;
}
else if (descCaptureIndex >= time2StartIndex && descCaptureIndex + descCapture.length <= time2EndIndex && StringUtility.isNullOrEmpty(rightDesc)) {
rightDesc = descCapture;
}
lastGroupIndex = descCaptureIndex + 1;
}
let beginDateTime = DateUtils.safeCreateFromMinValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0);
let endDateTime = DateUtils.safeCreateFromMinValue(year, month, day, endHour, endMinute >= 0 ? endMinute : 0, endSecond >= 0 ? endSecond : 0);
let hasLeftAm = !StringUtility.isNullOrEmpty(leftDesc) && leftDesc.toLowerCase().startsWith('a');
let hasLeftPm = !StringUtility.isNullOrEmpty(leftDesc) && leftDesc.toLowerCase().startsWith('p');
let hasRightAm = !StringUtility.isNullOrEmpty(rightDesc) && rightDesc.toLowerCase().startsWith('a');
let hasRightPm = !StringUtility.isNullOrEmpty(rightDesc) && rightDesc.toLowerCase().startsWith('p');
let hasLeft = hasLeftAm || hasLeftPm;
let hasRight = hasRightAm || hasRightPm;
// Both timepoint has description like 'am' or 'pm'
if (hasLeft && hasRight) {
if (hasLeftAm) {
if (beginHour >= 12) {
beginDateTime = DateUtils.addHours(beginDateTime, -12);
}
}
else if (hasLeftPm) {
if (beginHour < 12) {
beginDateTime = DateUtils.addHours(beginDateTime, 12);
}
while (j < result.length && result[j].start + result[j].length < numErs[i].start) {
hasBehindExtraction = true;
j++;
}
if (!hasBehindExtraction) {
continue;
}
let middleBegin = result[j - 1].start + result[j - 1].length;
let middleEnd = numErs[i].start;
let middleStr = source.substring(middleBegin, middleEnd).trim().toLowerCase();
// Separated by whitespace
if (StringUtility.isNullOrEmpty(middleStr)) {
unitNumbers.push(numErs[i]);
continue;
}
// Separated by connectors
let match = RegExpUtility.getMatches(this.config.compoundUnitConnectorRegex, middleStr).pop();
if (match && match.index === 0 && match.length === middleStr.length) {
unitNumbers.push(numErs[i]);
}
}
unitNumbers.forEach(extractResult => {
let overlap = false;
result.forEach(er => {
if (er.start <= extractResult.start && er.start + er.length >= extractResult.start) {
overlap = true;
}
lastGroupIndex = secondCaptureIndex + 1;
}
lastGroupIndex = 0;
// Desc here means descriptions like "am / pm / o'clock"
// Get leftDesc (if exists) and rightDesc (if exists)
let leftDesc = match.groups('leftDesc').value;
let rightDesc = match.groups('rightDesc').value;
for (let i = 0; i < match.groups('desc').captures.length; i++) {
let descCapture = match.groups('desc').captures[i];
let descCaptureIndex = source.indexOf(descCapture, lastGroupIndex);
if (descCaptureIndex >= time1StartIndex && descCaptureIndex + descCapture.length <= time1EndIndex && StringUtility.isNullOrEmpty(leftDesc)) {
leftDesc = descCapture;
}
else if (descCaptureIndex >= time2StartIndex && descCaptureIndex + descCapture.length <= time2EndIndex && StringUtility.isNullOrEmpty(rightDesc)) {
rightDesc = descCapture;
}
lastGroupIndex = descCaptureIndex + 1;
}
let beginDateTime = DateUtils.safeCreateFromMinValue(year, month, day, beginHour, beginMinute >= 0 ? beginMinute : 0, beginSecond >= 0 ? beginSecond : 0);
let endDateTime = DateUtils.safeCreateFromMinValue(year, month, day, endHour, endMinute >= 0 ? endMinute : 0, endSecond >= 0 ? endSecond : 0);
let hasLeftAm = !StringUtility.isNullOrEmpty(leftDesc) && leftDesc.toLowerCase().startsWith('a');
let hasLeftPm = !StringUtility.isNullOrEmpty(leftDesc) && leftDesc.toLowerCase().startsWith('p');
let hasRightAm = !StringUtility.isNullOrEmpty(rightDesc) && rightDesc.toLowerCase().startsWith('a');
let hasRightPm = !StringUtility.isNullOrEmpty(rightDesc) && rightDesc.toLowerCase().startsWith('p');
afterHourIndex = trimmedText.indexOf(hourStr, hourGroup.index + 1) + hourStr.length;
if (afterHourIndex === trimmedText.length || !trimmedText.substr(afterHourIndex).trim().startsWith(':')) {
let endHour = this.config.numbers.get(hourStr);
if (!endHour) {
endHour = Number.parseInt(hourStr, 10);
}
// parse "pm"
let leftDesc = matches[0].groups("leftDesc").value;
let rightDesc = matches[0].groups("rightDesc").value;
let pmStr = matches[0].groups("pm").value;
let amStr = matches[0].groups("am").value;
// The "ampm" only occurs in time, don't have to consider it here
if (StringUtility.isNullOrWhitespace(leftDesc)) {
let rightAmValid = !StringUtility.isNullOrEmpty(rightDesc) &&
RegExpUtility.getMatches(this.config.utilityConfiguration.amDescRegex, rightDesc.toLowerCase()).length;
let rightPmValid = !StringUtility.isNullOrEmpty(rightDesc) &&
RegExpUtility.getMatches(this.config.utilityConfiguration.pmDescRegex, rightDesc.toLowerCase()).length;
if (!StringUtility.isNullOrEmpty(amStr) || rightAmValid) {
if (endHour >= 12) {
endHour -= 12;
}
if (beginHour >= 12 && beginHour - 12 < endHour) {
beginHour -= 12;
}
// Resolve case like "11 to 3am"
if (beginHour < 12 && beginHour > endHour) {
let er2 = this.config.timeExtractor.extract(text, referenceTime);
if (er2.length === 0) {
// here we filter out "morning, afternoon, night..." time entities
er2 = this.config.timeExtractor.extract(this.config.tokenBeforeTime + text, referenceTime);
if (er2.length === 1) {
er2[0].start -= this.config.tokenBeforeTime.length;
}
else {
return ret;
}
}
// handle case "Oct. 5 in the afternoon at 7:00"
// in this case "5 in the afternoon" will be extract as a Time entity
let correctTimeIdx = 0;
while (correctTimeIdx < er2.length && ExtractResult.isOverlap(er2[correctTimeIdx], er1[0])) {
correctTimeIdx++;
}
if (correctTimeIdx >= er2.length) {
return ret;
}
let pr1 = this.config.dateParser.parse(er1[0], new Date(referenceTime.toDateString()));
let pr2 = this.config.timeParser.parse(er2[correctTimeIdx], referenceTime);
if (pr1.value === null || pr2.value === null) {
return ret;
}
let futureDate = pr1.value.futureValue;
let pastDate = pr1.value.pastValue;
let time = pr2.value.futureValue;