Skip to content

Commit 824c9bf

Browse files
committed
add zod schemas
Signed-off-by: Shan He <[email protected]>
1 parent 3b6e904 commit 824c9bf

28 files changed

+1965
-1
lines changed

src/schemas/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"apache-arrow": ">=15.0.0",
4343
"global": "^4.3.0",
4444
"keymirror": "^0.1.1",
45-
"lodash": "4.17.21"
45+
"lodash": "4.17.21",
46+
"zod": "^3.24.2"
4647
},
4748
"nyc": {
4849
"sourceMap": false,

src/schemas/src/animation.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright contributors to the kepler.gl project
3+
4+
import {z} from 'zod';
5+
6+
import {TimeRangeFilterSchema} from './filter';
7+
8+
export const AnimationTimeFormat = z.enum(['L', 'L LT', 'L LTS']);
9+
export type AnimationTimeFormat = z.infer<typeof AnimationTimeFormat>;
10+
11+
export const AnimationConfigSchema = z.preprocess(
12+
(config: any) => {
13+
// Remove null values so they are not saved and don't show up in the editors
14+
if (config?.timeFormat === null) {
15+
config = {...config};
16+
delete config.timeFormat;
17+
}
18+
if (config?.timezone === null) {
19+
config = {...config};
20+
delete config.timezone;
21+
}
22+
return config;
23+
},
24+
z.object({
25+
currentTime: z
26+
.number()
27+
.nullable()
28+
.optional()
29+
.describe('The current time of the animation in epoch milliseconds'),
30+
speed: z
31+
.number()
32+
.min(0)
33+
.max(10)
34+
.default(1)
35+
.describe('The speed of the animation, a number between 0 and 10'),
36+
domain: z
37+
.tuple([z.number(), z.number()])
38+
.optional()
39+
.describe(
40+
'Override the time domain of the animation (in epoch milliseconds). ' +
41+
'By default the domain is calculated from the data.'
42+
),
43+
timeFormat: AnimationTimeFormat.optional().describe(
44+
'The format for displaying the animation time ' +
45+
'For the syntax check "Locale aware formats" here: https://momentjs.com/docs/#/parsing/string-format/'
46+
),
47+
timezone: z
48+
.string()
49+
.optional()
50+
.describe(
51+
'The timezone for displaying the animation time e.g. "America/New_York"' +
52+
'For the list of timezones check here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones'
53+
)
54+
})
55+
);
56+
export type AnimationConfigSchema = z.infer<typeof AnimationConfigSchema>;
57+
58+
export const SyncTimelineMode = z.enum(['start', 'end']);
59+
export type SyncTimelineMode = z.infer<typeof SyncTimelineMode>;
60+
61+
/**
62+
* Subset of TimeRangeFilterSchema that is used for filter animation config JSON editor
63+
*/
64+
export const FilterAnimationSchema = TimeRangeFilterSchema.pick({
65+
dataId: true,
66+
value: true,
67+
animationWindow: true,
68+
speed: true,
69+
syncedWithLayerTimeline: true,
70+
syncTimelineMode: true,
71+
timezone: true
72+
}).required({
73+
dataId: true,
74+
animationWindow: true
75+
});
76+
77+
export type FilterAnimationSchema = z.infer<typeof FilterAnimationSchema>;

src/schemas/src/color.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright contributors to the kepler.gl project
3+
4+
import {z} from 'zod';
5+
6+
const RGBColorComponent = z.number().min(0).max(255);
7+
8+
export const RGBColorSchema = z.union([
9+
z.tuple([RGBColorComponent, RGBColorComponent, RGBColorComponent]),
10+
z.tuple([RGBColorComponent, RGBColorComponent, RGBColorComponent, RGBColorComponent])
11+
]);
12+
export type RGBColorSchema = z.infer<typeof RGBColorSchema>;
13+
14+
export const HexColorSchema = z.coerce.string();
15+
export type HexColorSchema = z.infer<typeof HexColorSchema>;
16+
17+
export const ColorMapSchema = z.array(
18+
z.tuple([z.union([z.string(), z.number(), z.null(), z.array(z.coerce.string())]), HexColorSchema])
19+
);
20+
export type ColorMapSchema = z.infer<typeof ColorMapSchema>;
21+
22+
export const ColorLegendsSchema = z.record(z.string(), z.string());
23+
export type ColorLegendsSchema = z.infer<typeof ColorLegendsSchema>;
24+
25+
export enum ColorRangeType {
26+
sequential = 'sequential',
27+
qualitative = 'qualitative',
28+
diverging = 'diverging',
29+
cyclical = 'cyclical',
30+
custom = 'custom',
31+
ordinal = 'ordinal',
32+
customOrdinal = 'customOrdinal'
33+
}
34+
35+
export const ColorRangeTypeZod = z.preprocess((type: any) => {
36+
if (type === 'singlehue') {
37+
type = ColorRangeType.sequential;
38+
}
39+
return type;
40+
}, z.nativeEnum(ColorRangeType).default(ColorRangeType.sequential));
41+
export type ColorRangeTypeZod = z.infer<typeof ColorRangeTypeZod>;
42+
43+
const COLOR_RANGE_TYPES = Object.values(ColorRangeType).join(', ');
44+
const COLOR_RANGE_TYPE_DESC = `The type of the color range. Must be one of: ${COLOR_RANGE_TYPES}`;
45+
46+
export const ColorRangeSchema = z.preprocess(
47+
(colorRange: any) => {
48+
let next = colorRange;
49+
if (colorRange.colorMap === null) {
50+
next = {...next};
51+
delete next.colorMap;
52+
}
53+
return next;
54+
},
55+
z.object({
56+
name: z.string().describe('The name of the color range.').default('Unnamed'),
57+
type: ColorRangeTypeZod.describe(COLOR_RANGE_TYPE_DESC),
58+
category: z.string().default('Unnamed'),
59+
colors: z.array(HexColorSchema),
60+
reversed: z.boolean().optional(),
61+
colorMap: ColorMapSchema.optional(),
62+
colorLegends: ColorLegendsSchema.optional()
63+
})
64+
);
65+
export type ColorRangeSchema = z.infer<typeof ColorRangeSchema>;
66+
67+
export const DEFAULT_COLOR_RANGE: ColorRangeSchema = {
68+
name: 'Uber Viz Qualitative',
69+
type: ColorRangeType.qualitative,
70+
category: 'Uber',
71+
colors: [
72+
'#12939A',
73+
'#DDB27C',
74+
'#88572C',
75+
'#FF991F',
76+
'#F15C17',
77+
'#223F9A',
78+
'#DA70BF',
79+
'#125C77',
80+
'#4DC19C',
81+
'#776E57'
82+
]
83+
};

src/schemas/src/common.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright contributors to the kepler.gl project
3+
4+
import {z} from 'zod';
5+
6+
const TIME_INTERVALS_KEYS = [
7+
'year',
8+
'month',
9+
'week',
10+
'day',
11+
'hour',
12+
'minute',
13+
'second',
14+
'millisecond'
15+
] as const;
16+
17+
export const TIME_INTERVAL_REGEX = new RegExp(`^([0-9]+)-(${TIME_INTERVALS_KEYS.join('|')})$`);
18+
19+
export const TIME_INTERVAL_DESC =
20+
`Should be in the form (number)-(interval), where interval is one of: ` +
21+
`${TIME_INTERVALS_KEYS.join(', ')}, e.g 1-day, 2-week, 3-month, 4-year`;
22+
23+
export const TimeIntervalSchema = z.string().regex(TIME_INTERVAL_REGEX);
24+
25+
export enum AggregationKey {
26+
COUNT = 'COUNT',
27+
SUM = 'SUM',
28+
MEAN = 'MEAN',
29+
MAX = 'MAX',
30+
MIN = 'MIN',
31+
DEVIATION = 'DEVIATION',
32+
VARIANCE = 'VARIANCE',
33+
MEDIAN = 'MEDIAN',
34+
P05 = 'P05',
35+
P25 = 'P25',
36+
P50 = 'P50',
37+
P75 = 'P75',
38+
P95 = 'P95',
39+
MODE = 'MODE',
40+
UNIQUE = 'UNIQUE',
41+
MERGE = 'MERGE'
42+
}
43+
export const AggregationKeySchema = z.nativeEnum(AggregationKey);
44+
export type AggregationKeySchema = z.infer<typeof AggregationKeySchema>;

0 commit comments

Comments
 (0)