@messagevisor/catalog 0.0.1 → 0.2.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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -0
  3. package/dist/assets/index-BoO0zn_O.js +73 -0
  4. package/dist/assets/index-Cn0qFwkD.css +1 -0
  5. package/dist/favicon.png +0 -0
  6. package/dist/index.html +14 -0
  7. package/dist/logo-text.png +0 -0
  8. package/lib/index.d.ts +1 -0
  9. package/lib/index.js +18 -0
  10. package/lib/index.js.map +1 -0
  11. package/lib/node/formatExamplePreview.d.ts +10 -0
  12. package/lib/node/formatExamplePreview.js +79 -0
  13. package/lib/node/formatExamplePreview.js.map +1 -0
  14. package/lib/node/index.d.ts +191 -0
  15. package/lib/node/index.js +1755 -0
  16. package/lib/node/index.js.map +1 -0
  17. package/package.json +59 -13
  18. package/src/App.tsx +73 -0
  19. package/src/api.spec.ts +42 -0
  20. package/src/api.ts +87 -0
  21. package/src/catalogBrandAssets.ts +8 -0
  22. package/src/components/details/ConditionTree.tsx +146 -0
  23. package/src/components/details/FieldGrid.tsx +16 -0
  24. package/src/components/details/GroupSegmentTree.tsx +73 -0
  25. package/src/components/details/MarkdownContent.tsx +23 -0
  26. package/src/components/details/TranslationsTable.tsx +263 -0
  27. package/src/components/details/UsageLinks.tsx +29 -0
  28. package/src/components/history/HistoryTimeline.tsx +122 -0
  29. package/src/components/layout/AppShell.tsx +338 -0
  30. package/src/components/layout/PageHeader.tsx +13 -0
  31. package/src/components/layout/Tabs.tsx +35 -0
  32. package/src/components/lists/EntityList.tsx +451 -0
  33. package/src/components/ui/Badge.tsx +21 -0
  34. package/src/components/ui/Button.tsx +12 -0
  35. package/src/components/ui/Card.tsx +9 -0
  36. package/src/components/ui/CodeBlock.tsx +7 -0
  37. package/src/components/ui/EmptyState.tsx +8 -0
  38. package/src/components/ui/Input.tsx +12 -0
  39. package/src/components/ui/LabelValueBadge.tsx +55 -0
  40. package/src/config.ts +2 -0
  41. package/src/context/CatalogContext.tsx +50 -0
  42. package/src/entityTypes.ts +49 -0
  43. package/src/index.ts +1 -0
  44. package/src/main.tsx +28 -0
  45. package/src/node/formatExamplePreview.ts +85 -0
  46. package/src/node/index.spec.ts +935 -0
  47. package/src/node/index.ts +2151 -0
  48. package/src/pages/EntityDetailPage.tsx +3345 -0
  49. package/src/pages/HistoryPage.tsx +26 -0
  50. package/src/pages/HomePage.tsx +21 -0
  51. package/src/pages/ListPage.tsx +59 -0
  52. package/src/styles.css +95 -0
  53. package/src/theme.ts +36 -0
  54. package/src/types.ts +127 -0
  55. package/src/utils/formatCatalogTimestamp.ts +77 -0
  56. package/src/utils/hashTranslationValue.spec.ts +20 -0
  57. package/src/utils/hashTranslationValue.ts +22 -0
  58. package/src/utils/searchQuery.ts +46 -0
@@ -0,0 +1,1755 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
47
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
48
+ return new (P || (P = Promise))(function (resolve, reject) {
49
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
50
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
51
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
52
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
53
+ });
54
+ };
55
+ var __generator = (this && this.__generator) || function (thisArg, body) {
56
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
57
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
58
+ function verb(n) { return function (v) { return step([n, v]); }; }
59
+ function step(op) {
60
+ if (f) throw new TypeError("Generator is already executing.");
61
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
62
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
63
+ if (y = 0, t) op = [op[0] & 2, t.value];
64
+ switch (op[0]) {
65
+ case 0: case 1: t = op; break;
66
+ case 4: _.label++; return { value: op[1], done: false };
67
+ case 5: _.label++; y = op[1]; op = [0]; continue;
68
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
69
+ default:
70
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
71
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
72
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
73
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
74
+ if (t[2]) _.ops.pop();
75
+ _.trys.pop(); continue;
76
+ }
77
+ op = body.call(thisArg, _);
78
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
79
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
80
+ }
81
+ };
82
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
83
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
84
+ if (ar || !(i in from)) {
85
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
86
+ ar[i] = from[i];
87
+ }
88
+ }
89
+ return to.concat(ar || Array.prototype.slice.call(from));
90
+ };
91
+ Object.defineProperty(exports, "__esModule", { value: true });
92
+ exports.CATALOG_HISTORY_PAGE_SIZE = exports.CATALOG_SCHEMA_VERSION = void 0;
93
+ exports.exportCatalog = exportCatalog;
94
+ exports.serveCatalog = serveCatalog;
95
+ exports.createCatalogApi = createCatalogApi;
96
+ exports.createCatalogPlugin = createCatalogPlugin;
97
+ /* eslint-disable @typescript-eslint/no-unused-vars */
98
+ var childProcess = __importStar(require("child_process"));
99
+ var fs = __importStar(require("fs"));
100
+ var http = __importStar(require("http"));
101
+ var path = __importStar(require("path"));
102
+ var formatExamplePreview_1 = require("./formatExamplePreview");
103
+ exports.CATALOG_SCHEMA_VERSION = "1";
104
+ exports.CATALOG_HISTORY_PAGE_SIZE = 50;
105
+ function toPosixPath(value) {
106
+ return value.split(path.sep).join("/");
107
+ }
108
+ function getRealPath(value) {
109
+ try {
110
+ return fs.realpathSync.native(value);
111
+ }
112
+ catch (_error) {
113
+ return value;
114
+ }
115
+ }
116
+ function encodeKey(key) {
117
+ return encodeURIComponent(key);
118
+ }
119
+ function matchesPattern(key, patterns) {
120
+ if (!patterns || patterns.length === 0) {
121
+ return false;
122
+ }
123
+ return patterns.some(function (pattern) {
124
+ var escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
125
+ return new RegExp("^".concat(escaped, "$")).test(key);
126
+ });
127
+ }
128
+ function readAll(keys, read) {
129
+ return __awaiter(this, void 0, void 0, function () {
130
+ var result, _i, keys_1, key, _a, _b;
131
+ return __generator(this, function (_c) {
132
+ switch (_c.label) {
133
+ case 0:
134
+ result = {};
135
+ _i = 0, keys_1 = keys;
136
+ _c.label = 1;
137
+ case 1:
138
+ if (!(_i < keys_1.length)) return [3 /*break*/, 4];
139
+ key = keys_1[_i];
140
+ _a = result;
141
+ _b = key;
142
+ return [4 /*yield*/, read(key)];
143
+ case 2:
144
+ _a[_b] = _c.sent();
145
+ _c.label = 3;
146
+ case 3:
147
+ _i++;
148
+ return [3 /*break*/, 1];
149
+ case 4: return [2 /*return*/, result];
150
+ }
151
+ });
152
+ });
153
+ }
154
+ function sortStrings(values) {
155
+ return Array.from(new Set(values)).sort();
156
+ }
157
+ function deepClone(value) {
158
+ return JSON.parse(JSON.stringify(value));
159
+ }
160
+ function getLocaleDirections(locales) {
161
+ return Object.fromEntries(Object.entries(locales).map(function (_a) {
162
+ var localeKey = _a[0], locale = _a[1];
163
+ return [localeKey, locale.direction];
164
+ }));
165
+ }
166
+ function collectAttributeKeysFromConditions(condition, result) {
167
+ if (!condition || condition === "*") {
168
+ return;
169
+ }
170
+ if (Array.isArray(condition)) {
171
+ for (var _i = 0, condition_1 = condition; _i < condition_1.length; _i++) {
172
+ var item = condition_1[_i];
173
+ collectAttributeKeysFromConditions(item, result);
174
+ }
175
+ return;
176
+ }
177
+ if (typeof condition === "string") {
178
+ return;
179
+ }
180
+ if ("attribute" in condition) {
181
+ result.add(condition.attribute);
182
+ return;
183
+ }
184
+ if ("and" in condition) {
185
+ collectAttributeKeysFromConditions(condition.and, result);
186
+ }
187
+ if ("or" in condition) {
188
+ collectAttributeKeysFromConditions(condition.or, result);
189
+ }
190
+ if ("not" in condition) {
191
+ collectAttributeKeysFromConditions(condition.not, result);
192
+ }
193
+ }
194
+ function collectSegmentKeys(segments, result) {
195
+ if (!segments || segments === "*") {
196
+ return;
197
+ }
198
+ if (typeof segments === "string") {
199
+ result.add(segments);
200
+ return;
201
+ }
202
+ if (Array.isArray(segments)) {
203
+ for (var _i = 0, segments_1 = segments; _i < segments_1.length; _i++) {
204
+ var segment = segments_1[_i];
205
+ collectSegmentKeys(segment, result);
206
+ }
207
+ return;
208
+ }
209
+ if ("and" in segments) {
210
+ collectSegmentKeys(segments.and, result);
211
+ }
212
+ if ("or" in segments) {
213
+ collectSegmentKeys(segments.or, result);
214
+ }
215
+ if ("not" in segments) {
216
+ collectSegmentKeys(segments.not, result);
217
+ }
218
+ }
219
+ function getTargetMessageKeys(target, messageKeys) {
220
+ var _a;
221
+ var includeMessages = ((_a = target.includeMessages) === null || _a === void 0 ? void 0 : _a.length) ? target.includeMessages : ["*"];
222
+ var excludeMessages = target.excludeMessages || [];
223
+ return messageKeys
224
+ .filter(function (messageKey) {
225
+ return matchesPattern(messageKey, includeMessages) && !matchesPattern(messageKey, excludeMessages);
226
+ })
227
+ .sort();
228
+ }
229
+ function getHistoryEntityKey(type, key, set) {
230
+ return "".concat(set || "", "\u001F").concat(type, "\u001F").concat(key);
231
+ }
232
+ function toLastModified(entry) {
233
+ return {
234
+ commit: entry.commit,
235
+ author: entry.author,
236
+ timestamp: entry.timestamp,
237
+ };
238
+ }
239
+ function getLastModified(historyIndex, type, key, set) {
240
+ return historyIndex.lastModifiedByEntity[getHistoryEntityKey(type, key, set)];
241
+ }
242
+ function getEntitySummary(entity, type, key, historyIndex, set, extra) {
243
+ if (extra === void 0) { extra = {}; }
244
+ return __assign(__assign({ key: key, description: entity.description, archived: entity.archived, deprecated: entity.deprecated }, extra), { lastModified: getLastModified(historyIndex, type, key, set), href: "entities/".concat(type, "/").concat(encodeKey(key), ".json") });
245
+ }
246
+ function getPathValue(value, segments) {
247
+ var current = value;
248
+ for (var _i = 0, segments_2 = segments; _i < segments_2.length; _i++) {
249
+ var segment = segments_2[_i];
250
+ if (!current || typeof current !== "object" || !(segment in current)) {
251
+ return undefined;
252
+ }
253
+ current = current[segment];
254
+ }
255
+ return current;
256
+ }
257
+ function flattenObjectRows(value, prefix) {
258
+ if (prefix === void 0) { prefix = ""; }
259
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
260
+ return prefix ? [{ path: prefix, value: value }] : [];
261
+ }
262
+ var rows = [];
263
+ for (var _i = 0, _a = Object.keys(value).sort(); _i < _a.length; _i++) {
264
+ var key = _a[_i];
265
+ var childPath = prefix ? "".concat(prefix, ".").concat(key) : key;
266
+ var childValue = value[key];
267
+ if (childValue && typeof childValue === "object" && !Array.isArray(childValue)) {
268
+ rows.push.apply(rows, flattenObjectRows(childValue, childPath));
269
+ }
270
+ else {
271
+ rows.push({ path: childPath, value: childValue });
272
+ }
273
+ }
274
+ return rows;
275
+ }
276
+ function resolveLocaleChain(localeKey, locales, field) {
277
+ var _a;
278
+ var chain = [];
279
+ var seen = new Set();
280
+ var currentKey = localeKey;
281
+ while (currentKey && !seen.has(currentKey)) {
282
+ seen.add(currentKey);
283
+ chain.unshift(currentKey);
284
+ currentKey = (_a = locales[currentKey]) === null || _a === void 0 ? void 0 : _a[field];
285
+ }
286
+ return chain;
287
+ }
288
+ function getLocaleFormatSource(localeKey, locales, formatPath) {
289
+ var _a, _b;
290
+ var pathSegments = formatPath.split(".");
291
+ if (typeof getPathValue((_a = locales[localeKey]) === null || _a === void 0 ? void 0 : _a.formats, pathSegments) !== "undefined") {
292
+ return { source: "direct" };
293
+ }
294
+ var chain = resolveLocaleChain(localeKey, locales, "inheritFormatsFrom").reverse();
295
+ for (var _i = 0, chain_1 = chain; _i < chain_1.length; _i++) {
296
+ var candidate = chain_1[_i];
297
+ if (candidate !== localeKey &&
298
+ typeof getPathValue((_b = locales[candidate]) === null || _b === void 0 ? void 0 : _b.formats, pathSegments) !== "undefined") {
299
+ return { source: "inherited", from: candidate };
300
+ }
301
+ }
302
+ return { source: "missing" };
303
+ }
304
+ function getFormatRows(runtime, localeKey, locales, target) {
305
+ var computedFormats = runtime.resolveFormats(localeKey, locales, target) || {};
306
+ var rows = flattenObjectRows(computedFormats).map(function (row) {
307
+ var _a;
308
+ if (target &&
309
+ typeof getPathValue((_a = target.formats) === null || _a === void 0 ? void 0 : _a[localeKey], row.path.split(".")) !== "undefined") {
310
+ return __assign(__assign({}, row), { source: "target", from: "target" });
311
+ }
312
+ return __assign(__assign({}, row), getLocaleFormatSource(localeKey, locales, row.path));
313
+ });
314
+ return (0, formatExamplePreview_1.attachFormatExamplePreviews)(localeKey, computedFormats, rows);
315
+ }
316
+ function resolveTranslationRow(translations, localeKey, locales) {
317
+ if (typeof (translations === null || translations === void 0 ? void 0 : translations[localeKey]) !== "undefined") {
318
+ return {
319
+ locale: localeKey,
320
+ value: translations[localeKey],
321
+ source: "direct",
322
+ };
323
+ }
324
+ var chain = resolveLocaleChain(localeKey, locales, "inheritTranslationsFrom").reverse();
325
+ for (var _i = 0, chain_2 = chain; _i < chain_2.length; _i++) {
326
+ var candidate = chain_2[_i];
327
+ if (candidate !== localeKey && typeof (translations === null || translations === void 0 ? void 0 : translations[candidate]) !== "undefined") {
328
+ return {
329
+ locale: localeKey,
330
+ value: translations[candidate],
331
+ source: "inherited",
332
+ from: candidate,
333
+ };
334
+ }
335
+ }
336
+ return {
337
+ locale: localeKey,
338
+ value: "",
339
+ source: "missing",
340
+ };
341
+ }
342
+ function getDuplicateSetKey(set) {
343
+ return set || "root";
344
+ }
345
+ function toLocaleDuplicatesFile(localeKey, duplicatesByLocale) {
346
+ var _a;
347
+ var duplicateValues = ((_a = duplicatesByLocale[localeKey]) === null || _a === void 0 ? void 0 : _a.duplicateValues) || [];
348
+ return {
349
+ locale: localeKey,
350
+ summary: {
351
+ duplicateValues: duplicateValues.length,
352
+ duplicateMessageKeys: duplicateValues.reduce(function (sum, duplicate) { return sum + duplicate.messageKeys.length; }, 0),
353
+ },
354
+ duplicateValues: duplicateValues,
355
+ };
356
+ }
357
+ function writeJson(filePath, content) {
358
+ return __awaiter(this, void 0, void 0, function () {
359
+ return __generator(this, function (_a) {
360
+ switch (_a.label) {
361
+ case 0: return [4 /*yield*/, fs.promises.mkdir(path.dirname(filePath), { recursive: true })];
362
+ case 1:
363
+ _a.sent();
364
+ return [4 /*yield*/, fs.promises.writeFile(filePath, JSON.stringify(content, null, 2))];
365
+ case 2:
366
+ _a.sent();
367
+ return [2 /*return*/];
368
+ }
369
+ });
370
+ });
371
+ }
372
+ function getEntityDirectoryPaths(config) {
373
+ return {
374
+ locale: config.localesDirectoryPath,
375
+ message: config.messagesDirectoryPath,
376
+ attribute: config.attributesDirectoryPath,
377
+ segment: config.segmentsDirectoryPath,
378
+ target: config.targetsDirectoryPath,
379
+ test: config.testsDirectoryPath,
380
+ };
381
+ }
382
+ function getKeyFromRelativeEntityPath(relativePath, extension, namespaceCharacter) {
383
+ var withoutExtension = relativePath.slice(0, -extension.length);
384
+ var parts = withoutExtension.split(path.sep);
385
+ var last = parts[parts.length - 1];
386
+ if (last.endsWith(".spec")) {
387
+ parts[parts.length - 1] = last.slice(0, -".spec".length);
388
+ }
389
+ return parts.join(namespaceCharacter);
390
+ }
391
+ function getEntityInfoFromRelativePath(rootDirectoryPath, projectConfig, relativePath) {
392
+ var absolutePath = path.join(rootDirectoryPath, relativePath);
393
+ var extension = ".".concat(projectConfig.parser.extension);
394
+ var configs = projectConfig.sets
395
+ ? fs.existsSync(projectConfig.setsDirectoryPath)
396
+ ? fs
397
+ .readdirSync(projectConfig.setsDirectoryPath, { withFileTypes: true })
398
+ .filter(function (entry) { return entry.isDirectory(); })
399
+ .map(function (entry) { return ({
400
+ set: entry.name,
401
+ directories: getEntityDirectoryPaths(__assign(__assign({}, projectConfig), { localesDirectoryPath: path.join(projectConfig.setsDirectoryPath, entry.name, "locales"), messagesDirectoryPath: path.join(projectConfig.setsDirectoryPath, entry.name, "messages"), attributesDirectoryPath: path.join(projectConfig.setsDirectoryPath, entry.name, "attributes"), segmentsDirectoryPath: path.join(projectConfig.setsDirectoryPath, entry.name, "segments"), targetsDirectoryPath: path.join(projectConfig.setsDirectoryPath, entry.name, "targets"), testsDirectoryPath: path.join(projectConfig.setsDirectoryPath, entry.name, "tests") })),
402
+ }); })
403
+ : []
404
+ : [{ set: undefined, directories: getEntityDirectoryPaths(projectConfig) }];
405
+ for (var _i = 0, configs_1 = configs; _i < configs_1.length; _i++) {
406
+ var config = configs_1[_i];
407
+ for (var _a = 0, _b = Object.keys(config.directories); _a < _b.length; _a++) {
408
+ var type = _b[_a];
409
+ var directoryPath = config.directories[type];
410
+ if (absolutePath === directoryPath ||
411
+ !absolutePath.startsWith("".concat(directoryPath).concat(path.sep)) ||
412
+ !absolutePath.endsWith(extension)) {
413
+ continue;
414
+ }
415
+ return {
416
+ type: type,
417
+ key: getKeyFromRelativeEntityPath(path.relative(directoryPath, absolutePath), extension, projectConfig.namespaceCharacter),
418
+ set: config.set,
419
+ };
420
+ }
421
+ }
422
+ return undefined;
423
+ }
424
+ function runGit(rootDirectoryPath, args) {
425
+ return childProcess.execFileSync("git", __spreadArray(["-C", rootDirectoryPath], args, true), {
426
+ encoding: "utf8",
427
+ stdio: ["ignore", "pipe", "ignore"],
428
+ });
429
+ }
430
+ function getCatalogHistoryPathPatterns(rootDirectoryPath, projectConfig) {
431
+ return projectConfig.sets
432
+ ? [path.relative(rootDirectoryPath, projectConfig.setsDirectoryPath)]
433
+ : [
434
+ path.relative(rootDirectoryPath, projectConfig.localesDirectoryPath),
435
+ path.relative(rootDirectoryPath, projectConfig.messagesDirectoryPath),
436
+ path.relative(rootDirectoryPath, projectConfig.attributesDirectoryPath),
437
+ path.relative(rootDirectoryPath, projectConfig.segmentsDirectoryPath),
438
+ path.relative(rootDirectoryPath, projectConfig.targetsDirectoryPath),
439
+ path.relative(rootDirectoryPath, projectConfig.testsDirectoryPath),
440
+ ];
441
+ }
442
+ function createEmptyHistoryIndex() {
443
+ return {
444
+ entries: [],
445
+ bySet: {},
446
+ byEntity: {},
447
+ lastModifiedByEntity: {},
448
+ };
449
+ }
450
+ function addHistoryIndexEntry(target, key, entry) {
451
+ if (!target[key]) {
452
+ target[key] = [];
453
+ }
454
+ target[key].push(entry);
455
+ }
456
+ function buildCatalogHistoryIndex(entries) {
457
+ var index = createEmptyHistoryIndex();
458
+ index.entries = entries;
459
+ for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
460
+ var entry = entries_1[_i];
461
+ var seenSets = new Set();
462
+ for (var _a = 0, _b = entry.entities; _a < _b.length; _a++) {
463
+ var entity = _b[_a];
464
+ if (entity.type === "test") {
465
+ continue;
466
+ }
467
+ var entityKey = getHistoryEntityKey(entity.type, entity.key, entity.set);
468
+ addHistoryIndexEntry(index.byEntity, entityKey, entry);
469
+ if (!index.lastModifiedByEntity[entityKey]) {
470
+ index.lastModifiedByEntity[entityKey] = toLastModified(entry);
471
+ }
472
+ if (entity.set && !seenSets.has(entity.set)) {
473
+ seenSets.add(entity.set);
474
+ addHistoryIndexEntry(index.bySet, entity.set, entry);
475
+ }
476
+ }
477
+ }
478
+ return index;
479
+ }
480
+ function appendHistoryEntry(history, current) {
481
+ if (!current || current.entities.length === 0) {
482
+ return;
483
+ }
484
+ history.push({
485
+ commit: current.commit,
486
+ author: current.author,
487
+ timestamp: current.timestamp,
488
+ entities: current.entities,
489
+ });
490
+ }
491
+ function addHistoryEntity(current, entity) {
492
+ if (entity.type === "test") {
493
+ return;
494
+ }
495
+ var entityKey = getHistoryEntityKey(entity.type, entity.key, entity.set);
496
+ if (current.seenEntityKeys.has(entityKey)) {
497
+ return;
498
+ }
499
+ current.seenEntityKeys.add(entityKey);
500
+ current.entities.push(entity);
501
+ }
502
+ function streamCatalogGitHistory(rootDirectoryPath, projectConfig) {
503
+ return __awaiter(this, void 0, void 0, function () {
504
+ var pathPatterns, args;
505
+ return __generator(this, function (_a) {
506
+ pathPatterns = getCatalogHistoryPathPatterns(rootDirectoryPath, projectConfig);
507
+ args = __spreadArray([
508
+ "-C",
509
+ rootDirectoryPath,
510
+ "log",
511
+ "--name-only",
512
+ "--pretty=format:%x1e%h%x1f%an%x1f%aI",
513
+ "--relative",
514
+ "--no-merges",
515
+ "--"
516
+ ], pathPatterns, true);
517
+ return [2 /*return*/, new Promise(function (resolve, reject) {
518
+ var current;
519
+ var buffer = "";
520
+ var history = [];
521
+ var git = childProcess.spawn("git", args, {
522
+ stdio: ["ignore", "pipe", "ignore"],
523
+ });
524
+ function processLine(line) {
525
+ if (!line) {
526
+ return;
527
+ }
528
+ if (line.startsWith("\x1e")) {
529
+ appendHistoryEntry(history, current);
530
+ var _a = line.slice(1).split("\x1f"), commit = _a[0], author = _a[1], timestamp = _a[2];
531
+ current =
532
+ commit && author && timestamp
533
+ ? {
534
+ commit: commit,
535
+ author: author,
536
+ timestamp: timestamp,
537
+ entities: [],
538
+ seenEntityKeys: new Set(),
539
+ }
540
+ : undefined;
541
+ return;
542
+ }
543
+ if (!current) {
544
+ return;
545
+ }
546
+ var entity = getEntityInfoFromRelativePath(rootDirectoryPath, projectConfig, line);
547
+ if (entity) {
548
+ addHistoryEntity(current, entity);
549
+ }
550
+ }
551
+ git.stdout.setEncoding("utf8");
552
+ git.stdout.on("data", function (chunk) {
553
+ buffer += chunk;
554
+ var lines = buffer.split(/\r?\n/);
555
+ buffer = lines.pop() || "";
556
+ for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
557
+ var line = lines_1[_i];
558
+ processLine(line);
559
+ }
560
+ });
561
+ git.on("error", reject);
562
+ git.on("close", function (code) {
563
+ if (buffer) {
564
+ processLine(buffer);
565
+ }
566
+ appendHistoryEntry(history, current);
567
+ if (code === 0) {
568
+ resolve(history);
569
+ return;
570
+ }
571
+ reject(new Error("git log exited with code ".concat(code)));
572
+ });
573
+ })];
574
+ });
575
+ });
576
+ }
577
+ function isExecutableFile(filePath) {
578
+ try {
579
+ var stat = fs.statSync(filePath);
580
+ if (!stat.isFile()) {
581
+ return false;
582
+ }
583
+ if (process.platform === "win32") {
584
+ return true;
585
+ }
586
+ fs.accessSync(filePath, fs.constants.X_OK);
587
+ return true;
588
+ }
589
+ catch (_error) {
590
+ return false;
591
+ }
592
+ }
593
+ function hasCommandInPath(command) {
594
+ var pathEntries = (process.env.PATH || "").split(path.delimiter).filter(Boolean);
595
+ var extensions = process.platform === "win32"
596
+ ? (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean)
597
+ : [""];
598
+ return pathEntries.some(function (entry) {
599
+ return extensions.some(function (extension) { return isExecutableFile(path.join(entry, "".concat(command).concat(extension))); });
600
+ });
601
+ }
602
+ function hasKnownEditorInstall(editor) {
603
+ if (hasCommandInPath(editor === "cursor" ? "cursor" : "code")) {
604
+ return true;
605
+ }
606
+ if (process.platform === "darwin") {
607
+ var appName = editor === "cursor" ? "Cursor.app" : "Visual Studio Code.app";
608
+ return [
609
+ path.join("/Applications", appName),
610
+ path.join(process.env.HOME || "", "Applications", appName),
611
+ ].some(function (appPath) { return fs.existsSync(appPath); });
612
+ }
613
+ if (process.platform === "win32") {
614
+ var localAppData = process.env.LOCALAPPDATA || "";
615
+ var programFiles = process.env.ProgramFiles || "";
616
+ var programFilesX86 = process.env["ProgramFiles(x86)"] || "";
617
+ var candidates = editor === "cursor"
618
+ ? [
619
+ path.join(localAppData, "Programs", "Cursor", "Cursor.exe"),
620
+ path.join(programFiles, "Cursor", "Cursor.exe"),
621
+ path.join(programFilesX86, "Cursor", "Cursor.exe"),
622
+ ]
623
+ : [
624
+ path.join(localAppData, "Programs", "Microsoft VS Code", "Code.exe"),
625
+ path.join(programFiles, "Microsoft VS Code", "Code.exe"),
626
+ path.join(programFilesX86, "Microsoft VS Code", "Code.exe"),
627
+ ];
628
+ return candidates.some(function (candidate) { return fs.existsSync(candidate); });
629
+ }
630
+ return false;
631
+ }
632
+ function detectDevEditors() {
633
+ var editors = [];
634
+ if (hasKnownEditorInstall("cursor")) {
635
+ editors.push({ id: "cursor", label: "Cursor", icon: "cursor" });
636
+ }
637
+ if (hasKnownEditorInstall("vscode")) {
638
+ editors.push({ id: "vscode", label: "VS Code", icon: "vscode" });
639
+ }
640
+ return editors;
641
+ }
642
+ function getGitHistoryIndex(rootDirectoryPath, projectConfig) {
643
+ return __awaiter(this, void 0, void 0, function () {
644
+ var _a, _error_1;
645
+ return __generator(this, function (_b) {
646
+ switch (_b.label) {
647
+ case 0:
648
+ _b.trys.push([0, 2, , 3]);
649
+ _a = buildCatalogHistoryIndex;
650
+ return [4 /*yield*/, streamCatalogGitHistory(rootDirectoryPath, projectConfig)];
651
+ case 1: return [2 /*return*/, _a.apply(void 0, [_b.sent()])];
652
+ case 2:
653
+ _error_1 = _b.sent();
654
+ return [2 /*return*/, createEmptyHistoryIndex()];
655
+ case 3: return [2 /*return*/];
656
+ }
657
+ });
658
+ });
659
+ }
660
+ function getCurrentBranch(rootDirectoryPath) {
661
+ try {
662
+ return runGit(rootDirectoryPath, ["symbolic-ref", "--short", "HEAD"]).trim() || "HEAD";
663
+ }
664
+ catch (_error) {
665
+ return "HEAD";
666
+ }
667
+ }
668
+ function getRepositoryRootDirectoryPath(rootDirectoryPath) {
669
+ try {
670
+ return (getRealPath(runGit(rootDirectoryPath, ["rev-parse", "--show-toplevel"]).trim()) ||
671
+ getRealPath(rootDirectoryPath));
672
+ }
673
+ catch (_error) {
674
+ return getRealPath(rootDirectoryPath);
675
+ }
676
+ }
677
+ function getOwnerAndRepoFromGitRemote(origin, host) {
678
+ var escapedHost = host.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
679
+ var match = origin.match(new RegExp("".concat(escapedHost, "[:/]([^/]+)/(.+?)(?:\\.git)?$")));
680
+ if (!match) {
681
+ return undefined;
682
+ }
683
+ return {
684
+ owner: match[1],
685
+ repo: match[2],
686
+ };
687
+ }
688
+ function getRepoLinks(rootDirectoryPath) {
689
+ try {
690
+ var origin_1 = runGit(rootDirectoryPath, ["config", "--get", "remote.origin.url"]).trim();
691
+ var branch_1 = encodeURI(getCurrentBranch(rootDirectoryPath));
692
+ var providers = {
693
+ github: {
694
+ host: "github.com",
695
+ repository: function (owner, repo) { return "https://github.com/".concat(owner, "/").concat(repo); },
696
+ source: function (owner, repo) { return "https://github.com/".concat(owner, "/").concat(repo, "/blob/").concat(branch_1, "/{{path}}"); },
697
+ commit: function (owner, repo) { return "https://github.com/".concat(owner, "/").concat(repo, "/commit/{{hash}}"); },
698
+ },
699
+ gitlab: {
700
+ host: "gitlab.com",
701
+ repository: function (owner, repo) { return "https://gitlab.com/".concat(owner, "/").concat(repo); },
702
+ source: function (owner, repo) { return "https://gitlab.com/".concat(owner, "/").concat(repo, "/-/blob/").concat(branch_1, "/{{path}}"); },
703
+ commit: function (owner, repo) { return "https://gitlab.com/".concat(owner, "/").concat(repo, "/-/commit/{{hash}}"); },
704
+ },
705
+ bitbucket: {
706
+ host: "bitbucket.org",
707
+ repository: function (owner, repo) { return "https://bitbucket.org/".concat(owner, "/").concat(repo); },
708
+ source: function (owner, repo) { return "https://bitbucket.org/".concat(owner, "/").concat(repo, "/src/").concat(branch_1, "/{{path}}"); },
709
+ commit: function (owner, repo) { return "https://bitbucket.org/".concat(owner, "/").concat(repo, "/commits/{{hash}}"); },
710
+ },
711
+ };
712
+ for (var _i = 0, _a = Object.keys(providers); _i < _a.length; _i++) {
713
+ var provider = _a[_i];
714
+ var config = providers[provider];
715
+ var details = getOwnerAndRepoFromGitRemote(origin_1, config.host);
716
+ if (details) {
717
+ return {
718
+ provider: provider,
719
+ repository: config.repository(details.owner, details.repo),
720
+ source: config.source(details.owner, details.repo),
721
+ commit: config.commit(details.owner, details.repo),
722
+ };
723
+ }
724
+ }
725
+ }
726
+ catch (_error) {
727
+ return undefined;
728
+ }
729
+ }
730
+ function chunkHistory(history, pageSize) {
731
+ if (pageSize === void 0) { pageSize = exports.CATALOG_HISTORY_PAGE_SIZE; }
732
+ var pages = [];
733
+ for (var index = 0; index < history.length; index += pageSize) {
734
+ pages.push(history.slice(index, index + pageSize));
735
+ }
736
+ return pages.length > 0 ? pages : [[]];
737
+ }
738
+ function writeHistoryPages(directoryPath, history) {
739
+ return __awaiter(this, void 0, void 0, function () {
740
+ var pages, index;
741
+ return __generator(this, function (_a) {
742
+ switch (_a.label) {
743
+ case 0:
744
+ pages = chunkHistory(history);
745
+ index = 0;
746
+ _a.label = 1;
747
+ case 1:
748
+ if (!(index < pages.length)) return [3 /*break*/, 4];
749
+ return [4 /*yield*/, writeJson(path.join(directoryPath, "page-".concat(index + 1, ".json")), {
750
+ page: index + 1,
751
+ pageSize: exports.CATALOG_HISTORY_PAGE_SIZE,
752
+ totalPages: pages.length,
753
+ entries: pages[index],
754
+ })];
755
+ case 2:
756
+ _a.sent();
757
+ _a.label = 3;
758
+ case 3:
759
+ index++;
760
+ return [3 /*break*/, 1];
761
+ case 4: return [2 /*return*/];
762
+ }
763
+ });
764
+ });
765
+ }
766
+ function getHistoryForEntity(historyIndex, type, key, set) {
767
+ return historyIndex.byEntity[getHistoryEntityKey(type, key, set)] || [];
768
+ }
769
+ function getSourceFileInfo(repositoryRootDirectoryPath, rootDirectoryPath, projectConfig, type, key) {
770
+ var directoryByType = {
771
+ locale: projectConfig.localesDirectoryPath,
772
+ message: projectConfig.messagesDirectoryPath,
773
+ attribute: projectConfig.attributesDirectoryPath,
774
+ segment: projectConfig.segmentsDirectoryPath,
775
+ target: projectConfig.targetsDirectoryPath,
776
+ };
777
+ var extension = ".".concat(projectConfig.parser.extension);
778
+ var filePath = path.resolve(path.resolve.apply(path, __spreadArray([rootDirectoryPath,
779
+ directoryByType[type]], key.split(projectConfig.namespaceCharacter), false)) + extension);
780
+ var absolutePath = getRealPath(filePath);
781
+ return {
782
+ sourcePath: toPosixPath(path.relative(repositoryRootDirectoryPath, absolutePath)),
783
+ absolutePath: absolutePath,
784
+ };
785
+ }
786
+ function encodeEditorPath(filePath) {
787
+ return encodeURI(filePath.split(path.sep).join("/")).replace(/#/g, "%23").replace(/\?/g, "%3F");
788
+ }
789
+ function getEditorUri(editor, filePath) {
790
+ return "".concat(editor === "cursor" ? "cursor" : "vscode", "://file/").concat(encodeEditorPath(filePath));
791
+ }
792
+ function getEditorLinks(editors, sourceFileInfo) {
793
+ if (editors.length === 0) {
794
+ return undefined;
795
+ }
796
+ return Object.fromEntries(editors.map(function (editor) { return [editor.id, getEditorUri(editor.id, sourceFileInfo.absolutePath)]; }));
797
+ }
798
+ function buildSetCatalog(context, set, projectConfig, datasource, outputRelativeDirectory) {
799
+ return __awaiter(this, void 0, void 0, function () {
800
+ function addToTranslationShard(msgKey, value) {
801
+ if (!value || value.length < 3)
802
+ return;
803
+ var lower = value.toLowerCase();
804
+ var seenSubs = new Set();
805
+ for (var i = 0; i <= lower.length - 3; i++) {
806
+ var sub = lower.slice(i, i + 3);
807
+ if (seenSubs.has(sub))
808
+ continue;
809
+ seenSubs.add(sub);
810
+ var filename = Buffer.from(sub, "utf8").toString("hex");
811
+ if (!translationShards[filename])
812
+ translationShards[filename] = {};
813
+ if (!translationShards[filename][msgKey])
814
+ translationShards[filename][msgKey] = new Set();
815
+ translationShards[filename][msgKey].add(lower);
816
+ }
817
+ }
818
+ var outputDirectoryPath, _a, localeKeys, messageKeys, attributeKeys, segmentKeys, targetKeys, _b, locales, messages, attributes, segments, targets, messageTargets, targetMessages, localeTargets, attributeTargets, segmentTargets, attributesUsedInSegments, attributesUsedInMessages, segmentsUsedInMessages, _i, targetKeys_1, targetKey, targetLocaleKeys, _c, targetLocaleKeys_1, localeKey, _d, _e, messageKey, _f, segmentKeys_1, segmentKey, usedAttributes, _g, _h, attributeKey, _j, messageKeys_1, messageKey, message, targetsForMessage, _k, _l, override, usedAttributes, usedSegments, _m, _o, attributeKey, _p, targetsForMessage_1, targetKey, _q, _r, segmentKey, _s, targetsForMessage_2, targetKey, _t, _u, attributeKey, _v, _w, segmentKey, _x, _y, targetKey, history, localeDirections, duplicateResult, duplicatesByLocale, index, evaluatedMessageExamplesByKey, evaluatedLocaleExamplesByKey, _loop_1, _z, localeKeys_1, localeKey, translationShards, _loop_2, _0, messageKeys_2, messageKey, _1, _2, _3, prefix, messageMap, shardData, _4, _5, _6, msgKey, valueSet, _7, attributeKeys_1, attributeKey, attribute, sourceFileInfo, detail, _8, segmentKeys_2, segmentKey, segment, usedAttributes, sourceFileInfo, detail, _9, targetKeys_2, targetKey, target, targetLocaleKeys, formatsByLocale, formatRowsByLocale, _10, targetLocaleKeys_2, localeKey, sourceFileInfo, detail, _11, _12, type;
819
+ var _13, _14;
820
+ return __generator(this, function (_15) {
821
+ switch (_15.label) {
822
+ case 0:
823
+ outputDirectoryPath = path.join(context.dataDirectoryPath, outputRelativeDirectory);
824
+ return [4 /*yield*/, Promise.all([
825
+ datasource.listLocales(),
826
+ datasource.listMessages(),
827
+ datasource.listAttributes(),
828
+ datasource.listSegments(),
829
+ datasource.listTargets(),
830
+ ])];
831
+ case 1:
832
+ _a = _15.sent(), localeKeys = _a[0], messageKeys = _a[1], attributeKeys = _a[2], segmentKeys = _a[3], targetKeys = _a[4];
833
+ return [4 /*yield*/, Promise.all([
834
+ readAll(localeKeys, function (key) { return datasource.readLocale(key); }),
835
+ readAll(messageKeys, function (key) { return datasource.readMessage(key); }),
836
+ readAll(attributeKeys, function (key) { return datasource.readAttribute(key); }),
837
+ readAll(segmentKeys, function (key) { return datasource.readSegment(key); }),
838
+ readAll(targetKeys, function (key) { return datasource.readTarget(key); }),
839
+ ])];
840
+ case 2:
841
+ _b = _15.sent(), locales = _b[0], messages = _b[1], attributes = _b[2], segments = _b[3], targets = _b[4];
842
+ messageTargets = {};
843
+ targetMessages = {};
844
+ localeTargets = {};
845
+ attributeTargets = {};
846
+ segmentTargets = {};
847
+ attributesUsedInSegments = {};
848
+ attributesUsedInMessages = {};
849
+ segmentsUsedInMessages = {};
850
+ for (_i = 0, targetKeys_1 = targetKeys; _i < targetKeys_1.length; _i++) {
851
+ targetKey = targetKeys_1[_i];
852
+ targetMessages[targetKey] = getTargetMessageKeys(targets[targetKey], messageKeys);
853
+ targetLocaleKeys = ((_13 = targets[targetKey].locales) === null || _13 === void 0 ? void 0 : _13.length)
854
+ ? targets[targetKey].locales
855
+ : localeKeys;
856
+ for (_c = 0, targetLocaleKeys_1 = targetLocaleKeys; _c < targetLocaleKeys_1.length; _c++) {
857
+ localeKey = targetLocaleKeys_1[_c];
858
+ if (!localeTargets[localeKey]) {
859
+ localeTargets[localeKey] = new Set();
860
+ }
861
+ localeTargets[localeKey].add(targetKey);
862
+ }
863
+ for (_d = 0, _e = targetMessages[targetKey]; _d < _e.length; _d++) {
864
+ messageKey = _e[_d];
865
+ if (!messageTargets[messageKey]) {
866
+ messageTargets[messageKey] = [];
867
+ }
868
+ messageTargets[messageKey].push(targetKey);
869
+ }
870
+ }
871
+ for (_f = 0, segmentKeys_1 = segmentKeys; _f < segmentKeys_1.length; _f++) {
872
+ segmentKey = segmentKeys_1[_f];
873
+ usedAttributes = new Set();
874
+ collectAttributeKeysFromConditions(segments[segmentKey].conditions, usedAttributes);
875
+ for (_g = 0, _h = Array.from(usedAttributes); _g < _h.length; _g++) {
876
+ attributeKey = _h[_g];
877
+ if (!attributesUsedInSegments[attributeKey]) {
878
+ attributesUsedInSegments[attributeKey] = new Set();
879
+ }
880
+ attributesUsedInSegments[attributeKey].add(segmentKey);
881
+ }
882
+ }
883
+ for (_j = 0, messageKeys_1 = messageKeys; _j < messageKeys_1.length; _j++) {
884
+ messageKey = messageKeys_1[_j];
885
+ message = messages[messageKey];
886
+ targetsForMessage = messageTargets[messageKey] || [];
887
+ for (_k = 0, _l = message.overrides || []; _k < _l.length; _k++) {
888
+ override = _l[_k];
889
+ usedAttributes = new Set();
890
+ usedSegments = new Set();
891
+ collectAttributeKeysFromConditions(override.conditions, usedAttributes);
892
+ collectSegmentKeys(override.segments, usedSegments);
893
+ for (_m = 0, _o = Array.from(usedAttributes); _m < _o.length; _m++) {
894
+ attributeKey = _o[_m];
895
+ if (!attributesUsedInMessages[attributeKey]) {
896
+ attributesUsedInMessages[attributeKey] = new Set();
897
+ }
898
+ attributesUsedInMessages[attributeKey].add(messageKey);
899
+ for (_p = 0, targetsForMessage_1 = targetsForMessage; _p < targetsForMessage_1.length; _p++) {
900
+ targetKey = targetsForMessage_1[_p];
901
+ if (!attributeTargets[attributeKey]) {
902
+ attributeTargets[attributeKey] = new Set();
903
+ }
904
+ attributeTargets[attributeKey].add(targetKey);
905
+ }
906
+ }
907
+ for (_q = 0, _r = Array.from(usedSegments); _q < _r.length; _q++) {
908
+ segmentKey = _r[_q];
909
+ if (!segmentsUsedInMessages[segmentKey]) {
910
+ segmentsUsedInMessages[segmentKey] = new Set();
911
+ }
912
+ segmentsUsedInMessages[segmentKey].add(messageKey);
913
+ for (_s = 0, targetsForMessage_2 = targetsForMessage; _s < targetsForMessage_2.length; _s++) {
914
+ targetKey = targetsForMessage_2[_s];
915
+ if (!segmentTargets[segmentKey]) {
916
+ segmentTargets[segmentKey] = new Set();
917
+ }
918
+ segmentTargets[segmentKey].add(targetKey);
919
+ }
920
+ }
921
+ }
922
+ }
923
+ for (_t = 0, _u = Object.keys(attributesUsedInSegments); _t < _u.length; _t++) {
924
+ attributeKey = _u[_t];
925
+ for (_v = 0, _w = Array.from(attributesUsedInSegments[attributeKey]); _v < _w.length; _v++) {
926
+ segmentKey = _w[_v];
927
+ for (_x = 0, _y = Array.from(segmentTargets[segmentKey] || []); _x < _y.length; _x++) {
928
+ targetKey = _y[_x];
929
+ if (!attributeTargets[attributeKey]) {
930
+ attributeTargets[attributeKey] = new Set();
931
+ }
932
+ attributeTargets[attributeKey].add(targetKey);
933
+ }
934
+ }
935
+ }
936
+ history = set ? context.historyIndex.bySet[set] || [] : context.historyIndex.entries;
937
+ localeDirections = getLocaleDirections(locales);
938
+ duplicateResult = context.duplicateResultsBySet[getDuplicateSetKey(set)] || {
939
+ set: set || null,
940
+ locales: [],
941
+ };
942
+ duplicatesByLocale = Object.fromEntries(duplicateResult.locales.map(function (entry) { return [entry.locale, entry]; }));
943
+ index = {
944
+ set: set,
945
+ counts: {
946
+ locale: localeKeys.length,
947
+ message: messageKeys.length,
948
+ attribute: attributeKeys.length,
949
+ segment: segmentKeys.length,
950
+ target: targetKeys.length,
951
+ },
952
+ entities: {
953
+ locale: [],
954
+ message: [],
955
+ attribute: [],
956
+ segment: [],
957
+ target: [],
958
+ },
959
+ };
960
+ return [4 /*yield*/, writeHistoryPages(path.join(outputDirectoryPath, "history"), history)];
961
+ case 3:
962
+ _15.sent();
963
+ return [4 /*yield*/, context.runtime.resolveExamples(projectConfig, datasource, {
964
+ onlyMessages: true,
965
+ })];
966
+ case 4:
967
+ evaluatedMessageExamplesByKey = (_15.sent()).messages.reduce(function (accumulator, example) {
968
+ if (!accumulator[example.message]) {
969
+ accumulator[example.message] = [];
970
+ }
971
+ accumulator[example.message].push(example);
972
+ return accumulator;
973
+ }, {});
974
+ return [4 /*yield*/, context.runtime.resolveExamples(projectConfig, datasource, {
975
+ onlyLocales: true,
976
+ })];
977
+ case 5:
978
+ evaluatedLocaleExamplesByKey = (_15.sent()).locales.reduce(function (accumulator, example) {
979
+ var _a;
980
+ var originalTranslation = example.message
981
+ ? resolveTranslationRow((_a = messages[example.message]) === null || _a === void 0 ? void 0 : _a.translations, example.locale, locales)
982
+ .value
983
+ : undefined;
984
+ if (!accumulator[example.locale]) {
985
+ accumulator[example.locale] = [];
986
+ }
987
+ accumulator[example.locale].push(__assign(__assign({}, example), { originalTranslation: originalTranslation || undefined }));
988
+ return accumulator;
989
+ }, {});
990
+ _loop_1 = function (localeKey) {
991
+ var locale, sourceFileInfo, detail;
992
+ return __generator(this, function (_16) {
993
+ switch (_16.label) {
994
+ case 0:
995
+ locale = locales[localeKey];
996
+ sourceFileInfo = getSourceFileInfo(context.repositoryRootDirectoryPath, context.rootDirectoryPath, projectConfig, "locale", localeKey);
997
+ detail = {
998
+ type: "locale",
999
+ key: localeKey,
1000
+ entity: locale,
1001
+ sourcePath: sourceFileInfo.sourcePath,
1002
+ editLinks: getEditorLinks(context.devEditors, sourceFileInfo),
1003
+ baseFormats: locale.formats || {},
1004
+ computedFormats: context.runtime.resolveFormats(localeKey, locales),
1005
+ formatRows: getFormatRows(context.runtime, localeKey, locales),
1006
+ evaluatedExamples: evaluatedLocaleExamplesByKey[localeKey] || [],
1007
+ targetFormats: Object.fromEntries(targetKeys.map(function (targetKey) { return [
1008
+ targetKey,
1009
+ context.runtime.resolveFormats(localeKey, locales, targets[targetKey]),
1010
+ ]; })),
1011
+ lastModified: getLastModified(context.historyIndex, "locale", localeKey, set || undefined),
1012
+ };
1013
+ index.entities.locale.push(getEntitySummary(locale, "locale", localeKey, context.historyIndex, set || undefined, {
1014
+ targets: sortStrings(Array.from(localeTargets[localeKey] || [])),
1015
+ }));
1016
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "entities", "locale", "".concat(encodeKey(localeKey), ".json")), detail)];
1017
+ case 1:
1018
+ _16.sent();
1019
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "duplicates", "locales", "".concat(encodeKey(localeKey), ".json")), toLocaleDuplicatesFile(localeKey, duplicatesByLocale))];
1020
+ case 2:
1021
+ _16.sent();
1022
+ return [4 /*yield*/, writeHistoryPages(path.join(outputDirectoryPath, "history", "locale", encodeKey(localeKey)), getHistoryForEntity(context.historyIndex, "locale", localeKey, set || undefined))];
1023
+ case 3:
1024
+ _16.sent();
1025
+ return [2 /*return*/];
1026
+ }
1027
+ });
1028
+ };
1029
+ _z = 0, localeKeys_1 = localeKeys;
1030
+ _15.label = 6;
1031
+ case 6:
1032
+ if (!(_z < localeKeys_1.length)) return [3 /*break*/, 9];
1033
+ localeKey = localeKeys_1[_z];
1034
+ return [5 /*yield**/, _loop_1(localeKey)];
1035
+ case 7:
1036
+ _15.sent();
1037
+ _15.label = 8;
1038
+ case 8:
1039
+ _z++;
1040
+ return [3 /*break*/, 6];
1041
+ case 9:
1042
+ translationShards = {};
1043
+ _loop_2 = function (messageKey) {
1044
+ var message, overrides, sourceFileInfo, detail, directLocales, overrideLocalesSet, _17, overrides_1, override, _18, _19, lk, overrideLocalesList, _20, localeKeys_2, localeKey, row, _21, overrides_2, override, overrideRow;
1045
+ return __generator(this, function (_22) {
1046
+ switch (_22.label) {
1047
+ case 0:
1048
+ message = messages[messageKey];
1049
+ overrides = (message.overrides || []).map(function (override) {
1050
+ var attributes = new Set();
1051
+ var overrideSegments = new Set();
1052
+ collectAttributeKeysFromConditions(override.conditions, attributes);
1053
+ collectSegmentKeys(override.segments, overrideSegments);
1054
+ return __assign(__assign({}, override), { usedAttributes: sortStrings(Array.from(attributes)), usedSegments: sortStrings(Array.from(overrideSegments)) });
1055
+ });
1056
+ sourceFileInfo = getSourceFileInfo(context.repositoryRootDirectoryPath, context.rootDirectoryPath, projectConfig, "message", messageKey);
1057
+ detail = {
1058
+ type: "message",
1059
+ key: messageKey,
1060
+ entity: __assign(__assign({}, message), { overrides: overrides }),
1061
+ sourcePath: sourceFileInfo.sourcePath,
1062
+ editLinks: getEditorLinks(context.devEditors, sourceFileInfo),
1063
+ targets: sortStrings(messageTargets[messageKey] || []),
1064
+ localeKeys: localeKeys,
1065
+ localeDirections: localeDirections,
1066
+ translations: localeKeys.map(function (localeKey) {
1067
+ return resolveTranslationRow(message.translations, localeKey, locales);
1068
+ }),
1069
+ evaluatedExamples: evaluatedMessageExamplesByKey[messageKey] || [],
1070
+ overrideTranslations: overrides.map(function (override) { return ({
1071
+ key: override.key,
1072
+ rows: localeKeys.map(function (localeKey) {
1073
+ return resolveTranslationRow(override.translations, localeKey, locales);
1074
+ }),
1075
+ }); }),
1076
+ lastModified: getLastModified(context.historyIndex, "message", messageKey, set || undefined),
1077
+ };
1078
+ directLocales = localeKeys.filter(function (lk) { return message.translations && typeof message.translations[lk] === "string"; });
1079
+ overrideLocalesSet = new Set();
1080
+ for (_17 = 0, overrides_1 = overrides; _17 < overrides_1.length; _17++) {
1081
+ override = overrides_1[_17];
1082
+ for (_18 = 0, _19 = Object.keys(override.translations || {}); _18 < _19.length; _18++) {
1083
+ lk = _19[_18];
1084
+ overrideLocalesSet.add(lk);
1085
+ }
1086
+ }
1087
+ overrideLocalesList = sortStrings(Array.from(overrideLocalesSet));
1088
+ // Build translation shards (direct + inherited + override, all locales combined)
1089
+ for (_20 = 0, localeKeys_2 = localeKeys; _20 < localeKeys_2.length; _20++) {
1090
+ localeKey = localeKeys_2[_20];
1091
+ row = resolveTranslationRow(message.translations, localeKey, locales);
1092
+ if (row.source !== "missing" && row.value) {
1093
+ addToTranslationShard(messageKey, row.value);
1094
+ }
1095
+ for (_21 = 0, overrides_2 = overrides; _21 < overrides_2.length; _21++) {
1096
+ override = overrides_2[_21];
1097
+ overrideRow = resolveTranslationRow(override.translations, localeKey, locales);
1098
+ if (overrideRow.source !== "missing" && overrideRow.value) {
1099
+ addToTranslationShard(messageKey, overrideRow.value);
1100
+ }
1101
+ }
1102
+ }
1103
+ index.entities.message.push(getEntitySummary(message, "message", messageKey, context.historyIndex, set || undefined, __assign(__assign({ targets: sortStrings(messageTargets[messageKey] || []) }, (directLocales.length > 0 ? { locales: sortStrings(directLocales) } : {})), (overrideLocalesList.length > 0 ? { overrideLocales: overrideLocalesList } : {}))));
1104
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "entities", "message", "".concat(encodeKey(messageKey), ".json")), detail)];
1105
+ case 1:
1106
+ _22.sent();
1107
+ return [4 /*yield*/, writeHistoryPages(path.join(outputDirectoryPath, "history", "message", encodeKey(messageKey)), getHistoryForEntity(context.historyIndex, "message", messageKey, set || undefined))];
1108
+ case 2:
1109
+ _22.sent();
1110
+ return [2 /*return*/];
1111
+ }
1112
+ });
1113
+ };
1114
+ _0 = 0, messageKeys_2 = messageKeys;
1115
+ _15.label = 10;
1116
+ case 10:
1117
+ if (!(_0 < messageKeys_2.length)) return [3 /*break*/, 13];
1118
+ messageKey = messageKeys_2[_0];
1119
+ return [5 /*yield**/, _loop_2(messageKey)];
1120
+ case 11:
1121
+ _15.sent();
1122
+ _15.label = 12;
1123
+ case 12:
1124
+ _0++;
1125
+ return [3 /*break*/, 10];
1126
+ case 13:
1127
+ _1 = 0, _2 = Object.entries(translationShards);
1128
+ _15.label = 14;
1129
+ case 14:
1130
+ if (!(_1 < _2.length)) return [3 /*break*/, 17];
1131
+ _3 = _2[_1], prefix = _3[0], messageMap = _3[1];
1132
+ shardData = {};
1133
+ for (_4 = 0, _5 = Object.entries(messageMap); _4 < _5.length; _4++) {
1134
+ _6 = _5[_4], msgKey = _6[0], valueSet = _6[1];
1135
+ shardData[msgKey] = Array.from(valueSet);
1136
+ }
1137
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "translations", "".concat(prefix, ".json")), shardData)];
1138
+ case 15:
1139
+ _15.sent();
1140
+ _15.label = 16;
1141
+ case 16:
1142
+ _1++;
1143
+ return [3 /*break*/, 14];
1144
+ case 17:
1145
+ _7 = 0, attributeKeys_1 = attributeKeys;
1146
+ _15.label = 18;
1147
+ case 18:
1148
+ if (!(_7 < attributeKeys_1.length)) return [3 /*break*/, 22];
1149
+ attributeKey = attributeKeys_1[_7];
1150
+ attribute = attributes[attributeKey];
1151
+ sourceFileInfo = getSourceFileInfo(context.repositoryRootDirectoryPath, context.rootDirectoryPath, projectConfig, "attribute", attributeKey);
1152
+ detail = {
1153
+ type: "attribute",
1154
+ key: attributeKey,
1155
+ entity: attribute,
1156
+ sourcePath: sourceFileInfo.sourcePath,
1157
+ editLinks: getEditorLinks(context.devEditors, sourceFileInfo),
1158
+ usage: {
1159
+ segments: sortStrings(Array.from(attributesUsedInSegments[attributeKey] || [])),
1160
+ messages: sortStrings(Array.from(attributesUsedInMessages[attributeKey] || [])),
1161
+ },
1162
+ lastModified: getLastModified(context.historyIndex, "attribute", attributeKey, set || undefined),
1163
+ };
1164
+ index.entities.attribute.push(getEntitySummary(attribute, "attribute", attributeKey, context.historyIndex, set || undefined, {
1165
+ targets: sortStrings(Array.from(attributeTargets[attributeKey] || [])),
1166
+ }));
1167
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "entities", "attribute", "".concat(encodeKey(attributeKey), ".json")), detail)];
1168
+ case 19:
1169
+ _15.sent();
1170
+ return [4 /*yield*/, writeHistoryPages(path.join(outputDirectoryPath, "history", "attribute", encodeKey(attributeKey)), getHistoryForEntity(context.historyIndex, "attribute", attributeKey, set || undefined))];
1171
+ case 20:
1172
+ _15.sent();
1173
+ _15.label = 21;
1174
+ case 21:
1175
+ _7++;
1176
+ return [3 /*break*/, 18];
1177
+ case 22:
1178
+ _8 = 0, segmentKeys_2 = segmentKeys;
1179
+ _15.label = 23;
1180
+ case 23:
1181
+ if (!(_8 < segmentKeys_2.length)) return [3 /*break*/, 27];
1182
+ segmentKey = segmentKeys_2[_8];
1183
+ segment = segments[segmentKey];
1184
+ usedAttributes = new Set();
1185
+ collectAttributeKeysFromConditions(segment.conditions, usedAttributes);
1186
+ sourceFileInfo = getSourceFileInfo(context.repositoryRootDirectoryPath, context.rootDirectoryPath, projectConfig, "segment", segmentKey);
1187
+ detail = {
1188
+ type: "segment",
1189
+ key: segmentKey,
1190
+ entity: segment,
1191
+ sourcePath: sourceFileInfo.sourcePath,
1192
+ editLinks: getEditorLinks(context.devEditors, sourceFileInfo),
1193
+ usage: {
1194
+ attributes: sortStrings(Array.from(usedAttributes)),
1195
+ messages: sortStrings(Array.from(segmentsUsedInMessages[segmentKey] || [])),
1196
+ },
1197
+ lastModified: getLastModified(context.historyIndex, "segment", segmentKey, set || undefined),
1198
+ };
1199
+ index.entities.segment.push(getEntitySummary(segment, "segment", segmentKey, context.historyIndex, set || undefined, {
1200
+ targets: sortStrings(Array.from(segmentTargets[segmentKey] || [])),
1201
+ }));
1202
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "entities", "segment", "".concat(encodeKey(segmentKey), ".json")), detail)];
1203
+ case 24:
1204
+ _15.sent();
1205
+ return [4 /*yield*/, writeHistoryPages(path.join(outputDirectoryPath, "history", "segment", encodeKey(segmentKey)), getHistoryForEntity(context.historyIndex, "segment", segmentKey, set || undefined))];
1206
+ case 25:
1207
+ _15.sent();
1208
+ _15.label = 26;
1209
+ case 26:
1210
+ _8++;
1211
+ return [3 /*break*/, 23];
1212
+ case 27:
1213
+ _9 = 0, targetKeys_2 = targetKeys;
1214
+ _15.label = 28;
1215
+ case 28:
1216
+ if (!(_9 < targetKeys_2.length)) return [3 /*break*/, 32];
1217
+ targetKey = targetKeys_2[_9];
1218
+ target = targets[targetKey];
1219
+ targetLocaleKeys = ((_14 = target.locales) === null || _14 === void 0 ? void 0 : _14.length) ? target.locales : localeKeys;
1220
+ formatsByLocale = {};
1221
+ formatRowsByLocale = {};
1222
+ for (_10 = 0, targetLocaleKeys_2 = targetLocaleKeys; _10 < targetLocaleKeys_2.length; _10++) {
1223
+ localeKey = targetLocaleKeys_2[_10];
1224
+ formatsByLocale[localeKey] = context.runtime.resolveFormats(localeKey, locales, target);
1225
+ formatRowsByLocale[localeKey] = getFormatRows(context.runtime, localeKey, locales, target);
1226
+ }
1227
+ sourceFileInfo = getSourceFileInfo(context.repositoryRootDirectoryPath, context.rootDirectoryPath, projectConfig, "target", targetKey);
1228
+ detail = {
1229
+ type: "target",
1230
+ key: targetKey,
1231
+ entity: target,
1232
+ sourcePath: sourceFileInfo.sourcePath,
1233
+ editLinks: getEditorLinks(context.devEditors, sourceFileInfo),
1234
+ locales: targetLocaleKeys,
1235
+ formatsByLocale: formatsByLocale,
1236
+ formatRowsByLocale: formatRowsByLocale,
1237
+ messages: targetMessages[targetKey],
1238
+ lastModified: getLastModified(context.historyIndex, "target", targetKey, set || undefined),
1239
+ };
1240
+ index.entities.target.push(getEntitySummary(target, "target", targetKey, context.historyIndex, set || undefined, {
1241
+ messageCount: targetMessages[targetKey].length,
1242
+ }));
1243
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "entities", "target", "".concat(encodeKey(targetKey), ".json")), detail)];
1244
+ case 29:
1245
+ _15.sent();
1246
+ return [4 /*yield*/, writeHistoryPages(path.join(outputDirectoryPath, "history", "target", encodeKey(targetKey)), getHistoryForEntity(context.historyIndex, "target", targetKey, set || undefined))];
1247
+ case 30:
1248
+ _15.sent();
1249
+ _15.label = 31;
1250
+ case 31:
1251
+ _9++;
1252
+ return [3 /*break*/, 28];
1253
+ case 32:
1254
+ for (_11 = 0, _12 = Object.keys(index.entities); _11 < _12.length; _11++) {
1255
+ type = _12[_11];
1256
+ index.entities[type].sort(function (a, b) { return a.key.localeCompare(b.key); });
1257
+ }
1258
+ return [4 /*yield*/, writeJson(path.join(outputDirectoryPath, "index.json"), index)];
1259
+ case 33:
1260
+ _15.sent();
1261
+ return [2 /*return*/, index];
1262
+ }
1263
+ });
1264
+ });
1265
+ }
1266
+ function copyCatalogAssets(outputDirectoryPath) {
1267
+ return __awaiter(this, void 0, void 0, function () {
1268
+ var packageJsonPath, distPath;
1269
+ return __generator(this, function (_a) {
1270
+ switch (_a.label) {
1271
+ case 0:
1272
+ try {
1273
+ packageJsonPath = require.resolve("@messagevisor/catalog/package.json");
1274
+ }
1275
+ catch (_error) {
1276
+ throw new Error("Unable to resolve @messagevisor/catalog. Run npm install from the repository root.");
1277
+ }
1278
+ distPath = path.join(path.dirname(packageJsonPath), "dist");
1279
+ if (!fs.existsSync(distPath)) {
1280
+ throw new Error("Catalog UI bundle not found. Run `npm run build --workspace @messagevisor/catalog` first.");
1281
+ }
1282
+ return [4 /*yield*/, fs.promises.cp(distPath, outputDirectoryPath, { recursive: true })];
1283
+ case 1:
1284
+ _a.sent();
1285
+ return [2 /*return*/];
1286
+ }
1287
+ });
1288
+ });
1289
+ }
1290
+ function exportCatalog(runtime_1, rootDirectoryPath_1, projectConfig_1, datasource_1) {
1291
+ return __awaiter(this, arguments, void 0, function (runtime, rootDirectoryPath, projectConfig, datasource, options) {
1292
+ var outputDirectoryPath, dataDirectoryPath, devEditors, historyIndex, duplicateTranslations, duplicateResultsBySet, context, executions, setIndexes, _i, executions_1, execution, outputRelativeDirectory, _a, _b, manifest;
1293
+ if (options === void 0) { options = {}; }
1294
+ return __generator(this, function (_c) {
1295
+ switch (_c.label) {
1296
+ case 0:
1297
+ outputDirectoryPath = options.outDir
1298
+ ? path.resolve(rootDirectoryPath, options.outDir)
1299
+ : projectConfig.catalogDirectoryPath;
1300
+ dataDirectoryPath = path.join(outputDirectoryPath, "data");
1301
+ return [4 /*yield*/, fs.promises.rm(outputDirectoryPath, { recursive: true, force: true })];
1302
+ case 1:
1303
+ _c.sent();
1304
+ return [4 /*yield*/, fs.promises.mkdir(dataDirectoryPath, { recursive: true })];
1305
+ case 2:
1306
+ _c.sent();
1307
+ if (!(options.copyAssets !== false)) return [3 /*break*/, 4];
1308
+ return [4 /*yield*/, copyCatalogAssets(outputDirectoryPath)];
1309
+ case 3:
1310
+ _c.sent();
1311
+ _c.label = 4;
1312
+ case 4:
1313
+ devEditors = options.dev ? options.devEditors || detectDevEditors() : [];
1314
+ return [4 /*yield*/, getGitHistoryIndex(rootDirectoryPath, projectConfig)];
1315
+ case 5:
1316
+ historyIndex = _c.sent();
1317
+ return [4 /*yield*/, runtime.findDuplicateTranslations(projectConfig, datasource)];
1318
+ case 6:
1319
+ duplicateTranslations = _c.sent();
1320
+ duplicateResultsBySet = Object.fromEntries(duplicateTranslations.results.map(function (result) { return [getDuplicateSetKey(result.set), result]; }));
1321
+ context = {
1322
+ rootDirectoryPath: rootDirectoryPath,
1323
+ repositoryRootDirectoryPath: getRepositoryRootDirectoryPath(rootDirectoryPath),
1324
+ outputDirectoryPath: outputDirectoryPath,
1325
+ dataDirectoryPath: dataDirectoryPath,
1326
+ historyIndex: historyIndex,
1327
+ runtime: runtime,
1328
+ devEditors: devEditors,
1329
+ duplicateResultsBySet: duplicateResultsBySet,
1330
+ };
1331
+ return [4 /*yield*/, runtime.getProjectSetExecutions(projectConfig, datasource)];
1332
+ case 7:
1333
+ executions = _c.sent();
1334
+ setIndexes = {};
1335
+ return [4 /*yield*/, writeHistoryPages(path.join(dataDirectoryPath, "project", "history"), historyIndex.entries)];
1336
+ case 8:
1337
+ _c.sent();
1338
+ _i = 0, executions_1 = executions;
1339
+ _c.label = 9;
1340
+ case 9:
1341
+ if (!(_i < executions_1.length)) return [3 /*break*/, 12];
1342
+ execution = executions_1[_i];
1343
+ outputRelativeDirectory = projectConfig.sets ? path.join("sets", execution.set) : "root";
1344
+ _a = setIndexes;
1345
+ _b = execution.set || "root";
1346
+ return [4 /*yield*/, buildSetCatalog(context, execution.set, execution.projectConfig, execution.datasource, outputRelativeDirectory)];
1347
+ case 10:
1348
+ _a[_b] = _c.sent();
1349
+ _c.label = 11;
1350
+ case 11:
1351
+ _i++;
1352
+ return [3 /*break*/, 9];
1353
+ case 12:
1354
+ manifest = {
1355
+ schemaVersion: exports.CATALOG_SCHEMA_VERSION,
1356
+ generatedAt: new Date().toISOString(),
1357
+ router: options.browserRouter === false ? "hash" : "browser",
1358
+ sets: projectConfig.sets,
1359
+ setKeys: projectConfig.sets ? executions.map(function (execution) { return execution.set; }) : [],
1360
+ dev: options.dev ? { editors: devEditors } : undefined,
1361
+ links: getRepoLinks(rootDirectoryPath),
1362
+ paths: {
1363
+ projectHistory: "data/project/history/page-1.json",
1364
+ root: projectConfig.sets ? undefined : "data/root/index.json",
1365
+ sets: projectConfig.sets
1366
+ ? Object.fromEntries(executions.map(function (execution) { return [
1367
+ execution.set,
1368
+ "data/sets/".concat(encodeURIComponent(execution.set), "/index.json"),
1369
+ ]; }))
1370
+ : undefined,
1371
+ },
1372
+ counts: Object.fromEntries(Object.keys(setIndexes).map(function (key) { return [key, setIndexes[key].counts]; })),
1373
+ };
1374
+ return [4 /*yield*/, writeJson(path.join(dataDirectoryPath, "manifest.json"), manifest)];
1375
+ case 13:
1376
+ _c.sent();
1377
+ console.log("Catalog exported to ".concat(outputDirectoryPath));
1378
+ return [2 /*return*/, {
1379
+ outputDirectoryPath: outputDirectoryPath,
1380
+ manifest: manifest,
1381
+ }];
1382
+ }
1383
+ });
1384
+ });
1385
+ }
1386
+ function getContentType(filePath) {
1387
+ var extension = path.extname(filePath);
1388
+ switch (extension) {
1389
+ case ".js":
1390
+ return "text/javascript";
1391
+ case ".css":
1392
+ return "text/css";
1393
+ case ".json":
1394
+ return "application/json";
1395
+ case ".png":
1396
+ return "image/png";
1397
+ case ".svg":
1398
+ return "image/svg+xml";
1399
+ case ".ico":
1400
+ return "image/x-icon";
1401
+ default:
1402
+ return "text/html";
1403
+ }
1404
+ }
1405
+ function getCatalogLiveReloadClientScript() {
1406
+ return [
1407
+ "<script>",
1408
+ "(() => {",
1409
+ ' const source = new EventSource("/__messagevisor_catalog_reload");',
1410
+ ' source.addEventListener("reload", () => window.location.reload());',
1411
+ " source.onerror = () => {",
1412
+ " source.close();",
1413
+ " setTimeout(() => window.location.reload(), 1000);",
1414
+ " };",
1415
+ "})();",
1416
+ "</script>",
1417
+ ].join("");
1418
+ }
1419
+ function injectCatalogLiveReloadClient(html) {
1420
+ var script = getCatalogLiveReloadClientScript();
1421
+ if (html.includes("</body>")) {
1422
+ return html.replace("</body>", "".concat(script, "</body>"));
1423
+ }
1424
+ return "".concat(html).concat(script);
1425
+ }
1426
+ function createProjectWatcher(rootDirectoryPath, ignoredDirectoryPaths, onChange) {
1427
+ function shouldIgnore(targetPath) {
1428
+ var resolvedTargetPath = path.resolve(targetPath);
1429
+ return ignoredDirectoryPaths.some(function (ignoredDirectoryPath) {
1430
+ var resolvedIgnoredPath = path.resolve(ignoredDirectoryPath);
1431
+ return (resolvedTargetPath === resolvedIgnoredPath ||
1432
+ resolvedTargetPath.startsWith("".concat(resolvedIgnoredPath).concat(path.sep)));
1433
+ });
1434
+ }
1435
+ function collectSnapshotEntries(directoryPath, snapshotEntries) {
1436
+ if (shouldIgnore(directoryPath)) {
1437
+ return;
1438
+ }
1439
+ var entries = [];
1440
+ try {
1441
+ entries = fs.readdirSync(directoryPath, { withFileTypes: true });
1442
+ }
1443
+ catch (_a) {
1444
+ return;
1445
+ }
1446
+ for (var _i = 0, entries_2 = entries; _i < entries_2.length; _i++) {
1447
+ var entry = entries_2[_i];
1448
+ var entryPath = path.join(directoryPath, entry.name);
1449
+ if (shouldIgnore(entryPath)) {
1450
+ continue;
1451
+ }
1452
+ if (entry.isDirectory()) {
1453
+ collectSnapshotEntries(entryPath, snapshotEntries);
1454
+ continue;
1455
+ }
1456
+ if (!entry.isFile()) {
1457
+ continue;
1458
+ }
1459
+ try {
1460
+ var stat = fs.statSync(entryPath);
1461
+ var relativePath = path.relative(rootDirectoryPath, entryPath);
1462
+ snapshotEntries.push("".concat(relativePath, ":").concat(stat.size, ":").concat(stat.mtimeMs));
1463
+ }
1464
+ catch (_b) {
1465
+ // Ignore transient editor save races.
1466
+ }
1467
+ }
1468
+ }
1469
+ function createSnapshot() {
1470
+ var snapshotEntries = [];
1471
+ collectSnapshotEntries(rootDirectoryPath, snapshotEntries);
1472
+ snapshotEntries.sort();
1473
+ return snapshotEntries.join("|");
1474
+ }
1475
+ var previousSnapshot = createSnapshot();
1476
+ var interval = setInterval(function () {
1477
+ var nextSnapshot = createSnapshot();
1478
+ if (nextSnapshot === previousSnapshot) {
1479
+ return;
1480
+ }
1481
+ previousSnapshot = nextSnapshot;
1482
+ onChange(rootDirectoryPath);
1483
+ }, 250);
1484
+ return function () {
1485
+ clearInterval(interval);
1486
+ };
1487
+ }
1488
+ function serveCatalog(runtime_1, rootDirectoryPath_1, projectConfig_1, datasource_1) {
1489
+ return __awaiter(this, arguments, void 0, function (runtime, rootDirectoryPath, projectConfig, datasource, options) {
1490
+ function triggerReload() {
1491
+ liveReloadClients.forEach(function (client) {
1492
+ client.write("event: reload\n");
1493
+ client.write("data: reload\n\n");
1494
+ });
1495
+ }
1496
+ var outputDirectoryPath, port, liveReloadClients, server;
1497
+ if (options === void 0) { options = {}; }
1498
+ return __generator(this, function (_a) {
1499
+ switch (_a.label) {
1500
+ case 0:
1501
+ outputDirectoryPath = options.outDir
1502
+ ? path.resolve(rootDirectoryPath, options.outDir)
1503
+ : projectConfig.catalogDirectoryPath;
1504
+ if (!!fs.existsSync(outputDirectoryPath)) return [3 /*break*/, 2];
1505
+ return [4 /*yield*/, exportCatalog(runtime, rootDirectoryPath, projectConfig, datasource, {
1506
+ outDir: outputDirectoryPath,
1507
+ browserRouter: options.browserRouter,
1508
+ })];
1509
+ case 1:
1510
+ _a.sent();
1511
+ _a.label = 2;
1512
+ case 2:
1513
+ port = Number(options.port || 3000);
1514
+ liveReloadClients = new Set();
1515
+ server = http.createServer(function (request, response) {
1516
+ var requestedUrl = decodeURIComponent((request.url || "/").split("?")[0]);
1517
+ if (options.liveReload && requestedUrl === "/__messagevisor_catalog_reload") {
1518
+ response.writeHead(200, {
1519
+ "Content-Type": "text/event-stream",
1520
+ "Cache-Control": "no-cache, no-transform",
1521
+ Connection: "keep-alive",
1522
+ });
1523
+ response.write("\n");
1524
+ liveReloadClients.add(response);
1525
+ request.on("close", function () {
1526
+ liveReloadClients.delete(response);
1527
+ });
1528
+ return;
1529
+ }
1530
+ var requestedPath = requestedUrl === "/" ? "/index.html" : requestedUrl;
1531
+ var filePath = path.join(outputDirectoryPath, requestedPath);
1532
+ var safeFilePath = filePath.startsWith(outputDirectoryPath)
1533
+ ? filePath
1534
+ : path.join(outputDirectoryPath, "index.html");
1535
+ fs.readFile(safeFilePath, function (error, content) {
1536
+ if (!error) {
1537
+ if (options.liveReload && path.basename(safeFilePath) === "index.html") {
1538
+ var html = injectCatalogLiveReloadClient(content.toString("utf8"));
1539
+ response.writeHead(200, { "Content-Type": "text/html" });
1540
+ response.end(html);
1541
+ return;
1542
+ }
1543
+ response.writeHead(200, { "Content-Type": getContentType(safeFilePath) });
1544
+ response.end(content);
1545
+ return;
1546
+ }
1547
+ if (requestedPath.startsWith("/assets/") ||
1548
+ requestedPath.startsWith("/data/") ||
1549
+ requestedPath === "/favicon.ico") {
1550
+ response.writeHead(404, { "Content-Type": "text/plain" });
1551
+ response.end("404 Not Found");
1552
+ return;
1553
+ }
1554
+ fs.readFile(path.join(outputDirectoryPath, "index.html"), function (indexError, indexContent) {
1555
+ if (indexError) {
1556
+ response.writeHead(500, { "Content-Type": "text/plain" });
1557
+ response.end("Catalog index.html not found.");
1558
+ return;
1559
+ }
1560
+ if (options.liveReload) {
1561
+ response.writeHead(200, { "Content-Type": "text/html" });
1562
+ response.end(injectCatalogLiveReloadClient(indexContent.toString("utf8")));
1563
+ return;
1564
+ }
1565
+ response.writeHead(200, { "Content-Type": "text/html" });
1566
+ response.end(indexContent);
1567
+ });
1568
+ });
1569
+ });
1570
+ server.on("error", function (error) {
1571
+ console.error("Unable to serve catalog on http://127.0.0.1:".concat(port, "/"));
1572
+ console.error(error);
1573
+ process.exitCode = 1;
1574
+ });
1575
+ server.listen(port, "127.0.0.1", function () {
1576
+ console.log("Catalog running at http://127.0.0.1:".concat(port, "/"));
1577
+ });
1578
+ return [2 /*return*/, {
1579
+ close: function () {
1580
+ return new Promise(function (resolve, reject) {
1581
+ server.close(function (error) {
1582
+ if (error) {
1583
+ reject(error);
1584
+ return;
1585
+ }
1586
+ resolve();
1587
+ });
1588
+ });
1589
+ },
1590
+ triggerReload: triggerReload,
1591
+ }];
1592
+ }
1593
+ });
1594
+ });
1595
+ }
1596
+ function createCatalogApi(runtime) {
1597
+ return {
1598
+ exportCatalog: function (rootDirectoryPath, projectConfig, datasource, options) {
1599
+ if (options === void 0) { options = {}; }
1600
+ return exportCatalog(runtime, rootDirectoryPath, projectConfig, datasource, options);
1601
+ },
1602
+ serveCatalog: function (rootDirectoryPath, projectConfig, datasource, options) {
1603
+ if (options === void 0) { options = {}; }
1604
+ return serveCatalog(runtime, rootDirectoryPath, projectConfig, datasource, options);
1605
+ },
1606
+ };
1607
+ }
1608
+ function createCatalogPlugin(runtime, api) {
1609
+ var _this = this;
1610
+ if (api === void 0) { api = createCatalogApi(runtime); }
1611
+ return {
1612
+ command: "catalog [subcommand]",
1613
+ handler: function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
1614
+ var allowedSubcommands, browserRouter, server_1, outputDirectoryPath, ignoredDirectoryPaths, exportInFlight_1, exportQueued_1, queuedReason_1, debounceTimer_1, runExportAndReload_1, stopWatchingProject;
1615
+ var _this = this;
1616
+ var rootDirectoryPath = _b.rootDirectoryPath, projectConfig = _b.projectConfig, datasource = _b.datasource, parsed = _b.parsed;
1617
+ return __generator(this, function (_c) {
1618
+ switch (_c.label) {
1619
+ case 0:
1620
+ allowedSubcommands = ["export", "serve"];
1621
+ browserRouter = !(parsed.hashRouter || parsed["hash-router"]);
1622
+ if (!!parsed.subcommand) return [3 /*break*/, 3];
1623
+ return [4 /*yield*/, api.exportCatalog(rootDirectoryPath, projectConfig, datasource, {
1624
+ outDir: parsed.outDir,
1625
+ copyAssets: !parsed.noAssets,
1626
+ browserRouter: browserRouter,
1627
+ dev: true,
1628
+ })];
1629
+ case 1:
1630
+ _c.sent();
1631
+ return [4 /*yield*/, api.serveCatalog(rootDirectoryPath, projectConfig, datasource, {
1632
+ outDir: parsed.outDir,
1633
+ port: parsed.port || parsed.p,
1634
+ browserRouter: browserRouter,
1635
+ liveReload: true,
1636
+ })];
1637
+ case 2:
1638
+ server_1 = _c.sent();
1639
+ outputDirectoryPath = parsed.outDir
1640
+ ? path.resolve(rootDirectoryPath, parsed.outDir)
1641
+ : projectConfig.catalogDirectoryPath;
1642
+ ignoredDirectoryPaths = [
1643
+ path.join(rootDirectoryPath, ".git"),
1644
+ path.join(rootDirectoryPath, "node_modules"),
1645
+ path.join(rootDirectoryPath, ".messagevisor"),
1646
+ path.join(rootDirectoryPath, "datafiles"),
1647
+ path.join(rootDirectoryPath, "catalog"),
1648
+ path.join(rootDirectoryPath, "exports"),
1649
+ path.join(rootDirectoryPath, "imports"),
1650
+ outputDirectoryPath,
1651
+ ];
1652
+ exportInFlight_1 = false;
1653
+ exportQueued_1 = false;
1654
+ queuedReason_1 = null;
1655
+ debounceTimer_1 = null;
1656
+ runExportAndReload_1 = function (reason) { return __awaiter(_this, void 0, void 0, function () {
1657
+ var error_1, nextReason;
1658
+ return __generator(this, function (_a) {
1659
+ switch (_a.label) {
1660
+ case 0:
1661
+ if (exportInFlight_1) {
1662
+ exportQueued_1 = true;
1663
+ queuedReason_1 = queuedReason_1 || reason;
1664
+ return [2 /*return*/];
1665
+ }
1666
+ exportInFlight_1 = true;
1667
+ console.log("\n[catalog] Re-exporting because ".concat(reason));
1668
+ _a.label = 1;
1669
+ case 1:
1670
+ _a.trys.push([1, 3, 4, 5]);
1671
+ return [4 /*yield*/, api.exportCatalog(rootDirectoryPath, projectConfig, datasource, {
1672
+ outDir: parsed.outDir,
1673
+ copyAssets: !parsed.noAssets,
1674
+ browserRouter: browserRouter,
1675
+ dev: true,
1676
+ })];
1677
+ case 2:
1678
+ _a.sent();
1679
+ server_1.triggerReload();
1680
+ return [3 /*break*/, 5];
1681
+ case 3:
1682
+ error_1 = _a.sent();
1683
+ console.error("[catalog] Export failed during watch mode");
1684
+ console.error(error_1);
1685
+ return [3 /*break*/, 5];
1686
+ case 4:
1687
+ exportInFlight_1 = false;
1688
+ if (exportQueued_1) {
1689
+ nextReason = queuedReason_1 || "more project changes";
1690
+ exportQueued_1 = false;
1691
+ queuedReason_1 = null;
1692
+ void runExportAndReload_1(nextReason);
1693
+ }
1694
+ return [7 /*endfinally*/];
1695
+ case 5: return [2 /*return*/];
1696
+ }
1697
+ });
1698
+ }); };
1699
+ stopWatchingProject = createProjectWatcher(rootDirectoryPath, ignoredDirectoryPaths, function (changedPath) {
1700
+ var reason = "project change in ".concat(path.relative(rootDirectoryPath, changedPath) || ".");
1701
+ if (debounceTimer_1) {
1702
+ clearTimeout(debounceTimer_1);
1703
+ }
1704
+ debounceTimer_1 = setTimeout(function () {
1705
+ debounceTimer_1 = null;
1706
+ void runExportAndReload_1(reason);
1707
+ }, 150);
1708
+ });
1709
+ process.on("exit", stopWatchingProject);
1710
+ return [2 /*return*/];
1711
+ case 3:
1712
+ if (allowedSubcommands.indexOf(parsed.subcommand) === -1) {
1713
+ console.log("Please specify a subcommand: `export` or `serve`");
1714
+ return [2 /*return*/, false];
1715
+ }
1716
+ if (!(parsed.subcommand === "export")) return [3 /*break*/, 5];
1717
+ return [4 /*yield*/, api.exportCatalog(rootDirectoryPath, projectConfig, datasource, {
1718
+ outDir: parsed.outDir,
1719
+ copyAssets: !parsed.noAssets,
1720
+ browserRouter: browserRouter,
1721
+ })];
1722
+ case 4:
1723
+ _c.sent();
1724
+ _c.label = 5;
1725
+ case 5:
1726
+ if (!(parsed.subcommand === "serve")) return [3 /*break*/, 7];
1727
+ return [4 /*yield*/, api.serveCatalog(rootDirectoryPath, projectConfig, datasource, {
1728
+ outDir: parsed.outDir,
1729
+ port: parsed.port || parsed.p,
1730
+ browserRouter: browserRouter,
1731
+ })];
1732
+ case 6:
1733
+ _c.sent();
1734
+ _c.label = 7;
1735
+ case 7: return [2 /*return*/];
1736
+ }
1737
+ });
1738
+ }); },
1739
+ examples: [
1740
+ {
1741
+ command: "catalog",
1742
+ description: "generate and serve the static catalog locally",
1743
+ },
1744
+ {
1745
+ command: "catalog export",
1746
+ description: "generate static catalog with project data",
1747
+ },
1748
+ {
1749
+ command: "catalog serve",
1750
+ description: "serve the generated catalog locally",
1751
+ },
1752
+ ],
1753
+ };
1754
+ }
1755
+ //# sourceMappingURL=index.js.map