@lingui/message-utils 5.9.2 → 6.0.0-next.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.
@@ -11,4 +11,5 @@ type MapTextFn = (value: string) => string;
11
11
  declare function compileMessageOrThrow(message: string, mapText?: MapTextFn): CompiledMessage;
12
12
  declare function compileMessage(message: string, mapText?: MapTextFn): CompiledMessage;
13
13
 
14
- export { type CompiledIcuChoices, type CompiledMessage, type CompiledMessageToken, compileMessage, compileMessageOrThrow };
14
+ export { compileMessage, compileMessageOrThrow };
15
+ export type { CompiledIcuChoices, CompiledMessage, CompiledMessageToken };
@@ -1,303 +1,6 @@
1
1
  import { parse } from '@messageformat/parser';
2
-
3
- /**
4
- * Parent class for errors.
5
- *
6
- * @remarks
7
- * Errors with `type: "warning"` do not necessarily indicate that the parser
8
- * encountered an error. In addition to a human-friendly `message`, may also
9
- * includes the `token` at which the error was encountered.
10
- *
11
- * @public
12
- */
13
- class DateFormatError extends Error {
14
- /** @internal */
15
- constructor(msg, token, type) {
16
- super(msg);
17
- this.token = token;
18
- this.type = type || 'error';
19
- }
20
- }
21
- const alpha = (width) => width < 4 ? 'short' : width === 4 ? 'long' : 'narrow';
22
- const numeric = (width) => (width % 2 === 0 ? '2-digit' : 'numeric');
23
- function yearOptions(token, onError) {
24
- switch (token.char) {
25
- case 'y':
26
- return { year: numeric(token.width) };
27
- case 'r':
28
- return { calendar: 'gregory', year: 'numeric' };
29
- case 'u':
30
- case 'U':
31
- case 'Y':
32
- default:
33
- onError(`${token.desc} is not supported; falling back to year:numeric`, DateFormatError.WARNING);
34
- return { year: 'numeric' };
35
- }
36
- }
37
- function monthStyle(token, onError) {
38
- switch (token.width) {
39
- case 1:
40
- return 'numeric';
41
- case 2:
42
- return '2-digit';
43
- case 3:
44
- return 'short';
45
- case 4:
46
- return 'long';
47
- case 5:
48
- return 'narrow';
49
- default:
50
- onError(`${token.desc} is not supported with width ${token.width}`);
51
- return undefined;
52
- }
53
- }
54
- function dayStyle(token, onError) {
55
- const { char, desc, width } = token;
56
- if (char === 'd') {
57
- return numeric(width);
58
- }
59
- else {
60
- onError(`${desc} is not supported`);
61
- return undefined;
62
- }
63
- }
64
- function weekdayStyle(token, onError) {
65
- const { char, desc, width } = token;
66
- if ((char === 'c' || char === 'e') && width < 3) {
67
- // ignoring stand-alone-ness
68
- const msg = `Numeric value is not supported for ${desc}; falling back to weekday:short`;
69
- onError(msg, DateFormatError.WARNING);
70
- }
71
- // merging narrow styles
72
- return alpha(width);
73
- }
74
- function hourOptions(token) {
75
- const hour = numeric(token.width);
76
- let hourCycle;
77
- switch (token.char) {
78
- case 'h':
79
- hourCycle = 'h12';
80
- break;
81
- case 'H':
82
- hourCycle = 'h23';
83
- break;
84
- case 'k':
85
- hourCycle = 'h24';
86
- break;
87
- case 'K':
88
- hourCycle = 'h11';
89
- break;
90
- }
91
- return hourCycle ? { hour, hourCycle } : { hour };
92
- }
93
- function timeZoneNameStyle(token, onError) {
94
- // so much fallback behaviour here
95
- const { char, desc, width } = token;
96
- switch (char) {
97
- case 'v':
98
- case 'z':
99
- return width === 4 ? 'long' : 'short';
100
- case 'V':
101
- if (width === 4)
102
- return 'long';
103
- onError(`${desc} is not supported with width ${width}`);
104
- return undefined;
105
- case 'X':
106
- onError(`${desc} is not supported`);
107
- return undefined;
108
- }
109
- return 'short';
110
- }
111
- function compileOptions(token, onError) {
112
- switch (token.field) {
113
- case 'era':
114
- return { era: alpha(token.width) };
115
- case 'year':
116
- return yearOptions(token, onError);
117
- case 'month':
118
- return { month: monthStyle(token, onError) };
119
- case 'day':
120
- return { day: dayStyle(token, onError) };
121
- case 'weekday':
122
- return { weekday: weekdayStyle(token, onError) };
123
- case 'period':
124
- return undefined;
125
- case 'hour':
126
- return hourOptions(token);
127
- case 'min':
128
- return { minute: numeric(token.width) };
129
- case 'sec':
130
- return { second: numeric(token.width) };
131
- case 'tz':
132
- return { timeZoneName: timeZoneNameStyle(token, onError) };
133
- case 'quarter':
134
- case 'week':
135
- case 'sec-frac':
136
- case 'ms':
137
- onError(`${token.desc} is not supported`);
138
- }
139
- return undefined;
140
- }
141
- function getDateFormatOptions(tokens, timeZone, onError = error => {
142
- throw error;
143
- }) {
144
- const options = {
145
- timeZone
146
- };
147
- const fields = [];
148
- for (const token of tokens) {
149
- const { error, field, str } = token;
150
- if (error) {
151
- const dte = new DateFormatError(error.message, token);
152
- dte.stack = error.stack;
153
- onError(dte);
154
- }
155
- if (str) {
156
- const msg = `Ignoring string part: ${str}`;
157
- onError(new DateFormatError(msg, token, DateFormatError.WARNING));
158
- }
159
- if (field) {
160
- if (fields.indexOf(field) === -1)
161
- fields.push(field);
162
- else
163
- onError(new DateFormatError(`Duplicate ${field} token`, token));
164
- }
165
- const opt = compileOptions(token, (msg, isWarning) => onError(new DateFormatError(msg, token, isWarning)));
166
- if (opt)
167
- Object.assign(options, opt);
168
- }
169
- return options;
170
- }
171
-
172
- const fields = {
173
- G: { field: 'era', desc: 'Era' },
174
- y: { field: 'year', desc: 'Year' },
175
- Y: { field: 'year', desc: 'Year of "Week of Year"' },
176
- u: { field: 'year', desc: 'Extended year' },
177
- U: { field: 'year', desc: 'Cyclic year name' },
178
- r: { field: 'year', desc: 'Related Gregorian year' },
179
- Q: { field: 'quarter', desc: 'Quarter' },
180
- q: { field: 'quarter', desc: 'Stand-alone quarter' },
181
- M: { field: 'month', desc: 'Month in year' },
182
- L: { field: 'month', desc: 'Stand-alone month in year' },
183
- w: { field: 'week', desc: 'Week of year' },
184
- W: { field: 'week', desc: 'Week of month' },
185
- d: { field: 'day', desc: 'Day in month' },
186
- D: { field: 'day', desc: 'Day of year' },
187
- F: { field: 'day', desc: 'Day of week in month' },
188
- g: { field: 'day', desc: 'Modified julian day' },
189
- E: { field: 'weekday', desc: 'Day of week' },
190
- e: { field: 'weekday', desc: 'Local day of week' },
191
- c: { field: 'weekday', desc: 'Stand-alone local day of week' },
192
- a: { field: 'period', desc: 'AM/PM marker' },
193
- b: { field: 'period', desc: 'AM/PM/noon/midnight marker' },
194
- B: { field: 'period', desc: 'Flexible day period' },
195
- h: { field: 'hour', desc: 'Hour in AM/PM (1~12)' },
196
- H: { field: 'hour', desc: 'Hour in day (0~23)' },
197
- k: { field: 'hour', desc: 'Hour in day (1~24)' },
198
- K: { field: 'hour', desc: 'Hour in AM/PM (0~11)' },
199
- j: { field: 'hour', desc: 'Hour in preferred cycle' },
200
- J: { field: 'hour', desc: 'Hour in preferred cycle without marker' },
201
- C: { field: 'hour', desc: 'Hour in preferred cycle with flexible marker' },
202
- m: { field: 'min', desc: 'Minute in hour' },
203
- s: { field: 'sec', desc: 'Second in minute' },
204
- S: { field: 'sec-frac', desc: 'Fractional second' },
205
- A: { field: 'ms', desc: 'Milliseconds in day' },
206
- z: { field: 'tz', desc: 'Time Zone: specific non-location' },
207
- Z: { field: 'tz', desc: 'Time Zone' },
208
- O: { field: 'tz', desc: 'Time Zone: localized' },
209
- v: { field: 'tz', desc: 'Time Zone: generic non-location' },
210
- V: { field: 'tz', desc: 'Time Zone: ID' },
211
- X: { field: 'tz', desc: 'Time Zone: ISO8601 with Z' },
212
- x: { field: 'tz', desc: 'Time Zone: ISO8601' }
213
- };
214
- const isLetter = (char) => (char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z');
215
- function readFieldToken(src, pos) {
216
- const char = src[pos];
217
- let width = 1;
218
- while (src[++pos] === char)
219
- ++width;
220
- const field = fields[char];
221
- if (!field) {
222
- const msg = `The letter ${char} is not a valid field identifier`;
223
- return { char, error: new Error(msg), width };
224
- }
225
- return { char, field: field.field, desc: field.desc, width };
226
- }
227
- function readQuotedToken(src, pos) {
228
- let str = src[++pos];
229
- let width = 2;
230
- if (str === "'")
231
- return { char: "'", str, width };
232
- while (true) {
233
- const next = src[++pos];
234
- ++width;
235
- if (next === undefined) {
236
- const msg = `Unterminated quoted literal in pattern: ${str || src}`;
237
- return { char: "'", error: new Error(msg), str, width };
238
- }
239
- else if (next === "'") {
240
- if (src[++pos] !== "'")
241
- return { char: "'", str, width };
242
- else
243
- ++width;
244
- }
245
- str += next;
246
- }
247
- }
248
- function readToken(src, pos) {
249
- const char = src[pos];
250
- if (!char)
251
- return null;
252
- if (isLetter(char))
253
- return readFieldToken(src, pos);
254
- if (char === "'")
255
- return readQuotedToken(src, pos);
256
- let str = char;
257
- let width = 1;
258
- while (true) {
259
- const next = src[++pos];
260
- if (!next || isLetter(next) || next === "'")
261
- return { char, str, width };
262
- str += next;
263
- width += 1;
264
- }
265
- }
266
- /**
267
- * Parse an {@link http://userguide.icu-project.org/formatparse/datetime | ICU
268
- * DateFormat skeleton} string into a {@link DateToken} array.
269
- *
270
- * @remarks
271
- * Errors will not be thrown, but if encountered are included as the relevant
272
- * token's `error` value.
273
- *
274
- * @public
275
- * @param src - The skeleton string
276
- *
277
- * @example
278
- * ```js
279
- * import { parseDateTokens } from '@messageformat/date-skeleton'
280
- *
281
- * parseDateTokens('GrMMMdd', console.error)
282
- * // [
283
- * // { char: 'G', field: 'era', desc: 'Era', width: 1 },
284
- * // { char: 'r', field: 'year', desc: 'Related Gregorian year', width: 1 },
285
- * // { char: 'M', field: 'month', desc: 'Month in year', width: 3 },
286
- * // { char: 'd', field: 'day', desc: 'Day in month', width: 2 }
287
- * // ]
288
- * ```
289
- */
290
- function parseDateTokens(src) {
291
- const tokens = [];
292
- let pos = 0;
293
- while (true) {
294
- const token = readToken(src, pos);
295
- if (!token)
296
- return tokens;
297
- tokens.push(token);
298
- pos += token.width;
299
- }
300
- }
2
+ import { getDateFormatOptions } from '@messageformat/date-skeleton/lib/options.js';
3
+ import { parseDateTokens } from '@messageformat/date-skeleton';
301
4
 
302
5
  function processTokens(tokens, mapText) {
303
6
  if (!tokens.filter((token) => token.type !== "content").length) {
@@ -1,3 +1,3 @@
1
- declare function generateMessageId(msg: string, context?: string): string;
1
+ declare function generateMessageId(msg: string, context?: string): any;
2
2
 
3
3
  export { generateMessageId };
@@ -1,9 +1,9 @@
1
1
  import { sha256 } from 'js-sha256';
2
- import { U as UNIT_SEPARATOR } from './shared/message-utils.0012eec6.mjs';
2
+ import { U as UNIT_SEPARATOR } from './shared/message-utils.CVg98WzE.mjs';
3
3
 
4
4
  function generateMessageId(msg, context = "") {
5
5
  const hashBytes = sha256.array(msg + UNIT_SEPARATOR + (context || ""));
6
- return btoa(String.fromCharCode(...hashBytes)).slice(0, 6);
6
+ return btoa(String.fromCharCode(...hashBytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "").slice(0, 6);
7
7
  }
8
8
 
9
9
  export { generateMessageId };
@@ -1,3 +1,3 @@
1
- declare const generateMessageId: (msg: string, context?: string) => string;
1
+ declare const generateMessageId: (msg: string, context?: string) => any;
2
2
 
3
3
  export { generateMessageId };
@@ -1,8 +1,8 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { U as UNIT_SEPARATOR } from './shared/message-utils.0012eec6.mjs';
2
+ import { U as UNIT_SEPARATOR } from './shared/message-utils.CVg98WzE.mjs';
3
3
 
4
4
  const generateMessageId = (msg, context = "") => {
5
- const hash = createHash("sha256").update(msg + UNIT_SEPARATOR + (context || "")).digest("base64");
5
+ const hash = createHash("sha256").update(msg + UNIT_SEPARATOR + (context || "")).digest("base64url");
6
6
  return hash.slice(0, 6);
7
7
  };
8
8
 
package/package.json CHANGED
@@ -1,46 +1,20 @@
1
1
  {
2
2
  "name": "@lingui/message-utils",
3
- "version": "5.9.2",
3
+ "version": "6.0.0-next.0",
4
4
  "license": "MIT",
5
5
  "keywords": [],
6
6
  "sideEffects": false,
7
+ "type": "module",
7
8
  "exports": {
8
9
  "./generateMessageId": {
9
- "node": {
10
- "import": {
11
- "types": "./dist/generateMessageId.node.d.mts",
12
- "default": "./dist/generateMessageId.node.mjs"
13
- },
14
- "require": {
15
- "types": "./dist/generateMessageId.node.d.cts",
16
- "default": "./dist/generateMessageId.node.cjs"
17
- }
18
- },
19
- "default": {
20
- "import": {
21
- "types": "./dist/generateMessageId.d.mts",
22
- "default": "./dist/generateMessageId.mjs"
23
- },
24
- "require": {
25
- "types": "./dist/generateMessageId.d.cts",
26
- "default": "./dist/generateMessageId.cjs"
27
- }
28
- }
10
+ "node": "./dist/generateMessageId.node.mjs",
11
+ "default": "./dist/generateMessageId.mjs"
29
12
  },
30
- "./compileMessage": {
31
- "import": {
32
- "types": "./dist/compileMessage.d.mts",
33
- "default": "./dist/compileMessage.mjs"
34
- },
35
- "require": {
36
- "types": "./dist/compileMessage.d.cts",
37
- "default": "./dist/compileMessage.cjs"
38
- }
39
- }
13
+ "./compileMessage": "./dist/compileMessage.mjs"
40
14
  },
41
15
  "scripts": {
42
- "build": "rimraf ./dist && unbuild",
43
- "stub": "unbuild --stub"
16
+ "build": "unbuild",
17
+ "check-types": "tsc --noEmit"
44
18
  },
45
19
  "homepage": "https://lingui.dev",
46
20
  "repository": {
@@ -52,22 +26,24 @@
52
26
  "url": "https://github.com/lingui/js-lingui/issues"
53
27
  },
54
28
  "engines": {
55
- "node": ">=20.0.0"
29
+ "node": ">=22.19.0"
56
30
  },
57
31
  "files": [
58
32
  "README.md",
59
- "dist/",
60
- "compileMessage.js",
61
- "generateMessageId.js"
33
+ "dist/"
62
34
  ],
63
35
  "dependencies": {
36
+ "@messageformat/date-skeleton": "^1.1.0",
64
37
  "@messageformat/parser": "^5.0.0",
65
38
  "js-sha256": "^0.10.1"
66
39
  },
67
40
  "devDependencies": {
68
- "@lingui/jest-mocks": "^3.0.3",
69
- "@messageformat/date-skeleton": "^1.1.0",
70
- "unbuild": "2.0.0"
41
+ "@lingui/test-utils": "3.0.3",
42
+ "unbuild": "3.6.1",
43
+ "vitest": "4.0.18"
44
+ },
45
+ "unbuild": {
46
+ "declaration": "node16"
71
47
  },
72
- "gitHead": "7b30f31b5510c98442eabbcef531a6b70e1c1381"
48
+ "gitHead": "a9576050487a4f7dfbc88db20814d5a1bb861c8c"
73
49
  }
package/compileMessage.js DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * this file is a workaround for older runtimes
3
- * such as React Native or Jest 27 which is not
4
- * support package.json exports field
5
- **/
6
- module.exports = require("./dist/compileMessage.cjs")
@@ -1,367 +0,0 @@
1
- 'use strict';
2
-
3
- const parser = require('@messageformat/parser');
4
-
5
- /**
6
- * Parent class for errors.
7
- *
8
- * @remarks
9
- * Errors with `type: "warning"` do not necessarily indicate that the parser
10
- * encountered an error. In addition to a human-friendly `message`, may also
11
- * includes the `token` at which the error was encountered.
12
- *
13
- * @public
14
- */
15
- class DateFormatError extends Error {
16
- /** @internal */
17
- constructor(msg, token, type) {
18
- super(msg);
19
- this.token = token;
20
- this.type = type || 'error';
21
- }
22
- }
23
- const alpha = (width) => width < 4 ? 'short' : width === 4 ? 'long' : 'narrow';
24
- const numeric = (width) => (width % 2 === 0 ? '2-digit' : 'numeric');
25
- function yearOptions(token, onError) {
26
- switch (token.char) {
27
- case 'y':
28
- return { year: numeric(token.width) };
29
- case 'r':
30
- return { calendar: 'gregory', year: 'numeric' };
31
- case 'u':
32
- case 'U':
33
- case 'Y':
34
- default:
35
- onError(`${token.desc} is not supported; falling back to year:numeric`, DateFormatError.WARNING);
36
- return { year: 'numeric' };
37
- }
38
- }
39
- function monthStyle(token, onError) {
40
- switch (token.width) {
41
- case 1:
42
- return 'numeric';
43
- case 2:
44
- return '2-digit';
45
- case 3:
46
- return 'short';
47
- case 4:
48
- return 'long';
49
- case 5:
50
- return 'narrow';
51
- default:
52
- onError(`${token.desc} is not supported with width ${token.width}`);
53
- return undefined;
54
- }
55
- }
56
- function dayStyle(token, onError) {
57
- const { char, desc, width } = token;
58
- if (char === 'd') {
59
- return numeric(width);
60
- }
61
- else {
62
- onError(`${desc} is not supported`);
63
- return undefined;
64
- }
65
- }
66
- function weekdayStyle(token, onError) {
67
- const { char, desc, width } = token;
68
- if ((char === 'c' || char === 'e') && width < 3) {
69
- // ignoring stand-alone-ness
70
- const msg = `Numeric value is not supported for ${desc}; falling back to weekday:short`;
71
- onError(msg, DateFormatError.WARNING);
72
- }
73
- // merging narrow styles
74
- return alpha(width);
75
- }
76
- function hourOptions(token) {
77
- const hour = numeric(token.width);
78
- let hourCycle;
79
- switch (token.char) {
80
- case 'h':
81
- hourCycle = 'h12';
82
- break;
83
- case 'H':
84
- hourCycle = 'h23';
85
- break;
86
- case 'k':
87
- hourCycle = 'h24';
88
- break;
89
- case 'K':
90
- hourCycle = 'h11';
91
- break;
92
- }
93
- return hourCycle ? { hour, hourCycle } : { hour };
94
- }
95
- function timeZoneNameStyle(token, onError) {
96
- // so much fallback behaviour here
97
- const { char, desc, width } = token;
98
- switch (char) {
99
- case 'v':
100
- case 'z':
101
- return width === 4 ? 'long' : 'short';
102
- case 'V':
103
- if (width === 4)
104
- return 'long';
105
- onError(`${desc} is not supported with width ${width}`);
106
- return undefined;
107
- case 'X':
108
- onError(`${desc} is not supported`);
109
- return undefined;
110
- }
111
- return 'short';
112
- }
113
- function compileOptions(token, onError) {
114
- switch (token.field) {
115
- case 'era':
116
- return { era: alpha(token.width) };
117
- case 'year':
118
- return yearOptions(token, onError);
119
- case 'month':
120
- return { month: monthStyle(token, onError) };
121
- case 'day':
122
- return { day: dayStyle(token, onError) };
123
- case 'weekday':
124
- return { weekday: weekdayStyle(token, onError) };
125
- case 'period':
126
- return undefined;
127
- case 'hour':
128
- return hourOptions(token);
129
- case 'min':
130
- return { minute: numeric(token.width) };
131
- case 'sec':
132
- return { second: numeric(token.width) };
133
- case 'tz':
134
- return { timeZoneName: timeZoneNameStyle(token, onError) };
135
- case 'quarter':
136
- case 'week':
137
- case 'sec-frac':
138
- case 'ms':
139
- onError(`${token.desc} is not supported`);
140
- }
141
- return undefined;
142
- }
143
- function getDateFormatOptions(tokens, timeZone, onError = error => {
144
- throw error;
145
- }) {
146
- const options = {
147
- timeZone
148
- };
149
- const fields = [];
150
- for (const token of tokens) {
151
- const { error, field, str } = token;
152
- if (error) {
153
- const dte = new DateFormatError(error.message, token);
154
- dte.stack = error.stack;
155
- onError(dte);
156
- }
157
- if (str) {
158
- const msg = `Ignoring string part: ${str}`;
159
- onError(new DateFormatError(msg, token, DateFormatError.WARNING));
160
- }
161
- if (field) {
162
- if (fields.indexOf(field) === -1)
163
- fields.push(field);
164
- else
165
- onError(new DateFormatError(`Duplicate ${field} token`, token));
166
- }
167
- const opt = compileOptions(token, (msg, isWarning) => onError(new DateFormatError(msg, token, isWarning)));
168
- if (opt)
169
- Object.assign(options, opt);
170
- }
171
- return options;
172
- }
173
-
174
- const fields = {
175
- G: { field: 'era', desc: 'Era' },
176
- y: { field: 'year', desc: 'Year' },
177
- Y: { field: 'year', desc: 'Year of "Week of Year"' },
178
- u: { field: 'year', desc: 'Extended year' },
179
- U: { field: 'year', desc: 'Cyclic year name' },
180
- r: { field: 'year', desc: 'Related Gregorian year' },
181
- Q: { field: 'quarter', desc: 'Quarter' },
182
- q: { field: 'quarter', desc: 'Stand-alone quarter' },
183
- M: { field: 'month', desc: 'Month in year' },
184
- L: { field: 'month', desc: 'Stand-alone month in year' },
185
- w: { field: 'week', desc: 'Week of year' },
186
- W: { field: 'week', desc: 'Week of month' },
187
- d: { field: 'day', desc: 'Day in month' },
188
- D: { field: 'day', desc: 'Day of year' },
189
- F: { field: 'day', desc: 'Day of week in month' },
190
- g: { field: 'day', desc: 'Modified julian day' },
191
- E: { field: 'weekday', desc: 'Day of week' },
192
- e: { field: 'weekday', desc: 'Local day of week' },
193
- c: { field: 'weekday', desc: 'Stand-alone local day of week' },
194
- a: { field: 'period', desc: 'AM/PM marker' },
195
- b: { field: 'period', desc: 'AM/PM/noon/midnight marker' },
196
- B: { field: 'period', desc: 'Flexible day period' },
197
- h: { field: 'hour', desc: 'Hour in AM/PM (1~12)' },
198
- H: { field: 'hour', desc: 'Hour in day (0~23)' },
199
- k: { field: 'hour', desc: 'Hour in day (1~24)' },
200
- K: { field: 'hour', desc: 'Hour in AM/PM (0~11)' },
201
- j: { field: 'hour', desc: 'Hour in preferred cycle' },
202
- J: { field: 'hour', desc: 'Hour in preferred cycle without marker' },
203
- C: { field: 'hour', desc: 'Hour in preferred cycle with flexible marker' },
204
- m: { field: 'min', desc: 'Minute in hour' },
205
- s: { field: 'sec', desc: 'Second in minute' },
206
- S: { field: 'sec-frac', desc: 'Fractional second' },
207
- A: { field: 'ms', desc: 'Milliseconds in day' },
208
- z: { field: 'tz', desc: 'Time Zone: specific non-location' },
209
- Z: { field: 'tz', desc: 'Time Zone' },
210
- O: { field: 'tz', desc: 'Time Zone: localized' },
211
- v: { field: 'tz', desc: 'Time Zone: generic non-location' },
212
- V: { field: 'tz', desc: 'Time Zone: ID' },
213
- X: { field: 'tz', desc: 'Time Zone: ISO8601 with Z' },
214
- x: { field: 'tz', desc: 'Time Zone: ISO8601' }
215
- };
216
- const isLetter = (char) => (char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z');
217
- function readFieldToken(src, pos) {
218
- const char = src[pos];
219
- let width = 1;
220
- while (src[++pos] === char)
221
- ++width;
222
- const field = fields[char];
223
- if (!field) {
224
- const msg = `The letter ${char} is not a valid field identifier`;
225
- return { char, error: new Error(msg), width };
226
- }
227
- return { char, field: field.field, desc: field.desc, width };
228
- }
229
- function readQuotedToken(src, pos) {
230
- let str = src[++pos];
231
- let width = 2;
232
- if (str === "'")
233
- return { char: "'", str, width };
234
- while (true) {
235
- const next = src[++pos];
236
- ++width;
237
- if (next === undefined) {
238
- const msg = `Unterminated quoted literal in pattern: ${str || src}`;
239
- return { char: "'", error: new Error(msg), str, width };
240
- }
241
- else if (next === "'") {
242
- if (src[++pos] !== "'")
243
- return { char: "'", str, width };
244
- else
245
- ++width;
246
- }
247
- str += next;
248
- }
249
- }
250
- function readToken(src, pos) {
251
- const char = src[pos];
252
- if (!char)
253
- return null;
254
- if (isLetter(char))
255
- return readFieldToken(src, pos);
256
- if (char === "'")
257
- return readQuotedToken(src, pos);
258
- let str = char;
259
- let width = 1;
260
- while (true) {
261
- const next = src[++pos];
262
- if (!next || isLetter(next) || next === "'")
263
- return { char, str, width };
264
- str += next;
265
- width += 1;
266
- }
267
- }
268
- /**
269
- * Parse an {@link http://userguide.icu-project.org/formatparse/datetime | ICU
270
- * DateFormat skeleton} string into a {@link DateToken} array.
271
- *
272
- * @remarks
273
- * Errors will not be thrown, but if encountered are included as the relevant
274
- * token's `error` value.
275
- *
276
- * @public
277
- * @param src - The skeleton string
278
- *
279
- * @example
280
- * ```js
281
- * import { parseDateTokens } from '@messageformat/date-skeleton'
282
- *
283
- * parseDateTokens('GrMMMdd', console.error)
284
- * // [
285
- * // { char: 'G', field: 'era', desc: 'Era', width: 1 },
286
- * // { char: 'r', field: 'year', desc: 'Related Gregorian year', width: 1 },
287
- * // { char: 'M', field: 'month', desc: 'Month in year', width: 3 },
288
- * // { char: 'd', field: 'day', desc: 'Day in month', width: 2 }
289
- * // ]
290
- * ```
291
- */
292
- function parseDateTokens(src) {
293
- const tokens = [];
294
- let pos = 0;
295
- while (true) {
296
- const token = readToken(src, pos);
297
- if (!token)
298
- return tokens;
299
- tokens.push(token);
300
- pos += token.width;
301
- }
302
- }
303
-
304
- function processTokens(tokens, mapText) {
305
- if (!tokens.filter((token) => token.type !== "content").length) {
306
- return tokens.map((token) => mapText(token.value));
307
- }
308
- return tokens.map((token) => {
309
- if (token.type === "content") {
310
- return mapText(token.value);
311
- } else if (token.type === "octothorpe") {
312
- return "#";
313
- } else if (token.type === "argument") {
314
- return [token.arg];
315
- } else if (token.type === "function") {
316
- const _param = token?.param?.[0];
317
- if (token.key === "date" && _param) {
318
- const opts = compileDateExpression(_param.value.trim(), (e) => {
319
- throw new Error(`Unable to compile date expression: ${e.message}`);
320
- });
321
- return [token.arg, token.key, opts];
322
- }
323
- if (_param) {
324
- return [token.arg, token.key, _param.value.trim()];
325
- } else {
326
- return [token.arg, token.key];
327
- }
328
- }
329
- const offset = token.pluralOffset;
330
- const formatProps = {};
331
- token.cases.forEach(({ key, tokens: tokens2 }) => {
332
- const prop = key[0] === "=" ? key.slice(1) : key;
333
- formatProps[prop] = processTokens(tokens2, mapText);
334
- });
335
- return [
336
- token.arg,
337
- token.type,
338
- {
339
- offset,
340
- ...formatProps
341
- }
342
- ];
343
- });
344
- }
345
- function compileDateExpression(format, onError) {
346
- if (/^::/.test(format)) {
347
- const tokens = parseDateTokens(format.substring(2));
348
- return getDateFormatOptions(tokens, void 0, onError);
349
- }
350
- return format;
351
- }
352
- function compileMessageOrThrow(message, mapText = (v) => v) {
353
- return processTokens(parser.parse(message), mapText);
354
- }
355
- function compileMessage(message, mapText = (v) => v) {
356
- try {
357
- return compileMessageOrThrow(message, mapText);
358
- } catch (e) {
359
- console.error(`${e.message}
360
-
361
- Message: ${message}`);
362
- return [message];
363
- }
364
- }
365
-
366
- exports.compileMessage = compileMessage;
367
- exports.compileMessageOrThrow = compileMessageOrThrow;
@@ -1,14 +0,0 @@
1
- type CompiledIcuChoices = Record<string, CompiledMessage> & {
2
- offset: number | undefined;
3
- };
4
- type CompiledMessageToken = string | [
5
- name: string,
6
- type?: string,
7
- format?: null | string | unknown | CompiledIcuChoices
8
- ];
9
- type CompiledMessage = CompiledMessageToken[];
10
- type MapTextFn = (value: string) => string;
11
- declare function compileMessageOrThrow(message: string, mapText?: MapTextFn): CompiledMessage;
12
- declare function compileMessage(message: string, mapText?: MapTextFn): CompiledMessage;
13
-
14
- export { type CompiledIcuChoices, type CompiledMessage, type CompiledMessageToken, compileMessage, compileMessageOrThrow };
@@ -1,14 +0,0 @@
1
- type CompiledIcuChoices = Record<string, CompiledMessage> & {
2
- offset: number | undefined;
3
- };
4
- type CompiledMessageToken = string | [
5
- name: string,
6
- type?: string,
7
- format?: null | string | unknown | CompiledIcuChoices
8
- ];
9
- type CompiledMessage = CompiledMessageToken[];
10
- type MapTextFn = (value: string) => string;
11
- declare function compileMessageOrThrow(message: string, mapText?: MapTextFn): CompiledMessage;
12
- declare function compileMessage(message: string, mapText?: MapTextFn): CompiledMessage;
13
-
14
- export { type CompiledIcuChoices, type CompiledMessage, type CompiledMessageToken, compileMessage, compileMessageOrThrow };
@@ -1,11 +0,0 @@
1
- 'use strict';
2
-
3
- const jsSha256 = require('js-sha256');
4
- const constants = require('./shared/message-utils.43a3d79e.cjs');
5
-
6
- function generateMessageId(msg, context = "") {
7
- const hashBytes = jsSha256.sha256.array(msg + constants.UNIT_SEPARATOR + (context || ""));
8
- return btoa(String.fromCharCode(...hashBytes)).slice(0, 6);
9
- }
10
-
11
- exports.generateMessageId = generateMessageId;
@@ -1,3 +0,0 @@
1
- declare function generateMessageId(msg: string, context?: string): string;
2
-
3
- export { generateMessageId };
@@ -1,3 +0,0 @@
1
- declare function generateMessageId(msg: string, context?: string): string;
2
-
3
- export { generateMessageId };
@@ -1,11 +0,0 @@
1
- 'use strict';
2
-
3
- const node_crypto = require('node:crypto');
4
- const constants = require('./shared/message-utils.43a3d79e.cjs');
5
-
6
- const generateMessageId = (msg, context = "") => {
7
- const hash = node_crypto.createHash("sha256").update(msg + constants.UNIT_SEPARATOR + (context || "")).digest("base64");
8
- return hash.slice(0, 6);
9
- };
10
-
11
- exports.generateMessageId = generateMessageId;
@@ -1,3 +0,0 @@
1
- declare const generateMessageId: (msg: string, context?: string) => string;
2
-
3
- export { generateMessageId };
@@ -1,3 +0,0 @@
1
- declare const generateMessageId: (msg: string, context?: string) => string;
2
-
3
- export { generateMessageId };
@@ -1,5 +0,0 @@
1
- 'use strict';
2
-
3
- const UNIT_SEPARATOR = "";
4
-
5
- exports.UNIT_SEPARATOR = UNIT_SEPARATOR;
@@ -1,6 +0,0 @@
1
- /**
2
- * this file is a workaround for older runtimes
3
- * such as React Native or Jest 27 which is not
4
- * support package.json exports field
5
- **/
6
- module.exports = require("./dist/generateMessageId.cjs")