xref: /aosp_15_r20/external/perfetto/ui/src/core/state_serialization_schema.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {z} from 'zod';
16import {Time} from '../base/time';
17
18// This should be bumped only in case of breaking changes that cannot be
19// addressed using zod's z.optional(), z.default() or z.coerce.xxx().
20// Ideally these cases should be extremely rare.
21export const SERIALIZED_STATE_VERSION = 1;
22
23// At deserialization time this takes a string as input and converts it into a
24// BigInt. The serialization side of this is handled by JsonSerialize(), which
25// converts BigInt into strings when invoking JSON.stringify.
26const zTime = z
27  .string()
28  .regex(/[-]?\d+/)
29  .transform((s) => Time.fromRaw(BigInt(s)));
30
31const SELECTION_SCHEMA = z.discriminatedUnion('kind', [
32  z.object({
33    kind: z.literal('TRACK_EVENT'),
34    // This is actually the track URI but let's not rename for backwards compat
35    trackKey: z.string(),
36    eventId: z.string(),
37    detailsPanel: z.unknown(),
38  }),
39  z.object({
40    kind: z.literal('AREA'),
41    start: zTime,
42    end: zTime,
43    trackUris: z.array(z.string()),
44  }),
45]);
46
47export type SerializedSelection = z.infer<typeof SELECTION_SCHEMA>;
48
49const NOTE_SCHEMA = z
50  .object({
51    id: z.string(),
52    start: zTime,
53    color: z.string(),
54    text: z.string(),
55  })
56  .and(
57    z.discriminatedUnion('noteType', [
58      z.object({noteType: z.literal('DEFAULT')}),
59      z.object({noteType: z.literal('SPAN'), end: zTime}),
60    ]),
61  );
62
63export type SerializedNote = z.infer<typeof NOTE_SCHEMA>;
64
65const PLUGIN_SCHEMA = z.object({
66  id: z.string(),
67  state: z.any(),
68});
69
70export type SerializedPluginState = z.infer<typeof PLUGIN_SCHEMA>;
71
72export const APP_STATE_SCHEMA = z.object({
73  version: z.number(),
74  pinnedTracks: z.array(z.string()).default([]),
75  viewport: z
76    .object({
77      start: zTime,
78      end: zTime,
79    })
80    .optional(),
81  selection: z.array(SELECTION_SCHEMA).default([]),
82  notes: z.array(NOTE_SCHEMA).default([]),
83  plugins: z.array(PLUGIN_SCHEMA).default([]),
84});
85
86export type SerializedAppState = z.infer<typeof APP_STATE_SCHEMA>;
87