@client-compose/client 0.9.0 → 0.10.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.
package/dist/strings.d.ts CHANGED
@@ -1,18 +1,5 @@
1
- import { type AppStringsDescriptor, type ClientContext, type PluralRules, type StringParams, type Strings, type StringsResponse, type StringTemplate } from "@client-compose/protocol";
2
- /** A count's plural category in a language: the first whose condition holds, or "other". */
3
- export declare function pluralCategory(rules: PluralRules | undefined, count: number): string;
4
- /** The values a string's params take. A counted string's `count` picks its variant. */
5
- export type StringValues = Record<string, string | number>;
6
- /**
7
- * A string's words with its params filled in. Variants are chosen by the exact count, then its
8
- * plural category, then `#*`.
9
- */
10
- export declare function formatString(template: StringTemplate | undefined, values?: StringValues, plurals?: PluralRules): string;
11
- /**
12
- * Strings as a renderer receives them: each declared string with no params as its text, each with
13
- * params as a function filling them in. A string the composer didn't send is empty.
14
- */
15
- export declare function buildStrings<S>(declared: StringParams, strings: Strings | undefined, plurals: PluralRules | undefined): S;
1
+ import { type AppStringsDescriptor, type ClientContext, type StringsResponse } from "@client-compose/protocol";
2
+ export { buildStrings, formatString, pluralCategory, type StringValues, } from "@client-compose/protocol";
16
3
  /** The app strings, typed by their generated descriptor: `appStrings(AppStrings, response).retry`. */
17
4
  export declare function appStrings<S>(descriptor: AppStringsDescriptor<S>, response: StringsResponse): S;
18
5
  /** Thrown for a strings request the composer didn't answer with 200 and its strings. */
@@ -1 +1 @@
1
- {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,WAAW,EAEhB,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,0BAA0B,CAAC;AAIlC,4FAA4F;AAC5F,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOpF;AA8BD,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,cAAc,GAAG,SAAS,EACpC,MAAM,GAAE,YAAiB,EACzB,OAAO,CAAC,EAAE,WAAW,GACpB,MAAM,CAQR;AAqBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC5B,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,OAAO,EAAE,WAAW,GAAG,SAAS,GAC/B,CAAC,CAYH;AAID,sGAAsG;AACtG,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,GAAG,CAAC,CAE/F;AAED,wFAAwF;AACxF,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAKzC;AAYD,kEAAkE;AAClE,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE,WAAgB,EACtB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
1
+ {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,aAAa,EAElB,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC;AAIlC,sGAAsG;AACtG,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,GAAG,CAAC,CAE/F;AAED,wFAAwF;AACxF,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAKzC;AAYD,kEAAkE;AAClE,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,aAAa,EACrB,IAAI,GAAE,WAAgB,EACtB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
package/dist/strings.js CHANGED
@@ -1,82 +1,9 @@
1
1
  // Strings (spec §4.7): the words a client shows, from the composer. Templates are filled in here,
2
2
  // counted strings pick their variant by the language's plural rules, and an island's strings
3
3
  // become the typed `t` its renderer receives.
4
- import { PROTOCOL_VERSION, } from "@client-compose/protocol";
5
- // ---- Plural rules ----
6
- /** A count's plural category in a language: the first whose condition holds, or "other". */
7
- export function pluralCategory(rules, count) {
8
- for (const [category, condition] of Object.entries(rules ?? {})) {
9
- if (condition !== undefined && holds(condition, count)) {
10
- return category;
11
- }
12
- }
13
- return "other";
14
- }
15
- /**
16
- * Whether a CLDR plural condition holds for a whole number: `or` of `and`s of relations like
17
- * `i % 10 = 2..4` or `v = 0`. For a whole number, `n` and `i` are the number, and `v`, `w`, `f`,
18
- * `t`, `c` and `e` are zero.
19
- */
20
- function holds(condition, count) {
21
- return condition.split(" or ").some((all) => all.split(" and ").every((r) => relates(r, count)));
22
- }
23
- const RELATION = /^\s*([nivwftce])\s*(?:%\s*(\d+))?\s*(!=|=)\s*(.+?)\s*$/;
24
- function relates(relation, count) {
25
- const match = RELATION.exec(relation);
26
- if (!match) {
27
- return false;
28
- }
29
- const [, operand = "", modulus, op, ranges = ""] = match;
30
- const base = operand === "n" || operand === "i" ? Math.abs(Math.trunc(count)) : 0;
31
- const value = modulus === undefined ? base : base % Number(modulus);
32
- const inRanges = ranges.split(",").some((range) => {
33
- const [from = "", to] = range.trim().split("..");
34
- return to === undefined ? value === Number(from) : value >= Number(from) && value <= Number(to);
35
- });
36
- return op === "=" ? inRanges : !inRanges;
37
- }
38
- /**
39
- * A string's words with its params filled in. Variants are chosen by the exact count, then its
40
- * plural category, then `#*`.
41
- */
42
- export function formatString(template, values = {}, plurals) {
43
- if (template === undefined) {
44
- return "";
45
- }
46
- const text = typeof template === "string" ? template : variant(template, values.count, plurals);
47
- return text.replace(/\{([A-Za-z0-9]+)\}/g, (slot, name) => name in values ? String(values[name]) : slot);
48
- }
49
- function variant(variants, count, plurals) {
50
- const n = Number(count);
51
- if (Number.isFinite(n)) {
52
- const exact = variants[`#${n}`];
53
- if (exact !== undefined) {
54
- return exact;
55
- }
56
- const category = variants[`#${pluralCategory(plurals, n)}`];
57
- if (category !== undefined) {
58
- return category;
59
- }
60
- }
61
- return variants["#*"] ?? "";
62
- }
63
- /**
64
- * Strings as a renderer receives them: each declared string with no params as its text, each with
65
- * params as a function filling them in. A string the composer didn't send is empty.
66
- */
67
- export function buildStrings(declared, strings, plurals) {
68
- const t = {};
69
- for (const [key, params] of Object.entries(declared)) {
70
- const template = strings?.[key];
71
- t[key] =
72
- params.length === 0
73
- ? formatString(template, {}, plurals)
74
- : (values) => formatString(template, values, plurals);
75
- }
76
- // The declared keys and params are the ones codegen typed S with.
77
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
78
- return t;
79
- }
4
+ import { buildStrings, PROTOCOL_VERSION, } from "@client-compose/protocol";
5
+ // Shared with composers; re-exported so apps need only this package.
6
+ export { buildStrings, formatString, pluralCategory, } from "@client-compose/protocol";
80
7
  // ---- App strings ----
81
8
  /** The app strings, typed by their generated descriptor: `appStrings(AppStrings, response).retry`. */
82
9
  export function appStrings(descriptor, response) {
@@ -1 +1 @@
1
- {"version":3,"file":"strings.js","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strings.js","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,6FAA6F;AAC7F,8CAA8C;AAE9C,OAAO,EAEL,YAAY,EAEZ,gBAAgB,GAEjB,MAAM,0BAA0B,CAAC;AAElC,qEAAqE;AACrE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,GAEf,MAAM,0BAA0B,CAAC;AAElC,wBAAwB;AAExB,sGAAsG;AACtG,MAAM,UAAU,UAAU,CAAI,UAAmC,EAAE,QAAyB;IAC1F,OAAO,YAAY,CAAI,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;AACjF,CAAC;AAED,wFAAwF;AACxF,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,MAAM,CAAS;IACf,IAAI,CAAS;IAEtB,YAAY,MAAc,EAAE,IAAY;QACtC,KAAK,CAAC,sCAAsC,MAAM,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEvE,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,MAAqB,EACrB,OAAoB,EAAE,EACtB,YAA0B,KAAK;IAE/B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,OAAO,UAAU,EAAE;QAChD,GAAG,IAAI;QACP,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC7D,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@client-compose/client",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Framework-agnostic Client Compose client: island registry, screen requests and render planning.",
5
5
  "keywords": [
6
6
  "client-compose",
@@ -44,10 +44,10 @@
44
44
  "LICENSE"
45
45
  ],
46
46
  "dependencies": {
47
- "@client-compose/protocol": "0.6.0"
47
+ "@client-compose/protocol": "0.7.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@client-compose/conformance": "0.9.0"
50
+ "@client-compose/conformance": "0.10.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "access": "public"
package/src/strings.ts CHANGED
@@ -4,116 +4,19 @@
4
4
 
5
5
  import {
6
6
  type AppStringsDescriptor,
7
+ buildStrings,
7
8
  type ClientContext,
8
- type PluralRules,
9
9
  PROTOCOL_VERSION,
10
- type StringParams,
11
- type Strings,
12
10
  type StringsResponse,
13
- type StringTemplate,
14
11
  } from "@client-compose/protocol";
15
12
 
16
- // ---- Plural rules ----
17
-
18
- /** A count's plural category in a language: the first whose condition holds, or "other". */
19
- export function pluralCategory(rules: PluralRules | undefined, count: number): string {
20
- for (const [category, condition] of Object.entries(rules ?? {})) {
21
- if (condition !== undefined && holds(condition, count)) {
22
- return category;
23
- }
24
- }
25
- return "other";
26
- }
27
-
28
- /**
29
- * Whether a CLDR plural condition holds for a whole number: `or` of `and`s of relations like
30
- * `i % 10 = 2..4` or `v = 0`. For a whole number, `n` and `i` are the number, and `v`, `w`, `f`,
31
- * `t`, `c` and `e` are zero.
32
- */
33
- function holds(condition: string, count: number): boolean {
34
- return condition.split(" or ").some((all) => all.split(" and ").every((r) => relates(r, count)));
35
- }
36
-
37
- const RELATION = /^\s*([nivwftce])\s*(?:%\s*(\d+))?\s*(!=|=)\s*(.+?)\s*$/;
38
-
39
- function relates(relation: string, count: number): boolean {
40
- const match = RELATION.exec(relation);
41
- if (!match) {
42
- return false;
43
- }
44
- const [, operand = "", modulus, op, ranges = ""] = match;
45
- const base = operand === "n" || operand === "i" ? Math.abs(Math.trunc(count)) : 0;
46
- const value = modulus === undefined ? base : base % Number(modulus);
47
- const inRanges = ranges.split(",").some((range) => {
48
- const [from = "", to] = range.trim().split("..");
49
- return to === undefined ? value === Number(from) : value >= Number(from) && value <= Number(to);
50
- });
51
- return op === "=" ? inRanges : !inRanges;
52
- }
53
-
54
- // ---- Templates ----
55
-
56
- /** The values a string's params take. A counted string's `count` picks its variant. */
57
- export type StringValues = Record<string, string | number>;
58
-
59
- /**
60
- * A string's words with its params filled in. Variants are chosen by the exact count, then its
61
- * plural category, then `#*`.
62
- */
63
- export function formatString(
64
- template: StringTemplate | undefined,
65
- values: StringValues = {},
66
- plurals?: PluralRules,
67
- ): string {
68
- if (template === undefined) {
69
- return "";
70
- }
71
- const text = typeof template === "string" ? template : variant(template, values.count, plurals);
72
- return text.replace(/\{([A-Za-z0-9]+)\}/g, (slot, name: string) =>
73
- name in values ? String(values[name]) : slot,
74
- );
75
- }
76
-
77
- function variant(
78
- variants: Record<string, string>,
79
- count: string | number | undefined,
80
- plurals: PluralRules | undefined,
81
- ): string {
82
- const n = Number(count);
83
- if (Number.isFinite(n)) {
84
- const exact = variants[`#${n}`];
85
- if (exact !== undefined) {
86
- return exact;
87
- }
88
- const category = variants[`#${pluralCategory(plurals, n)}`];
89
- if (category !== undefined) {
90
- return category;
91
- }
92
- }
93
- return variants["#*"] ?? "";
94
- }
95
-
96
- /**
97
- * Strings as a renderer receives them: each declared string with no params as its text, each with
98
- * params as a function filling them in. A string the composer didn't send is empty.
99
- */
100
- export function buildStrings<S>(
101
- declared: StringParams,
102
- strings: Strings | undefined,
103
- plurals: PluralRules | undefined,
104
- ): S {
105
- const t: Record<string, string | ((values: StringValues) => string)> = {};
106
- for (const [key, params] of Object.entries(declared)) {
107
- const template = strings?.[key];
108
- t[key] =
109
- params.length === 0
110
- ? formatString(template, {}, plurals)
111
- : (values: StringValues) => formatString(template, values, plurals);
112
- }
113
- // The declared keys and params are the ones codegen typed S with.
114
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
115
- return t as S;
116
- }
13
+ // Shared with composers; re-exported so apps need only this package.
14
+ export {
15
+ buildStrings,
16
+ formatString,
17
+ pluralCategory,
18
+ type StringValues,
19
+ } from "@client-compose/protocol";
117
20
 
118
21
  // ---- App strings ----
119
22