1
1
import camelcaseKeys from 'camelcase-keys'
2
2
import { atom } from 'jotai'
3
3
import { defaults , uniqueId } from 'lodash-es'
4
- import {
5
- CamelCasedPropertiesDeep ,
6
- PartialDeep ,
7
- SetOptional ,
8
- SetRequired ,
9
- } from 'type-fest'
4
+ import { PartialDeep , SetOptional , SetRequired } from 'type-fest'
10
5
11
6
import { CopilotDocV1 } from '../../models/copilot.schema'
12
7
import { FavGroup , favGroupAtom } from '../../store/useFavGroups'
@@ -36,6 +31,14 @@ export type WithPartialCoordinates<T> = T extends {
36
31
37
32
export type WithId < T = { } > = T extends never ? never : T & { id : string }
38
33
34
+ type DehydratedEditorOperation = WithoutIdDeep < EditorOperation >
35
+
36
+ type WithoutIdDeep < T > = T extends unknown [ ]
37
+ ? { [ K in keyof T ] : WithoutIdDeep < T [ K ] > }
38
+ : T extends object
39
+ ? Omit < { [ K in keyof T ] : WithoutIdDeep < T [ K ] > } , 'id' >
40
+ : T
41
+
39
42
export function createAction (
40
43
initialValues : SetRequired < Partial < Omit < EditorAction , 'id' > > , 'type' > ,
41
44
) {
@@ -168,33 +171,64 @@ export const editorFavGroupsAtom = atom(
168
171
} ,
169
172
)
170
173
171
- export function toEditorOperation (
172
- source : CopilotOperationLoose ,
174
+ /**
175
+ * Converts the operation to a dehydrated format that is suitable
176
+ * for storage or transmission. Essentially, it strips all `id` fields
177
+ * which only makes sense in the context of the editor.
178
+ */
179
+ export function dehydrateOperation (
180
+ source : EditorOperation ,
181
+ ) : DehydratedEditorOperation {
182
+ return {
183
+ ...source ,
184
+ opers : source . opers . map ( ( { id, ...operator } ) => operator ) ,
185
+ groups : source . groups . map ( ( { id, opers, ...group } ) => ( {
186
+ ...group ,
187
+ opers : opers . map ( ( { id, ...operator } ) => operator ) ,
188
+ } ) ) ,
189
+ actions : source . actions . map ( ( { id, ...action } ) => action ) ,
190
+ }
191
+ }
192
+
193
+ export function hydrateOperation (
194
+ source : DehydratedEditorOperation ,
173
195
) : EditorOperation {
174
- const camelCased = camelcaseKeys ( source , { deep : true } )
175
- const operation = JSON . parse ( JSON . stringify ( camelCased ) )
176
- const converted = {
177
- ...operation ,
178
- opers : operation . opers . map ( ( operator ) => ( {
196
+ return {
197
+ ...source ,
198
+ opers : source . opers . map ( ( operator ) => ( {
179
199
...operator ,
180
200
id : uniqueId ( ) ,
181
201
} ) ) ,
182
- groups : operation . groups . map ( ( group ) => ( {
202
+ groups : source . groups . map ( ( group ) => ( {
183
203
...group ,
184
204
id : uniqueId ( ) ,
185
- opers : group . opers . map ( ( operator ) => ( { ...operator , id : uniqueId ( ) } ) ) ,
205
+ opers : group . opers . map ( ( operator ) => ( {
206
+ ...operator ,
207
+ id : uniqueId ( ) ,
208
+ } ) ) ,
186
209
} ) ) ,
210
+ actions : source . actions . map ( ( action ) => ( {
211
+ ...action ,
212
+ id : uniqueId ( ) ,
213
+ } ) ) ,
214
+ }
215
+ }
216
+
217
+ export function toEditorOperation (
218
+ source : CopilotOperationLoose ,
219
+ ) : EditorOperation {
220
+ const camelCased = camelcaseKeys ( source , { deep : true } )
221
+ const operation = JSON . parse ( JSON . stringify ( camelCased ) ) as typeof camelCased
222
+ const converted = {
223
+ ...operation ,
187
224
actions : operation . actions . map ( ( action , index ) => {
188
225
const {
189
226
preDelay,
190
227
postDelay,
191
228
rearDelay,
192
229
...newAction
193
- } : EditorAction &
194
- CamelCasedPropertiesDeep < CopilotOperationLoose [ 'actions' ] [ number ] > = {
195
- ...action ,
196
- id : uniqueId ( ) ,
197
- }
230
+ } : WithoutIdDeep < EditorAction > & ( typeof camelCased ) [ 'actions' ] [ number ] =
231
+ action
198
232
// intermediatePostDelay 等于当前动作的 preDelay
199
233
if ( preDelay !== undefined ) {
200
234
newAction . intermediatePostDelay = preDelay
@@ -209,11 +243,11 @@ export function toEditorOperation(
209
243
newAction . intermediatePreDelay = prevAction . postDelay
210
244
}
211
245
}
212
- return newAction satisfies EditorAction
246
+ return newAction satisfies WithoutIdDeep < EditorAction >
213
247
} ) ,
214
248
}
215
249
216
- return converted
250
+ return hydrateOperation ( converted )
217
251
}
218
252
219
253
/**
@@ -223,22 +257,17 @@ export function toMaaOperation(
223
257
operation : EditorOperation ,
224
258
) : CopilotOperationLoose {
225
259
operation = JSON . parse ( JSON . stringify ( operation ) )
260
+ const dehydrated = dehydrateOperation ( operation )
226
261
const converted = {
227
- ...operation ,
228
- opers : operation . opers . map ( ( { id, ...operator } ) => operator ) ,
229
- groups : operation . groups . map ( ( { id, opers, ...group } ) => ( {
230
- ...group ,
231
- opers : opers . map ( ( { id, ...operator } ) => operator ) ,
232
- } ) ) ,
233
- actions : operation . actions . map ( ( action , index , actions ) => {
262
+ ...dehydrated ,
263
+ actions : dehydrated . actions . map ( ( action , index , actions ) => {
234
264
type Action = PartialDeep < WithPartialCoordinates < CopilotDocV1 . Action > >
235
265
const {
236
266
_id,
237
- id,
238
267
intermediatePreDelay,
239
268
intermediatePostDelay,
240
269
...newAction
241
- } : EditorAction & Action = action
270
+ } : WithoutIdDeep < EditorAction > & Action = action
242
271
// preDelay 等于当前动作的 intermediatePostDelay
243
272
if ( intermediatePostDelay !== undefined ) {
244
273
newAction . preDelay = intermediatePostDelay
0 commit comments