@messagevisor/core 0.0.1 → 0.1.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.
Files changed (211) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +7 -0
  4. package/jest.config.js +8 -0
  5. package/lib/benchmark/index.d.ts +2 -0
  6. package/lib/benchmark/index.js +417 -0
  7. package/lib/benchmark/index.js.map +1 -0
  8. package/lib/builder/index.d.ts +70 -0
  9. package/lib/builder/index.js +831 -0
  10. package/lib/builder/index.js.map +1 -0
  11. package/lib/cli/index.d.ts +28 -0
  12. package/lib/cli/index.js +182 -0
  13. package/lib/cli/index.js.map +1 -0
  14. package/lib/config/index.d.ts +61 -0
  15. package/lib/config/index.js +255 -0
  16. package/lib/config/index.js.map +1 -0
  17. package/lib/create/index.d.ts +2 -0
  18. package/lib/create/index.js +405 -0
  19. package/lib/create/index.js.map +1 -0
  20. package/lib/datasource/filesystemAdapter.d.ts +44 -0
  21. package/lib/datasource/filesystemAdapter.js +424 -0
  22. package/lib/datasource/filesystemAdapter.js.map +1 -0
  23. package/lib/datasource/index.d.ts +39 -0
  24. package/lib/datasource/index.js +96 -0
  25. package/lib/datasource/index.js.map +1 -0
  26. package/lib/error.d.ts +6 -0
  27. package/lib/error.js +49 -0
  28. package/lib/error.js.map +1 -0
  29. package/lib/evaluate/cli.d.ts +8 -0
  30. package/lib/evaluate/cli.js +179 -0
  31. package/lib/evaluate/cli.js.map +1 -0
  32. package/lib/evaluate/index.d.ts +10 -0
  33. package/lib/evaluate/index.js +131 -0
  34. package/lib/evaluate/index.js.map +1 -0
  35. package/lib/examples/coerceExampleIsoDates.d.ts +12 -0
  36. package/lib/examples/coerceExampleIsoDates.js +81 -0
  37. package/lib/examples/coerceExampleIsoDates.js.map +1 -0
  38. package/lib/examples/index.d.ts +63 -0
  39. package/lib/examples/index.js +713 -0
  40. package/lib/examples/index.js.map +1 -0
  41. package/lib/exporter/index.d.ts +60 -0
  42. package/lib/exporter/index.js +610 -0
  43. package/lib/exporter/index.js.map +1 -0
  44. package/lib/find-duplicates/index.d.ts +41 -0
  45. package/lib/find-duplicates/index.js +297 -0
  46. package/lib/find-duplicates/index.js.map +1 -0
  47. package/lib/generate-code/index.d.ts +11 -0
  48. package/lib/generate-code/index.js +157 -0
  49. package/lib/generate-code/index.js.map +1 -0
  50. package/lib/generate-code/typescript.d.ts +14 -0
  51. package/lib/generate-code/typescript.js +307 -0
  52. package/lib/generate-code/typescript.js.map +1 -0
  53. package/lib/importer/index.d.ts +64 -0
  54. package/lib/importer/index.js +1092 -0
  55. package/lib/importer/index.js.map +1 -0
  56. package/lib/index.d.ts +18 -0
  57. package/lib/index.js +35 -0
  58. package/lib/index.js.map +1 -0
  59. package/lib/info/index.d.ts +17 -0
  60. package/lib/info/index.js +132 -0
  61. package/lib/info/index.js.map +1 -0
  62. package/lib/init/index.d.ts +30 -0
  63. package/lib/init/index.js +348 -0
  64. package/lib/init/index.js.map +1 -0
  65. package/lib/lint/index.d.ts +1 -0
  66. package/lib/lint/index.js +6 -0
  67. package/lib/lint/index.js.map +1 -0
  68. package/lib/linter/attributeSchema.d.ts +7 -0
  69. package/lib/linter/attributeSchema.js +36 -0
  70. package/lib/linter/attributeSchema.js.map +1 -0
  71. package/lib/linter/checkLocaleCircularDependency.d.ts +7 -0
  72. package/lib/linter/checkLocaleCircularDependency.js +42 -0
  73. package/lib/linter/checkLocaleCircularDependency.js.map +1 -0
  74. package/lib/linter/conditionSchema.d.ts +3 -0
  75. package/lib/linter/conditionSchema.js +283 -0
  76. package/lib/linter/conditionSchema.js.map +1 -0
  77. package/lib/linter/formatSchema.d.ts +325 -0
  78. package/lib/linter/formatSchema.js +165 -0
  79. package/lib/linter/formatSchema.js.map +1 -0
  80. package/lib/linter/icuStyleLint.d.ts +6 -0
  81. package/lib/linter/icuStyleLint.js +226 -0
  82. package/lib/linter/icuStyleLint.js.map +1 -0
  83. package/lib/linter/index.d.ts +34 -0
  84. package/lib/linter/index.js +557 -0
  85. package/lib/linter/index.js.map +1 -0
  86. package/lib/linter/localeSchema.d.ts +672 -0
  87. package/lib/linter/localeSchema.js +50 -0
  88. package/lib/linter/localeSchema.js.map +1 -0
  89. package/lib/linter/messageSchema.d.ts +35 -0
  90. package/lib/linter/messageSchema.js +115 -0
  91. package/lib/linter/messageSchema.js.map +1 -0
  92. package/lib/linter/printError.d.ts +8 -0
  93. package/lib/linter/printError.js +41 -0
  94. package/lib/linter/printError.js.map +1 -0
  95. package/lib/linter/schema.d.ts +33 -0
  96. package/lib/linter/schema.js +192 -0
  97. package/lib/linter/schema.js.map +1 -0
  98. package/lib/linter/segmentSchema.d.ts +8 -0
  99. package/lib/linter/segmentSchema.js +18 -0
  100. package/lib/linter/segmentSchema.js.map +1 -0
  101. package/lib/linter/targetSchema.d.ts +337 -0
  102. package/lib/linter/targetSchema.js +39 -0
  103. package/lib/linter/targetSchema.js.map +1 -0
  104. package/lib/linter/testSchema.d.ts +71 -0
  105. package/lib/linter/testSchema.js +165 -0
  106. package/lib/linter/testSchema.js.map +1 -0
  107. package/lib/linter/zodHelpers.d.ts +2 -0
  108. package/lib/linter/zodHelpers.js +15 -0
  109. package/lib/linter/zodHelpers.js.map +1 -0
  110. package/lib/list/index.d.ts +8 -0
  111. package/lib/list/index.js +524 -0
  112. package/lib/list/index.js.map +1 -0
  113. package/lib/matrix.d.ts +4 -0
  114. package/lib/matrix.js +66 -0
  115. package/lib/matrix.js.map +1 -0
  116. package/lib/promoter/index.d.ts +65 -0
  117. package/lib/promoter/index.js +1208 -0
  118. package/lib/promoter/index.js.map +1 -0
  119. package/lib/prune/index.d.ts +37 -0
  120. package/lib/prune/index.js +673 -0
  121. package/lib/prune/index.js.map +1 -0
  122. package/lib/sets.d.ts +10 -0
  123. package/lib/sets.js +120 -0
  124. package/lib/sets.js.map +1 -0
  125. package/lib/tester/cliFormat.d.ts +8 -0
  126. package/lib/tester/cliFormat.js +15 -0
  127. package/lib/tester/cliFormat.js.map +1 -0
  128. package/lib/tester/index.d.ts +35 -0
  129. package/lib/tester/index.js +713 -0
  130. package/lib/tester/index.js.map +1 -0
  131. package/lib/tester/matrix.d.ts +14 -0
  132. package/lib/tester/matrix.js +76 -0
  133. package/lib/tester/matrix.js.map +1 -0
  134. package/lib/tester/prettyDuration.d.ts +1 -0
  135. package/lib/tester/prettyDuration.js +30 -0
  136. package/lib/tester/prettyDuration.js.map +1 -0
  137. package/lib/tester/printTestResult.d.ts +2 -0
  138. package/lib/tester/printTestResult.js +32 -0
  139. package/lib/tester/printTestResult.js.map +1 -0
  140. package/lib/tester/types.d.ts +29 -0
  141. package/lib/tester/types.js +3 -0
  142. package/lib/tester/types.js.map +1 -0
  143. package/package.json +41 -13
  144. package/src/benchmark/index.spec.ts +375 -0
  145. package/src/benchmark/index.ts +433 -0
  146. package/src/builder/index.spec.ts +822 -0
  147. package/src/builder/index.ts +920 -0
  148. package/src/cli/index.spec.ts +54 -0
  149. package/src/cli/index.ts +150 -0
  150. package/src/config/index.spec.ts +70 -0
  151. package/src/config/index.ts +259 -0
  152. package/src/create/index.spec.ts +272 -0
  153. package/src/create/index.ts +295 -0
  154. package/src/datasource/filesystemAdapter.ts +313 -0
  155. package/src/datasource/index.ts +135 -0
  156. package/src/error.ts +33 -0
  157. package/src/evaluate/cli.spec.ts +368 -0
  158. package/src/evaluate/cli.ts +130 -0
  159. package/src/evaluate/index.ts +161 -0
  160. package/src/examples/coerceExampleIsoDates.spec.ts +81 -0
  161. package/src/examples/coerceExampleIsoDates.ts +98 -0
  162. package/src/examples/index.spec.ts +453 -0
  163. package/src/examples/index.ts +854 -0
  164. package/src/exporter/index.spec.ts +443 -0
  165. package/src/exporter/index.ts +643 -0
  166. package/src/find-duplicates/index.spec.ts +289 -0
  167. package/src/find-duplicates/index.ts +314 -0
  168. package/src/generate-code/index.ts +92 -0
  169. package/src/generate-code/typescript.spec.ts +241 -0
  170. package/src/generate-code/typescript.ts +284 -0
  171. package/src/importer/index.spec.ts +1101 -0
  172. package/src/importer/index.ts +1190 -0
  173. package/src/index.ts +18 -0
  174. package/src/info/index.ts +67 -0
  175. package/src/init/index.spec.ts +279 -0
  176. package/src/init/index.ts +292 -0
  177. package/src/lint/index.ts +1 -0
  178. package/src/linter/attributeSchema.ts +38 -0
  179. package/src/linter/checkLocaleCircularDependency.ts +51 -0
  180. package/src/linter/conditionSchema.ts +386 -0
  181. package/src/linter/formatSchema.ts +170 -0
  182. package/src/linter/icuStyleLint.ts +312 -0
  183. package/src/linter/index.spec.ts +824 -0
  184. package/src/linter/index.ts +460 -0
  185. package/src/linter/localeSchema.ts +70 -0
  186. package/src/linter/messageSchema.ts +152 -0
  187. package/src/linter/printError.ts +52 -0
  188. package/src/linter/schema.ts +230 -0
  189. package/src/linter/segmentSchema.ts +15 -0
  190. package/src/linter/targetSchema.ts +50 -0
  191. package/src/linter/testSchema.spec.ts +405 -0
  192. package/src/linter/testSchema.ts +239 -0
  193. package/src/linter/zodHelpers.ts +16 -0
  194. package/src/list/index.spec.ts +431 -0
  195. package/src/list/index.ts +463 -0
  196. package/src/matrix.ts +69 -0
  197. package/src/promoter/index.spec.ts +584 -0
  198. package/src/promoter/index.ts +1267 -0
  199. package/src/prune/index.spec.ts +418 -0
  200. package/src/prune/index.ts +693 -0
  201. package/src/sets.ts +74 -0
  202. package/src/tester/cliFormat.ts +11 -0
  203. package/src/tester/featurevisorIntegration.spec.ts +101 -0
  204. package/src/tester/index.spec.ts +577 -0
  205. package/src/tester/index.ts +679 -0
  206. package/src/tester/matrix.ts +106 -0
  207. package/src/tester/prettyDuration.ts +34 -0
  208. package/src/tester/printTestResult.ts +40 -0
  209. package/src/tester/types.ts +32 -0
  210. package/tsconfig.cjs.json +11 -0
  211. package/tsconfig.typecheck.json +4 -0
@@ -0,0 +1,433 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import { performance } from "perf_hooks";
3
+
4
+ import { createMessagevisor } from "@messagevisor/sdk";
5
+ import type {
6
+ Condition,
7
+ Context,
8
+ DatafileContent,
9
+ FormatPresets,
10
+ GroupSegment,
11
+ Locale,
12
+ Target,
13
+ } from "@messagevisor/types";
14
+
15
+ import { buildDatafile, buildMessageDatafile, resolveFormats } from "../builder";
16
+ import type { Plugin } from "../cli";
17
+ import type { Datasource } from "../datasource";
18
+ import { MessagevisorCLIError, printMessagevisorCLIError } from "../error";
19
+ import { getProjectSetExecutions } from "../sets";
20
+
21
+ function parseJsonOption(optionName: string, value: string) {
22
+ try {
23
+ return JSON.parse(value);
24
+ } catch (error) {
25
+ throw new MessagevisorCLIError(`Invalid ${optionName}: expected valid JSON`);
26
+ }
27
+ }
28
+
29
+ function parseIterationCount(value: unknown) {
30
+ const parsed = parseInt(String(value || ""), 10);
31
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
32
+ }
33
+
34
+ function formatDuration(duration: number) {
35
+ return `${duration.toFixed(3)}ms`;
36
+ }
37
+
38
+ function parseStructuredString(value: string): unknown {
39
+ if (!(value.startsWith("{") || value.startsWith("["))) {
40
+ return value;
41
+ }
42
+
43
+ try {
44
+ return JSON.parse(value);
45
+ } catch {
46
+ return value;
47
+ }
48
+ }
49
+
50
+ interface BenchmarkResult {
51
+ value: unknown;
52
+ minDuration: number;
53
+ medianDuration: number;
54
+ maxDuration: number;
55
+ averageDuration: number;
56
+ totalDuration: number;
57
+ iterations: number;
58
+ }
59
+
60
+ interface BenchmarkDatafileCounts {
61
+ messages: number;
62
+ segments: number;
63
+ attributes: number;
64
+ }
65
+
66
+ interface BenchmarkSetup {
67
+ messagevisor: ReturnType<typeof createMessagevisor>;
68
+ datafileCounts: BenchmarkDatafileCounts;
69
+ }
70
+
71
+ function getMedian(values: number[]) {
72
+ if (values.length === 0) {
73
+ return 0;
74
+ }
75
+
76
+ const sorted = [...values].sort((left, right) => left - right);
77
+ const middle = Math.floor(sorted.length / 2);
78
+
79
+ if (sorted.length % 2 === 1) {
80
+ return sorted[middle];
81
+ }
82
+
83
+ return (sorted[middle - 1] + sorted[middle]) / 2;
84
+ }
85
+
86
+ function benchmarkIterations(run: () => unknown, iterations: number): BenchmarkResult {
87
+ let minDuration = Number.POSITIVE_INFINITY;
88
+ let maxDuration = 0;
89
+ let totalDuration = 0;
90
+ let value: unknown;
91
+ const durations: number[] = [];
92
+
93
+ for (let index = 0; index < iterations; index++) {
94
+ const start = performance.now();
95
+ value = run();
96
+ const duration = performance.now() - start;
97
+
98
+ minDuration = Math.min(minDuration, duration);
99
+ maxDuration = Math.max(maxDuration, duration);
100
+ totalDuration += duration;
101
+ durations.push(duration);
102
+ }
103
+
104
+ return {
105
+ value,
106
+ minDuration: Number.isFinite(minDuration) ? minDuration : 0,
107
+ medianDuration: getMedian(durations),
108
+ maxDuration,
109
+ averageDuration: totalDuration / iterations,
110
+ totalDuration,
111
+ iterations,
112
+ };
113
+ }
114
+
115
+ function collectAttributeKeysFromCondition(
116
+ condition: Condition | Condition[] | "*" | undefined,
117
+ result: Set<string>,
118
+ segments: DatafileContent["segments"],
119
+ seenSegments: Set<string>,
120
+ ): void {
121
+ if (!condition || condition === "*") {
122
+ return;
123
+ }
124
+
125
+ if (Array.isArray(condition)) {
126
+ for (const item of condition) {
127
+ collectAttributeKeysFromCondition(item, result, segments, seenSegments);
128
+ }
129
+ return;
130
+ }
131
+
132
+ if (typeof condition === "string") {
133
+ const parsedCondition = parseStructuredString(condition);
134
+
135
+ if (parsedCondition !== condition) {
136
+ collectAttributeKeysFromCondition(
137
+ parsedCondition as Condition | Condition[],
138
+ result,
139
+ segments,
140
+ seenSegments,
141
+ );
142
+ return;
143
+ }
144
+
145
+ collectAttributeKeysFromGroupSegment(condition, result, segments, seenSegments);
146
+ return;
147
+ }
148
+
149
+ if ("attribute" in condition) {
150
+ result.add(condition.attribute);
151
+ return;
152
+ }
153
+
154
+ if ("and" in condition) {
155
+ collectAttributeKeysFromCondition(condition.and, result, segments, seenSegments);
156
+ return;
157
+ }
158
+
159
+ if ("or" in condition) {
160
+ collectAttributeKeysFromCondition(condition.or, result, segments, seenSegments);
161
+ return;
162
+ }
163
+
164
+ if ("not" in condition) {
165
+ collectAttributeKeysFromCondition(condition.not, result, segments, seenSegments);
166
+ }
167
+ }
168
+
169
+ function collectAttributeKeysFromGroupSegment(
170
+ groupSegment: GroupSegment | GroupSegment[] | "*" | undefined,
171
+ result: Set<string>,
172
+ segments: DatafileContent["segments"],
173
+ seenSegments: Set<string>,
174
+ ): void {
175
+ if (!groupSegment || groupSegment === "*") {
176
+ return;
177
+ }
178
+
179
+ if (Array.isArray(groupSegment)) {
180
+ for (const item of groupSegment) {
181
+ collectAttributeKeysFromGroupSegment(item, result, segments, seenSegments);
182
+ }
183
+ return;
184
+ }
185
+
186
+ if (typeof groupSegment === "string") {
187
+ const parsedGroupSegment = parseStructuredString(groupSegment);
188
+
189
+ if (parsedGroupSegment !== groupSegment) {
190
+ collectAttributeKeysFromGroupSegment(
191
+ parsedGroupSegment as GroupSegment | GroupSegment[],
192
+ result,
193
+ segments,
194
+ seenSegments,
195
+ );
196
+ return;
197
+ }
198
+
199
+ if (seenSegments.has(groupSegment)) {
200
+ return;
201
+ }
202
+
203
+ seenSegments.add(groupSegment);
204
+ const segment = segments[groupSegment];
205
+
206
+ if (segment) {
207
+ collectAttributeKeysFromCondition(segment.conditions, result, segments, seenSegments);
208
+ }
209
+ return;
210
+ }
211
+
212
+ if ("and" in groupSegment) {
213
+ collectAttributeKeysFromGroupSegment(groupSegment.and, result, segments, seenSegments);
214
+ return;
215
+ }
216
+
217
+ if ("or" in groupSegment) {
218
+ collectAttributeKeysFromGroupSegment(groupSegment.or, result, segments, seenSegments);
219
+ return;
220
+ }
221
+
222
+ if ("not" in groupSegment) {
223
+ collectAttributeKeysFromGroupSegment(groupSegment.not, result, segments, seenSegments);
224
+ }
225
+ }
226
+
227
+ function getDatafileCounts(datafile?: DatafileContent): BenchmarkDatafileCounts {
228
+ if (!datafile) {
229
+ return {
230
+ messages: 0,
231
+ segments: 0,
232
+ attributes: 0,
233
+ };
234
+ }
235
+
236
+ const attributeKeys = new Set<string>();
237
+ const seenSegments = new Set<string>();
238
+
239
+ for (const segmentKey of Object.keys(datafile.segments)) {
240
+ collectAttributeKeysFromGroupSegment(
241
+ segmentKey,
242
+ attributeKeys,
243
+ datafile.segments,
244
+ seenSegments,
245
+ );
246
+ }
247
+
248
+ return {
249
+ messages: Object.keys(datafile.translations).length,
250
+ segments: Object.keys(datafile.segments).length,
251
+ attributes: attributeKeys.size,
252
+ };
253
+ }
254
+
255
+ async function readLocales(datasource: Datasource) {
256
+ const localeKeys = await datasource.listLocales();
257
+ const locales = await Promise.all(
258
+ localeKeys.map(
259
+ async (localeKey) => [localeKey, (await datasource.readLocale(localeKey)) as Locale] as const,
260
+ ),
261
+ );
262
+
263
+ return Object.fromEntries(locales) as Record<string, Locale>;
264
+ }
265
+
266
+ async function resolveBenchmarkFormats(
267
+ datasource: Datasource,
268
+ locale: string,
269
+ targetKey?: string,
270
+ ): Promise<FormatPresets | undefined> {
271
+ const locales = await readLocales(datasource);
272
+ const target = targetKey ? ((await datasource.readTarget(targetKey)) as Target) : undefined;
273
+
274
+ return resolveFormats(locale, locales, target);
275
+ }
276
+
277
+ async function createBenchmarkMessagevisor(options: {
278
+ projectConfig: any;
279
+ datasource: Datasource;
280
+ locale: string;
281
+ context: Context;
282
+ target?: string;
283
+ revision: string;
284
+ message?: string;
285
+ }): Promise<BenchmarkSetup> {
286
+ const { projectConfig, datasource, locale, context, target, revision, message } = options;
287
+ let datafile: DatafileContent | undefined;
288
+ let defaultFormatsByLocale: Record<string, FormatPresets | undefined> | undefined;
289
+
290
+ if (message) {
291
+ datafile = target
292
+ ? await buildDatafile(projectConfig, datasource, target, locale, revision)
293
+ : await buildMessageDatafile(projectConfig, datasource, message, locale, revision);
294
+ } else if (target) {
295
+ datafile = await buildDatafile(projectConfig, datasource, target, locale, revision);
296
+ } else {
297
+ defaultFormatsByLocale = {
298
+ [locale]: await resolveBenchmarkFormats(datasource, locale, target),
299
+ };
300
+ }
301
+
302
+ return {
303
+ messagevisor: createMessagevisor({
304
+ datafile,
305
+ defaultFormats: defaultFormatsByLocale,
306
+ locale,
307
+ context,
308
+ modules: projectConfig.modules || [],
309
+ logLevel: "warn",
310
+ }),
311
+ datafileCounts: getDatafileCounts(datafile),
312
+ };
313
+ }
314
+
315
+ function printBenchmarkSummary(
316
+ target: string,
317
+ locale: string,
318
+ datafileCounts: BenchmarkDatafileCounts,
319
+ result: BenchmarkResult,
320
+ ) {
321
+ console.log("");
322
+ console.log(`Benchmark target : ${target}`);
323
+ console.log(`Iterations : ${result.iterations}`);
324
+ console.log(
325
+ `Datafile : ${datafileCounts.messages} messages, ${datafileCounts.segments} segments, ${datafileCounts.attributes} attributes`,
326
+ );
327
+ console.log(`Locale : ${locale}`);
328
+ console.log(`Evaluated value : ${JSON.stringify(result.value)}`);
329
+ console.log(`Total duration : ${formatDuration(result.totalDuration)}`);
330
+ console.log(`Min duration : ${formatDuration(result.minDuration)}`);
331
+ console.log(`Median duration : ${formatDuration(result.medianDuration)}`);
332
+ console.log(`Max duration : ${formatDuration(result.maxDuration)}`);
333
+ console.log(`Average duration : ${formatDuration(result.averageDuration)}`);
334
+ }
335
+
336
+ export const benchmarkPlugin: Plugin = {
337
+ command: "benchmark",
338
+ handler: async ({ projectConfig, datasource, parsed }: any) => {
339
+ try {
340
+ if (projectConfig.sets && !parsed.set) {
341
+ throw new MessagevisorCLIError("Pass --set=<set>");
342
+ }
343
+
344
+ if (projectConfig.sets) {
345
+ const [execution] = await getProjectSetExecutions(projectConfig, datasource, parsed.set);
346
+ projectConfig = execution.projectConfig;
347
+ datasource = execution.datasource;
348
+ }
349
+
350
+ if (parsed.message && parsed.rawMessage) {
351
+ throw new MessagevisorCLIError(
352
+ "Pass either --message=<key> or --rawMessage=<message>, not both",
353
+ );
354
+ }
355
+
356
+ if (!parsed.message && !parsed.rawMessage) {
357
+ throw new MessagevisorCLIError("Pass --message=<key> or --rawMessage=<message>");
358
+ }
359
+
360
+ if (!parsed.locale) {
361
+ throw new MessagevisorCLIError("Pass --locale=<locale>");
362
+ }
363
+
364
+ const target = parsed.target;
365
+ const locale = parsed.locale;
366
+ const iterations = parseIterationCount(parsed.n);
367
+ const context = parsed.context ? parseJsonOption("--context", parsed.context) : {};
368
+ const values = parsed.values ? parseJsonOption("--values", parsed.values) : undefined;
369
+ const revision = await datasource.readRevision();
370
+ const benchmarkSetup = await createBenchmarkMessagevisor({
371
+ projectConfig,
372
+ datasource,
373
+ locale,
374
+ context,
375
+ target,
376
+ revision,
377
+ message: parsed.message,
378
+ });
379
+ const { messagevisor, datafileCounts } = benchmarkSetup;
380
+
381
+ const result = parsed.message
382
+ ? benchmarkIterations(
383
+ () => messagevisor.translate(parsed.message, values, { context }),
384
+ iterations,
385
+ )
386
+ : benchmarkIterations(
387
+ () => messagevisor.formatMessage(parsed.rawMessage, values),
388
+ iterations,
389
+ );
390
+
391
+ const output = {
392
+ target: target || null,
393
+ locale,
394
+ context,
395
+ values,
396
+ message: parsed.message || undefined,
397
+ rawMessage: parsed.rawMessage || undefined,
398
+ datafileCounts,
399
+ ...result,
400
+ };
401
+
402
+ if (parsed.json) {
403
+ console.log(parsed.pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output));
404
+ return;
405
+ }
406
+
407
+ printBenchmarkSummary(parsed.message || parsed.rawMessage, locale, datafileCounts, result);
408
+ } catch (error) {
409
+ if (printMessagevisorCLIError(error)) {
410
+ return false;
411
+ }
412
+
413
+ throw error;
414
+ }
415
+ },
416
+ examples: [
417
+ {
418
+ command:
419
+ 'benchmark --message=auth.signin --locale=en-US --context=\'{"plan":"pro"}\' -n=1000',
420
+ description: "benchmark a keyed message evaluation",
421
+ },
422
+ {
423
+ command:
424
+ 'benchmark --message=dashboard.welcome --target=web --locale=en-US --values=\'{"name":"Ada"}\' -n=1000',
425
+ description: "benchmark a target-specific keyed message evaluation with values",
426
+ },
427
+ {
428
+ command:
429
+ 'benchmark --rawMessage="Hello {name}" --locale=en-US --values=\'{"name":"Ada"}\' -n=1000',
430
+ description: "benchmark a raw message evaluation",
431
+ },
432
+ ],
433
+ };