@routevn/creator-model 1.1.12 → 1.2.2
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 +17 -0
- package/package.json +1 -1
- package/src/index.js +1 -6
- package/src/model.js +1397 -116
- package/src/runtimeFields.js +22 -0
- package/src/systemVariables.js +0 -69
package/src/model.js
CHANGED
|
@@ -15,15 +15,17 @@ import {
|
|
|
15
15
|
isPlainObject,
|
|
16
16
|
removeTreeNode,
|
|
17
17
|
} from "./helpers.js";
|
|
18
|
-
import {
|
|
18
|
+
import { isRuntimeFieldId } from "./runtimeFields.js";
|
|
19
19
|
|
|
20
20
|
const COLLECTION_KEYS = [
|
|
21
21
|
"scenes",
|
|
22
22
|
"files",
|
|
23
23
|
"images",
|
|
24
|
+
"spritesheets",
|
|
24
25
|
"sounds",
|
|
25
26
|
"videos",
|
|
26
27
|
"animations",
|
|
28
|
+
"particles",
|
|
27
29
|
"characters",
|
|
28
30
|
"fonts",
|
|
29
31
|
"transforms",
|
|
@@ -44,14 +46,25 @@ const normalizeStateCollections = (state) => {
|
|
|
44
46
|
return state;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
const missingCollectionKeys = [
|
|
50
|
+
"spritesheets",
|
|
51
|
+
"particles",
|
|
52
|
+
"controls",
|
|
53
|
+
].filter((key) => state[key] === undefined);
|
|
54
|
+
|
|
55
|
+
if (missingCollectionKeys.length === 0) {
|
|
48
56
|
return state;
|
|
49
57
|
}
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
const nextState = {
|
|
52
60
|
...state,
|
|
53
|
-
controls: createEmptyCollectionState(),
|
|
54
61
|
};
|
|
62
|
+
|
|
63
|
+
missingCollectionKeys.forEach((key) => {
|
|
64
|
+
nextState[key] = createEmptyCollectionState();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return nextState;
|
|
55
68
|
};
|
|
56
69
|
const isString = (value) => typeof value === "string";
|
|
57
70
|
const isHexColor = (value) =>
|
|
@@ -107,7 +120,7 @@ const ANIMATION_EASING_KEYS = [
|
|
|
107
120
|
"easeOutElastic",
|
|
108
121
|
"easeInOutElastic",
|
|
109
122
|
];
|
|
110
|
-
const VARIABLE_SCOPE_KEYS = ["context", "
|
|
123
|
+
const VARIABLE_SCOPE_KEYS = ["context", "device", "account"];
|
|
111
124
|
const VARIABLE_TYPE_KEYS = ["string", "number", "boolean"];
|
|
112
125
|
const LAYOUT_TYPE_KEYS = [
|
|
113
126
|
"normal",
|
|
@@ -125,6 +138,8 @@ const LAYOUT_ELEMENT_BASE_TYPES = [
|
|
|
125
138
|
"container",
|
|
126
139
|
"rect",
|
|
127
140
|
"sprite",
|
|
141
|
+
"particle",
|
|
142
|
+
"spritesheet-animation",
|
|
128
143
|
"text",
|
|
129
144
|
"text-revealing",
|
|
130
145
|
"slider",
|
|
@@ -145,7 +160,7 @@ const LAYOUT_ELEMENT_BASE_TYPES = [
|
|
|
145
160
|
"container-ref-confirm-dialog-ok",
|
|
146
161
|
"container-ref-confirm-dialog-cancel",
|
|
147
162
|
];
|
|
148
|
-
export const SCHEMA_VERSION =
|
|
163
|
+
export const SCHEMA_VERSION = 2;
|
|
149
164
|
const LAYOUT_CONTAINER_ELEMENT_TYPES = [
|
|
150
165
|
"folder",
|
|
151
166
|
"container",
|
|
@@ -244,20 +259,12 @@ const invalidInvariant = (message, details = {}) =>
|
|
|
244
259
|
});
|
|
245
260
|
|
|
246
261
|
const isVariableReferenceTarget = (state, variableId) => {
|
|
247
|
-
if (isSystemVariableId(variableId)) {
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
262
|
const variable = state.variables.items[variableId];
|
|
252
263
|
return isPlainObject(variable) && variable.type !== "folder";
|
|
253
264
|
};
|
|
254
265
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
"isLineCompleted",
|
|
258
|
-
"autoMode",
|
|
259
|
-
"skipMode",
|
|
260
|
-
]);
|
|
266
|
+
const LAYOUT_ITEM_TARGET_SET = new Set(["item.savedAt"]);
|
|
267
|
+
const RUNTIME_TARGET_DOT_PATTERN = /^runtime\.([A-Za-z_$][A-Za-z0-9_$]*)$/;
|
|
261
268
|
const VARIABLE_TARGET_DOT_PATTERN = /^variables\.([A-Za-z_$][A-Za-z0-9_$]*)$/;
|
|
262
269
|
const VARIABLE_TARGET_BRACKET_PATTERN = /^variables\[(.+)\]$/;
|
|
263
270
|
|
|
@@ -266,10 +273,19 @@ const parseLayoutConditionTarget = (target) => {
|
|
|
266
273
|
return undefined;
|
|
267
274
|
}
|
|
268
275
|
|
|
269
|
-
if (
|
|
276
|
+
if (LAYOUT_ITEM_TARGET_SET.has(target)) {
|
|
277
|
+
return {
|
|
278
|
+
kind: "item",
|
|
279
|
+
target,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const runtimeMatch = target.match(RUNTIME_TARGET_DOT_PATTERN);
|
|
284
|
+
if (runtimeMatch && isRuntimeFieldId(runtimeMatch[1])) {
|
|
270
285
|
return {
|
|
271
286
|
kind: "runtime",
|
|
272
287
|
target,
|
|
288
|
+
runtimeId: runtimeMatch[1],
|
|
273
289
|
};
|
|
274
290
|
}
|
|
275
291
|
|
|
@@ -853,6 +869,207 @@ const validateImageItems = ({ items, path, errorFactory }) => {
|
|
|
853
869
|
}
|
|
854
870
|
};
|
|
855
871
|
|
|
872
|
+
const validateSpritesheetAnimationMap = ({
|
|
873
|
+
animations,
|
|
874
|
+
path,
|
|
875
|
+
errorFactory,
|
|
876
|
+
}) => {
|
|
877
|
+
if (!isPlainObject(animations)) {
|
|
878
|
+
return invalidFromErrorFactory(errorFactory, `${path} must be an object`);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
for (const [animationName, animation] of Object.entries(animations)) {
|
|
882
|
+
const animationPath = `${path}.${animationName}`;
|
|
883
|
+
|
|
884
|
+
if (!isNonEmptyString(animationName)) {
|
|
885
|
+
return invalidFromErrorFactory(
|
|
886
|
+
errorFactory,
|
|
887
|
+
`${animationPath} must use a non-empty animation name`,
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
{
|
|
892
|
+
const result = validateAllowedKeys({
|
|
893
|
+
value: animation,
|
|
894
|
+
allowedKeys: ["frames", "animationSpeed", "loop"],
|
|
895
|
+
path: animationPath,
|
|
896
|
+
errorFactory,
|
|
897
|
+
});
|
|
898
|
+
if (result?.valid === false) {
|
|
899
|
+
return result;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (!Array.isArray(animation.frames)) {
|
|
904
|
+
return invalidFromErrorFactory(
|
|
905
|
+
errorFactory,
|
|
906
|
+
`${animationPath}.frames must be an array`,
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
for (let index = 0; index < animation.frames.length; index += 1) {
|
|
911
|
+
const frame = animation.frames[index];
|
|
912
|
+
if (!Number.isInteger(frame) || frame < 0) {
|
|
913
|
+
return invalidFromErrorFactory(
|
|
914
|
+
errorFactory,
|
|
915
|
+
`${animationPath}.frames.${index} must be an integer greater than or equal to 0`,
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (
|
|
921
|
+
animation.animationSpeed !== undefined &&
|
|
922
|
+
!isFiniteNumber(animation.animationSpeed)
|
|
923
|
+
) {
|
|
924
|
+
return invalidFromErrorFactory(
|
|
925
|
+
errorFactory,
|
|
926
|
+
`${animationPath}.animationSpeed must be a finite number when provided`,
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
if (animation.loop !== undefined && typeof animation.loop !== "boolean") {
|
|
931
|
+
return invalidFromErrorFactory(
|
|
932
|
+
errorFactory,
|
|
933
|
+
`${animationPath}.loop must be a boolean when provided`,
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
return VALID_RESULT;
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
const validateSpritesheetItems = ({ items, path, errorFactory }) => {
|
|
942
|
+
for (const [itemId, item] of Object.entries(items)) {
|
|
943
|
+
const itemPath = `${path}.${itemId}`;
|
|
944
|
+
|
|
945
|
+
if (item?.type !== "folder" && item?.type !== "spritesheet") {
|
|
946
|
+
return invalidFromErrorFactory(
|
|
947
|
+
errorFactory,
|
|
948
|
+
`${itemPath}.type must be 'folder' or 'spritesheet'`,
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
{
|
|
953
|
+
const result = validateAllowedKeys({
|
|
954
|
+
value: item,
|
|
955
|
+
allowedKeys:
|
|
956
|
+
item.type === "folder"
|
|
957
|
+
? ["id", "type", "name", "description"]
|
|
958
|
+
: [
|
|
959
|
+
"id",
|
|
960
|
+
"type",
|
|
961
|
+
"name",
|
|
962
|
+
"description",
|
|
963
|
+
"thumbnailFileId",
|
|
964
|
+
"fileId",
|
|
965
|
+
"fileType",
|
|
966
|
+
"fileSize",
|
|
967
|
+
"sheetWidth",
|
|
968
|
+
"sheetHeight",
|
|
969
|
+
"frameCount",
|
|
970
|
+
"width",
|
|
971
|
+
"height",
|
|
972
|
+
"jsonData",
|
|
973
|
+
"animations",
|
|
974
|
+
],
|
|
975
|
+
path: itemPath,
|
|
976
|
+
errorFactory,
|
|
977
|
+
});
|
|
978
|
+
if (result?.valid === false) {
|
|
979
|
+
return result;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (!isNonEmptyString(item.id)) {
|
|
984
|
+
return invalidFromErrorFactory(
|
|
985
|
+
errorFactory,
|
|
986
|
+
`${itemPath}.id must be a non-empty string`,
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (item.id !== itemId) {
|
|
991
|
+
return invalidFromErrorFactory(
|
|
992
|
+
errorFactory,
|
|
993
|
+
`${itemPath}.id must match item key '${itemId}'`,
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
if (!isNonEmptyString(item.name)) {
|
|
998
|
+
return invalidFromErrorFactory(
|
|
999
|
+
errorFactory,
|
|
1000
|
+
`${itemPath}.name must be a non-empty string`,
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
if (item.description !== undefined && !isString(item.description)) {
|
|
1005
|
+
return invalidFromErrorFactory(
|
|
1006
|
+
errorFactory,
|
|
1007
|
+
`${itemPath}.description must be a string when provided`,
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
if (item.type === "spritesheet") {
|
|
1012
|
+
if (
|
|
1013
|
+
item.thumbnailFileId !== undefined &&
|
|
1014
|
+
!isNonEmptyString(item.thumbnailFileId)
|
|
1015
|
+
) {
|
|
1016
|
+
return invalidFromErrorFactory(
|
|
1017
|
+
errorFactory,
|
|
1018
|
+
`${itemPath}.thumbnailFileId must be a non-empty string when provided`,
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
if (!isNonEmptyString(item.fileId)) {
|
|
1023
|
+
return invalidFromErrorFactory(
|
|
1024
|
+
errorFactory,
|
|
1025
|
+
`${itemPath}.fileId must be a non-empty string`,
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (item.fileType !== undefined && !isString(item.fileType)) {
|
|
1030
|
+
return invalidFromErrorFactory(
|
|
1031
|
+
errorFactory,
|
|
1032
|
+
`${itemPath}.fileType must be a string when provided`,
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
for (const key of [
|
|
1037
|
+
"fileSize",
|
|
1038
|
+
"sheetWidth",
|
|
1039
|
+
"sheetHeight",
|
|
1040
|
+
"frameCount",
|
|
1041
|
+
"width",
|
|
1042
|
+
"height",
|
|
1043
|
+
]) {
|
|
1044
|
+
if (item[key] !== undefined && !isFiniteNumber(item[key])) {
|
|
1045
|
+
return invalidFromErrorFactory(
|
|
1046
|
+
errorFactory,
|
|
1047
|
+
`${itemPath}.${key} must be a finite number when provided`,
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
if (!isPlainObject(item.jsonData)) {
|
|
1053
|
+
return invalidFromErrorFactory(
|
|
1054
|
+
errorFactory,
|
|
1055
|
+
`${itemPath}.jsonData must be an object`,
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
{
|
|
1060
|
+
const result = validateSpritesheetAnimationMap({
|
|
1061
|
+
animations: item.animations,
|
|
1062
|
+
path: `${itemPath}.animations`,
|
|
1063
|
+
errorFactory,
|
|
1064
|
+
});
|
|
1065
|
+
if (result?.valid === false) {
|
|
1066
|
+
return result;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
|
|
856
1073
|
const validateSoundItems = ({ items, path, errorFactory }) => {
|
|
857
1074
|
for (const [itemId, item] of Object.entries(items)) {
|
|
858
1075
|
const itemPath = `${path}.${itemId}`;
|
|
@@ -1141,16 +1358,57 @@ const validateAnimationKeyframes = ({ keyframes, path, errorFactory }) => {
|
|
|
1141
1358
|
}
|
|
1142
1359
|
};
|
|
1143
1360
|
|
|
1361
|
+
const validateAutoTweenProperty = ({ auto, path, errorFactory }) => {
|
|
1362
|
+
{
|
|
1363
|
+
const result = validateAllowedKeys({
|
|
1364
|
+
value: auto,
|
|
1365
|
+
allowedKeys: ["duration", "easing"],
|
|
1366
|
+
path,
|
|
1367
|
+
errorFactory,
|
|
1368
|
+
});
|
|
1369
|
+
if (result?.valid === false) {
|
|
1370
|
+
return result;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
if (!("duration" in auto)) {
|
|
1375
|
+
return invalidFromErrorFactory(
|
|
1376
|
+
errorFactory,
|
|
1377
|
+
`${path}.duration is required`,
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if (!isFiniteNumber(auto.duration) || auto.duration < 1) {
|
|
1382
|
+
return invalidFromErrorFactory(
|
|
1383
|
+
errorFactory,
|
|
1384
|
+
`${path}.duration must be a finite number >= 1`,
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
if (
|
|
1389
|
+
auto.easing !== undefined &&
|
|
1390
|
+
!ANIMATION_EASING_KEYS.includes(auto.easing)
|
|
1391
|
+
) {
|
|
1392
|
+
return invalidFromErrorFactory(
|
|
1393
|
+
errorFactory,
|
|
1394
|
+
`${path}.easing must be a supported Route Graphics easing`,
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1144
1399
|
const validateTweenProperty = ({
|
|
1145
1400
|
config,
|
|
1146
1401
|
path,
|
|
1147
1402
|
allowEmptyKeyframes = false,
|
|
1403
|
+
allowAuto = false,
|
|
1148
1404
|
errorFactory,
|
|
1149
1405
|
}) => {
|
|
1150
1406
|
{
|
|
1151
1407
|
const result = validateAllowedKeys({
|
|
1152
1408
|
value: config,
|
|
1153
|
-
allowedKeys:
|
|
1409
|
+
allowedKeys: allowAuto
|
|
1410
|
+
? ["initialValue", "keyframes", "auto"]
|
|
1411
|
+
: ["initialValue", "keyframes"],
|
|
1154
1412
|
path,
|
|
1155
1413
|
errorFactory,
|
|
1156
1414
|
});
|
|
@@ -1159,10 +1417,20 @@ const validateTweenProperty = ({
|
|
|
1159
1417
|
}
|
|
1160
1418
|
}
|
|
1161
1419
|
|
|
1162
|
-
|
|
1420
|
+
const hasKeyframes = "keyframes" in config;
|
|
1421
|
+
const hasAuto = "auto" in config;
|
|
1422
|
+
|
|
1423
|
+
if (!hasKeyframes && !hasAuto) {
|
|
1424
|
+
return invalidFromErrorFactory(
|
|
1425
|
+
errorFactory,
|
|
1426
|
+
`${path}.keyframes or ${path}.auto is required`,
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
if (hasKeyframes && hasAuto) {
|
|
1163
1431
|
return invalidFromErrorFactory(
|
|
1164
1432
|
errorFactory,
|
|
1165
|
-
`${path}.keyframes
|
|
1433
|
+
`${path}.keyframes and ${path}.auto cannot both be defined`,
|
|
1166
1434
|
);
|
|
1167
1435
|
}
|
|
1168
1436
|
|
|
@@ -1176,6 +1444,28 @@ const validateTweenProperty = ({
|
|
|
1176
1444
|
);
|
|
1177
1445
|
}
|
|
1178
1446
|
|
|
1447
|
+
if (hasAuto) {
|
|
1448
|
+
if (config.initialValue !== undefined) {
|
|
1449
|
+
return invalidFromErrorFactory(
|
|
1450
|
+
errorFactory,
|
|
1451
|
+
`${path}.initialValue is not supported when ${path}.auto is defined`,
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
{
|
|
1456
|
+
const result = validateAutoTweenProperty({
|
|
1457
|
+
auto: config.auto,
|
|
1458
|
+
path: `${path}.auto`,
|
|
1459
|
+
errorFactory,
|
|
1460
|
+
});
|
|
1461
|
+
if (result?.valid === false) {
|
|
1462
|
+
return result;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1179
1469
|
{
|
|
1180
1470
|
const result = validateAnimationKeyframes({
|
|
1181
1471
|
keyframes: config.keyframes,
|
|
@@ -1201,6 +1491,7 @@ const validateTweenDefinition = ({
|
|
|
1201
1491
|
path,
|
|
1202
1492
|
unsupportedMessage,
|
|
1203
1493
|
allowEmptyKeyframes = false,
|
|
1494
|
+
allowAuto = false,
|
|
1204
1495
|
errorFactory,
|
|
1205
1496
|
}) => {
|
|
1206
1497
|
if (!isPlainObject(tween)) {
|
|
@@ -1229,6 +1520,7 @@ const validateTweenDefinition = ({
|
|
|
1229
1520
|
config,
|
|
1230
1521
|
path: propertyPath,
|
|
1231
1522
|
allowEmptyKeyframes,
|
|
1523
|
+
allowAuto,
|
|
1232
1524
|
errorFactory,
|
|
1233
1525
|
});
|
|
1234
1526
|
if (result?.valid === false) {
|
|
@@ -1547,6 +1839,8 @@ const validateAnimationDefinition = ({ animation, path, errorFactory }) => {
|
|
|
1547
1839
|
allowedProperties: UPDATE_TWEEN_PROPERTY_KEYS,
|
|
1548
1840
|
path: `${path}.tween`,
|
|
1549
1841
|
unsupportedMessage: "is not a supported update tween property",
|
|
1842
|
+
allowEmptyKeyframes: true,
|
|
1843
|
+
allowAuto: true,
|
|
1550
1844
|
errorFactory,
|
|
1551
1845
|
});
|
|
1552
1846
|
if (result?.valid === false) {
|
|
@@ -1935,36 +2229,171 @@ const validateTransformItems = ({ items, path, errorFactory }) => {
|
|
|
1935
2229
|
}
|
|
1936
2230
|
};
|
|
1937
2231
|
|
|
1938
|
-
const
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
path,
|
|
1942
|
-
errorFactory,
|
|
1943
|
-
}) => {
|
|
1944
|
-
if (variableType === "string" && !isString(value)) {
|
|
1945
|
-
return invalidFromErrorFactory(errorFactory, `${path} must be a string`);
|
|
2232
|
+
const validateParticleModules = ({ modules, path, errorFactory }) => {
|
|
2233
|
+
if (!isPlainObject(modules)) {
|
|
2234
|
+
return invalidFromErrorFactory(errorFactory, `${path} must be an object`);
|
|
1946
2235
|
}
|
|
1947
2236
|
|
|
1948
|
-
if (
|
|
2237
|
+
if (!isPlainObject(modules.emission)) {
|
|
1949
2238
|
return invalidFromErrorFactory(
|
|
1950
2239
|
errorFactory,
|
|
1951
|
-
`${path} must be
|
|
2240
|
+
`${path}.emission must be an object`,
|
|
1952
2241
|
);
|
|
1953
2242
|
}
|
|
1954
2243
|
|
|
1955
|
-
if (
|
|
1956
|
-
return invalidFromErrorFactory(
|
|
2244
|
+
if (!isPlainObject(modules.appearance)) {
|
|
2245
|
+
return invalidFromErrorFactory(
|
|
2246
|
+
errorFactory,
|
|
2247
|
+
`${path}.appearance must be an object`,
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
if (modules.movement !== undefined && !isPlainObject(modules.movement)) {
|
|
2252
|
+
return invalidFromErrorFactory(
|
|
2253
|
+
errorFactory,
|
|
2254
|
+
`${path}.movement must be an object when provided`,
|
|
2255
|
+
);
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
if (modules.bounds !== undefined && !isPlainObject(modules.bounds)) {
|
|
2259
|
+
return invalidFromErrorFactory(
|
|
2260
|
+
errorFactory,
|
|
2261
|
+
`${path}.bounds must be an object when provided`,
|
|
2262
|
+
);
|
|
1957
2263
|
}
|
|
1958
2264
|
};
|
|
1959
2265
|
|
|
1960
|
-
const
|
|
2266
|
+
const validateParticleItems = ({ items, path, errorFactory }) => {
|
|
1961
2267
|
for (const [itemId, item] of Object.entries(items)) {
|
|
1962
2268
|
const itemPath = `${path}.${itemId}`;
|
|
1963
|
-
const variableType = item?.type;
|
|
1964
2269
|
|
|
1965
|
-
if (
|
|
1966
|
-
|
|
1967
|
-
|
|
2270
|
+
if (item?.type !== "folder" && item?.type !== "particle") {
|
|
2271
|
+
return invalidFromErrorFactory(
|
|
2272
|
+
errorFactory,
|
|
2273
|
+
`${itemPath}.type must be 'folder' or 'particle'`,
|
|
2274
|
+
);
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
{
|
|
2278
|
+
const result = validateAllowedKeys({
|
|
2279
|
+
value: item,
|
|
2280
|
+
allowedKeys:
|
|
2281
|
+
item.type === "folder"
|
|
2282
|
+
? ["id", "type", "name", "description"]
|
|
2283
|
+
: [
|
|
2284
|
+
"id",
|
|
2285
|
+
"type",
|
|
2286
|
+
"name",
|
|
2287
|
+
"description",
|
|
2288
|
+
"width",
|
|
2289
|
+
"height",
|
|
2290
|
+
"seed",
|
|
2291
|
+
"modules",
|
|
2292
|
+
],
|
|
2293
|
+
path: itemPath,
|
|
2294
|
+
errorFactory,
|
|
2295
|
+
});
|
|
2296
|
+
if (result?.valid === false) {
|
|
2297
|
+
return result;
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
if (!isNonEmptyString(item.id)) {
|
|
2302
|
+
return invalidFromErrorFactory(
|
|
2303
|
+
errorFactory,
|
|
2304
|
+
`${itemPath}.id must be a non-empty string`,
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
if (item.id !== itemId) {
|
|
2309
|
+
return invalidFromErrorFactory(
|
|
2310
|
+
errorFactory,
|
|
2311
|
+
`${itemPath}.id must match item key '${itemId}'`,
|
|
2312
|
+
);
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
if (!isNonEmptyString(item.name)) {
|
|
2316
|
+
return invalidFromErrorFactory(
|
|
2317
|
+
errorFactory,
|
|
2318
|
+
`${itemPath}.name must be a non-empty string`,
|
|
2319
|
+
);
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
if (item.description !== undefined && !isString(item.description)) {
|
|
2323
|
+
return invalidFromErrorFactory(
|
|
2324
|
+
errorFactory,
|
|
2325
|
+
`${itemPath}.description must be a string when provided`,
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
if (item.type !== "particle") {
|
|
2330
|
+
continue;
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
if (!isFiniteNumber(item.width) || item.width <= 0) {
|
|
2334
|
+
return invalidFromErrorFactory(
|
|
2335
|
+
errorFactory,
|
|
2336
|
+
`${itemPath}.width must be a positive finite number`,
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
if (!isFiniteNumber(item.height) || item.height <= 0) {
|
|
2341
|
+
return invalidFromErrorFactory(
|
|
2342
|
+
errorFactory,
|
|
2343
|
+
`${itemPath}.height must be a positive finite number`,
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
if (item.seed !== undefined && !isFiniteNumber(item.seed)) {
|
|
2348
|
+
return invalidFromErrorFactory(
|
|
2349
|
+
errorFactory,
|
|
2350
|
+
`${itemPath}.seed must be a finite number when provided`,
|
|
2351
|
+
);
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
{
|
|
2355
|
+
const result = validateParticleModules({
|
|
2356
|
+
modules: item.modules,
|
|
2357
|
+
path: `${itemPath}.modules`,
|
|
2358
|
+
errorFactory,
|
|
2359
|
+
});
|
|
2360
|
+
if (result?.valid === false) {
|
|
2361
|
+
return result;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
|
|
2367
|
+
const validateVariableTypedValue = ({
|
|
2368
|
+
value,
|
|
2369
|
+
variableType,
|
|
2370
|
+
path,
|
|
2371
|
+
errorFactory,
|
|
2372
|
+
}) => {
|
|
2373
|
+
if (variableType === "string" && !isString(value)) {
|
|
2374
|
+
return invalidFromErrorFactory(errorFactory, `${path} must be a string`);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
if (variableType === "number" && !isFiniteNumber(value)) {
|
|
2378
|
+
return invalidFromErrorFactory(
|
|
2379
|
+
errorFactory,
|
|
2380
|
+
`${path} must be a finite number`,
|
|
2381
|
+
);
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
if (variableType === "boolean" && typeof value !== "boolean") {
|
|
2385
|
+
return invalidFromErrorFactory(errorFactory, `${path} must be a boolean`);
|
|
2386
|
+
}
|
|
2387
|
+
};
|
|
2388
|
+
|
|
2389
|
+
const validateVariableItems = ({ items, path, errorFactory }) => {
|
|
2390
|
+
for (const [itemId, item] of Object.entries(items)) {
|
|
2391
|
+
const itemPath = `${path}.${itemId}`;
|
|
2392
|
+
const variableType = item?.type;
|
|
2393
|
+
|
|
2394
|
+
if (
|
|
2395
|
+
variableType !== "folder" &&
|
|
2396
|
+
!VARIABLE_TYPE_KEYS.includes(variableType)
|
|
1968
2397
|
) {
|
|
1969
2398
|
return invalidFromErrorFactory(
|
|
1970
2399
|
errorFactory,
|
|
@@ -2027,7 +2456,7 @@ const validateVariableItems = ({ items, path, errorFactory }) => {
|
|
|
2027
2456
|
if (!VARIABLE_SCOPE_KEYS.includes(item.scope)) {
|
|
2028
2457
|
return invalidFromErrorFactory(
|
|
2029
2458
|
errorFactory,
|
|
2030
|
-
`${itemPath}.scope must be 'context', '
|
|
2459
|
+
`${itemPath}.scope must be 'context', 'device', or 'account'`,
|
|
2031
2460
|
);
|
|
2032
2461
|
}
|
|
2033
2462
|
|
|
@@ -2486,6 +2915,8 @@ const validateLayoutElementData = ({
|
|
|
2486
2915
|
"textStyle",
|
|
2487
2916
|
"displaySpeed",
|
|
2488
2917
|
"revealEffect",
|
|
2918
|
+
"resourceId",
|
|
2919
|
+
"animationName",
|
|
2489
2920
|
"imageId",
|
|
2490
2921
|
"hoverImageId",
|
|
2491
2922
|
"clickImageId",
|
|
@@ -2510,6 +2941,7 @@ const validateLayoutElementData = ({
|
|
|
2510
2941
|
"step",
|
|
2511
2942
|
"initialValue",
|
|
2512
2943
|
"variableId",
|
|
2944
|
+
"particleId",
|
|
2513
2945
|
"fragmentLayoutId",
|
|
2514
2946
|
"paginationMode",
|
|
2515
2947
|
"paginationVariableId",
|
|
@@ -2607,6 +3039,9 @@ const validateLayoutElementData = ({
|
|
|
2607
3039
|
|
|
2608
3040
|
for (const key of [
|
|
2609
3041
|
"text",
|
|
3042
|
+
"resourceId",
|
|
3043
|
+
"animationName",
|
|
3044
|
+
"particleId",
|
|
2610
3045
|
"imageId",
|
|
2611
3046
|
"hoverImageId",
|
|
2612
3047
|
"clickImageId",
|
|
@@ -2633,6 +3068,40 @@ const validateLayoutElementData = ({
|
|
|
2633
3068
|
}
|
|
2634
3069
|
}
|
|
2635
3070
|
|
|
3071
|
+
if (data.type === "spritesheet-animation") {
|
|
3072
|
+
if (
|
|
3073
|
+
(!allowPartial || data.resourceId !== undefined) &&
|
|
3074
|
+
!isNonEmptyString(data.resourceId)
|
|
3075
|
+
) {
|
|
3076
|
+
return invalidFromErrorFactory(
|
|
3077
|
+
errorFactory,
|
|
3078
|
+
`${path}.resourceId must be a non-empty string`,
|
|
3079
|
+
);
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
if (
|
|
3083
|
+
(!allowPartial || data.animationName !== undefined) &&
|
|
3084
|
+
!isNonEmptyString(data.animationName)
|
|
3085
|
+
) {
|
|
3086
|
+
return invalidFromErrorFactory(
|
|
3087
|
+
errorFactory,
|
|
3088
|
+
`${path}.animationName must be a non-empty string`,
|
|
3089
|
+
);
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
|
|
3093
|
+
if (data.type === "particle") {
|
|
3094
|
+
if (
|
|
3095
|
+
(!allowPartial || data.particleId !== undefined) &&
|
|
3096
|
+
!isNonEmptyString(data.particleId)
|
|
3097
|
+
) {
|
|
3098
|
+
return invalidFromErrorFactory(
|
|
3099
|
+
errorFactory,
|
|
3100
|
+
`${path}.particleId must be a non-empty string`,
|
|
3101
|
+
);
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
|
|
2636
3105
|
if (data.conditionalOverrides !== undefined) {
|
|
2637
3106
|
if (!Array.isArray(data.conditionalOverrides)) {
|
|
2638
3107
|
return invalidFromErrorFactory(
|
|
@@ -2982,6 +3451,9 @@ const validateLayoutElementItems = ({ items, path, errorFactory }) => {
|
|
|
2982
3451
|
"textStyle",
|
|
2983
3452
|
"displaySpeed",
|
|
2984
3453
|
"revealEffect",
|
|
3454
|
+
"resourceId",
|
|
3455
|
+
"animationName",
|
|
3456
|
+
"particleId",
|
|
2985
3457
|
"imageId",
|
|
2986
3458
|
"hoverImageId",
|
|
2987
3459
|
"clickImageId",
|
|
@@ -3888,6 +4360,17 @@ const validateCollection = ({ collection, path }) => {
|
|
|
3888
4360
|
return result;
|
|
3889
4361
|
}
|
|
3890
4362
|
}
|
|
4363
|
+
} else if (path === "state.spritesheets") {
|
|
4364
|
+
{
|
|
4365
|
+
const result = validateSpritesheetItems({
|
|
4366
|
+
items: collection.items,
|
|
4367
|
+
path: `${path}.items`,
|
|
4368
|
+
errorFactory: createStateValidationError,
|
|
4369
|
+
});
|
|
4370
|
+
if (result?.valid === false) {
|
|
4371
|
+
return result;
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
3891
4374
|
} else if (path === "state.files") {
|
|
3892
4375
|
{
|
|
3893
4376
|
const result = validateFileItems({
|
|
@@ -3965,6 +4448,17 @@ const validateCollection = ({ collection, path }) => {
|
|
|
3965
4448
|
return result;
|
|
3966
4449
|
}
|
|
3967
4450
|
}
|
|
4451
|
+
} else if (path === "state.particles") {
|
|
4452
|
+
{
|
|
4453
|
+
const result = validateParticleItems({
|
|
4454
|
+
items: collection.items,
|
|
4455
|
+
path: `${path}.items`,
|
|
4456
|
+
errorFactory: createStateValidationError,
|
|
4457
|
+
});
|
|
4458
|
+
if (result?.valid === false) {
|
|
4459
|
+
return result;
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
3968
4462
|
} else if (path === "state.variables") {
|
|
3969
4463
|
{
|
|
3970
4464
|
const result = validateVariableItems({
|
|
@@ -4061,6 +4555,18 @@ const validateCollection = ({ collection, path }) => {
|
|
|
4061
4555
|
return result;
|
|
4062
4556
|
}
|
|
4063
4557
|
}
|
|
4558
|
+
} else if (path === "state.spritesheets") {
|
|
4559
|
+
{
|
|
4560
|
+
const result = validateGenericFolderOwnership({
|
|
4561
|
+
nodes: collection.tree,
|
|
4562
|
+
items: collection.items,
|
|
4563
|
+
path: `${path}.tree`,
|
|
4564
|
+
folderLabel: "folder spritesheet item",
|
|
4565
|
+
});
|
|
4566
|
+
if (result?.valid === false) {
|
|
4567
|
+
return result;
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4064
4570
|
} else if (path === "state.sounds") {
|
|
4065
4571
|
{
|
|
4066
4572
|
const result = validateSoundTreeFolderOwnership({
|
|
@@ -4118,6 +4624,7 @@ const validateCollection = ({ collection, path }) => {
|
|
|
4118
4624
|
}
|
|
4119
4625
|
} else if (
|
|
4120
4626
|
path === "state.files" ||
|
|
4627
|
+
path === "state.particles" ||
|
|
4121
4628
|
path === "state.transforms" ||
|
|
4122
4629
|
path === "state.variables" ||
|
|
4123
4630
|
path === "state.textStyles" ||
|
|
@@ -4417,6 +4924,43 @@ export const assertInvariants = ({ state }) => {
|
|
|
4417
4924
|
}
|
|
4418
4925
|
}
|
|
4419
4926
|
|
|
4927
|
+
for (const [spritesheetId, spritesheet] of Object.entries(
|
|
4928
|
+
state.spritesheets.items,
|
|
4929
|
+
)) {
|
|
4930
|
+
if (spritesheet.type !== "spritesheet") {
|
|
4931
|
+
continue;
|
|
4932
|
+
}
|
|
4933
|
+
|
|
4934
|
+
const result = validateFileReference({
|
|
4935
|
+
state,
|
|
4936
|
+
fileId: spritesheet.fileId,
|
|
4937
|
+
path: "spritesheet.fileId",
|
|
4938
|
+
details: { spritesheetId, fileId: spritesheet.fileId },
|
|
4939
|
+
errorFactory: createInvariantValidationError,
|
|
4940
|
+
});
|
|
4941
|
+
if (!result.valid) {
|
|
4942
|
+
return result;
|
|
4943
|
+
}
|
|
4944
|
+
|
|
4945
|
+
if (spritesheet.thumbnailFileId === undefined) {
|
|
4946
|
+
continue;
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4949
|
+
const thumbnailResult = validateFileReference({
|
|
4950
|
+
state,
|
|
4951
|
+
fileId: spritesheet.thumbnailFileId,
|
|
4952
|
+
path: "spritesheet.thumbnailFileId",
|
|
4953
|
+
details: {
|
|
4954
|
+
spritesheetId,
|
|
4955
|
+
thumbnailFileId: spritesheet.thumbnailFileId,
|
|
4956
|
+
},
|
|
4957
|
+
errorFactory: createInvariantValidationError,
|
|
4958
|
+
});
|
|
4959
|
+
if (!thumbnailResult.valid) {
|
|
4960
|
+
return thumbnailResult;
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4420
4964
|
for (const [soundId, sound] of Object.entries(state.sounds.items)) {
|
|
4421
4965
|
if (sound.type !== "sound") {
|
|
4422
4966
|
continue;
|
|
@@ -4708,6 +5252,68 @@ export const assertInvariants = ({ state }) => {
|
|
|
4708
5252
|
return VALID_RESULT;
|
|
4709
5253
|
};
|
|
4710
5254
|
|
|
5255
|
+
const assertSpritesheetAnimationReference = ({
|
|
5256
|
+
ownerIdField,
|
|
5257
|
+
ownerId,
|
|
5258
|
+
ownerLabel,
|
|
5259
|
+
elementId,
|
|
5260
|
+
targetId,
|
|
5261
|
+
animationName,
|
|
5262
|
+
}) => {
|
|
5263
|
+
const spritesheet = state.spritesheets?.items?.[targetId];
|
|
5264
|
+
if (!isPlainObject(spritesheet) || spritesheet.type === "folder") {
|
|
5265
|
+
return invalidInvariant(
|
|
5266
|
+
`${ownerLabel} element resourceId must reference an existing non-folder spritesheet`,
|
|
5267
|
+
{
|
|
5268
|
+
[ownerIdField]: ownerId,
|
|
5269
|
+
elementId,
|
|
5270
|
+
field: "resourceId",
|
|
5271
|
+
targetId,
|
|
5272
|
+
},
|
|
5273
|
+
);
|
|
5274
|
+
}
|
|
5275
|
+
|
|
5276
|
+
if (
|
|
5277
|
+
!isNonEmptyString(animationName) ||
|
|
5278
|
+
!isPlainObject(spritesheet.animations?.[animationName])
|
|
5279
|
+
) {
|
|
5280
|
+
return invalidInvariant(
|
|
5281
|
+
`${ownerLabel} element animationName must reference an existing spritesheet animation`,
|
|
5282
|
+
{
|
|
5283
|
+
[ownerIdField]: ownerId,
|
|
5284
|
+
elementId,
|
|
5285
|
+
field: "animationName",
|
|
5286
|
+
targetId: animationName,
|
|
5287
|
+
},
|
|
5288
|
+
);
|
|
5289
|
+
}
|
|
5290
|
+
|
|
5291
|
+
return VALID_RESULT;
|
|
5292
|
+
};
|
|
5293
|
+
|
|
5294
|
+
const assertParticleReference = ({
|
|
5295
|
+
ownerIdField,
|
|
5296
|
+
ownerId,
|
|
5297
|
+
ownerLabel,
|
|
5298
|
+
elementId,
|
|
5299
|
+
targetId,
|
|
5300
|
+
}) => {
|
|
5301
|
+
const particle = state.particles?.items?.[targetId];
|
|
5302
|
+
if (!isPlainObject(particle) || particle.type === "folder") {
|
|
5303
|
+
return invalidInvariant(
|
|
5304
|
+
`${ownerLabel} element particleId must reference an existing non-folder particle`,
|
|
5305
|
+
{
|
|
5306
|
+
[ownerIdField]: ownerId,
|
|
5307
|
+
elementId,
|
|
5308
|
+
field: "particleId",
|
|
5309
|
+
targetId,
|
|
5310
|
+
},
|
|
5311
|
+
);
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5314
|
+
return VALID_RESULT;
|
|
5315
|
+
};
|
|
5316
|
+
|
|
4711
5317
|
const assertElementReferencesForCollection = ({
|
|
4712
5318
|
items,
|
|
4713
5319
|
ownerIdField,
|
|
@@ -4720,6 +5326,37 @@ export const assertInvariants = ({ state }) => {
|
|
|
4720
5326
|
}
|
|
4721
5327
|
|
|
4722
5328
|
for (const [elementId, element] of Object.entries(owner.elements.items)) {
|
|
5329
|
+
if (
|
|
5330
|
+
element.type === "spritesheet-animation" ||
|
|
5331
|
+
element.resourceId !== undefined ||
|
|
5332
|
+
element.animationName !== undefined
|
|
5333
|
+
) {
|
|
5334
|
+
const result = assertSpritesheetAnimationReference({
|
|
5335
|
+
ownerIdField,
|
|
5336
|
+
ownerId,
|
|
5337
|
+
ownerLabel,
|
|
5338
|
+
elementId,
|
|
5339
|
+
targetId: element.resourceId,
|
|
5340
|
+
animationName: element.animationName,
|
|
5341
|
+
});
|
|
5342
|
+
if (!result.valid) {
|
|
5343
|
+
return result;
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
|
|
5347
|
+
if (element.type === "particle" || element.particleId !== undefined) {
|
|
5348
|
+
const result = assertParticleReference({
|
|
5349
|
+
ownerIdField,
|
|
5350
|
+
ownerId,
|
|
5351
|
+
ownerLabel,
|
|
5352
|
+
elementId,
|
|
5353
|
+
targetId: element.particleId,
|
|
5354
|
+
});
|
|
5355
|
+
if (!result.valid) {
|
|
5356
|
+
return result;
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
|
|
4723
5360
|
for (const field of [
|
|
4724
5361
|
"imageId",
|
|
4725
5362
|
"hoverImageId",
|
|
@@ -5460,7 +6097,234 @@ const validateImageUpdateData = ({ data, errorFactory }) => {
|
|
|
5460
6097
|
}
|
|
5461
6098
|
};
|
|
5462
6099
|
|
|
5463
|
-
const
|
|
6100
|
+
const validateSpritesheetCreateData = ({ data, errorFactory }) => {
|
|
6101
|
+
if (!isPlainObject(data)) {
|
|
6102
|
+
return invalidFromErrorFactory(
|
|
6103
|
+
errorFactory,
|
|
6104
|
+
"payload.data must be an object",
|
|
6105
|
+
);
|
|
6106
|
+
}
|
|
6107
|
+
|
|
6108
|
+
if (data.type !== "folder" && data.type !== "spritesheet") {
|
|
6109
|
+
return invalidFromErrorFactory(
|
|
6110
|
+
errorFactory,
|
|
6111
|
+
"payload.data.type must be 'folder' or 'spritesheet'",
|
|
6112
|
+
);
|
|
6113
|
+
}
|
|
6114
|
+
|
|
6115
|
+
{
|
|
6116
|
+
const result = validateAllowedKeys({
|
|
6117
|
+
value: data,
|
|
6118
|
+
allowedKeys:
|
|
6119
|
+
data.type === "folder"
|
|
6120
|
+
? ["type", "name", "description"]
|
|
6121
|
+
: [
|
|
6122
|
+
"type",
|
|
6123
|
+
"name",
|
|
6124
|
+
"description",
|
|
6125
|
+
"thumbnailFileId",
|
|
6126
|
+
"fileId",
|
|
6127
|
+
"fileType",
|
|
6128
|
+
"fileSize",
|
|
6129
|
+
"sheetWidth",
|
|
6130
|
+
"sheetHeight",
|
|
6131
|
+
"frameCount",
|
|
6132
|
+
"width",
|
|
6133
|
+
"height",
|
|
6134
|
+
"jsonData",
|
|
6135
|
+
"animations",
|
|
6136
|
+
],
|
|
6137
|
+
path: "payload.data",
|
|
6138
|
+
errorFactory,
|
|
6139
|
+
});
|
|
6140
|
+
if (result?.valid === false) {
|
|
6141
|
+
return result;
|
|
6142
|
+
}
|
|
6143
|
+
}
|
|
6144
|
+
|
|
6145
|
+
if (!isNonEmptyString(data.name)) {
|
|
6146
|
+
return invalidFromErrorFactory(
|
|
6147
|
+
errorFactory,
|
|
6148
|
+
"payload.data.name must be a non-empty string",
|
|
6149
|
+
);
|
|
6150
|
+
}
|
|
6151
|
+
|
|
6152
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
6153
|
+
return invalidFromErrorFactory(
|
|
6154
|
+
errorFactory,
|
|
6155
|
+
"payload.data.description must be a string when provided",
|
|
6156
|
+
);
|
|
6157
|
+
}
|
|
6158
|
+
|
|
6159
|
+
if (data.type === "spritesheet") {
|
|
6160
|
+
if (
|
|
6161
|
+
data.thumbnailFileId !== undefined &&
|
|
6162
|
+
!isNonEmptyString(data.thumbnailFileId)
|
|
6163
|
+
) {
|
|
6164
|
+
return invalidFromErrorFactory(
|
|
6165
|
+
errorFactory,
|
|
6166
|
+
"payload.data.thumbnailFileId must be a non-empty string when provided",
|
|
6167
|
+
);
|
|
6168
|
+
}
|
|
6169
|
+
|
|
6170
|
+
if (!isNonEmptyString(data.fileId)) {
|
|
6171
|
+
return invalidFromErrorFactory(
|
|
6172
|
+
errorFactory,
|
|
6173
|
+
"payload.data.fileId must be a non-empty string",
|
|
6174
|
+
);
|
|
6175
|
+
}
|
|
6176
|
+
|
|
6177
|
+
if (data.fileType !== undefined && !isString(data.fileType)) {
|
|
6178
|
+
return invalidFromErrorFactory(
|
|
6179
|
+
errorFactory,
|
|
6180
|
+
"payload.data.fileType must be a string when provided",
|
|
6181
|
+
);
|
|
6182
|
+
}
|
|
6183
|
+
|
|
6184
|
+
for (const key of [
|
|
6185
|
+
"fileSize",
|
|
6186
|
+
"sheetWidth",
|
|
6187
|
+
"sheetHeight",
|
|
6188
|
+
"frameCount",
|
|
6189
|
+
"width",
|
|
6190
|
+
"height",
|
|
6191
|
+
]) {
|
|
6192
|
+
if (data[key] !== undefined && !isFiniteNumber(data[key])) {
|
|
6193
|
+
return invalidFromErrorFactory(
|
|
6194
|
+
errorFactory,
|
|
6195
|
+
`payload.data.${key} must be a finite number`,
|
|
6196
|
+
);
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
6199
|
+
|
|
6200
|
+
if (!isPlainObject(data.jsonData)) {
|
|
6201
|
+
return invalidFromErrorFactory(
|
|
6202
|
+
errorFactory,
|
|
6203
|
+
"payload.data.jsonData must be an object",
|
|
6204
|
+
);
|
|
6205
|
+
}
|
|
6206
|
+
|
|
6207
|
+
{
|
|
6208
|
+
const result = validateSpritesheetAnimationMap({
|
|
6209
|
+
animations: data.animations,
|
|
6210
|
+
path: "payload.data.animations",
|
|
6211
|
+
errorFactory,
|
|
6212
|
+
});
|
|
6213
|
+
if (result?.valid === false) {
|
|
6214
|
+
return result;
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
}
|
|
6218
|
+
};
|
|
6219
|
+
|
|
6220
|
+
const validateSpritesheetUpdateData = ({ data, errorFactory }) => {
|
|
6221
|
+
{
|
|
6222
|
+
const result = validateAllowedKeys({
|
|
6223
|
+
value: data,
|
|
6224
|
+
allowedKeys: [
|
|
6225
|
+
"name",
|
|
6226
|
+
"description",
|
|
6227
|
+
"thumbnailFileId",
|
|
6228
|
+
"fileId",
|
|
6229
|
+
"fileType",
|
|
6230
|
+
"fileSize",
|
|
6231
|
+
"sheetWidth",
|
|
6232
|
+
"sheetHeight",
|
|
6233
|
+
"frameCount",
|
|
6234
|
+
"width",
|
|
6235
|
+
"height",
|
|
6236
|
+
"jsonData",
|
|
6237
|
+
"animations",
|
|
6238
|
+
],
|
|
6239
|
+
path: "payload.data",
|
|
6240
|
+
errorFactory,
|
|
6241
|
+
});
|
|
6242
|
+
if (result?.valid === false) {
|
|
6243
|
+
return result;
|
|
6244
|
+
}
|
|
6245
|
+
}
|
|
6246
|
+
|
|
6247
|
+
if (Object.keys(data).length === 0) {
|
|
6248
|
+
return invalidFromErrorFactory(
|
|
6249
|
+
errorFactory,
|
|
6250
|
+
"payload.data must include at least one updatable field",
|
|
6251
|
+
);
|
|
6252
|
+
}
|
|
6253
|
+
|
|
6254
|
+
if (data.name !== undefined && !isNonEmptyString(data.name)) {
|
|
6255
|
+
return invalidFromErrorFactory(
|
|
6256
|
+
errorFactory,
|
|
6257
|
+
"payload.data.name must be a non-empty string when provided",
|
|
6258
|
+
);
|
|
6259
|
+
}
|
|
6260
|
+
|
|
6261
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
6262
|
+
return invalidFromErrorFactory(
|
|
6263
|
+
errorFactory,
|
|
6264
|
+
"payload.data.description must be a string when provided",
|
|
6265
|
+
);
|
|
6266
|
+
}
|
|
6267
|
+
|
|
6268
|
+
if (
|
|
6269
|
+
data.thumbnailFileId !== undefined &&
|
|
6270
|
+
!isNonEmptyString(data.thumbnailFileId)
|
|
6271
|
+
) {
|
|
6272
|
+
return invalidFromErrorFactory(
|
|
6273
|
+
errorFactory,
|
|
6274
|
+
"payload.data.thumbnailFileId must be a non-empty string when provided",
|
|
6275
|
+
);
|
|
6276
|
+
}
|
|
6277
|
+
|
|
6278
|
+
if (data.fileId !== undefined && !isNonEmptyString(data.fileId)) {
|
|
6279
|
+
return invalidFromErrorFactory(
|
|
6280
|
+
errorFactory,
|
|
6281
|
+
"payload.data.fileId must be a non-empty string when provided",
|
|
6282
|
+
);
|
|
6283
|
+
}
|
|
6284
|
+
|
|
6285
|
+
if (data.fileType !== undefined && !isString(data.fileType)) {
|
|
6286
|
+
return invalidFromErrorFactory(
|
|
6287
|
+
errorFactory,
|
|
6288
|
+
"payload.data.fileType must be a string when provided",
|
|
6289
|
+
);
|
|
6290
|
+
}
|
|
6291
|
+
|
|
6292
|
+
for (const key of [
|
|
6293
|
+
"fileSize",
|
|
6294
|
+
"sheetWidth",
|
|
6295
|
+
"sheetHeight",
|
|
6296
|
+
"frameCount",
|
|
6297
|
+
"width",
|
|
6298
|
+
"height",
|
|
6299
|
+
]) {
|
|
6300
|
+
if (data[key] !== undefined && !isFiniteNumber(data[key])) {
|
|
6301
|
+
return invalidFromErrorFactory(
|
|
6302
|
+
errorFactory,
|
|
6303
|
+
`payload.data.${key} must be a finite number`,
|
|
6304
|
+
);
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6307
|
+
|
|
6308
|
+
if (data.jsonData !== undefined && !isPlainObject(data.jsonData)) {
|
|
6309
|
+
return invalidFromErrorFactory(
|
|
6310
|
+
errorFactory,
|
|
6311
|
+
"payload.data.jsonData must be an object when provided",
|
|
6312
|
+
);
|
|
6313
|
+
}
|
|
6314
|
+
|
|
6315
|
+
if (data.animations !== undefined) {
|
|
6316
|
+
const result = validateSpritesheetAnimationMap({
|
|
6317
|
+
animations: data.animations,
|
|
6318
|
+
path: "payload.data.animations",
|
|
6319
|
+
errorFactory,
|
|
6320
|
+
});
|
|
6321
|
+
if (result?.valid === false) {
|
|
6322
|
+
return result;
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
};
|
|
6326
|
+
|
|
6327
|
+
const validateSoundCreateData = ({ data, errorFactory }) => {
|
|
5464
6328
|
if (!isPlainObject(data)) {
|
|
5465
6329
|
return invalidFromErrorFactory(
|
|
5466
6330
|
errorFactory,
|
|
@@ -6230,11 +7094,234 @@ const validateAnimationCreateData = ({ data, errorFactory }) => {
|
|
|
6230
7094
|
}
|
|
6231
7095
|
};
|
|
6232
7096
|
|
|
6233
|
-
const validateAnimationUpdateData = ({ data, errorFactory }) => {
|
|
7097
|
+
const validateAnimationUpdateData = ({ data, errorFactory }) => {
|
|
7098
|
+
{
|
|
7099
|
+
const result = validateAllowedKeys({
|
|
7100
|
+
value: data,
|
|
7101
|
+
allowedKeys: ["name", "description", "animation"],
|
|
7102
|
+
path: "payload.data",
|
|
7103
|
+
errorFactory,
|
|
7104
|
+
});
|
|
7105
|
+
if (result?.valid === false) {
|
|
7106
|
+
return result;
|
|
7107
|
+
}
|
|
7108
|
+
}
|
|
7109
|
+
|
|
7110
|
+
if (Object.keys(data).length === 0) {
|
|
7111
|
+
return invalidFromErrorFactory(
|
|
7112
|
+
errorFactory,
|
|
7113
|
+
"payload.data must include at least one updatable field",
|
|
7114
|
+
);
|
|
7115
|
+
}
|
|
7116
|
+
|
|
7117
|
+
if (data.name !== undefined && !isNonEmptyString(data.name)) {
|
|
7118
|
+
return invalidFromErrorFactory(
|
|
7119
|
+
errorFactory,
|
|
7120
|
+
"payload.data.name must be a non-empty string when provided",
|
|
7121
|
+
);
|
|
7122
|
+
}
|
|
7123
|
+
|
|
7124
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
7125
|
+
return invalidFromErrorFactory(
|
|
7126
|
+
errorFactory,
|
|
7127
|
+
"payload.data.description must be a string when provided",
|
|
7128
|
+
);
|
|
7129
|
+
}
|
|
7130
|
+
|
|
7131
|
+
if (data.animation !== undefined) {
|
|
7132
|
+
{
|
|
7133
|
+
const result = validateAnimationDefinition({
|
|
7134
|
+
animation: data.animation,
|
|
7135
|
+
path: "payload.data.animation",
|
|
7136
|
+
errorFactory,
|
|
7137
|
+
});
|
|
7138
|
+
if (result?.valid === false) {
|
|
7139
|
+
return result;
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
7142
|
+
}
|
|
7143
|
+
};
|
|
7144
|
+
|
|
7145
|
+
const validateTransformCreateData = ({ data, errorFactory }) => {
|
|
7146
|
+
if (!isPlainObject(data)) {
|
|
7147
|
+
return invalidFromErrorFactory(
|
|
7148
|
+
errorFactory,
|
|
7149
|
+
"payload.data must be an object",
|
|
7150
|
+
);
|
|
7151
|
+
}
|
|
7152
|
+
|
|
7153
|
+
if (data.type !== "folder" && data.type !== "transform") {
|
|
7154
|
+
return invalidFromErrorFactory(
|
|
7155
|
+
errorFactory,
|
|
7156
|
+
"payload.data.type must be 'folder' or 'transform'",
|
|
7157
|
+
);
|
|
7158
|
+
}
|
|
7159
|
+
|
|
7160
|
+
{
|
|
7161
|
+
const result = validateAllowedKeys({
|
|
7162
|
+
value: data,
|
|
7163
|
+
allowedKeys:
|
|
7164
|
+
data.type === "folder"
|
|
7165
|
+
? ["type", "name", "description"]
|
|
7166
|
+
: [
|
|
7167
|
+
"type",
|
|
7168
|
+
"name",
|
|
7169
|
+
"description",
|
|
7170
|
+
"x",
|
|
7171
|
+
"y",
|
|
7172
|
+
"scaleX",
|
|
7173
|
+
"scaleY",
|
|
7174
|
+
"anchorX",
|
|
7175
|
+
"anchorY",
|
|
7176
|
+
"rotation",
|
|
7177
|
+
],
|
|
7178
|
+
path: "payload.data",
|
|
7179
|
+
errorFactory,
|
|
7180
|
+
});
|
|
7181
|
+
if (result?.valid === false) {
|
|
7182
|
+
return result;
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
|
|
7186
|
+
if (!isNonEmptyString(data.name)) {
|
|
7187
|
+
return invalidFromErrorFactory(
|
|
7188
|
+
errorFactory,
|
|
7189
|
+
"payload.data.name must be a non-empty string",
|
|
7190
|
+
);
|
|
7191
|
+
}
|
|
7192
|
+
|
|
7193
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
7194
|
+
return invalidFromErrorFactory(
|
|
7195
|
+
errorFactory,
|
|
7196
|
+
"payload.data.description must be a string when provided",
|
|
7197
|
+
);
|
|
7198
|
+
}
|
|
7199
|
+
|
|
7200
|
+
if (data.type === "transform") {
|
|
7201
|
+
for (const key of [
|
|
7202
|
+
"x",
|
|
7203
|
+
"y",
|
|
7204
|
+
"scaleX",
|
|
7205
|
+
"scaleY",
|
|
7206
|
+
"anchorX",
|
|
7207
|
+
"anchorY",
|
|
7208
|
+
"rotation",
|
|
7209
|
+
]) {
|
|
7210
|
+
if (!isFiniteNumber(data[key])) {
|
|
7211
|
+
return invalidFromErrorFactory(
|
|
7212
|
+
errorFactory,
|
|
7213
|
+
`payload.data.${key} must be a finite number`,
|
|
7214
|
+
);
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
};
|
|
7219
|
+
|
|
7220
|
+
const validateParticleCreateData = ({ data, errorFactory }) => {
|
|
7221
|
+
if (!isPlainObject(data)) {
|
|
7222
|
+
return invalidFromErrorFactory(
|
|
7223
|
+
errorFactory,
|
|
7224
|
+
"payload.data must be an object",
|
|
7225
|
+
);
|
|
7226
|
+
}
|
|
7227
|
+
|
|
7228
|
+
if (data.type !== "folder" && data.type !== "particle") {
|
|
7229
|
+
return invalidFromErrorFactory(
|
|
7230
|
+
errorFactory,
|
|
7231
|
+
"payload.data.type must be 'folder' or 'particle'",
|
|
7232
|
+
);
|
|
7233
|
+
}
|
|
7234
|
+
|
|
7235
|
+
{
|
|
7236
|
+
const result = validateAllowedKeys({
|
|
7237
|
+
value: data,
|
|
7238
|
+
allowedKeys:
|
|
7239
|
+
data.type === "folder"
|
|
7240
|
+
? ["type", "name", "description"]
|
|
7241
|
+
: [
|
|
7242
|
+
"type",
|
|
7243
|
+
"name",
|
|
7244
|
+
"description",
|
|
7245
|
+
"width",
|
|
7246
|
+
"height",
|
|
7247
|
+
"seed",
|
|
7248
|
+
"modules",
|
|
7249
|
+
],
|
|
7250
|
+
path: "payload.data",
|
|
7251
|
+
errorFactory,
|
|
7252
|
+
});
|
|
7253
|
+
if (result?.valid === false) {
|
|
7254
|
+
return result;
|
|
7255
|
+
}
|
|
7256
|
+
}
|
|
7257
|
+
|
|
7258
|
+
if (!isNonEmptyString(data.name)) {
|
|
7259
|
+
return invalidFromErrorFactory(
|
|
7260
|
+
errorFactory,
|
|
7261
|
+
"payload.data.name must be a non-empty string",
|
|
7262
|
+
);
|
|
7263
|
+
}
|
|
7264
|
+
|
|
7265
|
+
if (data.description !== undefined && !isString(data.description)) {
|
|
7266
|
+
return invalidFromErrorFactory(
|
|
7267
|
+
errorFactory,
|
|
7268
|
+
"payload.data.description must be a string when provided",
|
|
7269
|
+
);
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7272
|
+
if (data.type !== "particle") {
|
|
7273
|
+
return;
|
|
7274
|
+
}
|
|
7275
|
+
|
|
7276
|
+
if (!isFiniteNumber(data.width) || data.width <= 0) {
|
|
7277
|
+
return invalidFromErrorFactory(
|
|
7278
|
+
errorFactory,
|
|
7279
|
+
"payload.data.width must be a positive finite number",
|
|
7280
|
+
);
|
|
7281
|
+
}
|
|
7282
|
+
|
|
7283
|
+
if (!isFiniteNumber(data.height) || data.height <= 0) {
|
|
7284
|
+
return invalidFromErrorFactory(
|
|
7285
|
+
errorFactory,
|
|
7286
|
+
"payload.data.height must be a positive finite number",
|
|
7287
|
+
);
|
|
7288
|
+
}
|
|
7289
|
+
|
|
7290
|
+
if (
|
|
7291
|
+
data.seed !== undefined &&
|
|
7292
|
+
data.seed !== null &&
|
|
7293
|
+
!isFiniteNumber(data.seed)
|
|
7294
|
+
) {
|
|
7295
|
+
return invalidFromErrorFactory(
|
|
7296
|
+
errorFactory,
|
|
7297
|
+
"payload.data.seed must be a finite number when provided",
|
|
7298
|
+
);
|
|
7299
|
+
}
|
|
7300
|
+
|
|
7301
|
+
{
|
|
7302
|
+
const result = validateParticleModules({
|
|
7303
|
+
modules: data.modules,
|
|
7304
|
+
path: "payload.data.modules",
|
|
7305
|
+
errorFactory,
|
|
7306
|
+
});
|
|
7307
|
+
if (result?.valid === false) {
|
|
7308
|
+
return result;
|
|
7309
|
+
}
|
|
7310
|
+
}
|
|
7311
|
+
};
|
|
7312
|
+
|
|
7313
|
+
const validateParticleUpdateData = ({ data, errorFactory }) => {
|
|
6234
7314
|
{
|
|
6235
7315
|
const result = validateAllowedKeys({
|
|
6236
7316
|
value: data,
|
|
6237
|
-
allowedKeys: [
|
|
7317
|
+
allowedKeys: [
|
|
7318
|
+
"name",
|
|
7319
|
+
"description",
|
|
7320
|
+
"width",
|
|
7321
|
+
"height",
|
|
7322
|
+
"seed",
|
|
7323
|
+
"modules",
|
|
7324
|
+
],
|
|
6238
7325
|
path: "payload.data",
|
|
6239
7326
|
errorFactory,
|
|
6240
7327
|
});
|
|
@@ -6264,90 +7351,46 @@ const validateAnimationUpdateData = ({ data, errorFactory }) => {
|
|
|
6264
7351
|
);
|
|
6265
7352
|
}
|
|
6266
7353
|
|
|
6267
|
-
if (
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
path: "payload.data.animation",
|
|
6272
|
-
errorFactory,
|
|
6273
|
-
});
|
|
6274
|
-
if (result?.valid === false) {
|
|
6275
|
-
return result;
|
|
6276
|
-
}
|
|
6277
|
-
}
|
|
6278
|
-
}
|
|
6279
|
-
};
|
|
6280
|
-
|
|
6281
|
-
const validateTransformCreateData = ({ data, errorFactory }) => {
|
|
6282
|
-
if (!isPlainObject(data)) {
|
|
6283
|
-
return invalidFromErrorFactory(
|
|
6284
|
-
errorFactory,
|
|
6285
|
-
"payload.data must be an object",
|
|
6286
|
-
);
|
|
6287
|
-
}
|
|
6288
|
-
|
|
6289
|
-
if (data.type !== "folder" && data.type !== "transform") {
|
|
7354
|
+
if (
|
|
7355
|
+
data.width !== undefined &&
|
|
7356
|
+
(!isFiniteNumber(data.width) || data.width <= 0)
|
|
7357
|
+
) {
|
|
6290
7358
|
return invalidFromErrorFactory(
|
|
6291
7359
|
errorFactory,
|
|
6292
|
-
"payload.data.
|
|
7360
|
+
"payload.data.width must be a positive finite number when provided",
|
|
6293
7361
|
);
|
|
6294
7362
|
}
|
|
6295
7363
|
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
data.type === "folder"
|
|
6301
|
-
? ["type", "name", "description"]
|
|
6302
|
-
: [
|
|
6303
|
-
"type",
|
|
6304
|
-
"name",
|
|
6305
|
-
"description",
|
|
6306
|
-
"x",
|
|
6307
|
-
"y",
|
|
6308
|
-
"scaleX",
|
|
6309
|
-
"scaleY",
|
|
6310
|
-
"anchorX",
|
|
6311
|
-
"anchorY",
|
|
6312
|
-
"rotation",
|
|
6313
|
-
],
|
|
6314
|
-
path: "payload.data",
|
|
6315
|
-
errorFactory,
|
|
6316
|
-
});
|
|
6317
|
-
if (result?.valid === false) {
|
|
6318
|
-
return result;
|
|
6319
|
-
}
|
|
6320
|
-
}
|
|
6321
|
-
|
|
6322
|
-
if (!isNonEmptyString(data.name)) {
|
|
7364
|
+
if (
|
|
7365
|
+
data.height !== undefined &&
|
|
7366
|
+
(!isFiniteNumber(data.height) || data.height <= 0)
|
|
7367
|
+
) {
|
|
6323
7368
|
return invalidFromErrorFactory(
|
|
6324
7369
|
errorFactory,
|
|
6325
|
-
"payload.data.
|
|
7370
|
+
"payload.data.height must be a positive finite number when provided",
|
|
6326
7371
|
);
|
|
6327
7372
|
}
|
|
6328
7373
|
|
|
6329
|
-
if (
|
|
7374
|
+
if (
|
|
7375
|
+
data.seed !== undefined &&
|
|
7376
|
+
data.seed !== null &&
|
|
7377
|
+
!isFiniteNumber(data.seed)
|
|
7378
|
+
) {
|
|
6330
7379
|
return invalidFromErrorFactory(
|
|
6331
7380
|
errorFactory,
|
|
6332
|
-
"payload.data.
|
|
7381
|
+
"payload.data.seed must be a finite number when provided",
|
|
6333
7382
|
);
|
|
6334
7383
|
}
|
|
6335
7384
|
|
|
6336
|
-
if (data.
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
]) {
|
|
6346
|
-
if (!isFiniteNumber(data[key])) {
|
|
6347
|
-
return invalidFromErrorFactory(
|
|
6348
|
-
errorFactory,
|
|
6349
|
-
`payload.data.${key} must be a finite number`,
|
|
6350
|
-
);
|
|
7385
|
+
if (data.modules !== undefined) {
|
|
7386
|
+
{
|
|
7387
|
+
const result = validateParticleModules({
|
|
7388
|
+
modules: data.modules,
|
|
7389
|
+
path: "payload.data.modules",
|
|
7390
|
+
errorFactory,
|
|
7391
|
+
});
|
|
7392
|
+
if (result?.valid === false) {
|
|
7393
|
+
return result;
|
|
6351
7394
|
}
|
|
6352
7395
|
}
|
|
6353
7396
|
}
|
|
@@ -6463,7 +7506,7 @@ const validateVariableCreateData = ({ data, errorFactory }) => {
|
|
|
6463
7506
|
if (!VARIABLE_SCOPE_KEYS.includes(data.scope)) {
|
|
6464
7507
|
return invalidFromErrorFactory(
|
|
6465
7508
|
errorFactory,
|
|
6466
|
-
"payload.data.scope must be 'context', '
|
|
7509
|
+
"payload.data.scope must be 'context', 'device', or 'account'",
|
|
6467
7510
|
);
|
|
6468
7511
|
}
|
|
6469
7512
|
|
|
@@ -6529,7 +7572,7 @@ const validateVariableUpdateData = ({ data, errorFactory }) => {
|
|
|
6529
7572
|
if (data.scope !== undefined && !VARIABLE_SCOPE_KEYS.includes(data.scope)) {
|
|
6530
7573
|
return invalidFromErrorFactory(
|
|
6531
7574
|
errorFactory,
|
|
6532
|
-
"payload.data.scope must be 'context', '
|
|
7575
|
+
"payload.data.scope must be 'context', 'device', or 'account' when provided",
|
|
6533
7576
|
);
|
|
6534
7577
|
}
|
|
6535
7578
|
};
|
|
@@ -7433,6 +8476,58 @@ const validateVisualElementReferenceTargets = ({
|
|
|
7433
8476
|
state,
|
|
7434
8477
|
errorFactory,
|
|
7435
8478
|
}) => {
|
|
8479
|
+
if (
|
|
8480
|
+
data.type === "spritesheet-animation" ||
|
|
8481
|
+
data.resourceId !== undefined ||
|
|
8482
|
+
data.animationName !== undefined
|
|
8483
|
+
) {
|
|
8484
|
+
const spritesheet = state.spritesheets?.items?.[data.resourceId];
|
|
8485
|
+
if (!isPlainObject(spritesheet) || spritesheet.type === "folder") {
|
|
8486
|
+
return invalidFromErrorFactory(
|
|
8487
|
+
errorFactory,
|
|
8488
|
+
`${ownerLabel} element resourceId must reference an existing non-folder spritesheet`,
|
|
8489
|
+
{
|
|
8490
|
+
[ownerIdField]: ownerId,
|
|
8491
|
+
elementId,
|
|
8492
|
+
field: "resourceId",
|
|
8493
|
+
targetId: data.resourceId,
|
|
8494
|
+
},
|
|
8495
|
+
);
|
|
8496
|
+
}
|
|
8497
|
+
|
|
8498
|
+
if (
|
|
8499
|
+
!isNonEmptyString(data.animationName) ||
|
|
8500
|
+
!isPlainObject(spritesheet.animations?.[data.animationName])
|
|
8501
|
+
) {
|
|
8502
|
+
return invalidFromErrorFactory(
|
|
8503
|
+
errorFactory,
|
|
8504
|
+
`${ownerLabel} element animationName must reference an existing spritesheet animation`,
|
|
8505
|
+
{
|
|
8506
|
+
[ownerIdField]: ownerId,
|
|
8507
|
+
elementId,
|
|
8508
|
+
field: "animationName",
|
|
8509
|
+
targetId: data.animationName,
|
|
8510
|
+
},
|
|
8511
|
+
);
|
|
8512
|
+
}
|
|
8513
|
+
}
|
|
8514
|
+
|
|
8515
|
+
if (data.type === "particle" || data.particleId !== undefined) {
|
|
8516
|
+
const particle = state.particles?.items?.[data.particleId];
|
|
8517
|
+
if (!isPlainObject(particle) || particle.type === "folder") {
|
|
8518
|
+
return invalidFromErrorFactory(
|
|
8519
|
+
errorFactory,
|
|
8520
|
+
`${ownerLabel} element particleId must reference an existing non-folder particle`,
|
|
8521
|
+
{
|
|
8522
|
+
[ownerIdField]: ownerId,
|
|
8523
|
+
elementId,
|
|
8524
|
+
field: "particleId",
|
|
8525
|
+
targetId: data.particleId,
|
|
8526
|
+
},
|
|
8527
|
+
);
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
|
|
7436
8531
|
if (data.imageId !== undefined) {
|
|
7437
8532
|
const image = state.images.items[data.imageId];
|
|
7438
8533
|
if (!isPlainObject(image) || image.type === "folder") {
|
|
@@ -8246,6 +9341,30 @@ const findReferencedFileUsage = ({ state, fileId }) => {
|
|
|
8246
9341
|
}
|
|
8247
9342
|
}
|
|
8248
9343
|
|
|
9344
|
+
for (const [spritesheetId, spritesheet] of Object.entries(
|
|
9345
|
+
state.spritesheets.items,
|
|
9346
|
+
)) {
|
|
9347
|
+
if (spritesheet.type !== "spritesheet") {
|
|
9348
|
+
continue;
|
|
9349
|
+
}
|
|
9350
|
+
|
|
9351
|
+
if (spritesheet.fileId === fileId) {
|
|
9352
|
+
return {
|
|
9353
|
+
kind: "spritesheet",
|
|
9354
|
+
field: "fileId",
|
|
9355
|
+
ownerId: spritesheetId,
|
|
9356
|
+
};
|
|
9357
|
+
}
|
|
9358
|
+
|
|
9359
|
+
if (spritesheet.thumbnailFileId === fileId) {
|
|
9360
|
+
return {
|
|
9361
|
+
kind: "spritesheet",
|
|
9362
|
+
field: "thumbnailFileId",
|
|
9363
|
+
ownerId: spritesheetId,
|
|
9364
|
+
};
|
|
9365
|
+
}
|
|
9366
|
+
}
|
|
9367
|
+
|
|
8249
9368
|
for (const [soundId, sound] of Object.entries(state.sounds.items)) {
|
|
8250
9369
|
if (sound.type !== "sound") {
|
|
8251
9370
|
continue;
|
|
@@ -8439,6 +9558,108 @@ const COMMAND_DEFINITIONS = [
|
|
|
8439
9558
|
}
|
|
8440
9559
|
},
|
|
8441
9560
|
}),
|
|
9561
|
+
...createFolderedCollectionCommandDefinitions({
|
|
9562
|
+
familyName: "spritesheet",
|
|
9563
|
+
collectionKey: "spritesheets",
|
|
9564
|
+
idField: "spritesheetId",
|
|
9565
|
+
itemLabel: "spritesheet item",
|
|
9566
|
+
createDataValidator: validateSpritesheetCreateData,
|
|
9567
|
+
updateDataValidator: validateSpritesheetUpdateData,
|
|
9568
|
+
createItem: ({ payload }) => ({
|
|
9569
|
+
id: payload.spritesheetId,
|
|
9570
|
+
type: payload.data.type,
|
|
9571
|
+
name: payload.data.name,
|
|
9572
|
+
...(payload.data.description !== undefined
|
|
9573
|
+
? {
|
|
9574
|
+
description: payload.data.description,
|
|
9575
|
+
}
|
|
9576
|
+
: {}),
|
|
9577
|
+
...(payload.data.type === "spritesheet"
|
|
9578
|
+
? {
|
|
9579
|
+
fileId: payload.data.fileId,
|
|
9580
|
+
...(payload.data.thumbnailFileId !== undefined
|
|
9581
|
+
? {
|
|
9582
|
+
thumbnailFileId: payload.data.thumbnailFileId,
|
|
9583
|
+
}
|
|
9584
|
+
: {}),
|
|
9585
|
+
...(payload.data.fileType !== undefined
|
|
9586
|
+
? {
|
|
9587
|
+
fileType: payload.data.fileType,
|
|
9588
|
+
}
|
|
9589
|
+
: {}),
|
|
9590
|
+
...(payload.data.fileSize !== undefined
|
|
9591
|
+
? {
|
|
9592
|
+
fileSize: payload.data.fileSize,
|
|
9593
|
+
}
|
|
9594
|
+
: {}),
|
|
9595
|
+
...(payload.data.sheetWidth !== undefined
|
|
9596
|
+
? {
|
|
9597
|
+
sheetWidth: payload.data.sheetWidth,
|
|
9598
|
+
}
|
|
9599
|
+
: {}),
|
|
9600
|
+
...(payload.data.sheetHeight !== undefined
|
|
9601
|
+
? {
|
|
9602
|
+
sheetHeight: payload.data.sheetHeight,
|
|
9603
|
+
}
|
|
9604
|
+
: {}),
|
|
9605
|
+
...(payload.data.frameCount !== undefined
|
|
9606
|
+
? {
|
|
9607
|
+
frameCount: payload.data.frameCount,
|
|
9608
|
+
}
|
|
9609
|
+
: {}),
|
|
9610
|
+
...(payload.data.width !== undefined
|
|
9611
|
+
? {
|
|
9612
|
+
width: payload.data.width,
|
|
9613
|
+
}
|
|
9614
|
+
: {}),
|
|
9615
|
+
...(payload.data.height !== undefined
|
|
9616
|
+
? {
|
|
9617
|
+
height: payload.data.height,
|
|
9618
|
+
}
|
|
9619
|
+
: {}),
|
|
9620
|
+
jsonData: structuredClone(payload.data.jsonData),
|
|
9621
|
+
animations: structuredClone(payload.data.animations),
|
|
9622
|
+
}
|
|
9623
|
+
: {}),
|
|
9624
|
+
}),
|
|
9625
|
+
validateCreateState: ({ state, payload }) => {
|
|
9626
|
+
if (payload.data.type !== "spritesheet") {
|
|
9627
|
+
return;
|
|
9628
|
+
}
|
|
9629
|
+
|
|
9630
|
+
return validateReferencedFilesInData({
|
|
9631
|
+
state,
|
|
9632
|
+
data: payload.data,
|
|
9633
|
+
fields: ["fileId", "thumbnailFileId"],
|
|
9634
|
+
details: {
|
|
9635
|
+
spritesheetId: payload.spritesheetId,
|
|
9636
|
+
},
|
|
9637
|
+
});
|
|
9638
|
+
},
|
|
9639
|
+
validateUpdateState: ({ state, payload, currentItem }) => {
|
|
9640
|
+
if (
|
|
9641
|
+
currentItem.type === "folder" &&
|
|
9642
|
+
Object.keys(payload.data).some(
|
|
9643
|
+
(key) => key !== "name" && key !== "description",
|
|
9644
|
+
)
|
|
9645
|
+
) {
|
|
9646
|
+
return invalidPrecondition(
|
|
9647
|
+
"folder spritesheet items cannot update spritesheet fields",
|
|
9648
|
+
);
|
|
9649
|
+
}
|
|
9650
|
+
|
|
9651
|
+
if (currentItem.type === "spritesheet") {
|
|
9652
|
+
return validateReferencedFilesInData({
|
|
9653
|
+
state,
|
|
9654
|
+
data: payload.data,
|
|
9655
|
+
fields: ["fileId", "thumbnailFileId"],
|
|
9656
|
+
details: {
|
|
9657
|
+
spritesheetId: payload.spritesheetId,
|
|
9658
|
+
},
|
|
9659
|
+
});
|
|
9660
|
+
}
|
|
9661
|
+
},
|
|
9662
|
+
}),
|
|
8442
9663
|
{
|
|
8443
9664
|
type: "story.update",
|
|
8444
9665
|
validatePayload: ({ payload }) => {
|
|
@@ -12127,6 +13348,63 @@ const COMMAND_DEFINITIONS = [
|
|
|
12127
13348
|
return state;
|
|
12128
13349
|
},
|
|
12129
13350
|
},
|
|
13351
|
+
...createFolderedCollectionCommandDefinitions({
|
|
13352
|
+
familyName: "particle",
|
|
13353
|
+
collectionKey: "particles",
|
|
13354
|
+
idField: "particleId",
|
|
13355
|
+
itemLabel: "particle item",
|
|
13356
|
+
createDataValidator: validateParticleCreateData,
|
|
13357
|
+
updateDataValidator: validateParticleUpdateData,
|
|
13358
|
+
createItem: ({ payload }) => {
|
|
13359
|
+
const item = {
|
|
13360
|
+
id: payload.particleId,
|
|
13361
|
+
type: payload.data.type,
|
|
13362
|
+
name: payload.data.name,
|
|
13363
|
+
};
|
|
13364
|
+
|
|
13365
|
+
if (payload.data.description !== undefined) {
|
|
13366
|
+
item.description = payload.data.description;
|
|
13367
|
+
}
|
|
13368
|
+
|
|
13369
|
+
if (payload.data.type !== "particle") {
|
|
13370
|
+
return item;
|
|
13371
|
+
}
|
|
13372
|
+
|
|
13373
|
+
item.width = payload.data.width;
|
|
13374
|
+
item.height = payload.data.height;
|
|
13375
|
+
item.modules = structuredClone(payload.data.modules);
|
|
13376
|
+
|
|
13377
|
+
if (payload.data.seed !== undefined && payload.data.seed !== null) {
|
|
13378
|
+
item.seed = payload.data.seed;
|
|
13379
|
+
}
|
|
13380
|
+
|
|
13381
|
+
return item;
|
|
13382
|
+
},
|
|
13383
|
+
updateItem: ({ currentItem, payload }) => {
|
|
13384
|
+
const nextItem = {
|
|
13385
|
+
...structuredClone(currentItem),
|
|
13386
|
+
...structuredClone(payload.data),
|
|
13387
|
+
};
|
|
13388
|
+
|
|
13389
|
+
if (payload.data.seed === null) {
|
|
13390
|
+
delete nextItem.seed;
|
|
13391
|
+
}
|
|
13392
|
+
|
|
13393
|
+
return nextItem;
|
|
13394
|
+
},
|
|
13395
|
+
validateUpdateState: ({ payload, currentItem }) => {
|
|
13396
|
+
if (
|
|
13397
|
+
currentItem.type === "folder" &&
|
|
13398
|
+
Object.keys(payload.data).some(
|
|
13399
|
+
(key) => key !== "name" && key !== "description",
|
|
13400
|
+
)
|
|
13401
|
+
) {
|
|
13402
|
+
return invalidPrecondition(
|
|
13403
|
+
"folder particle items cannot update particle fields",
|
|
13404
|
+
);
|
|
13405
|
+
}
|
|
13406
|
+
},
|
|
13407
|
+
}),
|
|
12130
13408
|
...createFolderedCollectionCommandDefinitions({
|
|
12131
13409
|
familyName: "transform",
|
|
12132
13410
|
collectionKey: "transforms",
|
|
@@ -14134,8 +15412,11 @@ export const validateAgainstState = ({ state, command }) => {
|
|
|
14134
15412
|
export const processCommand = ({ state, command }) => {
|
|
14135
15413
|
return captureValidation(() => {
|
|
14136
15414
|
const normalizedState = normalizeStateCollections(state);
|
|
14137
|
-
const
|
|
14138
|
-
typeof command?.type === "string" &&
|
|
15415
|
+
const shouldMaterializeNormalizedState =
|
|
15416
|
+
typeof command?.type === "string" &&
|
|
15417
|
+
(command.type.startsWith("control.") ||
|
|
15418
|
+
command.type.startsWith("spritesheet.") ||
|
|
15419
|
+
command.type.startsWith("particle."));
|
|
14139
15420
|
|
|
14140
15421
|
if (!isPlainObject(command)) {
|
|
14141
15422
|
return invalidPrecondition("command must be an object");
|
|
@@ -14156,7 +15437,7 @@ export const processCommand = ({ state, command }) => {
|
|
|
14156
15437
|
|
|
14157
15438
|
const nextState = definition.reduce({
|
|
14158
15439
|
state: structuredClone(
|
|
14159
|
-
|
|
15440
|
+
shouldMaterializeNormalizedState ? normalizedState : state,
|
|
14160
15441
|
),
|
|
14161
15442
|
payload: command.payload,
|
|
14162
15443
|
});
|
|
@@ -14166,7 +15447,7 @@ export const processCommand = ({ state, command }) => {
|
|
|
14166
15447
|
|
|
14167
15448
|
const finalState =
|
|
14168
15449
|
nextState === undefined
|
|
14169
|
-
?
|
|
15450
|
+
? shouldMaterializeNormalizedState
|
|
14170
15451
|
? normalizedState
|
|
14171
15452
|
: state
|
|
14172
15453
|
: nextState;
|