UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

287 lines (286 loc) • 10.8 kB
/** * 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/ */ "use strict"; 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;