@rippling/rippling-sdk 0.2.0-alpha.107 → 0.2.0-alpha.109

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 (189) hide show
  1. package/client.d.mts +10 -1
  2. package/client.d.mts.map +1 -1
  3. package/client.d.ts +10 -1
  4. package/client.d.ts.map +1 -1
  5. package/client.js +10 -1
  6. package/client.js.map +1 -1
  7. package/client.mjs +10 -1
  8. package/client.mjs.map +1 -1
  9. package/lib/charts/builders.d.mts +18 -19
  10. package/lib/charts/builders.d.mts.map +1 -1
  11. package/lib/charts/builders.d.ts +18 -19
  12. package/lib/charts/builders.d.ts.map +1 -1
  13. package/lib/charts/builders.js +35 -28
  14. package/lib/charts/builders.js.map +1 -1
  15. package/lib/charts/builders.mjs +35 -28
  16. package/lib/charts/builders.mjs.map +1 -1
  17. package/lib/charts/describe.d.mts +6 -7
  18. package/lib/charts/describe.d.mts.map +1 -1
  19. package/lib/charts/describe.d.ts +6 -7
  20. package/lib/charts/describe.d.ts.map +1 -1
  21. package/lib/charts/describe.js +26 -27
  22. package/lib/charts/describe.js.map +1 -1
  23. package/lib/charts/describe.mjs +27 -28
  24. package/lib/charts/describe.mjs.map +1 -1
  25. package/lib/charts/errors.d.mts +2 -6
  26. package/lib/charts/errors.d.mts.map +1 -1
  27. package/lib/charts/errors.d.ts +2 -6
  28. package/lib/charts/errors.d.ts.map +1 -1
  29. package/lib/charts/errors.js +2 -6
  30. package/lib/charts/errors.js.map +1 -1
  31. package/lib/charts/errors.mjs +2 -6
  32. package/lib/charts/errors.mjs.map +1 -1
  33. package/lib/charts/evaluate.d.mts +5 -7
  34. package/lib/charts/evaluate.d.mts.map +1 -1
  35. package/lib/charts/evaluate.d.ts +5 -7
  36. package/lib/charts/evaluate.d.ts.map +1 -1
  37. package/lib/charts/evaluate.js +21 -35
  38. package/lib/charts/evaluate.js.map +1 -1
  39. package/lib/charts/evaluate.mjs +22 -36
  40. package/lib/charts/evaluate.mjs.map +1 -1
  41. package/lib/charts/schema.d.mts +8 -97
  42. package/lib/charts/schema.d.mts.map +1 -1
  43. package/lib/charts/schema.d.ts +8 -97
  44. package/lib/charts/schema.d.ts.map +1 -1
  45. package/lib/charts/schema.js +186 -65
  46. package/lib/charts/schema.js.map +1 -1
  47. package/lib/charts/schema.mjs +185 -65
  48. package/lib/charts/schema.mjs.map +1 -1
  49. package/lib/charts/types.d.mts +40 -25
  50. package/lib/charts/types.d.mts.map +1 -1
  51. package/lib/charts/types.d.ts +40 -25
  52. package/lib/charts/types.d.ts.map +1 -1
  53. package/lib/charts/types.js +8 -10
  54. package/lib/charts/types.js.map +1 -1
  55. package/lib/charts/types.mjs +8 -10
  56. package/lib/charts/types.mjs.map +1 -1
  57. package/lib/charts/visualization-grammar.d.mts +66 -0
  58. package/lib/charts/visualization-grammar.d.mts.map +1 -0
  59. package/lib/charts/visualization-grammar.d.ts +66 -0
  60. package/lib/charts/visualization-grammar.d.ts.map +1 -0
  61. package/lib/charts/visualization-grammar.js +70 -0
  62. package/lib/charts/visualization-grammar.js.map +1 -0
  63. package/lib/charts/visualization-grammar.mjs +67 -0
  64. package/lib/charts/visualization-grammar.mjs.map +1 -0
  65. package/lib/charts/vocabulary.d.mts +7 -0
  66. package/lib/charts/vocabulary.d.mts.map +1 -0
  67. package/lib/charts/vocabulary.d.ts +7 -0
  68. package/lib/charts/vocabulary.d.ts.map +1 -0
  69. package/lib/charts/vocabulary.js +10 -0
  70. package/lib/charts/vocabulary.js.map +1 -0
  71. package/lib/charts/vocabulary.mjs +7 -0
  72. package/lib/charts/vocabulary.mjs.map +1 -0
  73. package/lib/charts.d.mts +3 -3
  74. package/lib/charts.d.mts.map +1 -1
  75. package/lib/charts.d.ts +3 -3
  76. package/lib/charts.d.ts.map +1 -1
  77. package/lib/charts.js +2 -1
  78. package/lib/charts.js.map +1 -1
  79. package/lib/charts.mjs +1 -1
  80. package/lib/charts.mjs.map +1 -1
  81. package/package.json +4 -2
  82. package/resources/card-transactions.d.mts +579 -0
  83. package/resources/card-transactions.d.mts.map +1 -0
  84. package/resources/card-transactions.d.ts +579 -0
  85. package/resources/card-transactions.d.ts.map +1 -0
  86. package/resources/card-transactions.js +116 -0
  87. package/resources/card-transactions.js.map +1 -0
  88. package/resources/card-transactions.mjs +112 -0
  89. package/resources/card-transactions.mjs.map +1 -0
  90. package/resources/earning-types.d.mts +50 -10
  91. package/resources/earning-types.d.mts.map +1 -1
  92. package/resources/earning-types.d.ts +50 -10
  93. package/resources/earning-types.d.ts.map +1 -1
  94. package/resources/earning-types.js +21 -2
  95. package/resources/earning-types.js.map +1 -1
  96. package/resources/earning-types.mjs +21 -2
  97. package/resources/earning-types.mjs.map +1 -1
  98. package/resources/index.d.mts +4 -1
  99. package/resources/index.d.mts.map +1 -1
  100. package/resources/index.d.ts +4 -1
  101. package/resources/index.d.ts.map +1 -1
  102. package/resources/index.js +10 -4
  103. package/resources/index.js.map +1 -1
  104. package/resources/index.mjs +4 -1
  105. package/resources/index.mjs.map +1 -1
  106. package/resources/reimbursements.d.mts +954 -0
  107. package/resources/reimbursements.d.mts.map +1 -0
  108. package/resources/reimbursements.d.ts +954 -0
  109. package/resources/reimbursements.d.ts.map +1 -0
  110. package/resources/reimbursements.js +140 -0
  111. package/resources/reimbursements.js.map +1 -0
  112. package/resources/reimbursements.mjs +136 -0
  113. package/resources/reimbursements.mjs.map +1 -0
  114. package/resources/spend-categories.d.mts +140 -0
  115. package/resources/spend-categories.d.mts.map +1 -0
  116. package/resources/spend-categories.d.ts +140 -0
  117. package/resources/spend-categories.d.ts.map +1 -0
  118. package/resources/spend-categories.js +83 -0
  119. package/resources/spend-categories.js.map +1 -0
  120. package/resources/spend-categories.mjs +79 -0
  121. package/resources/spend-categories.mjs.map +1 -0
  122. package/resources/workflows/executions.d.mts +153 -0
  123. package/resources/workflows/executions.d.mts.map +1 -0
  124. package/resources/workflows/executions.d.ts +153 -0
  125. package/resources/workflows/executions.d.ts.map +1 -0
  126. package/resources/workflows/executions.js +74 -0
  127. package/resources/workflows/executions.js.map +1 -0
  128. package/resources/workflows/executions.mjs +70 -0
  129. package/resources/workflows/executions.mjs.map +1 -0
  130. package/resources/workflows/index.d.mts +3 -0
  131. package/resources/workflows/index.d.mts.map +1 -0
  132. package/resources/workflows/index.d.ts +3 -0
  133. package/resources/workflows/index.d.ts.map +1 -0
  134. package/resources/workflows/index.js +9 -0
  135. package/resources/workflows/index.js.map +1 -0
  136. package/resources/workflows/index.mjs +4 -0
  137. package/resources/workflows/index.mjs.map +1 -0
  138. package/resources/workflows/workflows.d.mts +977 -0
  139. package/resources/workflows/workflows.d.mts.map +1 -0
  140. package/resources/workflows/workflows.d.ts +977 -0
  141. package/resources/workflows/workflows.d.ts.map +1 -0
  142. package/resources/workflows/workflows.js +246 -0
  143. package/resources/workflows/workflows.js.map +1 -0
  144. package/resources/workflows/workflows.mjs +241 -0
  145. package/resources/workflows/workflows.mjs.map +1 -0
  146. package/resources/workflows.d.mts +1 -972
  147. package/resources/workflows.d.mts.map +1 -1
  148. package/resources/workflows.d.ts +1 -972
  149. package/resources/workflows.d.ts.map +1 -1
  150. package/resources/workflows.js +2 -234
  151. package/resources/workflows.js.map +1 -1
  152. package/resources/workflows.mjs +1 -232
  153. package/resources/workflows.mjs.map +1 -1
  154. package/src/client.ts +63 -12
  155. package/src/lib/charts/README.md +35 -28
  156. package/src/lib/charts/agent-reference.md +73 -0
  157. package/src/lib/charts/builders.ts +51 -35
  158. package/src/lib/charts/capabilities.json +96 -0
  159. package/src/lib/charts/describe.ts +31 -29
  160. package/src/lib/charts/errors.ts +2 -6
  161. package/src/lib/charts/evaluate.ts +25 -38
  162. package/src/lib/charts/schema.ts +232 -66
  163. package/src/lib/charts/types.ts +42 -31
  164. package/src/lib/charts/visualization-grammar.ts +67 -0
  165. package/src/lib/charts/vocabulary.ts +7 -0
  166. package/src/lib/charts.ts +8 -1
  167. package/src/resources/card-transactions.ts +718 -0
  168. package/src/resources/earning-types.ts +52 -10
  169. package/src/resources/index.ts +22 -1
  170. package/src/resources/reimbursements.ts +1157 -0
  171. package/src/resources/spend-categories.ts +175 -0
  172. package/src/resources/workflows/executions.ts +191 -0
  173. package/src/resources/workflows/index.ts +15 -0
  174. package/src/resources/workflows/workflows.ts +1661 -0
  175. package/src/resources/workflows.ts +1 -1647
  176. package/src/version.ts +1 -1
  177. package/version.d.mts +1 -1
  178. package/version.d.ts +1 -1
  179. package/version.js +1 -1
  180. package/version.mjs +1 -1
  181. package/lib/charts/guards.d.mts +0 -15
  182. package/lib/charts/guards.d.mts.map +0 -1
  183. package/lib/charts/guards.d.ts +0 -15
  184. package/lib/charts/guards.d.ts.map +0 -1
  185. package/lib/charts/guards.js +0 -38
  186. package/lib/charts/guards.js.map +0 -1
  187. package/lib/charts/guards.mjs +0 -34
  188. package/lib/charts/guards.mjs.map +0 -1
  189. package/src/lib/charts/guards.ts +0 -42
package/src/client.ts CHANGED
@@ -102,6 +102,13 @@ import {
102
102
  CandidateListResponsesPageCursorURL,
103
103
  Candidates,
104
104
  } from './resources/candidates';
105
+ import {
106
+ CardTransactionListParams,
107
+ CardTransactionListResponse,
108
+ CardTransactionListResponsesPageCursorURL,
109
+ CardTransactionRetrieveResponse,
110
+ CardTransactions,
111
+ } from './resources/card-transactions';
105
112
  import { Companies, CompaniesPageCursorURL, Company, CompanyListParams } from './resources/companies';
106
113
  import {
107
114
  CompanyLegalEntities,
@@ -501,6 +508,13 @@ import {
501
508
  PlatformCapabilityListResponse,
502
509
  PlatformCapabilityListResponsesPageCursorURL,
503
510
  } from './resources/platform-capabilities';
511
+ import {
512
+ ReimbursementListParams,
513
+ ReimbursementListResponse,
514
+ ReimbursementListResponsesPageCursorURL,
515
+ ReimbursementRetrieveResponse,
516
+ Reimbursements,
517
+ } from './resources/reimbursements';
504
518
  import {
505
519
  ReportRunCreateParams,
506
520
  ReportRunCreateResponse,
@@ -595,6 +609,13 @@ import {
595
609
  SoftwareDeploymentUpdateResponse,
596
610
  SoftwareDeployments,
597
611
  } from './resources/software-deployments';
612
+ import {
613
+ SpendCategories,
614
+ SpendCategoryListParams,
615
+ SpendCategoryListResponse,
616
+ SpendCategoryListResponsesPageCursorURL,
617
+ SpendCategoryRetrieveResponse,
618
+ } from './resources/spend-categories';
598
619
  import { SSOMe, SSOMeListParams, SSOMeResource } from './resources/sso-me';
599
620
  import {
600
621
  Team,
@@ -750,18 +771,6 @@ import {
750
771
  WorkflowActionExecutionCreateResponse,
751
772
  WorkflowActionExecutions,
752
773
  } from './resources/workflow-action-executions';
753
- import {
754
- WorkflowCreateParams,
755
- WorkflowCreateResponse,
756
- WorkflowListParams,
757
- WorkflowListResponse,
758
- WorkflowListResponsesPageCursorURL,
759
- WorkflowRetrieveParams,
760
- WorkflowRetrieveResponse,
761
- WorkflowUpdateParams,
762
- WorkflowUpdateResponse,
763
- Workflows,
764
- } from './resources/workflows';
765
774
  import {
766
775
  AgentCreateParams,
767
776
  AgentCreateResponse,
@@ -830,6 +839,18 @@ import {
830
839
  Supergroups,
831
840
  SupergroupsPageCursorURL,
832
841
  } from './resources/supergroups/supergroups';
842
+ import {
843
+ WorkflowCreateParams,
844
+ WorkflowCreateResponse,
845
+ WorkflowListParams,
846
+ WorkflowListResponse,
847
+ WorkflowListResponsesPageCursorURL,
848
+ WorkflowRetrieveParams,
849
+ WorkflowRetrieveResponse,
850
+ WorkflowUpdateParams,
851
+ WorkflowUpdateResponse,
852
+ Workflows,
853
+ } from './resources/workflows/workflows';
833
854
  import { type Fetch } from './internal/builtin-types';
834
855
  import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
835
856
  import { FinalRequestOptions, RequestOptions } from './internal/request-options';
@@ -1731,6 +1752,7 @@ export class RipplingSDK {
1731
1752
  * An application by a candidate to a specific job requisition
1732
1753
  */
1733
1754
  candidateApplications: API.CandidateApplications = new API.CandidateApplications(this);
1755
+ cardTransactions: API.CardTransactions = new API.CardTransactions(this);
1734
1756
  /**
1735
1757
  * Legal entities registered by the company
1736
1758
  */
@@ -1888,6 +1910,7 @@ export class RipplingSDK {
1888
1910
  * Custom objects defined by the company
1889
1911
  */
1890
1912
  platformCapabilities: API.PlatformCapabilities = new API.PlatformCapabilities(this);
1913
+ reimbursements: API.Reimbursements = new API.Reimbursements(this);
1891
1914
  /**
1892
1915
  * Report data for company
1893
1916
  */
@@ -1920,6 +1943,7 @@ export class RipplingSDK {
1920
1943
  * Software deployed to company devices
1921
1944
  */
1922
1945
  softwareDeployments: API.SoftwareDeployments = new API.SoftwareDeployments(this);
1946
+ spendCategories: API.SpendCategories = new API.SpendCategories(this);
1923
1947
  /**
1924
1948
  * Job titles used by the company
1925
1949
  */
@@ -2020,6 +2044,7 @@ RipplingSDK.BreakTypes = BreakTypes;
2020
2044
  RipplingSDK.BusinessStructurePaths = BusinessStructurePaths;
2021
2045
  RipplingSDK.Candidates = Candidates;
2022
2046
  RipplingSDK.CandidateApplications = CandidateApplications;
2047
+ RipplingSDK.CardTransactions = CardTransactions;
2023
2048
  RipplingSDK.CompanyLegalEntities = CompanyLegalEntities;
2024
2049
  RipplingSDK.CompanyLegalEntityWorkers = CompanyLegalEntityWorkers;
2025
2050
  RipplingSDK.CompensationBandsDetails = CompensationBandsDetails;
@@ -2061,6 +2086,7 @@ RipplingSDK.PackageVersionComponentUpdates = PackageVersionComponentUpdates;
2061
2086
  RipplingSDK.PayrollPaymentModeChanges = PayrollPaymentModeChanges;
2062
2087
  RipplingSDK.PayrollRuns = PayrollRuns;
2063
2088
  RipplingSDK.PlatformCapabilities = PlatformCapabilities;
2089
+ RipplingSDK.Reimbursements = Reimbursements;
2064
2090
  RipplingSDK.Reports = Reports;
2065
2091
  RipplingSDK.ReportRuns = ReportRuns;
2066
2092
  RipplingSDK.Sandboxes = Sandboxes;
@@ -2069,6 +2095,7 @@ RipplingSDK.ScheduledJobAssignments = ScheduledJobAssignments;
2069
2095
  RipplingSDK.Shiftassignments = Shiftassignments;
2070
2096
  RipplingSDK.Sites = Sites;
2071
2097
  RipplingSDK.SoftwareDeployments = SoftwareDeployments;
2098
+ RipplingSDK.SpendCategories = SpendCategories;
2072
2099
  RipplingSDK.Titles = Titles;
2073
2100
  RipplingSDK.Unassignedshifts = Unassignedshifts;
2074
2101
  RipplingSDK.VariableCompensationPayouts = VariableCompensationPayouts;
@@ -2476,6 +2503,14 @@ export declare namespace RipplingSDK {
2476
2503
  type CandidateApplicationListParams as CandidateApplicationListParams,
2477
2504
  };
2478
2505
 
2506
+ export {
2507
+ CardTransactions as CardTransactions,
2508
+ type CardTransactionListResponse as CardTransactionListResponse,
2509
+ type CardTransactionRetrieveResponse as CardTransactionRetrieveResponse,
2510
+ type CardTransactionListResponsesPageCursorURL as CardTransactionListResponsesPageCursorURL,
2511
+ type CardTransactionListParams as CardTransactionListParams,
2512
+ };
2513
+
2479
2514
  export {
2480
2515
  CompanyLegalEntities as CompanyLegalEntities,
2481
2516
  type CompanyLegalEntityListResponse as CompanyLegalEntityListResponse,
@@ -2809,6 +2844,14 @@ export declare namespace RipplingSDK {
2809
2844
  type PlatformCapabilityListResponsesPageCursorURL as PlatformCapabilityListResponsesPageCursorURL,
2810
2845
  };
2811
2846
 
2847
+ export {
2848
+ Reimbursements as Reimbursements,
2849
+ type ReimbursementListResponse as ReimbursementListResponse,
2850
+ type ReimbursementRetrieveResponse as ReimbursementRetrieveResponse,
2851
+ type ReimbursementListResponsesPageCursorURL as ReimbursementListResponsesPageCursorURL,
2852
+ type ReimbursementListParams as ReimbursementListParams,
2853
+ };
2854
+
2812
2855
  export { Reports as Reports, type ReportRetrieveResponse as ReportRetrieveResponse };
2813
2856
 
2814
2857
  export {
@@ -2894,6 +2937,14 @@ export declare namespace RipplingSDK {
2894
2937
  type SoftwareDeploymentUpdateParams as SoftwareDeploymentUpdateParams,
2895
2938
  };
2896
2939
 
2940
+ export {
2941
+ SpendCategories as SpendCategories,
2942
+ type SpendCategoryListResponse as SpendCategoryListResponse,
2943
+ type SpendCategoryRetrieveResponse as SpendCategoryRetrieveResponse,
2944
+ type SpendCategoryListResponsesPageCursorURL as SpendCategoryListResponsesPageCursorURL,
2945
+ type SpendCategoryListParams as SpendCategoryListParams,
2946
+ };
2947
+
2897
2948
  export {
2898
2949
  Titles as Titles,
2899
2950
  type TitleListResponse as TitleListResponse,
@@ -21,11 +21,10 @@ by comparing its value against a constant.
21
21
  - **`value`** — this data point's plotted numeric value (a bar's height, a
22
22
  point's y, a slice's amount). It is what the rule compares.
23
23
  - **Comparisons** — `equals`, `isNot`, `lessThan`, `greaterThan`, `lessOrEqual`, `greaterOrEqual`.
24
- - **`when(condition, ifTrue, ifFalse?)`** — a conditional value (channel-agnostic).
25
- `ifFalse` is optional and defaults to `null` — for a colour, no override (default kept).
24
+ - **`when(condition, ifTrue, ifFalse?)`** — a conditional colour. Both results
25
+ are colour strings; `ifFalse` defaults to `null` (keep the chart default).
26
26
  - **`color(rule)`** — target the colour channel. Wrapping `when(...)` in `color(...)`
27
- is what says "this rule sets the colour"; the channel is separate from the condition,
28
- so more channels (opacity, label visibility) are just more wrappers later.
27
+ is what says "this rule sets the colour".
29
28
  - **`literal`** — bare constants (`100`, `'#E24B4A'`) are wrapped automatically.
30
29
 
31
30
  ```ts
@@ -46,7 +45,7 @@ Agent writes a rule with these builders (the only consumer that imports the SDK)
46
45
  -> the placeholder is emitted into the chart option, like the {$fn} placeholders
47
46
  a chart already emits, and crosses to the app as plain JSON
48
47
  -> renderer resolves {$rule} against the point's value -> a colour, drawn
49
- -> settings panel reads the same {$rule} tree -> controls the user can edit
48
+ -> settings panel reads the same flat {$rule} value -> controls the user can edit
50
49
  ```
51
50
 
52
51
  ```json
@@ -64,28 +63,38 @@ Agent writes a rule with these builders (the only consumer that imports the SDK)
64
63
  `channel: 'color'` says what the rule targets, so a reader sees it without
65
64
  inferring from where it sits. `evaluate(rule, { value })` resolves it to a colour
66
65
  for the renderer; `describe(rule)` turns it into the controls the settings panel
67
- shows. Both accept the placeholder or the bare tree. A node can only ever be one
68
- of a fixed set of kinds, so the three faces never drift — the `chartRuleSchema`
69
- export describes that closed set.
66
+ shows. Both accept the placeholder or a bare node. A node can only ever be one
67
+ of a fixed set of kinds. `chartRuleSchema` is the executable Valibot schema for
68
+ that closed set, and `parseChartRule(unknown)` is the SDK-owned runtime boundary
69
+ for persisted or agent-authored JSON.
70
70
 
71
71
  ## How it is consumed
72
72
 
73
- The app never has to import this package. The rule crosses as data — a `{$rule}`
74
- placeholder alongside the `{$fn}` ones — and the app's own rehydrator resolves it
75
- at render time. Two ways, and only the first is needed:
73
+ The rule crosses as data — a `{$rule}` placeholder alongside the `{$fn}` ones.
74
+ Consumers have two integration choices:
76
75
 
77
- 1. **Contract-only** — the app keeps its own small evaluator and validates it
78
- against `chartRuleSchema` (published here) with a contract test, so the two
79
- can't drift without CI noticing. No dependency on this package.
80
- 2. **Shared** — the app imports `evaluate`/`describe` from here, so the closed
81
- set is defined exactly once. A no-drift choice, not a requirement.
76
+ 1. **Shared (preferred)** — import `evaluate`, `describe`, and
77
+ `parseChartRule` from the SDK. Parse once when the chart option is hydrated,
78
+ then pass that parsed value to `evaluate` for every datum. The parsed value is
79
+ an immutable validated clone, so repeated evaluation does not re-run schema
80
+ validation.
81
+ 2. **Serialized contract** — another language/runtime may interpret the JSON
82
+ independently. It must maintain parity tests against SDK builder output and
83
+ fail closed when the package-level `capabilities.json` contract version is
84
+ unsupported or a serialized rule contains an unknown node kind. Individual
85
+ serialized rules do not carry a version field.
86
+
87
+ Valibot is a production dependency because validation executes in shipped SDK
88
+ code. Node and Deno npm consumers resolve it transitively from the package; it
89
+ is not duplicated in the agent reference or capability manifest.
82
90
 
83
91
  ## Where it is going
84
92
 
85
- The vocabulary starts small on purpose and is built to grow. Each addition is a
86
- new kind (or channel) — one builder, one `evaluate` case, one `describe` case,
87
- one `schema` entry — and it becomes editable in the panel the moment it lands,
88
- with no change to charts already using it. Planned next, roughly in order:
93
+ The vocabulary starts small on purpose. The v1 schema stays flat; features that
94
+ require nesting or a different expression shape must use a new contract version
95
+ rather than silently widening v1. A compatible channel or leaf addition still
96
+ requires one builder, evaluator case, description case, and schema entry.
97
+ Potential future versions may add:
89
98
 
90
99
  - **More channels** — opacity, label visibility (`show`), and the like, added
91
100
  alongside `channel: 'color'`.
@@ -104,11 +113,9 @@ with no change to charts already using it. Planned next, roughly in order:
104
113
 
105
114
  ## Safety
106
115
 
107
- A rule is data, not code, so evaluating one is not running code. The vocabulary
108
- has no primitive with a side effect, so an untrusted, user-edited tree is safe
109
- to evaluate: the worst a malformed tree can do is throw a `ChartRuleError`, which
110
- the caller catches and turns into the read-only "configured in code" state. There
111
- are no loops or recursion, and a tree nested past `MAX_RULE_DEPTH` throws
112
- `RuleDepthError` (also a `ChartRuleError`) rather than overflowing the stack.
113
- Catch `ChartRuleError` — every failure mode is a subclass of it (`UnknownNodeError`,
114
- `RuleTypeError`, `RuleDepthError`).
116
+ A rule is data, not code: its vocabulary has no callbacks, loops, or side
117
+ effects. The v1 schema is non-recursive, so rule input cannot create recursive
118
+ validation or evaluation work. Runtime parsing also rejects inherited rule
119
+ fields before Valibot reads them, preventing prototype data from supplying
120
+ operands. Malformed rules throw a `ChartRuleError`; callers can use that one
121
+ base class for every rule-specific failure.
@@ -0,0 +1,73 @@
1
+ # Visualization grammar authoring reference
2
+
3
+ Use these builders only when a chart property must change according to the
4
+ current data point's numeric value. They produce JSON-safe rule data; they do not
5
+ execute callbacks or render a chart.
6
+
7
+ ## Import
8
+
9
+ In the Deno TypeScript sandbox, import from the module specifier published in
10
+ `capabilities.json`:
11
+
12
+ ```ts
13
+ import { color, greaterThan, value, when } from 'npm:@rippling/rippling-sdk/lib/charts';
14
+ ```
15
+
16
+ ## Builders
17
+
18
+ - `value` reads the current data point's plotted numeric value.
19
+ - `literal(scalar)` explicitly creates a constant. Bare numbers, strings,
20
+ booleans, and `null` are converted to literals automatically.
21
+ - `equals(left, right)`, `isNot(left, right)`, `lessThan(left, right)`,
22
+ `greaterThan(left, right)`, `lessOrEqual(left, right)`, and
23
+ `greaterOrEqual(left, right)` return a condition.
24
+ - `when(condition, ifTrue, ifFalse?)` returns `ifTrue` when the condition is true
25
+ and `ifFalse` otherwise. Both results are colour strings; the omitted false
26
+ branch becomes `null` to preserve the chart's default colour.
27
+ - `color(when(...))` marks the conditional result as a color rule.
28
+
29
+ Example: highlight values over 20 and otherwise preserve the chart's default
30
+ color.
31
+
32
+ ```ts
33
+ const conditionalColor = color(when(greaterThan(value, 20), '$token:categorical.series-5'));
34
+ ```
35
+
36
+ The builders return plain data that renderers and editors can read. Always use
37
+ the builders above. Do not hand-author the serialized `$rule` object shown here:
38
+
39
+ ```json
40
+ {
41
+ "channel": "color",
42
+ "$rule": {
43
+ "kind": "ifElse",
44
+ "cond": {
45
+ "kind": "greaterThan",
46
+ "left": { "kind": "value" },
47
+ "right": { "kind": "literal", "value": 20 }
48
+ },
49
+ "then": { "kind": "literal", "value": "$token:categorical.series-5" },
50
+ "else": { "kind": "literal", "value": null }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Current limits
56
+
57
+ The current contract supports only the `color` channel and per-point `value`.
58
+ It has one fixed, non-recursive shape: comparisons contain only `value` or
59
+ literal operands, and `when` contains one comparison plus two colour literals.
60
+ Do not place comparisons, `when(...)`, or `color(...)` inside another operand or
61
+ branch.
62
+
63
+ Rules do not calculate aggregates such as maximum, average, or percentile. Chart
64
+ code may calculate a finite scalar threshold from its data first and then use
65
+ that scalar in a rule. For example, after computing an 80th-percentile
66
+ `threshold`, use
67
+ `color(when(greaterOrEqual(value, threshold), highlightColor))` to highlight the
68
+ top 20%. The rule remains a per-point comparison; the surrounding chart code
69
+ owns the aggregate calculation.
70
+
71
+ Other data fields, compound boolean logic, opacity, label visibility, and other
72
+ output channels are not supported. Keep static colors as ordinary chart values
73
+ rather than wrapping them in rules.
@@ -1,37 +1,48 @@
1
1
  import { ChartRuleError } from './errors';
2
2
  import {
3
- type ComparisonKind,
4
- type ComparisonNode,
3
+ type ConditionNode,
4
+ type ComparisonOperandNode,
5
+ type EqualityComparisonNode,
5
6
  type IfElseNode,
6
7
  type LiteralNode,
8
+ type NumericComparisonNode,
9
+ type NumericOperandNode,
7
10
  type RefNode,
8
- type RuleNode,
9
11
  type RulePlaceholder,
10
12
  type Scalar,
11
13
  } from './types';
12
14
 
13
- /** A rule node, a nested rule (`{$rule}` placeholder), or a bare scalar. */
14
- export type Operand = RuleNode | RulePlaceholder | Scalar;
15
+ /** A non-recursive comparison operand: `value`, a literal node, or a scalar. */
16
+ export type Operand = ComparisonOperandNode | Scalar;
17
+ export type NumericOperand = NumericOperandNode | number;
15
18
 
16
- function isRuleNode(operand: Operand): operand is RuleNode {
17
- return typeof operand === 'object' && operand !== null && 'kind' in operand;
19
+ function hasOwn(value: object, key: PropertyKey): boolean {
20
+ return Object.prototype.hasOwnProperty.call(value, key);
21
+ }
22
+
23
+ function isOperandNode(operand: Operand): operand is ComparisonOperandNode {
24
+ return typeof operand === 'object' && operand !== null && hasOwn(operand, 'kind');
18
25
  }
19
26
 
20
27
  /** True when a value is a `{$rule}` placeholder — the marker the builders emit. */
21
28
  export function isRulePlaceholder(value: unknown): value is RulePlaceholder {
22
- return typeof value === 'object' && value !== null && '$rule' in value;
29
+ return typeof value === 'object' && value !== null && hasOwn(value, '$rule');
23
30
  }
24
31
 
25
32
  /** Wrap a bare scalar as a literal node. */
26
- export function literal(value: Scalar): LiteralNode {
33
+ export function literal<const TValue extends Scalar>(value: TValue): LiteralNode<TValue> {
34
+ if (typeof value === 'number' && !Number.isFinite(value)) {
35
+ throw new ChartRuleError('literal(value) requires a finite number');
36
+ }
27
37
  return { kind: 'literal', value };
28
38
  }
29
39
 
30
- function toNode(operand: Operand): RuleNode {
31
- if (isRulePlaceholder(operand)) {
32
- return operand.$rule; // a nested rule — unwrap it, never wrap it as a literal
33
- }
34
- return isRuleNode(operand) ? operand : literal(operand);
40
+ function toOperandNode(operand: Operand): ComparisonOperandNode {
41
+ return isOperandNode(operand) ? operand : literal(operand);
42
+ }
43
+
44
+ function toNumericOperandNode(operand: NumericOperand): NumericOperandNode {
45
+ return typeof operand === 'number' ? literal(operand) : operand;
35
46
  }
36
47
 
37
48
  /**
@@ -40,36 +51,43 @@ function toNode(operand: Operand): RuleNode {
40
51
  */
41
52
  export const value: RefNode = Object.freeze({ kind: 'value' });
42
53
 
43
- /* Comparisons — return a condition. */
44
- function comparison(kind: ComparisonKind): (left: Operand, right: Operand) => ComparisonNode {
45
- return (left, right) => ({ kind, left: toNode(left), right: toNode(right) });
54
+ /* Comparisons — return a condition with no nested expressions. */
55
+ function equalityComparison(
56
+ kind: EqualityComparisonNode['kind'],
57
+ ): (left: Operand, right: Operand) => EqualityComparisonNode {
58
+ return (left, right) => ({ kind, left: toOperandNode(left), right: toOperandNode(right) });
59
+ }
60
+ function numericComparison(
61
+ kind: NumericComparisonNode['kind'],
62
+ ): (left: NumericOperand, right: NumericOperand) => NumericComparisonNode {
63
+ return (left, right) => ({ kind, left: toNumericOperandNode(left), right: toNumericOperandNode(right) });
46
64
  }
47
- export const equals = comparison('equals');
48
- export const isNot = comparison('isNot');
49
- export const lessThan = comparison('lessThan');
50
- export const greaterThan = comparison('greaterThan');
51
- export const lessOrEqual = comparison('lessOrEqual');
52
- export const greaterOrEqual = comparison('greaterOrEqual');
65
+ export const equals = equalityComparison('equals');
66
+ export const isNot = equalityComparison('isNot');
67
+ export const lessThan = numericComparison('lessThan');
68
+ export const greaterThan = numericComparison('greaterThan');
69
+ export const lessOrEqual = numericComparison('lessOrEqual');
70
+ export const greaterOrEqual = numericComparison('greaterOrEqual');
53
71
 
54
72
  /**
55
- * A conditional value: pick `ifTrue` when the condition holds, else `ifFalse`.
56
- * Channel-agnostic — wrap it in a channel builder (`color`) to target something.
73
+ * A conditional colour: pick `ifTrue` when the condition holds, else `ifFalse`.
57
74
  *
58
75
  * when(lessThan(value, 100), '#E24B4A', '#378ADD')
59
76
  * // → '#E24B4A' when this point's value is under 100, '#378ADD' otherwise
60
77
  *
61
78
  * `ifFalse` is optional and defaults to `null` — for a colour, that means no
62
- * override (the chart's default is kept). Returns a plain node, not a placeholder.
79
+ * override (the chart's default is kept). Branches are colour literals only;
80
+ * nested rules are intentionally unsupported in v1.
63
81
  */
64
- export function when(condition: RuleNode, ifTrue: Operand, ifFalse?: Operand): IfElseNode {
82
+ export function when(condition: ConditionNode, ifTrue: string, ifFalse: string | null = null): IfElseNode {
65
83
  if (ifTrue === undefined) {
66
84
  throw new ChartRuleError('when(condition, ifTrue, ifFalse?) needs a value for the true case');
67
85
  }
68
86
  return {
69
87
  kind: 'ifElse',
70
88
  cond: condition,
71
- then: toNode(ifTrue),
72
- else: toNode(ifFalse ?? null),
89
+ then: literal(ifTrue),
90
+ else: literal(ifFalse),
73
91
  };
74
92
  }
75
93
 
@@ -80,11 +98,9 @@ export function when(condition: RuleNode, ifTrue: Operand, ifFalse?: Operand): I
80
98
  * color(when(lessThan(value, 100), '#E24B4A', '#378ADD'))
81
99
  * // → red when this point's value is under 100, blue otherwise
82
100
  *
83
- * Takes a conditional value — a `when(...)` (`IfElseNode`) or an already-wrapped
84
- * rule — not a bare `value` or comparison: those resolve to a number or a
85
- * boolean, which is not a colour. `evaluate` enforces the same at runtime for a
86
- * deserialized rule. Returns a `{$rule}` placeholder tagged `channel: 'color'`.
101
+ * Takes the flat conditional value produced by `when(...)`. Returns a `{$rule}`
102
+ * placeholder tagged `channel: 'color'`.
87
103
  */
88
- export function color(rule: IfElseNode | RulePlaceholder): RulePlaceholder {
89
- return { $rule: isRulePlaceholder(rule) ? rule.$rule : rule, channel: 'color' };
104
+ export function color(rule: IfElseNode): RulePlaceholder {
105
+ return { $rule: rule, channel: 'color' };
90
106
  }
@@ -0,0 +1,96 @@
1
+ {
2
+ "contractVersion": 1,
3
+ "moduleSpecifier": "npm:@rippling/rippling-sdk/lib/charts",
4
+ "builders": {
5
+ "value": {
6
+ "kind": "input",
7
+ "returns": "number"
8
+ },
9
+ "literal": {
10
+ "kind": "literal",
11
+ "parameters": [
12
+ "scalar"
13
+ ],
14
+ "returns": "value"
15
+ },
16
+ "equals": {
17
+ "kind": "comparison",
18
+ "parameters": [
19
+ "value",
20
+ "value"
21
+ ],
22
+ "returns": "condition"
23
+ },
24
+ "isNot": {
25
+ "kind": "comparison",
26
+ "parameters": [
27
+ "value",
28
+ "value"
29
+ ],
30
+ "returns": "condition"
31
+ },
32
+ "lessThan": {
33
+ "kind": "comparison",
34
+ "parameters": [
35
+ "value",
36
+ "value"
37
+ ],
38
+ "returns": "condition"
39
+ },
40
+ "greaterThan": {
41
+ "kind": "comparison",
42
+ "parameters": [
43
+ "value",
44
+ "value"
45
+ ],
46
+ "returns": "condition"
47
+ },
48
+ "lessOrEqual": {
49
+ "kind": "comparison",
50
+ "parameters": [
51
+ "value",
52
+ "value"
53
+ ],
54
+ "returns": "condition"
55
+ },
56
+ "greaterOrEqual": {
57
+ "kind": "comparison",
58
+ "parameters": [
59
+ "value",
60
+ "value"
61
+ ],
62
+ "returns": "condition"
63
+ },
64
+ "when": {
65
+ "kind": "conditional",
66
+ "parameters": [
67
+ "condition",
68
+ "color",
69
+ "color?"
70
+ ],
71
+ "returns": "conditional-color"
72
+ },
73
+ "color": {
74
+ "kind": "channel",
75
+ "parameters": [
76
+ "conditional-color"
77
+ ],
78
+ "returns": "color-rule",
79
+ "placeholderChannel": "color"
80
+ }
81
+ },
82
+ "supportedChannels": [
83
+ "color"
84
+ ],
85
+ "supportedNodeKinds": [
86
+ "literal",
87
+ "value",
88
+ "equals",
89
+ "isNot",
90
+ "lessThan",
91
+ "greaterThan",
92
+ "lessOrEqual",
93
+ "greaterOrEqual",
94
+ "ifElse"
95
+ ]
96
+ }