@rippling/rippling-sdk 0.2.0-alpha.105 → 0.2.0-alpha.107
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 +6 -0
- package/client.d.mts.map +1 -1
- package/client.d.ts +6 -0
- package/client.d.ts.map +1 -1
- package/client.js +6 -0
- package/client.js.map +1 -1
- package/client.mjs +6 -0
- package/client.mjs.map +1 -1
- package/lib/charts/builders.d.mts +43 -0
- package/lib/charts/builders.d.mts.map +1 -0
- package/lib/charts/builders.d.ts +43 -0
- package/lib/charts/builders.d.ts.map +1 -0
- package/lib/charts/builders.js +77 -0
- package/lib/charts/builders.js.map +1 -0
- package/lib/charts/builders.mjs +70 -0
- package/lib/charts/builders.mjs.map +1 -0
- package/lib/charts/describe.d.mts +12 -0
- package/lib/charts/describe.d.mts.map +1 -0
- package/lib/charts/describe.d.ts +12 -0
- package/lib/charts/describe.d.ts.map +1 -0
- package/lib/charts/describe.js +64 -0
- package/lib/charts/describe.js.map +1 -0
- package/lib/charts/describe.mjs +61 -0
- package/lib/charts/describe.mjs.map +1 -0
- package/lib/charts/errors.d.mts +35 -0
- package/lib/charts/errors.d.mts.map +1 -0
- package/lib/charts/errors.d.ts +35 -0
- package/lib/charts/errors.d.ts.map +1 -0
- package/lib/charts/errors.js +55 -0
- package/lib/charts/errors.js.map +1 -0
- package/lib/charts/errors.mjs +47 -0
- package/lib/charts/errors.mjs.map +1 -0
- package/lib/charts/evaluate.d.mts +16 -0
- package/lib/charts/evaluate.d.mts.map +1 -0
- package/lib/charts/evaluate.d.ts +16 -0
- package/lib/charts/evaluate.d.ts.map +1 -0
- package/lib/charts/evaluate.js +99 -0
- package/lib/charts/evaluate.js.map +1 -0
- package/lib/charts/evaluate.mjs +96 -0
- package/lib/charts/evaluate.mjs.map +1 -0
- package/lib/charts/guards.d.mts +15 -0
- package/lib/charts/guards.d.mts.map +1 -0
- package/lib/charts/guards.d.ts +15 -0
- package/lib/charts/guards.d.ts.map +1 -0
- package/lib/charts/guards.js +38 -0
- package/lib/charts/guards.js.map +1 -0
- package/lib/charts/guards.mjs +34 -0
- package/lib/charts/guards.mjs.map +1 -0
- package/lib/charts/schema.d.mts +101 -0
- package/lib/charts/schema.d.mts.map +1 -0
- package/lib/charts/schema.d.ts +101 -0
- package/lib/charts/schema.d.ts.map +1 -0
- package/lib/charts/schema.js +74 -0
- package/lib/charts/schema.js.map +1 -0
- package/lib/charts/schema.mjs +71 -0
- package/lib/charts/schema.mjs.map +1 -0
- package/lib/charts/types.d.mts +79 -0
- package/lib/charts/types.d.mts.map +1 -0
- package/lib/charts/types.d.ts +79 -0
- package/lib/charts/types.d.ts.map +1 -0
- package/lib/charts/types.js +25 -0
- package/lib/charts/types.js.map +1 -0
- package/lib/charts/types.mjs +22 -0
- package/lib/charts/types.mjs.map +1 -0
- package/lib/charts.d.mts +7 -0
- package/lib/charts.d.mts.map +1 -0
- package/lib/charts.d.ts +7 -0
- package/lib/charts.d.ts.map +1 -0
- package/lib/charts.js +32 -0
- package/lib/charts.js.map +1 -0
- package/lib/charts.mjs +7 -0
- package/lib/charts.mjs.map +1 -0
- package/package.json +1 -1
- package/resources/custom-settings.d.mts +1 -1
- package/resources/custom-settings.d.ts +1 -1
- package/resources/custom-settings.js +1 -1
- package/resources/custom-settings.mjs +1 -1
- package/resources/hire-requirements.d.mts +8 -74
- package/resources/hire-requirements.d.mts.map +1 -1
- package/resources/hire-requirements.d.ts +8 -74
- package/resources/hire-requirements.d.ts.map +1 -1
- package/resources/hire-requirements.js +3 -19
- package/resources/hire-requirements.js.map +1 -1
- package/resources/hire-requirements.mjs +3 -19
- package/resources/hire-requirements.mjs.map +1 -1
- package/resources/hires.d.mts +677 -147
- package/resources/hires.d.mts.map +1 -1
- package/resources/hires.d.ts +677 -147
- package/resources/hires.d.ts.map +1 -1
- package/resources/hires.js +3 -5
- package/resources/hires.js.map +1 -1
- package/resources/hires.mjs +3 -5
- package/resources/hires.mjs.map +1 -1
- 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/payroll-payment-mode-changes.d.mts +150 -0
- package/resources/payroll-payment-mode-changes.d.mts.map +1 -0
- package/resources/payroll-payment-mode-changes.d.ts +150 -0
- package/resources/payroll-payment-mode-changes.d.ts.map +1 -0
- package/resources/payroll-payment-mode-changes.js +66 -0
- package/resources/payroll-payment-mode-changes.js.map +1 -0
- package/resources/payroll-payment-mode-changes.mjs +62 -0
- package/resources/payroll-payment-mode-changes.mjs.map +1 -0
- package/resources/payroll-runs/index.d.mts +1 -0
- package/resources/payroll-runs/index.d.mts.map +1 -1
- package/resources/payroll-runs/index.d.ts +1 -0
- package/resources/payroll-runs/index.d.ts.map +1 -1
- package/resources/payroll-runs/index.js +3 -1
- package/resources/payroll-runs/index.js.map +1 -1
- package/resources/payroll-runs/index.mjs +1 -0
- package/resources/payroll-runs/index.mjs.map +1 -1
- package/resources/payroll-runs/off-cycle.d.mts +322 -0
- package/resources/payroll-runs/off-cycle.d.mts.map +1 -0
- package/resources/payroll-runs/off-cycle.d.ts +322 -0
- package/resources/payroll-runs/off-cycle.d.ts.map +1 -0
- package/resources/payroll-runs/off-cycle.js +112 -0
- package/resources/payroll-runs/off-cycle.js.map +1 -0
- package/resources/payroll-runs/off-cycle.mjs +108 -0
- package/resources/payroll-runs/off-cycle.mjs.map +1 -0
- package/resources/payroll-runs/payroll-runs.d.mts +4 -0
- package/resources/payroll-runs/payroll-runs.d.mts.map +1 -1
- package/resources/payroll-runs/payroll-runs.d.ts +4 -0
- package/resources/payroll-runs/payroll-runs.d.ts.map +1 -1
- package/resources/payroll-runs/payroll-runs.js +4 -0
- package/resources/payroll-runs/payroll-runs.js.map +1 -1
- package/resources/payroll-runs/payroll-runs.mjs +4 -0
- package/resources/payroll-runs/payroll-runs.mjs.map +1 -1
- package/resources/sandboxes.d.mts +17 -11
- package/resources/sandboxes.d.mts.map +1 -1
- package/resources/sandboxes.d.ts +17 -11
- package/resources/sandboxes.d.ts.map +1 -1
- package/resources/sandboxes.js +1 -3
- package/resources/sandboxes.js.map +1 -1
- package/resources/sandboxes.mjs +1 -3
- package/resources/sandboxes.mjs.map +1 -1
- package/resources/variable-compensation-payout-labels.d.mts +1 -1
- package/resources/variable-compensation-payout-labels.d.ts +1 -1
- package/resources/variable-compensation-payout-labels.js +1 -1
- package/resources/variable-compensation-payout-labels.mjs +1 -1
- package/resources/variable-compensation-payout-types.d.mts +1 -1
- package/resources/variable-compensation-payout-types.d.ts +1 -1
- package/resources/variable-compensation-payout-types.js +1 -1
- package/resources/variable-compensation-payout-types.mjs +1 -1
- package/resources/variable-compensation-payouts.d.mts +1 -1
- package/resources/variable-compensation-payouts.d.ts +1 -1
- package/resources/variable-compensation-payouts.js +1 -1
- package/resources/variable-compensation-payouts.mjs +1 -1
- package/resources/workflows.d.mts +20 -5
- package/resources/workflows.d.mts.map +1 -1
- package/resources/workflows.d.ts +20 -5
- package/resources/workflows.d.ts.map +1 -1
- package/src/client.ts +16 -0
- package/src/lib/charts/README.md +114 -0
- package/src/lib/charts/builders.ts +90 -0
- package/src/lib/charts/describe.ts +67 -0
- package/src/lib/charts/errors.ts +48 -0
- package/src/lib/charts/evaluate.ts +114 -0
- package/src/lib/charts/guards.ts +42 -0
- package/src/lib/charts/schema.ts +72 -0
- package/src/lib/charts/types.ts +113 -0
- package/src/lib/charts.ts +43 -0
- package/src/resources/custom-settings.ts +1 -1
- package/src/resources/hire-requirements.ts +8 -85
- package/src/resources/hires.ts +866 -219
- package/src/resources/index.ts +5 -0
- package/src/resources/payroll-payment-mode-changes.ts +182 -0
- package/src/resources/payroll-runs/index.ts +1 -0
- package/src/resources/payroll-runs/off-cycle.ts +372 -0
- package/src/resources/payroll-runs/payroll-runs.ts +10 -0
- package/src/resources/sandboxes.ts +17 -11
- package/src/resources/variable-compensation-payout-labels.ts +1 -1
- package/src/resources/variable-compensation-payout-types.ts +1 -1
- package/src/resources/variable-compensation-payouts.ts +1 -1
- package/src/resources/workflows.ts +25 -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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Base class for every error the chart-rule evaluator can throw. */
|
|
2
|
+
export class ChartRuleError extends Error {}
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A node whose `kind` is not in the vocabulary. The caller catches this and
|
|
6
|
+
* shows the setting as "configured in code", read-only.
|
|
7
|
+
*/
|
|
8
|
+
export class UnknownNodeError extends ChartRuleError {
|
|
9
|
+
constructor(public readonly kind?: string) {
|
|
10
|
+
super(`Unknown chart-rule node: ${kind ?? '(missing kind)'}`);
|
|
11
|
+
this.name = 'UnknownNodeError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A node evaluated to the wrong type of value (e.g. comparing non-numbers). */
|
|
16
|
+
export class RuleTypeError extends ChartRuleError {
|
|
17
|
+
constructor(message: string) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'RuleTypeError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A structurally invalid node in a deserialized tree: not an object, no string
|
|
25
|
+
* `kind`, or a `literal` without a scalar `value`. Distinct from
|
|
26
|
+
* `UnknownNodeError` (a well-formed node whose `kind` is simply not in the
|
|
27
|
+
* vocabulary — the intentional escape hatch). Like the others it is a
|
|
28
|
+
* `ChartRuleError`, so a caller reading an untrusted rule catches it instead of
|
|
29
|
+
* a native `TypeError` (or, worse, an `undefined` slipping through silently).
|
|
30
|
+
*/
|
|
31
|
+
export class MalformedRuleError extends ChartRuleError {
|
|
32
|
+
constructor(message: string) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = 'MalformedRuleError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A rule nested deeper than the evaluator will walk. Guards against a
|
|
40
|
+
* stack-overflowing tree from untrusted, deserialized input; like the others it
|
|
41
|
+
* is a `ChartRuleError`, so the caller's escape hatch catches it.
|
|
42
|
+
*/
|
|
43
|
+
export class RuleDepthError extends ChartRuleError {
|
|
44
|
+
constructor(maxDepth: number) {
|
|
45
|
+
super(`chart rule nested deeper than ${maxDepth} levels`);
|
|
46
|
+
this.name = 'RuleDepthError';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { isRulePlaceholder } from './builders';
|
|
2
|
+
import { MalformedRuleError, RuleDepthError, RuleTypeError, UnknownNodeError } from './errors';
|
|
3
|
+
import { assertRuleNode, literalValue } from './guards';
|
|
4
|
+
import {
|
|
5
|
+
MAX_RULE_DEPTH,
|
|
6
|
+
type Rule,
|
|
7
|
+
type RuleChannel,
|
|
8
|
+
type RuleContext,
|
|
9
|
+
type RuleNode,
|
|
10
|
+
type RuleValue,
|
|
11
|
+
} from './types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a rule to a value against `ctx`. Accepts a `{$rule}` placeholder or a
|
|
15
|
+
* bare tree. A malformed or unknown node throws a `ChartRuleError` (never a
|
|
16
|
+
* native `TypeError`), so a caller reading an untrusted, deserialized rule can
|
|
17
|
+
* catch every failure with one type. When the rule is a colour placeholder, the
|
|
18
|
+
* result is checked to be a colour (`string | null`) — a rule that resolves to a
|
|
19
|
+
* number or boolean is a `RuleTypeError`, not something the renderer paints.
|
|
20
|
+
*
|
|
21
|
+
* Pure: the only inputs are the node and the context. No clock, no randomness,
|
|
22
|
+
* no I/O — which is what makes it safe to run on an untrusted, user-edited tree
|
|
23
|
+
* and identical across the renderer, the panel readout, and a test. A tree
|
|
24
|
+
* nested past `MAX_RULE_DEPTH` throws `RuleDepthError` rather than overflowing.
|
|
25
|
+
*/
|
|
26
|
+
export function evaluate(rule: Rule, ctx: RuleContext): RuleValue {
|
|
27
|
+
if (isRulePlaceholder(rule)) {
|
|
28
|
+
return coerceForChannel(rule.channel, visit(rule.$rule, ctx, 0));
|
|
29
|
+
}
|
|
30
|
+
return visit(rule, ctx, 0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function visit(node: RuleNode, ctx: RuleContext, depth: number): RuleValue {
|
|
34
|
+
if (depth > MAX_RULE_DEPTH) {
|
|
35
|
+
throw new RuleDepthError(MAX_RULE_DEPTH);
|
|
36
|
+
}
|
|
37
|
+
assertRuleNode(node);
|
|
38
|
+
const next = depth + 1;
|
|
39
|
+
switch (node.kind) {
|
|
40
|
+
case 'value':
|
|
41
|
+
return ctx.value;
|
|
42
|
+
case 'literal':
|
|
43
|
+
return literalValue(node);
|
|
44
|
+
|
|
45
|
+
case 'equals':
|
|
46
|
+
return visit(node.left, ctx, next) === visit(node.right, ctx, next);
|
|
47
|
+
case 'isNot':
|
|
48
|
+
return visit(node.left, ctx, next) !== visit(node.right, ctx, next);
|
|
49
|
+
case 'lessThan':
|
|
50
|
+
return num(visit(node.left, ctx, next)) < num(visit(node.right, ctx, next));
|
|
51
|
+
case 'greaterThan':
|
|
52
|
+
return num(visit(node.left, ctx, next)) > num(visit(node.right, ctx, next));
|
|
53
|
+
case 'lessOrEqual':
|
|
54
|
+
return num(visit(node.left, ctx, next)) <= num(visit(node.right, ctx, next));
|
|
55
|
+
case 'greaterOrEqual':
|
|
56
|
+
return num(visit(node.left, ctx, next)) >= num(visit(node.right, ctx, next));
|
|
57
|
+
|
|
58
|
+
case 'ifElse':
|
|
59
|
+
return bool(visit(node.cond, ctx, next)) ? visit(node.then, ctx, next) : visit(node.else, ctx, next);
|
|
60
|
+
|
|
61
|
+
default:
|
|
62
|
+
return unreachable(node);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* -------------------------------------------------------------------------- */
|
|
67
|
+
/* Coercions — narrow a RuleValue, or throw a typed error. */
|
|
68
|
+
/* -------------------------------------------------------------------------- */
|
|
69
|
+
|
|
70
|
+
function num(value: RuleValue): number {
|
|
71
|
+
if (typeof value === 'number') {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
throw new RuleTypeError(`expected a number, got ${typeName(value)}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function bool(value: RuleValue): boolean {
|
|
78
|
+
if (typeof value === 'boolean') {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
throw new RuleTypeError(`expected a boolean, got ${typeName(value)}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** A colour channel must resolve to a colour string, or null for "no override". */
|
|
85
|
+
function asColor(value: RuleValue): RuleValue {
|
|
86
|
+
if (value === null || typeof value === 'string') {
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
throw new RuleTypeError(`a colour rule must resolve to a colour string or null, got ${typeName(value)}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Coerce a resolved value to what its channel can use. A colour rule must
|
|
94
|
+
* resolve to a colour; a future channel would add its own case here. A
|
|
95
|
+
* placeholder whose `channel` is missing or unrecognised (only possible from
|
|
96
|
+
* untrusted, deserialized input — the type and schema both pin it to `'color'`)
|
|
97
|
+
* is malformed rather than silently unchecked.
|
|
98
|
+
*/
|
|
99
|
+
function coerceForChannel(channel: RuleChannel, value: RuleValue): RuleValue {
|
|
100
|
+
switch (channel) {
|
|
101
|
+
case 'color':
|
|
102
|
+
return asColor(value);
|
|
103
|
+
default:
|
|
104
|
+
throw new MalformedRuleError(`a rule placeholder has an unsupported channel: ${String(channel)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function typeName(value: RuleValue): string {
|
|
109
|
+
return value === null ? 'null' : typeof value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function unreachable(node: never): never {
|
|
113
|
+
throw new UnknownNodeError((node as { kind?: string }).kind);
|
|
114
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { MalformedRuleError } from './errors';
|
|
2
|
+
import { type RuleNode, type Scalar } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Runtime validation for one node of a deserialized, untrusted rule tree, shared
|
|
6
|
+
* by `evaluate` and `describe`. A rule can arrive from JSON that TypeScript never
|
|
7
|
+
* checked, so `null`, a non-object, or a node without a string `kind` would throw
|
|
8
|
+
* a native `TypeError` on the first field read — skipping the `ChartRuleError`
|
|
9
|
+
* escape hatch a caller relies on. Validate before reading fields.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const SCALAR_TYPES: ReadonlySet<string> = new Set(['number', 'string', 'boolean']);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Assert `node` is shaped like a rule node — an object carrying a string `kind`.
|
|
16
|
+
* An unrecognised `kind` is *not* rejected here; that is the caller's `switch`
|
|
17
|
+
* default (`UnknownNodeError`), the deliberate "configured in code" signal.
|
|
18
|
+
*/
|
|
19
|
+
export function assertRuleNode(node: unknown): asserts node is RuleNode {
|
|
20
|
+
if (
|
|
21
|
+
node === null ||
|
|
22
|
+
typeof node !== 'object' ||
|
|
23
|
+
Array.isArray(node) ||
|
|
24
|
+
typeof (node as { kind?: unknown }).kind !== 'string'
|
|
25
|
+
) {
|
|
26
|
+
throw new MalformedRuleError('a rule node must be an object with a string "kind"');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Read a `literal` node's `value`, rejecting a missing or non-scalar one. Without
|
|
32
|
+
* this, `{ kind: 'literal' }` resolves to `undefined` and slips past the caller.
|
|
33
|
+
*/
|
|
34
|
+
export function literalValue(node: { value?: unknown }): Scalar {
|
|
35
|
+
const { value } = node;
|
|
36
|
+
if (value === null || SCALAR_TYPES.has(typeof value)) {
|
|
37
|
+
return value as Scalar;
|
|
38
|
+
}
|
|
39
|
+
throw new MalformedRuleError(
|
|
40
|
+
`a literal must carry a scalar value, got ${value === undefined ? 'undefined' : typeof value}`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { CHART_RULE_CONTRACT_VERSION } from './types';
|
|
2
|
+
|
|
3
|
+
/** Stable identifier for the published contract, versioned by the tag. */
|
|
4
|
+
export const CHART_RULE_SCHEMA_ID = `https://rippling.com/schemas/${CHART_RULE_CONTRACT_VERSION}.json`;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* JSON Schema (2020-12) for the `{$rule}` placeholder and its closed node set.
|
|
8
|
+
*
|
|
9
|
+
* This is the contract. A consumer that keeps its own rule evaluator (rather
|
|
10
|
+
* than importing `evaluate`) can validate against this so the two never drift —
|
|
11
|
+
* every kind and operand shape the builders can emit is described here.
|
|
12
|
+
*/
|
|
13
|
+
export const chartRuleSchema = {
|
|
14
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
15
|
+
$id: CHART_RULE_SCHEMA_ID,
|
|
16
|
+
title: 'Chart rule placeholder',
|
|
17
|
+
description: 'A rule tree the chart agent emits into a chart option, marked with $rule.',
|
|
18
|
+
type: 'object',
|
|
19
|
+
required: ['$rule', 'channel'],
|
|
20
|
+
additionalProperties: false,
|
|
21
|
+
properties: {
|
|
22
|
+
// A colour rule's top-level tree is the conditional-value form (`when(...)`),
|
|
23
|
+
// matching what `color()` builds and accepts. A bare ref/comparison/literal
|
|
24
|
+
// resolves to a number/boolean/constant, not a colour decision.
|
|
25
|
+
$rule: { $ref: '#/$defs/ifElse' },
|
|
26
|
+
channel: { const: 'color' },
|
|
27
|
+
},
|
|
28
|
+
$defs: {
|
|
29
|
+
scalar: { type: ['number', 'string', 'boolean', 'null'] },
|
|
30
|
+
node: {
|
|
31
|
+
oneOf: [
|
|
32
|
+
{ $ref: '#/$defs/ref' },
|
|
33
|
+
{ $ref: '#/$defs/literal' },
|
|
34
|
+
{ $ref: '#/$defs/comparison' },
|
|
35
|
+
{ $ref: '#/$defs/ifElse' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
ref: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
required: ['kind'],
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
properties: { kind: { const: 'value' } },
|
|
43
|
+
},
|
|
44
|
+
literal: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
required: ['kind', 'value'],
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
properties: { kind: { const: 'literal' }, value: { $ref: '#/$defs/scalar' } },
|
|
49
|
+
},
|
|
50
|
+
comparison: {
|
|
51
|
+
type: 'object',
|
|
52
|
+
required: ['kind', 'left', 'right'],
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
properties: {
|
|
55
|
+
kind: { enum: ['equals', 'isNot', 'lessThan', 'greaterThan', 'lessOrEqual', 'greaterOrEqual'] },
|
|
56
|
+
left: { $ref: '#/$defs/node' },
|
|
57
|
+
right: { $ref: '#/$defs/node' },
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
ifElse: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
required: ['kind', 'cond', 'then', 'else'],
|
|
63
|
+
additionalProperties: false,
|
|
64
|
+
properties: {
|
|
65
|
+
kind: { const: 'ifElse' },
|
|
66
|
+
cond: { $ref: '#/$defs/node' },
|
|
67
|
+
then: { $ref: '#/$defs/node' },
|
|
68
|
+
else: { $ref: '#/$defs/node' },
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
} as const;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart rule vocabulary — shared types.
|
|
3
|
+
*
|
|
4
|
+
* A rule is a small, serializable tree of nodes discriminated by `kind`. The
|
|
5
|
+
* agent builds it with the helpers in `builders.ts`, which emit it wrapped in a
|
|
6
|
+
* `{$rule}` placeholder — the same idea as the `{$fn}` placeholders a chart
|
|
7
|
+
* already emits. The renderer resolves it with `evaluate`; the settings panel
|
|
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` describes.
|
|
10
|
+
*
|
|
11
|
+
* v1 is scoped to conditional formatting: compare this datum's `value` against a
|
|
12
|
+
* constant, and (optionally) pick between two values. Richer pieces — aggregates,
|
|
13
|
+
* logic, more refs — are the documented roadmap in the README.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const CHART_RULE_CONTRACT_VERSION = 'chart_rule.v1' as const;
|
|
17
|
+
export type ChartRuleContractVersion = typeof CHART_RULE_CONTRACT_VERSION;
|
|
18
|
+
|
|
19
|
+
/** A leaf value a rule can carry or resolve to. */
|
|
20
|
+
export type Scalar = number | string | boolean | null;
|
|
21
|
+
|
|
22
|
+
/* -------------------------------------------------------------------------- */
|
|
23
|
+
/* Nodes — the closed set, discriminated by `kind`. Each appears in every face. */
|
|
24
|
+
/* -------------------------------------------------------------------------- */
|
|
25
|
+
|
|
26
|
+
/** Reads a value out of the evaluation context — this datum's plotted value. */
|
|
27
|
+
export type RefNode = { kind: 'value' };
|
|
28
|
+
|
|
29
|
+
export interface LiteralNode {
|
|
30
|
+
kind: 'literal';
|
|
31
|
+
value: Scalar;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ComparisonKind =
|
|
35
|
+
| 'equals'
|
|
36
|
+
| 'isNot'
|
|
37
|
+
| 'lessThan'
|
|
38
|
+
| 'greaterThan'
|
|
39
|
+
| 'lessOrEqual'
|
|
40
|
+
| 'greaterOrEqual';
|
|
41
|
+
export interface ComparisonNode {
|
|
42
|
+
kind: ComparisonKind;
|
|
43
|
+
left: RuleNode;
|
|
44
|
+
right: RuleNode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The conditional-value form produced by `when(cond, then, else)`. */
|
|
48
|
+
export interface IfElseNode {
|
|
49
|
+
kind: 'ifElse';
|
|
50
|
+
cond: RuleNode;
|
|
51
|
+
then: RuleNode;
|
|
52
|
+
else: RuleNode;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Any node of a rule tree. */
|
|
56
|
+
export type RuleNode = RefNode | LiteralNode | ComparisonNode | IfElseNode;
|
|
57
|
+
|
|
58
|
+
/* -------------------------------------------------------------------------- */
|
|
59
|
+
/* The placeholder — how a rule is embedded in a chart option (like {$fn}). */
|
|
60
|
+
/* -------------------------------------------------------------------------- */
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The chart channel a rule drives. v1 supports colour only — a rule decides the
|
|
64
|
+
* colour of a series/datum. Other channels (opacity, label visibility, …) are
|
|
65
|
+
* the documented roadmap and would be added here.
|
|
66
|
+
*/
|
|
67
|
+
export type RuleChannel = 'color';
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* What a builder returns: a rule tree, marked so the renderer can find it, and
|
|
71
|
+
* tagged with the channel it targets. `channel: 'color'` says this resolves to a
|
|
72
|
+
* colour — so a reader sees the target without inferring it from where it sits.
|
|
73
|
+
*/
|
|
74
|
+
export interface RulePlaceholder {
|
|
75
|
+
$rule: RuleNode;
|
|
76
|
+
channel: RuleChannel;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A placeholder, or the bare tree — what `evaluate` and `describe` accept. */
|
|
80
|
+
export type Rule = RulePlaceholder | RuleNode;
|
|
81
|
+
|
|
82
|
+
/* -------------------------------------------------------------------------- */
|
|
83
|
+
/* Evaluation */
|
|
84
|
+
/* -------------------------------------------------------------------------- */
|
|
85
|
+
|
|
86
|
+
/** What a rule is evaluated against: the current datum's value. */
|
|
87
|
+
export interface RuleContext {
|
|
88
|
+
value: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The result of evaluating a node. */
|
|
92
|
+
export type RuleValue = Scalar;
|
|
93
|
+
|
|
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
|
+
*/
|
|
99
|
+
export const MAX_RULE_DEPTH = 256;
|
|
100
|
+
|
|
101
|
+
/* -------------------------------------------------------------------------- */
|
|
102
|
+
/* Description — what the settings panel renders */
|
|
103
|
+
/* -------------------------------------------------------------------------- */
|
|
104
|
+
|
|
105
|
+
export type ControlRole = 'rule' | 'comparison' | 'ref' | 'literal';
|
|
106
|
+
|
|
107
|
+
/** A node as the panel should show it: a label, its editable value, its parts. */
|
|
108
|
+
export interface Control {
|
|
109
|
+
role: ControlRole;
|
|
110
|
+
label: string;
|
|
111
|
+
value?: Scalar;
|
|
112
|
+
parts?: Control[];
|
|
113
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export {
|
|
2
|
+
color,
|
|
3
|
+
equals,
|
|
4
|
+
greaterOrEqual,
|
|
5
|
+
greaterThan,
|
|
6
|
+
isNot,
|
|
7
|
+
isRulePlaceholder,
|
|
8
|
+
lessOrEqual,
|
|
9
|
+
lessThan,
|
|
10
|
+
literal,
|
|
11
|
+
value,
|
|
12
|
+
when,
|
|
13
|
+
type Operand,
|
|
14
|
+
} from './charts/builders';
|
|
15
|
+
export { evaluate } from './charts/evaluate';
|
|
16
|
+
export { describe } from './charts/describe';
|
|
17
|
+
export { chartRuleSchema, CHART_RULE_SCHEMA_ID } from './charts/schema';
|
|
18
|
+
export {
|
|
19
|
+
ChartRuleError,
|
|
20
|
+
MalformedRuleError,
|
|
21
|
+
RuleDepthError,
|
|
22
|
+
RuleTypeError,
|
|
23
|
+
UnknownNodeError,
|
|
24
|
+
} from './charts/errors';
|
|
25
|
+
export {
|
|
26
|
+
CHART_RULE_CONTRACT_VERSION,
|
|
27
|
+
MAX_RULE_DEPTH,
|
|
28
|
+
type ChartRuleContractVersion,
|
|
29
|
+
type ComparisonKind,
|
|
30
|
+
type ComparisonNode,
|
|
31
|
+
type Control,
|
|
32
|
+
type ControlRole,
|
|
33
|
+
type IfElseNode,
|
|
34
|
+
type LiteralNode,
|
|
35
|
+
type RefNode,
|
|
36
|
+
type Rule,
|
|
37
|
+
type RuleChannel,
|
|
38
|
+
type RuleContext,
|
|
39
|
+
type RuleNode,
|
|
40
|
+
type RulePlaceholder,
|
|
41
|
+
type RuleValue,
|
|
42
|
+
type Scalar,
|
|
43
|
+
} from './charts/types';
|
|
@@ -9,8 +9,9 @@ import { RequestOptions } from '../internal/request-options';
|
|
|
9
9
|
*/
|
|
10
10
|
export class HireRequirements extends APIResource {
|
|
11
11
|
/**
|
|
12
|
-
* Return baseline required fields for a country and hire type.
|
|
13
|
-
*
|
|
12
|
+
* Return baseline required fields for a country and hire type.
|
|
13
|
+
* requirements_version identifies this catalog snapshot. POST /hires/ does not
|
|
14
|
+
* accept it. POST /hires/ remains authoritative for company-specific validation.
|
|
14
15
|
*
|
|
15
16
|
* @example HTTP
|
|
16
17
|
* Representative request and response shapes.
|
|
@@ -30,23 +31,6 @@ export class HireRequirements extends APIResource {
|
|
|
30
31
|
* "required_groups": [
|
|
31
32
|
* "string"
|
|
32
33
|
* ],
|
|
33
|
-
* "top_level_fields": [
|
|
34
|
-
* {
|
|
35
|
-
* "field": "string",
|
|
36
|
-
* "type": {},
|
|
37
|
-
* "requiredness": "string",
|
|
38
|
-
* "required_when": {
|
|
39
|
-
* "field": "string",
|
|
40
|
-
* "operator": "string",
|
|
41
|
-
* "value": {}
|
|
42
|
-
* },
|
|
43
|
-
* "format": "string",
|
|
44
|
-
* "items": null,
|
|
45
|
-
* "fields": [
|
|
46
|
-
* "string"
|
|
47
|
-
* ]
|
|
48
|
-
* }
|
|
49
|
-
* ],
|
|
50
34
|
* "fields_by_group": [
|
|
51
35
|
* null
|
|
52
36
|
* ],
|
|
@@ -79,12 +63,13 @@ export interface HireRequirementListResponse {
|
|
|
79
63
|
fields_by_group: Array<unknown>;
|
|
80
64
|
|
|
81
65
|
/**
|
|
82
|
-
* Hire type
|
|
66
|
+
* Hire type for this catalog. POST /hires/ uses the same value. An omitted POST
|
|
67
|
+
* value defaults to direct_hire.
|
|
83
68
|
*/
|
|
84
69
|
hire_type: string;
|
|
85
70
|
|
|
86
71
|
/**
|
|
87
|
-
*
|
|
72
|
+
* Groups you must send for this country.
|
|
88
73
|
*/
|
|
89
74
|
required_groups: Array<string>;
|
|
90
75
|
|
|
@@ -93,11 +78,6 @@ export interface HireRequirementListResponse {
|
|
|
93
78
|
*/
|
|
94
79
|
requirements_version: string;
|
|
95
80
|
|
|
96
|
-
/**
|
|
97
|
-
* Item-level fields such as client_request_id.
|
|
98
|
-
*/
|
|
99
|
-
top_level_fields?: Array<HireRequirementListResponse.TopLevelField>;
|
|
100
|
-
|
|
101
81
|
/**
|
|
102
82
|
* Public field paths that are not writable for this selector tuple.
|
|
103
83
|
*/
|
|
@@ -109,67 +89,10 @@ export interface HireRequirementListResponse {
|
|
|
109
89
|
warnings?: Array<string>;
|
|
110
90
|
}
|
|
111
91
|
|
|
112
|
-
export namespace HireRequirementListResponse {
|
|
113
|
-
export interface TopLevelField {
|
|
114
|
-
/**
|
|
115
|
-
* JSON type string, or a list of allowed types for custom-field values.
|
|
116
|
-
*/
|
|
117
|
-
type: unknown;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Public field name relative to its group, or omitted for array item descriptors.
|
|
121
|
-
*/
|
|
122
|
-
field?: string;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Nested object fields when type is object.
|
|
126
|
-
*/
|
|
127
|
-
fields?: Array<unknown>;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* date means YYYY-MM-DD.
|
|
131
|
-
*/
|
|
132
|
-
format?: string;
|
|
133
|
-
|
|
134
|
-
items?: unknown;
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Sibling-field condition when requiredness is dependent.
|
|
138
|
-
*/
|
|
139
|
-
required_when?: TopLevelField.RequiredWhen;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* required, optional, or dependent.
|
|
143
|
-
*/
|
|
144
|
-
requiredness?: string;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export namespace TopLevelField {
|
|
148
|
-
/**
|
|
149
|
-
* Sibling-field condition when requiredness is dependent.
|
|
150
|
-
*/
|
|
151
|
-
export interface RequiredWhen {
|
|
152
|
-
/**
|
|
153
|
-
* Sibling field in the same object that this condition inspects.
|
|
154
|
-
*/
|
|
155
|
-
field: string;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* equals, not_equals, present, or absent.
|
|
159
|
-
*/
|
|
160
|
-
operator: string;
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Comparison value for equals and not_equals. Omitted for present and absent.
|
|
164
|
-
*/
|
|
165
|
-
value?: unknown;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
92
|
export interface HireRequirementListParams {
|
|
171
93
|
/**
|
|
172
|
-
* ISO 3166-1 alpha-2 country code.
|
|
94
|
+
* ISO 3166-1 alpha-2 country code. Direct hire is supported in AU, CA, CH, CN, DE,
|
|
95
|
+
* ES, FR, GB, HK, IE, IN, NL, NZ, and US.
|
|
173
96
|
*/
|
|
174
97
|
country_code: string;
|
|
175
98
|
|