@rippling/rippling-sdk 0.2.0-alpha.108 → 0.2.0-alpha.110
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/client.d.mts +14 -0
- package/client.d.mts.map +1 -1
- package/client.d.ts +14 -0
- package/client.d.ts.map +1 -1
- package/client.js +18 -0
- package/client.js.map +1 -1
- package/client.mjs +18 -0
- package/client.mjs.map +1 -1
- package/index.d.mts +5 -0
- package/index.d.mts.map +1 -1
- package/index.d.ts +5 -0
- package/index.d.ts.map +1 -1
- package/index.js +11 -1
- package/index.js.map +1 -1
- package/index.mjs +5 -0
- package/index.mjs.map +1 -1
- package/lib/charts/builders.d.mts +18 -19
- package/lib/charts/builders.d.mts.map +1 -1
- package/lib/charts/builders.d.ts +18 -19
- package/lib/charts/builders.d.ts.map +1 -1
- package/lib/charts/builders.js +35 -28
- package/lib/charts/builders.js.map +1 -1
- package/lib/charts/builders.mjs +35 -28
- package/lib/charts/builders.mjs.map +1 -1
- package/lib/charts/describe.d.mts +6 -7
- package/lib/charts/describe.d.mts.map +1 -1
- package/lib/charts/describe.d.ts +6 -7
- package/lib/charts/describe.d.ts.map +1 -1
- package/lib/charts/describe.js +26 -27
- package/lib/charts/describe.js.map +1 -1
- package/lib/charts/describe.mjs +27 -28
- package/lib/charts/describe.mjs.map +1 -1
- package/lib/charts/errors.d.mts +2 -6
- package/lib/charts/errors.d.mts.map +1 -1
- package/lib/charts/errors.d.ts +2 -6
- package/lib/charts/errors.d.ts.map +1 -1
- package/lib/charts/errors.js +2 -6
- package/lib/charts/errors.js.map +1 -1
- package/lib/charts/errors.mjs +2 -6
- package/lib/charts/errors.mjs.map +1 -1
- package/lib/charts/evaluate.d.mts +5 -7
- package/lib/charts/evaluate.d.mts.map +1 -1
- package/lib/charts/evaluate.d.ts +5 -7
- package/lib/charts/evaluate.d.ts.map +1 -1
- package/lib/charts/evaluate.js +21 -35
- package/lib/charts/evaluate.js.map +1 -1
- package/lib/charts/evaluate.mjs +22 -36
- package/lib/charts/evaluate.mjs.map +1 -1
- package/lib/charts/schema.d.mts +8 -97
- package/lib/charts/schema.d.mts.map +1 -1
- package/lib/charts/schema.d.ts +8 -97
- package/lib/charts/schema.d.ts.map +1 -1
- package/lib/charts/schema.js +186 -65
- package/lib/charts/schema.js.map +1 -1
- package/lib/charts/schema.mjs +185 -65
- package/lib/charts/schema.mjs.map +1 -1
- package/lib/charts/types.d.mts +40 -25
- package/lib/charts/types.d.mts.map +1 -1
- package/lib/charts/types.d.ts +40 -25
- package/lib/charts/types.d.ts.map +1 -1
- package/lib/charts/types.js +8 -10
- package/lib/charts/types.js.map +1 -1
- package/lib/charts/types.mjs +8 -10
- package/lib/charts/types.mjs.map +1 -1
- package/lib/charts/visualization-grammar.d.mts +66 -0
- package/lib/charts/visualization-grammar.d.mts.map +1 -0
- package/lib/charts/visualization-grammar.d.ts +66 -0
- package/lib/charts/visualization-grammar.d.ts.map +1 -0
- package/lib/charts/visualization-grammar.js +70 -0
- package/lib/charts/visualization-grammar.js.map +1 -0
- package/lib/charts/visualization-grammar.mjs +67 -0
- package/lib/charts/visualization-grammar.mjs.map +1 -0
- package/lib/charts/vocabulary.d.mts +7 -0
- package/lib/charts/vocabulary.d.mts.map +1 -0
- package/lib/charts/vocabulary.d.ts +7 -0
- package/lib/charts/vocabulary.d.ts.map +1 -0
- package/lib/charts/vocabulary.js +10 -0
- package/lib/charts/vocabulary.js.map +1 -0
- package/lib/charts/vocabulary.mjs +7 -0
- package/lib/charts/vocabulary.mjs.map +1 -0
- package/lib/charts.d.mts +3 -3
- package/lib/charts.d.mts.map +1 -1
- package/lib/charts.d.ts +3 -3
- package/lib/charts.d.ts.map +1 -1
- package/lib/charts.js +2 -1
- package/lib/charts.js.map +1 -1
- package/lib/charts.mjs +1 -1
- package/lib/charts.mjs.map +1 -1
- package/lib/manifest/composition.d.mts +21 -0
- package/lib/manifest/composition.d.mts.map +1 -0
- package/lib/manifest/composition.d.ts +21 -0
- package/lib/manifest/composition.d.ts.map +1 -0
- package/lib/manifest/composition.js +103 -0
- package/lib/manifest/composition.js.map +1 -0
- package/lib/manifest/composition.mjs +99 -0
- package/lib/manifest/composition.mjs.map +1 -0
- package/lib/manifest/definitions/_object-records.d.mts +23 -0
- package/lib/manifest/definitions/_object-records.d.mts.map +1 -0
- package/lib/manifest/definitions/_object-records.d.ts +23 -0
- package/lib/manifest/definitions/_object-records.d.ts.map +1 -0
- package/lib/manifest/definitions/_object-records.js +151 -0
- package/lib/manifest/definitions/_object-records.js.map +1 -0
- package/lib/manifest/definitions/_object-records.mjs +147 -0
- package/lib/manifest/definitions/_object-records.mjs.map +1 -0
- package/lib/manifest/definitions/action.d.mts +7 -0
- package/lib/manifest/definitions/action.d.mts.map +1 -0
- package/lib/manifest/definitions/action.d.ts +7 -0
- package/lib/manifest/definitions/action.d.ts.map +1 -0
- package/lib/manifest/definitions/action.js +25 -0
- package/lib/manifest/definitions/action.js.map +1 -0
- package/lib/manifest/definitions/action.mjs +22 -0
- package/lib/manifest/definitions/action.mjs.map +1 -0
- package/lib/manifest/definitions/agent.d.mts +51 -0
- package/lib/manifest/definitions/agent.d.mts.map +1 -0
- package/lib/manifest/definitions/agent.d.ts +51 -0
- package/lib/manifest/definitions/agent.d.ts.map +1 -0
- package/lib/manifest/definitions/agent.js +65 -0
- package/lib/manifest/definitions/agent.js.map +1 -0
- package/lib/manifest/definitions/agent.mjs +59 -0
- package/lib/manifest/definitions/agent.mjs.map +1 -0
- package/lib/manifest/definitions/app.d.mts +3 -0
- package/lib/manifest/definitions/app.d.mts.map +1 -0
- package/lib/manifest/definitions/app.d.ts +3 -0
- package/lib/manifest/definitions/app.d.ts.map +1 -0
- package/lib/manifest/definitions/app.js +14 -0
- package/lib/manifest/definitions/app.js.map +1 -0
- package/lib/manifest/definitions/app.mjs +11 -0
- package/lib/manifest/definitions/app.mjs.map +1 -0
- package/lib/manifest/definitions/category.d.mts +9 -0
- package/lib/manifest/definitions/category.d.mts.map +1 -0
- package/lib/manifest/definitions/category.d.ts +9 -0
- package/lib/manifest/definitions/category.d.ts.map +1 -0
- package/lib/manifest/definitions/category.js +27 -0
- package/lib/manifest/definitions/category.js.map +1 -0
- package/lib/manifest/definitions/category.mjs +23 -0
- package/lib/manifest/definitions/category.mjs.map +1 -0
- package/lib/manifest/definitions/component.d.mts +101 -0
- package/lib/manifest/definitions/component.d.mts.map +1 -0
- package/lib/manifest/definitions/component.d.ts +101 -0
- package/lib/manifest/definitions/component.d.ts.map +1 -0
- package/lib/manifest/definitions/component.js +106 -0
- package/lib/manifest/definitions/component.js.map +1 -0
- package/lib/manifest/definitions/component.mjs +97 -0
- package/lib/manifest/definitions/component.mjs.map +1 -0
- package/lib/manifest/definitions/custom-field-section.d.mts +13 -0
- package/lib/manifest/definitions/custom-field-section.d.mts.map +1 -0
- package/lib/manifest/definitions/custom-field-section.d.ts +13 -0
- package/lib/manifest/definitions/custom-field-section.d.ts.map +1 -0
- package/lib/manifest/definitions/custom-field-section.js +15 -0
- package/lib/manifest/definitions/custom-field-section.js.map +1 -0
- package/lib/manifest/definitions/custom-field-section.mjs +12 -0
- package/lib/manifest/definitions/custom-field-section.mjs.map +1 -0
- package/lib/manifest/definitions/custom-field.d.mts +10 -0
- package/lib/manifest/definitions/custom-field.d.mts.map +1 -0
- package/lib/manifest/definitions/custom-field.d.ts +10 -0
- package/lib/manifest/definitions/custom-field.d.ts.map +1 -0
- package/lib/manifest/definitions/custom-field.js +18 -0
- package/lib/manifest/definitions/custom-field.js.map +1 -0
- package/lib/manifest/definitions/custom-field.mjs +15 -0
- package/lib/manifest/definitions/custom-field.mjs.map +1 -0
- package/lib/manifest/definitions/custom-object.d.mts +162 -0
- package/lib/manifest/definitions/custom-object.d.mts.map +1 -0
- package/lib/manifest/definitions/custom-object.d.ts +162 -0
- package/lib/manifest/definitions/custom-object.d.ts.map +1 -0
- package/lib/manifest/definitions/custom-object.js +412 -0
- package/lib/manifest/definitions/custom-object.js.map +1 -0
- package/lib/manifest/definitions/custom-object.mjs +386 -0
- package/lib/manifest/definitions/custom-object.mjs.map +1 -0
- package/lib/manifest/definitions/custom-skill.d.mts +8 -0
- package/lib/manifest/definitions/custom-skill.d.mts.map +1 -0
- package/lib/manifest/definitions/custom-skill.d.ts +8 -0
- package/lib/manifest/definitions/custom-skill.d.ts.map +1 -0
- package/lib/manifest/definitions/custom-skill.js +15 -0
- package/lib/manifest/definitions/custom-skill.js.map +1 -0
- package/lib/manifest/definitions/custom-skill.mjs +12 -0
- package/lib/manifest/definitions/custom-skill.mjs.map +1 -0
- package/lib/manifest/definitions/field-section.d.mts +7 -0
- package/lib/manifest/definitions/field-section.d.mts.map +1 -0
- package/lib/manifest/definitions/field-section.d.ts +7 -0
- package/lib/manifest/definitions/field-section.d.ts.map +1 -0
- package/lib/manifest/definitions/field-section.js +16 -0
- package/lib/manifest/definitions/field-section.js.map +1 -0
- package/lib/manifest/definitions/field-section.mjs +13 -0
- package/lib/manifest/definitions/field-section.mjs.map +1 -0
- package/lib/manifest/definitions/field.d.mts +38 -0
- package/lib/manifest/definitions/field.d.mts.map +1 -0
- package/lib/manifest/definitions/field.d.ts +38 -0
- package/lib/manifest/definitions/field.d.ts.map +1 -0
- package/lib/manifest/definitions/field.js +50 -0
- package/lib/manifest/definitions/field.js.map +1 -0
- package/lib/manifest/definitions/field.mjs +45 -0
- package/lib/manifest/definitions/field.mjs.map +1 -0
- package/lib/manifest/definitions/function.d.mts +61 -0
- package/lib/manifest/definitions/function.d.mts.map +1 -0
- package/lib/manifest/definitions/function.d.ts +61 -0
- package/lib/manifest/definitions/function.d.ts.map +1 -0
- package/lib/manifest/definitions/function.js +79 -0
- package/lib/manifest/definitions/function.js.map +1 -0
- package/lib/manifest/definitions/function.mjs +73 -0
- package/lib/manifest/definitions/function.mjs.map +1 -0
- package/lib/manifest/definitions/index.d.mts +22 -0
- package/lib/manifest/definitions/index.d.mts.map +1 -0
- package/lib/manifest/definitions/index.d.ts +22 -0
- package/lib/manifest/definitions/index.d.ts.map +1 -0
- package/lib/manifest/definitions/index.js +64 -0
- package/lib/manifest/definitions/index.js.map +1 -0
- package/lib/manifest/definitions/index.mjs +22 -0
- package/lib/manifest/definitions/index.mjs.map +1 -0
- package/lib/manifest/definitions/list-view.d.mts +9 -0
- package/lib/manifest/definitions/list-view.d.mts.map +1 -0
- package/lib/manifest/definitions/list-view.d.ts +9 -0
- package/lib/manifest/definitions/list-view.d.ts.map +1 -0
- package/lib/manifest/definitions/list-view.js +25 -0
- package/lib/manifest/definitions/list-view.js.map +1 -0
- package/lib/manifest/definitions/list-view.mjs +22 -0
- package/lib/manifest/definitions/list-view.mjs.map +1 -0
- package/lib/manifest/definitions/object-search-config.d.mts +13 -0
- package/lib/manifest/definitions/object-search-config.d.mts.map +1 -0
- package/lib/manifest/definitions/object-search-config.d.ts +13 -0
- package/lib/manifest/definitions/object-search-config.d.ts.map +1 -0
- package/lib/manifest/definitions/object-search-config.js +25 -0
- package/lib/manifest/definitions/object-search-config.js.map +1 -0
- package/lib/manifest/definitions/object-search-config.mjs +22 -0
- package/lib/manifest/definitions/object-search-config.mjs.map +1 -0
- package/lib/manifest/definitions/object-settings.d.mts +24 -0
- package/lib/manifest/definitions/object-settings.d.mts.map +1 -0
- package/lib/manifest/definitions/object-settings.d.ts +24 -0
- package/lib/manifest/definitions/object-settings.d.ts.map +1 -0
- package/lib/manifest/definitions/object-settings.js +32 -0
- package/lib/manifest/definitions/object-settings.js.map +1 -0
- package/lib/manifest/definitions/object-settings.mjs +29 -0
- package/lib/manifest/definitions/object-settings.mjs.map +1 -0
- package/lib/manifest/definitions/page-layout.d.mts +21 -0
- package/lib/manifest/definitions/page-layout.d.mts.map +1 -0
- package/lib/manifest/definitions/page-layout.d.ts +21 -0
- package/lib/manifest/definitions/page-layout.d.ts.map +1 -0
- package/lib/manifest/definitions/page-layout.js +155 -0
- package/lib/manifest/definitions/page-layout.js.map +1 -0
- package/lib/manifest/definitions/page-layout.mjs +152 -0
- package/lib/manifest/definitions/page-layout.mjs.map +1 -0
- package/lib/manifest/definitions/page.d.mts +8 -0
- package/lib/manifest/definitions/page.d.mts.map +1 -0
- package/lib/manifest/definitions/page.d.ts +8 -0
- package/lib/manifest/definitions/page.d.ts.map +1 -0
- package/lib/manifest/definitions/page.js +15 -0
- package/lib/manifest/definitions/page.js.map +1 -0
- package/lib/manifest/definitions/page.mjs +12 -0
- package/lib/manifest/definitions/page.mjs.map +1 -0
- package/lib/manifest/definitions/record-triggered-flow.d.mts +24 -0
- package/lib/manifest/definitions/record-triggered-flow.d.mts.map +1 -0
- package/lib/manifest/definitions/record-triggered-flow.d.ts +24 -0
- package/lib/manifest/definitions/record-triggered-flow.d.ts.map +1 -0
- package/lib/manifest/definitions/record-triggered-flow.js +28 -0
- package/lib/manifest/definitions/record-triggered-flow.js.map +1 -0
- package/lib/manifest/definitions/record-triggered-flow.mjs +25 -0
- package/lib/manifest/definitions/record-triggered-flow.mjs.map +1 -0
- package/lib/manifest/definitions/validation.d.mts +8 -0
- package/lib/manifest/definitions/validation.d.mts.map +1 -0
- package/lib/manifest/definitions/validation.d.ts +8 -0
- package/lib/manifest/definitions/validation.d.ts.map +1 -0
- package/lib/manifest/definitions/validation.js +24 -0
- package/lib/manifest/definitions/validation.js.map +1 -0
- package/lib/manifest/definitions/validation.mjs +21 -0
- package/lib/manifest/definitions/validation.mjs.map +1 -0
- package/lib/manifest/definitions/workflow.d.mts +10 -0
- package/lib/manifest/definitions/workflow.d.mts.map +1 -0
- package/lib/manifest/definitions/workflow.d.ts +10 -0
- package/lib/manifest/definitions/workflow.d.ts.map +1 -0
- package/lib/manifest/definitions/workflow.js +33 -0
- package/lib/manifest/definitions/workflow.js.map +1 -0
- package/lib/manifest/definitions/workflow.mjs +29 -0
- package/lib/manifest/definitions/workflow.mjs.map +1 -0
- package/lib/manifest/index.d.mts +3 -0
- package/lib/manifest/index.d.mts.map +1 -1
- package/lib/manifest/index.d.ts +3 -0
- package/lib/manifest/index.d.ts.map +1 -1
- package/lib/manifest/index.js +4 -0
- package/lib/manifest/index.js.map +1 -1
- package/lib/manifest/index.mjs +3 -0
- package/lib/manifest/index.mjs.map +1 -1
- package/lib/manifest/package-manifest.d.mts +17 -0
- package/lib/manifest/package-manifest.d.mts.map +1 -0
- package/lib/manifest/package-manifest.d.ts +17 -0
- package/lib/manifest/package-manifest.d.ts.map +1 -0
- package/lib/manifest/package-manifest.js +26 -0
- package/lib/manifest/package-manifest.js.map +1 -0
- package/lib/manifest/package-manifest.mjs +23 -0
- package/lib/manifest/package-manifest.mjs.map +1 -0
- package/package.json +4 -2
- package/resources/index.d.mts +1 -0
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts +1 -0
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +4 -2
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +1 -0
- package/resources/index.mjs.map +1 -1
- package/resources/reimbursements.d.mts +1 -1
- package/resources/reimbursements.d.ts +1 -1
- package/resources/reimbursements.js +1 -1
- package/resources/reimbursements.mjs +1 -1
- package/resources/spend-categories.d.mts +140 -0
- package/resources/spend-categories.d.mts.map +1 -0
- package/resources/spend-categories.d.ts +140 -0
- package/resources/spend-categories.d.ts.map +1 -0
- package/resources/spend-categories.js +83 -0
- package/resources/spend-categories.js.map +1 -0
- package/resources/spend-categories.mjs +79 -0
- package/resources/spend-categories.mjs.map +1 -0
- package/src/client.ts +41 -0
- package/src/index.ts +17 -0
- package/src/lib/charts/README.md +35 -28
- package/src/lib/charts/agent-reference.md +73 -0
- package/src/lib/charts/builders.ts +51 -35
- package/src/lib/charts/capabilities.json +96 -0
- package/src/lib/charts/describe.ts +31 -29
- package/src/lib/charts/errors.ts +2 -6
- package/src/lib/charts/evaluate.ts +25 -38
- package/src/lib/charts/schema.ts +232 -66
- package/src/lib/charts/types.ts +42 -31
- package/src/lib/charts/visualization-grammar.ts +67 -0
- package/src/lib/charts/vocabulary.ts +7 -0
- package/src/lib/charts.ts +8 -1
- package/src/lib/manifest/composition.ts +133 -0
- package/src/lib/manifest/definitions/README.md +89 -0
- package/src/lib/manifest/definitions/_object-records.ts +218 -0
- package/src/lib/manifest/definitions/action.ts +31 -0
- package/src/lib/manifest/definitions/agent.ts +149 -0
- package/src/lib/manifest/definitions/app.ts +12 -0
- package/src/lib/manifest/definitions/category.ts +35 -0
- package/src/lib/manifest/definitions/component.ts +241 -0
- package/src/lib/manifest/definitions/custom-field-section.ts +39 -0
- package/src/lib/manifest/definitions/custom-field.ts +32 -0
- package/src/lib/manifest/definitions/custom-object.ts +786 -0
- package/src/lib/manifest/definitions/custom-skill.ts +28 -0
- package/src/lib/manifest/definitions/field-section.ts +31 -0
- package/src/lib/manifest/definitions/field.ts +119 -0
- package/src/lib/manifest/definitions/function.ts +198 -0
- package/src/lib/manifest/definitions/index.ts +91 -0
- package/src/lib/manifest/definitions/list-view.ts +48 -0
- package/src/lib/manifest/definitions/object-search-config.ts +44 -0
- package/src/lib/manifest/definitions/object-settings.ts +61 -0
- package/src/lib/manifest/definitions/page-layout.ts +218 -0
- package/src/lib/manifest/definitions/page.ts +28 -0
- package/src/lib/manifest/definitions/record-triggered-flow.ts +71 -0
- package/src/lib/manifest/definitions/validation.ts +46 -0
- package/src/lib/manifest/definitions/workflow.ts +62 -0
- package/src/lib/manifest/index.ts +4 -0
- package/src/lib/manifest/package-manifest.ts +40 -0
- package/src/resources/index.ts +7 -0
- package/src/resources/reimbursements.ts +1 -1
- package/src/resources/spend-categories.ts +175 -0
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
- package/lib/charts/guards.d.mts +0 -15
- package/lib/charts/guards.d.mts.map +0 -1
- package/lib/charts/guards.d.ts +0 -15
- package/lib/charts/guards.d.ts.map +0 -1
- package/lib/charts/guards.js +0 -38
- package/lib/charts/guards.js.map +0 -1
- package/lib/charts/guards.mjs +0 -34
- package/lib/charts/guards.mjs.map +0 -1
- package/src/lib/charts/guards.ts +0 -42
package/src/lib/charts/schema.ts
CHANGED
|
@@ -1,72 +1,238 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type BaseIssue,
|
|
3
|
+
boolean,
|
|
4
|
+
type GenericSchema,
|
|
5
|
+
finite,
|
|
6
|
+
literal,
|
|
7
|
+
null_,
|
|
8
|
+
number,
|
|
9
|
+
picklist,
|
|
10
|
+
pipe,
|
|
11
|
+
safeParse,
|
|
12
|
+
strictObject,
|
|
13
|
+
string,
|
|
14
|
+
summarize,
|
|
15
|
+
union,
|
|
16
|
+
variant,
|
|
17
|
+
} from 'valibot';
|
|
2
18
|
|
|
3
|
-
|
|
19
|
+
import { MalformedRuleError, UnknownNodeError } from './errors';
|
|
20
|
+
import { CHART_RULE_CONTRACT_VERSION, type ParsedRule, type Rule, type RuleNode, type Scalar } from './types';
|
|
21
|
+
import {
|
|
22
|
+
EQUALITY_COMPARISON_KINDS,
|
|
23
|
+
NUMERIC_COMPARISON_KINDS,
|
|
24
|
+
RULE_CHANNELS,
|
|
25
|
+
RULE_NODE_KINDS,
|
|
26
|
+
} from './vocabulary';
|
|
27
|
+
|
|
28
|
+
const ruleNodeKinds: ReadonlySet<string> = new Set(RULE_NODE_KINDS);
|
|
29
|
+
const placeholderKeys: ReadonlySet<string> = new Set(['$rule', 'channel']);
|
|
30
|
+
const ruleFieldKeys = ['$rule', 'channel', 'kind', 'value', 'left', 'right', 'cond', 'then', 'else'] as const;
|
|
31
|
+
const scalarSchema: GenericSchema<unknown, Scalar> = union([
|
|
32
|
+
pipe(number(), finite()),
|
|
33
|
+
string(),
|
|
34
|
+
boolean(),
|
|
35
|
+
null_(),
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
const parsedRules = new WeakSet<object>();
|
|
39
|
+
|
|
40
|
+
/** @deprecated Use `CHART_RULE_CONTRACT_VERSION` to identify the executable contract. */
|
|
4
41
|
export const CHART_RULE_SCHEMA_ID = `https://rippling.com/schemas/${CHART_RULE_CONTRACT_VERSION}.json`;
|
|
5
42
|
|
|
43
|
+
function hasOwn(value: object, key: PropertyKey): boolean {
|
|
44
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const refNodeSchema = strictObject({ kind: literal('value') });
|
|
48
|
+
const literalNodeSchema = strictObject({ kind: literal('literal'), value: scalarSchema });
|
|
49
|
+
const numericLiteralNodeSchema = strictObject({
|
|
50
|
+
kind: literal('literal'),
|
|
51
|
+
value: pipe(number(), finite()),
|
|
52
|
+
});
|
|
53
|
+
const requiredColorLiteralNodeSchema = strictObject({
|
|
54
|
+
kind: literal('literal'),
|
|
55
|
+
value: string(),
|
|
56
|
+
});
|
|
57
|
+
const optionalColorLiteralNodeSchema = strictObject({
|
|
58
|
+
kind: literal('literal'),
|
|
59
|
+
value: union([string(), null_()]),
|
|
60
|
+
});
|
|
61
|
+
const comparisonOperandSchema = variant('kind', [refNodeSchema, literalNodeSchema]);
|
|
62
|
+
const numericOperandSchema = variant('kind', [refNodeSchema, numericLiteralNodeSchema]);
|
|
63
|
+
|
|
64
|
+
const equalityComparisonNodeSchema = strictObject({
|
|
65
|
+
kind: picklist(EQUALITY_COMPARISON_KINDS),
|
|
66
|
+
left: comparisonOperandSchema,
|
|
67
|
+
right: comparisonOperandSchema,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const numericComparisonNodeSchema = strictObject({
|
|
71
|
+
kind: picklist(NUMERIC_COMPARISON_KINDS),
|
|
72
|
+
left: numericOperandSchema,
|
|
73
|
+
right: numericOperandSchema,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const comparisonNodeSchema = variant('kind', [equalityComparisonNodeSchema, numericComparisonNodeSchema]);
|
|
77
|
+
|
|
78
|
+
const ifElseNodeSchema = strictObject({
|
|
79
|
+
kind: literal('ifElse'),
|
|
80
|
+
cond: comparisonNodeSchema,
|
|
81
|
+
then: requiredColorLiteralNodeSchema,
|
|
82
|
+
else: optionalColorLiteralNodeSchema,
|
|
83
|
+
});
|
|
84
|
+
|
|
6
85
|
/**
|
|
7
|
-
*
|
|
86
|
+
* Executable runtime schema for a chart-rule node.
|
|
8
87
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
88
|
+
* v1 is intentionally non-recursive. A comparison contains only `value` or
|
|
89
|
+
* literal operands, and a conditional contains one comparison plus two colour
|
|
90
|
+
* literals. Contract tests prove that every public builder output parses.
|
|
91
|
+
*/
|
|
92
|
+
const ruleNodeSchema: GenericSchema<unknown, RuleNode, BaseIssue<unknown>> = variant('kind', [
|
|
93
|
+
refNodeSchema,
|
|
94
|
+
literalNodeSchema,
|
|
95
|
+
equalityComparisonNodeSchema,
|
|
96
|
+
numericComparisonNodeSchema,
|
|
97
|
+
ifElseNodeSchema,
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
/** Runtime schema for the `{$rule, channel}` value embedded in a chart option. */
|
|
101
|
+
const rulePlaceholderSchema = strictObject({
|
|
102
|
+
$rule: ifElseNodeSchema,
|
|
103
|
+
channel: picklist(RULE_CHANNELS),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Runtime schema for either a bare rule node or a chart-option placeholder.
|
|
108
|
+
* Persisted and agent-authored JSON crosses this boundary as `unknown`.
|
|
109
|
+
*/
|
|
110
|
+
export const chartRuleSchema: GenericSchema<unknown, Rule, BaseIssue<unknown>> = union([
|
|
111
|
+
rulePlaceholderSchema,
|
|
112
|
+
ruleNodeSchema,
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
/** Parse untrusted chart-rule JSON and return an immutable validated clone. */
|
|
116
|
+
export function parseChartRule(input: unknown): ParsedRule {
|
|
117
|
+
if (isParsedRule(input)) {
|
|
118
|
+
return input;
|
|
119
|
+
}
|
|
120
|
+
preflight(input);
|
|
121
|
+
const result = safeParse(chartRuleSchema, input);
|
|
122
|
+
if (result.success) {
|
|
123
|
+
return markParsedRule(result.output);
|
|
124
|
+
}
|
|
125
|
+
throw new MalformedRuleError(summarize(result.issues));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Valibot's object schemas use `key in input`, which also reads inherited
|
|
130
|
+
* properties. Reject inherited rule fields before parsing so prototype data
|
|
131
|
+
* cannot supply required operands or bypass the flat v1 contract.
|
|
12
132
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
133
|
+
function preflight(input: unknown): void {
|
|
134
|
+
assertNoInheritedRuleFields(input);
|
|
135
|
+
const root = unwrapPlaceholder(input);
|
|
136
|
+
assertNoInheritedRuleFields(root);
|
|
137
|
+
assertKnownNode(root);
|
|
138
|
+
|
|
139
|
+
if (!isRecord(root) || !hasOwn(root, 'kind')) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (root['kind'] === 'ifElse') {
|
|
143
|
+
inspectChildren(root, ['cond', 'then', 'else']);
|
|
144
|
+
const condition = root['cond'];
|
|
145
|
+
inspectComparison(condition);
|
|
146
|
+
} else if (typeof root['kind'] === 'string' && isComparisonKind(root['kind'])) {
|
|
147
|
+
inspectComparison(root);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function inspectComparison(value: unknown): void {
|
|
152
|
+
assertNoInheritedRuleFields(value);
|
|
153
|
+
assertKnownNode(value);
|
|
154
|
+
if (isRecord(value)) {
|
|
155
|
+
inspectChildren(value, ['left', 'right']);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function inspectChildren(parent: Record<string, unknown>, keys: readonly string[]): void {
|
|
160
|
+
for (const key of keys) {
|
|
161
|
+
if (hasOwn(parent, key)) {
|
|
162
|
+
const child = parent[key];
|
|
163
|
+
assertNoInheritedRuleFields(child);
|
|
164
|
+
assertKnownNode(child);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function assertNoInheritedRuleFields(value: unknown): void {
|
|
170
|
+
if (!isRecord(value)) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
for (const key of ruleFieldKeys) {
|
|
174
|
+
if (key in value && !hasOwn(value, key)) {
|
|
175
|
+
throw new MalformedRuleError(`a chart rule must not inherit the ${key} property`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function assertKnownNode(value: unknown): void {
|
|
181
|
+
if (
|
|
182
|
+
isRecord(value) &&
|
|
183
|
+
hasOwn(value, 'kind') &&
|
|
184
|
+
typeof value['kind'] === 'string' &&
|
|
185
|
+
!ruleNodeKinds.has(value['kind'])
|
|
186
|
+
) {
|
|
187
|
+
throw new UnknownNodeError(value['kind']);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function isComparisonKind(kind: string): boolean {
|
|
192
|
+
return kind !== 'literal' && kind !== 'value' && kind !== 'ifElse' && ruleNodeKinds.has(kind);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
196
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function unwrapPlaceholder(input: unknown): unknown {
|
|
200
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input) || !hasOwn(input, '$rule')) {
|
|
201
|
+
return input;
|
|
202
|
+
}
|
|
203
|
+
const unexpectedKey = Object.keys(input).find((key) => !placeholderKeys.has(key));
|
|
204
|
+
if (unexpectedKey !== undefined) {
|
|
205
|
+
throw new MalformedRuleError(`a rule placeholder has an unexpected property: ${unexpectedKey}`);
|
|
206
|
+
}
|
|
207
|
+
return (input as { $rule?: unknown }).$rule;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function isParsedRule(input: unknown): input is ParsedRule {
|
|
211
|
+
return input !== null && typeof input === 'object' && !Array.isArray(input) && parsedRules.has(input);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Mark the validated clone so `evaluate(parseChartRule(input), ctx)` does not
|
|
216
|
+
* reparse the full value for every datum. Freezing prevents a caller from
|
|
217
|
+
* mutating a trusted value after validation.
|
|
218
|
+
*/
|
|
219
|
+
function markParsedRule(rule: Rule): ParsedRule {
|
|
220
|
+
const stack: object[] = [rule];
|
|
221
|
+
const seen = new WeakSet<object>();
|
|
222
|
+
while (stack.length > 0) {
|
|
223
|
+
const current = stack.pop();
|
|
224
|
+
if (!current || seen.has(current)) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
seen.add(current);
|
|
228
|
+
for (const value of Object.values(current)) {
|
|
229
|
+
if (value !== null && typeof value === 'object') {
|
|
230
|
+
stack.push(value);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
Object.freeze(current);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
parsedRules.add(rule);
|
|
237
|
+
return rule as ParsedRule;
|
|
238
|
+
}
|
package/src/lib/charts/types.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Chart rule vocabulary — shared types.
|
|
3
3
|
*
|
|
4
|
-
* A rule is a small, serializable
|
|
4
|
+
* A rule is a small, serializable value discriminated by `kind`. The
|
|
5
5
|
* agent builds it with the helpers in `builders.ts`, which emit it wrapped in a
|
|
6
6
|
* `{$rule}` placeholder — the same idea as the `{$fn}` placeholders a chart
|
|
7
7
|
* already emits. The renderer resolves it with `evaluate`; the settings panel
|
|
8
8
|
* reads it with `describe`. All three agree because a node can only ever be one
|
|
9
|
-
* of the kinds defined here — the closed set the `chartRuleSchema`
|
|
9
|
+
* of the kinds defined here — the closed set the executable `chartRuleSchema`
|
|
10
|
+
* validates at runtime.
|
|
10
11
|
*
|
|
11
|
-
* v1 is
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* v1 is deliberately non-recursive: compare this datum's `value` or a literal
|
|
13
|
+
* against another literal, then choose between two colour literals. Rules may
|
|
14
|
+
* not appear inside operands or branches. Richer expressions require a future
|
|
15
|
+
* contract version.
|
|
14
16
|
*/
|
|
15
17
|
|
|
18
|
+
import { COMPARISON_KINDS, RULE_CHANNELS } from './vocabulary';
|
|
19
|
+
|
|
16
20
|
export const CHART_RULE_CONTRACT_VERSION = 'chart_rule.v1' as const;
|
|
17
21
|
export type ChartRuleContractVersion = typeof CHART_RULE_CONTRACT_VERSION;
|
|
18
22
|
|
|
@@ -26,33 +30,39 @@ export type Scalar = number | string | boolean | null;
|
|
|
26
30
|
/** Reads a value out of the evaluation context — this datum's plotted value. */
|
|
27
31
|
export type RefNode = { kind: 'value' };
|
|
28
32
|
|
|
29
|
-
export interface LiteralNode {
|
|
33
|
+
export interface LiteralNode<TValue extends Scalar = Scalar> {
|
|
30
34
|
kind: 'literal';
|
|
31
|
-
value:
|
|
35
|
+
value: TValue;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
export type
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
| '
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
kind: ComparisonKind;
|
|
43
|
-
left: RuleNode;
|
|
44
|
-
right: RuleNode;
|
|
38
|
+
export type ComparisonOperandNode = RefNode | LiteralNode;
|
|
39
|
+
export type NumericOperandNode = RefNode | LiteralNode<number>;
|
|
40
|
+
|
|
41
|
+
export type ComparisonKind = (typeof COMPARISON_KINDS)[number];
|
|
42
|
+
export interface EqualityComparisonNode {
|
|
43
|
+
kind: 'equals' | 'isNot';
|
|
44
|
+
left: ComparisonOperandNode;
|
|
45
|
+
right: ComparisonOperandNode;
|
|
45
46
|
}
|
|
47
|
+
export interface NumericComparisonNode {
|
|
48
|
+
kind: Exclude<ComparisonKind, EqualityComparisonNode['kind']>;
|
|
49
|
+
left: NumericOperandNode;
|
|
50
|
+
right: NumericOperandNode;
|
|
51
|
+
}
|
|
52
|
+
export type ComparisonNode = EqualityComparisonNode | NumericComparisonNode;
|
|
53
|
+
|
|
54
|
+
/** A node whose evaluated result is valid as a `when(...)` condition in v1. */
|
|
55
|
+
export type ConditionNode = ComparisonNode;
|
|
46
56
|
|
|
47
57
|
/** The conditional-value form produced by `when(cond, then, else)`. */
|
|
48
58
|
export interface IfElseNode {
|
|
49
59
|
kind: 'ifElse';
|
|
50
|
-
cond:
|
|
51
|
-
then:
|
|
52
|
-
else:
|
|
60
|
+
cond: ConditionNode;
|
|
61
|
+
then: LiteralNode<string>;
|
|
62
|
+
else: LiteralNode<string | null>;
|
|
53
63
|
}
|
|
54
64
|
|
|
55
|
-
/** Any node
|
|
65
|
+
/** Any top-level node accepted by the v1 runtime boundary. */
|
|
56
66
|
export type RuleNode = RefNode | LiteralNode | ComparisonNode | IfElseNode;
|
|
57
67
|
|
|
58
68
|
/* -------------------------------------------------------------------------- */
|
|
@@ -64,21 +74,26 @@ export type RuleNode = RefNode | LiteralNode | ComparisonNode | IfElseNode;
|
|
|
64
74
|
* colour of a series/datum. Other channels (opacity, label visibility, …) are
|
|
65
75
|
* the documented roadmap and would be added here.
|
|
66
76
|
*/
|
|
67
|
-
export type RuleChannel =
|
|
77
|
+
export type RuleChannel = (typeof RULE_CHANNELS)[number];
|
|
68
78
|
|
|
69
79
|
/**
|
|
70
|
-
* What a builder returns: a rule
|
|
80
|
+
* What a builder returns: a flat rule value, marked so the renderer can find it, and
|
|
71
81
|
* tagged with the channel it targets. `channel: 'color'` says this resolves to a
|
|
72
82
|
* colour — so a reader sees the target without inferring it from where it sits.
|
|
73
83
|
*/
|
|
74
84
|
export interface RulePlaceholder {
|
|
75
|
-
$rule:
|
|
85
|
+
$rule: IfElseNode;
|
|
76
86
|
channel: RuleChannel;
|
|
77
87
|
}
|
|
78
88
|
|
|
79
|
-
/** A placeholder, or
|
|
89
|
+
/** A placeholder, or a bare node — what `evaluate` and `describe` accept. */
|
|
80
90
|
export type Rule = RulePlaceholder | RuleNode;
|
|
81
91
|
|
|
92
|
+
type DeepReadonly<T> = T extends object ? { readonly [Key in keyof T]: DeepReadonly<T[Key]> } : T;
|
|
93
|
+
|
|
94
|
+
/** The deeply frozen value returned by `parseChartRule`. */
|
|
95
|
+
export type ParsedRule = DeepReadonly<Rule>;
|
|
96
|
+
|
|
82
97
|
/* -------------------------------------------------------------------------- */
|
|
83
98
|
/* Evaluation */
|
|
84
99
|
/* -------------------------------------------------------------------------- */
|
|
@@ -91,11 +106,7 @@ export interface RuleContext {
|
|
|
91
106
|
/** The result of evaluating a node. */
|
|
92
107
|
export type RuleValue = Scalar;
|
|
93
108
|
|
|
94
|
-
/**
|
|
95
|
-
* The deepest a rule may nest before `evaluate`/`describe` refuse it. Real rules
|
|
96
|
-
* are a handful of levels; this only stops a pathological deserialized tree from
|
|
97
|
-
* overflowing the stack. Far below the JS call-stack limit.
|
|
98
|
-
*/
|
|
109
|
+
/** @deprecated v1 is non-recursive. Retained for source compatibility. */
|
|
99
110
|
export const MAX_RULE_DEPTH = 256;
|
|
100
111
|
|
|
101
112
|
/* -------------------------------------------------------------------------- */
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { RULE_CHANNELS, RULE_NODE_KINDS } from './vocabulary';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Machine-readable authoring surface for chart visualization primitives.
|
|
5
|
+
*
|
|
6
|
+
* The SDK build serializes this registry to `capabilities.json`. Keep the
|
|
7
|
+
* registry aligned with the public builders and the serialized-node schema;
|
|
8
|
+
* contract tests enforce both relationships.
|
|
9
|
+
*/
|
|
10
|
+
export const visualizationGrammarCapabilities = {
|
|
11
|
+
contractVersion: 1,
|
|
12
|
+
moduleSpecifier: 'npm:@rippling/rippling-sdk/lib/charts',
|
|
13
|
+
builders: {
|
|
14
|
+
value: {
|
|
15
|
+
kind: 'input',
|
|
16
|
+
returns: 'number',
|
|
17
|
+
},
|
|
18
|
+
literal: {
|
|
19
|
+
kind: 'literal',
|
|
20
|
+
parameters: ['scalar'],
|
|
21
|
+
returns: 'value',
|
|
22
|
+
},
|
|
23
|
+
equals: {
|
|
24
|
+
kind: 'comparison',
|
|
25
|
+
parameters: ['value', 'value'],
|
|
26
|
+
returns: 'condition',
|
|
27
|
+
},
|
|
28
|
+
isNot: {
|
|
29
|
+
kind: 'comparison',
|
|
30
|
+
parameters: ['value', 'value'],
|
|
31
|
+
returns: 'condition',
|
|
32
|
+
},
|
|
33
|
+
lessThan: {
|
|
34
|
+
kind: 'comparison',
|
|
35
|
+
parameters: ['value', 'value'],
|
|
36
|
+
returns: 'condition',
|
|
37
|
+
},
|
|
38
|
+
greaterThan: {
|
|
39
|
+
kind: 'comparison',
|
|
40
|
+
parameters: ['value', 'value'],
|
|
41
|
+
returns: 'condition',
|
|
42
|
+
},
|
|
43
|
+
lessOrEqual: {
|
|
44
|
+
kind: 'comparison',
|
|
45
|
+
parameters: ['value', 'value'],
|
|
46
|
+
returns: 'condition',
|
|
47
|
+
},
|
|
48
|
+
greaterOrEqual: {
|
|
49
|
+
kind: 'comparison',
|
|
50
|
+
parameters: ['value', 'value'],
|
|
51
|
+
returns: 'condition',
|
|
52
|
+
},
|
|
53
|
+
when: {
|
|
54
|
+
kind: 'conditional',
|
|
55
|
+
parameters: ['condition', 'color', 'color?'],
|
|
56
|
+
returns: 'conditional-color',
|
|
57
|
+
},
|
|
58
|
+
color: {
|
|
59
|
+
kind: 'channel',
|
|
60
|
+
parameters: ['conditional-color'],
|
|
61
|
+
returns: 'color-rule',
|
|
62
|
+
placeholderChannel: 'color',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
supportedChannels: RULE_CHANNELS,
|
|
66
|
+
supportedNodeKinds: RULE_NODE_KINDS,
|
|
67
|
+
} as const;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Runtime constants shared by the schema, capability manifest, and types. */
|
|
2
|
+
export const EQUALITY_COMPARISON_KINDS = ['equals', 'isNot'] as const;
|
|
3
|
+
export const NUMERIC_COMPARISON_KINDS = ['lessThan', 'greaterThan', 'lessOrEqual', 'greaterOrEqual'] as const;
|
|
4
|
+
export const COMPARISON_KINDS = [...EQUALITY_COMPARISON_KINDS, ...NUMERIC_COMPARISON_KINDS] as const;
|
|
5
|
+
|
|
6
|
+
export const RULE_NODE_KINDS = ['literal', 'value', ...COMPARISON_KINDS, 'ifElse'] as const;
|
|
7
|
+
export const RULE_CHANNELS = ['color'] as const;
|
package/src/lib/charts.ts
CHANGED
|
@@ -10,11 +10,12 @@ export {
|
|
|
10
10
|
literal,
|
|
11
11
|
value,
|
|
12
12
|
when,
|
|
13
|
+
type NumericOperand,
|
|
13
14
|
type Operand,
|
|
14
15
|
} from './charts/builders';
|
|
15
16
|
export { evaluate } from './charts/evaluate';
|
|
16
17
|
export { describe } from './charts/describe';
|
|
17
|
-
export { chartRuleSchema, CHART_RULE_SCHEMA_ID } from './charts/schema';
|
|
18
|
+
export { chartRuleSchema, CHART_RULE_SCHEMA_ID, parseChartRule } from './charts/schema';
|
|
18
19
|
export {
|
|
19
20
|
ChartRuleError,
|
|
20
21
|
MalformedRuleError,
|
|
@@ -28,10 +29,16 @@ export {
|
|
|
28
29
|
type ChartRuleContractVersion,
|
|
29
30
|
type ComparisonKind,
|
|
30
31
|
type ComparisonNode,
|
|
32
|
+
type ComparisonOperandNode,
|
|
33
|
+
type ConditionNode,
|
|
31
34
|
type Control,
|
|
32
35
|
type ControlRole,
|
|
36
|
+
type EqualityComparisonNode,
|
|
33
37
|
type IfElseNode,
|
|
34
38
|
type LiteralNode,
|
|
39
|
+
type NumericComparisonNode,
|
|
40
|
+
type NumericOperandNode,
|
|
41
|
+
type ParsedRule,
|
|
35
42
|
type RefNode,
|
|
36
43
|
type Rule,
|
|
37
44
|
type RuleChannel,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { BuiltManifest } from './manifest-builder';
|
|
2
|
+
import {
|
|
3
|
+
registeredComponent,
|
|
4
|
+
entryKey,
|
|
5
|
+
type CompileContext,
|
|
6
|
+
type MetadataEntry,
|
|
7
|
+
} from './definitions/component';
|
|
8
|
+
|
|
9
|
+
// Existing CLI loaders use this stable marker to request deferred source compilation.
|
|
10
|
+
const manifestBuilds = Symbol.for('@rippling/sdk/package-sources');
|
|
11
|
+
type DeferredBuild = { readonly index: number; readonly entry: MetadataEntry };
|
|
12
|
+
|
|
13
|
+
/** Compose new definitions; legacy ManifestBuilder remains an independent authoring flow. */
|
|
14
|
+
export type ManifestInput = object;
|
|
15
|
+
|
|
16
|
+
export interface DefineManifestOptions {
|
|
17
|
+
components: readonly ManifestInput[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ManifestDefinition extends BuiltManifest {
|
|
21
|
+
readonly [manifestBuilds]?: readonly DeferredBuild[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Run the build hooks supplied by component implementations, preserving the metadata JSON contract. */
|
|
25
|
+
export async function compileManifest(
|
|
26
|
+
definition: Readonly<ManifestDefinition>,
|
|
27
|
+
bundle: (entrypoint: URL) => Promise<string>,
|
|
28
|
+
): Promise<Readonly<ManifestDefinition>> {
|
|
29
|
+
const builds = definition[manifestBuilds] ?? [];
|
|
30
|
+
if (builds.length === 0) return definition;
|
|
31
|
+
const compiled: ManifestDefinition = JSON.parse(JSON.stringify({ ...definition }));
|
|
32
|
+
for (const { index, entry } of builds) {
|
|
33
|
+
const config = await entry.build!({ bundle });
|
|
34
|
+
compiled.components[index] = JSON.parse(JSON.stringify(config));
|
|
35
|
+
}
|
|
36
|
+
return freezeManifest(compiled);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function canonicalJson(value: unknown): string {
|
|
40
|
+
return JSON.stringify(value, (_key, item: unknown) =>
|
|
41
|
+
item != null && typeof item === 'object' && !Array.isArray(item) ?
|
|
42
|
+
Object.fromEntries(Object.entries(item).sort(([left], [right]) => left.localeCompare(right)))
|
|
43
|
+
: item,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Collect references, then compile batches. Component-specific behavior lives in definitions/. */
|
|
48
|
+
export function defineManifest(options: DefineManifestOptions): Readonly<ManifestDefinition> {
|
|
49
|
+
const definitions: object[] = [];
|
|
50
|
+
const visited = new Set<object>();
|
|
51
|
+
const batches = new Map<
|
|
52
|
+
object,
|
|
53
|
+
{
|
|
54
|
+
implementation: NonNullable<ReturnType<typeof registeredComponent>>['implementation'];
|
|
55
|
+
definitions: object[];
|
|
56
|
+
}
|
|
57
|
+
>();
|
|
58
|
+
const entries: MetadataEntry[] = [];
|
|
59
|
+
const visit = (definition: object): void => {
|
|
60
|
+
if (visited.has(definition)) return;
|
|
61
|
+
visited.add(definition);
|
|
62
|
+
const registered = registeredComponent(definition);
|
|
63
|
+
if (registered != null) {
|
|
64
|
+
definitions.push(definition);
|
|
65
|
+
for (const dependency of registered.references()) visit(dependency);
|
|
66
|
+
const implementation = registered.implementation;
|
|
67
|
+
const batch = batches.get(implementation.batchKey) ?? { implementation, definitions: [] };
|
|
68
|
+
batch.definitions.push(definition);
|
|
69
|
+
batches.set(implementation.batchKey, batch);
|
|
70
|
+
} else {
|
|
71
|
+
throw new Error(
|
|
72
|
+
'Use defineX helpers in defineManifest; existing constructors belong in ManifestBuilder.',
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
options.components.forEach(visit);
|
|
77
|
+
const context: CompileContext = { definitions };
|
|
78
|
+
for (const batch of batches.values()) {
|
|
79
|
+
for (const output of batch.implementation.compileBatch(batch.definitions, context))
|
|
80
|
+
entries.push('type' in output ? { config: output } : output);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const snapshots: Record<string, any>[] = JSON.parse(JSON.stringify(entries.map((entry) => entry.config)));
|
|
84
|
+
const unique = new Map<string, { config: Record<string, any>; entry: MetadataEntry }>();
|
|
85
|
+
for (const [index, config] of snapshots.entries()) {
|
|
86
|
+
const entry = entries[index]!;
|
|
87
|
+
const key = entryKey(entry);
|
|
88
|
+
const existing = unique.get(key);
|
|
89
|
+
if (existing != null) {
|
|
90
|
+
for (const parent of ['model_name', 'model_rql_name', 'object_rql_name']) {
|
|
91
|
+
if (existing.config[parent] !== config[parent])
|
|
92
|
+
throw new Error(`Conflicting manifest component ${key}: apiName must be unique across objects.`);
|
|
93
|
+
}
|
|
94
|
+
if (entry.fallback && !existing.entry.fallback) continue;
|
|
95
|
+
if (!entry.fallback && existing.entry.fallback) {
|
|
96
|
+
unique.set(key, { config, entry });
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (canonicalJson(existing.config) !== canonicalJson(config))
|
|
100
|
+
throw new Error(`Conflicting manifest component ${key}`);
|
|
101
|
+
if (existing.entry.build != null && entry.build != null && existing.entry.buildKey !== entry.buildKey)
|
|
102
|
+
throw new Error(`Conflicting manifest source ${key}`);
|
|
103
|
+
if (entry.build == null && existing.entry.build != null) continue;
|
|
104
|
+
}
|
|
105
|
+
unique.set(key, { config, entry });
|
|
106
|
+
}
|
|
107
|
+
const builds = [...unique.values()].flatMap(({ entry }, index) =>
|
|
108
|
+
entry.build == null ? [] : [{ index, entry }],
|
|
109
|
+
);
|
|
110
|
+
const manifest: ManifestDefinition = {
|
|
111
|
+
metadata: {},
|
|
112
|
+
components: [...unique.values()].map(({ config }) => config),
|
|
113
|
+
};
|
|
114
|
+
if (builds.length > 0) {
|
|
115
|
+
Object.defineProperty(manifest, manifestBuilds, { value: Object.freeze(builds) });
|
|
116
|
+
Object.defineProperty(manifest, 'toJSON', {
|
|
117
|
+
value(): never {
|
|
118
|
+
throw new Error(
|
|
119
|
+
'Manifest source entrypoints must be compiled before JSON export. Use rippling project export or compileManifest.',
|
|
120
|
+
);
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return freezeManifest(manifest);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function freezeManifest<T>(value: T): T {
|
|
128
|
+
if (value != null && typeof value === 'object') {
|
|
129
|
+
Object.values(value).forEach(freezeManifest);
|
|
130
|
+
Object.freeze(value);
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
}
|