@shuo-li/i18n 1.0.9 → 1.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.
@@ -55,7 +55,6 @@ interface SSEMessage {
55
55
  type: string;
56
56
  langCode: string;
57
57
  moduleCode: string;
58
- /** SSE 消息携带的数据版本号,与本地 version 对比决定是否拉取 */
59
58
  version: number;
60
59
  storeName: string;
61
60
  }
@@ -74,7 +73,6 @@ interface ResourceRecord {
74
73
  key: string;
75
74
  moduleCode: string;
76
75
  langCode: string;
77
- /** 当前已存储数据的版本号(对应旧的 toSynTime) */
78
76
  version: number;
79
77
  resources: Record<string, unknown>;
80
78
  }
@@ -84,6 +82,8 @@ interface WorkerTask {
84
82
  moduleCode?: string;
85
83
  /** 全量拉取时为 0;SSE 增量拉取时为本地已有版本号 */
86
84
  version?: number;
85
+ /** 唯一标识,用于主线程回传 parsedData 时关联任务(Web 模式下必须) */
86
+ taskId?: number;
87
87
  trigger?: 'init-full' | 'sse';
88
88
  /** 经 buildParams 映射后的实际请求参数;未提供时 Worker 使用内部字段名 */
89
89
  params?: Record<string, unknown>;
@@ -93,6 +93,14 @@ interface WorkerRawDataMessage {
93
93
  task: WorkerTask;
94
94
  raw: unknown;
95
95
  }
96
+ /** Worker 写入一个模块后通知主线程(Web 模式,Worker 写 IDB) */
97
+ interface WorkerModuleLoadedMessage {
98
+ type: 'moduleLoaded';
99
+ storeName: string;
100
+ moduleCode: string;
101
+ langCode: string;
102
+ version: number;
103
+ }
96
104
  interface WorkerModuleErrorMessage {
97
105
  type: 'moduleError';
98
106
  storeName: string;
@@ -106,7 +114,7 @@ interface WorkerErrorMessage {
106
114
  type: 'error';
107
115
  message?: string;
108
116
  }
109
- type WorkerOutMessage = WorkerRawDataMessage | WorkerModuleErrorMessage | WorkerDoneMessage | WorkerErrorMessage;
117
+ type WorkerOutMessage = WorkerRawDataMessage | WorkerModuleLoadedMessage | WorkerModuleErrorMessage | WorkerDoneMessage | WorkerErrorMessage;
110
118
  interface WorkerLike {
111
119
  postMessage(data: unknown): void;
112
120
  onMessage(handler: (data: WorkerOutMessage) => void): void;
@@ -122,4 +130,4 @@ declare function getAllRecordsByModule(moduleCode: string): Promise<ResourceReco
122
130
  declare const I18N_RESOURCES_UPDATED_EVENT = "golucky:i18n-resources-updated";
123
131
  declare function emitI18nResourcesUpdated(): void;
124
132
 
125
- export { I18N_RESOURCES_UPDATED_EVENT as I, type PullLangBlock as P, type ResourceRecord as R, type SSEMessage as S, type WorkerLike as W, getResource as a, type I18nInitOptions as b, closeSSE as c, type StandardPullParams as d, ensureModules as e, type StoreConfig as f, getAllRecordsByModule as g, emitI18nResourcesUpdated as h, initI18n as i };
133
+ export { I18N_RESOURCES_UPDATED_EVENT as I, type PullLangBlock as P, type ResourceRecord as R, type SSEMessage as S, type WorkerLike as W, getResource as a, type I18nInitOptions as b, closeSSE as c, type StandardPullParams as d, ensureModules as e, type StoreConfig as f, getAllRecordsByModule as g, emitI18nResourcesUpdated as h, initI18n as i, type I18nValue as j };
@@ -55,7 +55,6 @@ interface SSEMessage {
55
55
  type: string;
56
56
  langCode: string;
57
57
  moduleCode: string;
58
- /** SSE 消息携带的数据版本号,与本地 version 对比决定是否拉取 */
59
58
  version: number;
60
59
  storeName: string;
61
60
  }
@@ -74,7 +73,6 @@ interface ResourceRecord {
74
73
  key: string;
75
74
  moduleCode: string;
76
75
  langCode: string;
77
- /** 当前已存储数据的版本号(对应旧的 toSynTime) */
78
76
  version: number;
79
77
  resources: Record<string, unknown>;
80
78
  }
@@ -84,6 +82,8 @@ interface WorkerTask {
84
82
  moduleCode?: string;
85
83
  /** 全量拉取时为 0;SSE 增量拉取时为本地已有版本号 */
86
84
  version?: number;
85
+ /** 唯一标识,用于主线程回传 parsedData 时关联任务(Web 模式下必须) */
86
+ taskId?: number;
87
87
  trigger?: 'init-full' | 'sse';
88
88
  /** 经 buildParams 映射后的实际请求参数;未提供时 Worker 使用内部字段名 */
89
89
  params?: Record<string, unknown>;
@@ -93,6 +93,14 @@ interface WorkerRawDataMessage {
93
93
  task: WorkerTask;
94
94
  raw: unknown;
95
95
  }
96
+ /** Worker 写入一个模块后通知主线程(Web 模式,Worker 写 IDB) */
97
+ interface WorkerModuleLoadedMessage {
98
+ type: 'moduleLoaded';
99
+ storeName: string;
100
+ moduleCode: string;
101
+ langCode: string;
102
+ version: number;
103
+ }
96
104
  interface WorkerModuleErrorMessage {
97
105
  type: 'moduleError';
98
106
  storeName: string;
@@ -106,7 +114,7 @@ interface WorkerErrorMessage {
106
114
  type: 'error';
107
115
  message?: string;
108
116
  }
109
- type WorkerOutMessage = WorkerRawDataMessage | WorkerModuleErrorMessage | WorkerDoneMessage | WorkerErrorMessage;
117
+ type WorkerOutMessage = WorkerRawDataMessage | WorkerModuleLoadedMessage | WorkerModuleErrorMessage | WorkerDoneMessage | WorkerErrorMessage;
110
118
  interface WorkerLike {
111
119
  postMessage(data: unknown): void;
112
120
  onMessage(handler: (data: WorkerOutMessage) => void): void;
@@ -122,4 +130,4 @@ declare function getAllRecordsByModule(moduleCode: string): Promise<ResourceReco
122
130
  declare const I18N_RESOURCES_UPDATED_EVENT = "golucky:i18n-resources-updated";
123
131
  declare function emitI18nResourcesUpdated(): void;
124
132
 
125
- export { I18N_RESOURCES_UPDATED_EVENT as I, type PullLangBlock as P, type ResourceRecord as R, type SSEMessage as S, type WorkerLike as W, getResource as a, type I18nInitOptions as b, closeSSE as c, type StandardPullParams as d, ensureModules as e, type StoreConfig as f, getAllRecordsByModule as g, emitI18nResourcesUpdated as h, initI18n as i };
133
+ export { I18N_RESOURCES_UPDATED_EVENT as I, type PullLangBlock as P, type ResourceRecord as R, type SSEMessage as S, type WorkerLike as W, getResource as a, type I18nInitOptions as b, closeSSE as c, type StandardPullParams as d, ensureModules as e, type StoreConfig as f, getAllRecordsByModule as g, emitI18nResourcesUpdated as h, initI18n as i, type I18nValue as j };
@@ -1,3 +1,12 @@
1
+ import {
2
+ buildKey,
3
+ deepMerge,
4
+ flatToNested,
5
+ parseI18nValues,
6
+ toDefaultParams,
7
+ toQueryString
8
+ } from "./chunk-NEXKR7GY.js";
9
+
1
10
  // src/core/cacheEvents.ts
2
11
  var I18N_RESOURCES_UPDATED_EVENT = "golucky:i18n-resources-updated";
3
12
  function emitI18nResourcesUpdated() {
@@ -136,12 +145,31 @@ var WorkerManager = class {
136
145
  }
137
146
  const worker = createWorker();
138
147
  this.worker = worker;
148
+ const workerWritesDB = typeof callbacks.transformRaw === "function";
139
149
  worker.onMessage((msg) => {
140
150
  if (msg.type === "rawData") {
141
- const p = callbacks.onRawData(msg.task, msg.raw).catch(() => {
142
- });
143
- this.pendingCallbacks.add(p);
144
- p.finally(() => this.pendingCallbacks.delete(p));
151
+ if (workerWritesDB && callbacks.transformRaw) {
152
+ let blocks;
153
+ try {
154
+ blocks = callbacks.transformRaw(msg.task, msg.raw);
155
+ } catch (err) {
156
+ console.error("[i18n] transform failed", msg.task, err);
157
+ blocks = [];
158
+ }
159
+ worker.postMessage({ type: "parsedData", taskId: msg.task.taskId, blocks });
160
+ } else if (callbacks.onRawData) {
161
+ const p = callbacks.onRawData(msg.task, msg.raw).catch(() => {
162
+ });
163
+ this.pendingCallbacks.add(p);
164
+ p.finally(() => this.pendingCallbacks.delete(p));
165
+ }
166
+ } else if (msg.type === "moduleLoaded") {
167
+ if (callbacks.onModuleLoaded) {
168
+ const p = callbacks.onModuleLoaded(msg).catch(() => {
169
+ });
170
+ this.pendingCallbacks.add(p);
171
+ p.finally(() => this.pendingCallbacks.delete(p));
172
+ }
145
173
  } else if (msg.type === "moduleError") {
146
174
  callbacks.onModuleError?.(msg);
147
175
  } else if (msg.type === "done" || msg.type === "error") {
@@ -169,61 +197,6 @@ var WorkerManager = class {
169
197
  }
170
198
  };
171
199
 
172
- // src/core/utils.ts
173
- function buildKey(moduleCode, langCode, store) {
174
- return store.cacheGroupKey ? `${moduleCode}_${langCode}_${store.cacheGroupKey}` : `${moduleCode}_${langCode}`;
175
- }
176
- function flatToNested(flat) {
177
- const result = {};
178
- for (const [key, value] of Object.entries(flat)) {
179
- const parts = key.split(".");
180
- let cur = result;
181
- for (let i = 0; i < parts.length - 1; i++) {
182
- const part = parts[i];
183
- if (typeof cur[part] !== "object" || cur[part] === null) {
184
- cur[part] = {};
185
- }
186
- cur = cur[part];
187
- }
188
- cur[parts[parts.length - 1]] = value;
189
- }
190
- return result;
191
- }
192
- function deepMerge(target, source) {
193
- const result = { ...target };
194
- for (const [key, sv] of Object.entries(source)) {
195
- const tv = result[key];
196
- if (sv !== null && typeof sv === "object" && !Array.isArray(sv) && tv !== null && typeof tv === "object" && !Array.isArray(tv)) {
197
- result[key] = deepMerge(tv, sv);
198
- } else {
199
- result[key] = sv;
200
- }
201
- }
202
- return result;
203
- }
204
- function parseI18nValues(values) {
205
- const result = {};
206
- for (const { termCode, langValue } of values) {
207
- if (termCode && langValue !== void 0) {
208
- result[termCode] = langValue ?? "";
209
- }
210
- }
211
- return result;
212
- }
213
- function toDefaultParams(p) {
214
- const result = {};
215
- if (p?.storeName) result["storeName"] = p.storeName;
216
- if (p?.langCode) result["langCode"] = p.langCode;
217
- if (p?.moduleCode) result["moduleCode"] = p.moduleCode;
218
- if (p?.version != null) result["version"] = String(p.version);
219
- return result;
220
- }
221
- function toQueryString(params) {
222
- return new URLSearchParams(
223
- Object.entries(params).filter(([, v]) => v != null).map(([k, v]) => [k, String(v)])
224
- ).toString();
225
- }
226
-
227
200
  // src/core/manager.ts
228
201
  var PRIORITY_MODULES = ["ENUMS", "CUSTOMER"];
229
202
  var currentLang = "zh_CN";
@@ -236,6 +209,7 @@ var resolvedLanguages = [];
236
209
  var unloginPullStarted = false;
237
210
  var managerOptions = null;
238
211
  var initOptions = null;
212
+ var taskIdCounter = 0;
239
213
  var loadedModules = /* @__PURE__ */ new Set();
240
214
  var loadingModules = /* @__PURE__ */ new Set();
241
215
  var sseClient = new SSEClient();
@@ -316,7 +290,7 @@ async function getResource(moduleCode, langCode) {
316
290
  if (result.status === "rejected") continue;
317
291
  const record = result.value;
318
292
  if (!record?.resources) continue;
319
- merged = i === 0 ? deepMerge(merged, record.resources) : deepMerge(merged, flatToNested(record.resources));
293
+ merged = deepMerge(merged, record.resources);
320
294
  }
321
295
  return merged;
322
296
  }
@@ -372,24 +346,15 @@ async function _initI18n(options) {
372
346
  startSSE(options);
373
347
  }
374
348
  }
375
- var CACHE_VERSION_KEY = "__meta__:cache_version";
376
349
  async function checkCacheVersion(storage, options) {
377
350
  if (options.version == null) return;
378
- const baseStoreName = resolvedStores[0].name;
379
351
  const current = String(options.version);
380
- const record = await storage.getRecord(baseStoreName, CACHE_VERSION_KEY).catch(() => void 0);
381
- const stored = record?.resources?.["value"];
352
+ const stored = await storage.getMeta("cache_version").catch(() => null);
382
353
  if (stored === current) return;
383
354
  for (const store of options.stores) {
384
355
  await storage.clearStore(store.name);
385
356
  }
386
- await storage.putRecord(baseStoreName, {
387
- key: CACHE_VERSION_KEY,
388
- moduleCode: "__meta__",
389
- langCode: "__meta__",
390
- version: 0,
391
- resources: { value: current }
392
- });
357
+ await storage.setMeta("cache_version", current);
393
358
  }
394
359
  async function doUnloginPull(storage, options) {
395
360
  const { apiContext } = options;
@@ -398,9 +363,8 @@ async function doUnloginPull(storage, options) {
398
363
  let blocks;
399
364
  try {
400
365
  blocks = await doFetch(apiContext.unloginPull, options);
401
- } catch {
402
- await injectCurrentLanguageModules(currentLang);
403
- await i18n.changeLanguage(currentLang);
366
+ } catch (err) {
367
+ console.error("[i18n] unloginPull \u8BF7\u6C42\u5931\u8D25\uFF0C\u964D\u7EA7\u9759\u6001\u515C\u5E95", err);
404
368
  emitI18nResourcesUpdated();
405
369
  return;
406
370
  }
@@ -408,10 +372,10 @@ async function doUnloginPull(storage, options) {
408
372
  for (const mod of block.modules ?? []) {
409
373
  const key = buildKey(mod.moduleCode, block.langCode, baseStore);
410
374
  const existing = await storage.getRecord(baseStore.name, key);
411
- const parsed = parseI18nValues(mod.i18nValues ?? []);
375
+ const flat = parseI18nValues(mod.i18nValues);
412
376
  const resources = deepMerge(
413
377
  existing?.resources ?? {},
414
- flatToNested(parsed)
378
+ flatToNested(flat)
415
379
  );
416
380
  await storage.putRecord(baseStore.name, {
417
381
  key,
@@ -431,16 +395,13 @@ async function startWorkerFull(options) {
431
395
  const pull = apiContext.pull;
432
396
  const tasks = [];
433
397
  for (const store of resolvedStores) {
434
- for (const lang of resolvedLanguages) {
435
- for (const module of sortedModules()) {
436
- const internal = { storeName: store.name, langCode: lang, moduleCode: module, version: 0 };
437
- tasks.push({
438
- ...internal,
439
- trigger: "init-full",
440
- params: pull.buildParams ? pull.buildParams(internal) : void 0
441
- });
442
- }
443
- }
398
+ const internal = { storeName: store.name };
399
+ tasks.push({
400
+ storeName: store.name,
401
+ taskId: ++taskIdCounter,
402
+ trigger: "init-full",
403
+ params: pull.buildParams ? pull.buildParams(internal) : void 0
404
+ });
444
405
  }
445
406
  await runWorker(options, tasks, pull);
446
407
  }
@@ -448,18 +409,43 @@ function runWorker(options, tasks, pull) {
448
409
  return new Promise((resolve, reject) => {
449
410
  const { apiContext } = options;
450
411
  const storage = managerOptions.storage;
451
- workerManager.start(
452
- managerOptions.createWorker,
453
- {
454
- baseURL: apiContext.baseURL,
455
- headers: apiContext.getHeaders(),
456
- pullPath: pull.path,
457
- pullMethod: pull.method ?? "GET",
458
- tasks
459
- },
460
- {
412
+ const workerWritesDB = managerOptions.workerWritesDB ?? false;
413
+ const payload = {
414
+ baseURL: apiContext.baseURL,
415
+ headers: apiContext.getHeaders(),
416
+ pullPath: pull.path,
417
+ pullMethod: pull.method ?? "GET",
418
+ tasks,
419
+ ...workerWritesDB ? { storeConfigs: resolvedStores } : {}
420
+ };
421
+ if (workerWritesDB) {
422
+ workerManager.start(managerOptions.createWorker, payload, {
423
+ transformRaw: (task, raw) => {
424
+ try {
425
+ return pull.transform ? pull.transform(raw) : raw;
426
+ } catch (err) {
427
+ console.error("[i18n] pull transform \u5931\u8D25", task, err);
428
+ return [];
429
+ }
430
+ },
431
+ onModuleLoaded: async (info) => {
432
+ await onModuleLoaded(info);
433
+ },
434
+ onModuleError: () => {
435
+ },
436
+ onDone: resolve,
437
+ onError: () => reject(new Error("[i18n] Worker fatal error"))
438
+ });
439
+ } else {
440
+ workerManager.start(managerOptions.createWorker, payload, {
461
441
  onRawData: async (task, raw) => {
462
- const blocks = pull.transform ? pull.transform(raw) : raw;
442
+ let blocks;
443
+ try {
444
+ blocks = pull.transform ? pull.transform(raw) : raw;
445
+ } catch (err) {
446
+ console.error("[i18n] pull transform \u5931\u8D25", task, err);
447
+ return;
448
+ }
463
449
  const store = resolvedStores.find((s) => s.name === task.storeName);
464
450
  if (!store) return;
465
451
  const storeIndex = resolvedStores.indexOf(store);
@@ -468,11 +454,8 @@ function runWorker(options, tasks, pull) {
468
454
  const key = buildKey(mod.moduleCode, block.langCode, store);
469
455
  const existing = await storage.getRecord(store.name, key);
470
456
  if (existing && mod.version <= existing.version) continue;
471
- const parsed = parseI18nValues(mod.i18nValues ?? []);
472
- const resources = storeIndex === 0 ? deepMerge(
473
- existing?.resources ?? {},
474
- flatToNested(parsed)
475
- ) : { ...existing?.resources ?? {}, ...parsed };
457
+ const flat = parseI18nValues(mod.i18nValues);
458
+ const resources = storeIndex === 0 ? deepMerge(existing?.resources ?? {}, flatToNested(flat)) : { ...existing?.resources ?? {}, ...flat };
476
459
  await storage.putRecord(store.name, {
477
460
  key,
478
461
  moduleCode: mod.moduleCode,
@@ -482,19 +465,19 @@ function runWorker(options, tasks, pull) {
482
465
  });
483
466
  await onModuleLoaded({
484
467
  storeName: task.storeName,
485
- langCode: block.langCode,
486
468
  moduleCode: mod.moduleCode,
469
+ langCode: block.langCode,
487
470
  version: mod.version
488
471
  });
489
472
  }
490
473
  }
491
474
  },
492
- onModuleError: (_data) => {
475
+ onModuleError: () => {
493
476
  },
494
477
  onDone: resolve,
495
478
  onError: () => reject(new Error("[i18n] Worker fatal error"))
496
- }
497
- );
479
+ });
480
+ }
498
481
  });
499
482
  }
500
483
  async function onModuleLoaded(data) {
@@ -618,16 +601,8 @@ async function pullAndStore(task, fromVersion, options) {
618
601
  const key = buildKey(mod.moduleCode, block.langCode, store);
619
602
  const existing = await storage.getRecord(store.name, key);
620
603
  if (mod.version <= (existing?.version ?? 0)) continue;
621
- let resources;
622
- const parsed = parseI18nValues(mod.i18nValues ?? []);
623
- if (storeIndex === 0) {
624
- resources = deepMerge(
625
- existing?.resources ?? {},
626
- flatToNested(parsed)
627
- );
628
- } else {
629
- resources = { ...existing?.resources ?? {}, ...parsed };
630
- }
604
+ const flat = parseI18nValues(mod.i18nValues);
605
+ const resources = storeIndex === 0 ? deepMerge(existing?.resources ?? {}, flatToNested(flat)) : { ...existing?.resources ?? {}, ...flat };
631
606
  const version = Math.max(mod.version, task.targetVersion);
632
607
  await storage.putRecord(store.name, {
633
608
  key,
@@ -0,0 +1,61 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/core/utils.ts
2
+ function buildKey(moduleCode, langCode, store) {
3
+ return store.cacheGroupKey ? `${moduleCode}_${langCode}_${store.cacheGroupKey}` : `${moduleCode}_${langCode}`;
4
+ }
5
+ function parseI18nValues(values) {
6
+ const result = {};
7
+ for (const v of values) {
8
+ if (v.termCode) result[v.termCode] = _nullishCoalesce(v.langValue, () => ( ""));
9
+ }
10
+ return result;
11
+ }
12
+ function flatToNested(flat) {
13
+ const result = {};
14
+ for (const [key, value] of Object.entries(flat)) {
15
+ const parts = key.split(".");
16
+ let cur = result;
17
+ for (let i = 0; i < parts.length - 1; i++) {
18
+ const part = parts[i];
19
+ if (typeof cur[part] !== "object" || cur[part] === null) {
20
+ cur[part] = {};
21
+ }
22
+ cur = cur[part];
23
+ }
24
+ cur[parts[parts.length - 1]] = value;
25
+ }
26
+ return result;
27
+ }
28
+ function deepMerge(target, source) {
29
+ const result = { ...target };
30
+ for (const [key, sv] of Object.entries(source)) {
31
+ const tv = result[key];
32
+ if (sv !== null && typeof sv === "object" && !Array.isArray(sv) && tv !== null && typeof tv === "object" && !Array.isArray(tv)) {
33
+ result[key] = deepMerge(tv, sv);
34
+ } else {
35
+ result[key] = sv;
36
+ }
37
+ }
38
+ return result;
39
+ }
40
+ function toDefaultParams(p) {
41
+ const result = {};
42
+ if (_optionalChain([p, 'optionalAccess', _ => _.storeName])) result["storeName"] = p.storeName;
43
+ if (_optionalChain([p, 'optionalAccess', _2 => _2.langCode])) result["langCode"] = p.langCode;
44
+ if (_optionalChain([p, 'optionalAccess', _3 => _3.moduleCode])) result["moduleCode"] = p.moduleCode;
45
+ if (_optionalChain([p, 'optionalAccess', _4 => _4.version]) != null) result["version"] = String(p.version);
46
+ return result;
47
+ }
48
+ function toQueryString(params) {
49
+ return new URLSearchParams(
50
+ Object.entries(params).filter(([, v]) => v != null).map(([k, v]) => [k, String(v)])
51
+ ).toString();
52
+ }
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+ exports.buildKey = buildKey; exports.parseI18nValues = parseI18nValues; exports.flatToNested = flatToNested; exports.deepMerge = deepMerge; exports.toDefaultParams = toDefaultParams; exports.toQueryString = toQueryString;
@@ -0,0 +1,61 @@
1
+ // src/core/utils.ts
2
+ function buildKey(moduleCode, langCode, store) {
3
+ return store.cacheGroupKey ? `${moduleCode}_${langCode}_${store.cacheGroupKey}` : `${moduleCode}_${langCode}`;
4
+ }
5
+ function parseI18nValues(values) {
6
+ const result = {};
7
+ for (const v of values) {
8
+ if (v.termCode) result[v.termCode] = v.langValue ?? "";
9
+ }
10
+ return result;
11
+ }
12
+ function flatToNested(flat) {
13
+ const result = {};
14
+ for (const [key, value] of Object.entries(flat)) {
15
+ const parts = key.split(".");
16
+ let cur = result;
17
+ for (let i = 0; i < parts.length - 1; i++) {
18
+ const part = parts[i];
19
+ if (typeof cur[part] !== "object" || cur[part] === null) {
20
+ cur[part] = {};
21
+ }
22
+ cur = cur[part];
23
+ }
24
+ cur[parts[parts.length - 1]] = value;
25
+ }
26
+ return result;
27
+ }
28
+ function deepMerge(target, source) {
29
+ const result = { ...target };
30
+ for (const [key, sv] of Object.entries(source)) {
31
+ const tv = result[key];
32
+ if (sv !== null && typeof sv === "object" && !Array.isArray(sv) && tv !== null && typeof tv === "object" && !Array.isArray(tv)) {
33
+ result[key] = deepMerge(tv, sv);
34
+ } else {
35
+ result[key] = sv;
36
+ }
37
+ }
38
+ return result;
39
+ }
40
+ function toDefaultParams(p) {
41
+ const result = {};
42
+ if (p?.storeName) result["storeName"] = p.storeName;
43
+ if (p?.langCode) result["langCode"] = p.langCode;
44
+ if (p?.moduleCode) result["moduleCode"] = p.moduleCode;
45
+ if (p?.version != null) result["version"] = String(p.version);
46
+ return result;
47
+ }
48
+ function toQueryString(params) {
49
+ return new URLSearchParams(
50
+ Object.entries(params).filter(([, v]) => v != null).map(([k, v]) => [k, String(v)])
51
+ ).toString();
52
+ }
53
+
54
+ export {
55
+ buildKey,
56
+ parseI18nValues,
57
+ flatToNested,
58
+ deepMerge,
59
+ toDefaultParams,
60
+ toQueryString
61
+ };