@routevn/creator-model 1.5.0 → 1.5.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/package.json +1 -1
  3. package/src/model.js +127 -0
package/README.md CHANGED
@@ -293,6 +293,7 @@ Currently implemented command types:
293
293
  - `layout.update`
294
294
  - `layout.delete`
295
295
  - `layout.move`
296
+ - `layout.schema.upgrade`
296
297
  - `character.sprite.create`
297
298
  - `character.sprite.update`
298
299
  - `character.sprite.delete`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routevn/creator-model",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/model.js CHANGED
@@ -40,7 +40,12 @@ const LINE_UPDATE_ACTIONS_PRESERVE_PATHS = ["dialogue.content"];
40
40
  const LINE_UPDATE_ACTIONS_PRESERVE_PATHS_SET = new Set(
41
41
  LINE_UPDATE_ACTIONS_PRESERVE_PATHS,
42
42
  );
43
+ const CURRENT_LAYOUT_SCHEMA_VERSION = 2;
43
44
  const isPositiveFiniteNumber = (value) => isFiniteNumber(value) && value > 0;
45
+ const normalizeLayoutSchemaVersion = (value) =>
46
+ Number.isInteger(value) && value >= 1 ? value : 1;
47
+ const isSupportedLayoutSchemaVersion = (value) =>
48
+ value === CURRENT_LAYOUT_SCHEMA_VERSION;
44
49
  const createEmptyCollectionState = () => ({
45
50
  items: {},
46
51
  tree: [],
@@ -4997,6 +5002,7 @@ const validateLayoutItems = ({ items, path, errorFactory }) => {
4997
5002
  "description",
4998
5003
  "tagIds",
4999
5004
  "layoutType",
5005
+ "layoutSchemaVersion",
5000
5006
  "isFragment",
5001
5007
  "thumbnailFileId",
5002
5008
  "preview",
@@ -5079,6 +5085,16 @@ const validateLayoutItems = ({ items, path, errorFactory }) => {
5079
5085
  );
5080
5086
  }
5081
5087
 
5088
+ if (
5089
+ item.layoutSchemaVersion !== undefined &&
5090
+ !isSupportedLayoutSchemaVersion(item.layoutSchemaVersion)
5091
+ ) {
5092
+ return invalidFromErrorFactory(
5093
+ errorFactory,
5094
+ `${itemPath}.layoutSchemaVersion must be ${CURRENT_LAYOUT_SCHEMA_VERSION} when provided`,
5095
+ );
5096
+ }
5097
+
5082
5098
  if (
5083
5099
  item.isFragment !== undefined &&
5084
5100
  typeof item.isFragment !== "boolean"
@@ -10520,6 +10536,7 @@ const validateLayoutCreateData = ({ data, errorFactory }) => {
10520
10536
  "description",
10521
10537
  "tagIds",
10522
10538
  "layoutType",
10539
+ "layoutSchemaVersion",
10523
10540
  "isFragment",
10524
10541
  "thumbnailFileId",
10525
10542
  "preview",
@@ -10587,6 +10604,16 @@ const validateLayoutCreateData = ({ data, errorFactory }) => {
10587
10604
  );
10588
10605
  }
10589
10606
 
10607
+ if (
10608
+ data.layoutSchemaVersion !== undefined &&
10609
+ !isSupportedLayoutSchemaVersion(data.layoutSchemaVersion)
10610
+ ) {
10611
+ return invalidFromErrorFactory(
10612
+ errorFactory,
10613
+ `payload.data.layoutSchemaVersion must be ${CURRENT_LAYOUT_SCHEMA_VERSION} when provided`,
10614
+ );
10615
+ }
10616
+
10590
10617
  if (data.isFragment !== undefined && typeof data.isFragment !== "boolean") {
10591
10618
  return invalidFromErrorFactory(
10592
10619
  errorFactory,
@@ -11393,6 +11420,32 @@ const createEmptyNestedCollection = () => ({
11393
11420
  tree: [],
11394
11421
  });
11395
11422
 
11423
+ const isDirectedLayoutContainer = (item) =>
11424
+ item?.direction === "horizontal" || item?.direction === "vertical";
11425
+
11426
+ const upgradeLayoutTreeOrder = ({ nodes, items, parentItem } = {}) => {
11427
+ const sourceNodes = Array.isArray(nodes) ? nodes : [];
11428
+ const orderedNodes = isDirectedLayoutContainer(parentItem)
11429
+ ? sourceNodes
11430
+ : [...sourceNodes].reverse();
11431
+
11432
+ return orderedNodes.map((node) => {
11433
+ const nextNode = {
11434
+ ...node,
11435
+ };
11436
+
11437
+ if (Array.isArray(node?.children) && node.children.length > 0) {
11438
+ nextNode.children = upgradeLayoutTreeOrder({
11439
+ nodes: node.children,
11440
+ items,
11441
+ parentItem: items?.[node.id],
11442
+ });
11443
+ }
11444
+
11445
+ return nextNode;
11446
+ });
11447
+ };
11448
+
11396
11449
  const findSectionLocation = ({ state, sectionId }) => {
11397
11450
  for (const [sceneId, scene] of Object.entries(state.scenes.items)) {
11398
11451
  if (scene?.type !== "scene") {
@@ -16866,6 +16919,11 @@ const COMMAND_DEFINITIONS = [
16866
16919
  }
16867
16920
  : {}),
16868
16921
  layoutType: payload.data.layoutType,
16922
+ ...(payload.data.layoutSchemaVersion !== undefined
16923
+ ? {
16924
+ layoutSchemaVersion: payload.data.layoutSchemaVersion,
16925
+ }
16926
+ : {}),
16869
16927
  isFragment: payload.data.isFragment,
16870
16928
  ...(payload.data.thumbnailFileId !== undefined
16871
16929
  ? {
@@ -16954,6 +17012,75 @@ const COMMAND_DEFINITIONS = [
16954
17012
  }
16955
17013
  },
16956
17014
  }),
17015
+ {
17016
+ type: "layout.schema.upgrade",
17017
+ validatePayload: ({ payload }) => {
17018
+ {
17019
+ const result = validateExactKeys({
17020
+ value: payload,
17021
+ expectedKeys: ["layoutIds", "targetSchemaVersion"],
17022
+ path: "payload",
17023
+ errorFactory: createPayloadValidationError,
17024
+ });
17025
+ if (result?.valid === false) {
17026
+ return result;
17027
+ }
17028
+ }
17029
+
17030
+ {
17031
+ const result = validateRequiredUniqueIdArray({
17032
+ value: payload.layoutIds,
17033
+ path: "payload.layoutIds",
17034
+ errorFactory: createPayloadValidationError,
17035
+ });
17036
+ if (result?.valid === false) {
17037
+ return result;
17038
+ }
17039
+ }
17040
+
17041
+ if (payload.targetSchemaVersion !== CURRENT_LAYOUT_SCHEMA_VERSION) {
17042
+ return invalidPayload(
17043
+ `payload.targetSchemaVersion must be ${CURRENT_LAYOUT_SCHEMA_VERSION}`,
17044
+ );
17045
+ }
17046
+
17047
+ return VALID_RESULT;
17048
+ },
17049
+ validateAgainstState: ({ state, payload }) => {
17050
+ for (const layoutId of payload.layoutIds) {
17051
+ const layout = state.layouts.items[layoutId];
17052
+ if (!isPlainObject(layout) || layout.type !== "layout") {
17053
+ return invalidPrecondition(
17054
+ "payload.layoutIds must reference existing layouts",
17055
+ {
17056
+ layoutId,
17057
+ },
17058
+ );
17059
+ }
17060
+ }
17061
+
17062
+ return VALID_RESULT;
17063
+ },
17064
+ reduce: ({ state, payload }) => {
17065
+ for (const layoutId of payload.layoutIds) {
17066
+ const layout = state.layouts.items[layoutId];
17067
+ if (
17068
+ normalizeLayoutSchemaVersion(layout.layoutSchemaVersion) >=
17069
+ payload.targetSchemaVersion
17070
+ ) {
17071
+ continue;
17072
+ }
17073
+
17074
+ layout.elements.tree = upgradeLayoutTreeOrder({
17075
+ nodes: layout.elements.tree,
17076
+ items: layout.elements.items,
17077
+ });
17078
+ layout.layoutSchemaVersion = payload.targetSchemaVersion;
17079
+ }
17080
+
17081
+ return state;
17082
+ },
17083
+ },
16957
17084
  ...createFolderedCollectionCommandDefinitions({
16958
17085
  familyName: "control",
16959
17086
  collectionKey: "controls",