@formatjs/icu-messageformat-parser 3.2.1 → 3.3.0

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 CHANGED
@@ -1,178 +1,177 @@
1
- import { __assign, __spreadArray } from "tslib";
2
- import { isArgumentElement, isDateElement, isNumberElement, isPluralElement, isPoundElement, isSelectElement, isTagElement, isTimeElement, TYPE, } from './types.js';
1
+ import { isArgumentElement, isDateElement, isNumberElement, isPluralElement, isPoundElement, isSelectElement, isTagElement, isTimeElement, TYPE } from "./types.js";
3
2
  function cloneDeep(obj) {
4
- if (Array.isArray(obj)) {
5
- // @ts-expect-error meh
6
- return obj.map(cloneDeep);
7
- }
8
- if (obj !== null && typeof obj === 'object') {
9
- // @ts-expect-error meh
10
- return Object.keys(obj).reduce(function (cloned, k) {
11
- // @ts-expect-error meh
12
- cloned[k] = cloneDeep(obj[k]);
13
- return cloned;
14
- }, {});
15
- }
16
- return obj;
3
+ if (Array.isArray(obj)) {
4
+ // @ts-expect-error meh
5
+ return obj.map(cloneDeep);
6
+ }
7
+ if (obj !== null && typeof obj === "object") {
8
+ // @ts-expect-error meh
9
+ return Object.keys(obj).reduce((cloned, k) => {
10
+ // @ts-expect-error meh
11
+ cloned[k] = cloneDeep(obj[k]);
12
+ return cloned;
13
+ }, {});
14
+ }
15
+ return obj;
17
16
  }
18
17
  /**
19
- * Replace pound elements with number elements referencing the given variable.
20
- * This is needed when nesting plurals - the # in the outer plural should become
21
- * an explicit variable reference when nested inside another plural.
22
- * GH #4202
23
- */
18
+ * Replace pound elements with number elements referencing the given variable.
19
+ * This is needed when nesting plurals - the # in the outer plural should become
20
+ * an explicit variable reference when nested inside another plural.
21
+ * GH #4202
22
+ */
24
23
  function replacePoundWithArgument(ast, variableName) {
25
- return ast.map(function (el) {
26
- if (isPoundElement(el)) {
27
- // Replace # with {variableName, number}
28
- return {
29
- type: TYPE.number,
30
- value: variableName,
31
- style: null,
32
- location: el.location,
33
- };
34
- }
35
- if (isPluralElement(el) || isSelectElement(el)) {
36
- // Recursively process options
37
- var newOptions = {};
38
- for (var _i = 0, _a = Object.keys(el.options); _i < _a.length; _i++) {
39
- var key = _a[_i];
40
- newOptions[key] = {
41
- value: replacePoundWithArgument(el.options[key].value, variableName),
42
- };
43
- }
44
- return __assign(__assign({}, el), { options: newOptions });
45
- }
46
- if (isTagElement(el)) {
47
- return __assign(__assign({}, el), { children: replacePoundWithArgument(el.children, variableName) });
48
- }
49
- return el;
50
- });
24
+ return ast.map((el) => {
25
+ if (isPoundElement(el)) {
26
+ // Replace # with {variableName, number}
27
+ return {
28
+ type: TYPE.number,
29
+ value: variableName,
30
+ style: null,
31
+ location: el.location
32
+ };
33
+ }
34
+ if (isPluralElement(el) || isSelectElement(el)) {
35
+ // Recursively process options
36
+ const newOptions = {};
37
+ for (const key of Object.keys(el.options)) {
38
+ newOptions[key] = { value: replacePoundWithArgument(el.options[key].value, variableName) };
39
+ }
40
+ return {
41
+ ...el,
42
+ options: newOptions
43
+ };
44
+ }
45
+ if (isTagElement(el)) {
46
+ return {
47
+ ...el,
48
+ children: replacePoundWithArgument(el.children, variableName)
49
+ };
50
+ }
51
+ return el;
52
+ });
51
53
  }
52
54
  function hoistPluralOrSelectElement(ast, el, positionToInject) {
53
- // pull this out of the ast and move it to the top
54
- var cloned = cloneDeep(el);
55
- var options = cloned.options;
56
- // GH #4202: Check if there are other plural/select elements after this one
57
- var afterElements = ast.slice(positionToInject + 1);
58
- var hasSubsequentPluralOrSelect = afterElements.some(isPluralOrSelectElement);
59
- cloned.options = Object.keys(options).reduce(function (all, k) {
60
- var optionValue = options[k].value;
61
- // GH #4202: If there are subsequent plurals/selects and this is a plural,
62
- // replace # with explicit variable reference to avoid ambiguity
63
- if (hasSubsequentPluralOrSelect && isPluralElement(el)) {
64
- optionValue = replacePoundWithArgument(optionValue, el.value);
65
- }
66
- var newValue = hoistSelectors(__spreadArray(__spreadArray(__spreadArray([], ast.slice(0, positionToInject), true), optionValue, true), afterElements, true));
67
- all[k] = {
68
- value: newValue,
69
- };
70
- return all;
71
- }, {});
72
- return cloned;
55
+ // pull this out of the ast and move it to the top
56
+ const cloned = cloneDeep(el);
57
+ const { options } = cloned;
58
+ // GH #4202: Check if there are other plural/select elements after this one
59
+ const afterElements = ast.slice(positionToInject + 1);
60
+ const hasSubsequentPluralOrSelect = afterElements.some(isPluralOrSelectElement);
61
+ cloned.options = Object.keys(options).reduce((all, k) => {
62
+ let optionValue = options[k].value;
63
+ // GH #4202: If there are subsequent plurals/selects and this is a plural,
64
+ // replace # with explicit variable reference to avoid ambiguity
65
+ if (hasSubsequentPluralOrSelect && isPluralElement(el)) {
66
+ optionValue = replacePoundWithArgument(optionValue, el.value);
67
+ }
68
+ const newValue = hoistSelectors([
69
+ ...ast.slice(0, positionToInject),
70
+ ...optionValue,
71
+ ...afterElements
72
+ ]);
73
+ all[k] = { value: newValue };
74
+ return all;
75
+ }, {});
76
+ return cloned;
73
77
  }
74
78
  function isPluralOrSelectElement(el) {
75
- return isPluralElement(el) || isSelectElement(el);
79
+ return isPluralElement(el) || isSelectElement(el);
76
80
  }
77
81
  function findPluralOrSelectElement(ast) {
78
- return !!ast.find(function (el) {
79
- if (isPluralOrSelectElement(el)) {
80
- return true;
81
- }
82
- if (isTagElement(el)) {
83
- return findPluralOrSelectElement(el.children);
84
- }
85
- return false;
86
- });
82
+ return !!ast.find((el) => {
83
+ if (isPluralOrSelectElement(el)) {
84
+ return true;
85
+ }
86
+ if (isTagElement(el)) {
87
+ return findPluralOrSelectElement(el.children);
88
+ }
89
+ return false;
90
+ });
87
91
  }
88
92
  /**
89
- * Hoist all selectors to the beginning of the AST & flatten the
90
- * resulting options. E.g:
91
- * "I have {count, plural, one{a dog} other{many dogs}}"
92
- * becomes "{count, plural, one{I have a dog} other{I have many dogs}}".
93
- * If there are multiple selectors, the order of which one is hoisted 1st
94
- * is non-deterministic.
95
- * The goal is to provide as many full sentences as possible since fragmented
96
- * sentences are not translator-friendly
97
- * @param ast AST
98
- */
93
+ * Hoist all selectors to the beginning of the AST & flatten the
94
+ * resulting options. E.g:
95
+ * "I have {count, plural, one{a dog} other{many dogs}}"
96
+ * becomes "{count, plural, one{I have a dog} other{I have many dogs}}".
97
+ * If there are multiple selectors, the order of which one is hoisted 1st
98
+ * is non-deterministic.
99
+ * The goal is to provide as many full sentences as possible since fragmented
100
+ * sentences are not translator-friendly
101
+ * @param ast AST
102
+ */
99
103
  export function hoistSelectors(ast) {
100
- for (var i = 0; i < ast.length; i++) {
101
- var el = ast[i];
102
- if (isPluralOrSelectElement(el)) {
103
- return [hoistPluralOrSelectElement(ast, el, i)];
104
- }
105
- if (isTagElement(el) && findPluralOrSelectElement([el])) {
106
- throw new Error('Cannot hoist plural/select within a tag element. Please put the tag element inside each plural/select option');
107
- }
108
- }
109
- return ast;
104
+ for (let i = 0; i < ast.length; i++) {
105
+ const el = ast[i];
106
+ if (isPluralOrSelectElement(el)) {
107
+ return [hoistPluralOrSelectElement(ast, el, i)];
108
+ }
109
+ if (isTagElement(el) && findPluralOrSelectElement([el])) {
110
+ throw new Error("Cannot hoist plural/select within a tag element. Please put the tag element inside each plural/select option");
111
+ }
112
+ }
113
+ return ast;
110
114
  }
111
115
  /**
112
- * Collect all variables in an AST to Record<string, TYPE>
113
- * @param ast AST to collect variables from
114
- * @param vars Record of variable name to variable type
115
- */
116
- function collectVariables(ast, vars) {
117
- if (vars === void 0) { vars = new Map(); }
118
- ast.forEach(function (el) {
119
- if (isArgumentElement(el) ||
120
- isDateElement(el) ||
121
- isTimeElement(el) ||
122
- isNumberElement(el)) {
123
- if (el.value in vars && vars.get(el.value) !== el.type) {
124
- throw new Error("Variable ".concat(el.value, " has conflicting types"));
125
- }
126
- vars.set(el.value, el.type);
127
- }
128
- if (isPluralElement(el) || isSelectElement(el)) {
129
- vars.set(el.value, el.type);
130
- Object.keys(el.options).forEach(function (k) {
131
- collectVariables(el.options[k].value, vars);
132
- });
133
- }
134
- if (isTagElement(el)) {
135
- vars.set(el.value, el.type);
136
- collectVariables(el.children, vars);
137
- }
138
- });
116
+ * Collect all variables in an AST to Record<string, TYPE>
117
+ * @param ast AST to collect variables from
118
+ * @param vars Record of variable name to variable type
119
+ */
120
+ function collectVariables(ast, vars = new Map()) {
121
+ ast.forEach((el) => {
122
+ if (isArgumentElement(el) || isDateElement(el) || isTimeElement(el) || isNumberElement(el)) {
123
+ if (el.value in vars && vars.get(el.value) !== el.type) {
124
+ throw new Error(`Variable ${el.value} has conflicting types`);
125
+ }
126
+ vars.set(el.value, el.type);
127
+ }
128
+ if (isPluralElement(el) || isSelectElement(el)) {
129
+ vars.set(el.value, el.type);
130
+ Object.keys(el.options).forEach((k) => {
131
+ collectVariables(el.options[k].value, vars);
132
+ });
133
+ }
134
+ if (isTagElement(el)) {
135
+ vars.set(el.value, el.type);
136
+ collectVariables(el.children, vars);
137
+ }
138
+ });
139
139
  }
140
140
  /**
141
- * Check if 2 ASTs are structurally the same. This primarily means that
142
- * they have the same variables with the same type
143
- * @param a
144
- * @param b
145
- * @returns
146
- */
141
+ * Check if 2 ASTs are structurally the same. This primarily means that
142
+ * they have the same variables with the same type
143
+ * @param a
144
+ * @param b
145
+ * @returns
146
+ */
147
147
  export function isStructurallySame(a, b) {
148
- var aVars = new Map();
149
- var bVars = new Map();
150
- collectVariables(a, aVars);
151
- collectVariables(b, bVars);
152
- if (aVars.size !== bVars.size) {
153
- return {
154
- success: false,
155
- error: new Error("Different number of variables: [".concat(Array.from(aVars.keys()).join(', '), "] vs [").concat(Array.from(bVars.keys()).join(', '), "]")),
156
- };
157
- }
158
- return Array.from(aVars.entries()).reduce(function (result, _a) {
159
- var key = _a[0], type = _a[1];
160
- if (!result.success) {
161
- return result;
162
- }
163
- var bType = bVars.get(key);
164
- if (bType == null) {
165
- return {
166
- success: false,
167
- error: new Error("Missing variable ".concat(key, " in message")),
168
- };
169
- }
170
- if (bType !== type) {
171
- return {
172
- success: false,
173
- error: new Error("Variable ".concat(key, " has conflicting types: ").concat(TYPE[type], " vs ").concat(TYPE[bType])),
174
- };
175
- }
176
- return result;
177
- }, { success: true });
148
+ const aVars = new Map();
149
+ const bVars = new Map();
150
+ collectVariables(a, aVars);
151
+ collectVariables(b, bVars);
152
+ if (aVars.size !== bVars.size) {
153
+ return {
154
+ success: false,
155
+ error: new Error(`Different number of variables: [${Array.from(aVars.keys()).join(", ")}] vs [${Array.from(bVars.keys()).join(", ")}]`)
156
+ };
157
+ }
158
+ return Array.from(aVars.entries()).reduce((result, [key, type]) => {
159
+ if (!result.success) {
160
+ return result;
161
+ }
162
+ const bType = bVars.get(key);
163
+ if (bType == null) {
164
+ return {
165
+ success: false,
166
+ error: new Error(`Missing variable ${key} in message`)
167
+ };
168
+ }
169
+ if (bType !== type) {
170
+ return {
171
+ success: false,
172
+ error: new Error(`Variable ${key} has conflicting types: ${TYPE[type]} vs ${TYPE[bType]}`)
173
+ };
174
+ }
175
+ return result;
176
+ }, { success: true });
178
177
  }
package/no-parser.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export declare function parse(): void;
2
- export * from './types.js';
2
+ export * from "./types.js";
3
3
  export declare const _Parser: undefined;
4
- export { isStructurallySame } from './manipulator.js';
4
+ export { isStructurallySame } from "./manipulator.js";
package/no-parser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export function parse() {
2
- throw new Error("You're trying to format an uncompiled message with react-intl without parser, please import from 'react-intl' instead");
2
+ throw new Error("You're trying to format an uncompiled message with react-intl without parser, please import from 'react-intl' instead");
3
3
  }
4
- export * from './types.js';
5
- export var _Parser = undefined;
6
- export { isStructurallySame } from './manipulator.js';
4
+ export * from "./types.js";
5
+ export const _Parser = undefined;
6
+ export { isStructurallySame } from "./manipulator.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formatjs/icu-messageformat-parser",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "types": "index.d.ts",
@@ -12,8 +12,8 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "tslib": "^2.8.0",
15
- "@formatjs/ecma402-abstract": "3.0.7",
16
- "@formatjs/icu-skeleton-parser": "2.0.7"
15
+ "@formatjs/ecma402-abstract": "3.0.8",
16
+ "@formatjs/icu-skeleton-parser": "2.0.8"
17
17
  },
18
18
  "repository": {
19
19
  "type": "git",