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