@common.js/formatjs__icu-messageformat-parser 3.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/manipulator.js ADDED
@@ -0,0 +1,344 @@
1
+ //#region packages/icu-messageformat-parser/types.ts
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ function _export(target, all) {
7
+ for(var name in all)Object.defineProperty(target, name, {
8
+ enumerable: true,
9
+ get: all[name]
10
+ });
11
+ }
12
+ _export(exports, {
13
+ hoistSelectors: function() {
14
+ return hoistSelectors;
15
+ },
16
+ isStructurallySame: function() {
17
+ return isStructurallySame;
18
+ }
19
+ });
20
+ function _arrayLikeToArray(arr, len) {
21
+ if (len == null || len > arr.length) len = arr.length;
22
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
23
+ return arr2;
24
+ }
25
+ function _arrayWithHoles(arr) {
26
+ if (Array.isArray(arr)) return arr;
27
+ }
28
+ function _arrayWithoutHoles(arr) {
29
+ if (Array.isArray(arr)) return _arrayLikeToArray(arr);
30
+ }
31
+ function _defineProperty(obj, key, value) {
32
+ if (key in obj) {
33
+ Object.defineProperty(obj, key, {
34
+ value: value,
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true
38
+ });
39
+ } else {
40
+ obj[key] = value;
41
+ }
42
+ return obj;
43
+ }
44
+ function _iterableToArray(iter) {
45
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
46
+ }
47
+ function _iterableToArrayLimit(arr, i) {
48
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
49
+ if (_i == null) return;
50
+ var _arr = [];
51
+ var _n = true;
52
+ var _d = false;
53
+ var _s, _e;
54
+ try {
55
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
56
+ _arr.push(_s.value);
57
+ if (i && _arr.length === i) break;
58
+ }
59
+ } catch (err) {
60
+ _d = true;
61
+ _e = err;
62
+ } finally{
63
+ try {
64
+ if (!_n && _i["return"] != null) _i["return"]();
65
+ } finally{
66
+ if (_d) throw _e;
67
+ }
68
+ }
69
+ return _arr;
70
+ }
71
+ function _nonIterableRest() {
72
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
73
+ }
74
+ function _nonIterableSpread() {
75
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
76
+ }
77
+ function _objectSpread(target) {
78
+ for(var i = 1; i < arguments.length; i++){
79
+ var source = arguments[i] != null ? arguments[i] : {};
80
+ var ownKeys = Object.keys(source);
81
+ if (typeof Object.getOwnPropertySymbols === "function") {
82
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
83
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
84
+ }));
85
+ }
86
+ ownKeys.forEach(function(key) {
87
+ _defineProperty(target, key, source[key]);
88
+ });
89
+ }
90
+ return target;
91
+ }
92
+ function ownKeys(object, enumerableOnly) {
93
+ var keys = Object.keys(object);
94
+ if (Object.getOwnPropertySymbols) {
95
+ var symbols = Object.getOwnPropertySymbols(object);
96
+ if (enumerableOnly) {
97
+ symbols = symbols.filter(function(sym) {
98
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
99
+ });
100
+ }
101
+ keys.push.apply(keys, symbols);
102
+ }
103
+ return keys;
104
+ }
105
+ function _objectSpreadProps(target, source) {
106
+ source = source != null ? source : {};
107
+ if (Object.getOwnPropertyDescriptors) {
108
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
109
+ } else {
110
+ ownKeys(Object(source)).forEach(function(key) {
111
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
112
+ });
113
+ }
114
+ return target;
115
+ }
116
+ function _slicedToArray(arr, i) {
117
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
118
+ }
119
+ function _toConsumableArray(arr) {
120
+ return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
121
+ }
122
+ function _unsupportedIterableToArray(o, minLen) {
123
+ if (!o) return;
124
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
125
+ var n = Object.prototype.toString.call(o).slice(8, -1);
126
+ if (n === "Object" && o.constructor) n = o.constructor.name;
127
+ if (n === "Map" || n === "Set") return Array.from(n);
128
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
129
+ }
130
+ var TYPE = /* @__PURE__ */ function(TYPE) {
131
+ /**
132
+ * Raw text
133
+ */ TYPE[TYPE["literal"] = 0] = "literal";
134
+ /**
135
+ * Variable w/o any format, e.g `var` in `this is a {var}`
136
+ */ TYPE[TYPE["argument"] = 1] = "argument";
137
+ /**
138
+ * Variable w/ number format
139
+ */ TYPE[TYPE["number"] = 2] = "number";
140
+ /**
141
+ * Variable w/ date format
142
+ */ TYPE[TYPE["date"] = 3] = "date";
143
+ /**
144
+ * Variable w/ time format
145
+ */ TYPE[TYPE["time"] = 4] = "time";
146
+ /**
147
+ * Variable w/ select format
148
+ */ TYPE[TYPE["select"] = 5] = "select";
149
+ /**
150
+ * Variable w/ plural format
151
+ */ TYPE[TYPE["plural"] = 6] = "plural";
152
+ /**
153
+ * Only possible within plural argument.
154
+ * This is the `#` symbol that will be substituted with the count.
155
+ */ TYPE[TYPE["pound"] = 7] = "pound";
156
+ /**
157
+ * XML-like tag
158
+ */ TYPE[TYPE["tag"] = 8] = "tag";
159
+ return TYPE;
160
+ }({});
161
+ function isArgumentElement(el) {
162
+ return el.type === 1;
163
+ }
164
+ function isNumberElement(el) {
165
+ return el.type === 2;
166
+ }
167
+ function isDateElement(el) {
168
+ return el.type === 3;
169
+ }
170
+ function isTimeElement(el) {
171
+ return el.type === 4;
172
+ }
173
+ function isSelectElement(el) {
174
+ return el.type === 5;
175
+ }
176
+ function isPluralElement(el) {
177
+ return el.type === 6;
178
+ }
179
+ function isPoundElement(el) {
180
+ return el.type === 7;
181
+ }
182
+ function isTagElement(el) {
183
+ return el.type === 8;
184
+ }
185
+ //#endregion
186
+ //#region packages/icu-messageformat-parser/manipulator.ts
187
+ function cloneDeep(obj) {
188
+ if (Array.isArray(obj)) return obj.map(cloneDeep);
189
+ if (obj !== null && typeof obj === "object") return Object.keys(obj).reduce(function(cloned, k) {
190
+ cloned[k] = cloneDeep(obj[k]);
191
+ return cloned;
192
+ }, {});
193
+ return obj;
194
+ }
195
+ /**
196
+ * Replace pound elements with number elements referencing the given variable.
197
+ * This is needed when nesting plurals - the # in the outer plural should become
198
+ * an explicit variable reference when nested inside another plural.
199
+ * GH #4202
200
+ */ function replacePoundWithArgument(ast, variableName) {
201
+ return ast.map(function(el) {
202
+ if (isPoundElement(el)) return {
203
+ type: 2,
204
+ value: variableName,
205
+ style: null,
206
+ location: el.location
207
+ };
208
+ if (isPluralElement(el) || isSelectElement(el)) {
209
+ var newOptions = {};
210
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
211
+ try {
212
+ for(var _iterator = Object.keys(el.options)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
213
+ var key = _step.value;
214
+ newOptions[key] = {
215
+ value: replacePoundWithArgument(el.options[key].value, variableName)
216
+ };
217
+ }
218
+ } catch (err) {
219
+ _didIteratorError = true;
220
+ _iteratorError = err;
221
+ } finally{
222
+ try {
223
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
224
+ _iterator.return();
225
+ }
226
+ } finally{
227
+ if (_didIteratorError) {
228
+ throw _iteratorError;
229
+ }
230
+ }
231
+ }
232
+ return _objectSpreadProps(_objectSpread({}, el), {
233
+ options: newOptions
234
+ });
235
+ }
236
+ if (isTagElement(el)) return _objectSpreadProps(_objectSpread({}, el), {
237
+ children: replacePoundWithArgument(el.children, variableName)
238
+ });
239
+ return el;
240
+ });
241
+ }
242
+ function hoistPluralOrSelectElement(ast, el, positionToInject) {
243
+ var cloned = cloneDeep(el);
244
+ var options = cloned.options;
245
+ var afterElements = ast.slice(positionToInject + 1);
246
+ var hasSubsequentPluralOrSelect = afterElements.some(isPluralOrSelectElement);
247
+ cloned.options = Object.keys(options).reduce(function(all, k) {
248
+ var optionValue = options[k].value;
249
+ if (hasSubsequentPluralOrSelect && isPluralElement(el)) optionValue = replacePoundWithArgument(optionValue, el.value);
250
+ all[k] = {
251
+ value: hoistSelectors(_toConsumableArray(ast.slice(0, positionToInject)).concat(_toConsumableArray(optionValue), _toConsumableArray(afterElements)))
252
+ };
253
+ return all;
254
+ }, {});
255
+ return cloned;
256
+ }
257
+ function isPluralOrSelectElement(el) {
258
+ return isPluralElement(el) || isSelectElement(el);
259
+ }
260
+ function findPluralOrSelectElement(ast) {
261
+ return !!ast.find(function(el) {
262
+ if (isPluralOrSelectElement(el)) return true;
263
+ if (isTagElement(el)) return findPluralOrSelectElement(el.children);
264
+ return false;
265
+ });
266
+ }
267
+ /**
268
+ * Hoist all selectors to the beginning of the AST & flatten the
269
+ * resulting options. E.g:
270
+ * "I have {count, plural, one{a dog} other{many dogs}}"
271
+ * becomes "{count, plural, one{I have a dog} other{I have many dogs}}".
272
+ * If there are multiple selectors, the order of which one is hoisted 1st
273
+ * is non-deterministic.
274
+ * The goal is to provide as many full sentences as possible since fragmented
275
+ * sentences are not translator-friendly
276
+ * @param ast AST
277
+ */ function hoistSelectors(ast) {
278
+ for(var i = 0; i < ast.length; i++){
279
+ var el = ast[i];
280
+ if (isPluralOrSelectElement(el)) return [
281
+ hoistPluralOrSelectElement(ast, el, i)
282
+ ];
283
+ if (isTagElement(el) && findPluralOrSelectElement([
284
+ el
285
+ ])) throw new Error("Cannot hoist plural/select within a tag element. Please put the tag element inside each plural/select option");
286
+ }
287
+ return ast;
288
+ }
289
+ /**
290
+ * Collect all variables in an AST to Record<string, TYPE>
291
+ * @param ast AST to collect variables from
292
+ * @param vars Record of variable name to variable type
293
+ */ function collectVariables(ast) {
294
+ var vars = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : /* @__PURE__ */ new Map();
295
+ ast.forEach(function(el) {
296
+ if (isArgumentElement(el) || isDateElement(el) || isTimeElement(el) || isNumberElement(el)) if (vars.has(el.value)) {
297
+ var existingType = vars.get(el.value);
298
+ if (existingType !== el.type && existingType !== 6 && existingType !== 5) throw new Error("Variable ".concat(el.value, " has conflicting types"));
299
+ } else vars.set(el.value, el.type);
300
+ if (isPluralElement(el) || isSelectElement(el)) {
301
+ vars.set(el.value, el.type);
302
+ Object.keys(el.options).forEach(function(k) {
303
+ collectVariables(el.options[k].value, vars);
304
+ });
305
+ }
306
+ if (isTagElement(el)) {
307
+ vars.set(el.value, el.type);
308
+ collectVariables(el.children, vars);
309
+ }
310
+ });
311
+ }
312
+ /**
313
+ * Check if 2 ASTs are structurally the same. This primarily means that
314
+ * they have the same variables with the same type
315
+ * @param a
316
+ * @param b
317
+ * @returns
318
+ */ function isStructurallySame(a, b) {
319
+ var aVars = /* @__PURE__ */ new Map();
320
+ var bVars = /* @__PURE__ */ new Map();
321
+ collectVariables(a, aVars);
322
+ collectVariables(b, bVars);
323
+ if (aVars.size !== bVars.size) return {
324
+ success: false,
325
+ error: /* @__PURE__ */ new Error("Different number of variables: [".concat(Array.from(aVars.keys()).join(", "), "] vs [").concat(Array.from(bVars.keys()).join(", "), "]"))
326
+ };
327
+ return Array.from(aVars.entries()).reduce(function(result, param) {
328
+ var _param = _slicedToArray(param, 2), key = _param[0], type = _param[1];
329
+ if (!result.success) return result;
330
+ var bType = bVars.get(key);
331
+ if (bType == null) return {
332
+ success: false,
333
+ error: /* @__PURE__ */ new Error("Missing variable ".concat(key, " in message"))
334
+ };
335
+ if (bType !== type) return {
336
+ success: false,
337
+ error: /* @__PURE__ */ new Error("Variable ".concat(key, " has conflicting types: ").concat(TYPE[type], " vs ").concat(TYPE[bType]))
338
+ };
339
+ return result;
340
+ }, {
341
+ success: true
342
+ });
343
+ }
344
+ //# sourceMappingURL=manipulator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manipulator.js","names":[],"sources":["../types.ts","../manipulator.ts"],"sourcesContent":["import type {NumberFormatOptions} from '#packages/ecma402-abstract/types/number.js'\nimport {type NumberSkeletonToken} from '@formatjs/icu-skeleton-parser'\n\nexport interface ExtendedNumberFormatOptions extends NumberFormatOptions {\n scale?: number\n}\n\nexport enum TYPE {\n /**\n * Raw text\n */\n literal,\n /**\n * Variable w/o any format, e.g `var` in `this is a {var}`\n */\n argument,\n /**\n * Variable w/ number format\n */\n number,\n /**\n * Variable w/ date format\n */\n date,\n /**\n * Variable w/ time format\n */\n time,\n /**\n * Variable w/ select format\n */\n select,\n /**\n * Variable w/ plural format\n */\n plural,\n /**\n * Only possible within plural argument.\n * This is the `#` symbol that will be substituted with the count.\n */\n pound,\n /**\n * XML-like tag\n */\n tag,\n}\n\nexport enum SKELETON_TYPE {\n number,\n dateTime,\n}\n\nexport interface LocationDetails {\n offset: number\n line: number\n column: number\n}\nexport interface Location {\n start: LocationDetails\n end: LocationDetails\n}\n\nexport interface BaseElement<T extends TYPE> {\n type: T\n value: string\n location?: Location\n}\n\nexport type LiteralElement = BaseElement<TYPE.literal>\nexport type ArgumentElement = BaseElement<TYPE.argument>\nexport interface TagElement extends BaseElement<TYPE.tag> {\n children: MessageFormatElement[]\n}\n\nexport interface SimpleFormatElement<\n T extends TYPE,\n S extends Skeleton,\n> extends BaseElement<T> {\n style?: string | S | null\n}\n\nexport type NumberElement = SimpleFormatElement<TYPE.number, NumberSkeleton>\nexport type DateElement = SimpleFormatElement<TYPE.date, DateTimeSkeleton>\nexport type TimeElement = SimpleFormatElement<TYPE.time, DateTimeSkeleton>\n\nexport type ValidPluralRule =\n | 'zero'\n | 'one'\n | 'two'\n | 'few'\n | 'many'\n | 'other'\n | string\n\nexport interface PluralOrSelectOption {\n value: MessageFormatElement[]\n location?: Location\n}\n\nexport interface SelectElement extends BaseElement<TYPE.select> {\n options: Record<string, PluralOrSelectOption>\n}\n\nexport interface PluralElement extends BaseElement<TYPE.plural> {\n options: Record<ValidPluralRule, PluralOrSelectOption>\n offset: number\n pluralType: Intl.PluralRulesOptions['type']\n}\n\nexport interface PoundElement {\n type: TYPE.pound\n location?: Location\n}\n\nexport type MessageFormatElement =\n | ArgumentElement\n | DateElement\n | LiteralElement\n | NumberElement\n | PluralElement\n | PoundElement\n | SelectElement\n | TagElement\n | TimeElement\n\nexport interface NumberSkeleton {\n type: SKELETON_TYPE.number\n tokens: NumberSkeletonToken[]\n location?: Location\n parsedOptions: ExtendedNumberFormatOptions\n}\n\nexport interface DateTimeSkeleton {\n type: SKELETON_TYPE.dateTime\n pattern: string\n location?: Location\n parsedOptions: Intl.DateTimeFormatOptions\n}\n\nexport type Skeleton = NumberSkeleton | DateTimeSkeleton\n\n/**\n * Type Guards\n */\nexport function isLiteralElement(\n el: MessageFormatElement\n): el is LiteralElement {\n return el.type === TYPE.literal\n}\nexport function isArgumentElement(\n el: MessageFormatElement\n): el is ArgumentElement {\n return el.type === TYPE.argument\n}\nexport function isNumberElement(el: MessageFormatElement): el is NumberElement {\n return el.type === TYPE.number\n}\nexport function isDateElement(el: MessageFormatElement): el is DateElement {\n return el.type === TYPE.date\n}\nexport function isTimeElement(el: MessageFormatElement): el is TimeElement {\n return el.type === TYPE.time\n}\nexport function isSelectElement(el: MessageFormatElement): el is SelectElement {\n return el.type === TYPE.select\n}\nexport function isPluralElement(el: MessageFormatElement): el is PluralElement {\n return el.type === TYPE.plural\n}\nexport function isPoundElement(el: MessageFormatElement): el is PoundElement {\n return el.type === TYPE.pound\n}\nexport function isTagElement(el: MessageFormatElement): el is TagElement {\n return el.type === TYPE.tag\n}\nexport function isNumberSkeleton(\n el: NumberElement['style'] | Skeleton\n): el is NumberSkeleton {\n return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.number)\n}\nexport function isDateTimeSkeleton(\n el?: DateElement['style'] | TimeElement['style'] | Skeleton\n): el is DateTimeSkeleton {\n return !!(el && typeof el === 'object' && el.type === SKELETON_TYPE.dateTime)\n}\n\nexport function createLiteralElement(value: string): LiteralElement {\n return {\n type: TYPE.literal,\n value,\n }\n}\n\nexport function createNumberElement(\n value: string,\n style?: string | null\n): NumberElement {\n return {\n type: TYPE.number,\n value,\n style,\n }\n}\n","import {\n isArgumentElement,\n isDateElement,\n isNumberElement,\n isPluralElement,\n isPoundElement,\n isSelectElement,\n isTagElement,\n isTimeElement,\n type MessageFormatElement,\n type PluralElement,\n type PluralOrSelectOption,\n type SelectElement,\n TYPE,\n} from '#packages/icu-messageformat-parser/types.js'\n\nfunction cloneDeep<T>(obj: T): T {\n if (Array.isArray(obj)) {\n // @ts-expect-error meh\n return obj.map(cloneDeep)\n }\n if (obj !== null && typeof obj === 'object') {\n // @ts-expect-error meh\n return Object.keys(obj).reduce((cloned, k) => {\n // @ts-expect-error meh\n cloned[k] = cloneDeep(obj[k])\n return cloned\n }, {})\n }\n return obj\n}\n\n/**\n * Replace pound elements with number elements referencing the given variable.\n * This is needed when nesting plurals - the # in the outer plural should become\n * an explicit variable reference when nested inside another plural.\n * GH #4202\n */\nfunction replacePoundWithArgument(\n ast: MessageFormatElement[],\n variableName: string\n): MessageFormatElement[] {\n return ast.map(el => {\n if (isPoundElement(el)) {\n // Replace # with {variableName, number}\n return {\n type: TYPE.number,\n value: variableName,\n style: null,\n location: el.location,\n }\n }\n if (isPluralElement(el) || isSelectElement(el)) {\n // Recursively process options\n const newOptions: Record<string, PluralOrSelectOption> = {}\n for (const key of Object.keys(el.options)) {\n newOptions[key] = {\n value: replacePoundWithArgument(el.options[key].value, variableName),\n }\n }\n return {...el, options: newOptions}\n }\n if (isTagElement(el)) {\n return {\n ...el,\n children: replacePoundWithArgument(el.children, variableName),\n }\n }\n return el\n })\n}\n\nfunction hoistPluralOrSelectElement(\n ast: MessageFormatElement[],\n el: PluralElement | SelectElement,\n positionToInject: number\n) {\n // pull this out of the ast and move it to the top\n const cloned = cloneDeep(el)\n const {options} = cloned\n\n // GH #4202: Check if there are other plural/select elements after this one\n const afterElements = ast.slice(positionToInject + 1)\n const hasSubsequentPluralOrSelect = afterElements.some(\n isPluralOrSelectElement\n )\n\n cloned.options = Object.keys(options).reduce(\n (all: Record<string, PluralOrSelectOption>, k) => {\n let optionValue = options[k].value\n\n // GH #4202: If there are subsequent plurals/selects and this is a plural,\n // replace # with explicit variable reference to avoid ambiguity\n if (hasSubsequentPluralOrSelect && isPluralElement(el)) {\n optionValue = replacePoundWithArgument(optionValue, el.value)\n }\n\n const newValue = hoistSelectors([\n ...ast.slice(0, positionToInject),\n ...optionValue,\n ...afterElements,\n ])\n all[k] = {\n value: newValue,\n }\n return all\n },\n {}\n )\n return cloned\n}\n\nfunction isPluralOrSelectElement(\n el: MessageFormatElement\n): el is PluralElement | SelectElement {\n return isPluralElement(el) || isSelectElement(el)\n}\n\nfunction findPluralOrSelectElement(ast: MessageFormatElement[]): boolean {\n return !!ast.find(el => {\n if (isPluralOrSelectElement(el)) {\n return true\n }\n if (isTagElement(el)) {\n return findPluralOrSelectElement(el.children)\n }\n return false\n })\n}\n\n/**\n * Hoist all selectors to the beginning of the AST & flatten the\n * resulting options. E.g:\n * \"I have {count, plural, one{a dog} other{many dogs}}\"\n * becomes \"{count, plural, one{I have a dog} other{I have many dogs}}\".\n * If there are multiple selectors, the order of which one is hoisted 1st\n * is non-deterministic.\n * The goal is to provide as many full sentences as possible since fragmented\n * sentences are not translator-friendly\n * @param ast AST\n */\nexport function hoistSelectors(\n ast: MessageFormatElement[]\n): MessageFormatElement[] {\n for (let i = 0; i < ast.length; i++) {\n const el = ast[i]\n if (isPluralOrSelectElement(el)) {\n return [hoistPluralOrSelectElement(ast, el, i)]\n }\n if (isTagElement(el) && findPluralOrSelectElement([el])) {\n throw new Error(\n 'Cannot hoist plural/select within a tag element. Please put the tag element inside each plural/select option'\n )\n }\n }\n return ast\n}\n\n/**\n * Collect all variables in an AST to Record<string, TYPE>\n * @param ast AST to collect variables from\n * @param vars Record of variable name to variable type\n */\nfunction collectVariables(\n ast: MessageFormatElement[],\n vars: Map<string, TYPE> = new Map<string, TYPE>()\n): void {\n ast.forEach(el => {\n if (\n isArgumentElement(el) ||\n isDateElement(el) ||\n isTimeElement(el) ||\n isNumberElement(el)\n ) {\n // If the variable was already registered as a plural/select, it's normal\n // for it to also appear inside as number/date/time/argument — not a conflict.\n if (vars.has(el.value)) {\n const existingType = vars.get(el.value)!\n if (\n existingType !== el.type &&\n existingType !== TYPE.plural &&\n existingType !== TYPE.select\n ) {\n throw new Error(`Variable ${el.value} has conflicting types`)\n }\n } else {\n vars.set(el.value, el.type)\n }\n }\n\n if (isPluralElement(el) || isSelectElement(el)) {\n vars.set(el.value, el.type)\n Object.keys(el.options).forEach(k => {\n collectVariables(el.options[k].value, vars)\n })\n }\n\n if (isTagElement(el)) {\n vars.set(el.value, el.type)\n collectVariables(el.children, vars)\n }\n })\n}\n\ninterface IsStructurallySameResult {\n error?: Error\n success: boolean\n}\n\n/**\n * Check if 2 ASTs are structurally the same. This primarily means that\n * they have the same variables with the same type\n * @param a\n * @param b\n * @returns\n */\nexport function isStructurallySame(\n a: MessageFormatElement[],\n b: MessageFormatElement[]\n): IsStructurallySameResult {\n const aVars = new Map<string, TYPE>()\n const bVars = new Map<string, TYPE>()\n collectVariables(a, aVars)\n collectVariables(b, bVars)\n\n if (aVars.size !== bVars.size) {\n return {\n success: false,\n error: new Error(\n `Different number of variables: [${Array.from(aVars.keys()).join(', ')}] vs [${Array.from(bVars.keys()).join(', ')}]`\n ),\n }\n }\n\n return Array.from(aVars.entries()).reduce<IsStructurallySameResult>(\n (result, [key, type]) => {\n if (!result.success) {\n return result\n }\n const bType = bVars.get(key)\n if (bType == null) {\n return {\n success: false,\n error: new Error(`Missing variable ${key} in message`),\n }\n }\n if (bType !== type) {\n return {\n success: false,\n error: new Error(\n `Variable ${key} has conflicting types: ${TYPE[type]} vs ${TYPE[bType]}`\n ),\n }\n }\n return result\n },\n {success: true}\n )\n}\n"],"mappings":"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"}
package/no-parser.d.ts ADDED
@@ -0,0 +1,185 @@
1
+ import { NumberSkeletonToken } from "@formatjs/icu-skeleton-parser";
2
+
3
+ //#region packages/ecma402-abstract/types/number.d.ts
4
+ type NumberFormatNotation = "standard" | "scientific" | "engineering" | "compact";
5
+ type RoundingPriorityType = "auto" | "morePrecision" | "lessPrecision";
6
+ type RoundingModeType = "ceil" | "floor" | "expand" | "trunc" | "halfCeil" | "halfFloor" | "halfExpand" | "halfTrunc" | "halfEven";
7
+ type UseGroupingType = "min2" | "auto" | "always" | boolean;
8
+ interface NumberFormatDigitOptions {
9
+ minimumIntegerDigits?: number;
10
+ minimumSignificantDigits?: number;
11
+ maximumSignificantDigits?: number;
12
+ minimumFractionDigits?: number;
13
+ maximumFractionDigits?: number;
14
+ roundingPriority?: RoundingPriorityType;
15
+ roundingIncrement?: number;
16
+ roundingMode?: RoundingModeType;
17
+ trailingZeroDisplay?: TrailingZeroDisplay;
18
+ }
19
+ type NumberFormatOptionsLocaleMatcher = "lookup" | "best fit";
20
+ type NumberFormatOptionsStyle = "decimal" | "percent" | "currency" | "unit";
21
+ type NumberFormatOptionsCompactDisplay = "short" | "long";
22
+ type NumberFormatOptionsCurrencyDisplay = "symbol" | "code" | "name" | "narrowSymbol";
23
+ type NumberFormatOptionsCurrencySign = "standard" | "accounting";
24
+ type NumberFormatOptionsNotation = NumberFormatNotation;
25
+ type NumberFormatOptionsSignDisplay = "auto" | "always" | "never" | "exceptZero" | "negative";
26
+ type NumberFormatOptionsUnitDisplay = "long" | "short" | "narrow";
27
+ type TrailingZeroDisplay = "auto" | "stripIfInteger";
28
+ type NumberFormatOptions = Omit<Intl.NumberFormatOptions, "signDisplay" | "useGrouping"> & NumberFormatDigitOptions & {
29
+ localeMatcher?: NumberFormatOptionsLocaleMatcher;
30
+ style?: NumberFormatOptionsStyle;
31
+ compactDisplay?: NumberFormatOptionsCompactDisplay;
32
+ currencyDisplay?: NumberFormatOptionsCurrencyDisplay;
33
+ currencySign?: NumberFormatOptionsCurrencySign;
34
+ notation?: NumberFormatOptionsNotation;
35
+ signDisplay?: NumberFormatOptionsSignDisplay;
36
+ unit?: string;
37
+ unitDisplay?: NumberFormatOptionsUnitDisplay;
38
+ numberingSystem?: string;
39
+ trailingZeroDisplay?: TrailingZeroDisplay;
40
+ roundingPriority?: RoundingPriorityType;
41
+ roundingIncrement?: number;
42
+ roundingMode?: RoundingModeType;
43
+ useGrouping?: UseGroupingType;
44
+ };
45
+ //#endregion
46
+ //#region packages/icu-messageformat-parser/types.d.ts
47
+ interface ExtendedNumberFormatOptions extends NumberFormatOptions {
48
+ scale?: number;
49
+ }
50
+ declare enum TYPE {
51
+ /**
52
+ * Raw text
53
+ */
54
+ literal = 0,
55
+ /**
56
+ * Variable w/o any format, e.g `var` in `this is a {var}`
57
+ */
58
+ argument = 1,
59
+ /**
60
+ * Variable w/ number format
61
+ */
62
+ number = 2,
63
+ /**
64
+ * Variable w/ date format
65
+ */
66
+ date = 3,
67
+ /**
68
+ * Variable w/ time format
69
+ */
70
+ time = 4,
71
+ /**
72
+ * Variable w/ select format
73
+ */
74
+ select = 5,
75
+ /**
76
+ * Variable w/ plural format
77
+ */
78
+ plural = 6,
79
+ /**
80
+ * Only possible within plural argument.
81
+ * This is the `#` symbol that will be substituted with the count.
82
+ */
83
+ pound = 7,
84
+ /**
85
+ * XML-like tag
86
+ */
87
+ tag = 8
88
+ }
89
+ declare enum SKELETON_TYPE {
90
+ number = 0,
91
+ dateTime = 1
92
+ }
93
+ interface LocationDetails {
94
+ offset: number;
95
+ line: number;
96
+ column: number;
97
+ }
98
+ interface Location {
99
+ start: LocationDetails;
100
+ end: LocationDetails;
101
+ }
102
+ interface BaseElement<T extends TYPE> {
103
+ type: T;
104
+ value: string;
105
+ location?: Location;
106
+ }
107
+ type LiteralElement = BaseElement<TYPE.literal>;
108
+ type ArgumentElement = BaseElement<TYPE.argument>;
109
+ interface TagElement extends BaseElement<TYPE.tag> {
110
+ children: MessageFormatElement[];
111
+ }
112
+ interface SimpleFormatElement<T extends TYPE, S extends Skeleton> extends BaseElement<T> {
113
+ style?: string | S | null;
114
+ }
115
+ type NumberElement = SimpleFormatElement<TYPE.number, NumberSkeleton>;
116
+ type DateElement = SimpleFormatElement<TYPE.date, DateTimeSkeleton>;
117
+ type TimeElement = SimpleFormatElement<TYPE.time, DateTimeSkeleton>;
118
+ type ValidPluralRule = "zero" | "one" | "two" | "few" | "many" | "other" | string;
119
+ interface PluralOrSelectOption {
120
+ value: MessageFormatElement[];
121
+ location?: Location;
122
+ }
123
+ interface SelectElement extends BaseElement<TYPE.select> {
124
+ options: Record<string, PluralOrSelectOption>;
125
+ }
126
+ interface PluralElement extends BaseElement<TYPE.plural> {
127
+ options: Record<ValidPluralRule, PluralOrSelectOption>;
128
+ offset: number;
129
+ pluralType: Intl.PluralRulesOptions["type"];
130
+ }
131
+ interface PoundElement {
132
+ type: TYPE.pound;
133
+ location?: Location;
134
+ }
135
+ type MessageFormatElement = ArgumentElement | DateElement | LiteralElement | NumberElement | PluralElement | PoundElement | SelectElement | TagElement | TimeElement;
136
+ interface NumberSkeleton {
137
+ type: SKELETON_TYPE.number;
138
+ tokens: NumberSkeletonToken[];
139
+ location?: Location;
140
+ parsedOptions: ExtendedNumberFormatOptions;
141
+ }
142
+ interface DateTimeSkeleton {
143
+ type: SKELETON_TYPE.dateTime;
144
+ pattern: string;
145
+ location?: Location;
146
+ parsedOptions: Intl.DateTimeFormatOptions;
147
+ }
148
+ type Skeleton = NumberSkeleton | DateTimeSkeleton;
149
+ /**
150
+ * Type Guards
151
+ */
152
+ declare function isLiteralElement(el: MessageFormatElement): el is LiteralElement;
153
+ declare function isArgumentElement(el: MessageFormatElement): el is ArgumentElement;
154
+ declare function isNumberElement(el: MessageFormatElement): el is NumberElement;
155
+ declare function isDateElement(el: MessageFormatElement): el is DateElement;
156
+ declare function isTimeElement(el: MessageFormatElement): el is TimeElement;
157
+ declare function isSelectElement(el: MessageFormatElement): el is SelectElement;
158
+ declare function isPluralElement(el: MessageFormatElement): el is PluralElement;
159
+ declare function isPoundElement(el: MessageFormatElement): el is PoundElement;
160
+ declare function isTagElement(el: MessageFormatElement): el is TagElement;
161
+ declare function isNumberSkeleton(el: NumberElement["style"] | Skeleton): el is NumberSkeleton;
162
+ declare function isDateTimeSkeleton(el?: DateElement["style"] | TimeElement["style"] | Skeleton): el is DateTimeSkeleton;
163
+ declare function createLiteralElement(value: string): LiteralElement;
164
+ declare function createNumberElement(value: string, style?: string | null): NumberElement;
165
+ //#endregion
166
+ //#region packages/icu-messageformat-parser/manipulator.d.ts
167
+ interface IsStructurallySameResult {
168
+ error?: Error;
169
+ success: boolean;
170
+ }
171
+ /**
172
+ * Check if 2 ASTs are structurally the same. This primarily means that
173
+ * they have the same variables with the same type
174
+ * @param a
175
+ * @param b
176
+ * @returns
177
+ */
178
+ declare function isStructurallySame(a: MessageFormatElement[], b: MessageFormatElement[]): IsStructurallySameResult;
179
+ //#endregion
180
+ //#region packages/icu-messageformat-parser/no-parser.d.ts
181
+ declare function parse(): void;
182
+ declare const _Parser: undefined;
183
+ //#endregion
184
+ export { ArgumentElement, BaseElement, DateElement, DateTimeSkeleton, ExtendedNumberFormatOptions, LiteralElement, Location, LocationDetails, MessageFormatElement, NumberElement, NumberSkeleton, PluralElement, PluralOrSelectOption, PoundElement, SKELETON_TYPE, SelectElement, SimpleFormatElement, Skeleton, TYPE, TagElement, TimeElement, ValidPluralRule, _Parser, createLiteralElement, createNumberElement, isArgumentElement, isDateElement, isDateTimeSkeleton, isLiteralElement, isNumberElement, isNumberSkeleton, isPluralElement, isPoundElement, isSelectElement, isStructurallySame, isTagElement, isTimeElement, parse };
185
+ //# sourceMappingURL=no-parser.d.ts.map