@inlang/sdk 0.7.0 → 0.9.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 (42) hide show
  1. package/dist/adapter/solidAdapter.test.js +6 -6
  2. package/dist/createMessagesQuery.test.js +9 -0
  3. package/dist/loadProject.d.ts.map +1 -1
  4. package/dist/loadProject.js +8 -4
  5. package/dist/loadProject.test.js +14 -15
  6. package/dist/messages/variant.d.ts +4 -4
  7. package/dist/messages/variant.d.ts.map +1 -1
  8. package/dist/messages/variant.js +55 -55
  9. package/dist/messages/variant.test.js +102 -45
  10. package/dist/resolve-modules/plugins/resolvePlugins.d.ts.map +1 -1
  11. package/dist/resolve-modules/plugins/resolvePlugins.js +3 -5
  12. package/dist/resolve-modules/plugins/resolvePlugins.test.js +79 -49
  13. package/dist/resolve-modules/plugins/types.d.ts +4 -5
  14. package/dist/resolve-modules/plugins/types.d.ts.map +1 -1
  15. package/dist/test-utilities/createMessage.d.ts +1 -1
  16. package/dist/test-utilities/createMessage.js +1 -1
  17. package/dist/test-utilities/createMessage.test.js +4 -4
  18. package/package.json +1 -1
  19. package/src/adapter/solidAdapter.test.ts +14 -14
  20. package/src/adapter/solidAdapter.ts +1 -1
  21. package/src/api.ts +2 -2
  22. package/src/createMessageLintReportsQuery.ts +4 -4
  23. package/src/createMessagesQuery.test.ts +30 -17
  24. package/src/createMessagesQuery.ts +2 -2
  25. package/src/lint/message/lintMessages.ts +1 -1
  26. package/src/lint/message/lintSingleMessage.test.ts +1 -1
  27. package/src/lint/message/lintSingleMessage.ts +2 -2
  28. package/src/loadProject.test.ts +24 -27
  29. package/src/loadProject.ts +20 -16
  30. package/src/messages/errors.ts +2 -2
  31. package/src/messages/variant.test.ts +113 -49
  32. package/src/messages/variant.ts +73 -67
  33. package/src/parseConfig.ts +2 -2
  34. package/src/resolve-modules/import.test.ts +2 -2
  35. package/src/resolve-modules/import.ts +1 -1
  36. package/src/resolve-modules/message-lint-rules/resolveMessageLintRules.ts +1 -1
  37. package/src/resolve-modules/plugins/resolvePlugins.test.ts +96 -64
  38. package/src/resolve-modules/plugins/resolvePlugins.ts +19 -21
  39. package/src/resolve-modules/plugins/types.ts +4 -8
  40. package/src/resolve-modules/resolveModules.ts +4 -4
  41. package/src/test-utilities/createMessage.test.ts +7 -7
  42. package/src/test-utilities/createMessage.ts +1 -1
@@ -32,7 +32,7 @@ const exampleMessages = [
32
32
  variants: [
33
33
  {
34
34
  languageTag: "en",
35
- match: {},
35
+ match: [],
36
36
  pattern: [
37
37
  {
38
38
  type: "Text",
@@ -48,7 +48,7 @@ const exampleMessages = [
48
48
  variants: [
49
49
  {
50
50
  languageTag: "en",
51
- match: {},
51
+ match: [],
52
52
  pattern: [
53
53
  {
54
54
  type: "Text",
@@ -143,7 +143,7 @@ describe("messages", () => {
143
143
  description: {
144
144
  en: "wo",
145
145
  },
146
- loadMessages: ({ languageTags }) => (languageTags.length ? exampleMessages : []),
146
+ loadMessages: ({ settings }) => (settings.languageTags.length ? exampleMessages : []),
147
147
  saveMessages: () => undefined,
148
148
  };
149
149
  const mockImport = async () => ({ default: mockPlugin });
@@ -190,7 +190,7 @@ describe("messages", () => {
190
190
  variants: [
191
191
  {
192
192
  languageTag: "en",
193
- match: {},
193
+ match: [],
194
194
  pattern: [
195
195
  {
196
196
  type: "Text",
@@ -254,7 +254,7 @@ describe("lint", () => {
254
254
  where: { id: "a" },
255
255
  data: {
256
256
  ...exampleMessages[0],
257
- variants: [{ languageTag: "en", match: {}, pattern: [{ type: "Text", value: "new" }] }],
257
+ variants: [{ languageTag: "en", match: [], pattern: [{ type: "Text", value: "new" }] }],
258
258
  },
259
259
  });
260
260
  expect(counter).toBe(1);
@@ -264,7 +264,7 @@ describe("lint", () => {
264
264
  where: { id: "a" },
265
265
  data: {
266
266
  ...exampleMessages[0],
267
- variants: [{ languageTag: "en", match: {}, pattern: [{ type: "Text", value: "new" }] }],
267
+ variants: [{ languageTag: "en", match: [], pattern: [{ type: "Text", value: "new" }] }],
268
268
  },
269
269
  });
270
270
  expect(counter).toBe(6);
@@ -276,6 +276,15 @@ describe("reactivity", () => {
276
276
  expect(Object.values(messages)[0].variants.find((variant) => variant.languageTag === "en")
277
277
  .pattern[0].value).toBe("after");
278
278
  });
279
+ it("should not mutate messages signal outside the query when using the query", async () => {
280
+ const [inputMessages] = createSignal([createMessage("1", { en: "before" })]);
281
+ const query = createMessagesQuery(inputMessages);
282
+ let messages = undefined;
283
+ await createChangeListener(() => (messages = query.getAll()));
284
+ expect(Object.values(messages)).toHaveLength(1);
285
+ query.create({ data: createMessage("2", { en: "" }) });
286
+ expect(inputMessages().length).toBe(1);
287
+ });
279
288
  });
280
289
  });
281
290
  it("instances should not share state", async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"loadProject.d.ts","sourceRoot":"","sources":["../src/loadProject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EAGb,YAAY,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,4BAA4B,CAAA;AAahF,OAAO,EAA4B,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAMjG;;;;;;GAMG;AACH,eAAO,MAAM,WAAW;sBACL,MAAM;eACb,uBAAuB;;qBAElB,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;MAC5D,QAAQ,aAAa,CAiLxB,CAAA;AAsGD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
1
+ {"version":3,"file":"loadProject.d.ts","sourceRoot":"","sources":["../src/loadProject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EAGb,YAAY,EACZ,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,4BAA4B,CAAA;AAahF,OAAO,EAA4B,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAMjG;;;;;;GAMG;AACH,eAAO,MAAM,WAAW;sBACL,MAAM;eACb,uBAAuB;;qBAElB,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;MAC5D,QAAQ,aAAa,CAqLxB,CAAA;AAsGD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAQtE"}
@@ -25,7 +25,9 @@ export const loadProject = async (args) => {
25
25
  loadSettings({ settingsFilePath: args.settingsFilePath, nodeishFs: args.nodeishFs })
26
26
  .then((settings) => {
27
27
  setSettings(settings);
28
- args._capture?.("SDK used settings", settings);
28
+ // rename settings to get a convenient access to the data in Posthog
29
+ const project_settings = settings;
30
+ args._capture?.("SDK used settings", { project_settings });
29
31
  })
30
32
  .catch((err) => {
31
33
  markInitAsFailed(err);
@@ -75,8 +77,7 @@ export const loadProject = async (args) => {
75
77
  return;
76
78
  }
77
79
  makeTrulyAsync(_resolvedModules.resolvedPluginApi.loadMessages({
78
- languageTags: settingsValue.languageTags,
79
- sourceLanguageTag: settingsValue.sourceLanguageTag,
80
+ settings: settingsValue,
80
81
  }))
81
82
  .then((messages) => {
82
83
  setMessages(messages);
@@ -115,7 +116,10 @@ export const loadProject = async (args) => {
115
116
  const lintReportsQuery = createMessageLintReportsQuery(messages, settings, installedMessageLintRules, resolvedModules);
116
117
  const debouncedSave = skipFirst(debounce(500, async (newMessages) => {
117
118
  try {
118
- await resolvedModules()?.resolvedPluginApi.saveMessages({ messages: newMessages });
119
+ await resolvedModules()?.resolvedPluginApi.saveMessages({
120
+ settings: settingsValue,
121
+ messages: newMessages,
122
+ });
119
123
  }
120
124
  catch (err) {
121
125
  throw new PluginSaveMessagesError("Error in saving messages", {
@@ -41,7 +41,7 @@ const exampleMessages = [
41
41
  variants: [
42
42
  {
43
43
  languageTag: "en",
44
- match: {},
44
+ match: [],
45
45
  pattern: [
46
46
  {
47
47
  type: "Text",
@@ -57,7 +57,7 @@ const exampleMessages = [
57
57
  variants: [
58
58
  {
59
59
  languageTag: "en",
60
- match: {},
60
+ match: [],
61
61
  pattern: [
62
62
  {
63
63
  type: "Text",
@@ -399,14 +399,15 @@ describe("functionality", () => {
399
399
  describe("query", () => {
400
400
  it("should call saveMessages() on updates", async () => {
401
401
  const fs = createNodeishMemoryFs();
402
- await fs.writeFile("./project.inlang.json", JSON.stringify({
402
+ const settings = {
403
403
  sourceLanguageTag: "en",
404
404
  languageTags: ["en", "de"],
405
405
  modules: ["plugin.js"],
406
406
  "plugin.project.json": {
407
407
  pathPattern: "./resources/{languageTag}.json",
408
408
  },
409
- }));
409
+ };
410
+ await fs.writeFile("./project.inlang.json", JSON.stringify(settings));
410
411
  await fs.mkdir("./resources");
411
412
  const mockSaveFn = vi.fn();
412
413
  const _mockPlugin = {
@@ -434,7 +435,7 @@ describe("functionality", () => {
434
435
  variants: [
435
436
  {
436
437
  languageTag: "en",
437
- match: {},
438
+ match: [],
438
439
  pattern: [
439
440
  {
440
441
  type: "Text",
@@ -444,7 +445,7 @@ describe("functionality", () => {
444
445
  },
445
446
  {
446
447
  languageTag: "de",
447
- match: {},
448
+ match: [],
448
449
  pattern: [
449
450
  {
450
451
  type: "Text",
@@ -463,7 +464,7 @@ describe("functionality", () => {
463
464
  variants: [
464
465
  {
465
466
  languageTag: "en",
466
- match: {},
467
+ match: [],
467
468
  pattern: [
468
469
  {
469
470
  type: "Text",
@@ -473,7 +474,7 @@ describe("functionality", () => {
473
474
  },
474
475
  {
475
476
  languageTag: "de",
476
- match: {},
477
+ match: [],
477
478
  pattern: [
478
479
  {
479
480
  type: "Text",
@@ -486,9 +487,7 @@ describe("functionality", () => {
486
487
  });
487
488
  await new Promise((resolve) => setTimeout(resolve, 510));
488
489
  expect(mockSaveFn.mock.calls.length).toBe(1);
489
- expect(mockSaveFn.mock.calls[0][0].settings).toStrictEqual({
490
- pathPattern: "./resources/{languageTag}.json",
491
- });
490
+ expect(mockSaveFn.mock.calls[0][0].settings).toStrictEqual(settings);
492
491
  expect(Object.values(mockSaveFn.mock.calls[0][0].messages)).toStrictEqual([
493
492
  {
494
493
  id: "a",
@@ -496,7 +495,7 @@ describe("functionality", () => {
496
495
  variants: [
497
496
  {
498
497
  languageTag: "en",
499
- match: {},
498
+ match: [],
500
499
  pattern: [
501
500
  {
502
501
  type: "Text",
@@ -506,7 +505,7 @@ describe("functionality", () => {
506
505
  },
507
506
  {
508
507
  languageTag: "de",
509
- match: {},
508
+ match: [],
510
509
  pattern: [
511
510
  {
512
511
  type: "Text",
@@ -522,7 +521,7 @@ describe("functionality", () => {
522
521
  variants: [
523
522
  {
524
523
  languageTag: "en",
525
- match: {},
524
+ match: [],
526
525
  pattern: [
527
526
  {
528
527
  type: "Text",
@@ -532,7 +531,7 @@ describe("functionality", () => {
532
531
  },
533
532
  {
534
533
  languageTag: "de",
535
- match: {},
534
+ match: [],
536
535
  pattern: [
537
536
  {
538
537
  type: "Text",
@@ -9,12 +9,12 @@ import { MessagePatternsForLanguageTagDoNotExistError, MessageVariantAlreadyExis
9
9
  * (if it exists).
10
10
  *
11
11
  * @example
12
- * const variant = getVariant(message, { where: { languageTag: "en", selectors: { gender: "male" }}});
12
+ * const variant = getVariant(message, { where: { languageTag: "en", match: ["male"]}});
13
13
  */
14
14
  export declare function getVariant(message: Message, args: {
15
15
  where: {
16
16
  languageTag: LanguageTag;
17
- selectors?: Variant["match"];
17
+ match?: Variant["match"];
18
18
  };
19
19
  }): Variant | undefined;
20
20
  /**
@@ -34,12 +34,12 @@ export declare function createVariant(message: Message, args: {
34
34
  * All actions are immutable.
35
35
  *
36
36
  * @example
37
- * const message = updateVariant(message, { languageTag: "en", selectors: { gender: "male" }, pattern: []})
37
+ * const message = updateVariant(message, { languageTag: "en", match: ["male"], pattern: []})
38
38
  */
39
39
  export declare function updateVariantPattern(message: Message, args: {
40
40
  where: {
41
41
  languageTag: LanguageTag;
42
- selectors: Record<string, string>;
42
+ match: Variant["match"];
43
43
  };
44
44
  data: Variant["pattern"];
45
45
  }): Result<Message, MessageVariantDoesNotExistError | MessagePatternsForLanguageTagDoNotExistError>;
@@ -1 +1 @@
1
- {"version":3,"file":"variant.d.ts","sourceRoot":"","sources":["../../src/messages/variant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EACN,4CAA4C,EAC5C,gCAAgC,EAChC,+BAA+B,EAC/B,MAAM,aAAa,CAAA;AAEpB;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IACL,KAAK,EAAE;QACN,WAAW,EAAE,WAAW,CAAA;QACxB,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAC5B,CAAA;CACD,GACC,OAAO,GAAG,SAAS,CASrB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IACL,IAAI,EAAE,OAAO,CAAA;CACb,GACC,MAAM,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAcnD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IACL,KAAK,EAAE;QACN,WAAW,EAAE,WAAW,CAAA;QACxB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACjC,CAAA;IACD,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;CACxB,GACC,MAAM,CAAC,OAAO,EAAE,+BAA+B,GAAG,4CAA4C,CAAC,CAqBjG"}
1
+ {"version":3,"file":"variant.d.ts","sourceRoot":"","sources":["../../src/messages/variant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EACN,4CAA4C,EAC5C,gCAAgC,EAChC,+BAA+B,EAC/B,MAAM,aAAa,CAAA;AAEpB;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IACL,KAAK,EAAE;QACN,WAAW,EAAE,WAAW,CAAA;QACxB,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KACxB,CAAA;CACD,GACC,OAAO,GAAG,SAAS,CASrB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IACL,IAAI,EAAE,OAAO,CAAA;CACb,GACC,MAAM,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAanD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE;IACL,KAAK,EAAE;QACN,WAAW,EAAE,WAAW,CAAA;QACxB,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KACvB,CAAA;IACD,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;CACxB,GACC,MAAM,CAAC,OAAO,EAAE,+BAA+B,GAAG,4CAA4C,CAAC,CAqBjG"}
@@ -7,10 +7,10 @@ import { MessagePatternsForLanguageTagDoNotExistError, MessageVariantAlreadyExis
7
7
  * (if it exists).
8
8
  *
9
9
  * @example
10
- * const variant = getVariant(message, { where: { languageTag: "en", selectors: { gender: "male" }}});
10
+ * const variant = getVariant(message, { where: { languageTag: "en", match: ["male"]}});
11
11
  */
12
12
  export function getVariant(message, args) {
13
- const variant = matchMostSpecificVariant(message, args.where.languageTag, args.where.selectors);
13
+ const variant = matchMostSpecificVariant(message, args.where.languageTag, args.where.match);
14
14
  if (variant) {
15
15
  //! do not return a reference to the message in a resource
16
16
  //! modifications to the returned message will leak into the
@@ -33,10 +33,9 @@ export function createVariant(message, args) {
33
33
  if (matchVariant(copy, args.data.languageTag, args.data.match)) {
34
34
  return { error: new MessageVariantAlreadyExistsError(message.id, args.data.languageTag) };
35
35
  }
36
- // need to resolve selectors to match length and order of message selectors
37
36
  copy.variants.push({
38
37
  ...args.data,
39
- match: resolveSelector(copy.selectors, args.data.match),
38
+ match: args.data.match,
40
39
  });
41
40
  return { data: copy };
42
41
  }
@@ -46,7 +45,7 @@ export function createVariant(message, args) {
46
45
  * All actions are immutable.
47
46
  *
48
47
  * @example
49
- * const message = updateVariant(message, { languageTag: "en", selectors: { gender: "male" }, pattern: []})
48
+ * const message = updateVariant(message, { languageTag: "en", match: ["male"], pattern: []})
50
49
  */
51
50
  export function updateVariantPattern(message, args) {
52
51
  const copy = structuredClone(message);
@@ -56,7 +55,7 @@ export function updateVariantPattern(message, args) {
56
55
  error: new MessagePatternsForLanguageTagDoNotExistError(message.id, args.where.languageTag),
57
56
  };
58
57
  }
59
- const variant = matchVariant(copy, args.where.languageTag, args.where.selectors);
58
+ const variant = matchVariant(copy, args.where.languageTag, args.where.match);
60
59
  if (variant === undefined) {
61
60
  return { error: new MessageVariantDoesNotExistError(message.id, args.where.languageTag) };
62
61
  }
@@ -70,21 +69,24 @@ export function updateVariantPattern(message, args) {
70
69
  * Returns the specific variant defined by selectors or undefined
71
70
  *
72
71
  * @example
73
- * const variant = matchVariant(message, languageTag: "en", selectors: { gender: "male" })
72
+ * const variant = matchVariant(message, languageTag: "en", match: ["male"])
74
73
  */
75
- const matchVariant = (message, languageTag, selectors) => {
76
- // resolve preferenceSelectors to match length and order of message selectors
77
- const resolvedSelectors = resolveSelector(message.selectors, selectors);
74
+ const matchVariant = (message, languageTag, match) => {
78
75
  const languageVariants = message.variants.filter((variant) => variant.languageTag === languageTag);
79
76
  if (languageVariants.length === 0)
80
77
  return undefined;
81
78
  for (const variant of languageVariants) {
82
79
  let isMatch = true;
83
80
  //check if vaiant is a match
84
- for (const [key, value] of Object.entries(variant.match)) {
85
- if (resolvedSelectors[key] !== value) {
86
- isMatch = false;
87
- }
81
+ if (variant.match.length > 0) {
82
+ variant.match.map((value, index) => {
83
+ if (match && match[index] !== value) {
84
+ isMatch = false;
85
+ }
86
+ });
87
+ }
88
+ if (!message.selectors || !match || match.length !== message.selectors.length) {
89
+ isMatch = false;
88
90
  }
89
91
  if (isMatch) {
90
92
  return variant;
@@ -98,47 +100,61 @@ const matchVariant = (message, languageTag, selectors) => {
98
100
  * @example
99
101
  * const variant = matchMostSpecificVariant(message, languageTag: "en", selectors: { gender: "male" })
100
102
  */
101
- const matchMostSpecificVariant = (message, languageTag, selectors) => {
102
- // make selector undefined if empty object
103
- selectors = JSON.stringify(selectors) === "{}" ? undefined : selectors;
103
+ const matchMostSpecificVariant = (message, languageTag, match) => {
104
104
  // resolve preferenceSelectors to match length and order of message selectors
105
- const resolvedSelectors = resolveSelector(message.selectors, selectors);
106
105
  const index = {};
107
106
  for (const variant of message.variants) {
108
107
  if (variant.languageTag !== languageTag)
109
108
  continue;
110
109
  let isMatch = true;
110
+ // if slector and stored match are not the same throw error
111
+ if (variant.match.length !== message.selectors.length) {
112
+ return undefined;
113
+ }
111
114
  //check if variant is a match
112
- for (const [key, value] of Object.entries(variant.match)) {
113
- if (resolvedSelectors[key] !== value && value !== "*") {
114
- isMatch = false;
115
- }
115
+ if (variant.match.length > 0) {
116
+ variant.match.map((value, index) => {
117
+ if (match && match[index] !== value && value !== "*") {
118
+ isMatch = false;
119
+ }
120
+ });
116
121
  }
117
- if (isMatch && selectors) {
118
- // add variant to nested index
122
+ if (isMatch && match && match.length > 0) {
119
123
  // eslint-disable-next-line no-inner-declarations
120
- function recursiveAddToIndex(currentIndex, currentKeys, variant) {
121
- if (currentKeys[0]?.name) {
122
- const key = variant.match[currentKeys[0].name];
123
- if (key) {
124
- if (currentKeys.length === 1) {
125
- currentIndex[key] = variant;
126
- }
127
- else {
128
- if (!currentIndex[key]) {
129
- currentIndex[key] = {};
130
- }
131
- recursiveAddToIndex(currentIndex[key], currentKeys.slice(1), variant);
124
+ function recursiveAddToIndex(currentIndex, selectorIndex, selectorLength, variant) {
125
+ const key = variant.match[selectorIndex];
126
+ if (key) {
127
+ if (selectorIndex === 1) {
128
+ currentIndex[key] = variant;
129
+ }
130
+ else {
131
+ if (!currentIndex[key]) {
132
+ currentIndex[key] = {};
132
133
  }
134
+ recursiveAddToIndex(currentIndex[key], selectorIndex + 1, selectorLength, variant);
133
135
  }
134
136
  }
135
137
  }
136
- recursiveAddToIndex(index, message.selectors, variant);
138
+ recursiveAddToIndex(index, 0, message.selectors ? message.selectors.length - 1 : 0, variant);
137
139
  }
138
- else if (isMatch && !selectors) {
140
+ else if (isMatch && !match) {
139
141
  return variant;
140
142
  }
141
143
  }
144
+ // if number of selectors and numver of required match is not the same match catch all
145
+ if (!message.selectors || !match || match.length !== message.selectors.length) {
146
+ const catchAllMatcher = [];
147
+ const selectorCount = message.selectors.length;
148
+ catchAllMatcher.push("*");
149
+ for (let i = 0; i < selectorCount - 1; i++) {
150
+ catchAllMatcher.push("*");
151
+ }
152
+ return message.variants.find((v) => v.languageTag === languageTag && JSON.stringify(v.match) === JSON.stringify(catchAllMatcher));
153
+ }
154
+ // if selector is empty match empty variant match
155
+ if (message.selectors && message.selectors.length === 0) {
156
+ return message.variants.find((v) => v.languageTag === languageTag && JSON.stringify(v.match) === "[]");
157
+ }
142
158
  //find the most specific variant
143
159
  const findOptimalMatch = (index, selectors) => {
144
160
  const keys = Object.keys(index);
@@ -156,21 +172,5 @@ const matchMostSpecificVariant = (message, languageTag, selectors) => {
156
172
  }
157
173
  return undefined;
158
174
  };
159
- return findOptimalMatch(index, Object.values(resolvedSelectors));
160
- };
161
- /**
162
- * Returns resolved selector.
163
- * -> Adds all possible selectors, if not defined it adds '*'. Order is determined by messageSelectors
164
- *
165
- * @example
166
- * const variant = resolveSelector(["gender","count"], selector: {count: "2"})
167
- */
168
- const resolveSelector = (messageSelectors, selectors) => {
169
- const resolvedSelectors = {};
170
- if (!selectors)
171
- return {};
172
- for (const messageSelector of messageSelectors) {
173
- resolvedSelectors[messageSelector.name] = selectors[messageSelector.name] ?? "*";
174
- }
175
- return resolvedSelectors;
175
+ return findOptimalMatch(index, match || []);
176
176
  };