@routevn/creator-model 1.12.2 → 1.13.1
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/README.md +46 -2
- package/package.json +1 -1
- package/src/model.js +895 -26
package/README.md
CHANGED
|
@@ -131,8 +131,12 @@ font IDs. Both forms are persisted as supplied, and every ID must reference an
|
|
|
131
131
|
existing non-folder font:
|
|
132
132
|
|
|
133
133
|
```js
|
|
134
|
-
{
|
|
135
|
-
|
|
134
|
+
{
|
|
135
|
+
fontId: "font-primary";
|
|
136
|
+
}
|
|
137
|
+
{
|
|
138
|
+
fontId: ["font-primary", "font-fallback"];
|
|
139
|
+
}
|
|
136
140
|
```
|
|
137
141
|
|
|
138
142
|
## Computed Variables
|
|
@@ -225,6 +229,8 @@ tests/
|
|
|
225
229
|
images.spec.yaml
|
|
226
230
|
sounds-and-videos.spec.yaml
|
|
227
231
|
animations.spec.yaml
|
|
232
|
+
audio-effects.test.js
|
|
233
|
+
audio-effects-drift.test.js
|
|
228
234
|
fonts-and-colors.spec.yaml
|
|
229
235
|
transforms-variables-textstyles.spec.yaml
|
|
230
236
|
characters-and-layouts.spec.yaml
|
|
@@ -332,6 +338,40 @@ Transition animation `mask` accepts one mask object or a non-empty ordered
|
|
|
332
338
|
array. Each mask may define a non-negative safe-integer `delay` in
|
|
333
339
|
milliseconds.
|
|
334
340
|
|
|
341
|
+
Audio effects are foldered resources stored in `audioEffects.items` and
|
|
342
|
+
`audioEffects.tree`. Non-folder items use this wrapper:
|
|
343
|
+
|
|
344
|
+
```js
|
|
345
|
+
{
|
|
346
|
+
id: "crossfade",
|
|
347
|
+
type: "audioEffect",
|
|
348
|
+
name: "Crossfade",
|
|
349
|
+
description: "Fade between two BGM sources",
|
|
350
|
+
tagIds: ["smooth"],
|
|
351
|
+
preview: {
|
|
352
|
+
outgoing: { soundId: "calm-theme" },
|
|
353
|
+
incoming: { soundId: "battle-theme" },
|
|
354
|
+
},
|
|
355
|
+
audioEffect: {
|
|
356
|
+
type: "transition",
|
|
357
|
+
prev: { fade: { duration: 600, easing: "easeInOutSine" } },
|
|
358
|
+
next: { fade: { duration: 900, easing: "easeInOutSine" } },
|
|
359
|
+
},
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
The optional editor preview uses `outgoing` and `incoming` sound slots for a
|
|
364
|
+
transition effect, or a single `target` sound slot for an update effect. Each
|
|
365
|
+
slot is an object containing a `soundId`.
|
|
366
|
+
|
|
367
|
+
`audioEffect.type` is either `transition` or `update`. Transition effects have
|
|
368
|
+
at least one `prev.fade` or `next.fade`. Update effects tween one or more of
|
|
369
|
+
`volume`, `pan`, and `playbackRate`; each property has non-empty keyframes and
|
|
370
|
+
must finish with an absolute numeric keyframe. That final number becomes the
|
|
371
|
+
persistent BGM property value after the effect finishes. Absolute volume values
|
|
372
|
+
are bounded to `0..100`, pan to `-1..1`, and playback rate to `>= 0`; relative
|
|
373
|
+
keyframes represent unbounded numeric deltas and cannot be final.
|
|
374
|
+
|
|
335
375
|
## Current Scope
|
|
336
376
|
|
|
337
377
|
Currently implemented command types:
|
|
@@ -370,6 +410,10 @@ Currently implemented command types:
|
|
|
370
410
|
- `animation.update`
|
|
371
411
|
- `animation.delete`
|
|
372
412
|
- `animation.move`
|
|
413
|
+
- `audioEffect.create`
|
|
414
|
+
- `audioEffect.update`
|
|
415
|
+
- `audioEffect.delete`
|
|
416
|
+
- `audioEffect.move`
|
|
373
417
|
- `font.create`
|
|
374
418
|
- `font.update`
|
|
375
419
|
- `font.delete`
|
package/package.json
CHANGED
package/src/model.js
CHANGED
|
@@ -26,6 +26,7 @@ const COLLECTION_KEYS = [
|
|
|
26
26
|
"voices",
|
|
27
27
|
"videos",
|
|
28
28
|
"animations",
|
|
29
|
+
"audioEffects",
|
|
29
30
|
"particles",
|
|
30
31
|
"characters",
|
|
31
32
|
"fonts",
|
|
@@ -66,6 +67,7 @@ const TAG_SCOPE_BASE_KEYS = [
|
|
|
66
67
|
"layouts",
|
|
67
68
|
"controls",
|
|
68
69
|
"animations",
|
|
70
|
+
"audioEffects",
|
|
69
71
|
"particles",
|
|
70
72
|
"spritesheets",
|
|
71
73
|
];
|
|
@@ -83,6 +85,7 @@ const createEmptyTagsState = () => ({
|
|
|
83
85
|
layouts: createEmptyCollectionState(),
|
|
84
86
|
controls: createEmptyCollectionState(),
|
|
85
87
|
animations: createEmptyCollectionState(),
|
|
88
|
+
audioEffects: createEmptyCollectionState(),
|
|
86
89
|
particles: createEmptyCollectionState(),
|
|
87
90
|
spritesheets: createEmptyCollectionState(),
|
|
88
91
|
});
|
|
@@ -248,6 +251,7 @@ const normalizeStateCollections = (state) => {
|
|
|
248
251
|
"particles",
|
|
249
252
|
"controls",
|
|
250
253
|
"voices",
|
|
254
|
+
"audioEffects",
|
|
251
255
|
].filter((key) => state[key] === undefined);
|
|
252
256
|
const normalizedTags = normalizeTagsState(state.tags);
|
|
253
257
|
const hasNormalizedTags = normalizedTags !== state.tags;
|
|
@@ -340,6 +344,7 @@ const ANIMATION_EASING_KEYS = [
|
|
|
340
344
|
"easeOutElastic",
|
|
341
345
|
"easeInOutElastic",
|
|
342
346
|
];
|
|
347
|
+
const AUDIO_EFFECT_TWEEN_PROPERTY_KEYS = ["volume", "pan", "playbackRate"];
|
|
343
348
|
const VARIABLE_SCOPE_KEYS = ["context", "device", "account"];
|
|
344
349
|
const VARIABLE_TYPE_KEYS = ["string", "number", "boolean", "object"];
|
|
345
350
|
const LAYOUT_TYPE_KEYS = [
|
|
@@ -403,7 +408,7 @@ const SAVE_LOAD_DATE_FORMATS = new Set([
|
|
|
403
408
|
"DD MMM YYYY",
|
|
404
409
|
"YYYY年MM月DD日",
|
|
405
410
|
]);
|
|
406
|
-
export const SCHEMA_VERSION =
|
|
411
|
+
export const SCHEMA_VERSION = 13;
|
|
407
412
|
const LAYOUT_CONTAINER_ELEMENT_TYPES = [
|
|
408
413
|
"folder",
|
|
409
414
|
"container",
|
|
@@ -1680,7 +1685,14 @@ const validateAnimationKeyframes = ({ keyframes, path, errorFactory }) => {
|
|
|
1680
1685
|
{
|
|
1681
1686
|
const result = validateAllowedKeys({
|
|
1682
1687
|
value: keyframe,
|
|
1683
|
-
allowedKeys: [
|
|
1688
|
+
allowedKeys: [
|
|
1689
|
+
"startValue",
|
|
1690
|
+
"value",
|
|
1691
|
+
"duration",
|
|
1692
|
+
"delay",
|
|
1693
|
+
"easing",
|
|
1694
|
+
"relative",
|
|
1695
|
+
],
|
|
1684
1696
|
path: keyframePath,
|
|
1685
1697
|
errorFactory,
|
|
1686
1698
|
});
|
|
@@ -1710,6 +1722,16 @@ const validateAnimationKeyframes = ({ keyframes, path, errorFactory }) => {
|
|
|
1710
1722
|
);
|
|
1711
1723
|
}
|
|
1712
1724
|
|
|
1725
|
+
if (
|
|
1726
|
+
keyframe.startValue !== undefined &&
|
|
1727
|
+
!isFiniteNumber(keyframe.startValue)
|
|
1728
|
+
) {
|
|
1729
|
+
return invalidFromErrorFactory(
|
|
1730
|
+
errorFactory,
|
|
1731
|
+
`${keyframePath}.startValue must be a finite number when provided`,
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1713
1735
|
if (!isFiniteNumber(keyframe.duration) || keyframe.duration < 1) {
|
|
1714
1736
|
return invalidFromErrorFactory(
|
|
1715
1737
|
errorFactory,
|
|
@@ -2408,27 +2430,606 @@ const validateAnimationItems = ({ items, path, errorFactory }) => {
|
|
|
2408
2430
|
}
|
|
2409
2431
|
}
|
|
2410
2432
|
|
|
2411
|
-
{
|
|
2412
|
-
const result = validateOptionalUniqueIdArray({
|
|
2413
|
-
value: item.tagIds,
|
|
2414
|
-
path: `${itemPath}.tagIds`,
|
|
2415
|
-
errorFactory,
|
|
2416
|
-
allowEmpty: false,
|
|
2417
|
-
});
|
|
2418
|
-
if (result?.valid === false) {
|
|
2419
|
-
return result;
|
|
2420
|
-
}
|
|
2433
|
+
{
|
|
2434
|
+
const result = validateOptionalUniqueIdArray({
|
|
2435
|
+
value: item.tagIds,
|
|
2436
|
+
path: `${itemPath}.tagIds`,
|
|
2437
|
+
errorFactory,
|
|
2438
|
+
allowEmpty: false,
|
|
2439
|
+
});
|
|
2440
|
+
if (result?.valid === false) {
|
|
2441
|
+
return result;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
{
|
|
2446
|
+
const result = validateAnimationDefinition({
|
|
2447
|
+
animation: item.animation,
|
|
2448
|
+
path: `${itemPath}.animation`,
|
|
2449
|
+
errorFactory,
|
|
2450
|
+
});
|
|
2451
|
+
if (result?.valid === false) {
|
|
2452
|
+
return result;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
};
|
|
2458
|
+
|
|
2459
|
+
const validateAudioEffectEasing = ({ value, path, errorFactory }) => {
|
|
2460
|
+
if (value !== undefined && !ANIMATION_EASING_KEYS.includes(value)) {
|
|
2461
|
+
return invalidFromErrorFactory(
|
|
2462
|
+
errorFactory,
|
|
2463
|
+
`${path} must be a supported Route Graphics easing`,
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
const validateAudioEffectAbsoluteValue = ({
|
|
2469
|
+
value,
|
|
2470
|
+
property,
|
|
2471
|
+
path,
|
|
2472
|
+
errorFactory,
|
|
2473
|
+
}) => {
|
|
2474
|
+
if (property === "volume" && (value < 0 || value > 100)) {
|
|
2475
|
+
return invalidFromErrorFactory(
|
|
2476
|
+
errorFactory,
|
|
2477
|
+
`${path} must be between 0 and 100 for an absolute volume keyframe`,
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
if (property === "pan" && (value < -1 || value > 1)) {
|
|
2482
|
+
return invalidFromErrorFactory(
|
|
2483
|
+
errorFactory,
|
|
2484
|
+
`${path} must be between -1 and 1 for an absolute pan keyframe`,
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
if (property === "playbackRate" && value < 0) {
|
|
2489
|
+
return invalidFromErrorFactory(
|
|
2490
|
+
errorFactory,
|
|
2491
|
+
`${path} must be greater than or equal to 0 for an absolute playbackRate keyframe`,
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
|
|
2496
|
+
const validateAudioEffectKeyframes = ({
|
|
2497
|
+
keyframes,
|
|
2498
|
+
property,
|
|
2499
|
+
path,
|
|
2500
|
+
errorFactory,
|
|
2501
|
+
}) => {
|
|
2502
|
+
if (!Array.isArray(keyframes) || keyframes.length === 0) {
|
|
2503
|
+
return invalidFromErrorFactory(
|
|
2504
|
+
errorFactory,
|
|
2505
|
+
`${path} must be a non-empty array`,
|
|
2506
|
+
);
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
for (const [index, keyframe] of keyframes.entries()) {
|
|
2510
|
+
const keyframePath = `${path}[${index}]`;
|
|
2511
|
+
|
|
2512
|
+
{
|
|
2513
|
+
const result = validateAllowedKeys({
|
|
2514
|
+
value: keyframe,
|
|
2515
|
+
allowedKeys: [
|
|
2516
|
+
"startValue",
|
|
2517
|
+
"value",
|
|
2518
|
+
"duration",
|
|
2519
|
+
"delay",
|
|
2520
|
+
"easing",
|
|
2521
|
+
"relative",
|
|
2522
|
+
],
|
|
2523
|
+
path: keyframePath,
|
|
2524
|
+
errorFactory,
|
|
2525
|
+
});
|
|
2526
|
+
if (result?.valid === false) {
|
|
2527
|
+
return result;
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
if (!Object.hasOwn(keyframe, "value")) {
|
|
2532
|
+
return invalidFromErrorFactory(
|
|
2533
|
+
errorFactory,
|
|
2534
|
+
`${keyframePath}.value is required`,
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
if (!Object.hasOwn(keyframe, "duration")) {
|
|
2539
|
+
return invalidFromErrorFactory(
|
|
2540
|
+
errorFactory,
|
|
2541
|
+
`${keyframePath}.duration is required`,
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
if (!isFiniteNumber(keyframe.value)) {
|
|
2546
|
+
return invalidFromErrorFactory(
|
|
2547
|
+
errorFactory,
|
|
2548
|
+
`${keyframePath}.value must be a finite number`,
|
|
2549
|
+
);
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
if (!isFiniteNumber(keyframe.duration) || keyframe.duration < 0) {
|
|
2553
|
+
return invalidFromErrorFactory(
|
|
2554
|
+
errorFactory,
|
|
2555
|
+
`${keyframePath}.duration must be a finite number >= 0`,
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
if (
|
|
2560
|
+
keyframe.delay !== undefined &&
|
|
2561
|
+
(!isFiniteNumber(keyframe.delay) || keyframe.delay < 0)
|
|
2562
|
+
) {
|
|
2563
|
+
return invalidFromErrorFactory(
|
|
2564
|
+
errorFactory,
|
|
2565
|
+
`${keyframePath}.delay must be a finite number >= 0 when provided`,
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
if (
|
|
2570
|
+
keyframe.startValue !== undefined &&
|
|
2571
|
+
!isFiniteNumber(keyframe.startValue)
|
|
2572
|
+
) {
|
|
2573
|
+
return invalidFromErrorFactory(
|
|
2574
|
+
errorFactory,
|
|
2575
|
+
`${keyframePath}.startValue must be a finite number when provided`,
|
|
2576
|
+
);
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
if (
|
|
2580
|
+
keyframe.relative !== undefined &&
|
|
2581
|
+
typeof keyframe.relative !== "boolean"
|
|
2582
|
+
) {
|
|
2583
|
+
return invalidFromErrorFactory(
|
|
2584
|
+
errorFactory,
|
|
2585
|
+
`${keyframePath}.relative must be a boolean when provided`,
|
|
2586
|
+
);
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
{
|
|
2590
|
+
const result = validateAudioEffectEasing({
|
|
2591
|
+
value: keyframe.easing,
|
|
2592
|
+
path: `${keyframePath}.easing`,
|
|
2593
|
+
errorFactory,
|
|
2594
|
+
});
|
|
2595
|
+
if (result?.valid === false) {
|
|
2596
|
+
return result;
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
if (keyframe.relative !== true) {
|
|
2601
|
+
const result = validateAudioEffectAbsoluteValue({
|
|
2602
|
+
value: keyframe.value,
|
|
2603
|
+
property,
|
|
2604
|
+
path: `${keyframePath}.value`,
|
|
2605
|
+
errorFactory,
|
|
2606
|
+
});
|
|
2607
|
+
if (result?.valid === false) {
|
|
2608
|
+
return result;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
if (keyframe.startValue !== undefined) {
|
|
2612
|
+
const result = validateAudioEffectAbsoluteValue({
|
|
2613
|
+
value: keyframe.startValue,
|
|
2614
|
+
property,
|
|
2615
|
+
path: `${keyframePath}.startValue`,
|
|
2616
|
+
errorFactory,
|
|
2617
|
+
});
|
|
2618
|
+
if (result?.valid === false) {
|
|
2619
|
+
return result;
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
const finalKeyframe = keyframes.at(-1);
|
|
2626
|
+
if (finalKeyframe.relative === true) {
|
|
2627
|
+
return invalidFromErrorFactory(
|
|
2628
|
+
errorFactory,
|
|
2629
|
+
`${path} final keyframe must use an absolute numeric value`,
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
};
|
|
2633
|
+
|
|
2634
|
+
const validateAudioEffectTween = ({ tween, path, errorFactory }) => {
|
|
2635
|
+
if (!isPlainObject(tween)) {
|
|
2636
|
+
return invalidFromErrorFactory(errorFactory, `${path} must be an object`);
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
if (Object.keys(tween).length === 0) {
|
|
2640
|
+
return invalidFromErrorFactory(
|
|
2641
|
+
errorFactory,
|
|
2642
|
+
`${path} must contain at least one tween property`,
|
|
2643
|
+
);
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
for (const [property, config] of Object.entries(tween)) {
|
|
2647
|
+
if (!AUDIO_EFFECT_TWEEN_PROPERTY_KEYS.includes(property)) {
|
|
2648
|
+
return invalidFromErrorFactory(
|
|
2649
|
+
errorFactory,
|
|
2650
|
+
`${path}.${property} is not a supported audio effect tween property`,
|
|
2651
|
+
);
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
{
|
|
2655
|
+
const result = validateExactKeys({
|
|
2656
|
+
value: config,
|
|
2657
|
+
expectedKeys: ["keyframes"],
|
|
2658
|
+
path: `${path}.${property}`,
|
|
2659
|
+
errorFactory,
|
|
2660
|
+
});
|
|
2661
|
+
if (result?.valid === false) {
|
|
2662
|
+
return result;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
{
|
|
2667
|
+
const result = validateAudioEffectKeyframes({
|
|
2668
|
+
keyframes: config.keyframes,
|
|
2669
|
+
property,
|
|
2670
|
+
path: `${path}.${property}.keyframes`,
|
|
2671
|
+
errorFactory,
|
|
2672
|
+
});
|
|
2673
|
+
if (result?.valid === false) {
|
|
2674
|
+
return result;
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
};
|
|
2679
|
+
|
|
2680
|
+
const validateAudioEffectFade = ({ fade, path, side, errorFactory }) => {
|
|
2681
|
+
if (!isPlainObject(fade)) {
|
|
2682
|
+
return invalidFromErrorFactory(errorFactory, `${path} must be an object`);
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
if (Object.hasOwn(fade, "keyframes")) {
|
|
2686
|
+
{
|
|
2687
|
+
const result = validateExactKeys({
|
|
2688
|
+
value: fade,
|
|
2689
|
+
expectedKeys: ["keyframes"],
|
|
2690
|
+
path,
|
|
2691
|
+
errorFactory,
|
|
2692
|
+
});
|
|
2693
|
+
if (result?.valid === false) {
|
|
2694
|
+
return result;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
{
|
|
2699
|
+
const result = validateAudioEffectKeyframes({
|
|
2700
|
+
keyframes: fade.keyframes,
|
|
2701
|
+
property: "volume",
|
|
2702
|
+
path: `${path}.keyframes`,
|
|
2703
|
+
errorFactory,
|
|
2704
|
+
});
|
|
2705
|
+
if (result?.valid === false) {
|
|
2706
|
+
return result;
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
for (const [index, keyframe] of fade.keyframes.entries()) {
|
|
2711
|
+
if (keyframe.relative === true) {
|
|
2712
|
+
return invalidFromErrorFactory(
|
|
2713
|
+
errorFactory,
|
|
2714
|
+
`${path}.keyframes[${index}].relative is not supported for transition fades`,
|
|
2715
|
+
);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
{
|
|
2723
|
+
const result = validateAllowedKeys({
|
|
2724
|
+
value: fade,
|
|
2725
|
+
allowedKeys: ["delay", "duration", "easing"],
|
|
2726
|
+
path,
|
|
2727
|
+
errorFactory,
|
|
2728
|
+
});
|
|
2729
|
+
if (result?.valid === false) {
|
|
2730
|
+
return result;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
if (!Object.hasOwn(fade, "duration")) {
|
|
2735
|
+
return invalidFromErrorFactory(
|
|
2736
|
+
errorFactory,
|
|
2737
|
+
`${path}.duration is required`,
|
|
2738
|
+
);
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
if (!isFiniteNumber(fade.duration) || fade.duration < 0) {
|
|
2742
|
+
return invalidFromErrorFactory(
|
|
2743
|
+
errorFactory,
|
|
2744
|
+
`${path}.duration must be a finite number >= 0`,
|
|
2745
|
+
);
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
if (
|
|
2749
|
+
fade.delay !== undefined &&
|
|
2750
|
+
(!isFiniteNumber(fade.delay) || fade.delay < 0)
|
|
2751
|
+
) {
|
|
2752
|
+
return invalidFromErrorFactory(
|
|
2753
|
+
errorFactory,
|
|
2754
|
+
`${path}.delay must be a finite number >= 0 when provided`,
|
|
2755
|
+
);
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2758
|
+
return validateAudioEffectEasing({
|
|
2759
|
+
value: fade.easing,
|
|
2760
|
+
path: `${path}.easing`,
|
|
2761
|
+
errorFactory,
|
|
2762
|
+
});
|
|
2763
|
+
};
|
|
2764
|
+
|
|
2765
|
+
const validateAudioEffectTransitionSide = ({
|
|
2766
|
+
side,
|
|
2767
|
+
sideName,
|
|
2768
|
+
path,
|
|
2769
|
+
errorFactory,
|
|
2770
|
+
}) => {
|
|
2771
|
+
{
|
|
2772
|
+
const result = validateExactKeys({
|
|
2773
|
+
value: side,
|
|
2774
|
+
expectedKeys: ["fade"],
|
|
2775
|
+
path,
|
|
2776
|
+
errorFactory,
|
|
2777
|
+
});
|
|
2778
|
+
if (result?.valid === false) {
|
|
2779
|
+
return result;
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
return validateAudioEffectFade({
|
|
2784
|
+
fade: side.fade,
|
|
2785
|
+
path: `${path}.fade`,
|
|
2786
|
+
side: sideName,
|
|
2787
|
+
errorFactory,
|
|
2788
|
+
});
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2791
|
+
const validateAudioEffectDefinition = ({ audioEffect, path, errorFactory }) => {
|
|
2792
|
+
{
|
|
2793
|
+
const result = validateAllowedKeys({
|
|
2794
|
+
value: audioEffect,
|
|
2795
|
+
allowedKeys: ["type", "tween", "prev", "next"],
|
|
2796
|
+
path,
|
|
2797
|
+
errorFactory,
|
|
2798
|
+
});
|
|
2799
|
+
if (result?.valid === false) {
|
|
2800
|
+
return result;
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
if (audioEffect.type !== "update" && audioEffect.type !== "transition") {
|
|
2805
|
+
return invalidFromErrorFactory(
|
|
2806
|
+
errorFactory,
|
|
2807
|
+
`${path}.type must be 'update' or 'transition'`,
|
|
2808
|
+
);
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
if (audioEffect.type === "update") {
|
|
2812
|
+
if (audioEffect.prev !== undefined || audioEffect.next !== undefined) {
|
|
2813
|
+
return invalidFromErrorFactory(
|
|
2814
|
+
errorFactory,
|
|
2815
|
+
`${path}.update audio effects cannot define prev or next`,
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
if (audioEffect.tween === undefined) {
|
|
2820
|
+
return invalidFromErrorFactory(
|
|
2821
|
+
errorFactory,
|
|
2822
|
+
`${path}.tween is required when ${path}.type is 'update'`,
|
|
2823
|
+
);
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
return validateAudioEffectTween({
|
|
2827
|
+
tween: audioEffect.tween,
|
|
2828
|
+
path: `${path}.tween`,
|
|
2829
|
+
errorFactory,
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
if (audioEffect.tween !== undefined) {
|
|
2834
|
+
return invalidFromErrorFactory(
|
|
2835
|
+
errorFactory,
|
|
2836
|
+
`${path}.transition audio effects cannot define tween`,
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
if (audioEffect.prev === undefined && audioEffect.next === undefined) {
|
|
2841
|
+
return invalidFromErrorFactory(
|
|
2842
|
+
errorFactory,
|
|
2843
|
+
`${path}.prev or ${path}.next is required when ${path}.type is 'transition'`,
|
|
2844
|
+
);
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
for (const side of ["prev", "next"]) {
|
|
2848
|
+
if (audioEffect[side] === undefined) {
|
|
2849
|
+
continue;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
const result = validateAudioEffectTransitionSide({
|
|
2853
|
+
side: audioEffect[side],
|
|
2854
|
+
sideName: side,
|
|
2855
|
+
path: `${path}.${side}`,
|
|
2856
|
+
errorFactory,
|
|
2857
|
+
});
|
|
2858
|
+
if (result?.valid === false) {
|
|
2859
|
+
return result;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
};
|
|
2863
|
+
|
|
2864
|
+
const validateAudioEffectPreviewSlot = ({ value, path, errorFactory }) => {
|
|
2865
|
+
if (value === undefined) {
|
|
2866
|
+
return VALID_RESULT;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
if (!isPlainObject(value)) {
|
|
2870
|
+
return invalidFromErrorFactory(
|
|
2871
|
+
errorFactory,
|
|
2872
|
+
`${path} must be an object when provided`,
|
|
2873
|
+
);
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
{
|
|
2877
|
+
const result = validateAllowedKeys({
|
|
2878
|
+
value,
|
|
2879
|
+
allowedKeys: ["soundId"],
|
|
2880
|
+
path,
|
|
2881
|
+
errorFactory,
|
|
2882
|
+
});
|
|
2883
|
+
if (result?.valid === false) {
|
|
2884
|
+
return result;
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
if (value.soundId !== undefined && !isNonEmptyString(value.soundId)) {
|
|
2889
|
+
return invalidFromErrorFactory(
|
|
2890
|
+
errorFactory,
|
|
2891
|
+
`${path}.soundId must be a non-empty string when provided`,
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
return VALID_RESULT;
|
|
2896
|
+
};
|
|
2897
|
+
|
|
2898
|
+
const validateAudioEffectPreviewObject = ({ value, path, errorFactory }) => {
|
|
2899
|
+
if (value === undefined) {
|
|
2900
|
+
return VALID_RESULT;
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
if (!isPlainObject(value)) {
|
|
2904
|
+
return invalidFromErrorFactory(
|
|
2905
|
+
errorFactory,
|
|
2906
|
+
`${path} must be an object when provided`,
|
|
2907
|
+
);
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2910
|
+
{
|
|
2911
|
+
const result = validateAllowedKeys({
|
|
2912
|
+
value,
|
|
2913
|
+
allowedKeys: ["target", "outgoing", "incoming"],
|
|
2914
|
+
path,
|
|
2915
|
+
errorFactory,
|
|
2916
|
+
});
|
|
2917
|
+
if (result?.valid === false) {
|
|
2918
|
+
return result;
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
for (const key of ["target", "outgoing", "incoming"]) {
|
|
2923
|
+
const result = validateAudioEffectPreviewSlot({
|
|
2924
|
+
value: value[key],
|
|
2925
|
+
path: `${path}.${key}`,
|
|
2926
|
+
errorFactory,
|
|
2927
|
+
});
|
|
2928
|
+
if (result?.valid === false) {
|
|
2929
|
+
return result;
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
return VALID_RESULT;
|
|
2934
|
+
};
|
|
2935
|
+
|
|
2936
|
+
const validateAudioEffectItems = ({ items, path, errorFactory }) => {
|
|
2937
|
+
for (const [itemId, item] of Object.entries(items)) {
|
|
2938
|
+
const itemPath = `${path}.${itemId}`;
|
|
2939
|
+
|
|
2940
|
+
if (item?.type !== "folder" && item?.type !== "audioEffect") {
|
|
2941
|
+
return invalidFromErrorFactory(
|
|
2942
|
+
errorFactory,
|
|
2943
|
+
`${itemPath}.type must be 'folder' or 'audioEffect'`,
|
|
2944
|
+
);
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
{
|
|
2948
|
+
const result = validateAllowedKeys({
|
|
2949
|
+
value: item,
|
|
2950
|
+
allowedKeys:
|
|
2951
|
+
item.type === "folder"
|
|
2952
|
+
? ["id", "type", "name", "description"]
|
|
2953
|
+
: [
|
|
2954
|
+
"id",
|
|
2955
|
+
"type",
|
|
2956
|
+
"name",
|
|
2957
|
+
"description",
|
|
2958
|
+
"tagIds",
|
|
2959
|
+
"preview",
|
|
2960
|
+
"audioEffect",
|
|
2961
|
+
],
|
|
2962
|
+
path: itemPath,
|
|
2963
|
+
errorFactory,
|
|
2964
|
+
});
|
|
2965
|
+
if (result?.valid === false) {
|
|
2966
|
+
return result;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
if (!isNonEmptyString(item.id)) {
|
|
2971
|
+
return invalidFromErrorFactory(
|
|
2972
|
+
errorFactory,
|
|
2973
|
+
`${itemPath}.id must be a non-empty string`,
|
|
2974
|
+
);
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
if (item.id !== itemId) {
|
|
2978
|
+
return invalidFromErrorFactory(
|
|
2979
|
+
errorFactory,
|
|
2980
|
+
`${itemPath}.id must match item key '${itemId}'`,
|
|
2981
|
+
);
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
if (!isNonEmptyString(item.name)) {
|
|
2985
|
+
return invalidFromErrorFactory(
|
|
2986
|
+
errorFactory,
|
|
2987
|
+
`${itemPath}.name must be a non-empty string`,
|
|
2988
|
+
);
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
if (item.description !== undefined && !isString(item.description)) {
|
|
2992
|
+
return invalidFromErrorFactory(
|
|
2993
|
+
errorFactory,
|
|
2994
|
+
`${itemPath}.description must be a string when provided`,
|
|
2995
|
+
);
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
if (item.type !== "audioEffect") {
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
{
|
|
3003
|
+
const result = validateAudioEffectPreviewObject({
|
|
3004
|
+
value: item.preview,
|
|
3005
|
+
path: `${itemPath}.preview`,
|
|
3006
|
+
errorFactory,
|
|
3007
|
+
});
|
|
3008
|
+
if (result?.valid === false) {
|
|
3009
|
+
return result;
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
{
|
|
3014
|
+
const result = validateOptionalUniqueIdArray({
|
|
3015
|
+
value: item.tagIds,
|
|
3016
|
+
path: `${itemPath}.tagIds`,
|
|
3017
|
+
errorFactory,
|
|
3018
|
+
allowEmpty: false,
|
|
3019
|
+
});
|
|
3020
|
+
if (result?.valid === false) {
|
|
3021
|
+
return result;
|
|
2421
3022
|
}
|
|
3023
|
+
}
|
|
2422
3024
|
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
}
|
|
3025
|
+
{
|
|
3026
|
+
const result = validateAudioEffectDefinition({
|
|
3027
|
+
audioEffect: item.audioEffect,
|
|
3028
|
+
path: `${itemPath}.audioEffect`,
|
|
3029
|
+
errorFactory,
|
|
3030
|
+
});
|
|
3031
|
+
if (result?.valid === false) {
|
|
3032
|
+
return result;
|
|
2432
3033
|
}
|
|
2433
3034
|
}
|
|
2434
3035
|
}
|
|
@@ -6855,6 +7456,15 @@ const stripDeletedTagIdsFromScopeItems = ({
|
|
|
6855
7456
|
return;
|
|
6856
7457
|
}
|
|
6857
7458
|
|
|
7459
|
+
if (scopeKey === "audioEffects") {
|
|
7460
|
+
for (const item of Object.values(state.audioEffects.items)) {
|
|
7461
|
+
if (item?.type === "audioEffect") {
|
|
7462
|
+
stripDeletedTagIdsFromItem({ item, deletedTagIds });
|
|
7463
|
+
}
|
|
7464
|
+
}
|
|
7465
|
+
return;
|
|
7466
|
+
}
|
|
7467
|
+
|
|
6858
7468
|
if (scopeKey === "particles") {
|
|
6859
7469
|
for (const item of Object.values(state.particles.items)) {
|
|
6860
7470
|
if (item?.type === "particle") {
|
|
@@ -7955,6 +8565,17 @@ const validateCollection = ({ collection, path }) => {
|
|
|
7955
8565
|
return result;
|
|
7956
8566
|
}
|
|
7957
8567
|
}
|
|
8568
|
+
} else if (path === "state.audioEffects") {
|
|
8569
|
+
{
|
|
8570
|
+
const result = validateAudioEffectItems({
|
|
8571
|
+
items: collection.items,
|
|
8572
|
+
path: `${path}.items`,
|
|
8573
|
+
errorFactory: createStateValidationError,
|
|
8574
|
+
});
|
|
8575
|
+
if (result?.valid === false) {
|
|
8576
|
+
return result;
|
|
8577
|
+
}
|
|
8578
|
+
}
|
|
7958
8579
|
} else if (path === "state.fonts") {
|
|
7959
8580
|
{
|
|
7960
8581
|
const result = validateFontItems({
|
|
@@ -8176,6 +8797,7 @@ const validateCollection = ({ collection, path }) => {
|
|
|
8176
8797
|
}
|
|
8177
8798
|
} else if (
|
|
8178
8799
|
path === "state.files" ||
|
|
8800
|
+
path === "state.audioEffects" ||
|
|
8179
8801
|
path === "state.particles" ||
|
|
8180
8802
|
path === "state.transforms" ||
|
|
8181
8803
|
path === "state.variables" ||
|
|
@@ -8190,11 +8812,13 @@ const validateCollection = ({ collection, path }) => {
|
|
|
8190
8812
|
items: collection.items,
|
|
8191
8813
|
path: `${path}.tree`,
|
|
8192
8814
|
folderLabel:
|
|
8193
|
-
path === "state.
|
|
8194
|
-
? "folder
|
|
8195
|
-
: path === "state.
|
|
8196
|
-
? "folder
|
|
8197
|
-
:
|
|
8815
|
+
path === "state.audioEffects"
|
|
8816
|
+
? "folder audio effect item"
|
|
8817
|
+
: path === "state.layouts"
|
|
8818
|
+
? "folder layout item"
|
|
8819
|
+
: path === "state.controls"
|
|
8820
|
+
? "folder control item"
|
|
8821
|
+
: "folder item",
|
|
8198
8822
|
});
|
|
8199
8823
|
if (result?.valid === false) {
|
|
8200
8824
|
return result;
|
|
@@ -8860,6 +9484,28 @@ export const assertInvariants = ({ state }) => {
|
|
|
8860
9484
|
}
|
|
8861
9485
|
}
|
|
8862
9486
|
|
|
9487
|
+
for (const [audioEffectId, audioEffect] of Object.entries(
|
|
9488
|
+
state.audioEffects.items,
|
|
9489
|
+
)) {
|
|
9490
|
+
if (audioEffect.type !== "audioEffect") {
|
|
9491
|
+
continue;
|
|
9492
|
+
}
|
|
9493
|
+
|
|
9494
|
+
const result = validateTagIdsAgainstScope({
|
|
9495
|
+
state,
|
|
9496
|
+
tagIds: audioEffect.tagIds,
|
|
9497
|
+
scopeKey: "audioEffects",
|
|
9498
|
+
path: "audioEffect.tagIds",
|
|
9499
|
+
details: {
|
|
9500
|
+
audioEffectId,
|
|
9501
|
+
},
|
|
9502
|
+
errorFactory: createInvariantValidationError,
|
|
9503
|
+
});
|
|
9504
|
+
if (!result.valid) {
|
|
9505
|
+
return result;
|
|
9506
|
+
}
|
|
9507
|
+
}
|
|
9508
|
+
|
|
8863
9509
|
for (const [characterId, character] of Object.entries(
|
|
8864
9510
|
state.characters.items,
|
|
8865
9511
|
)) {
|
|
@@ -11839,6 +12485,148 @@ const validateAnimationUpdateData = ({ data, errorFactory }) => {
|
|
|
11839
12485
|
}
|
|
11840
12486
|
};
|
|
11841
12487
|
|
|
12488
|
+
const validateAudioEffectCreateData = ({ data, errorFactory }) => {
|
|
12489
|
+
if (!isPlainObject(data)) {
|
|
12490
|
+
return invalidFromErrorFactory(
|
|
12491
|
+
errorFactory,
|
|
12492
|
+
"payload.data must be an object",
|
|
12493
|
+
);
|
|
12494
|
+
}
|
|
12495
|
+
|
|
12496
|
+
if (data.type !== "folder" && data.type !== "audioEffect") {
|
|
12497
|
+
return invalidFromErrorFactory(
|
|
12498
|
+
errorFactory,
|
|
12499
|
+
"payload.data.type must be 'folder' or 'audioEffect'",
|
|
12500
|
+
);
|
|
12501
|
+
}
|
|
12502
|
+
|
|
12503
|
+
{
|
|
12504
|
+
const result = validateAllowedKeys({
|
|
12505
|
+
value: data,
|
|
12506
|
+
allowedKeys:
|
|
12507
|
+
data.type === "folder"
|
|
12508
|
+
? ["type", "name", "description"]
|
|
12509
|
+
: ["type", "name", "description", "tagIds", "preview", "audioEffect"],
|
|
12510
|
+
path: "payload.data",
|
|
12511
|
+
errorFactory,
|
|
12512
|
+
});
|
|
12513
|
+
if (result?.valid === false) {
|
|
12514
|
+
return result;
|
|
12515
|
+
}
|
|
12516
|
+
}
|
|
12517
|
+
|
|
12518
|
+
if (!isNonEmptyString(data.name)) {
|
|
12519
|
+
return invalidFromErrorFactory(
|
|
12520
|
+
errorFactory,
|
|
12521
|
+
"payload.data.name must be a non-empty string",
|
|
12522
|
+
);
|
|
12523
|
+
}
|
|
12524
|
+
|
|
12525
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
12526
|
+
return invalidFromErrorFactory(
|
|
12527
|
+
errorFactory,
|
|
12528
|
+
"payload.data.description must be a string when provided",
|
|
12529
|
+
);
|
|
12530
|
+
}
|
|
12531
|
+
|
|
12532
|
+
if (data.type !== "audioEffect") {
|
|
12533
|
+
return;
|
|
12534
|
+
}
|
|
12535
|
+
|
|
12536
|
+
{
|
|
12537
|
+
const result = validateAudioEffectPreviewObject({
|
|
12538
|
+
value: data.preview,
|
|
12539
|
+
path: "payload.data.preview",
|
|
12540
|
+
errorFactory,
|
|
12541
|
+
});
|
|
12542
|
+
if (result?.valid === false) {
|
|
12543
|
+
return result;
|
|
12544
|
+
}
|
|
12545
|
+
}
|
|
12546
|
+
|
|
12547
|
+
{
|
|
12548
|
+
const result = validateOptionalUniqueIdArray({
|
|
12549
|
+
value: data.tagIds,
|
|
12550
|
+
path: "payload.data.tagIds",
|
|
12551
|
+
errorFactory,
|
|
12552
|
+
});
|
|
12553
|
+
if (result?.valid === false) {
|
|
12554
|
+
return result;
|
|
12555
|
+
}
|
|
12556
|
+
}
|
|
12557
|
+
|
|
12558
|
+
return validateAudioEffectDefinition({
|
|
12559
|
+
audioEffect: data.audioEffect,
|
|
12560
|
+
path: "payload.data.audioEffect",
|
|
12561
|
+
errorFactory,
|
|
12562
|
+
});
|
|
12563
|
+
};
|
|
12564
|
+
|
|
12565
|
+
const validateAudioEffectUpdateData = ({ data, errorFactory }) => {
|
|
12566
|
+
{
|
|
12567
|
+
const result = validateAllowedKeys({
|
|
12568
|
+
value: data,
|
|
12569
|
+
allowedKeys: ["name", "description", "tagIds", "preview", "audioEffect"],
|
|
12570
|
+
path: "payload.data",
|
|
12571
|
+
errorFactory,
|
|
12572
|
+
});
|
|
12573
|
+
if (result?.valid === false) {
|
|
12574
|
+
return result;
|
|
12575
|
+
}
|
|
12576
|
+
}
|
|
12577
|
+
|
|
12578
|
+
if (Object.keys(data).length === 0) {
|
|
12579
|
+
return invalidFromErrorFactory(
|
|
12580
|
+
errorFactory,
|
|
12581
|
+
"payload.data must include at least one updatable field",
|
|
12582
|
+
);
|
|
12583
|
+
}
|
|
12584
|
+
|
|
12585
|
+
if (Object.hasOwn(data, "name") && !isNonEmptyString(data.name)) {
|
|
12586
|
+
return invalidFromErrorFactory(
|
|
12587
|
+
errorFactory,
|
|
12588
|
+
"payload.data.name must be a non-empty string when provided",
|
|
12589
|
+
);
|
|
12590
|
+
}
|
|
12591
|
+
|
|
12592
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
12593
|
+
return invalidFromErrorFactory(
|
|
12594
|
+
errorFactory,
|
|
12595
|
+
"payload.data.description must be a string when provided",
|
|
12596
|
+
);
|
|
12597
|
+
}
|
|
12598
|
+
|
|
12599
|
+
{
|
|
12600
|
+
const result = validateAudioEffectPreviewObject({
|
|
12601
|
+
value: data.preview,
|
|
12602
|
+
path: "payload.data.preview",
|
|
12603
|
+
errorFactory,
|
|
12604
|
+
});
|
|
12605
|
+
if (result?.valid === false) {
|
|
12606
|
+
return result;
|
|
12607
|
+
}
|
|
12608
|
+
}
|
|
12609
|
+
|
|
12610
|
+
{
|
|
12611
|
+
const result = validateOptionalUniqueIdArray({
|
|
12612
|
+
value: data.tagIds,
|
|
12613
|
+
path: "payload.data.tagIds",
|
|
12614
|
+
errorFactory,
|
|
12615
|
+
});
|
|
12616
|
+
if (result?.valid === false) {
|
|
12617
|
+
return result;
|
|
12618
|
+
}
|
|
12619
|
+
}
|
|
12620
|
+
|
|
12621
|
+
if (Object.hasOwn(data, "audioEffect")) {
|
|
12622
|
+
return validateAudioEffectDefinition({
|
|
12623
|
+
audioEffect: data.audioEffect,
|
|
12624
|
+
path: "payload.data.audioEffect",
|
|
12625
|
+
errorFactory,
|
|
12626
|
+
});
|
|
12627
|
+
}
|
|
12628
|
+
};
|
|
12629
|
+
|
|
11842
12630
|
const validateTransformCreateData = ({ data, errorFactory }) => {
|
|
11843
12631
|
if (!isPlainObject(data)) {
|
|
11844
12632
|
return invalidFromErrorFactory(
|
|
@@ -18650,6 +19438,87 @@ const COMMAND_DEFINITIONS = [
|
|
|
18650
19438
|
return state;
|
|
18651
19439
|
},
|
|
18652
19440
|
},
|
|
19441
|
+
...createFolderedCollectionCommandDefinitions({
|
|
19442
|
+
familyName: "audioEffect",
|
|
19443
|
+
collectionKey: "audioEffects",
|
|
19444
|
+
idField: "audioEffectId",
|
|
19445
|
+
itemLabel: "audio effect item",
|
|
19446
|
+
createDataValidator: validateAudioEffectCreateData,
|
|
19447
|
+
updateDataValidator: validateAudioEffectUpdateData,
|
|
19448
|
+
createItem: ({ payload }) => {
|
|
19449
|
+
const item = {
|
|
19450
|
+
id: payload.audioEffectId,
|
|
19451
|
+
type: payload.data.type,
|
|
19452
|
+
name: payload.data.name,
|
|
19453
|
+
};
|
|
19454
|
+
|
|
19455
|
+
if (payload.data.description !== undefined) {
|
|
19456
|
+
item.description = payload.data.description;
|
|
19457
|
+
}
|
|
19458
|
+
|
|
19459
|
+
if (payload.data.type === "audioEffect") {
|
|
19460
|
+
assignOptionalTagIds({
|
|
19461
|
+
target: item,
|
|
19462
|
+
tagIds: payload.data.tagIds,
|
|
19463
|
+
});
|
|
19464
|
+
if (payload.data.preview !== undefined) {
|
|
19465
|
+
item.preview = structuredClone(payload.data.preview);
|
|
19466
|
+
}
|
|
19467
|
+
item.audioEffect = structuredClone(payload.data.audioEffect);
|
|
19468
|
+
}
|
|
19469
|
+
|
|
19470
|
+
return item;
|
|
19471
|
+
},
|
|
19472
|
+
updateItem: ({ currentItem, payload }) =>
|
|
19473
|
+
applyTagIdsUpdate({
|
|
19474
|
+
currentItem,
|
|
19475
|
+
data: payload.data,
|
|
19476
|
+
}),
|
|
19477
|
+
validateCreateState: ({ state, payload }) => {
|
|
19478
|
+
if (payload.data.type !== "audioEffect") {
|
|
19479
|
+
return;
|
|
19480
|
+
}
|
|
19481
|
+
|
|
19482
|
+
return validateTagIdsAgainstScope({
|
|
19483
|
+
state,
|
|
19484
|
+
tagIds: payload.data.tagIds,
|
|
19485
|
+
scopeKey: "audioEffects",
|
|
19486
|
+
path: "payload.data.tagIds",
|
|
19487
|
+
details: {
|
|
19488
|
+
audioEffectId: payload.audioEffectId,
|
|
19489
|
+
},
|
|
19490
|
+
errorFactory: createPreconditionValidationError,
|
|
19491
|
+
});
|
|
19492
|
+
},
|
|
19493
|
+
validateUpdateState: ({ state, payload, currentItem }) => {
|
|
19494
|
+
if (
|
|
19495
|
+
currentItem.type === "folder" &&
|
|
19496
|
+
Object.keys(payload.data).some(
|
|
19497
|
+
(key) => key !== "name" && key !== "description",
|
|
19498
|
+
)
|
|
19499
|
+
) {
|
|
19500
|
+
return invalidFromErrorFactory(
|
|
19501
|
+
createPreconditionValidationError,
|
|
19502
|
+
"folder audio effect items cannot update audio effect fields",
|
|
19503
|
+
);
|
|
19504
|
+
}
|
|
19505
|
+
|
|
19506
|
+
if (currentItem.type !== "audioEffect") {
|
|
19507
|
+
return;
|
|
19508
|
+
}
|
|
19509
|
+
|
|
19510
|
+
return validateTagIdsAgainstScope({
|
|
19511
|
+
state,
|
|
19512
|
+
tagIds: payload.data.tagIds,
|
|
19513
|
+
scopeKey: "audioEffects",
|
|
19514
|
+
path: "payload.data.tagIds",
|
|
19515
|
+
details: {
|
|
19516
|
+
audioEffectId: payload.audioEffectId,
|
|
19517
|
+
},
|
|
19518
|
+
errorFactory: createPreconditionValidationError,
|
|
19519
|
+
});
|
|
19520
|
+
},
|
|
19521
|
+
}),
|
|
18653
19522
|
{
|
|
18654
19523
|
type: "font.create",
|
|
18655
19524
|
validatePayload: ({ payload }) => {
|