saykit 0.5.0 → 0.6.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.
@@ -2,6 +2,15 @@
2
2
  type Tuple = [any, ...any[]];
3
3
  type Disallow<T, K extends PropertyKey> = T & Partial<Record<K, never>>;
4
4
  type Awaitable<T> = T | PromiseLike<T>;
5
+ /**
6
+ * A value wrapped in the name its ICU placeholder should take, written inline
7
+ * as a single-key object: `` say`Total: ${{ cartTotal: getTotal() }}` ``. The
8
+ * transform reads the key at build time and compiles only the value, so this
9
+ * is never a real object at runtime.
10
+ */
11
+ type Named<T> = {
12
+ [name: string]: T;
13
+ };
5
14
  interface NumeralOptions extends Omit<Partial<Record<Intl.LDMLPluralRule, string>>, 'other'> {
6
15
  other: string;
7
16
  [digit: number]: string;
@@ -31,9 +40,13 @@ interface Say {
31
40
  /**
32
41
  * Define a message.
33
42
  *
43
+ * An interpolated variable is named after itself. Anything else is numbered,
44
+ * unless it is written as a single-key object, which names it.
45
+ *
34
46
  * @example
35
47
  * ```ts
36
48
  * say`Hello, ${name}!`
49
+ * say`Your total is ${{ cartTotal: getCartTotal() }}`
37
50
  * ```
38
51
  *
39
52
  * @remark This is a macro and must be used with the relevant saykit plugin
@@ -163,7 +176,7 @@ declare class Say<Locale extends string = string, Loader extends Say.Loader<Loca
163
176
  * @returns The plural form of the number
164
177
  * @remark This is a macro and must be used with the relevant saykit plugin
165
178
  */
166
- plural(_: number, options: Disallow<NumeralOptions, 'id' | 'context'>): string;
179
+ plural(_: number | Named<number>, options: Disallow<NumeralOptions, 'id' | 'context'>): string;
167
180
  /**
168
181
  * Define an ordinal message (e.g. "1st", "2nd", "3rd").
169
182
  * The `#` symbol inside options is replaced with the numeric value.
@@ -183,7 +196,7 @@ declare class Say<Locale extends string = string, Loader extends Say.Loader<Loca
183
196
  * @returns The ordinal form of the number
184
197
  * @remark This is a macro and must be used with the relevant saykit plugin
185
198
  */
186
- ordinal(_: number, options: Disallow<NumeralOptions, 'id' | 'context'>): string;
199
+ ordinal(_: number | Named<number>, options: Disallow<NumeralOptions, 'id' | 'context'>): string;
187
200
  /**
188
201
  * Define a select message, useful for handling gender, status, or other categories.
189
202
  *
@@ -201,7 +214,7 @@ declare class Say<Locale extends string = string, Loader extends Say.Loader<Loca
201
214
  * @returns The select form of the value
202
215
  * @remark This is a macro and must be used with the relevant saykit plugin
203
216
  */
204
- select(_: string, options: Disallow<SelectOptions, 'id' | 'context'>): string;
217
+ select(_: string | Named<string>, options: Disallow<SelectOptions, 'id' | 'context'>): string;
205
218
  }
206
219
  //#endregion
207
- export { Awaitable, Disallow, NumeralOptions, ReadonlySay, Say, SelectOptions, Tuple };
220
+ export { Awaitable, Disallow, Named, NumeralOptions, ReadonlySay, Say, SelectOptions, Tuple };
package/dist/runtime.mjs CHANGED
@@ -33,6 +33,20 @@ function _classPrivateFieldGet2(s, a) {
33
33
  //#region src/runtime.ts
34
34
  let _Symbol$iterator;
35
35
  let _Symbol$for;
36
+ /**
37
+ * Map a descriptor's keys back to the placeholders the message names. The
38
+ * transform emits every value with one underscore in front, which keeps a
39
+ * message's values out of the descriptor's own namespace, so stripping exactly
40
+ * one is the whole inverse — `_0` is `0`, and `__total` is a placeholder named
41
+ * `_total`. Keys without one are passed through, so a hand-written
42
+ * `call({ id, name })` still formats `{name}`.
43
+ *
44
+ * Built from the descriptor's own entries so a value named `__proto__` stays a
45
+ * placeholder rather than reaching through to the prototype.
46
+ */
47
+ function resolveDescriptorValues(descriptor) {
48
+ return Object.fromEntries(Object.entries(descriptor).filter(([key]) => key !== "id").map(([key, value]) => [key.startsWith("_") ? key.slice(1) : key, value]));
49
+ }
36
50
  var _locales = /* @__PURE__ */ new WeakMap();
37
51
  var _loader = /* @__PURE__ */ new WeakMap();
38
52
  var _messages = /* @__PURE__ */ new WeakMap();
@@ -250,7 +264,7 @@ function _call(locale, messages, descriptor) {
250
264
  if (typeof message !== "string") throw new Error(`Message for ${descriptor.id} is not a string`);
251
265
  const key = `${locale}:${descriptor.id}`;
252
266
  const format = _classPrivateFieldGet2(_formats, this).get(key) ?? _classPrivateFieldGet2(_formats, this).set(key, mf1ToMessage(locale, message)).get(key);
253
- return String(format.format(descriptor));
267
+ return String(format.format(resolveDescriptorValues(descriptor)));
254
268
  }
255
269
  //#endregion
256
270
  export { Say };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saykit",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Type-safe i18n library with compile-time macro transforms",
5
5
  "keywords": [
6
6
  "i18n",