@inlang/sdk 0.7.0 → 0.8.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 (36) hide show
  1. package/dist/adapter/solidAdapter.test.js +5 -5
  2. package/dist/createMessagesQuery.test.js +9 -0
  3. package/dist/loadProject.d.ts.map +1 -1
  4. package/dist/loadProject.js +3 -1
  5. package/dist/loadProject.test.js +10 -10
  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/test-utilities/createMessage.d.ts +1 -1
  11. package/dist/test-utilities/createMessage.js +1 -1
  12. package/dist/test-utilities/createMessage.test.js +4 -4
  13. package/package.json +1 -1
  14. package/src/adapter/solidAdapter.test.ts +13 -13
  15. package/src/adapter/solidAdapter.ts +1 -1
  16. package/src/api.ts +2 -2
  17. package/src/createMessageLintReportsQuery.ts +4 -4
  18. package/src/createMessagesQuery.test.ts +30 -17
  19. package/src/createMessagesQuery.ts +2 -2
  20. package/src/lint/message/lintMessages.ts +1 -1
  21. package/src/lint/message/lintSingleMessage.test.ts +1 -1
  22. package/src/lint/message/lintSingleMessage.ts +2 -2
  23. package/src/loadProject.test.ts +14 -14
  24. package/src/loadProject.ts +15 -13
  25. package/src/messages/errors.ts +2 -2
  26. package/src/messages/variant.test.ts +113 -49
  27. package/src/messages/variant.ts +73 -67
  28. package/src/parseConfig.ts +2 -2
  29. package/src/resolve-modules/import.test.ts +2 -2
  30. package/src/resolve-modules/import.ts +1 -1
  31. package/src/resolve-modules/message-lint-rules/resolveMessageLintRules.ts +1 -1
  32. package/src/resolve-modules/plugins/resolvePlugins.test.ts +2 -2
  33. package/src/resolve-modules/plugins/resolvePlugins.ts +16 -16
  34. package/src/resolve-modules/resolveModules.ts +4 -4
  35. package/src/test-utilities/createMessage.test.ts +7 -7
  36. package/src/test-utilities/createMessage.ts +1 -1
@@ -15,7 +15,7 @@ describe("getVariant", () => {
15
15
  const variant = getVariant(mockMessage, {
16
16
  where: {
17
17
  languageTag: "en",
18
- selectors: { gender: "female", guestOther: "1" },
18
+ match: ["female", "1"],
19
19
  },
20
20
  })
21
21
 
@@ -31,7 +31,7 @@ describe("getVariant", () => {
31
31
  const variant = getVariant(mockMessage, {
32
32
  where: {
33
33
  languageTag: "en",
34
- selectors: { gender: "female", guestOther: "0" },
34
+ match: ["female", "0"],
35
35
  },
36
36
  })
37
37
  expect(variant?.pattern[0]).toStrictEqual({
@@ -40,7 +40,7 @@ describe("getVariant", () => {
40
40
  })
41
41
  })
42
42
 
43
- test("it should return undefined (but never throw an error) if selectors is an empty array", () => {
43
+ test("it should not throw error if selector is empty and match", () => {
44
44
  const mockMessage: Message = {
45
45
  id: "mockMessage",
46
46
  selectors: [],
@@ -48,21 +48,45 @@ describe("getVariant", () => {
48
48
  {
49
49
  languageTag: "en",
50
50
  pattern: [{ type: "Text", value: "Gender male" }],
51
- match: {
52
- gender: "male",
53
- },
51
+ match: [],
54
52
  },
55
53
  {
56
54
  languageTag: "de",
57
55
  pattern: [{ type: "Text", value: "Veraltete Übersetzung" }],
58
- match: {},
56
+ match: [],
57
+ },
58
+ ],
59
+ }
60
+ const variant = getVariant(mockMessage, {
61
+ where: {
62
+ languageTag: "en",
63
+ match: [],
64
+ },
65
+ })
66
+ expect(variant).toBeDefined()
67
+ })
68
+
69
+ test("it should not throw error if selector is empty, return undefined", () => {
70
+ const mockMessage: Message = {
71
+ id: "mockMessage",
72
+ selectors: [],
73
+ variants: [
74
+ {
75
+ languageTag: "en",
76
+ pattern: [{ type: "Text", value: "Gender male" }],
77
+ match: ["male", "*"],
78
+ },
79
+ {
80
+ languageTag: "de",
81
+ pattern: [{ type: "Text", value: "Veraltete Übersetzung" }],
82
+ match: ["*", "*"],
59
83
  },
60
84
  ],
61
85
  }
62
86
  const variant = getVariant(mockMessage, {
63
87
  where: {
64
88
  languageTag: "fr",
65
- selectors: {},
89
+ match: ["*", "*"],
66
90
  },
67
91
  })
68
92
  expect(variant).toBeUndefined()
@@ -74,7 +98,7 @@ describe("getVariant", () => {
74
98
  const variant = getVariant(mockMessage, {
75
99
  where: {
76
100
  languageTag: "en",
77
- selectors: { guestOther: "0" },
101
+ match: ["*", "0"],
78
102
  },
79
103
  })
80
104
  expect(variant?.pattern[0]).toStrictEqual({
@@ -89,7 +113,7 @@ describe("getVariant", () => {
89
113
  const variant = getVariant(mockMessage, {
90
114
  where: {
91
115
  languageTag: "en",
92
- selectors: {},
116
+ match: ["*", "*"],
93
117
  },
94
118
  })
95
119
  expect(variant?.pattern[0]).toStrictEqual({
@@ -104,7 +128,7 @@ describe("getVariant", () => {
104
128
  const variant = getVariant(mockMessage, {
105
129
  where: {
106
130
  languageTag: "en",
107
- selectors: { gender: "trans", guestOther: "2" },
131
+ match: ["trans", "2"],
108
132
  },
109
133
  })
110
134
  expect(variant?.pattern[0]).toStrictEqual({
@@ -115,7 +139,7 @@ describe("getVariant", () => {
115
139
  const variant2 = getVariant(mockMessage, {
116
140
  where: {
117
141
  languageTag: "en",
118
- selectors: { gender: "male", guestOther: "8" },
142
+ match: ["male", "8"],
119
143
  },
120
144
  })
121
145
  expect(variant2?.pattern[0]).toStrictEqual({
@@ -128,14 +152,14 @@ describe("getVariant", () => {
128
152
  const mockMessage: Message = getMockMessage()
129
153
  mockMessage.variants = [
130
154
  ...mockMessage.variants!.filter(
131
- (v) => v.languageTag === "en" && (v.match.gender !== "*" || v.match.guestOther !== "*"),
155
+ (v) => v.languageTag === "en" && (v.match[0] !== "*" || v.match[1] !== "*")
132
156
  ),
133
157
  ]
134
158
 
135
159
  const variant = getVariant(mockMessage, {
136
160
  where: {
137
161
  languageTag: "en",
138
- selectors: {},
162
+ match: ["*", "*"],
139
163
  },
140
164
  })
141
165
  expect(variant).toBeUndefined()
@@ -147,18 +171,19 @@ describe("getVariant", () => {
147
171
  const variant = getVariant(mockMessage, {
148
172
  where: {
149
173
  languageTag: "de",
150
- selectors: { gender: "female", guestOther: "1" },
174
+ match: ["female", "1"],
151
175
  },
152
176
  })
153
177
  expect(variant).toBeUndefined()
154
178
  })
155
179
 
156
- test("should return the catch all variant if no selector defined", () => {
180
+ test("should return undefined variant if no selector defined", () => {
157
181
  const mockMessage: Message = {} as any
182
+ mockMessage.selectors = []
158
183
  mockMessage.variants = [
159
184
  {
160
185
  languageTag: "en",
161
- match: {},
186
+ match: ["*", "*"],
162
187
  pattern: [
163
188
  {
164
189
  type: "Text",
@@ -171,13 +196,52 @@ describe("getVariant", () => {
171
196
  const variant = getVariant(mockMessage, {
172
197
  where: {
173
198
  languageTag: "en",
174
- selectors: {},
199
+ match: ["*", "*"],
175
200
  },
176
201
  })
177
- // should return the female variant
178
- expect(variant?.pattern[0]).toStrictEqual({
202
+ // should return undefined
203
+ expect(variant).toBeUndefined()
204
+ })
205
+
206
+ test("should match catch all if the number of matches and selectors do not match", () => {
207
+ const mockMessage: Message = getMockMessage()
208
+
209
+ const variant1 = getVariant(mockMessage, {
210
+ where: {
211
+ languageTag: "en",
212
+ match: ["12"],
213
+ },
214
+ })
215
+
216
+ // should return catch all
217
+ expect(variant1?.pattern[0]).toStrictEqual({
179
218
  type: "Text",
180
- value: "test",
219
+ value: "{$hostName} invites {$guestName} and {$guestsOther} other people to their party.",
220
+ })
221
+
222
+ const variant2 = getVariant(mockMessage, {
223
+ where: {
224
+ languageTag: "en",
225
+ match: ["12", "*", "23"],
226
+ },
227
+ })
228
+
229
+ // should return catch all
230
+ expect(variant2?.pattern[0]).toStrictEqual({
231
+ type: "Text",
232
+ value: "{$hostName} invites {$guestName} and {$guestsOther} other people to their party.",
233
+ })
234
+ const variant3 = getVariant(mockMessage, {
235
+ where: {
236
+ languageTag: "en",
237
+ match: [],
238
+ },
239
+ })
240
+
241
+ // should return catch all
242
+ expect(variant3?.pattern[0]).toStrictEqual({
243
+ type: "Text",
244
+ value: "{$hostName} invites {$guestName} and {$guestsOther} other people to their party.",
181
245
  })
182
246
  })
183
247
  })
@@ -188,7 +252,7 @@ describe("createVariant", () => {
188
252
 
189
253
  const newVariant: Variant = {
190
254
  languageTag: "en",
191
- match: { gender: "female", guestOther: "0" },
255
+ match: ["female", "0"],
192
256
  pattern: [],
193
257
  }
194
258
  const message = createVariant(mockMessage, {
@@ -197,8 +261,8 @@ describe("createVariant", () => {
197
261
  // should return the female variant
198
262
  expect(
199
263
  message.data!.variants.find(
200
- (v) => v.languageTag === "en" && v.match.gender === "female" && v.match.guestOther === "0",
201
- )?.pattern,
264
+ (v) => v.languageTag === "en" && v.match[0] === "female" && v.match[1] === "0"
265
+ )?.pattern
202
266
  ).toStrictEqual([])
203
267
  })
204
268
 
@@ -206,22 +270,22 @@ describe("createVariant", () => {
206
270
  const mockMessage: Message = getMockMessage()
207
271
  mockMessage.variants = [
208
272
  ...mockMessage.variants!.filter(
209
- (v) => v.languageTag === "en" && (v.match.gender !== "*" || v.match.guestOther !== "*"),
273
+ (v) => v.languageTag === "en" && (v.match[0] !== "*" || v.match[1] !== "*")
210
274
  ),
211
275
  ]
212
276
 
213
277
  const message = createVariant(mockMessage, {
214
278
  data: {
215
279
  languageTag: "en",
216
- match: {},
280
+ match: ["*", "*"],
217
281
  pattern: [],
218
282
  },
219
283
  })
220
284
  // should return the female variant
221
285
  expect(
222
286
  message.data!.variants.find(
223
- (v) => v.languageTag === "en" && v.match.gender === "*" && v.match.guestOther === "*",
224
- )?.pattern,
287
+ (v) => v.languageTag === "en" && v.match[0] === "*" && v.match[1] === "*"
288
+ )?.pattern
225
289
  ).toStrictEqual([])
226
290
  })
227
291
 
@@ -231,7 +295,7 @@ describe("createVariant", () => {
231
295
  const variant = createVariant(mockMessage, {
232
296
  data: {
233
297
  languageTag: "en",
234
- match: { gender: "male", guestOther: "1" },
298
+ match: ["male", "1"],
235
299
  pattern: [],
236
300
  },
237
301
  })
@@ -246,7 +310,7 @@ describe("createVariant", () => {
246
310
  const variant = createVariant(mockMessage, {
247
311
  data: {
248
312
  languageTag: "de",
249
- match: { gender: "female", guestOther: "1" },
313
+ match: ["female", "1"],
250
314
  pattern: [],
251
315
  },
252
316
  })
@@ -263,15 +327,15 @@ describe("updateVariant", () => {
263
327
  const message = updateVariantPattern(mockMessage, {
264
328
  where: {
265
329
  languageTag: "en",
266
- selectors: { gender: "female", guestOther: "1" },
330
+ match: ["female", "1"],
267
331
  },
268
332
  data: [],
269
333
  })
270
334
  // should return the female variant
271
335
  expect(
272
336
  message.data!.variants.find(
273
- (v) => v.languageTag === "en" && v.match.gender === "female" && v.match.guestOther === "1",
274
- )?.pattern,
337
+ (v) => v.languageTag === "en" && v.match[0] === "female" && v.match[1] === "1"
338
+ )?.pattern
275
339
  ).toStrictEqual([])
276
340
  })
277
341
 
@@ -281,15 +345,15 @@ describe("updateVariant", () => {
281
345
  const message = updateVariantPattern(mockMessage, {
282
346
  where: {
283
347
  languageTag: "en",
284
- selectors: {},
348
+ match: ["*", "*"],
285
349
  },
286
350
  data: [],
287
351
  })
288
352
  // should return the female variant
289
353
  expect(
290
354
  message.data!.variants.find(
291
- (v) => v.languageTag === "en" && v.match.gender === "*" && v.match.guestOther === "*",
292
- )?.pattern,
355
+ (v) => v.languageTag === "en" && v.match[0] === "*" && v.match[1] === "*"
356
+ )?.pattern
293
357
  ).toStrictEqual([])
294
358
  })
295
359
 
@@ -298,14 +362,14 @@ describe("updateVariant", () => {
298
362
 
299
363
  mockMessage.variants = [
300
364
  ...mockMessage.variants!.filter(
301
- (v) => v.languageTag === "en" && (v.match.gender !== "*" || v.match.guestOther !== "*"),
365
+ (v) => v.languageTag === "en" && (v.match[0] !== "*" || v.match[1] !== "*")
302
366
  ),
303
367
  ]
304
368
 
305
369
  const variant = updateVariantPattern(mockMessage, {
306
370
  where: {
307
371
  languageTag: "en",
308
- selectors: {},
372
+ match: ["*", "*"],
309
373
  },
310
374
  data: [],
311
375
  })
@@ -320,7 +384,7 @@ describe("updateVariant", () => {
320
384
  const variant = updateVariantPattern(mockMessage, {
321
385
  where: {
322
386
  languageTag: "de",
323
- selectors: {},
387
+ match: ["*", "*"],
324
388
  },
325
389
  data: [],
326
390
  })
@@ -340,7 +404,7 @@ const getMockMessage = (): Message => {
340
404
  variants: [
341
405
  {
342
406
  languageTag: "en",
343
- match: { gender: "female", guestOther: "1" },
407
+ match: ["female", "1"],
344
408
  pattern: [
345
409
  {
346
410
  type: "Text",
@@ -350,7 +414,7 @@ const getMockMessage = (): Message => {
350
414
  },
351
415
  {
352
416
  languageTag: "en",
353
- match: { gender: "female", guestOther: "2" },
417
+ match: ["female", "2"],
354
418
  pattern: [
355
419
  {
356
420
  type: "Text",
@@ -360,7 +424,7 @@ const getMockMessage = (): Message => {
360
424
  },
361
425
  {
362
426
  languageTag: "en",
363
- match: { gender: "female", guestOther: "*" },
427
+ match: ["female", "*"],
364
428
  pattern: [
365
429
  {
366
430
  type: "Text",
@@ -370,7 +434,7 @@ const getMockMessage = (): Message => {
370
434
  },
371
435
  {
372
436
  languageTag: "en",
373
- match: { gender: "male", guestOther: "1" },
437
+ match: ["male", "1"],
374
438
  pattern: [
375
439
  {
376
440
  type: "Text",
@@ -380,7 +444,7 @@ const getMockMessage = (): Message => {
380
444
  },
381
445
  {
382
446
  languageTag: "en",
383
- match: { gender: "male", guestOther: "2" },
447
+ match: ["male", "2"],
384
448
  pattern: [
385
449
  {
386
450
  type: "Text",
@@ -390,7 +454,7 @@ const getMockMessage = (): Message => {
390
454
  },
391
455
  {
392
456
  languageTag: "en",
393
- match: { gender: "male", guestOther: "*" },
457
+ match: ["male", "*"],
394
458
  pattern: [
395
459
  {
396
460
  type: "Text",
@@ -400,7 +464,7 @@ const getMockMessage = (): Message => {
400
464
  },
401
465
  {
402
466
  languageTag: "en",
403
- match: { gender: "*", guestOther: "0" },
467
+ match: ["*", "0"],
404
468
  pattern: [
405
469
  {
406
470
  type: "Text",
@@ -410,7 +474,7 @@ const getMockMessage = (): Message => {
410
474
  },
411
475
  {
412
476
  languageTag: "en",
413
- match: { gender: "*", guestOther: "1" },
477
+ match: ["*", "1"],
414
478
  pattern: [
415
479
  {
416
480
  type: "Text",
@@ -420,7 +484,7 @@ const getMockMessage = (): Message => {
420
484
  },
421
485
  {
422
486
  languageTag: "en",
423
- match: { gender: "*", guestOther: "2" },
487
+ match: ["*", "2"],
424
488
  pattern: [
425
489
  {
426
490
  type: "Text",
@@ -430,7 +494,7 @@ const getMockMessage = (): Message => {
430
494
  },
431
495
  {
432
496
  languageTag: "en",
433
- match: { gender: "*", guestOther: "*" },
497
+ match: ["*", "*"],
434
498
  pattern: [
435
499
  {
436
500
  type: "Text",
@@ -14,18 +14,18 @@ import {
14
14
  * (if it exists).
15
15
  *
16
16
  * @example
17
- * const variant = getVariant(message, { where: { languageTag: "en", selectors: { gender: "male" }}});
17
+ * const variant = getVariant(message, { where: { languageTag: "en", match: ["male"]}});
18
18
  */
19
19
  export function getVariant(
20
20
  message: Message,
21
21
  args: {
22
22
  where: {
23
23
  languageTag: LanguageTag
24
- selectors?: Variant["match"]
24
+ match?: Variant["match"]
25
25
  }
26
- },
26
+ }
27
27
  ): Variant | undefined {
28
- const variant = matchMostSpecificVariant(message, args.where.languageTag, args.where.selectors)
28
+ const variant = matchMostSpecificVariant(message, args.where.languageTag, args.where.match)
29
29
  if (variant) {
30
30
  //! do not return a reference to the message in a resource
31
31
  //! modifications to the returned message will leak into the
@@ -47,7 +47,7 @@ export function createVariant(
47
47
  message: Message,
48
48
  args: {
49
49
  data: Variant
50
- },
50
+ }
51
51
  ): Result<Message, MessageVariantAlreadyExistsError> {
52
52
  const copy = structuredClone(message)
53
53
 
@@ -56,10 +56,9 @@ export function createVariant(
56
56
  return { error: new MessageVariantAlreadyExistsError(message.id, args.data.languageTag) }
57
57
  }
58
58
 
59
- // need to resolve selectors to match length and order of message selectors
60
59
  copy.variants.push({
61
60
  ...args.data,
62
- match: resolveSelector(copy.selectors, args.data.match),
61
+ match: args.data.match,
63
62
  })
64
63
  return { data: copy }
65
64
  }
@@ -70,22 +69,22 @@ export function createVariant(
70
69
  * All actions are immutable.
71
70
  *
72
71
  * @example
73
- * const message = updateVariant(message, { languageTag: "en", selectors: { gender: "male" }, pattern: []})
72
+ * const message = updateVariant(message, { languageTag: "en", match: ["male"], pattern: []})
74
73
  */
75
74
  export function updateVariantPattern(
76
75
  message: Message,
77
76
  args: {
78
77
  where: {
79
78
  languageTag: LanguageTag
80
- selectors: Record<string, string>
79
+ match: Variant["match"]
81
80
  }
82
81
  data: Variant["pattern"]
83
- },
82
+ }
84
83
  ): Result<Message, MessageVariantDoesNotExistError | MessagePatternsForLanguageTagDoNotExistError> {
85
84
  const copy = structuredClone(message)
86
85
 
87
86
  const containsLanguageTag = message.variants.some(
88
- (variant) => variant.languageTag === args.where.languageTag,
87
+ (variant) => variant.languageTag === args.where.languageTag
89
88
  )
90
89
  if (!containsLanguageTag) {
91
90
  return {
@@ -93,7 +92,7 @@ export function updateVariantPattern(
93
92
  }
94
93
  }
95
94
 
96
- const variant = matchVariant(copy, args.where.languageTag, args.where.selectors)
95
+ const variant = matchVariant(copy, args.where.languageTag, args.where.match)
97
96
  if (variant === undefined) {
98
97
  return { error: new MessageVariantDoesNotExistError(message.id, args.where.languageTag) }
99
98
  }
@@ -108,27 +107,31 @@ export function updateVariantPattern(
108
107
  * Returns the specific variant defined by selectors or undefined
109
108
  *
110
109
  * @example
111
- * const variant = matchVariant(message, languageTag: "en", selectors: { gender: "male" })
110
+ * const variant = matchVariant(message, languageTag: "en", match: ["male"])
112
111
  */
113
112
  const matchVariant = (
114
113
  message: Message,
115
114
  languageTag: LanguageTag,
116
- selectors: Record<string, string>,
115
+ match: Variant["match"]
117
116
  ): Variant | undefined => {
118
- // resolve preferenceSelectors to match length and order of message selectors
119
- const resolvedSelectors = resolveSelector(message.selectors, selectors)
120
-
121
117
  const languageVariants = message.variants.filter((variant) => variant.languageTag === languageTag)
122
118
  if (languageVariants.length === 0) return undefined
123
119
 
124
120
  for (const variant of languageVariants) {
125
121
  let isMatch = true
126
122
  //check if vaiant is a match
127
- for (const [key, value] of Object.entries(variant.match)) {
128
- if (resolvedSelectors[key] !== value) {
129
- isMatch = false
130
- }
123
+ if (variant.match.length > 0) {
124
+ variant.match.map((value, index) => {
125
+ if (match && match[index] !== value) {
126
+ isMatch = false
127
+ }
128
+ })
131
129
  }
130
+
131
+ if (!message.selectors || !match || match.length !== message.selectors.length) {
132
+ isMatch = false
133
+ }
134
+
132
135
  if (isMatch) {
133
136
  return variant
134
137
  }
@@ -145,13 +148,9 @@ const matchVariant = (
145
148
  const matchMostSpecificVariant = (
146
149
  message: Message,
147
150
  languageTag: LanguageTag,
148
- selectors?: Record<string, string>,
151
+ match?: Variant["match"]
149
152
  ): Variant | undefined => {
150
- // make selector undefined if empty object
151
- selectors = JSON.stringify(selectors) === "{}" ? undefined : selectors
152
-
153
153
  // resolve preferenceSelectors to match length and order of message selectors
154
- const resolvedSelectors = resolveSelector(message.selectors, selectors)
155
154
  const index: Record<string, any> = {}
156
155
 
157
156
  for (const variant of message.variants) {
@@ -159,44 +158,70 @@ const matchMostSpecificVariant = (
159
158
 
160
159
  let isMatch = true
161
160
 
161
+ // if slector and stored match are not the same throw error
162
+ if (variant.match.length !== message.selectors.length) {
163
+ return undefined
164
+ }
165
+
162
166
  //check if variant is a match
163
- for (const [key, value] of Object.entries(variant.match)) {
164
- if (resolvedSelectors[key] !== value && value !== "*") {
165
- isMatch = false
166
- }
167
+ if (variant.match.length > 0) {
168
+ variant.match.map((value, index) => {
169
+ if (match && match[index] !== value && value !== "*") {
170
+ isMatch = false
171
+ }
172
+ })
167
173
  }
168
- if (isMatch && selectors) {
169
- // add variant to nested index
174
+ if (isMatch && match && match.length > 0) {
170
175
  // eslint-disable-next-line no-inner-declarations
171
176
  function recursiveAddToIndex(
172
177
  currentIndex: Record<string, any>,
173
- currentKeys: Message["selectors"],
174
- variant: Variant,
178
+ selectorIndex: number,
179
+ selectorLength: number,
180
+ variant: Variant
175
181
  ) {
176
- if (currentKeys[0]?.name) {
177
- const key = variant.match[currentKeys[0].name]
178
- if (key) {
179
- if (currentKeys.length === 1) {
180
- currentIndex[key] = variant
181
- } else {
182
- if (!currentIndex[key]) {
183
- currentIndex[key] = {}
184
- }
185
- recursiveAddToIndex(currentIndex[key], currentKeys.slice(1), variant)
182
+ const key = variant.match[selectorIndex]
183
+ if (key) {
184
+ if (selectorIndex === 1) {
185
+ currentIndex[key] = variant
186
+ } else {
187
+ if (!currentIndex[key]) {
188
+ currentIndex[key] = {}
186
189
  }
190
+ recursiveAddToIndex(currentIndex[key], selectorIndex + 1, selectorLength, variant)
187
191
  }
188
192
  }
189
193
  }
190
- recursiveAddToIndex(index, message.selectors, variant)
191
- } else if (isMatch && !selectors) {
194
+ recursiveAddToIndex(index, 0, message.selectors ? message.selectors.length - 1 : 0, variant)
195
+ } else if (isMatch && !match) {
192
196
  return variant
193
197
  }
194
198
  }
195
199
 
200
+ // if number of selectors and numver of required match is not the same match catch all
201
+ if (!message.selectors || !match || match.length !== message.selectors.length) {
202
+ const catchAllMatcher: Array<string> = []
203
+ const selectorCount = message.selectors.length
204
+ catchAllMatcher.push("*")
205
+ for (let i = 0; i < selectorCount - 1; i++) {
206
+ catchAllMatcher.push("*")
207
+ }
208
+ return message.variants.find(
209
+ (v) =>
210
+ v.languageTag === languageTag && JSON.stringify(v.match) === JSON.stringify(catchAllMatcher)
211
+ )
212
+ }
213
+
214
+ // if selector is empty match empty variant match
215
+ if (message.selectors && message.selectors.length === 0) {
216
+ return message.variants.find(
217
+ (v) => v.languageTag === languageTag && JSON.stringify(v.match) === "[]"
218
+ )
219
+ }
220
+
196
221
  //find the most specific variant
197
222
  const findOptimalMatch = (
198
223
  index: Record<string, any>,
199
- selectors: string[],
224
+ selectors: string[]
200
225
  ): Variant | undefined => {
201
226
  const keys = Object.keys(index)
202
227
 
@@ -218,24 +243,5 @@ const matchMostSpecificVariant = (
218
243
  return undefined
219
244
  }
220
245
 
221
- return findOptimalMatch(index, Object.values(resolvedSelectors))
222
- }
223
-
224
- /**
225
- * Returns resolved selector.
226
- * -> Adds all possible selectors, if not defined it adds '*'. Order is determined by messageSelectors
227
- *
228
- * @example
229
- * const variant = resolveSelector(["gender","count"], selector: {count: "2"})
230
- */
231
- const resolveSelector = (
232
- messageSelectors: Message["selectors"],
233
- selectors?: Record<string, string>,
234
- ): Record<string, string> => {
235
- const resolvedSelectors: Record<string, string> = {}
236
- if (!selectors) return {}
237
- for (const messageSelector of messageSelectors) {
238
- resolvedSelectors[messageSelector.name] = selectors[messageSelector.name] ?? "*"
239
- }
240
- return resolvedSelectors
246
+ return findOptimalMatch(index, match || [])
241
247
  }
@@ -16,7 +16,7 @@ export class ParseConfigError extends Error {
16
16
  const ConfigCompiler = TypeCompiler.Compile(ProjectSettings)
17
17
 
18
18
  export const parseSettings = (
19
- config: ProjectSettings,
19
+ config: ProjectSettings
20
20
  ): Result<ProjectSettings, ParseConfigError> => {
21
21
  if (ConfigCompiler.Check(config)) {
22
22
  return {
@@ -27,7 +27,7 @@ export const parseSettings = (
27
27
  return {
28
28
  error: new ParseConfigError(
29
29
  "The inlang config is not valid.",
30
- [...ConfigCompiler.Errors(config)].toString(),
30
+ [...ConfigCompiler.Errors(config)].toString()
31
31
  ),
32
32
  data: undefined as never,
33
33
  }