devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
287 lines (286 loc) • 10.8 kB
JavaScript
/**
* DevExtreme (cjs/__internal/core/localization/ldml/date.parser.js)
* Version: 25.2.3
* Build date: Fri Dec 12 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isPossibleForParsingFormat = exports.getRegExpInfo = exports.getPatternSetters = exports.getParser = void 0;
var _m_common = require("../../../core/utils/m_common");
var _m_console = require("../../../core/utils/m_console");
const FORMAT_TYPES = {
3: "abbreviated",
4: "wide",
5: "narrow"
};
const monthRegExpGenerator = (count, dateParts) => {
if (count > 2) {
return Object.keys(FORMAT_TYPES).map((count => ["format", "standalone"].map((type => dateParts.getMonthNames(FORMAT_TYPES[count], type).join("|"))).join("|"))).join("|")
}
return 2 === count ? "1[012]|0?[1-9]" : "0??[1-9]|1[012]"
};
const PATTERN_REGEXPS = {
":": (count, dateParts) => {
var _dateParts$getTimeSep;
const countSuffix = count > 1 ? `{${count}}` : "";
let timeSeparator = (0, _m_common.escapeRegExp)(null === (_dateParts$getTimeSep = dateParts.getTimeSeparator) || void 0 === _dateParts$getTimeSep ? void 0 : _dateParts$getTimeSep.call(dateParts));
if (":" !== timeSeparator) {
timeSeparator = `${timeSeparator}|:`
}
return `${timeSeparator}${countSuffix}`
},
y: count => 2 === count ? `[0-9]{${count}}` : "[0-9]+?",
M: monthRegExpGenerator,
L: monthRegExpGenerator,
Q(count, dateParts) {
if (count > 2) {
return dateParts.getQuarterNames(FORMAT_TYPES[count], "format").join("|")
}
return "0?[1-4]"
},
E: (_count, _dateParts) => "\\D*",
a: (count, dateParts) => dateParts.getPeriodNames(FORMAT_TYPES[count < 3 ? 3 : count], "format").join("|"),
d: count => 2 === count ? "3[01]|[12][0-9]|0?[1-9]" : "0??[1-9]|[12][0-9]|3[01]",
H: count => 2 === count ? "2[0-3]|1[0-9]|0?[0-9]" : "0??[0-9]|1[0-9]|2[0-3]",
h: count => 2 === count ? "1[012]|0?[1-9]" : "0??[1-9]|1[012]",
m: count => 2 === count ? "[1-5][0-9]|0?[0-9]" : "0??[0-9]|[1-5][0-9]",
s: count => 2 === count ? "[1-5][0-9]|0?[0-9]" : "0??[0-9]|[1-5][0-9]",
S: count => `[0-9]{1,${count}}`,
w: count => 2 === count ? "[1-5][0-9]|0?[0-9]" : "0??[0-9]|[1-5][0-9]",
x: count => 3 === count ? "[+-](?:2[0-3]|[01][0-9]):(?:[0-5][0-9])|Z" : "[+-](?:2[0-3]|[01][0-9])(?:[0-5][0-9])|Z"
};
const parseNumber = Number;
const caseInsensitiveIndexOf = (array, value) => array.map((item => item.toLowerCase())).indexOf(value.toLowerCase());
const monthPatternParser = (text, count, dateParts) => {
if (count > 2) {
return ["format", "standalone"].map((type => Object.keys(FORMAT_TYPES).map((count => {
const monthNames = dateParts.getMonthNames(FORMAT_TYPES[count], type);
return caseInsensitiveIndexOf(monthNames, text)
})))).reduce(((a, b) => a.concat(b))).filter((index => index >= 0))[0]
}
return parseNumber(text) - 1
};
const PATTERN_PARSERS = {
y(text, count) {
const year = parseNumber(text);
if (2 === count) {
return year < 30 ? 2e3 + year : 1900 + year
}
return year
},
M: monthPatternParser,
L: monthPatternParser,
Q(text, count, dateParts) {
if (count > 2) {
return dateParts.getQuarterNames(FORMAT_TYPES[count], "format").indexOf(text)
}
return parseNumber(text) - 1
},
E(text, count, dateParts) {
const dayNames = dateParts.getDayNames(FORMAT_TYPES[count < 3 ? 3 : count], "format");
return caseInsensitiveIndexOf(dayNames, text)
},
a(text, count, dateParts) {
const periodNames = dateParts.getPeriodNames(FORMAT_TYPES[count < 3 ? 3 : count], "format");
return caseInsensitiveIndexOf(periodNames, text)
},
d: parseNumber,
H: parseNumber,
h: parseNumber,
m: parseNumber,
s: parseNumber,
S(text, count) {
count = Math.max(count, 3);
text = text.slice(0, 3);
while (count < 3) {
text = `${text}0`;
count += 1
}
return parseNumber(text)
}
};
const ORDERED_PATTERNS = ["y", "M", "d", "h", "m", "s", "S"];
const PATTERN_SETTERS = {
y: "setFullYear",
M: "setMonth",
L: "setMonth",
a(date, value, datePartValues) {
let hours = date.getHours();
const hourPartValue = datePartValues.h;
if (void 0 !== hourPartValue && hourPartValue !== hours) {
hours -= 1
}
if (!value && 12 === hours) {
hours = 0
} else if (value && 12 !== hours) {
hours += 12
}
date.setHours(hours)
},
d: "setDate",
H: "setHours",
h: "setHours",
m: "setMinutes",
s: "setSeconds",
S: "setMilliseconds"
};
const getSameCharCount = (text, index) => {
const char = text[index];
if (!char) {
return 0
}
let count = 0;
do {
index += 1;
count += 1
} while (text[index] === char);
return count
};
const createPattern = (char, count) => {
let result = "";
for (let i = 0; i < count; i += 1) {
result += char
}
return result
};
const digitFieldSymbols = ["d", "H", "h", "m", "s", "w", "M", "L", "Q"];
const isPossibleForParsingFormat = patterns => {
const isDigitPattern = pattern => {
if (!pattern) {
return false
}
const char = pattern[0];
return ["y", "S"].includes(char) || digitFieldSymbols.includes(char) && pattern.length < 3
};
let possibleForParsing = true;
let ambiguousDigitPatternsCount = 0;
return patterns.every(((pattern, index, patterns) => {
if (isDigitPattern(pattern)) {
if ((pattern => !pattern.startsWith("S") && 2 !== pattern.length)(pattern)) {
possibleForParsing = ++ambiguousDigitPatternsCount < 2
}
if (!isDigitPattern(patterns[index + 1])) {
ambiguousDigitPatternsCount = 0
}
}
return possibleForParsing
}))
};
exports.isPossibleForParsingFormat = isPossibleForParsingFormat;
const getRegExpInfo = (format, dateParts) => {
let regexpText = "";
let stubText = "";
let isEscaping = false;
const patterns = [];
const addPreviousStub = () => {
if (stubText) {
patterns.push(`'${stubText}'`);
regexpText += `${(0,_m_common.escapeRegExp)(stubText)})`;
stubText = ""
}
};
for (let i = 0; i < format.length; i += 1) {
const char = format[i];
const isEscapeChar = "'" === char;
const regexpPart = PATTERN_REGEXPS[char];
if (isEscapeChar) {
isEscaping = !isEscaping;
if ("'" !== format[i - 1]) {
continue
}
}
if (regexpPart && !isEscaping) {
const count = getSameCharCount(format, i);
const pattern = createPattern(char, count);
addPreviousStub();
patterns.push(pattern);
regexpText += `(${regexpPart(count,dateParts)})`;
i += count - 1
} else {
if (!stubText) {
regexpText += "("
}
stubText += char
}
}
addPreviousStub();
if (!isPossibleForParsingFormat(patterns)) {
_m_console.logger.warn(`The following format may be parsed incorrectly: ${format}.`)
}
return {
patterns: patterns,
regexp: new RegExp(`^${regexpText}$`, "i")
}
};
exports.getRegExpInfo = getRegExpInfo;
const getPatternSetters = () => PATTERN_SETTERS;
exports.getPatternSetters = getPatternSetters;
const setPatternPart = (date, pattern, text, dateParts, datePartValues) => {
const patternChar = pattern[0];
const partSetter = PATTERN_SETTERS[patternChar];
const partParser = PATTERN_PARSERS[patternChar];
if (partSetter && partParser) {
const value = partParser(text, pattern.length, dateParts);
datePartValues[pattern] = value;
if (date[partSetter]) {
date[partSetter](value)
} else {
partSetter(date, value, datePartValues)
}
}
};
const setPatternPartFromNow = (date, pattern, now) => {
const setterName = PATTERN_SETTERS[pattern];
const getterName = `g${setterName.substr(1)}`;
const value = now[getterName]();
date[setterName](value)
};
const getShortPatterns = fullPatterns => fullPatterns.map((pattern => {
if (pattern.startsWith("'")) {
return ""
}
return pattern.startsWith("H") ? "h" : pattern[0]
}));
const getMaxOrderedPatternIndex = patterns => {
const indexes = patterns.map((pattern => ORDERED_PATTERNS.indexOf(pattern)));
return Math.max(...indexes)
};
const getOrderedFormatPatterns = formatPatterns => {
const otherPatterns = formatPatterns.filter((pattern => !ORDERED_PATTERNS.includes(pattern)));
return ORDERED_PATTERNS.concat(otherPatterns)
};
const getParser = (format, dateParts) => {
const regExpInfo = getRegExpInfo(format, dateParts);
return text => {
const regExpResult = regExpInfo.regexp.exec(text);
if (regExpResult) {
const now = new Date;
const date = new Date(now.getFullYear(), 0, 1);
const formatPatterns = getShortPatterns(regExpInfo.patterns);
const maxPatternIndex = getMaxOrderedPatternIndex(formatPatterns);
const orderedFormatPatterns = getOrderedFormatPatterns(formatPatterns);
const datePartValues = {};
orderedFormatPatterns.forEach(((pattern, index) => {
if (!pattern || index < ORDERED_PATTERNS.length && index > maxPatternIndex) {
return
}
const patternIndex = formatPatterns.indexOf(pattern);
if (patternIndex >= 0) {
const regExpPattern = regExpInfo.patterns[patternIndex];
const regExpText = regExpResult[patternIndex + 1];
setPatternPart(date, regExpPattern, regExpText, dateParts, datePartValues)
} else {
setPatternPartFromNow(date, pattern, now)
}
}));
return date
}
return null
}
};
exports.getParser = getParser;