node_modules ignore

This commit is contained in:
2025-05-08 23:43:47 +02:00
parent e19d52f172
commit 4574544c9f
65041 changed files with 10593536 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2023 FormatJS
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,25 @@
# MessageFormat Parser
Hand-written ICU MessageFormat parser with compatible output as
[`intl-messageformat-parser`](https://www.npmjs.com/package/intl-messageformat-parser)
but 6 - 10 times as fast.
```
$ node benchmark
complex_msg AST length 10861
normal_msg AST length 1665
simple_msg AST length 364
string_msg AST length 131
== Baseline ==
complex_msg x 4,884 ops/sec ±0.97% (91 runs sampled)
normal_msg x 40,113 ops/sec ±1.08% (92 runs sampled)
simple_msg x 200,401 ops/sec ±1.12% (91 runs sampled)
string_msg x 241,103 ops/sec ±0.84% (92 runs sampled)
== This package ==
complex_msg x 31,590 ops/sec ±0.80% (88 runs sampled)
normal_msg x 278,703 ops/sec ±0.83% (95 runs sampled)
simple_msg x 2,038,061 ops/sec ±0.90% (96 runs sampled)
string_msg x 2,392,794 ops/sec ±0.67% (96 runs sampled)
```

View File

@@ -0,0 +1,8 @@
/**
* 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;

View File

@@ -0,0 +1,87 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBestPattern = void 0;
var time_data_generated_1 = require("./time-data.generated");
/**
* 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
*/
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;
}
exports.getBestPattern = getBestPattern;
/**
* 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 = time_data_generated_1.timeData[regionTag || ''] ||
time_data_generated_1.timeData[languageTag || ''] ||
time_data_generated_1.timeData["".concat(languageTag, "-001")] ||
time_data_generated_1.timeData['001'];
return hourCycles[0];
}

View File

@@ -0,0 +1,68 @@
import { Location } from './types';
export interface ParserError {
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
}

View File

@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorKind = void 0;
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 || (exports.ErrorKind = ErrorKind = {}));

View File

@@ -0,0 +1,6 @@
import { Parser, ParserOptions } from './parser';
import { MessageFormatElement } from './types';
export declare function parse(message: string, opts?: ParserOptions): MessageFormatElement[];
export type { ParserOptions };
export * from './types';
export declare const _Parser: typeof Parser;

View File

@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._Parser = exports.parse = void 0;
var tslib_1 = require("tslib");
var error_1 = require("./error");
var parser_1 = require("./parser");
var types_1 = require("./types");
function pruneLocation(els) {
els.forEach(function (el) {
delete el.location;
if ((0, types_1.isSelectElement)(el) || (0, types_1.isPluralElement)(el)) {
for (var k in el.options) {
delete el.options[k].location;
pruneLocation(el.options[k].value);
}
}
else if ((0, types_1.isNumberElement)(el) && (0, types_1.isNumberSkeleton)(el.style)) {
delete el.style.location;
}
else if (((0, types_1.isDateElement)(el) || (0, types_1.isTimeElement)(el)) &&
(0, types_1.isDateTimeSkeleton)(el.style)) {
delete el.style.location;
}
else if ((0, types_1.isTagElement)(el)) {
pruneLocation(el.children);
}
});
}
function parse(message, opts) {
if (opts === void 0) { opts = {}; }
opts = tslib_1.__assign({ shouldParseSkeletons: true, requiresOtherClause: true }, opts);
var result = new parser_1.Parser(message, opts).parse();
if (result.err) {
var error = SyntaxError(error_1.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;
}
exports.parse = parse;
tslib_1.__exportStar(require("./types"), exports);
// only for testing
exports._Parser = parser_1.Parser;

View File

@@ -0,0 +1,8 @@
/**
* 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;

View File

@@ -0,0 +1,83 @@
import { timeData } from './time-data.generated';
/**
* 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;
}
/**
* 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];
}

View File

@@ -0,0 +1,68 @@
import { Location } from './types';
export interface ParserError {
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
}

View File

@@ -0,0 +1,63 @@
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 = {}));

View File

@@ -0,0 +1,6 @@
import { Parser, ParserOptions } from './parser';
import { MessageFormatElement } from './types';
export declare function parse(message: string, opts?: ParserOptions): MessageFormatElement[];
export type { ParserOptions };
export * from './types';
export declare const _Parser: typeof Parser;

View File

@@ -0,0 +1,45 @@
import { __assign } from "tslib";
import { ErrorKind } from './error';
import { Parser } from './parser';
import { isDateElement, isDateTimeSkeleton, isNumberElement, isNumberSkeleton, isPluralElement, isSelectElement, isTagElement, isTimeElement, } from './types';
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);
}
});
}
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 * from './types';
// only for testing
export var _Parser = Parser;

View File

@@ -0,0 +1,13 @@
import { MessageFormatElement } from './types';
/**
* 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[];

View File

@@ -0,0 +1,67 @@
import { __spreadArray } from "tslib";
import { isPluralElement, isSelectElement, isTagElement, } from './types';
function cloneDeep(obj) {
if (Array.isArray(obj)) {
// @ts-expect-error meh
return __spreadArray([], obj.map(cloneDeep), true);
}
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;
}
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;
cloned.options = Object.keys(options).reduce(function (all, k) {
var newValue = hoistSelectors(__spreadArray(__spreadArray(__spreadArray([], ast.slice(0, positionToInject), true), options[k].value, true), ast.slice(positionToInject + 1), true));
all[k] = {
value: newValue,
};
return all;
}, {});
return cloned;
}
function isPluralOrSelectElement(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;
});
}
/**
* 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;
}

View File

@@ -0,0 +1,3 @@
export declare function parse(): void;
export * from './types';
export declare const _Parser: undefined;

View File

@@ -0,0 +1,5 @@
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");
}
export * from './types';
export var _Parser = undefined;

View File

@@ -0,0 +1,147 @@
import { ParserError } from './error';
import { MessageFormatElement } from './types';
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;
}
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;
}
export type Result<T, E> = {
val: T;
err: null;
} | {
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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
import { MessageFormatElement, DateTimeSkeleton } from './types';
export declare function printAST(ast: MessageFormatElement[]): string;
export declare function doPrintAST(ast: MessageFormatElement[], isInPlural: boolean): string;
export declare function printDateTimeSkeleton(style: DateTimeSkeleton): string;

View File

@@ -0,0 +1,101 @@
import { __spreadArray } from "tslib";
import { isLiteralElement, isTagElement, isSelectElement, isArgumentElement, isDateElement, isTimeElement, isNumberElement, isPluralElement, TYPE, SKELETON_TYPE, isPoundElement, } from './types';
export function printAST(ast) {
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('');
}
function printTagElement(el) {
return "<".concat(el.value, ">").concat(printAST(el.children), "</").concat(el.value, ">");
}
function printEscapedMessage(message) {
return message.replace(/([{}](?:.*[{}])?)/su, "'$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 printArgumentElement(_a) {
var value = _a.value;
return "{".concat(value, "}");
}
function printSimpleFormatElement(el) {
return "{".concat(el.value, ", ").concat(TYPE[el.type]).concat(el.style ? ", ".concat(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(''));
}
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(' '));
}
}
export function printDateTimeSkeleton(style) {
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, "}");
}
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, "}");
}

View File

@@ -0,0 +1,2 @@
export declare const SPACE_SEPARATOR_REGEX: RegExp;
export declare const WHITE_SPACE_REGEX: RegExp;

View File

@@ -0,0 +1,3 @@
// @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]/;

View File

@@ -0,0 +1 @@
export declare const timeData: Record<string, string[]>;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
import type { NumberFormatOptions } from '@formatjs/ecma402-abstract';
import { NumberSkeletonToken } from '@formatjs/icu-skeleton-parser';
export interface ExtendedNumberFormatOptions extends NumberFormatOptions {
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
}
export declare enum SKELETON_TYPE {
number = 0,
dateTime = 1
}
export interface LocationDetails {
offset: number;
line: number;
column: number;
}
export interface Location {
start: LocationDetails;
end: LocationDetails;
}
export interface BaseElement<T extends TYPE> {
type: T;
value: string;
location?: Location;
}
export type LiteralElement = BaseElement<TYPE.literal>;
export type ArgumentElement = BaseElement<TYPE.argument>;
export interface TagElement {
type: TYPE.tag;
value: string;
children: MessageFormatElement[];
location?: Location;
}
export interface SimpleFormatElement<T extends TYPE, S extends Skeleton> extends BaseElement<T> {
style?: string | S | null;
}
export type NumberElement = SimpleFormatElement<TYPE.number, NumberSkeleton>;
export type DateElement = SimpleFormatElement<TYPE.date, DateTimeSkeleton>;
export type TimeElement = SimpleFormatElement<TYPE.time, DateTimeSkeleton>;
export type ValidPluralRule = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' | string;
export interface PluralOrSelectOption {
value: MessageFormatElement[];
location?: Location;
}
export interface SelectElement extends BaseElement<TYPE.select> {
options: Record<string, PluralOrSelectOption>;
}
export interface PluralElement extends BaseElement<TYPE.plural> {
options: Record<ValidPluralRule, PluralOrSelectOption>;
offset: number;
pluralType: Intl.PluralRulesOptions['type'];
}
export interface PoundElement {
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;
}
export interface DateTimeSkeleton {
type: SKELETON_TYPE.dateTime;
pattern: string;
location?: Location;
parsedOptions: Intl.DateTimeFormatOptions;
}
export type Skeleton = NumberSkeleton | DateTimeSkeleton;
/**
* Type Guards
*/
export declare function isLiteralElement(el: MessageFormatElement): el is LiteralElement;
export declare function isArgumentElement(el: MessageFormatElement): el is ArgumentElement;
export declare function isNumberElement(el: MessageFormatElement): el is NumberElement;
export declare function isDateElement(el: MessageFormatElement): el is DateElement;
export declare function isTimeElement(el: MessageFormatElement): el is TimeElement;
export declare function isSelectElement(el: MessageFormatElement): el is SelectElement;
export declare function isPluralElement(el: MessageFormatElement): el is PluralElement;
export declare function isPoundElement(el: MessageFormatElement): el is PoundElement;
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 createLiteralElement(value: string): LiteralElement;
export declare function createNumberElement(value: string, style?: string | null): NumberElement;
export type IntlLocaleLike = {
readonly hourCycle?: Intl.LocaleHourCycleKey;
readonly hourCycles?: Array<Intl.LocaleHourCycleKey>;
};

View File

@@ -0,0 +1,94 @@
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 = {}));
/**
* Type Guards
*/
export function isLiteralElement(el) {
return el.type === TYPE.literal;
}
export function isArgumentElement(el) {
return el.type === TYPE.argument;
}
export function isNumberElement(el) {
return el.type === TYPE.number;
}
export function isDateElement(el) {
return el.type === TYPE.date;
}
export function isTimeElement(el) {
return el.type === TYPE.time;
}
export function isSelectElement(el) {
return el.type === TYPE.select;
}
export function isPluralElement(el) {
return el.type === TYPE.plural;
}
export function isPoundElement(el) {
return el.type === TYPE.pound;
}
export function isTagElement(el) {
return el.type === TYPE.tag;
}
export function isNumberSkeleton(el) {
return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.number);
}
export function isDateTimeSkeleton(el) {
return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.dateTime);
}
export function createLiteralElement(value) {
return {
type: TYPE.literal,
value: value,
};
}
export function createNumberElement(value, style) {
return {
type: TYPE.number,
value: value,
style: style,
};
}

View File

@@ -0,0 +1,13 @@
import { MessageFormatElement } from './types';
/**
* 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[];

View File

@@ -0,0 +1,71 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hoistSelectors = void 0;
var tslib_1 = require("tslib");
var types_1 = require("./types");
function cloneDeep(obj) {
if (Array.isArray(obj)) {
// @ts-expect-error meh
return tslib_1.__spreadArray([], obj.map(cloneDeep), true);
}
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;
}
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;
cloned.options = Object.keys(options).reduce(function (all, k) {
var newValue = hoistSelectors(tslib_1.__spreadArray(tslib_1.__spreadArray(tslib_1.__spreadArray([], ast.slice(0, positionToInject), true), options[k].value, true), ast.slice(positionToInject + 1), true));
all[k] = {
value: newValue,
};
return all;
}, {});
return cloned;
}
function isPluralOrSelectElement(el) {
return (0, types_1.isPluralElement)(el) || (0, types_1.isSelectElement)(el);
}
function findPluralOrSelectElement(ast) {
return !!ast.find(function (el) {
if (isPluralOrSelectElement(el)) {
return true;
}
if ((0, types_1.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
*/
function hoistSelectors(ast) {
for (var i = 0; i < ast.length; i++) {
var el = ast[i];
if (isPluralOrSelectElement(el)) {
return [hoistPluralOrSelectElement(ast, el, i)];
}
if ((0, types_1.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;
}
exports.hoistSelectors = hoistSelectors;

View File

@@ -0,0 +1,3 @@
export declare function parse(): void;
export * from './types';
export declare const _Parser: undefined;

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._Parser = exports.parse = void 0;
var tslib_1 = require("tslib");
function parse() {
throw new Error("You're trying to format an uncompiled message with react-intl without parser, please import from 'react-intl' instead");
}
exports.parse = parse;
tslib_1.__exportStar(require("./types"), exports);
exports._Parser = undefined;

View File

@@ -0,0 +1,18 @@
{
"name": "@formatjs/icu-messageformat-parser",
"version": "2.7.6",
"main": "index.js",
"module": "lib/index.js",
"types": "index.d.ts",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/formatjs/formatjs.git",
"directory": "packages/icu-messageformat-parser"
},
"dependencies": {
"tslib": "^2.4.0",
"@formatjs/icu-skeleton-parser": "1.8.0",
"@formatjs/ecma402-abstract": "1.18.2"
}
}

View File

@@ -0,0 +1,147 @@
import { ParserError } from './error';
import { MessageFormatElement } from './types';
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;
}
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;
}
export type Result<T, E> = {
val: T;
err: null;
} | {
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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
import { MessageFormatElement, DateTimeSkeleton } from './types';
export declare function printAST(ast: MessageFormatElement[]): string;
export declare function doPrintAST(ast: MessageFormatElement[], isInPlural: boolean): string;
export declare function printDateTimeSkeleton(style: DateTimeSkeleton): string;

View File

@@ -0,0 +1,107 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.printDateTimeSkeleton = exports.doPrintAST = exports.printAST = void 0;
var tslib_1 = require("tslib");
var types_1 = require("./types");
function printAST(ast) {
return doPrintAST(ast, false);
}
exports.printAST = printAST;
function doPrintAST(ast, isInPlural) {
var printedNodes = ast.map(function (el, i) {
if ((0, types_1.isLiteralElement)(el)) {
return printLiteralElement(el, isInPlural, i === 0, i === ast.length - 1);
}
if ((0, types_1.isArgumentElement)(el)) {
return printArgumentElement(el);
}
if ((0, types_1.isDateElement)(el) || (0, types_1.isTimeElement)(el) || (0, types_1.isNumberElement)(el)) {
return printSimpleFormatElement(el);
}
if ((0, types_1.isPluralElement)(el)) {
return printPluralElement(el);
}
if ((0, types_1.isSelectElement)(el)) {
return printSelectElement(el);
}
if ((0, types_1.isPoundElement)(el)) {
return '#';
}
if ((0, types_1.isTagElement)(el)) {
return printTagElement(el);
}
});
return printedNodes.join('');
}
exports.doPrintAST = doPrintAST;
function printTagElement(el) {
return "<".concat(el.value, ">").concat(printAST(el.children), "</").concat(el.value, ">");
}
function printEscapedMessage(message) {
return message.replace(/([{}](?:.*[{}])?)/su, "'$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 printArgumentElement(_a) {
var value = _a.value;
return "{".concat(value, "}");
}
function printSimpleFormatElement(el) {
return "{".concat(el.value, ", ").concat(types_1.TYPE[el.type]).concat(el.style ? ", ".concat(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(''));
}
function printArgumentStyle(style) {
if (typeof style === 'string') {
return printEscapedMessage(style);
}
else if (style.type === types_1.SKELETON_TYPE.dateTime) {
return "::".concat(printDateTimeSkeleton(style));
}
else {
return "::".concat(style.tokens.map(printNumberSkeletonToken).join(' '));
}
}
function printDateTimeSkeleton(style) {
return style.pattern;
}
exports.printDateTimeSkeleton = printDateTimeSkeleton;
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, "}");
}
function printPluralElement(el) {
var type = el.pluralType === 'cardinal' ? 'plural' : 'selectordinal';
var msg = [
el.value,
type,
tslib_1.__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, "}");
}

View File

@@ -0,0 +1,2 @@
export declare const SPACE_SEPARATOR_REGEX: RegExp;
export declare const WHITE_SPACE_REGEX: RegExp;

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WHITE_SPACE_REGEX = exports.SPACE_SEPARATOR_REGEX = void 0;
// @generated from regex-gen.ts
exports.SPACE_SEPARATOR_REGEX = /[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/;
exports.WHITE_SPACE_REGEX = /[\t-\r \x85\u200E\u200F\u2028\u2029]/;

View File

@@ -0,0 +1 @@
export declare const timeData: Record<string, string[]>;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
import type { NumberFormatOptions } from '@formatjs/ecma402-abstract';
import { NumberSkeletonToken } from '@formatjs/icu-skeleton-parser';
export interface ExtendedNumberFormatOptions extends NumberFormatOptions {
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
}
export declare enum SKELETON_TYPE {
number = 0,
dateTime = 1
}
export interface LocationDetails {
offset: number;
line: number;
column: number;
}
export interface Location {
start: LocationDetails;
end: LocationDetails;
}
export interface BaseElement<T extends TYPE> {
type: T;
value: string;
location?: Location;
}
export type LiteralElement = BaseElement<TYPE.literal>;
export type ArgumentElement = BaseElement<TYPE.argument>;
export interface TagElement {
type: TYPE.tag;
value: string;
children: MessageFormatElement[];
location?: Location;
}
export interface SimpleFormatElement<T extends TYPE, S extends Skeleton> extends BaseElement<T> {
style?: string | S | null;
}
export type NumberElement = SimpleFormatElement<TYPE.number, NumberSkeleton>;
export type DateElement = SimpleFormatElement<TYPE.date, DateTimeSkeleton>;
export type TimeElement = SimpleFormatElement<TYPE.time, DateTimeSkeleton>;
export type ValidPluralRule = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' | string;
export interface PluralOrSelectOption {
value: MessageFormatElement[];
location?: Location;
}
export interface SelectElement extends BaseElement<TYPE.select> {
options: Record<string, PluralOrSelectOption>;
}
export interface PluralElement extends BaseElement<TYPE.plural> {
options: Record<ValidPluralRule, PluralOrSelectOption>;
offset: number;
pluralType: Intl.PluralRulesOptions['type'];
}
export interface PoundElement {
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;
}
export interface DateTimeSkeleton {
type: SKELETON_TYPE.dateTime;
pattern: string;
location?: Location;
parsedOptions: Intl.DateTimeFormatOptions;
}
export type Skeleton = NumberSkeleton | DateTimeSkeleton;
/**
* Type Guards
*/
export declare function isLiteralElement(el: MessageFormatElement): el is LiteralElement;
export declare function isArgumentElement(el: MessageFormatElement): el is ArgumentElement;
export declare function isNumberElement(el: MessageFormatElement): el is NumberElement;
export declare function isDateElement(el: MessageFormatElement): el is DateElement;
export declare function isTimeElement(el: MessageFormatElement): el is TimeElement;
export declare function isSelectElement(el: MessageFormatElement): el is SelectElement;
export declare function isPluralElement(el: MessageFormatElement): el is PluralElement;
export declare function isPoundElement(el: MessageFormatElement): el is PoundElement;
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 createLiteralElement(value: string): LiteralElement;
export declare function createNumberElement(value: string, style?: string | null): NumberElement;
export type IntlLocaleLike = {
readonly hourCycle?: Intl.LocaleHourCycleKey;
readonly hourCycles?: Array<Intl.LocaleHourCycleKey>;
};

View File

@@ -0,0 +1,110 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNumberElement = exports.createLiteralElement = exports.isDateTimeSkeleton = exports.isNumberSkeleton = exports.isTagElement = exports.isPoundElement = exports.isPluralElement = exports.isSelectElement = exports.isTimeElement = exports.isDateElement = exports.isNumberElement = exports.isArgumentElement = exports.isLiteralElement = exports.SKELETON_TYPE = exports.TYPE = void 0;
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 || (exports.TYPE = TYPE = {}));
var SKELETON_TYPE;
(function (SKELETON_TYPE) {
SKELETON_TYPE[SKELETON_TYPE["number"] = 0] = "number";
SKELETON_TYPE[SKELETON_TYPE["dateTime"] = 1] = "dateTime";
})(SKELETON_TYPE || (exports.SKELETON_TYPE = SKELETON_TYPE = {}));
/**
* Type Guards
*/
function isLiteralElement(el) {
return el.type === TYPE.literal;
}
exports.isLiteralElement = isLiteralElement;
function isArgumentElement(el) {
return el.type === TYPE.argument;
}
exports.isArgumentElement = isArgumentElement;
function isNumberElement(el) {
return el.type === TYPE.number;
}
exports.isNumberElement = isNumberElement;
function isDateElement(el) {
return el.type === TYPE.date;
}
exports.isDateElement = isDateElement;
function isTimeElement(el) {
return el.type === TYPE.time;
}
exports.isTimeElement = isTimeElement;
function isSelectElement(el) {
return el.type === TYPE.select;
}
exports.isSelectElement = isSelectElement;
function isPluralElement(el) {
return el.type === TYPE.plural;
}
exports.isPluralElement = isPluralElement;
function isPoundElement(el) {
return el.type === TYPE.pound;
}
exports.isPoundElement = isPoundElement;
function isTagElement(el) {
return el.type === TYPE.tag;
}
exports.isTagElement = isTagElement;
function isNumberSkeleton(el) {
return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.number);
}
exports.isNumberSkeleton = isNumberSkeleton;
function isDateTimeSkeleton(el) {
return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.dateTime);
}
exports.isDateTimeSkeleton = isDateTimeSkeleton;
function createLiteralElement(value) {
return {
type: TYPE.literal,
value: value,
};
}
exports.createLiteralElement = createLiteralElement;
function createNumberElement(value, style) {
return {
type: TYPE.number,
value: value,
style: style,
};
}
exports.createNumberElement = createNumberElement;