@formatjs/icu-messageformat-parser
Advanced tools
| /** | ||
| * Returns the best matching date time pattern if a date time skeleton | ||
| * pattern is provided with a locale. Follows the Unicode specification: | ||
| * https://www.unicode.org/reports/tr35/tr35-dates.html#table-mapping-requested-time-skeletons-to-patterns | ||
| * @param skeleton date time skeleton pattern that possibly includes j, J or C | ||
| * @param locale | ||
| */ | ||
| * Returns the best matching date time pattern if a date time skeleton | ||
| * pattern is provided with a locale. Follows the Unicode specification: | ||
| * https://www.unicode.org/reports/tr35/tr35-dates.html#table-mapping-requested-time-skeletons-to-patterns | ||
| * @param skeleton date time skeleton pattern that possibly includes j, J or C | ||
| * @param locale | ||
| */ | ||
| export declare function getBestPattern(skeleton: string, locale: Intl.Locale): string; |
@@ -1,83 +0,68 @@ | ||
| import { timeData } from './time-data.generated.js'; | ||
| import { timeData } from "./time-data.generated.js"; | ||
| /** | ||
| * Returns the best matching date time pattern if a date time skeleton | ||
| * pattern is provided with a locale. Follows the Unicode specification: | ||
| * https://www.unicode.org/reports/tr35/tr35-dates.html#table-mapping-requested-time-skeletons-to-patterns | ||
| * @param skeleton date time skeleton pattern that possibly includes j, J or C | ||
| * @param locale | ||
| */ | ||
| * Returns the best matching date time pattern if a date time skeleton | ||
| * pattern is provided with a locale. Follows the Unicode specification: | ||
| * https://www.unicode.org/reports/tr35/tr35-dates.html#table-mapping-requested-time-skeletons-to-patterns | ||
| * @param skeleton date time skeleton pattern that possibly includes j, J or C | ||
| * @param locale | ||
| */ | ||
| export function getBestPattern(skeleton, locale) { | ||
| var skeletonCopy = ''; | ||
| for (var patternPos = 0; patternPos < skeleton.length; patternPos++) { | ||
| var patternChar = skeleton.charAt(patternPos); | ||
| if (patternChar === 'j') { | ||
| var extraLength = 0; | ||
| while (patternPos + 1 < skeleton.length && | ||
| skeleton.charAt(patternPos + 1) === patternChar) { | ||
| extraLength++; | ||
| patternPos++; | ||
| } | ||
| var hourLen = 1 + (extraLength & 1); | ||
| var dayPeriodLen = extraLength < 2 ? 1 : 3 + (extraLength >> 1); | ||
| var dayPeriodChar = 'a'; | ||
| var hourChar = getDefaultHourSymbolFromLocale(locale); | ||
| if (hourChar == 'H' || hourChar == 'k') { | ||
| dayPeriodLen = 0; | ||
| } | ||
| while (dayPeriodLen-- > 0) { | ||
| skeletonCopy += dayPeriodChar; | ||
| } | ||
| while (hourLen-- > 0) { | ||
| skeletonCopy = hourChar + skeletonCopy; | ||
| } | ||
| } | ||
| else if (patternChar === 'J') { | ||
| skeletonCopy += 'H'; | ||
| } | ||
| else { | ||
| skeletonCopy += patternChar; | ||
| } | ||
| } | ||
| return skeletonCopy; | ||
| let skeletonCopy = ""; | ||
| for (let patternPos = 0; patternPos < skeleton.length; patternPos++) { | ||
| const patternChar = skeleton.charAt(patternPos); | ||
| if (patternChar === "j") { | ||
| let extraLength = 0; | ||
| while (patternPos + 1 < skeleton.length && skeleton.charAt(patternPos + 1) === patternChar) { | ||
| extraLength++; | ||
| patternPos++; | ||
| } | ||
| let hourLen = 1 + (extraLength & 1); | ||
| let dayPeriodLen = extraLength < 2 ? 1 : 3 + (extraLength >> 1); | ||
| let dayPeriodChar = "a"; | ||
| let hourChar = getDefaultHourSymbolFromLocale(locale); | ||
| if (hourChar == "H" || hourChar == "k") { | ||
| dayPeriodLen = 0; | ||
| } | ||
| while (dayPeriodLen-- > 0) { | ||
| skeletonCopy += dayPeriodChar; | ||
| } | ||
| while (hourLen-- > 0) { | ||
| skeletonCopy = hourChar + skeletonCopy; | ||
| } | ||
| } else if (patternChar === "J") { | ||
| skeletonCopy += "H"; | ||
| } else { | ||
| skeletonCopy += patternChar; | ||
| } | ||
| } | ||
| return skeletonCopy; | ||
| } | ||
| /** | ||
| * Maps the [hour cycle type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/hourCycle) | ||
| * of the given `locale` to the corresponding time pattern. | ||
| * @param locale | ||
| */ | ||
| * Maps the [hour cycle type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/hourCycle) | ||
| * of the given `locale` to the corresponding time pattern. | ||
| * @param locale | ||
| */ | ||
| function getDefaultHourSymbolFromLocale(locale) { | ||
| var hourCycle = locale.hourCycle; | ||
| if (hourCycle === undefined && | ||
| // @ts-ignore hourCycle(s) is not identified yet | ||
| locale.hourCycles && | ||
| // @ts-ignore | ||
| locale.hourCycles.length) { | ||
| // @ts-ignore | ||
| hourCycle = locale.hourCycles[0]; | ||
| } | ||
| if (hourCycle) { | ||
| switch (hourCycle) { | ||
| case 'h24': | ||
| return 'k'; | ||
| case 'h23': | ||
| return 'H'; | ||
| case 'h12': | ||
| return 'h'; | ||
| case 'h11': | ||
| return 'K'; | ||
| default: | ||
| throw new Error('Invalid hourCycle'); | ||
| } | ||
| } | ||
| // TODO: Once hourCycle is fully supported remove the following with data generation | ||
| var languageTag = locale.language; | ||
| var regionTag; | ||
| if (languageTag !== 'root') { | ||
| regionTag = locale.maximize().region; | ||
| } | ||
| var hourCycles = timeData[regionTag || ''] || | ||
| timeData[languageTag || ''] || | ||
| timeData["".concat(languageTag, "-001")] || | ||
| timeData['001']; | ||
| return hourCycles[0]; | ||
| let hourCycle = locale.hourCycle; | ||
| if (hourCycle === undefined && locale.hourCycles && locale.hourCycles.length) { | ||
| // @ts-ignore | ||
| hourCycle = locale.hourCycles[0]; | ||
| } | ||
| if (hourCycle) { | ||
| switch (hourCycle) { | ||
| case "h24": return "k"; | ||
| case "h23": return "H"; | ||
| case "h12": return "h"; | ||
| case "h11": return "K"; | ||
| default: throw new Error("Invalid hourCycle"); | ||
| } | ||
| } | ||
| // TODO: Once hourCycle is fully supported remove the following with data generation | ||
| const languageTag = locale.language; | ||
| let regionTag; | ||
| if (languageTag !== "root") { | ||
| regionTag = locale.maximize().region; | ||
| } | ||
| const hourCycles = timeData[regionTag || ""] || timeData[languageTag || ""] || timeData[`${languageTag}-001`] || timeData["001"]; | ||
| return hourCycles[0]; | ||
| } |
+64
-64
@@ -1,68 +0,68 @@ | ||
| import { Location } from './types.js'; | ||
| import { type Location } from "./types.js"; | ||
| export interface ParserError { | ||
| kind: ErrorKind; | ||
| message: string; | ||
| location: Location; | ||
| kind: ErrorKind; | ||
| message: string; | ||
| location: Location; | ||
| } | ||
| export declare enum ErrorKind { | ||
| /** Argument is unclosed (e.g. `{0`) */ | ||
| EXPECT_ARGUMENT_CLOSING_BRACE = 1, | ||
| /** Argument is empty (e.g. `{}`). */ | ||
| EMPTY_ARGUMENT = 2, | ||
| /** Argument is malformed (e.g. `{foo!}``) */ | ||
| MALFORMED_ARGUMENT = 3, | ||
| /** Expect an argument type (e.g. `{foo,}`) */ | ||
| EXPECT_ARGUMENT_TYPE = 4, | ||
| /** Unsupported argument type (e.g. `{foo,foo}`) */ | ||
| INVALID_ARGUMENT_TYPE = 5, | ||
| /** Expect an argument style (e.g. `{foo, number, }`) */ | ||
| EXPECT_ARGUMENT_STYLE = 6, | ||
| /** The number skeleton is invalid. */ | ||
| INVALID_NUMBER_SKELETON = 7, | ||
| /** The date time skeleton is invalid. */ | ||
| INVALID_DATE_TIME_SKELETON = 8, | ||
| /** Exepct a number skeleton following the `::` (e.g. `{foo, number, ::}`) */ | ||
| EXPECT_NUMBER_SKELETON = 9, | ||
| /** Exepct a date time skeleton following the `::` (e.g. `{foo, date, ::}`) */ | ||
| EXPECT_DATE_TIME_SKELETON = 10, | ||
| /** Unmatched apostrophes in the argument style (e.g. `{foo, number, 'test`) */ | ||
| UNCLOSED_QUOTE_IN_ARGUMENT_STYLE = 11, | ||
| /** Missing select argument options (e.g. `{foo, select}`) */ | ||
| EXPECT_SELECT_ARGUMENT_OPTIONS = 12, | ||
| /** Expecting an offset value in `plural` or `selectordinal` argument (e.g `{foo, plural, offset}`) */ | ||
| EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE = 13, | ||
| /** Offset value in `plural` or `selectordinal` is invalid (e.g. `{foo, plural, offset: x}`) */ | ||
| INVALID_PLURAL_ARGUMENT_OFFSET_VALUE = 14, | ||
| /** Expecting a selector in `select` argument (e.g `{foo, select}`) */ | ||
| EXPECT_SELECT_ARGUMENT_SELECTOR = 15, | ||
| /** Expecting a selector in `plural` or `selectordinal` argument (e.g `{foo, plural}`) */ | ||
| EXPECT_PLURAL_ARGUMENT_SELECTOR = 16, | ||
| /** Expecting a message fragment after the `select` selector (e.g. `{foo, select, apple}`) */ | ||
| EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT = 17, | ||
| /** | ||
| * Expecting a message fragment after the `plural` or `selectordinal` selector | ||
| * (e.g. `{foo, plural, one}`) | ||
| */ | ||
| EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT = 18, | ||
| /** Selector in `plural` or `selectordinal` is malformed (e.g. `{foo, plural, =x {#}}`) */ | ||
| INVALID_PLURAL_ARGUMENT_SELECTOR = 19, | ||
| /** | ||
| * Duplicate selectors in `plural` or `selectordinal` argument. | ||
| * (e.g. {foo, plural, one {#} one {#}}) | ||
| */ | ||
| DUPLICATE_PLURAL_ARGUMENT_SELECTOR = 20, | ||
| /** Duplicate selectors in `select` argument. | ||
| * (e.g. {foo, select, apple {apple} apple {apple}}) | ||
| */ | ||
| DUPLICATE_SELECT_ARGUMENT_SELECTOR = 21, | ||
| /** Plural or select argument option must have `other` clause. */ | ||
| MISSING_OTHER_CLAUSE = 22, | ||
| /** The tag is malformed. (e.g. `<bold!>foo</bold!>) */ | ||
| INVALID_TAG = 23, | ||
| /** The tag name is invalid. (e.g. `<123>foo</123>`) */ | ||
| INVALID_TAG_NAME = 25, | ||
| /** The closing tag does not match the opening tag. (e.g. `<bold>foo</italic>`) */ | ||
| UNMATCHED_CLOSING_TAG = 26, | ||
| /** The opening tag has unmatched closing tag. (e.g. `<bold>foo`) */ | ||
| UNCLOSED_TAG = 27 | ||
| /** Argument is unclosed (e.g. `{0`) */ | ||
| EXPECT_ARGUMENT_CLOSING_BRACE = 1, | ||
| /** Argument is empty (e.g. `{}`). */ | ||
| EMPTY_ARGUMENT = 2, | ||
| /** Argument is malformed (e.g. `{foo!}``) */ | ||
| MALFORMED_ARGUMENT = 3, | ||
| /** Expect an argument type (e.g. `{foo,}`) */ | ||
| EXPECT_ARGUMENT_TYPE = 4, | ||
| /** Unsupported argument type (e.g. `{foo,foo}`) */ | ||
| INVALID_ARGUMENT_TYPE = 5, | ||
| /** Expect an argument style (e.g. `{foo, number, }`) */ | ||
| EXPECT_ARGUMENT_STYLE = 6, | ||
| /** The number skeleton is invalid. */ | ||
| INVALID_NUMBER_SKELETON = 7, | ||
| /** The date time skeleton is invalid. */ | ||
| INVALID_DATE_TIME_SKELETON = 8, | ||
| /** Exepct a number skeleton following the `::` (e.g. `{foo, number, ::}`) */ | ||
| EXPECT_NUMBER_SKELETON = 9, | ||
| /** Exepct a date time skeleton following the `::` (e.g. `{foo, date, ::}`) */ | ||
| EXPECT_DATE_TIME_SKELETON = 10, | ||
| /** Unmatched apostrophes in the argument style (e.g. `{foo, number, 'test`) */ | ||
| UNCLOSED_QUOTE_IN_ARGUMENT_STYLE = 11, | ||
| /** Missing select argument options (e.g. `{foo, select}`) */ | ||
| EXPECT_SELECT_ARGUMENT_OPTIONS = 12, | ||
| /** Expecting an offset value in `plural` or `selectordinal` argument (e.g `{foo, plural, offset}`) */ | ||
| EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE = 13, | ||
| /** Offset value in `plural` or `selectordinal` is invalid (e.g. `{foo, plural, offset: x}`) */ | ||
| INVALID_PLURAL_ARGUMENT_OFFSET_VALUE = 14, | ||
| /** Expecting a selector in `select` argument (e.g `{foo, select}`) */ | ||
| EXPECT_SELECT_ARGUMENT_SELECTOR = 15, | ||
| /** Expecting a selector in `plural` or `selectordinal` argument (e.g `{foo, plural}`) */ | ||
| EXPECT_PLURAL_ARGUMENT_SELECTOR = 16, | ||
| /** Expecting a message fragment after the `select` selector (e.g. `{foo, select, apple}`) */ | ||
| EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT = 17, | ||
| /** | ||
| * Expecting a message fragment after the `plural` or `selectordinal` selector | ||
| * (e.g. `{foo, plural, one}`) | ||
| */ | ||
| EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT = 18, | ||
| /** Selector in `plural` or `selectordinal` is malformed (e.g. `{foo, plural, =x {#}}`) */ | ||
| INVALID_PLURAL_ARGUMENT_SELECTOR = 19, | ||
| /** | ||
| * Duplicate selectors in `plural` or `selectordinal` argument. | ||
| * (e.g. {foo, plural, one {#} one {#}}) | ||
| */ | ||
| DUPLICATE_PLURAL_ARGUMENT_SELECTOR = 20, | ||
| /** Duplicate selectors in `select` argument. | ||
| * (e.g. {foo, select, apple {apple} apple {apple}}) | ||
| */ | ||
| DUPLICATE_SELECT_ARGUMENT_SELECTOR = 21, | ||
| /** Plural or select argument option must have `other` clause. */ | ||
| MISSING_OTHER_CLAUSE = 22, | ||
| /** The tag is malformed. (e.g. `<bold!>foo</bold!>) */ | ||
| INVALID_TAG = 23, | ||
| /** The tag name is invalid. (e.g. `<123>foo</123>`) */ | ||
| INVALID_TAG_NAME = 25, | ||
| /** The closing tag does not match the opening tag. (e.g. `<bold>foo</italic>`) */ | ||
| UNMATCHED_CLOSING_TAG = 26, | ||
| /** The opening tag has unmatched closing tag. (e.g. `<bold>foo`) */ | ||
| UNCLOSED_TAG = 27 | ||
| } |
+64
-63
@@ -1,63 +0,64 @@ | ||
| export var ErrorKind; | ||
| (function (ErrorKind) { | ||
| /** Argument is unclosed (e.g. `{0`) */ | ||
| ErrorKind[ErrorKind["EXPECT_ARGUMENT_CLOSING_BRACE"] = 1] = "EXPECT_ARGUMENT_CLOSING_BRACE"; | ||
| /** Argument is empty (e.g. `{}`). */ | ||
| ErrorKind[ErrorKind["EMPTY_ARGUMENT"] = 2] = "EMPTY_ARGUMENT"; | ||
| /** Argument is malformed (e.g. `{foo!}``) */ | ||
| ErrorKind[ErrorKind["MALFORMED_ARGUMENT"] = 3] = "MALFORMED_ARGUMENT"; | ||
| /** Expect an argument type (e.g. `{foo,}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_ARGUMENT_TYPE"] = 4] = "EXPECT_ARGUMENT_TYPE"; | ||
| /** Unsupported argument type (e.g. `{foo,foo}`) */ | ||
| ErrorKind[ErrorKind["INVALID_ARGUMENT_TYPE"] = 5] = "INVALID_ARGUMENT_TYPE"; | ||
| /** Expect an argument style (e.g. `{foo, number, }`) */ | ||
| ErrorKind[ErrorKind["EXPECT_ARGUMENT_STYLE"] = 6] = "EXPECT_ARGUMENT_STYLE"; | ||
| /** The number skeleton is invalid. */ | ||
| ErrorKind[ErrorKind["INVALID_NUMBER_SKELETON"] = 7] = "INVALID_NUMBER_SKELETON"; | ||
| /** The date time skeleton is invalid. */ | ||
| ErrorKind[ErrorKind["INVALID_DATE_TIME_SKELETON"] = 8] = "INVALID_DATE_TIME_SKELETON"; | ||
| /** Exepct a number skeleton following the `::` (e.g. `{foo, number, ::}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_NUMBER_SKELETON"] = 9] = "EXPECT_NUMBER_SKELETON"; | ||
| /** Exepct a date time skeleton following the `::` (e.g. `{foo, date, ::}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_DATE_TIME_SKELETON"] = 10] = "EXPECT_DATE_TIME_SKELETON"; | ||
| /** Unmatched apostrophes in the argument style (e.g. `{foo, number, 'test`) */ | ||
| ErrorKind[ErrorKind["UNCLOSED_QUOTE_IN_ARGUMENT_STYLE"] = 11] = "UNCLOSED_QUOTE_IN_ARGUMENT_STYLE"; | ||
| /** Missing select argument options (e.g. `{foo, select}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_SELECT_ARGUMENT_OPTIONS"] = 12] = "EXPECT_SELECT_ARGUMENT_OPTIONS"; | ||
| /** Expecting an offset value in `plural` or `selectordinal` argument (e.g `{foo, plural, offset}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE"] = 13] = "EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE"; | ||
| /** Offset value in `plural` or `selectordinal` is invalid (e.g. `{foo, plural, offset: x}`) */ | ||
| ErrorKind[ErrorKind["INVALID_PLURAL_ARGUMENT_OFFSET_VALUE"] = 14] = "INVALID_PLURAL_ARGUMENT_OFFSET_VALUE"; | ||
| /** Expecting a selector in `select` argument (e.g `{foo, select}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_SELECT_ARGUMENT_SELECTOR"] = 15] = "EXPECT_SELECT_ARGUMENT_SELECTOR"; | ||
| /** Expecting a selector in `plural` or `selectordinal` argument (e.g `{foo, plural}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_PLURAL_ARGUMENT_SELECTOR"] = 16] = "EXPECT_PLURAL_ARGUMENT_SELECTOR"; | ||
| /** Expecting a message fragment after the `select` selector (e.g. `{foo, select, apple}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT"] = 17] = "EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT"; | ||
| /** | ||
| * Expecting a message fragment after the `plural` or `selectordinal` selector | ||
| * (e.g. `{foo, plural, one}`) | ||
| */ | ||
| ErrorKind[ErrorKind["EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT"] = 18] = "EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT"; | ||
| /** Selector in `plural` or `selectordinal` is malformed (e.g. `{foo, plural, =x {#}}`) */ | ||
| ErrorKind[ErrorKind["INVALID_PLURAL_ARGUMENT_SELECTOR"] = 19] = "INVALID_PLURAL_ARGUMENT_SELECTOR"; | ||
| /** | ||
| * Duplicate selectors in `plural` or `selectordinal` argument. | ||
| * (e.g. {foo, plural, one {#} one {#}}) | ||
| */ | ||
| ErrorKind[ErrorKind["DUPLICATE_PLURAL_ARGUMENT_SELECTOR"] = 20] = "DUPLICATE_PLURAL_ARGUMENT_SELECTOR"; | ||
| /** Duplicate selectors in `select` argument. | ||
| * (e.g. {foo, select, apple {apple} apple {apple}}) | ||
| */ | ||
| ErrorKind[ErrorKind["DUPLICATE_SELECT_ARGUMENT_SELECTOR"] = 21] = "DUPLICATE_SELECT_ARGUMENT_SELECTOR"; | ||
| /** Plural or select argument option must have `other` clause. */ | ||
| ErrorKind[ErrorKind["MISSING_OTHER_CLAUSE"] = 22] = "MISSING_OTHER_CLAUSE"; | ||
| /** The tag is malformed. (e.g. `<bold!>foo</bold!>) */ | ||
| ErrorKind[ErrorKind["INVALID_TAG"] = 23] = "INVALID_TAG"; | ||
| /** The tag name is invalid. (e.g. `<123>foo</123>`) */ | ||
| ErrorKind[ErrorKind["INVALID_TAG_NAME"] = 25] = "INVALID_TAG_NAME"; | ||
| /** The closing tag does not match the opening tag. (e.g. `<bold>foo</italic>`) */ | ||
| ErrorKind[ErrorKind["UNMATCHED_CLOSING_TAG"] = 26] = "UNMATCHED_CLOSING_TAG"; | ||
| /** The opening tag has unmatched closing tag. (e.g. `<bold>foo`) */ | ||
| ErrorKind[ErrorKind["UNCLOSED_TAG"] = 27] = "UNCLOSED_TAG"; | ||
| })(ErrorKind || (ErrorKind = {})); | ||
| import "./types.js"; | ||
| export let ErrorKind = /* @__PURE__ */ function(ErrorKind) { | ||
| /** Argument is unclosed (e.g. `{0`) */ | ||
| ErrorKind[ErrorKind["EXPECT_ARGUMENT_CLOSING_BRACE"] = 1] = "EXPECT_ARGUMENT_CLOSING_BRACE"; | ||
| /** Argument is empty (e.g. `{}`). */ | ||
| ErrorKind[ErrorKind["EMPTY_ARGUMENT"] = 2] = "EMPTY_ARGUMENT"; | ||
| /** Argument is malformed (e.g. `{foo!}``) */ | ||
| ErrorKind[ErrorKind["MALFORMED_ARGUMENT"] = 3] = "MALFORMED_ARGUMENT"; | ||
| /** Expect an argument type (e.g. `{foo,}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_ARGUMENT_TYPE"] = 4] = "EXPECT_ARGUMENT_TYPE"; | ||
| /** Unsupported argument type (e.g. `{foo,foo}`) */ | ||
| ErrorKind[ErrorKind["INVALID_ARGUMENT_TYPE"] = 5] = "INVALID_ARGUMENT_TYPE"; | ||
| /** Expect an argument style (e.g. `{foo, number, }`) */ | ||
| ErrorKind[ErrorKind["EXPECT_ARGUMENT_STYLE"] = 6] = "EXPECT_ARGUMENT_STYLE"; | ||
| /** The number skeleton is invalid. */ | ||
| ErrorKind[ErrorKind["INVALID_NUMBER_SKELETON"] = 7] = "INVALID_NUMBER_SKELETON"; | ||
| /** The date time skeleton is invalid. */ | ||
| ErrorKind[ErrorKind["INVALID_DATE_TIME_SKELETON"] = 8] = "INVALID_DATE_TIME_SKELETON"; | ||
| /** Exepct a number skeleton following the `::` (e.g. `{foo, number, ::}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_NUMBER_SKELETON"] = 9] = "EXPECT_NUMBER_SKELETON"; | ||
| /** Exepct a date time skeleton following the `::` (e.g. `{foo, date, ::}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_DATE_TIME_SKELETON"] = 10] = "EXPECT_DATE_TIME_SKELETON"; | ||
| /** Unmatched apostrophes in the argument style (e.g. `{foo, number, 'test`) */ | ||
| ErrorKind[ErrorKind["UNCLOSED_QUOTE_IN_ARGUMENT_STYLE"] = 11] = "UNCLOSED_QUOTE_IN_ARGUMENT_STYLE"; | ||
| /** Missing select argument options (e.g. `{foo, select}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_SELECT_ARGUMENT_OPTIONS"] = 12] = "EXPECT_SELECT_ARGUMENT_OPTIONS"; | ||
| /** Expecting an offset value in `plural` or `selectordinal` argument (e.g `{foo, plural, offset}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE"] = 13] = "EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE"; | ||
| /** Offset value in `plural` or `selectordinal` is invalid (e.g. `{foo, plural, offset: x}`) */ | ||
| ErrorKind[ErrorKind["INVALID_PLURAL_ARGUMENT_OFFSET_VALUE"] = 14] = "INVALID_PLURAL_ARGUMENT_OFFSET_VALUE"; | ||
| /** Expecting a selector in `select` argument (e.g `{foo, select}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_SELECT_ARGUMENT_SELECTOR"] = 15] = "EXPECT_SELECT_ARGUMENT_SELECTOR"; | ||
| /** Expecting a selector in `plural` or `selectordinal` argument (e.g `{foo, plural}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_PLURAL_ARGUMENT_SELECTOR"] = 16] = "EXPECT_PLURAL_ARGUMENT_SELECTOR"; | ||
| /** Expecting a message fragment after the `select` selector (e.g. `{foo, select, apple}`) */ | ||
| ErrorKind[ErrorKind["EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT"] = 17] = "EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT"; | ||
| /** | ||
| * Expecting a message fragment after the `plural` or `selectordinal` selector | ||
| * (e.g. `{foo, plural, one}`) | ||
| */ | ||
| ErrorKind[ErrorKind["EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT"] = 18] = "EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT"; | ||
| /** Selector in `plural` or `selectordinal` is malformed (e.g. `{foo, plural, =x {#}}`) */ | ||
| ErrorKind[ErrorKind["INVALID_PLURAL_ARGUMENT_SELECTOR"] = 19] = "INVALID_PLURAL_ARGUMENT_SELECTOR"; | ||
| /** | ||
| * Duplicate selectors in `plural` or `selectordinal` argument. | ||
| * (e.g. {foo, plural, one {#} one {#}}) | ||
| */ | ||
| ErrorKind[ErrorKind["DUPLICATE_PLURAL_ARGUMENT_SELECTOR"] = 20] = "DUPLICATE_PLURAL_ARGUMENT_SELECTOR"; | ||
| /** Duplicate selectors in `select` argument. | ||
| * (e.g. {foo, select, apple {apple} apple {apple}}) | ||
| */ | ||
| ErrorKind[ErrorKind["DUPLICATE_SELECT_ARGUMENT_SELECTOR"] = 21] = "DUPLICATE_SELECT_ARGUMENT_SELECTOR"; | ||
| /** Plural or select argument option must have `other` clause. */ | ||
| ErrorKind[ErrorKind["MISSING_OTHER_CLAUSE"] = 22] = "MISSING_OTHER_CLAUSE"; | ||
| /** The tag is malformed. (e.g. `<bold!>foo</bold!>) */ | ||
| ErrorKind[ErrorKind["INVALID_TAG"] = 23] = "INVALID_TAG"; | ||
| /** The tag name is invalid. (e.g. `<123>foo</123>`) */ | ||
| ErrorKind[ErrorKind["INVALID_TAG_NAME"] = 25] = "INVALID_TAG_NAME"; | ||
| /** The closing tag does not match the opening tag. (e.g. `<bold>foo</italic>`) */ | ||
| ErrorKind[ErrorKind["UNMATCHED_CLOSING_TAG"] = 26] = "UNMATCHED_CLOSING_TAG"; | ||
| /** The opening tag has unmatched closing tag. (e.g. `<bold>foo`) */ | ||
| ErrorKind[ErrorKind["UNCLOSED_TAG"] = 27] = "UNCLOSED_TAG"; | ||
| return ErrorKind; | ||
| }({}); |
+5
-4
@@ -1,7 +0,8 @@ | ||
| import { Parser, ParserOptions } from './parser.js'; | ||
| import { MessageFormatElement } from './types.js'; | ||
| import { Parser, type ParserOptions } from "./parser.js"; | ||
| import { type MessageFormatElement } from "./types.js"; | ||
| export declare function parse(message: string, opts?: ParserOptions): MessageFormatElement[]; | ||
| export * from './types.js'; | ||
| export * from "./types.js"; | ||
| export type { ParserOptions }; | ||
| // only for testing | ||
| export declare const _Parser: typeof Parser; | ||
| export { isStructurallySame } from './manipulator.js'; | ||
| export { isStructurallySame } from "./manipulator.js"; |
+40
-42
@@ -1,46 +0,44 @@ | ||
| import { __assign } from "tslib"; | ||
| import { ErrorKind } from './error.js'; | ||
| import { Parser } from './parser.js'; | ||
| import { isDateElement, isDateTimeSkeleton, isNumberElement, isNumberSkeleton, isPluralElement, isSelectElement, isTagElement, isTimeElement, } from './types.js'; | ||
| import { ErrorKind } from "./error.js"; | ||
| import { Parser } from "./parser.js"; | ||
| import { isDateElement, isDateTimeSkeleton, isNumberElement, isNumberSkeleton, isPluralElement, isSelectElement, isTagElement, isTimeElement } from "./types.js"; | ||
| function pruneLocation(els) { | ||
| els.forEach(function (el) { | ||
| delete el.location; | ||
| if (isSelectElement(el) || isPluralElement(el)) { | ||
| for (var k in el.options) { | ||
| delete el.options[k].location; | ||
| pruneLocation(el.options[k].value); | ||
| } | ||
| } | ||
| else if (isNumberElement(el) && isNumberSkeleton(el.style)) { | ||
| delete el.style.location; | ||
| } | ||
| else if ((isDateElement(el) || isTimeElement(el)) && | ||
| isDateTimeSkeleton(el.style)) { | ||
| delete el.style.location; | ||
| } | ||
| else if (isTagElement(el)) { | ||
| pruneLocation(el.children); | ||
| } | ||
| }); | ||
| els.forEach((el) => { | ||
| delete el.location; | ||
| if (isSelectElement(el) || isPluralElement(el)) { | ||
| for (const k in el.options) { | ||
| delete el.options[k].location; | ||
| pruneLocation(el.options[k].value); | ||
| } | ||
| } else if (isNumberElement(el) && isNumberSkeleton(el.style)) { | ||
| delete el.style.location; | ||
| } else if ((isDateElement(el) || isTimeElement(el)) && isDateTimeSkeleton(el.style)) { | ||
| delete el.style.location; | ||
| } else if (isTagElement(el)) { | ||
| pruneLocation(el.children); | ||
| } | ||
| }); | ||
| } | ||
| export function parse(message, opts) { | ||
| if (opts === void 0) { opts = {}; } | ||
| opts = __assign({ shouldParseSkeletons: true, requiresOtherClause: true }, opts); | ||
| var result = new Parser(message, opts).parse(); | ||
| if (result.err) { | ||
| var error = SyntaxError(ErrorKind[result.err.kind]); | ||
| // @ts-expect-error Assign to error object | ||
| error.location = result.err.location; | ||
| // @ts-expect-error Assign to error object | ||
| error.originalMessage = result.err.message; | ||
| throw error; | ||
| } | ||
| if (!(opts === null || opts === void 0 ? void 0 : opts.captureLocation)) { | ||
| pruneLocation(result.val); | ||
| } | ||
| return result.val; | ||
| export function parse(message, opts = {}) { | ||
| opts = { | ||
| shouldParseSkeletons: true, | ||
| requiresOtherClause: true, | ||
| ...opts | ||
| }; | ||
| const result = new Parser(message, opts).parse(); | ||
| if (result.err) { | ||
| const error = SyntaxError(ErrorKind[result.err.kind]); | ||
| // @ts-expect-error Assign to error object | ||
| error.location = result.err.location; | ||
| // @ts-expect-error Assign to error object | ||
| error.originalMessage = result.err.message; | ||
| throw error; | ||
| } | ||
| if (!opts?.captureLocation) { | ||
| pruneLocation(result.val); | ||
| } | ||
| return result.val; | ||
| } | ||
| export * from './types.js'; | ||
| export * from "./types.js"; | ||
| // only for testing | ||
| export var _Parser = Parser; | ||
| export { isStructurallySame } from './manipulator.js'; | ||
| export const _Parser = Parser; | ||
| export { isStructurallySame } from "./manipulator.js"; |
+19
-19
@@ -1,26 +0,26 @@ | ||
| import { MessageFormatElement } from './types.js'; | ||
| import { type MessageFormatElement } from "./types.js"; | ||
| /** | ||
| * Hoist all selectors to the beginning of the AST & flatten the | ||
| * resulting options. E.g: | ||
| * "I have {count, plural, one{a dog} other{many dogs}}" | ||
| * becomes "{count, plural, one{I have a dog} other{I have many dogs}}". | ||
| * If there are multiple selectors, the order of which one is hoisted 1st | ||
| * is non-deterministic. | ||
| * The goal is to provide as many full sentences as possible since fragmented | ||
| * sentences are not translator-friendly | ||
| * @param ast AST | ||
| */ | ||
| * Hoist all selectors to the beginning of the AST & flatten the | ||
| * resulting options. E.g: | ||
| * "I have {count, plural, one{a dog} other{many dogs}}" | ||
| * becomes "{count, plural, one{I have a dog} other{I have many dogs}}". | ||
| * If there are multiple selectors, the order of which one is hoisted 1st | ||
| * is non-deterministic. | ||
| * The goal is to provide as many full sentences as possible since fragmented | ||
| * sentences are not translator-friendly | ||
| * @param ast AST | ||
| */ | ||
| export declare function hoistSelectors(ast: MessageFormatElement[]): MessageFormatElement[]; | ||
| interface IsStructurallySameResult { | ||
| error?: Error; | ||
| success: boolean; | ||
| error?: Error; | ||
| success: boolean; | ||
| } | ||
| /** | ||
| * Check if 2 ASTs are structurally the same. This primarily means that | ||
| * they have the same variables with the same type | ||
| * @param a | ||
| * @param b | ||
| * @returns | ||
| */ | ||
| * Check if 2 ASTs are structurally the same. This primarily means that | ||
| * they have the same variables with the same type | ||
| * @param a | ||
| * @param b | ||
| * @returns | ||
| */ | ||
| export declare function isStructurallySame(a: MessageFormatElement[], b: MessageFormatElement[]): IsStructurallySameResult; | ||
| export {}; |
+158
-159
@@ -1,178 +0,177 @@ | ||
| import { __assign, __spreadArray } from "tslib"; | ||
| import { isArgumentElement, isDateElement, isNumberElement, isPluralElement, isPoundElement, isSelectElement, isTagElement, isTimeElement, TYPE, } from './types.js'; | ||
| import { isArgumentElement, isDateElement, isNumberElement, isPluralElement, isPoundElement, isSelectElement, isTagElement, isTimeElement, TYPE } from "./types.js"; | ||
| function cloneDeep(obj) { | ||
| if (Array.isArray(obj)) { | ||
| // @ts-expect-error meh | ||
| return obj.map(cloneDeep); | ||
| } | ||
| if (obj !== null && typeof obj === 'object') { | ||
| // @ts-expect-error meh | ||
| return Object.keys(obj).reduce(function (cloned, k) { | ||
| // @ts-expect-error meh | ||
| cloned[k] = cloneDeep(obj[k]); | ||
| return cloned; | ||
| }, {}); | ||
| } | ||
| return obj; | ||
| if (Array.isArray(obj)) { | ||
| // @ts-expect-error meh | ||
| return obj.map(cloneDeep); | ||
| } | ||
| if (obj !== null && typeof obj === "object") { | ||
| // @ts-expect-error meh | ||
| return Object.keys(obj).reduce((cloned, k) => { | ||
| // @ts-expect-error meh | ||
| cloned[k] = cloneDeep(obj[k]); | ||
| return cloned; | ||
| }, {}); | ||
| } | ||
| return obj; | ||
| } | ||
| /** | ||
| * Replace pound elements with number elements referencing the given variable. | ||
| * This is needed when nesting plurals - the # in the outer plural should become | ||
| * an explicit variable reference when nested inside another plural. | ||
| * GH #4202 | ||
| */ | ||
| * Replace pound elements with number elements referencing the given variable. | ||
| * This is needed when nesting plurals - the # in the outer plural should become | ||
| * an explicit variable reference when nested inside another plural. | ||
| * GH #4202 | ||
| */ | ||
| function replacePoundWithArgument(ast, variableName) { | ||
| return ast.map(function (el) { | ||
| if (isPoundElement(el)) { | ||
| // Replace # with {variableName, number} | ||
| return { | ||
| type: TYPE.number, | ||
| value: variableName, | ||
| style: null, | ||
| location: el.location, | ||
| }; | ||
| } | ||
| if (isPluralElement(el) || isSelectElement(el)) { | ||
| // Recursively process options | ||
| var newOptions = {}; | ||
| for (var _i = 0, _a = Object.keys(el.options); _i < _a.length; _i++) { | ||
| var key = _a[_i]; | ||
| newOptions[key] = { | ||
| value: replacePoundWithArgument(el.options[key].value, variableName), | ||
| }; | ||
| } | ||
| return __assign(__assign({}, el), { options: newOptions }); | ||
| } | ||
| if (isTagElement(el)) { | ||
| return __assign(__assign({}, el), { children: replacePoundWithArgument(el.children, variableName) }); | ||
| } | ||
| return el; | ||
| }); | ||
| return ast.map((el) => { | ||
| if (isPoundElement(el)) { | ||
| // Replace # with {variableName, number} | ||
| return { | ||
| type: TYPE.number, | ||
| value: variableName, | ||
| style: null, | ||
| location: el.location | ||
| }; | ||
| } | ||
| if (isPluralElement(el) || isSelectElement(el)) { | ||
| // Recursively process options | ||
| const newOptions = {}; | ||
| for (const key of Object.keys(el.options)) { | ||
| newOptions[key] = { value: replacePoundWithArgument(el.options[key].value, variableName) }; | ||
| } | ||
| return { | ||
| ...el, | ||
| options: newOptions | ||
| }; | ||
| } | ||
| if (isTagElement(el)) { | ||
| return { | ||
| ...el, | ||
| children: replacePoundWithArgument(el.children, variableName) | ||
| }; | ||
| } | ||
| return el; | ||
| }); | ||
| } | ||
| function hoistPluralOrSelectElement(ast, el, positionToInject) { | ||
| // pull this out of the ast and move it to the top | ||
| var cloned = cloneDeep(el); | ||
| var options = cloned.options; | ||
| // GH #4202: Check if there are other plural/select elements after this one | ||
| var afterElements = ast.slice(positionToInject + 1); | ||
| var hasSubsequentPluralOrSelect = afterElements.some(isPluralOrSelectElement); | ||
| cloned.options = Object.keys(options).reduce(function (all, k) { | ||
| var optionValue = options[k].value; | ||
| // GH #4202: If there are subsequent plurals/selects and this is a plural, | ||
| // replace # with explicit variable reference to avoid ambiguity | ||
| if (hasSubsequentPluralOrSelect && isPluralElement(el)) { | ||
| optionValue = replacePoundWithArgument(optionValue, el.value); | ||
| } | ||
| var newValue = hoistSelectors(__spreadArray(__spreadArray(__spreadArray([], ast.slice(0, positionToInject), true), optionValue, true), afterElements, true)); | ||
| all[k] = { | ||
| value: newValue, | ||
| }; | ||
| return all; | ||
| }, {}); | ||
| return cloned; | ||
| // pull this out of the ast and move it to the top | ||
| const cloned = cloneDeep(el); | ||
| const { options } = cloned; | ||
| // GH #4202: Check if there are other plural/select elements after this one | ||
| const afterElements = ast.slice(positionToInject + 1); | ||
| const hasSubsequentPluralOrSelect = afterElements.some(isPluralOrSelectElement); | ||
| cloned.options = Object.keys(options).reduce((all, k) => { | ||
| let optionValue = options[k].value; | ||
| // GH #4202: If there are subsequent plurals/selects and this is a plural, | ||
| // replace # with explicit variable reference to avoid ambiguity | ||
| if (hasSubsequentPluralOrSelect && isPluralElement(el)) { | ||
| optionValue = replacePoundWithArgument(optionValue, el.value); | ||
| } | ||
| const newValue = hoistSelectors([ | ||
| ...ast.slice(0, positionToInject), | ||
| ...optionValue, | ||
| ...afterElements | ||
| ]); | ||
| all[k] = { value: newValue }; | ||
| return all; | ||
| }, {}); | ||
| return cloned; | ||
| } | ||
| function isPluralOrSelectElement(el) { | ||
| return isPluralElement(el) || isSelectElement(el); | ||
| return isPluralElement(el) || isSelectElement(el); | ||
| } | ||
| function findPluralOrSelectElement(ast) { | ||
| return !!ast.find(function (el) { | ||
| if (isPluralOrSelectElement(el)) { | ||
| return true; | ||
| } | ||
| if (isTagElement(el)) { | ||
| return findPluralOrSelectElement(el.children); | ||
| } | ||
| return false; | ||
| }); | ||
| return !!ast.find((el) => { | ||
| if (isPluralOrSelectElement(el)) { | ||
| return true; | ||
| } | ||
| if (isTagElement(el)) { | ||
| return findPluralOrSelectElement(el.children); | ||
| } | ||
| return false; | ||
| }); | ||
| } | ||
| /** | ||
| * Hoist all selectors to the beginning of the AST & flatten the | ||
| * resulting options. E.g: | ||
| * "I have {count, plural, one{a dog} other{many dogs}}" | ||
| * becomes "{count, plural, one{I have a dog} other{I have many dogs}}". | ||
| * If there are multiple selectors, the order of which one is hoisted 1st | ||
| * is non-deterministic. | ||
| * The goal is to provide as many full sentences as possible since fragmented | ||
| * sentences are not translator-friendly | ||
| * @param ast AST | ||
| */ | ||
| * Hoist all selectors to the beginning of the AST & flatten the | ||
| * resulting options. E.g: | ||
| * "I have {count, plural, one{a dog} other{many dogs}}" | ||
| * becomes "{count, plural, one{I have a dog} other{I have many dogs}}". | ||
| * If there are multiple selectors, the order of which one is hoisted 1st | ||
| * is non-deterministic. | ||
| * The goal is to provide as many full sentences as possible since fragmented | ||
| * sentences are not translator-friendly | ||
| * @param ast AST | ||
| */ | ||
| export function hoistSelectors(ast) { | ||
| for (var i = 0; i < ast.length; i++) { | ||
| var el = ast[i]; | ||
| if (isPluralOrSelectElement(el)) { | ||
| return [hoistPluralOrSelectElement(ast, el, i)]; | ||
| } | ||
| if (isTagElement(el) && findPluralOrSelectElement([el])) { | ||
| throw new Error('Cannot hoist plural/select within a tag element. Please put the tag element inside each plural/select option'); | ||
| } | ||
| } | ||
| return ast; | ||
| for (let i = 0; i < ast.length; i++) { | ||
| const el = ast[i]; | ||
| if (isPluralOrSelectElement(el)) { | ||
| return [hoistPluralOrSelectElement(ast, el, i)]; | ||
| } | ||
| if (isTagElement(el) && findPluralOrSelectElement([el])) { | ||
| throw new Error("Cannot hoist plural/select within a tag element. Please put the tag element inside each plural/select option"); | ||
| } | ||
| } | ||
| return ast; | ||
| } | ||
| /** | ||
| * Collect all variables in an AST to Record<string, TYPE> | ||
| * @param ast AST to collect variables from | ||
| * @param vars Record of variable name to variable type | ||
| */ | ||
| function collectVariables(ast, vars) { | ||
| if (vars === void 0) { vars = new Map(); } | ||
| ast.forEach(function (el) { | ||
| if (isArgumentElement(el) || | ||
| isDateElement(el) || | ||
| isTimeElement(el) || | ||
| isNumberElement(el)) { | ||
| if (el.value in vars && vars.get(el.value) !== el.type) { | ||
| throw new Error("Variable ".concat(el.value, " has conflicting types")); | ||
| } | ||
| vars.set(el.value, el.type); | ||
| } | ||
| if (isPluralElement(el) || isSelectElement(el)) { | ||
| vars.set(el.value, el.type); | ||
| Object.keys(el.options).forEach(function (k) { | ||
| collectVariables(el.options[k].value, vars); | ||
| }); | ||
| } | ||
| if (isTagElement(el)) { | ||
| vars.set(el.value, el.type); | ||
| collectVariables(el.children, vars); | ||
| } | ||
| }); | ||
| * Collect all variables in an AST to Record<string, TYPE> | ||
| * @param ast AST to collect variables from | ||
| * @param vars Record of variable name to variable type | ||
| */ | ||
| function collectVariables(ast, vars = new Map()) { | ||
| ast.forEach((el) => { | ||
| if (isArgumentElement(el) || isDateElement(el) || isTimeElement(el) || isNumberElement(el)) { | ||
| if (el.value in vars && vars.get(el.value) !== el.type) { | ||
| throw new Error(`Variable ${el.value} has conflicting types`); | ||
| } | ||
| vars.set(el.value, el.type); | ||
| } | ||
| if (isPluralElement(el) || isSelectElement(el)) { | ||
| vars.set(el.value, el.type); | ||
| Object.keys(el.options).forEach((k) => { | ||
| collectVariables(el.options[k].value, vars); | ||
| }); | ||
| } | ||
| if (isTagElement(el)) { | ||
| vars.set(el.value, el.type); | ||
| collectVariables(el.children, vars); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Check if 2 ASTs are structurally the same. This primarily means that | ||
| * they have the same variables with the same type | ||
| * @param a | ||
| * @param b | ||
| * @returns | ||
| */ | ||
| * Check if 2 ASTs are structurally the same. This primarily means that | ||
| * they have the same variables with the same type | ||
| * @param a | ||
| * @param b | ||
| * @returns | ||
| */ | ||
| export function isStructurallySame(a, b) { | ||
| var aVars = new Map(); | ||
| var bVars = new Map(); | ||
| collectVariables(a, aVars); | ||
| collectVariables(b, bVars); | ||
| if (aVars.size !== bVars.size) { | ||
| return { | ||
| success: false, | ||
| error: new Error("Different number of variables: [".concat(Array.from(aVars.keys()).join(', '), "] vs [").concat(Array.from(bVars.keys()).join(', '), "]")), | ||
| }; | ||
| } | ||
| return Array.from(aVars.entries()).reduce(function (result, _a) { | ||
| var key = _a[0], type = _a[1]; | ||
| if (!result.success) { | ||
| return result; | ||
| } | ||
| var bType = bVars.get(key); | ||
| if (bType == null) { | ||
| return { | ||
| success: false, | ||
| error: new Error("Missing variable ".concat(key, " in message")), | ||
| }; | ||
| } | ||
| if (bType !== type) { | ||
| return { | ||
| success: false, | ||
| error: new Error("Variable ".concat(key, " has conflicting types: ").concat(TYPE[type], " vs ").concat(TYPE[bType])), | ||
| }; | ||
| } | ||
| return result; | ||
| }, { success: true }); | ||
| const aVars = new Map(); | ||
| const bVars = new Map(); | ||
| collectVariables(a, aVars); | ||
| collectVariables(b, bVars); | ||
| if (aVars.size !== bVars.size) { | ||
| return { | ||
| success: false, | ||
| error: new Error(`Different number of variables: [${Array.from(aVars.keys()).join(", ")}] vs [${Array.from(bVars.keys()).join(", ")}]`) | ||
| }; | ||
| } | ||
| return Array.from(aVars.entries()).reduce((result, [key, type]) => { | ||
| if (!result.success) { | ||
| return result; | ||
| } | ||
| const bType = bVars.get(key); | ||
| if (bType == null) { | ||
| return { | ||
| success: false, | ||
| error: new Error(`Missing variable ${key} in message`) | ||
| }; | ||
| } | ||
| if (bType !== type) { | ||
| return { | ||
| success: false, | ||
| error: new Error(`Variable ${key} has conflicting types: ${TYPE[type]} vs ${TYPE[bType]}`) | ||
| }; | ||
| } | ||
| return result; | ||
| }, { success: true }); | ||
| } |
+2
-2
| export declare function parse(): void; | ||
| export * from './types.js'; | ||
| export * from "./types.js"; | ||
| export declare const _Parser: undefined; | ||
| export { isStructurallySame } from './manipulator.js'; | ||
| export { isStructurallySame } from "./manipulator.js"; |
+4
-4
| export function parse() { | ||
| throw new Error("You're trying to format an uncompiled message with react-intl without parser, please import from 'react-intl' instead"); | ||
| throw new Error("You're trying to format an uncompiled message with react-intl without parser, please import from 'react-intl' instead"); | ||
| } | ||
| export * from './types.js'; | ||
| export var _Parser = undefined; | ||
| export { isStructurallySame } from './manipulator.js'; | ||
| export * from "./types.js"; | ||
| export const _Parser = undefined; | ||
| export { isStructurallySame } from "./manipulator.js"; |
+3
-3
| { | ||
| "name": "@formatjs/icu-messageformat-parser", | ||
| "version": "3.2.1", | ||
| "version": "3.3.0", | ||
| "license": "MIT", | ||
@@ -15,4 +15,4 @@ "type": "module", | ||
| "tslib": "^2.8.0", | ||
| "@formatjs/ecma402-abstract": "3.0.7", | ||
| "@formatjs/icu-skeleton-parser": "2.0.7" | ||
| "@formatjs/ecma402-abstract": "3.0.8", | ||
| "@formatjs/icu-skeleton-parser": "2.0.8" | ||
| }, | ||
@@ -19,0 +19,0 @@ "repository": { |
+142
-139
@@ -1,147 +0,150 @@ | ||
| import { ParserError } from './error.js'; | ||
| import { MessageFormatElement } from './types.js'; | ||
| import { type ParserError } from "./error.js"; | ||
| import { type MessageFormatElement } from "./types.js"; | ||
| export interface Position { | ||
| /** Offset in terms of UTF-16 *code unit*. */ | ||
| offset: number; | ||
| line: number; | ||
| /** Column offset in terms of unicode *code point*. */ | ||
| column: number; | ||
| /** Offset in terms of UTF-16 *code unit*. */ | ||
| offset: number; | ||
| line: number; | ||
| /** Column offset in terms of unicode *code point*. */ | ||
| column: number; | ||
| } | ||
| export interface ParserOptions { | ||
| /** | ||
| * Whether to treat HTML/XML tags as string literal | ||
| * instead of parsing them as tag token. | ||
| * When this is false we only allow simple tags without | ||
| * any attributes | ||
| */ | ||
| ignoreTag?: boolean; | ||
| /** | ||
| * Should `select`, `selectordinal`, and `plural` arguments always include | ||
| * the `other` case clause. | ||
| */ | ||
| requiresOtherClause?: boolean; | ||
| /** | ||
| * Whether to parse number/datetime skeleton | ||
| * into Intl.NumberFormatOptions and Intl.DateTimeFormatOptions, respectively. | ||
| */ | ||
| shouldParseSkeletons?: boolean; | ||
| /** | ||
| * Capture location info in AST | ||
| * Default is false | ||
| */ | ||
| captureLocation?: boolean; | ||
| /** | ||
| * Instance of Intl.Locale to resolve locale-dependent skeleton | ||
| */ | ||
| locale?: Intl.Locale; | ||
| /** | ||
| * Whether to treat HTML/XML tags as string literal | ||
| * instead of parsing them as tag token. | ||
| * When this is false we only allow simple tags without | ||
| * any attributes | ||
| */ | ||
| ignoreTag?: boolean; | ||
| /** | ||
| * Should `select`, `selectordinal`, and `plural` arguments always include | ||
| * the `other` case clause. | ||
| */ | ||
| requiresOtherClause?: boolean; | ||
| /** | ||
| * Whether to parse number/datetime skeleton | ||
| * into Intl.NumberFormatOptions and Intl.DateTimeFormatOptions, respectively. | ||
| */ | ||
| shouldParseSkeletons?: boolean; | ||
| /** | ||
| * Capture location info in AST | ||
| * Default is false | ||
| */ | ||
| captureLocation?: boolean; | ||
| /** | ||
| * Instance of Intl.Locale to resolve locale-dependent skeleton | ||
| */ | ||
| locale?: Intl.Locale; | ||
| } | ||
| export type Result<T, E> = { | ||
| val: T; | ||
| err: null; | ||
| export type Result< | ||
| T, | ||
| E | ||
| > = { | ||
| val: T; | ||
| err: null; | ||
| } | { | ||
| val: null; | ||
| err: E; | ||
| val: null; | ||
| err: E; | ||
| }; | ||
| export declare class Parser { | ||
| private message; | ||
| private position; | ||
| private locale?; | ||
| private ignoreTag; | ||
| private requiresOtherClause; | ||
| private shouldParseSkeletons?; | ||
| constructor(message: string, options?: ParserOptions); | ||
| parse(): Result<MessageFormatElement[], ParserError>; | ||
| private parseMessage; | ||
| /** | ||
| * A tag name must start with an ASCII lower/upper case letter. The grammar is based on the | ||
| * [custom element name][] except that a dash is NOT always mandatory and uppercase letters | ||
| * are accepted: | ||
| * | ||
| * ``` | ||
| * tag ::= "<" tagName (whitespace)* "/>" | "<" tagName (whitespace)* ">" message "</" tagName (whitespace)* ">" | ||
| * tagName ::= [a-z] (PENChar)* | ||
| * PENChar ::= | ||
| * "-" | "." | [0-9] | "_" | [a-z] | [A-Z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x37D] | | ||
| * [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] | [#x2070-#x218F] | [#x2C00-#x2FEF] | | ||
| * [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] | ||
| * ``` | ||
| * | ||
| * [custom element name]: https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name | ||
| * NOTE: We're a bit more lax here since HTML technically does not allow uppercase HTML element but we do | ||
| * since other tag-based engines like React allow it | ||
| */ | ||
| private parseTag; | ||
| /** | ||
| * This method assumes that the caller has peeked ahead for the first tag character. | ||
| */ | ||
| private parseTagName; | ||
| private parseLiteral; | ||
| tryParseLeftAngleBracket(): string | null; | ||
| /** | ||
| * Starting with ICU 4.8, an ASCII apostrophe only starts quoted text if it immediately precedes | ||
| * a character that requires quoting (that is, "only where needed"), and works the same in | ||
| * nested messages as on the top level of the pattern. The new behavior is otherwise compatible. | ||
| */ | ||
| private tryParseQuote; | ||
| private tryParseUnquoted; | ||
| private parseArgument; | ||
| /** | ||
| * Advance the parser until the end of the identifier, if it is currently on | ||
| * an identifier character. Return an empty string otherwise. | ||
| */ | ||
| private parseIdentifierIfPossible; | ||
| private parseArgumentOptions; | ||
| private tryParseArgumentClose; | ||
| /** | ||
| * See: https://github.com/unicode-org/icu/blob/af7ed1f6d2298013dc303628438ec4abe1f16479/icu4c/source/common/messagepattern.cpp#L659 | ||
| */ | ||
| private parseSimpleArgStyleIfPossible; | ||
| private parseNumberSkeletonFromString; | ||
| /** | ||
| * @param nesting_level The current nesting level of messages. | ||
| * This can be positive when parsing message fragment in select or plural argument options. | ||
| * @param parent_arg_type The parent argument's type. | ||
| * @param parsed_first_identifier If provided, this is the first identifier-like selector of | ||
| * the argument. It is a by-product of a previous parsing attempt. | ||
| * @param expecting_close_tag If true, this message is directly or indirectly nested inside | ||
| * between a pair of opening and closing tags. The nested message will not parse beyond | ||
| * the closing tag boundary. | ||
| */ | ||
| private tryParsePluralOrSelectOptions; | ||
| private tryParseDecimalInteger; | ||
| private offset; | ||
| private isEOF; | ||
| private clonePosition; | ||
| /** | ||
| * Return the code point at the current position of the parser. | ||
| * Throws if the index is out of bound. | ||
| */ | ||
| private char; | ||
| private error; | ||
| /** Bump the parser to the next UTF-16 code unit. */ | ||
| private bump; | ||
| /** | ||
| * If the substring starting at the current position of the parser has | ||
| * the given prefix, then bump the parser to the character immediately | ||
| * following the prefix and return true. Otherwise, don't bump the parser | ||
| * and return false. | ||
| */ | ||
| private bumpIf; | ||
| /** | ||
| * Bump the parser until the pattern character is found and return `true`. | ||
| * Otherwise bump to the end of the file and return `false`. | ||
| */ | ||
| private bumpUntil; | ||
| /** | ||
| * Bump the parser to the target offset. | ||
| * If target offset is beyond the end of the input, bump the parser to the end of the input. | ||
| */ | ||
| private bumpTo; | ||
| /** advance the parser through all whitespace to the next non-whitespace code unit. */ | ||
| private bumpSpace; | ||
| /** | ||
| * Peek at the *next* Unicode codepoint in the input without advancing the parser. | ||
| * If the input has been exhausted, then this returns null. | ||
| */ | ||
| private peek; | ||
| private message; | ||
| private position; | ||
| private locale?; | ||
| private ignoreTag; | ||
| private requiresOtherClause; | ||
| private shouldParseSkeletons?; | ||
| constructor(message: string, options?: ParserOptions); | ||
| parse(): Result<MessageFormatElement[], ParserError>; | ||
| private parseMessage; | ||
| /** | ||
| * A tag name must start with an ASCII lower/upper case letter. The grammar is based on the | ||
| * [custom element name][] except that a dash is NOT always mandatory and uppercase letters | ||
| * are accepted: | ||
| * | ||
| * ``` | ||
| * tag ::= "<" tagName (whitespace)* "/>" | "<" tagName (whitespace)* ">" message "</" tagName (whitespace)* ">" | ||
| * tagName ::= [a-z] (PENChar)* | ||
| * PENChar ::= | ||
| * "-" | "." | [0-9] | "_" | [a-z] | [A-Z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x37D] | | ||
| * [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] | [#x2070-#x218F] | [#x2C00-#x2FEF] | | ||
| * [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] | ||
| * ``` | ||
| * | ||
| * [custom element name]: https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name | ||
| * NOTE: We're a bit more lax here since HTML technically does not allow uppercase HTML element but we do | ||
| * since other tag-based engines like React allow it | ||
| */ | ||
| private parseTag; | ||
| /** | ||
| * This method assumes that the caller has peeked ahead for the first tag character. | ||
| */ | ||
| private parseTagName; | ||
| private parseLiteral; | ||
| tryParseLeftAngleBracket(): string | null; | ||
| /** | ||
| * Starting with ICU 4.8, an ASCII apostrophe only starts quoted text if it immediately precedes | ||
| * a character that requires quoting (that is, "only where needed"), and works the same in | ||
| * nested messages as on the top level of the pattern. The new behavior is otherwise compatible. | ||
| */ | ||
| private tryParseQuote; | ||
| private tryParseUnquoted; | ||
| private parseArgument; | ||
| /** | ||
| * Advance the parser until the end of the identifier, if it is currently on | ||
| * an identifier character. Return an empty string otherwise. | ||
| */ | ||
| private parseIdentifierIfPossible; | ||
| private parseArgumentOptions; | ||
| private tryParseArgumentClose; | ||
| /** | ||
| * See: https://github.com/unicode-org/icu/blob/af7ed1f6d2298013dc303628438ec4abe1f16479/icu4c/source/common/messagepattern.cpp#L659 | ||
| */ | ||
| private parseSimpleArgStyleIfPossible; | ||
| private parseNumberSkeletonFromString; | ||
| /** | ||
| * @param nesting_level The current nesting level of messages. | ||
| * This can be positive when parsing message fragment in select or plural argument options. | ||
| * @param parent_arg_type The parent argument's type. | ||
| * @param parsed_first_identifier If provided, this is the first identifier-like selector of | ||
| * the argument. It is a by-product of a previous parsing attempt. | ||
| * @param expecting_close_tag If true, this message is directly or indirectly nested inside | ||
| * between a pair of opening and closing tags. The nested message will not parse beyond | ||
| * the closing tag boundary. | ||
| */ | ||
| private tryParsePluralOrSelectOptions; | ||
| private tryParseDecimalInteger; | ||
| private offset; | ||
| private isEOF; | ||
| private clonePosition; | ||
| /** | ||
| * Return the code point at the current position of the parser. | ||
| * Throws if the index is out of bound. | ||
| */ | ||
| private char; | ||
| private error; | ||
| /** Bump the parser to the next UTF-16 code unit. */ | ||
| private bump; | ||
| /** | ||
| * If the substring starting at the current position of the parser has | ||
| * the given prefix, then bump the parser to the character immediately | ||
| * following the prefix and return true. Otherwise, don't bump the parser | ||
| * and return false. | ||
| */ | ||
| private bumpIf; | ||
| /** | ||
| * Bump the parser until the pattern character is found and return `true`. | ||
| * Otherwise bump to the end of the file and return `false`. | ||
| */ | ||
| private bumpUntil; | ||
| /** | ||
| * Bump the parser to the target offset. | ||
| * If target offset is beyond the end of the input, bump the parser to the end of the input. | ||
| */ | ||
| private bumpTo; | ||
| /** advance the parser through all whitespace to the next non-whitespace code unit. */ | ||
| private bumpSpace; | ||
| /** | ||
| * Peek at the *next* Unicode codepoint in the input without advancing the parser. | ||
| * If the input has been exhausted, then this returns null. | ||
| */ | ||
| private peek; | ||
| } |
+839
-900
@@ -1,918 +0,857 @@ | ||
| import { __assign } from "tslib"; | ||
| import { ErrorKind } from './error.js'; | ||
| import { SKELETON_TYPE, TYPE, } from './types.js'; | ||
| import { SPACE_SEPARATOR_REGEX } from './regex.generated.js'; | ||
| import { parseNumberSkeleton, parseNumberSkeletonFromString, parseDateTimeSkeleton, } from '@formatjs/icu-skeleton-parser'; | ||
| import { getBestPattern } from './date-time-pattern-generator.js'; | ||
| var SPACE_SEPARATOR_START_REGEX = new RegExp("^".concat(SPACE_SEPARATOR_REGEX.source, "*")); | ||
| var SPACE_SEPARATOR_END_REGEX = new RegExp("".concat(SPACE_SEPARATOR_REGEX.source, "*$")); | ||
| import { ErrorKind } from "./error.js"; | ||
| import { SKELETON_TYPE, TYPE } from "./types.js"; | ||
| import { SPACE_SEPARATOR_REGEX } from "./regex.generated.js"; | ||
| import { parseNumberSkeleton, parseNumberSkeletonFromString, parseDateTimeSkeleton } from "@formatjs/icu-skeleton-parser"; | ||
| import { getBestPattern } from "./date-time-pattern-generator.js"; | ||
| const SPACE_SEPARATOR_START_REGEX = new RegExp(`^${SPACE_SEPARATOR_REGEX.source}*`); | ||
| const SPACE_SEPARATOR_END_REGEX = new RegExp(`${SPACE_SEPARATOR_REGEX.source}*$`); | ||
| function createLocation(start, end) { | ||
| return { start: start, end: end }; | ||
| return { | ||
| start, | ||
| end | ||
| }; | ||
| } | ||
| // #region Ponyfills | ||
| // Consolidate these variables up top for easier toggling during debugging | ||
| var hasNativeFromEntries = !!Object.fromEntries; | ||
| var hasTrimStart = !!String.prototype.trimStart; | ||
| var hasTrimEnd = !!String.prototype.trimEnd; | ||
| var fromEntries = | ||
| // native | ||
| hasNativeFromEntries | ||
| ? Object.fromEntries | ||
| : // Ponyfill | ||
| function fromEntries(entries) { | ||
| var obj = {}; | ||
| for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) { | ||
| var _a = entries_1[_i], k = _a[0], v = _a[1]; | ||
| obj[k] = v; | ||
| } | ||
| return obj; | ||
| }; | ||
| var trimStart = hasTrimStart | ||
| ? // Native | ||
| function trimStart(s) { | ||
| return s.trimStart(); | ||
| } | ||
| : // Ponyfill | ||
| function trimStart(s) { | ||
| return s.replace(SPACE_SEPARATOR_START_REGEX, ''); | ||
| }; | ||
| var trimEnd = hasTrimEnd | ||
| ? // Native | ||
| function trimEnd(s) { | ||
| return s.trimEnd(); | ||
| } | ||
| : // Ponyfill | ||
| function trimEnd(s) { | ||
| return s.replace(SPACE_SEPARATOR_END_REGEX, ''); | ||
| }; | ||
| const hasNativeFromEntries = !!Object.fromEntries; | ||
| const hasTrimStart = !!String.prototype.trimStart; | ||
| const hasTrimEnd = !!String.prototype.trimEnd; | ||
| const fromEntries = hasNativeFromEntries ? Object.fromEntries : function fromEntries(entries) { | ||
| const obj = {}; | ||
| for (const [k, v] of entries) { | ||
| obj[k] = v; | ||
| } | ||
| return obj; | ||
| }; | ||
| const trimStart = hasTrimStart ? function trimStart(s) { | ||
| return s.trimStart(); | ||
| } : function trimStart(s) { | ||
| return s.replace(SPACE_SEPARATOR_START_REGEX, ""); | ||
| }; | ||
| const trimEnd = hasTrimEnd ? function trimEnd(s) { | ||
| return s.trimEnd(); | ||
| } : function trimEnd(s) { | ||
| return s.replace(SPACE_SEPARATOR_END_REGEX, ""); | ||
| }; | ||
| // #endregion | ||
| var IDENTIFIER_PREFIX_RE = new RegExp('([^\\p{White_Space}\\p{Pattern_Syntax}]*)', 'yu'); | ||
| const IDENTIFIER_PREFIX_RE = new RegExp("([^\\p{White_Space}\\p{Pattern_Syntax}]*)", "yu"); | ||
| function matchIdentifierAtIndex(s, index) { | ||
| var _a; | ||
| IDENTIFIER_PREFIX_RE.lastIndex = index; | ||
| var match = IDENTIFIER_PREFIX_RE.exec(s); | ||
| return (_a = match[1]) !== null && _a !== void 0 ? _a : ''; | ||
| IDENTIFIER_PREFIX_RE.lastIndex = index; | ||
| const match = IDENTIFIER_PREFIX_RE.exec(s); | ||
| return match[1] ?? ""; | ||
| } | ||
| var Parser = /** @class */ (function () { | ||
| function Parser(message, options) { | ||
| if (options === void 0) { options = {}; } | ||
| this.message = message; | ||
| this.position = { offset: 0, line: 1, column: 1 }; | ||
| this.ignoreTag = !!options.ignoreTag; | ||
| this.locale = options.locale; | ||
| this.requiresOtherClause = !!options.requiresOtherClause; | ||
| this.shouldParseSkeletons = !!options.shouldParseSkeletons; | ||
| } | ||
| Parser.prototype.parse = function () { | ||
| if (this.offset() !== 0) { | ||
| throw Error('parser can only be used once'); | ||
| } | ||
| return this.parseMessage(0, '', false); | ||
| }; | ||
| Parser.prototype.parseMessage = function (nestingLevel, parentArgType, expectingCloseTag) { | ||
| var elements = []; | ||
| while (!this.isEOF()) { | ||
| var char = this.char(); | ||
| if (char === 123 /* `{` */) { | ||
| var result = this.parseArgument(nestingLevel, expectingCloseTag); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| elements.push(result.val); | ||
| } | ||
| else if (char === 125 /* `}` */ && nestingLevel > 0) { | ||
| break; | ||
| } | ||
| else if (char === 35 /* `#` */ && | ||
| (parentArgType === 'plural' || parentArgType === 'selectordinal')) { | ||
| var position = this.clonePosition(); | ||
| this.bump(); | ||
| elements.push({ | ||
| type: TYPE.pound, | ||
| location: createLocation(position, this.clonePosition()), | ||
| }); | ||
| } | ||
| else if (char === 60 /* `<` */ && | ||
| !this.ignoreTag && | ||
| this.peek() === 47 // char code for '/' | ||
| ) { | ||
| if (expectingCloseTag) { | ||
| break; | ||
| } | ||
| else { | ||
| return this.error(ErrorKind.UNMATCHED_CLOSING_TAG, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| } | ||
| else if (char === 60 /* `<` */ && | ||
| !this.ignoreTag && | ||
| _isAlpha(this.peek() || 0)) { | ||
| var result = this.parseTag(nestingLevel, parentArgType); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| elements.push(result.val); | ||
| } | ||
| else { | ||
| var result = this.parseLiteral(nestingLevel, parentArgType); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| elements.push(result.val); | ||
| } | ||
| } | ||
| return { val: elements, err: null }; | ||
| }; | ||
| /** | ||
| * A tag name must start with an ASCII lower/upper case letter. The grammar is based on the | ||
| * [custom element name][] except that a dash is NOT always mandatory and uppercase letters | ||
| * are accepted: | ||
| * | ||
| * ``` | ||
| * tag ::= "<" tagName (whitespace)* "/>" | "<" tagName (whitespace)* ">" message "</" tagName (whitespace)* ">" | ||
| * tagName ::= [a-z] (PENChar)* | ||
| * PENChar ::= | ||
| * "-" | "." | [0-9] | "_" | [a-z] | [A-Z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x37D] | | ||
| * [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] | [#x2070-#x218F] | [#x2C00-#x2FEF] | | ||
| * [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] | ||
| * ``` | ||
| * | ||
| * [custom element name]: https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name | ||
| * NOTE: We're a bit more lax here since HTML technically does not allow uppercase HTML element but we do | ||
| * since other tag-based engines like React allow it | ||
| */ | ||
| Parser.prototype.parseTag = function (nestingLevel, parentArgType) { | ||
| var startPosition = this.clonePosition(); | ||
| this.bump(); // `<` | ||
| var tagName = this.parseTagName(); | ||
| this.bumpSpace(); | ||
| if (this.bumpIf('/>')) { | ||
| // Self closing tag | ||
| return { | ||
| val: { | ||
| type: TYPE.literal, | ||
| value: "<".concat(tagName, "/>"), | ||
| location: createLocation(startPosition, this.clonePosition()), | ||
| }, | ||
| err: null, | ||
| }; | ||
| } | ||
| else if (this.bumpIf('>')) { | ||
| var childrenResult = this.parseMessage(nestingLevel + 1, parentArgType, true); | ||
| if (childrenResult.err) { | ||
| return childrenResult; | ||
| } | ||
| var children = childrenResult.val; | ||
| // Expecting a close tag | ||
| var endTagStartPosition = this.clonePosition(); | ||
| if (this.bumpIf('</')) { | ||
| if (this.isEOF() || !_isAlpha(this.char())) { | ||
| return this.error(ErrorKind.INVALID_TAG, createLocation(endTagStartPosition, this.clonePosition())); | ||
| } | ||
| var closingTagNameStartPosition = this.clonePosition(); | ||
| var closingTagName = this.parseTagName(); | ||
| if (tagName !== closingTagName) { | ||
| return this.error(ErrorKind.UNMATCHED_CLOSING_TAG, createLocation(closingTagNameStartPosition, this.clonePosition())); | ||
| } | ||
| this.bumpSpace(); | ||
| if (!this.bumpIf('>')) { | ||
| return this.error(ErrorKind.INVALID_TAG, createLocation(endTagStartPosition, this.clonePosition())); | ||
| } | ||
| return { | ||
| val: { | ||
| type: TYPE.tag, | ||
| value: tagName, | ||
| children: children, | ||
| location: createLocation(startPosition, this.clonePosition()), | ||
| }, | ||
| err: null, | ||
| }; | ||
| } | ||
| else { | ||
| return this.error(ErrorKind.UNCLOSED_TAG, createLocation(startPosition, this.clonePosition())); | ||
| } | ||
| } | ||
| else { | ||
| return this.error(ErrorKind.INVALID_TAG, createLocation(startPosition, this.clonePosition())); | ||
| } | ||
| }; | ||
| /** | ||
| * This method assumes that the caller has peeked ahead for the first tag character. | ||
| */ | ||
| Parser.prototype.parseTagName = function () { | ||
| var startOffset = this.offset(); | ||
| this.bump(); // the first tag name character | ||
| while (!this.isEOF() && _isPotentialElementNameChar(this.char())) { | ||
| this.bump(); | ||
| } | ||
| return this.message.slice(startOffset, this.offset()); | ||
| }; | ||
| Parser.prototype.parseLiteral = function (nestingLevel, parentArgType) { | ||
| var start = this.clonePosition(); | ||
| var value = ''; | ||
| while (true) { | ||
| var parseQuoteResult = this.tryParseQuote(parentArgType); | ||
| if (parseQuoteResult) { | ||
| value += parseQuoteResult; | ||
| continue; | ||
| } | ||
| var parseUnquotedResult = this.tryParseUnquoted(nestingLevel, parentArgType); | ||
| if (parseUnquotedResult) { | ||
| value += parseUnquotedResult; | ||
| continue; | ||
| } | ||
| var parseLeftAngleResult = this.tryParseLeftAngleBracket(); | ||
| if (parseLeftAngleResult) { | ||
| value += parseLeftAngleResult; | ||
| continue; | ||
| } | ||
| break; | ||
| } | ||
| var location = createLocation(start, this.clonePosition()); | ||
| return { | ||
| val: { type: TYPE.literal, value: value, location: location }, | ||
| err: null, | ||
| }; | ||
| }; | ||
| Parser.prototype.tryParseLeftAngleBracket = function () { | ||
| if (!this.isEOF() && | ||
| this.char() === 60 /* `<` */ && | ||
| (this.ignoreTag || | ||
| // If at the opening tag or closing tag position, bail. | ||
| !_isAlphaOrSlash(this.peek() || 0))) { | ||
| this.bump(); // `<` | ||
| return '<'; | ||
| } | ||
| return null; | ||
| }; | ||
| /** | ||
| * Starting with ICU 4.8, an ASCII apostrophe only starts quoted text if it immediately precedes | ||
| * a character that requires quoting (that is, "only where needed"), and works the same in | ||
| * nested messages as on the top level of the pattern. The new behavior is otherwise compatible. | ||
| */ | ||
| Parser.prototype.tryParseQuote = function (parentArgType) { | ||
| if (this.isEOF() || this.char() !== 39 /* `'` */) { | ||
| return null; | ||
| } | ||
| // Parse escaped char following the apostrophe, or early return if there is no escaped char. | ||
| // Check if is valid escaped character | ||
| switch (this.peek()) { | ||
| case 39 /* `'` */: | ||
| // double quote, should return as a single quote. | ||
| this.bump(); | ||
| this.bump(); | ||
| return "'"; | ||
| // '{', '<', '>', '}' | ||
| case 123: | ||
| case 60: | ||
| case 62: | ||
| case 125: | ||
| break; | ||
| case 35: // '#' | ||
| if (parentArgType === 'plural' || parentArgType === 'selectordinal') { | ||
| break; | ||
| } | ||
| return null; | ||
| default: | ||
| return null; | ||
| } | ||
| this.bump(); // apostrophe | ||
| var codePoints = [this.char()]; // escaped char | ||
| this.bump(); | ||
| // read chars until the optional closing apostrophe is found | ||
| while (!this.isEOF()) { | ||
| var ch = this.char(); | ||
| if (ch === 39 /* `'` */) { | ||
| if (this.peek() === 39 /* `'` */) { | ||
| codePoints.push(39); | ||
| // Bump one more time because we need to skip 2 characters. | ||
| this.bump(); | ||
| } | ||
| else { | ||
| // Optional closing apostrophe. | ||
| this.bump(); | ||
| break; | ||
| } | ||
| } | ||
| else { | ||
| codePoints.push(ch); | ||
| } | ||
| this.bump(); | ||
| } | ||
| return String.fromCodePoint.apply(String, codePoints); | ||
| }; | ||
| Parser.prototype.tryParseUnquoted = function (nestingLevel, parentArgType) { | ||
| if (this.isEOF()) { | ||
| return null; | ||
| } | ||
| var ch = this.char(); | ||
| if (ch === 60 /* `<` */ || | ||
| ch === 123 /* `{` */ || | ||
| (ch === 35 /* `#` */ && | ||
| (parentArgType === 'plural' || parentArgType === 'selectordinal')) || | ||
| (ch === 125 /* `}` */ && nestingLevel > 0)) { | ||
| return null; | ||
| } | ||
| else { | ||
| this.bump(); | ||
| return String.fromCodePoint(ch); | ||
| } | ||
| }; | ||
| Parser.prototype.parseArgument = function (nestingLevel, expectingCloseTag) { | ||
| var openingBracePosition = this.clonePosition(); | ||
| this.bump(); // `{` | ||
| this.bumpSpace(); | ||
| if (this.isEOF()) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| if (this.char() === 125 /* `}` */) { | ||
| this.bump(); | ||
| return this.error(ErrorKind.EMPTY_ARGUMENT, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| // argument name | ||
| var value = this.parseIdentifierIfPossible().value; | ||
| if (!value) { | ||
| return this.error(ErrorKind.MALFORMED_ARGUMENT, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| this.bumpSpace(); | ||
| if (this.isEOF()) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| switch (this.char()) { | ||
| // Simple argument: `{name}` | ||
| case 125 /* `}` */: { | ||
| this.bump(); // `}` | ||
| return { | ||
| val: { | ||
| type: TYPE.argument, | ||
| // value does not include the opening and closing braces. | ||
| value: value, | ||
| location: createLocation(openingBracePosition, this.clonePosition()), | ||
| }, | ||
| err: null, | ||
| }; | ||
| } | ||
| // Argument with options: `{name, format, ...}` | ||
| case 44 /* `,` */: { | ||
| this.bump(); // `,` | ||
| this.bumpSpace(); | ||
| if (this.isEOF()) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| return this.parseArgumentOptions(nestingLevel, expectingCloseTag, value, openingBracePosition); | ||
| } | ||
| default: | ||
| return this.error(ErrorKind.MALFORMED_ARGUMENT, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| }; | ||
| /** | ||
| * Advance the parser until the end of the identifier, if it is currently on | ||
| * an identifier character. Return an empty string otherwise. | ||
| */ | ||
| Parser.prototype.parseIdentifierIfPossible = function () { | ||
| var startingPosition = this.clonePosition(); | ||
| var startOffset = this.offset(); | ||
| var value = matchIdentifierAtIndex(this.message, startOffset); | ||
| var endOffset = startOffset + value.length; | ||
| this.bumpTo(endOffset); | ||
| var endPosition = this.clonePosition(); | ||
| var location = createLocation(startingPosition, endPosition); | ||
| return { value: value, location: location }; | ||
| }; | ||
| Parser.prototype.parseArgumentOptions = function (nestingLevel, expectingCloseTag, value, openingBracePosition) { | ||
| var _a; | ||
| // Parse this range: | ||
| // {name, type, style} | ||
| // ^---^ | ||
| var typeStartPosition = this.clonePosition(); | ||
| var argType = this.parseIdentifierIfPossible().value; | ||
| var typeEndPosition = this.clonePosition(); | ||
| switch (argType) { | ||
| case '': | ||
| // Expecting a style string number, date, time, plural, selectordinal, or select. | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_TYPE, createLocation(typeStartPosition, typeEndPosition)); | ||
| case 'number': | ||
| case 'date': | ||
| case 'time': { | ||
| // Parse this range: | ||
| // {name, number, style} | ||
| // ^-------^ | ||
| this.bumpSpace(); | ||
| var styleAndLocation = null; | ||
| if (this.bumpIf(',')) { | ||
| this.bumpSpace(); | ||
| var styleStartPosition = this.clonePosition(); | ||
| var result = this.parseSimpleArgStyleIfPossible(); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| var style = trimEnd(result.val); | ||
| if (style.length === 0) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_STYLE, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| var styleLocation = createLocation(styleStartPosition, this.clonePosition()); | ||
| styleAndLocation = { style: style, styleLocation: styleLocation }; | ||
| } | ||
| var argCloseResult = this.tryParseArgumentClose(openingBracePosition); | ||
| if (argCloseResult.err) { | ||
| return argCloseResult; | ||
| } | ||
| var location_1 = createLocation(openingBracePosition, this.clonePosition()); | ||
| // Extract style or skeleton | ||
| if (styleAndLocation && styleAndLocation.style.startsWith('::')) { | ||
| // Skeleton starts with `::`. | ||
| var skeleton = trimStart(styleAndLocation.style.slice(2)); | ||
| if (argType === 'number') { | ||
| var result = this.parseNumberSkeletonFromString(skeleton, styleAndLocation.styleLocation); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| return { | ||
| val: { type: TYPE.number, value: value, location: location_1, style: result.val }, | ||
| err: null, | ||
| }; | ||
| } | ||
| else { | ||
| if (skeleton.length === 0) { | ||
| return this.error(ErrorKind.EXPECT_DATE_TIME_SKELETON, location_1); | ||
| } | ||
| var dateTimePattern = skeleton; | ||
| // Get "best match" pattern only if locale is passed, if not, let it | ||
| // pass as-is where `parseDateTimeSkeleton()` will throw an error | ||
| // for unsupported patterns. | ||
| if (this.locale) { | ||
| dateTimePattern = getBestPattern(skeleton, this.locale); | ||
| } | ||
| var style = { | ||
| type: SKELETON_TYPE.dateTime, | ||
| pattern: dateTimePattern, | ||
| location: styleAndLocation.styleLocation, | ||
| parsedOptions: this.shouldParseSkeletons | ||
| ? parseDateTimeSkeleton(dateTimePattern) | ||
| : {}, | ||
| }; | ||
| var type = argType === 'date' ? TYPE.date : TYPE.time; | ||
| return { | ||
| val: { type: type, value: value, location: location_1, style: style }, | ||
| err: null, | ||
| }; | ||
| } | ||
| } | ||
| // Regular style or no style. | ||
| return { | ||
| val: { | ||
| type: argType === 'number' | ||
| ? TYPE.number | ||
| : argType === 'date' | ||
| ? TYPE.date | ||
| : TYPE.time, | ||
| value: value, | ||
| location: location_1, | ||
| style: (_a = styleAndLocation === null || styleAndLocation === void 0 ? void 0 : styleAndLocation.style) !== null && _a !== void 0 ? _a : null, | ||
| }, | ||
| err: null, | ||
| }; | ||
| } | ||
| case 'plural': | ||
| case 'selectordinal': | ||
| case 'select': { | ||
| // Parse this range: | ||
| // {name, plural, options} | ||
| // ^---------^ | ||
| var typeEndPosition_1 = this.clonePosition(); | ||
| this.bumpSpace(); | ||
| if (!this.bumpIf(',')) { | ||
| return this.error(ErrorKind.EXPECT_SELECT_ARGUMENT_OPTIONS, createLocation(typeEndPosition_1, __assign({}, typeEndPosition_1))); | ||
| } | ||
| this.bumpSpace(); | ||
| // Parse offset: | ||
| // {name, plural, offset:1, options} | ||
| // ^-----^ | ||
| // | ||
| // or the first option: | ||
| // | ||
| // {name, plural, one {...} other {...}} | ||
| // ^--^ | ||
| var identifierAndLocation = this.parseIdentifierIfPossible(); | ||
| var pluralOffset = 0; | ||
| if (argType !== 'select' && identifierAndLocation.value === 'offset') { | ||
| if (!this.bumpIf(':')) { | ||
| return this.error(ErrorKind.EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| this.bumpSpace(); | ||
| var result = this.tryParseDecimalInteger(ErrorKind.EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE, ErrorKind.INVALID_PLURAL_ARGUMENT_OFFSET_VALUE); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| // Parse another identifier for option parsing | ||
| this.bumpSpace(); | ||
| identifierAndLocation = this.parseIdentifierIfPossible(); | ||
| pluralOffset = result.val; | ||
| } | ||
| var optionsResult = this.tryParsePluralOrSelectOptions(nestingLevel, argType, expectingCloseTag, identifierAndLocation); | ||
| if (optionsResult.err) { | ||
| return optionsResult; | ||
| } | ||
| var argCloseResult = this.tryParseArgumentClose(openingBracePosition); | ||
| if (argCloseResult.err) { | ||
| return argCloseResult; | ||
| } | ||
| var location_2 = createLocation(openingBracePosition, this.clonePosition()); | ||
| if (argType === 'select') { | ||
| return { | ||
| val: { | ||
| type: TYPE.select, | ||
| value: value, | ||
| options: fromEntries(optionsResult.val), | ||
| location: location_2, | ||
| }, | ||
| err: null, | ||
| }; | ||
| } | ||
| else { | ||
| return { | ||
| val: { | ||
| type: TYPE.plural, | ||
| value: value, | ||
| options: fromEntries(optionsResult.val), | ||
| offset: pluralOffset, | ||
| pluralType: argType === 'plural' ? 'cardinal' : 'ordinal', | ||
| location: location_2, | ||
| }, | ||
| err: null, | ||
| }; | ||
| } | ||
| } | ||
| default: | ||
| return this.error(ErrorKind.INVALID_ARGUMENT_TYPE, createLocation(typeStartPosition, typeEndPosition)); | ||
| } | ||
| }; | ||
| Parser.prototype.tryParseArgumentClose = function (openingBracePosition) { | ||
| // Parse: {value, number, ::currency/GBP } | ||
| // | ||
| if (this.isEOF() || this.char() !== 125 /* `}` */) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| this.bump(); // `}` | ||
| return { val: true, err: null }; | ||
| }; | ||
| /** | ||
| * See: https://github.com/unicode-org/icu/blob/af7ed1f6d2298013dc303628438ec4abe1f16479/icu4c/source/common/messagepattern.cpp#L659 | ||
| */ | ||
| Parser.prototype.parseSimpleArgStyleIfPossible = function () { | ||
| var nestedBraces = 0; | ||
| var startPosition = this.clonePosition(); | ||
| while (!this.isEOF()) { | ||
| var ch = this.char(); | ||
| switch (ch) { | ||
| case 39 /* `'` */: { | ||
| // Treat apostrophe as quoting but include it in the style part. | ||
| // Find the end of the quoted literal text. | ||
| this.bump(); | ||
| var apostrophePosition = this.clonePosition(); | ||
| if (!this.bumpUntil("'")) { | ||
| return this.error(ErrorKind.UNCLOSED_QUOTE_IN_ARGUMENT_STYLE, createLocation(apostrophePosition, this.clonePosition())); | ||
| } | ||
| this.bump(); | ||
| break; | ||
| } | ||
| case 123 /* `{` */: { | ||
| nestedBraces += 1; | ||
| this.bump(); | ||
| break; | ||
| } | ||
| case 125 /* `}` */: { | ||
| if (nestedBraces > 0) { | ||
| nestedBraces -= 1; | ||
| } | ||
| else { | ||
| return { | ||
| val: this.message.slice(startPosition.offset, this.offset()), | ||
| err: null, | ||
| }; | ||
| } | ||
| break; | ||
| } | ||
| default: | ||
| this.bump(); | ||
| break; | ||
| } | ||
| } | ||
| return { | ||
| val: this.message.slice(startPosition.offset, this.offset()), | ||
| err: null, | ||
| }; | ||
| }; | ||
| Parser.prototype.parseNumberSkeletonFromString = function (skeleton, location) { | ||
| var tokens = []; | ||
| try { | ||
| tokens = parseNumberSkeletonFromString(skeleton); | ||
| } | ||
| catch (_a) { | ||
| return this.error(ErrorKind.INVALID_NUMBER_SKELETON, location); | ||
| } | ||
| return { | ||
| val: { | ||
| type: SKELETON_TYPE.number, | ||
| tokens: tokens, | ||
| location: location, | ||
| parsedOptions: this.shouldParseSkeletons | ||
| ? parseNumberSkeleton(tokens) | ||
| : {}, | ||
| }, | ||
| err: null, | ||
| }; | ||
| }; | ||
| /** | ||
| * @param nesting_level The current nesting level of messages. | ||
| * This can be positive when parsing message fragment in select or plural argument options. | ||
| * @param parent_arg_type The parent argument's type. | ||
| * @param parsed_first_identifier If provided, this is the first identifier-like selector of | ||
| * the argument. It is a by-product of a previous parsing attempt. | ||
| * @param expecting_close_tag If true, this message is directly or indirectly nested inside | ||
| * between a pair of opening and closing tags. The nested message will not parse beyond | ||
| * the closing tag boundary. | ||
| */ | ||
| Parser.prototype.tryParsePluralOrSelectOptions = function (nestingLevel, parentArgType, expectCloseTag, parsedFirstIdentifier) { | ||
| var _a; | ||
| var hasOtherClause = false; | ||
| var options = []; | ||
| var parsedSelectors = new Set(); | ||
| var selector = parsedFirstIdentifier.value, selectorLocation = parsedFirstIdentifier.location; | ||
| // Parse: | ||
| // one {one apple} | ||
| // ^--^ | ||
| while (true) { | ||
| if (selector.length === 0) { | ||
| var startPosition = this.clonePosition(); | ||
| if (parentArgType !== 'select' && this.bumpIf('=')) { | ||
| // Try parse `={number}` selector | ||
| var result = this.tryParseDecimalInteger(ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR, ErrorKind.INVALID_PLURAL_ARGUMENT_SELECTOR); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| selectorLocation = createLocation(startPosition, this.clonePosition()); | ||
| selector = this.message.slice(startPosition.offset, this.offset()); | ||
| } | ||
| else { | ||
| break; | ||
| } | ||
| } | ||
| // Duplicate selector clauses | ||
| if (parsedSelectors.has(selector)) { | ||
| return this.error(parentArgType === 'select' | ||
| ? ErrorKind.DUPLICATE_SELECT_ARGUMENT_SELECTOR | ||
| : ErrorKind.DUPLICATE_PLURAL_ARGUMENT_SELECTOR, selectorLocation); | ||
| } | ||
| if (selector === 'other') { | ||
| hasOtherClause = true; | ||
| } | ||
| // Parse: | ||
| // one {one apple} | ||
| // ^----------^ | ||
| this.bumpSpace(); | ||
| var openingBracePosition = this.clonePosition(); | ||
| if (!this.bumpIf('{')) { | ||
| return this.error(parentArgType === 'select' | ||
| ? ErrorKind.EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT | ||
| : ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| var fragmentResult = this.parseMessage(nestingLevel + 1, parentArgType, expectCloseTag); | ||
| if (fragmentResult.err) { | ||
| return fragmentResult; | ||
| } | ||
| var argCloseResult = this.tryParseArgumentClose(openingBracePosition); | ||
| if (argCloseResult.err) { | ||
| return argCloseResult; | ||
| } | ||
| options.push([ | ||
| selector, | ||
| { | ||
| value: fragmentResult.val, | ||
| location: createLocation(openingBracePosition, this.clonePosition()), | ||
| }, | ||
| ]); | ||
| // Keep track of the existing selectors | ||
| parsedSelectors.add(selector); | ||
| // Prep next selector clause. | ||
| this.bumpSpace(); | ||
| (_a = this.parseIdentifierIfPossible(), selector = _a.value, selectorLocation = _a.location); | ||
| } | ||
| if (options.length === 0) { | ||
| return this.error(parentArgType === 'select' | ||
| ? ErrorKind.EXPECT_SELECT_ARGUMENT_SELECTOR | ||
| : ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| if (this.requiresOtherClause && !hasOtherClause) { | ||
| return this.error(ErrorKind.MISSING_OTHER_CLAUSE, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| return { val: options, err: null }; | ||
| }; | ||
| Parser.prototype.tryParseDecimalInteger = function (expectNumberError, invalidNumberError) { | ||
| var sign = 1; | ||
| var startingPosition = this.clonePosition(); | ||
| if (this.bumpIf('+')) { | ||
| } | ||
| else if (this.bumpIf('-')) { | ||
| sign = -1; | ||
| } | ||
| var hasDigits = false; | ||
| var decimal = 0; | ||
| while (!this.isEOF()) { | ||
| var ch = this.char(); | ||
| if (ch >= 48 /* `0` */ && ch <= 57 /* `9` */) { | ||
| hasDigits = true; | ||
| decimal = decimal * 10 + (ch - 48); | ||
| this.bump(); | ||
| } | ||
| else { | ||
| break; | ||
| } | ||
| } | ||
| var location = createLocation(startingPosition, this.clonePosition()); | ||
| if (!hasDigits) { | ||
| return this.error(expectNumberError, location); | ||
| } | ||
| decimal *= sign; | ||
| if (!Number.isSafeInteger(decimal)) { | ||
| return this.error(invalidNumberError, location); | ||
| } | ||
| return { val: decimal, err: null }; | ||
| }; | ||
| Parser.prototype.offset = function () { | ||
| return this.position.offset; | ||
| }; | ||
| Parser.prototype.isEOF = function () { | ||
| return this.offset() === this.message.length; | ||
| }; | ||
| Parser.prototype.clonePosition = function () { | ||
| // This is much faster than `Object.assign` or spread. | ||
| return { | ||
| offset: this.position.offset, | ||
| line: this.position.line, | ||
| column: this.position.column, | ||
| }; | ||
| }; | ||
| /** | ||
| * Return the code point at the current position of the parser. | ||
| * Throws if the index is out of bound. | ||
| */ | ||
| Parser.prototype.char = function () { | ||
| var offset = this.position.offset; | ||
| if (offset >= this.message.length) { | ||
| throw Error('out of bound'); | ||
| } | ||
| var code = this.message.codePointAt(offset); | ||
| if (code === undefined) { | ||
| throw Error("Offset ".concat(offset, " is at invalid UTF-16 code unit boundary")); | ||
| } | ||
| return code; | ||
| }; | ||
| Parser.prototype.error = function (kind, location) { | ||
| return { | ||
| val: null, | ||
| err: { | ||
| kind: kind, | ||
| message: this.message, | ||
| location: location, | ||
| }, | ||
| }; | ||
| }; | ||
| /** Bump the parser to the next UTF-16 code unit. */ | ||
| Parser.prototype.bump = function () { | ||
| if (this.isEOF()) { | ||
| return; | ||
| } | ||
| var code = this.char(); | ||
| if (code === 10 /* '\n' */) { | ||
| this.position.line += 1; | ||
| this.position.column = 1; | ||
| this.position.offset += 1; | ||
| } | ||
| else { | ||
| this.position.column += 1; | ||
| // 0 ~ 0x10000 -> unicode BMP, otherwise skip the surrogate pair. | ||
| this.position.offset += code < 0x10000 ? 1 : 2; | ||
| } | ||
| }; | ||
| /** | ||
| * If the substring starting at the current position of the parser has | ||
| * the given prefix, then bump the parser to the character immediately | ||
| * following the prefix and return true. Otherwise, don't bump the parser | ||
| * and return false. | ||
| */ | ||
| Parser.prototype.bumpIf = function (prefix) { | ||
| if (this.message.startsWith(prefix, this.offset())) { | ||
| for (var i = 0; i < prefix.length; i++) { | ||
| this.bump(); | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| }; | ||
| /** | ||
| * Bump the parser until the pattern character is found and return `true`. | ||
| * Otherwise bump to the end of the file and return `false`. | ||
| */ | ||
| Parser.prototype.bumpUntil = function (pattern) { | ||
| var currentOffset = this.offset(); | ||
| var index = this.message.indexOf(pattern, currentOffset); | ||
| if (index >= 0) { | ||
| this.bumpTo(index); | ||
| return true; | ||
| } | ||
| else { | ||
| this.bumpTo(this.message.length); | ||
| return false; | ||
| } | ||
| }; | ||
| /** | ||
| * Bump the parser to the target offset. | ||
| * If target offset is beyond the end of the input, bump the parser to the end of the input. | ||
| */ | ||
| Parser.prototype.bumpTo = function (targetOffset) { | ||
| if (this.offset() > targetOffset) { | ||
| throw Error("targetOffset ".concat(targetOffset, " must be greater than or equal to the current offset ").concat(this.offset())); | ||
| } | ||
| targetOffset = Math.min(targetOffset, this.message.length); | ||
| while (true) { | ||
| var offset = this.offset(); | ||
| if (offset === targetOffset) { | ||
| break; | ||
| } | ||
| if (offset > targetOffset) { | ||
| throw Error("targetOffset ".concat(targetOffset, " is at invalid UTF-16 code unit boundary")); | ||
| } | ||
| this.bump(); | ||
| if (this.isEOF()) { | ||
| break; | ||
| } | ||
| } | ||
| }; | ||
| /** advance the parser through all whitespace to the next non-whitespace code unit. */ | ||
| Parser.prototype.bumpSpace = function () { | ||
| while (!this.isEOF() && _isWhiteSpace(this.char())) { | ||
| this.bump(); | ||
| } | ||
| }; | ||
| /** | ||
| * Peek at the *next* Unicode codepoint in the input without advancing the parser. | ||
| * If the input has been exhausted, then this returns null. | ||
| */ | ||
| Parser.prototype.peek = function () { | ||
| if (this.isEOF()) { | ||
| return null; | ||
| } | ||
| var code = this.char(); | ||
| var offset = this.offset(); | ||
| var nextCode = this.message.charCodeAt(offset + (code >= 0x10000 ? 2 : 1)); | ||
| return nextCode !== null && nextCode !== void 0 ? nextCode : null; | ||
| }; | ||
| return Parser; | ||
| }()); | ||
| export { Parser }; | ||
| export class Parser { | ||
| message; | ||
| position; | ||
| locale; | ||
| ignoreTag; | ||
| requiresOtherClause; | ||
| shouldParseSkeletons; | ||
| constructor(message, options = {}) { | ||
| this.message = message; | ||
| this.position = { | ||
| offset: 0, | ||
| line: 1, | ||
| column: 1 | ||
| }; | ||
| this.ignoreTag = !!options.ignoreTag; | ||
| this.locale = options.locale; | ||
| this.requiresOtherClause = !!options.requiresOtherClause; | ||
| this.shouldParseSkeletons = !!options.shouldParseSkeletons; | ||
| } | ||
| parse() { | ||
| if (this.offset() !== 0) { | ||
| throw Error("parser can only be used once"); | ||
| } | ||
| return this.parseMessage(0, "", false); | ||
| } | ||
| parseMessage(nestingLevel, parentArgType, expectingCloseTag) { | ||
| let elements = []; | ||
| while (!this.isEOF()) { | ||
| const char = this.char(); | ||
| if (char === 123) { | ||
| const result = this.parseArgument(nestingLevel, expectingCloseTag); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| elements.push(result.val); | ||
| } else if (char === 125 && nestingLevel > 0) { | ||
| break; | ||
| } else if (char === 35 && (parentArgType === "plural" || parentArgType === "selectordinal")) { | ||
| const position = this.clonePosition(); | ||
| this.bump(); | ||
| elements.push({ | ||
| type: TYPE.pound, | ||
| location: createLocation(position, this.clonePosition()) | ||
| }); | ||
| } else if (char === 60 && !this.ignoreTag && this.peek() === 47) { | ||
| if (expectingCloseTag) { | ||
| break; | ||
| } else { | ||
| return this.error(ErrorKind.UNMATCHED_CLOSING_TAG, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| } else if (char === 60 && !this.ignoreTag && _isAlpha(this.peek() || 0)) { | ||
| const result = this.parseTag(nestingLevel, parentArgType); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| elements.push(result.val); | ||
| } else { | ||
| const result = this.parseLiteral(nestingLevel, parentArgType); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| elements.push(result.val); | ||
| } | ||
| } | ||
| return { | ||
| val: elements, | ||
| err: null | ||
| }; | ||
| } | ||
| /** | ||
| * A tag name must start with an ASCII lower/upper case letter. The grammar is based on the | ||
| * [custom element name][] except that a dash is NOT always mandatory and uppercase letters | ||
| * are accepted: | ||
| * | ||
| * ``` | ||
| * tag ::= "<" tagName (whitespace)* "/>" | "<" tagName (whitespace)* ">" message "</" tagName (whitespace)* ">" | ||
| * tagName ::= [a-z] (PENChar)* | ||
| * PENChar ::= | ||
| * "-" | "." | [0-9] | "_" | [a-z] | [A-Z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x37D] | | ||
| * [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] | [#x2070-#x218F] | [#x2C00-#x2FEF] | | ||
| * [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] | ||
| * ``` | ||
| * | ||
| * [custom element name]: https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name | ||
| * NOTE: We're a bit more lax here since HTML technically does not allow uppercase HTML element but we do | ||
| * since other tag-based engines like React allow it | ||
| */ | ||
| parseTag(nestingLevel, parentArgType) { | ||
| const startPosition = this.clonePosition(); | ||
| this.bump(); | ||
| const tagName = this.parseTagName(); | ||
| this.bumpSpace(); | ||
| if (this.bumpIf("/>")) { | ||
| // Self closing tag | ||
| return { | ||
| val: { | ||
| type: TYPE.literal, | ||
| value: `<${tagName}/>`, | ||
| location: createLocation(startPosition, this.clonePosition()) | ||
| }, | ||
| err: null | ||
| }; | ||
| } else if (this.bumpIf(">")) { | ||
| const childrenResult = this.parseMessage(nestingLevel + 1, parentArgType, true); | ||
| if (childrenResult.err) { | ||
| return childrenResult; | ||
| } | ||
| const children = childrenResult.val; | ||
| // Expecting a close tag | ||
| const endTagStartPosition = this.clonePosition(); | ||
| if (this.bumpIf("</")) { | ||
| if (this.isEOF() || !_isAlpha(this.char())) { | ||
| return this.error(ErrorKind.INVALID_TAG, createLocation(endTagStartPosition, this.clonePosition())); | ||
| } | ||
| const closingTagNameStartPosition = this.clonePosition(); | ||
| const closingTagName = this.parseTagName(); | ||
| if (tagName !== closingTagName) { | ||
| return this.error(ErrorKind.UNMATCHED_CLOSING_TAG, createLocation(closingTagNameStartPosition, this.clonePosition())); | ||
| } | ||
| this.bumpSpace(); | ||
| if (!this.bumpIf(">")) { | ||
| return this.error(ErrorKind.INVALID_TAG, createLocation(endTagStartPosition, this.clonePosition())); | ||
| } | ||
| return { | ||
| val: { | ||
| type: TYPE.tag, | ||
| value: tagName, | ||
| children, | ||
| location: createLocation(startPosition, this.clonePosition()) | ||
| }, | ||
| err: null | ||
| }; | ||
| } else { | ||
| return this.error(ErrorKind.UNCLOSED_TAG, createLocation(startPosition, this.clonePosition())); | ||
| } | ||
| } else { | ||
| return this.error(ErrorKind.INVALID_TAG, createLocation(startPosition, this.clonePosition())); | ||
| } | ||
| } | ||
| /** | ||
| * This method assumes that the caller has peeked ahead for the first tag character. | ||
| */ | ||
| parseTagName() { | ||
| const startOffset = this.offset(); | ||
| this.bump(); | ||
| while (!this.isEOF() && _isPotentialElementNameChar(this.char())) { | ||
| this.bump(); | ||
| } | ||
| return this.message.slice(startOffset, this.offset()); | ||
| } | ||
| parseLiteral(nestingLevel, parentArgType) { | ||
| const start = this.clonePosition(); | ||
| let value = ""; | ||
| while (true) { | ||
| const parseQuoteResult = this.tryParseQuote(parentArgType); | ||
| if (parseQuoteResult) { | ||
| value += parseQuoteResult; | ||
| continue; | ||
| } | ||
| const parseUnquotedResult = this.tryParseUnquoted(nestingLevel, parentArgType); | ||
| if (parseUnquotedResult) { | ||
| value += parseUnquotedResult; | ||
| continue; | ||
| } | ||
| const parseLeftAngleResult = this.tryParseLeftAngleBracket(); | ||
| if (parseLeftAngleResult) { | ||
| value += parseLeftAngleResult; | ||
| continue; | ||
| } | ||
| break; | ||
| } | ||
| const location = createLocation(start, this.clonePosition()); | ||
| return { | ||
| val: { | ||
| type: TYPE.literal, | ||
| value, | ||
| location | ||
| }, | ||
| err: null | ||
| }; | ||
| } | ||
| tryParseLeftAngleBracket() { | ||
| if (!this.isEOF() && this.char() === 60 && (this.ignoreTag || !_isAlphaOrSlash(this.peek() || 0))) { | ||
| this.bump(); | ||
| return "<"; | ||
| } | ||
| return null; | ||
| } | ||
| /** | ||
| * Starting with ICU 4.8, an ASCII apostrophe only starts quoted text if it immediately precedes | ||
| * a character that requires quoting (that is, "only where needed"), and works the same in | ||
| * nested messages as on the top level of the pattern. The new behavior is otherwise compatible. | ||
| */ | ||
| tryParseQuote(parentArgType) { | ||
| if (this.isEOF() || this.char() !== 39) { | ||
| return null; | ||
| } | ||
| // Parse escaped char following the apostrophe, or early return if there is no escaped char. | ||
| // Check if is valid escaped character | ||
| switch (this.peek()) { | ||
| case 39: | ||
| // double quote, should return as a single quote. | ||
| this.bump(); | ||
| this.bump(); | ||
| return "'"; | ||
| case 123: | ||
| case 60: | ||
| case 62: | ||
| case 125: break; | ||
| case 35: | ||
| if (parentArgType === "plural" || parentArgType === "selectordinal") { | ||
| break; | ||
| } | ||
| return null; | ||
| default: return null; | ||
| } | ||
| this.bump(); | ||
| const codePoints = [this.char()]; | ||
| this.bump(); | ||
| // read chars until the optional closing apostrophe is found | ||
| while (!this.isEOF()) { | ||
| const ch = this.char(); | ||
| if (ch === 39) { | ||
| if (this.peek() === 39) { | ||
| codePoints.push(39); | ||
| // Bump one more time because we need to skip 2 characters. | ||
| this.bump(); | ||
| } else { | ||
| // Optional closing apostrophe. | ||
| this.bump(); | ||
| break; | ||
| } | ||
| } else { | ||
| codePoints.push(ch); | ||
| } | ||
| this.bump(); | ||
| } | ||
| return String.fromCodePoint(...codePoints); | ||
| } | ||
| tryParseUnquoted(nestingLevel, parentArgType) { | ||
| if (this.isEOF()) { | ||
| return null; | ||
| } | ||
| const ch = this.char(); | ||
| if (ch === 60 || ch === 123 || ch === 35 && (parentArgType === "plural" || parentArgType === "selectordinal") || ch === 125 && nestingLevel > 0) { | ||
| return null; | ||
| } else { | ||
| this.bump(); | ||
| return String.fromCodePoint(ch); | ||
| } | ||
| } | ||
| parseArgument(nestingLevel, expectingCloseTag) { | ||
| const openingBracePosition = this.clonePosition(); | ||
| this.bump(); | ||
| this.bumpSpace(); | ||
| if (this.isEOF()) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| if (this.char() === 125) { | ||
| this.bump(); | ||
| return this.error(ErrorKind.EMPTY_ARGUMENT, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| // argument name | ||
| let value = this.parseIdentifierIfPossible().value; | ||
| if (!value) { | ||
| return this.error(ErrorKind.MALFORMED_ARGUMENT, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| this.bumpSpace(); | ||
| if (this.isEOF()) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| switch (this.char()) { | ||
| case 125: { | ||
| this.bump(); | ||
| return { | ||
| val: { | ||
| type: TYPE.argument, | ||
| value, | ||
| location: createLocation(openingBracePosition, this.clonePosition()) | ||
| }, | ||
| err: null | ||
| }; | ||
| } | ||
| case 44: { | ||
| this.bump(); | ||
| this.bumpSpace(); | ||
| if (this.isEOF()) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| return this.parseArgumentOptions(nestingLevel, expectingCloseTag, value, openingBracePosition); | ||
| } | ||
| default: return this.error(ErrorKind.MALFORMED_ARGUMENT, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| } | ||
| /** | ||
| * Advance the parser until the end of the identifier, if it is currently on | ||
| * an identifier character. Return an empty string otherwise. | ||
| */ | ||
| parseIdentifierIfPossible() { | ||
| const startingPosition = this.clonePosition(); | ||
| const startOffset = this.offset(); | ||
| const value = matchIdentifierAtIndex(this.message, startOffset); | ||
| const endOffset = startOffset + value.length; | ||
| this.bumpTo(endOffset); | ||
| const endPosition = this.clonePosition(); | ||
| const location = createLocation(startingPosition, endPosition); | ||
| return { | ||
| value, | ||
| location | ||
| }; | ||
| } | ||
| parseArgumentOptions(nestingLevel, expectingCloseTag, value, openingBracePosition) { | ||
| // Parse this range: | ||
| // {name, type, style} | ||
| // ^---^ | ||
| let typeStartPosition = this.clonePosition(); | ||
| let argType = this.parseIdentifierIfPossible().value; | ||
| let typeEndPosition = this.clonePosition(); | ||
| switch (argType) { | ||
| case "": | ||
| // Expecting a style string number, date, time, plural, selectordinal, or select. | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_TYPE, createLocation(typeStartPosition, typeEndPosition)); | ||
| case "number": | ||
| case "date": | ||
| case "time": { | ||
| // Parse this range: | ||
| // {name, number, style} | ||
| // ^-------^ | ||
| this.bumpSpace(); | ||
| let styleAndLocation = null; | ||
| if (this.bumpIf(",")) { | ||
| this.bumpSpace(); | ||
| const styleStartPosition = this.clonePosition(); | ||
| const result = this.parseSimpleArgStyleIfPossible(); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| const style = trimEnd(result.val); | ||
| if (style.length === 0) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_STYLE, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| const styleLocation = createLocation(styleStartPosition, this.clonePosition()); | ||
| styleAndLocation = { | ||
| style, | ||
| styleLocation | ||
| }; | ||
| } | ||
| const argCloseResult = this.tryParseArgumentClose(openingBracePosition); | ||
| if (argCloseResult.err) { | ||
| return argCloseResult; | ||
| } | ||
| const location = createLocation(openingBracePosition, this.clonePosition()); | ||
| // Extract style or skeleton | ||
| if (styleAndLocation && styleAndLocation.style.startsWith("::")) { | ||
| // Skeleton starts with `::`. | ||
| let skeleton = trimStart(styleAndLocation.style.slice(2)); | ||
| if (argType === "number") { | ||
| const result = this.parseNumberSkeletonFromString(skeleton, styleAndLocation.styleLocation); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| return { | ||
| val: { | ||
| type: TYPE.number, | ||
| value, | ||
| location, | ||
| style: result.val | ||
| }, | ||
| err: null | ||
| }; | ||
| } else { | ||
| if (skeleton.length === 0) { | ||
| return this.error(ErrorKind.EXPECT_DATE_TIME_SKELETON, location); | ||
| } | ||
| let dateTimePattern = skeleton; | ||
| // Get "best match" pattern only if locale is passed, if not, let it | ||
| // pass as-is where `parseDateTimeSkeleton()` will throw an error | ||
| // for unsupported patterns. | ||
| if (this.locale) { | ||
| dateTimePattern = getBestPattern(skeleton, this.locale); | ||
| } | ||
| const style = { | ||
| type: SKELETON_TYPE.dateTime, | ||
| pattern: dateTimePattern, | ||
| location: styleAndLocation.styleLocation, | ||
| parsedOptions: this.shouldParseSkeletons ? parseDateTimeSkeleton(dateTimePattern) : {} | ||
| }; | ||
| const type = argType === "date" ? TYPE.date : TYPE.time; | ||
| return { | ||
| val: { | ||
| type, | ||
| value, | ||
| location, | ||
| style | ||
| }, | ||
| err: null | ||
| }; | ||
| } | ||
| } | ||
| // Regular style or no style. | ||
| return { | ||
| val: { | ||
| type: argType === "number" ? TYPE.number : argType === "date" ? TYPE.date : TYPE.time, | ||
| value, | ||
| location, | ||
| style: styleAndLocation?.style ?? null | ||
| }, | ||
| err: null | ||
| }; | ||
| } | ||
| case "plural": | ||
| case "selectordinal": | ||
| case "select": { | ||
| // Parse this range: | ||
| // {name, plural, options} | ||
| // ^---------^ | ||
| const typeEndPosition = this.clonePosition(); | ||
| this.bumpSpace(); | ||
| if (!this.bumpIf(",")) { | ||
| return this.error(ErrorKind.EXPECT_SELECT_ARGUMENT_OPTIONS, createLocation(typeEndPosition, { ...typeEndPosition })); | ||
| } | ||
| this.bumpSpace(); | ||
| // Parse offset: | ||
| // {name, plural, offset:1, options} | ||
| // ^-----^ | ||
| // | ||
| // or the first option: | ||
| // | ||
| // {name, plural, one {...} other {...}} | ||
| // ^--^ | ||
| let identifierAndLocation = this.parseIdentifierIfPossible(); | ||
| let pluralOffset = 0; | ||
| if (argType !== "select" && identifierAndLocation.value === "offset") { | ||
| if (!this.bumpIf(":")) { | ||
| return this.error(ErrorKind.EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| this.bumpSpace(); | ||
| const result = this.tryParseDecimalInteger(ErrorKind.EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE, ErrorKind.INVALID_PLURAL_ARGUMENT_OFFSET_VALUE); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| // Parse another identifier for option parsing | ||
| this.bumpSpace(); | ||
| identifierAndLocation = this.parseIdentifierIfPossible(); | ||
| pluralOffset = result.val; | ||
| } | ||
| const optionsResult = this.tryParsePluralOrSelectOptions(nestingLevel, argType, expectingCloseTag, identifierAndLocation); | ||
| if (optionsResult.err) { | ||
| return optionsResult; | ||
| } | ||
| const argCloseResult = this.tryParseArgumentClose(openingBracePosition); | ||
| if (argCloseResult.err) { | ||
| return argCloseResult; | ||
| } | ||
| const location = createLocation(openingBracePosition, this.clonePosition()); | ||
| if (argType === "select") { | ||
| return { | ||
| val: { | ||
| type: TYPE.select, | ||
| value, | ||
| options: fromEntries(optionsResult.val), | ||
| location | ||
| }, | ||
| err: null | ||
| }; | ||
| } else { | ||
| return { | ||
| val: { | ||
| type: TYPE.plural, | ||
| value, | ||
| options: fromEntries(optionsResult.val), | ||
| offset: pluralOffset, | ||
| pluralType: argType === "plural" ? "cardinal" : "ordinal", | ||
| location | ||
| }, | ||
| err: null | ||
| }; | ||
| } | ||
| } | ||
| default: return this.error(ErrorKind.INVALID_ARGUMENT_TYPE, createLocation(typeStartPosition, typeEndPosition)); | ||
| } | ||
| } | ||
| tryParseArgumentClose(openingBracePosition) { | ||
| // Parse: {value, number, ::currency/GBP } | ||
| // | ||
| if (this.isEOF() || this.char() !== 125) { | ||
| return this.error(ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition())); | ||
| } | ||
| this.bump(); | ||
| return { | ||
| val: true, | ||
| err: null | ||
| }; | ||
| } | ||
| /** | ||
| * See: https://github.com/unicode-org/icu/blob/af7ed1f6d2298013dc303628438ec4abe1f16479/icu4c/source/common/messagepattern.cpp#L659 | ||
| */ | ||
| parseSimpleArgStyleIfPossible() { | ||
| let nestedBraces = 0; | ||
| const startPosition = this.clonePosition(); | ||
| while (!this.isEOF()) { | ||
| const ch = this.char(); | ||
| switch (ch) { | ||
| case 39: { | ||
| // Treat apostrophe as quoting but include it in the style part. | ||
| // Find the end of the quoted literal text. | ||
| this.bump(); | ||
| let apostrophePosition = this.clonePosition(); | ||
| if (!this.bumpUntil("'")) { | ||
| return this.error(ErrorKind.UNCLOSED_QUOTE_IN_ARGUMENT_STYLE, createLocation(apostrophePosition, this.clonePosition())); | ||
| } | ||
| this.bump(); | ||
| break; | ||
| } | ||
| case 123: { | ||
| nestedBraces += 1; | ||
| this.bump(); | ||
| break; | ||
| } | ||
| case 125: { | ||
| if (nestedBraces > 0) { | ||
| nestedBraces -= 1; | ||
| } else { | ||
| return { | ||
| val: this.message.slice(startPosition.offset, this.offset()), | ||
| err: null | ||
| }; | ||
| } | ||
| break; | ||
| } | ||
| default: | ||
| this.bump(); | ||
| break; | ||
| } | ||
| } | ||
| return { | ||
| val: this.message.slice(startPosition.offset, this.offset()), | ||
| err: null | ||
| }; | ||
| } | ||
| parseNumberSkeletonFromString(skeleton, location) { | ||
| let tokens = []; | ||
| try { | ||
| tokens = parseNumberSkeletonFromString(skeleton); | ||
| } catch { | ||
| return this.error(ErrorKind.INVALID_NUMBER_SKELETON, location); | ||
| } | ||
| return { | ||
| val: { | ||
| type: SKELETON_TYPE.number, | ||
| tokens, | ||
| location, | ||
| parsedOptions: this.shouldParseSkeletons ? parseNumberSkeleton(tokens) : {} | ||
| }, | ||
| err: null | ||
| }; | ||
| } | ||
| /** | ||
| * @param nesting_level The current nesting level of messages. | ||
| * This can be positive when parsing message fragment in select or plural argument options. | ||
| * @param parent_arg_type The parent argument's type. | ||
| * @param parsed_first_identifier If provided, this is the first identifier-like selector of | ||
| * the argument. It is a by-product of a previous parsing attempt. | ||
| * @param expecting_close_tag If true, this message is directly or indirectly nested inside | ||
| * between a pair of opening and closing tags. The nested message will not parse beyond | ||
| * the closing tag boundary. | ||
| */ | ||
| tryParsePluralOrSelectOptions(nestingLevel, parentArgType, expectCloseTag, parsedFirstIdentifier) { | ||
| let hasOtherClause = false; | ||
| const options = []; | ||
| const parsedSelectors = new Set(); | ||
| let { value: selector, location: selectorLocation } = parsedFirstIdentifier; | ||
| // Parse: | ||
| // one {one apple} | ||
| // ^--^ | ||
| while (true) { | ||
| if (selector.length === 0) { | ||
| const startPosition = this.clonePosition(); | ||
| if (parentArgType !== "select" && this.bumpIf("=")) { | ||
| // Try parse `={number}` selector | ||
| const result = this.tryParseDecimalInteger(ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR, ErrorKind.INVALID_PLURAL_ARGUMENT_SELECTOR); | ||
| if (result.err) { | ||
| return result; | ||
| } | ||
| selectorLocation = createLocation(startPosition, this.clonePosition()); | ||
| selector = this.message.slice(startPosition.offset, this.offset()); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| // Duplicate selector clauses | ||
| if (parsedSelectors.has(selector)) { | ||
| return this.error(parentArgType === "select" ? ErrorKind.DUPLICATE_SELECT_ARGUMENT_SELECTOR : ErrorKind.DUPLICATE_PLURAL_ARGUMENT_SELECTOR, selectorLocation); | ||
| } | ||
| if (selector === "other") { | ||
| hasOtherClause = true; | ||
| } | ||
| // Parse: | ||
| // one {one apple} | ||
| // ^----------^ | ||
| this.bumpSpace(); | ||
| const openingBracePosition = this.clonePosition(); | ||
| if (!this.bumpIf("{")) { | ||
| return this.error(parentArgType === "select" ? ErrorKind.EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT : ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| const fragmentResult = this.parseMessage(nestingLevel + 1, parentArgType, expectCloseTag); | ||
| if (fragmentResult.err) { | ||
| return fragmentResult; | ||
| } | ||
| const argCloseResult = this.tryParseArgumentClose(openingBracePosition); | ||
| if (argCloseResult.err) { | ||
| return argCloseResult; | ||
| } | ||
| options.push([selector, { | ||
| value: fragmentResult.val, | ||
| location: createLocation(openingBracePosition, this.clonePosition()) | ||
| }]); | ||
| // Keep track of the existing selectors | ||
| parsedSelectors.add(selector); | ||
| // Prep next selector clause. | ||
| this.bumpSpace(); | ||
| ({value: selector, location: selectorLocation} = this.parseIdentifierIfPossible()); | ||
| } | ||
| if (options.length === 0) { | ||
| return this.error(parentArgType === "select" ? ErrorKind.EXPECT_SELECT_ARGUMENT_SELECTOR : ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| if (this.requiresOtherClause && !hasOtherClause) { | ||
| return this.error(ErrorKind.MISSING_OTHER_CLAUSE, createLocation(this.clonePosition(), this.clonePosition())); | ||
| } | ||
| return { | ||
| val: options, | ||
| err: null | ||
| }; | ||
| } | ||
| tryParseDecimalInteger(expectNumberError, invalidNumberError) { | ||
| let sign = 1; | ||
| const startingPosition = this.clonePosition(); | ||
| if (this.bumpIf("+")) {} else if (this.bumpIf("-")) { | ||
| sign = -1; | ||
| } | ||
| let hasDigits = false; | ||
| let decimal = 0; | ||
| while (!this.isEOF()) { | ||
| const ch = this.char(); | ||
| if (ch >= 48 && ch <= 57) { | ||
| hasDigits = true; | ||
| decimal = decimal * 10 + (ch - 48); | ||
| this.bump(); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| const location = createLocation(startingPosition, this.clonePosition()); | ||
| if (!hasDigits) { | ||
| return this.error(expectNumberError, location); | ||
| } | ||
| decimal *= sign; | ||
| if (!Number.isSafeInteger(decimal)) { | ||
| return this.error(invalidNumberError, location); | ||
| } | ||
| return { | ||
| val: decimal, | ||
| err: null | ||
| }; | ||
| } | ||
| offset() { | ||
| return this.position.offset; | ||
| } | ||
| isEOF() { | ||
| return this.offset() === this.message.length; | ||
| } | ||
| clonePosition() { | ||
| // This is much faster than `Object.assign` or spread. | ||
| return { | ||
| offset: this.position.offset, | ||
| line: this.position.line, | ||
| column: this.position.column | ||
| }; | ||
| } | ||
| /** | ||
| * Return the code point at the current position of the parser. | ||
| * Throws if the index is out of bound. | ||
| */ | ||
| char() { | ||
| const offset = this.position.offset; | ||
| if (offset >= this.message.length) { | ||
| throw Error("out of bound"); | ||
| } | ||
| const code = this.message.codePointAt(offset); | ||
| if (code === undefined) { | ||
| throw Error(`Offset ${offset} is at invalid UTF-16 code unit boundary`); | ||
| } | ||
| return code; | ||
| } | ||
| error(kind, location) { | ||
| return { | ||
| val: null, | ||
| err: { | ||
| kind, | ||
| message: this.message, | ||
| location | ||
| } | ||
| }; | ||
| } | ||
| /** Bump the parser to the next UTF-16 code unit. */ | ||
| bump() { | ||
| if (this.isEOF()) { | ||
| return; | ||
| } | ||
| const code = this.char(); | ||
| if (code === 10) { | ||
| this.position.line += 1; | ||
| this.position.column = 1; | ||
| this.position.offset += 1; | ||
| } else { | ||
| this.position.column += 1; | ||
| // 0 ~ 0x10000 -> unicode BMP, otherwise skip the surrogate pair. | ||
| this.position.offset += code < 65536 ? 1 : 2; | ||
| } | ||
| } | ||
| /** | ||
| * If the substring starting at the current position of the parser has | ||
| * the given prefix, then bump the parser to the character immediately | ||
| * following the prefix and return true. Otherwise, don't bump the parser | ||
| * and return false. | ||
| */ | ||
| bumpIf(prefix) { | ||
| if (this.message.startsWith(prefix, this.offset())) { | ||
| for (let i = 0; i < prefix.length; i++) { | ||
| this.bump(); | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Bump the parser until the pattern character is found and return `true`. | ||
| * Otherwise bump to the end of the file and return `false`. | ||
| */ | ||
| bumpUntil(pattern) { | ||
| const currentOffset = this.offset(); | ||
| const index = this.message.indexOf(pattern, currentOffset); | ||
| if (index >= 0) { | ||
| this.bumpTo(index); | ||
| return true; | ||
| } else { | ||
| this.bumpTo(this.message.length); | ||
| return false; | ||
| } | ||
| } | ||
| /** | ||
| * Bump the parser to the target offset. | ||
| * If target offset is beyond the end of the input, bump the parser to the end of the input. | ||
| */ | ||
| bumpTo(targetOffset) { | ||
| if (this.offset() > targetOffset) { | ||
| throw Error(`targetOffset ${targetOffset} must be greater than or equal to the current offset ${this.offset()}`); | ||
| } | ||
| targetOffset = Math.min(targetOffset, this.message.length); | ||
| while (true) { | ||
| const offset = this.offset(); | ||
| if (offset === targetOffset) { | ||
| break; | ||
| } | ||
| if (offset > targetOffset) { | ||
| throw Error(`targetOffset ${targetOffset} is at invalid UTF-16 code unit boundary`); | ||
| } | ||
| this.bump(); | ||
| if (this.isEOF()) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| /** advance the parser through all whitespace to the next non-whitespace code unit. */ | ||
| bumpSpace() { | ||
| while (!this.isEOF() && _isWhiteSpace(this.char())) { | ||
| this.bump(); | ||
| } | ||
| } | ||
| /** | ||
| * Peek at the *next* Unicode codepoint in the input without advancing the parser. | ||
| * If the input has been exhausted, then this returns null. | ||
| */ | ||
| peek() { | ||
| if (this.isEOF()) { | ||
| return null; | ||
| } | ||
| const code = this.char(); | ||
| const offset = this.offset(); | ||
| const nextCode = this.message.charCodeAt(offset + (code >= 65536 ? 2 : 1)); | ||
| return nextCode ?? null; | ||
| } | ||
| } | ||
| /** | ||
| * This check if codepoint is alphabet (lower & uppercase) | ||
| * @param codepoint | ||
| * @returns | ||
| */ | ||
| * This check if codepoint is alphabet (lower & uppercase) | ||
| * @param codepoint | ||
| * @returns | ||
| */ | ||
| function _isAlpha(codepoint) { | ||
| return ((codepoint >= 97 && codepoint <= 122) || | ||
| (codepoint >= 65 && codepoint <= 90)); | ||
| return codepoint >= 97 && codepoint <= 122 || codepoint >= 65 && codepoint <= 90; | ||
| } | ||
| function _isAlphaOrSlash(codepoint) { | ||
| return _isAlpha(codepoint) || codepoint === 47; /* '/' */ | ||
| return _isAlpha(codepoint) || codepoint === 47; | ||
| } | ||
| /** See `parseTag` function docs. */ | ||
| function _isPotentialElementNameChar(c) { | ||
| return (c === 45 /* '-' */ || | ||
| c === 46 /* '.' */ || | ||
| (c >= 48 && c <= 57) /* 0..9 */ || | ||
| c === 95 /* '_' */ || | ||
| (c >= 97 && c <= 122) /** a..z */ || | ||
| (c >= 65 && c <= 90) /* A..Z */ || | ||
| c == 0xb7 || | ||
| (c >= 0xc0 && c <= 0xd6) || | ||
| (c >= 0xd8 && c <= 0xf6) || | ||
| (c >= 0xf8 && c <= 0x37d) || | ||
| (c >= 0x37f && c <= 0x1fff) || | ||
| (c >= 0x200c && c <= 0x200d) || | ||
| (c >= 0x203f && c <= 0x2040) || | ||
| (c >= 0x2070 && c <= 0x218f) || | ||
| (c >= 0x2c00 && c <= 0x2fef) || | ||
| (c >= 0x3001 && c <= 0xd7ff) || | ||
| (c >= 0xf900 && c <= 0xfdcf) || | ||
| (c >= 0xfdf0 && c <= 0xfffd) || | ||
| (c >= 0x10000 && c <= 0xeffff)); | ||
| return c === 45 || c === 46 || c >= 48 && c <= 57 || c === 95 || c >= 97 && c <= 122 || c >= 65 && c <= 90 || c == 183 || c >= 192 && c <= 214 || c >= 216 && c <= 246 || c >= 248 && c <= 893 || c >= 895 && c <= 8191 || c >= 8204 && c <= 8205 || c >= 8255 && c <= 8256 || c >= 8304 && c <= 8591 || c >= 11264 && c <= 12271 || c >= 12289 && c <= 55295 || c >= 63744 && c <= 64975 || c >= 65008 && c <= 65533 || c >= 65536 && c <= 983039; | ||
| } | ||
| /** | ||
| * Code point equivalent of regex `\p{White_Space}`. | ||
| * From: https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt | ||
| */ | ||
| * Code point equivalent of regex `\p{White_Space}`. | ||
| * From: https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt | ||
| */ | ||
| function _isWhiteSpace(c) { | ||
| return ((c >= 0x0009 && c <= 0x000d) || | ||
| c === 0x0020 || | ||
| c === 0x0085 || | ||
| (c >= 0x200e && c <= 0x200f) || | ||
| c === 0x2028 || | ||
| c === 0x2029); | ||
| return c >= 9 && c <= 13 || c === 32 || c === 133 || c >= 8206 && c <= 8207 || c === 8232 || c === 8233; | ||
| } |
+1
-1
@@ -1,4 +0,4 @@ | ||
| import { DateTimeSkeleton, MessageFormatElement } from './types.js'; | ||
| import { type DateTimeSkeleton, type MessageFormatElement } from "./types.js"; | ||
| export declare function printAST(ast: MessageFormatElement[]): string; | ||
| export declare function doPrintAST(ast: MessageFormatElement[], isInPlural: boolean): string; | ||
| export declare function printDateTimeSkeleton(style: DateTimeSkeleton): string; |
+68
-79
@@ -1,101 +0,90 @@ | ||
| import { __spreadArray } from "tslib"; | ||
| import { isArgumentElement, isDateElement, isLiteralElement, isNumberElement, isPluralElement, isPoundElement, isSelectElement, isTagElement, isTimeElement, SKELETON_TYPE, TYPE, } from './types.js'; | ||
| import "@formatjs/icu-skeleton-parser"; | ||
| import { isArgumentElement, isDateElement, isLiteralElement, isNumberElement, isPluralElement, isPoundElement, isSelectElement, isTagElement, isTimeElement, SKELETON_TYPE, TYPE } from "./types.js"; | ||
| export function printAST(ast) { | ||
| return doPrintAST(ast, false); | ||
| return doPrintAST(ast, false); | ||
| } | ||
| export function doPrintAST(ast, isInPlural) { | ||
| var printedNodes = ast.map(function (el, i) { | ||
| if (isLiteralElement(el)) { | ||
| return printLiteralElement(el, isInPlural, i === 0, i === ast.length - 1); | ||
| } | ||
| if (isArgumentElement(el)) { | ||
| return printArgumentElement(el); | ||
| } | ||
| if (isDateElement(el) || isTimeElement(el) || isNumberElement(el)) { | ||
| return printSimpleFormatElement(el); | ||
| } | ||
| if (isPluralElement(el)) { | ||
| return printPluralElement(el); | ||
| } | ||
| if (isSelectElement(el)) { | ||
| return printSelectElement(el); | ||
| } | ||
| if (isPoundElement(el)) { | ||
| return '#'; | ||
| } | ||
| if (isTagElement(el)) { | ||
| return printTagElement(el); | ||
| } | ||
| }); | ||
| return printedNodes.join(''); | ||
| const printedNodes = ast.map((el, i) => { | ||
| if (isLiteralElement(el)) { | ||
| return printLiteralElement(el, isInPlural, i === 0, i === ast.length - 1); | ||
| } | ||
| if (isArgumentElement(el)) { | ||
| return printArgumentElement(el); | ||
| } | ||
| if (isDateElement(el) || isTimeElement(el) || isNumberElement(el)) { | ||
| return printSimpleFormatElement(el); | ||
| } | ||
| if (isPluralElement(el)) { | ||
| return printPluralElement(el); | ||
| } | ||
| if (isSelectElement(el)) { | ||
| return printSelectElement(el); | ||
| } | ||
| if (isPoundElement(el)) { | ||
| return "#"; | ||
| } | ||
| if (isTagElement(el)) { | ||
| return printTagElement(el); | ||
| } | ||
| }); | ||
| return printedNodes.join(""); | ||
| } | ||
| function printTagElement(el) { | ||
| return "<".concat(el.value, ">").concat(printAST(el.children), "</").concat(el.value, ">"); | ||
| return `<${el.value}>${printAST(el.children)}</${el.value}>`; | ||
| } | ||
| function printEscapedMessage(message) { | ||
| return message.replace(/([{}](?:[\s\S]*[{}])?)/, "'$1'"); | ||
| return message.replace(/([{}](?:[\s\S]*[{}])?)/, `'$1'`); | ||
| } | ||
| function printLiteralElement(_a, isInPlural, isFirstEl, isLastEl) { | ||
| var value = _a.value; | ||
| var escaped = value; | ||
| // If this literal starts with a ' and its not the 1st node, this means the node before it is non-literal | ||
| // and the `'` needs to be unescaped | ||
| if (!isFirstEl && escaped[0] === "'") { | ||
| escaped = "''".concat(escaped.slice(1)); | ||
| } | ||
| // Same logic but for last el | ||
| if (!isLastEl && escaped[escaped.length - 1] === "'") { | ||
| escaped = "".concat(escaped.slice(0, escaped.length - 1), "''"); | ||
| } | ||
| escaped = printEscapedMessage(escaped); | ||
| return isInPlural ? escaped.replace('#', "'#'") : escaped; | ||
| function printLiteralElement({ value }, isInPlural, isFirstEl, isLastEl) { | ||
| let escaped = value; | ||
| // If this literal starts with a ' and its not the 1st node, this means the node before it is non-literal | ||
| // and the `'` needs to be unescaped | ||
| if (!isFirstEl && escaped[0] === `'`) { | ||
| escaped = `''${escaped.slice(1)}`; | ||
| } | ||
| // Same logic but for last el | ||
| if (!isLastEl && escaped[escaped.length - 1] === `'`) { | ||
| escaped = `${escaped.slice(0, escaped.length - 1)}''`; | ||
| } | ||
| escaped = printEscapedMessage(escaped); | ||
| return isInPlural ? escaped.replace("#", "'#'") : escaped; | ||
| } | ||
| function printArgumentElement(_a) { | ||
| var value = _a.value; | ||
| return "{".concat(value, "}"); | ||
| function printArgumentElement({ value }) { | ||
| return `{${value}}`; | ||
| } | ||
| function printSimpleFormatElement(el) { | ||
| return "{".concat(el.value, ", ").concat(TYPE[el.type]).concat(el.style ? ", ".concat(printArgumentStyle(el.style)) : '', "}"); | ||
| return `{${el.value}, ${TYPE[el.type]}${el.style ? `, ${printArgumentStyle(el.style)}` : ""}}`; | ||
| } | ||
| function printNumberSkeletonToken(token) { | ||
| var stem = token.stem, options = token.options; | ||
| return options.length === 0 | ||
| ? stem | ||
| : "".concat(stem).concat(options.map(function (o) { return "/".concat(o); }).join('')); | ||
| const { stem, options } = token; | ||
| return options.length === 0 ? stem : `${stem}${options.map((o) => `/${o}`).join("")}`; | ||
| } | ||
| function printArgumentStyle(style) { | ||
| if (typeof style === 'string') { | ||
| return printEscapedMessage(style); | ||
| } | ||
| else if (style.type === SKELETON_TYPE.dateTime) { | ||
| return "::".concat(printDateTimeSkeleton(style)); | ||
| } | ||
| else { | ||
| return "::".concat(style.tokens.map(printNumberSkeletonToken).join(' ')); | ||
| } | ||
| if (typeof style === "string") { | ||
| return printEscapedMessage(style); | ||
| } else if (style.type === SKELETON_TYPE.dateTime) { | ||
| return `::${printDateTimeSkeleton(style)}`; | ||
| } else { | ||
| return `::${style.tokens.map(printNumberSkeletonToken).join(" ")}`; | ||
| } | ||
| } | ||
| export function printDateTimeSkeleton(style) { | ||
| return style.pattern; | ||
| return style.pattern; | ||
| } | ||
| function printSelectElement(el) { | ||
| var msg = [ | ||
| el.value, | ||
| 'select', | ||
| Object.keys(el.options) | ||
| .map(function (id) { return "".concat(id, "{").concat(doPrintAST(el.options[id].value, false), "}"); }) | ||
| .join(' '), | ||
| ].join(','); | ||
| return "{".concat(msg, "}"); | ||
| const msg = [ | ||
| el.value, | ||
| "select", | ||
| Object.keys(el.options).map((id) => `${id}{${doPrintAST(el.options[id].value, false)}}`).join(" ") | ||
| ].join(","); | ||
| return `{${msg}}`; | ||
| } | ||
| function printPluralElement(el) { | ||
| var type = el.pluralType === 'cardinal' ? 'plural' : 'selectordinal'; | ||
| var msg = [ | ||
| el.value, | ||
| type, | ||
| __spreadArray([ | ||
| el.offset ? "offset:".concat(el.offset) : '' | ||
| ], Object.keys(el.options).map(function (id) { return "".concat(id, "{").concat(doPrintAST(el.options[id].value, true), "}"); }), true).filter(Boolean) | ||
| .join(' '), | ||
| ].join(','); | ||
| return "{".concat(msg, "}"); | ||
| const type = el.pluralType === "cardinal" ? "plural" : "selectordinal"; | ||
| const msg = [ | ||
| el.value, | ||
| type, | ||
| [el.offset ? `offset:${el.offset}` : "", ...Object.keys(el.options).map((id) => `${id}{${doPrintAST(el.options[id].value, true)}}`)].filter(Boolean).join(" ") | ||
| ].join(","); | ||
| return `{${msg}}`; | ||
| } |
@@ -0,2 +1,3 @@ | ||
| // @generated from regex-gen.ts | ||
| export declare const SPACE_SEPARATOR_REGEX: RegExp; | ||
| export declare const WHITE_SPACE_REGEX: RegExp; |
| // @generated from regex-gen.ts | ||
| export var SPACE_SEPARATOR_REGEX = /[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/; | ||
| export var WHITE_SPACE_REGEX = /[\t-\r \x85\u200E\u200F\u2028\u2029]/; | ||
| export const SPACE_SEPARATOR_REGEX = /[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/; | ||
| export const WHITE_SPACE_REGEX = /[\t-\r \x85\u200E\u200F\u2028\u2029]/; |
@@ -0,1 +1,3 @@ | ||
| // @generated from time-data-gen.ts | ||
| // prettier-ignore | ||
| export declare const timeData: Record<string, string[]>; |
+1162
-1424
| // @generated from time-data-gen.ts | ||
| // prettier-ignore | ||
| export var timeData = { | ||
| "001": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "419": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "AC": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "AD": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AE": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "AF": [ | ||
| "H", | ||
| "hb", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "AG": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AI": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "AL": [ | ||
| "h", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AM": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AO": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "AS": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "AT": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AU": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AW": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AX": [ | ||
| "H" | ||
| ], | ||
| "AZ": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "BA": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "BB": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BD": [ | ||
| "h", | ||
| "hB", | ||
| "H" | ||
| ], | ||
| "BE": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BF": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BG": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "BH": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "BI": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "BJ": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BL": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BN": [ | ||
| "hb", | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "BO": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "BQ": [ | ||
| "H" | ||
| ], | ||
| "BR": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BS": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BT": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "BW": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "BY": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "BZ": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CA": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "CC": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CD": [ | ||
| "hB", | ||
| "H" | ||
| ], | ||
| "CF": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "CG": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "CH": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "CI": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "CK": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CL": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CM": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "CN": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ], | ||
| "CO": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CP": [ | ||
| "H" | ||
| ], | ||
| "CR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CU": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CV": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "CW": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "CX": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CY": [ | ||
| "h", | ||
| "H", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CZ": [ | ||
| "H" | ||
| ], | ||
| "DE": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "DG": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "DJ": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "DK": [ | ||
| "H" | ||
| ], | ||
| "DM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "DO": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "DZ": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "EA": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "EC": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "EE": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "EG": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "EH": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "ER": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "ES": [ | ||
| "H", | ||
| "hB", | ||
| "h", | ||
| "hb" | ||
| ], | ||
| "ET": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "FI": [ | ||
| "H" | ||
| ], | ||
| "FJ": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "FK": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "FM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "FO": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "FR": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GA": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GB": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GD": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GE": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "GF": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GG": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GH": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "GI": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GL": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "GM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GN": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GP": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GQ": [ | ||
| "H", | ||
| "hB", | ||
| "h", | ||
| "hb" | ||
| ], | ||
| "GR": [ | ||
| "h", | ||
| "H", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GS": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GT": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "GU": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GW": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GY": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "HK": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "HN": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "HR": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "HU": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "IC": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "ID": [ | ||
| "H" | ||
| ], | ||
| "IE": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "IL": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "IM": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "IN": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "IO": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "IQ": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "IR": [ | ||
| "hB", | ||
| "H" | ||
| ], | ||
| "IS": [ | ||
| "H" | ||
| ], | ||
| "IT": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "JE": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "JM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "JO": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "JP": [ | ||
| "H", | ||
| "K", | ||
| "h" | ||
| ], | ||
| "KE": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "KG": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KH": [ | ||
| "hB", | ||
| "h", | ||
| "H", | ||
| "hb" | ||
| ], | ||
| "KI": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "KM": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KN": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "KP": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KW": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "KY": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "KZ": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "LA": [ | ||
| "H", | ||
| "hb", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "LB": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "LC": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "LI": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "LK": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "LR": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "LS": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "LT": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "LU": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "LV": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ], | ||
| "LY": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "MA": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "MC": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MD": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ME": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "MF": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MG": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "MH": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MK": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "ML": [ | ||
| "H" | ||
| ], | ||
| "MM": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "MN": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "MO": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "MP": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MQ": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MR": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "MS": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "MT": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "MU": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "MV": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "MW": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MX": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "MY": [ | ||
| "hb", | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "MZ": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "NA": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "NC": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "NE": [ | ||
| "H" | ||
| ], | ||
| "NF": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NG": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NI": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "NL": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "NO": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "NP": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "NR": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NU": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NZ": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "OM": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "PA": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "PE": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "PF": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "PG": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "PH": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "PK": [ | ||
| "h", | ||
| "hB", | ||
| "H" | ||
| ], | ||
| "PL": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "PM": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "PN": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "PR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "PS": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "PT": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "PW": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "PY": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "QA": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "RE": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "RO": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "RS": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "RU": [ | ||
| "H" | ||
| ], | ||
| "RW": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "SA": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "SB": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SC": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "SD": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "SE": [ | ||
| "H" | ||
| ], | ||
| "SG": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SH": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "SI": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SJ": [ | ||
| "H" | ||
| ], | ||
| "SK": [ | ||
| "H" | ||
| ], | ||
| "SL": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SM": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "SN": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "SO": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "SR": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SS": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ST": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SV": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "SX": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "SY": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "SZ": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TA": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "TC": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TD": [ | ||
| "h", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TF": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "TG": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TH": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "TJ": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "TL": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ], | ||
| "TM": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "TN": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "TO": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "TR": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TT": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TW": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "TZ": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "UA": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "UG": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "UM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "US": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "UY": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "UZ": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "VA": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "VC": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "VE": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "VG": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "VI": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "VN": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "VU": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "WF": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "WS": [ | ||
| "h", | ||
| "H" | ||
| ], | ||
| "XK": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "YE": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "YT": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ZA": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "ZM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ZW": [ | ||
| "H", | ||
| "h" | ||
| ], | ||
| "af-ZA": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "ar-001": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "ca-ES": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "en-001": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "en-HK": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "en-IL": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "en-MY": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "es-BR": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "es-ES": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "es-GQ": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "fr-CA": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "gl-ES": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "gu-IN": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "hi-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "it-CH": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "it-IT": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "kn-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "ku-SY": [ | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ml-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "mr-IN": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "pa-IN": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "ta-IN": [ | ||
| "hB", | ||
| "h", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "te-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "zu-ZA": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ] | ||
| export const timeData = { | ||
| "001": ["H", "h"], | ||
| "419": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "AC": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "AD": ["H", "hB"], | ||
| "AE": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "AF": [ | ||
| "H", | ||
| "hb", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "AG": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AI": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "AL": [ | ||
| "h", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AM": ["H", "hB"], | ||
| "AO": ["H", "hB"], | ||
| "AR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "AS": ["h", "H"], | ||
| "AT": ["H", "hB"], | ||
| "AU": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "AW": ["H", "hB"], | ||
| "AX": ["H"], | ||
| "AZ": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "BA": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "BB": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BD": [ | ||
| "h", | ||
| "hB", | ||
| "H" | ||
| ], | ||
| "BE": ["H", "hB"], | ||
| "BF": ["H", "hB"], | ||
| "BG": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "BH": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "BI": ["H", "h"], | ||
| "BJ": ["H", "hB"], | ||
| "BL": ["H", "hB"], | ||
| "BM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BN": [ | ||
| "hb", | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "BO": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "BQ": ["H"], | ||
| "BR": ["H", "hB"], | ||
| "BS": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "BT": ["h", "H"], | ||
| "BW": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "BY": ["H", "h"], | ||
| "BZ": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CA": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "CC": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CD": ["hB", "H"], | ||
| "CF": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "CG": ["H", "hB"], | ||
| "CH": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "CI": ["H", "hB"], | ||
| "CK": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CL": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CM": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "CN": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ], | ||
| "CO": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CP": ["H"], | ||
| "CR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CU": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "CV": ["H", "hB"], | ||
| "CW": ["H", "hB"], | ||
| "CX": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CY": [ | ||
| "h", | ||
| "H", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "CZ": ["H"], | ||
| "DE": ["H", "hB"], | ||
| "DG": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "DJ": ["h", "H"], | ||
| "DK": ["H"], | ||
| "DM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "DO": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "DZ": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "EA": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "EC": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "EE": ["H", "hB"], | ||
| "EG": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "EH": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "ER": ["h", "H"], | ||
| "ES": [ | ||
| "H", | ||
| "hB", | ||
| "h", | ||
| "hb" | ||
| ], | ||
| "ET": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "FI": ["H"], | ||
| "FJ": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "FK": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "FM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "FO": ["H", "h"], | ||
| "FR": ["H", "hB"], | ||
| "GA": ["H", "hB"], | ||
| "GB": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GD": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GE": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "GF": ["H", "hB"], | ||
| "GG": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GH": ["h", "H"], | ||
| "GI": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GL": ["H", "h"], | ||
| "GM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GN": ["H", "hB"], | ||
| "GP": ["H", "hB"], | ||
| "GQ": [ | ||
| "H", | ||
| "hB", | ||
| "h", | ||
| "hb" | ||
| ], | ||
| "GR": [ | ||
| "h", | ||
| "H", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GS": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "GT": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "GU": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "GW": ["H", "hB"], | ||
| "GY": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "HK": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "HN": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "HR": ["H", "hB"], | ||
| "HU": ["H", "h"], | ||
| "IC": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "ID": ["H"], | ||
| "IE": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "IL": ["H", "hB"], | ||
| "IM": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "IN": ["h", "H"], | ||
| "IO": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "IQ": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "IR": ["hB", "H"], | ||
| "IS": ["H"], | ||
| "IT": ["H", "hB"], | ||
| "JE": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "JM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "JO": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "JP": [ | ||
| "H", | ||
| "K", | ||
| "h" | ||
| ], | ||
| "KE": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "KG": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KH": [ | ||
| "hB", | ||
| "h", | ||
| "H", | ||
| "hb" | ||
| ], | ||
| "KI": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "KM": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KN": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "KP": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "KW": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "KY": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "KZ": ["H", "hB"], | ||
| "LA": [ | ||
| "H", | ||
| "hb", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "LB": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "LC": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "LI": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "LK": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "LR": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "LS": ["h", "H"], | ||
| "LT": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "LU": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "LV": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ], | ||
| "LY": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "MA": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "MC": ["H", "hB"], | ||
| "MD": ["H", "hB"], | ||
| "ME": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "MF": ["H", "hB"], | ||
| "MG": ["H", "h"], | ||
| "MH": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MK": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "ML": ["H"], | ||
| "MM": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "MN": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "MO": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "MP": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MQ": ["H", "hB"], | ||
| "MR": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "MS": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "MT": ["H", "h"], | ||
| "MU": ["H", "h"], | ||
| "MV": ["H", "h"], | ||
| "MW": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "MX": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "MY": [ | ||
| "hb", | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "MZ": ["H", "hB"], | ||
| "NA": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "NC": ["H", "hB"], | ||
| "NE": ["H"], | ||
| "NF": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NG": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NI": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "NL": ["H", "hB"], | ||
| "NO": ["H", "h"], | ||
| "NP": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "NR": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NU": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "NZ": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "OM": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "PA": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "PE": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "PF": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "PG": ["h", "H"], | ||
| "PH": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "PK": [ | ||
| "h", | ||
| "hB", | ||
| "H" | ||
| ], | ||
| "PL": ["H", "h"], | ||
| "PM": ["H", "hB"], | ||
| "PN": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "PR": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "PS": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "PT": ["H", "hB"], | ||
| "PW": ["h", "H"], | ||
| "PY": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "QA": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "RE": ["H", "hB"], | ||
| "RO": ["H", "hB"], | ||
| "RS": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "RU": ["H"], | ||
| "RW": ["H", "h"], | ||
| "SA": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "SB": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SC": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "SD": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "SE": ["H"], | ||
| "SG": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SH": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "SI": ["H", "hB"], | ||
| "SJ": ["H"], | ||
| "SK": ["H"], | ||
| "SL": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "SM": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "SN": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "SO": ["h", "H"], | ||
| "SR": ["H", "hB"], | ||
| "SS": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ST": ["H", "hB"], | ||
| "SV": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "SX": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "SY": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "SZ": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TA": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "TC": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TD": [ | ||
| "h", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TF": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "TG": ["H", "hB"], | ||
| "TH": ["H", "h"], | ||
| "TJ": ["H", "h"], | ||
| "TL": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ], | ||
| "TM": ["H", "h"], | ||
| "TN": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "TO": ["h", "H"], | ||
| "TR": ["H", "hB"], | ||
| "TT": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "TW": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "TZ": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "UA": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "UG": [ | ||
| "hB", | ||
| "hb", | ||
| "H", | ||
| "h" | ||
| ], | ||
| "UM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "US": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "UY": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "UZ": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "VA": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "VC": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "VE": [ | ||
| "h", | ||
| "H", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "VG": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "VI": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "VN": ["H", "h"], | ||
| "VU": ["h", "H"], | ||
| "WF": ["H", "hB"], | ||
| "WS": ["h", "H"], | ||
| "XK": [ | ||
| "H", | ||
| "hB", | ||
| "h" | ||
| ], | ||
| "YE": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "YT": ["H", "hB"], | ||
| "ZA": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "ZM": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "ZW": ["H", "h"], | ||
| "af-ZA": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "ar-001": [ | ||
| "h", | ||
| "hB", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "ca-ES": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "en-001": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "en-HK": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "en-IL": [ | ||
| "H", | ||
| "h", | ||
| "hb", | ||
| "hB" | ||
| ], | ||
| "en-MY": [ | ||
| "h", | ||
| "hb", | ||
| "H", | ||
| "hB" | ||
| ], | ||
| "es-BR": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "es-ES": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "es-GQ": [ | ||
| "H", | ||
| "h", | ||
| "hB", | ||
| "hb" | ||
| ], | ||
| "fr-CA": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "gl-ES": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "gu-IN": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "hi-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "it-CH": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "it-IT": [ | ||
| "H", | ||
| "h", | ||
| "hB" | ||
| ], | ||
| "kn-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "ku-SY": ["H", "hB"], | ||
| "ml-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "mr-IN": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "pa-IN": [ | ||
| "hB", | ||
| "hb", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "ta-IN": [ | ||
| "hB", | ||
| "h", | ||
| "hb", | ||
| "H" | ||
| ], | ||
| "te-IN": [ | ||
| "hB", | ||
| "h", | ||
| "H" | ||
| ], | ||
| "zu-ZA": [ | ||
| "H", | ||
| "hB", | ||
| "hb", | ||
| "h" | ||
| ] | ||
| }; |
+77
-74
@@ -1,62 +0,62 @@ | ||
| import type { NumberFormatOptions } from '@formatjs/ecma402-abstract'; | ||
| import { NumberSkeletonToken } from '@formatjs/icu-skeleton-parser'; | ||
| import type { NumberFormatOptions } from "@formatjs/ecma402-abstract"; | ||
| import { type NumberSkeletonToken } from "@formatjs/icu-skeleton-parser"; | ||
| export interface ExtendedNumberFormatOptions extends NumberFormatOptions { | ||
| scale?: number; | ||
| scale?: number; | ||
| } | ||
| export declare enum TYPE { | ||
| /** | ||
| * Raw text | ||
| */ | ||
| literal = 0, | ||
| /** | ||
| * Variable w/o any format, e.g `var` in `this is a {var}` | ||
| */ | ||
| argument = 1, | ||
| /** | ||
| * Variable w/ number format | ||
| */ | ||
| number = 2, | ||
| /** | ||
| * Variable w/ date format | ||
| */ | ||
| date = 3, | ||
| /** | ||
| * Variable w/ time format | ||
| */ | ||
| time = 4, | ||
| /** | ||
| * Variable w/ select format | ||
| */ | ||
| select = 5, | ||
| /** | ||
| * Variable w/ plural format | ||
| */ | ||
| plural = 6, | ||
| /** | ||
| * Only possible within plural argument. | ||
| * This is the `#` symbol that will be substituted with the count. | ||
| */ | ||
| pound = 7, | ||
| /** | ||
| * XML-like tag | ||
| */ | ||
| tag = 8 | ||
| /** | ||
| * Raw text | ||
| */ | ||
| literal = 0, | ||
| /** | ||
| * Variable w/o any format, e.g `var` in `this is a {var}` | ||
| */ | ||
| argument = 1, | ||
| /** | ||
| * Variable w/ number format | ||
| */ | ||
| number = 2, | ||
| /** | ||
| * Variable w/ date format | ||
| */ | ||
| date = 3, | ||
| /** | ||
| * Variable w/ time format | ||
| */ | ||
| time = 4, | ||
| /** | ||
| * Variable w/ select format | ||
| */ | ||
| select = 5, | ||
| /** | ||
| * Variable w/ plural format | ||
| */ | ||
| plural = 6, | ||
| /** | ||
| * Only possible within plural argument. | ||
| * This is the `#` symbol that will be substituted with the count. | ||
| */ | ||
| pound = 7, | ||
| /** | ||
| * XML-like tag | ||
| */ | ||
| tag = 8 | ||
| } | ||
| export declare enum SKELETON_TYPE { | ||
| number = 0, | ||
| dateTime = 1 | ||
| number = 0, | ||
| dateTime = 1 | ||
| } | ||
| export interface LocationDetails { | ||
| offset: number; | ||
| line: number; | ||
| column: number; | ||
| offset: number; | ||
| line: number; | ||
| column: number; | ||
| } | ||
| export interface Location { | ||
| start: LocationDetails; | ||
| end: LocationDetails; | ||
| start: LocationDetails; | ||
| end: LocationDetails; | ||
| } | ||
| export interface BaseElement<T extends TYPE> { | ||
| type: T; | ||
| value: string; | ||
| location?: Location; | ||
| type: T; | ||
| value: string; | ||
| location?: Location; | ||
| } | ||
@@ -66,6 +66,9 @@ export type LiteralElement = BaseElement<TYPE.literal>; | ||
| export interface TagElement extends BaseElement<TYPE.tag> { | ||
| children: MessageFormatElement[]; | ||
| children: MessageFormatElement[]; | ||
| } | ||
| export interface SimpleFormatElement<T extends TYPE, S extends Skeleton> extends BaseElement<T> { | ||
| style?: string | S | null; | ||
| export interface SimpleFormatElement< | ||
| T extends TYPE, | ||
| S extends Skeleton | ||
| > extends BaseElement<T> { | ||
| style?: string | S | null; | ||
| } | ||
@@ -75,36 +78,36 @@ export type NumberElement = SimpleFormatElement<TYPE.number, NumberSkeleton>; | ||
| export type TimeElement = SimpleFormatElement<TYPE.time, DateTimeSkeleton>; | ||
| export type ValidPluralRule = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' | string; | ||
| export type ValidPluralRule = "zero" | "one" | "two" | "few" | "many" | "other" | string; | ||
| export interface PluralOrSelectOption { | ||
| value: MessageFormatElement[]; | ||
| location?: Location; | ||
| value: MessageFormatElement[]; | ||
| location?: Location; | ||
| } | ||
| export interface SelectElement extends BaseElement<TYPE.select> { | ||
| options: Record<string, PluralOrSelectOption>; | ||
| options: Record<string, PluralOrSelectOption>; | ||
| } | ||
| export interface PluralElement extends BaseElement<TYPE.plural> { | ||
| options: Record<ValidPluralRule, PluralOrSelectOption>; | ||
| offset: number; | ||
| pluralType: Intl.PluralRulesOptions['type']; | ||
| options: Record<ValidPluralRule, PluralOrSelectOption>; | ||
| offset: number; | ||
| pluralType: Intl.PluralRulesOptions["type"]; | ||
| } | ||
| export interface PoundElement { | ||
| type: TYPE.pound; | ||
| location?: Location; | ||
| type: TYPE.pound; | ||
| location?: Location; | ||
| } | ||
| export type MessageFormatElement = ArgumentElement | DateElement | LiteralElement | NumberElement | PluralElement | PoundElement | SelectElement | TagElement | TimeElement; | ||
| export interface NumberSkeleton { | ||
| type: SKELETON_TYPE.number; | ||
| tokens: NumberSkeletonToken[]; | ||
| location?: Location; | ||
| parsedOptions: ExtendedNumberFormatOptions; | ||
| type: SKELETON_TYPE.number; | ||
| tokens: NumberSkeletonToken[]; | ||
| location?: Location; | ||
| parsedOptions: ExtendedNumberFormatOptions; | ||
| } | ||
| export interface DateTimeSkeleton { | ||
| type: SKELETON_TYPE.dateTime; | ||
| pattern: string; | ||
| location?: Location; | ||
| parsedOptions: Intl.DateTimeFormatOptions; | ||
| type: SKELETON_TYPE.dateTime; | ||
| pattern: string; | ||
| location?: Location; | ||
| parsedOptions: Intl.DateTimeFormatOptions; | ||
| } | ||
| export type Skeleton = NumberSkeleton | DateTimeSkeleton; | ||
| /** | ||
| * Type Guards | ||
| */ | ||
| * Type Guards | ||
| */ | ||
| export declare function isLiteralElement(el: MessageFormatElement): el is LiteralElement; | ||
@@ -119,5 +122,5 @@ export declare function isArgumentElement(el: MessageFormatElement): el is ArgumentElement; | ||
| export declare function isTagElement(el: MessageFormatElement): el is TagElement; | ||
| export declare function isNumberSkeleton(el: NumberElement['style'] | Skeleton): el is NumberSkeleton; | ||
| export declare function isDateTimeSkeleton(el?: DateElement['style'] | TimeElement['style'] | Skeleton): el is DateTimeSkeleton; | ||
| export declare function isNumberSkeleton(el: NumberElement["style"] | Skeleton): el is NumberSkeleton; | ||
| export declare function isDateTimeSkeleton(el?: DateElement["style"] | TimeElement["style"] | Skeleton): el is DateTimeSkeleton; | ||
| export declare function createLiteralElement(value: string): LiteralElement; | ||
| export declare function createNumberElement(value: string, style?: string | null): NumberElement; |
+68
-67
@@ -1,94 +0,95 @@ | ||
| export var TYPE; | ||
| (function (TYPE) { | ||
| /** | ||
| * Raw text | ||
| */ | ||
| TYPE[TYPE["literal"] = 0] = "literal"; | ||
| /** | ||
| * Variable w/o any format, e.g `var` in `this is a {var}` | ||
| */ | ||
| TYPE[TYPE["argument"] = 1] = "argument"; | ||
| /** | ||
| * Variable w/ number format | ||
| */ | ||
| TYPE[TYPE["number"] = 2] = "number"; | ||
| /** | ||
| * Variable w/ date format | ||
| */ | ||
| TYPE[TYPE["date"] = 3] = "date"; | ||
| /** | ||
| * Variable w/ time format | ||
| */ | ||
| TYPE[TYPE["time"] = 4] = "time"; | ||
| /** | ||
| * Variable w/ select format | ||
| */ | ||
| TYPE[TYPE["select"] = 5] = "select"; | ||
| /** | ||
| * Variable w/ plural format | ||
| */ | ||
| TYPE[TYPE["plural"] = 6] = "plural"; | ||
| /** | ||
| * Only possible within plural argument. | ||
| * This is the `#` symbol that will be substituted with the count. | ||
| */ | ||
| TYPE[TYPE["pound"] = 7] = "pound"; | ||
| /** | ||
| * XML-like tag | ||
| */ | ||
| TYPE[TYPE["tag"] = 8] = "tag"; | ||
| })(TYPE || (TYPE = {})); | ||
| export var SKELETON_TYPE; | ||
| (function (SKELETON_TYPE) { | ||
| SKELETON_TYPE[SKELETON_TYPE["number"] = 0] = "number"; | ||
| SKELETON_TYPE[SKELETON_TYPE["dateTime"] = 1] = "dateTime"; | ||
| })(SKELETON_TYPE || (SKELETON_TYPE = {})); | ||
| import "@formatjs/icu-skeleton-parser"; | ||
| export let TYPE = /* @__PURE__ */ function(TYPE) { | ||
| /** | ||
| * Raw text | ||
| */ | ||
| TYPE[TYPE["literal"] = 0] = "literal"; | ||
| /** | ||
| * Variable w/o any format, e.g `var` in `this is a {var}` | ||
| */ | ||
| TYPE[TYPE["argument"] = 1] = "argument"; | ||
| /** | ||
| * Variable w/ number format | ||
| */ | ||
| TYPE[TYPE["number"] = 2] = "number"; | ||
| /** | ||
| * Variable w/ date format | ||
| */ | ||
| TYPE[TYPE["date"] = 3] = "date"; | ||
| /** | ||
| * Variable w/ time format | ||
| */ | ||
| TYPE[TYPE["time"] = 4] = "time"; | ||
| /** | ||
| * Variable w/ select format | ||
| */ | ||
| TYPE[TYPE["select"] = 5] = "select"; | ||
| /** | ||
| * Variable w/ plural format | ||
| */ | ||
| TYPE[TYPE["plural"] = 6] = "plural"; | ||
| /** | ||
| * Only possible within plural argument. | ||
| * This is the `#` symbol that will be substituted with the count. | ||
| */ | ||
| TYPE[TYPE["pound"] = 7] = "pound"; | ||
| /** | ||
| * XML-like tag | ||
| */ | ||
| TYPE[TYPE["tag"] = 8] = "tag"; | ||
| return TYPE; | ||
| }({}); | ||
| export let SKELETON_TYPE = /* @__PURE__ */ function(SKELETON_TYPE) { | ||
| SKELETON_TYPE[SKELETON_TYPE["number"] = 0] = "number"; | ||
| SKELETON_TYPE[SKELETON_TYPE["dateTime"] = 1] = "dateTime"; | ||
| return SKELETON_TYPE; | ||
| }({}); | ||
| /** | ||
| * Type Guards | ||
| */ | ||
| * Type Guards | ||
| */ | ||
| export function isLiteralElement(el) { | ||
| return el.type === TYPE.literal; | ||
| return el.type === TYPE.literal; | ||
| } | ||
| export function isArgumentElement(el) { | ||
| return el.type === TYPE.argument; | ||
| return el.type === TYPE.argument; | ||
| } | ||
| export function isNumberElement(el) { | ||
| return el.type === TYPE.number; | ||
| return el.type === TYPE.number; | ||
| } | ||
| export function isDateElement(el) { | ||
| return el.type === TYPE.date; | ||
| return el.type === TYPE.date; | ||
| } | ||
| export function isTimeElement(el) { | ||
| return el.type === TYPE.time; | ||
| return el.type === TYPE.time; | ||
| } | ||
| export function isSelectElement(el) { | ||
| return el.type === TYPE.select; | ||
| return el.type === TYPE.select; | ||
| } | ||
| export function isPluralElement(el) { | ||
| return el.type === TYPE.plural; | ||
| return el.type === TYPE.plural; | ||
| } | ||
| export function isPoundElement(el) { | ||
| return el.type === TYPE.pound; | ||
| return el.type === TYPE.pound; | ||
| } | ||
| export function isTagElement(el) { | ||
| return el.type === TYPE.tag; | ||
| return el.type === TYPE.tag; | ||
| } | ||
| export function isNumberSkeleton(el) { | ||
| return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.number); | ||
| return !!(el && typeof el === "object" && el.type === SKELETON_TYPE.number); | ||
| } | ||
| export function isDateTimeSkeleton(el) { | ||
| return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.dateTime); | ||
| return !!(el && typeof el === "object" && el.type === SKELETON_TYPE.dateTime); | ||
| } | ||
| export function createLiteralElement(value) { | ||
| return { | ||
| type: TYPE.literal, | ||
| value: value, | ||
| }; | ||
| return { | ||
| type: TYPE.literal, | ||
| value | ||
| }; | ||
| } | ||
| export function createNumberElement(value, style) { | ||
| return { | ||
| type: TYPE.number, | ||
| value: value, | ||
| style: style, | ||
| }; | ||
| return { | ||
| type: TYPE.number, | ||
| value, | ||
| style | ||
| }; | ||
| } |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
4
-33.33%72445
-23.41%2967
-10.25%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed