kintone-migrator 0.35.2 → 0.35.3

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/dist/index.mjs CHANGED
@@ -121,7 +121,6 @@ const ProcessManagementErrorCode = {
121
121
  PmInvalidEntityType: "PM_INVALID_ENTITY_TYPE",
122
122
  PmInvalidBooleanField: "PM_INVALID_BOOLEAN_FIELD",
123
123
  PmInvalidActionReference: "PM_INVALID_ACTION_REFERENCE",
124
- PmDuplicateActionName: "PM_DUPLICATE_ACTION_NAME",
125
124
  PmUnresolvedConflict: "PM_UNRESOLVED_CONFLICT"
126
125
  };
127
126
  //#endregion
@@ -6811,6 +6810,16 @@ async function applyPlugin({ container }) {
6811
6810
  };
6812
6811
  }
6813
6812
  //#endregion
6813
+ //#region src/core/domain/processManagement/valueObject.ts
6814
+ /**
6815
+ * Human-readable label of an action, e.g. `申請する (未申請 → 部長承認待ち)`.
6816
+ * The name alone is ambiguous: kintone allows several actions with the same
6817
+ * name, both from different states and as conditional branches from one state.
6818
+ */
6819
+ function describeProcessAction(action) {
6820
+ return `${action.name} (${action.from} → ${action.to})`;
6821
+ }
6822
+ //#endregion
6814
6823
  //#region src/core/domain/processManagement/services/configParser.ts
6815
6824
  const VALID_ASSIGNEE_TYPES$1 = /* @__PURE__ */ new Set([
6816
6825
  "ONE",
@@ -6890,15 +6899,10 @@ const ProcessManagementConfigParser = { parse: (parsed) => {
6890
6899
  for (const [name, value] of Object.entries(rawStates)) states[name] = parseState(value, name);
6891
6900
  if (!Array.isArray(obj.actions) && obj.actions !== void 0) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidConfigStructure, "Config \"actions\" must be an array");
6892
6901
  const actions = (Array.isArray(obj.actions) ? obj.actions : []).map((item, i) => parseAction(item, i));
6893
- const actionNames = /* @__PURE__ */ new Set();
6894
- for (const action of actions) {
6895
- if (actionNames.has(action.name)) throw new BusinessRuleError(ProcessManagementErrorCode.PmDuplicateActionName, `Duplicate action name: "${action.name}"`);
6896
- actionNames.add(action.name);
6897
- }
6898
6902
  const stateNames = new Set(Object.keys(states));
6899
6903
  for (const action of actions) {
6900
- if (!stateNames.has(action.from)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidActionReference, `Action "${action.name}" references unknown "from" state: "${action.from}"`);
6901
- if (!stateNames.has(action.to)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidActionReference, `Action "${action.name}" references unknown "to" state: "${action.to}"`);
6904
+ if (!stateNames.has(action.from)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidActionReference, `Action "${describeProcessAction(action)}" references unknown "from" state: "${action.from}"`);
6905
+ if (!stateNames.has(action.to)) throw new BusinessRuleError(ProcessManagementErrorCode.PmInvalidActionReference, `Action "${describeProcessAction(action)}" references unknown "to" state: "${action.to}"`);
6902
6906
  }
6903
6907
  return {
6904
6908
  enable,
@@ -9363,6 +9367,56 @@ function groupByKey(items, keyFn) {
9363
9367
  return map;
9364
9368
  }
9365
9369
  //#endregion
9370
+ //#region src/lib/pairByKeyInOrder.ts
9371
+ /**
9372
+ * Pairs local and remote items by key. Items sharing a key are matched by
9373
+ * their order of appearance, so the n-th local item with a key pairs with the
9374
+ * n-th remote item with that key.
9375
+ *
9376
+ * Pairs are returned grouped by key: keys in local first-appearance order,
9377
+ * then remote-only keys in remote first-appearance order.
9378
+ */
9379
+ function pairByKeyInOrder(local, remote, keyFn) {
9380
+ const localGroups = groupByKey(local, keyFn);
9381
+ const remoteGroups = groupByKey(remote, keyFn);
9382
+ const pairs = [];
9383
+ for (const [key, localItems] of localGroups) {
9384
+ const remoteItems = remoteGroups.get(key) ?? [];
9385
+ const length = Math.max(localItems.length, remoteItems.length);
9386
+ for (let index = 0; index < length; index++) if (index >= remoteItems.length) pairs.push({
9387
+ kind: "localOnly",
9388
+ key,
9389
+ index,
9390
+ local: localItems[index]
9391
+ });
9392
+ else if (index >= localItems.length) pairs.push({
9393
+ kind: "remoteOnly",
9394
+ key,
9395
+ index,
9396
+ remote: remoteItems[index]
9397
+ });
9398
+ else pairs.push({
9399
+ kind: "both",
9400
+ key,
9401
+ index,
9402
+ local: localItems[index],
9403
+ remote: remoteItems[index]
9404
+ });
9405
+ }
9406
+ for (const [key, remoteItems] of remoteGroups) {
9407
+ if (localGroups.has(key)) continue;
9408
+ remoteItems.forEach((remoteItem, index) => {
9409
+ pairs.push({
9410
+ kind: "remoteOnly",
9411
+ key,
9412
+ index,
9413
+ remote: remoteItem
9414
+ });
9415
+ });
9416
+ }
9417
+ return pairs;
9418
+ }
9419
+ //#endregion
9366
9420
  //#region src/core/domain/notification/services/diffDetector.ts
9367
9421
  function serializeEntity$1(entity) {
9368
9422
  return `${entity.type}:${entity.code}`;
@@ -9416,14 +9470,6 @@ function compareGeneralSection(local, remote) {
9416
9470
  });
9417
9471
  return entries;
9418
9472
  }
9419
- /**
9420
- * Groups per-record notifications by filterCond. Multiple notifications can share
9421
- * the same filterCond, so notifications within a group are compared by position
9422
- * (index-based matching).
9423
- */
9424
- function buildPerRecordMultiMap(notifications) {
9425
- return groupByKey(notifications, (n) => n.filterCond);
9426
- }
9427
9473
  function perRecordLabel(notif) {
9428
9474
  return notif.title || notif.filterCond || "(empty filter)";
9429
9475
  }
@@ -9445,43 +9491,30 @@ function describeReminderChanges(local, remote) {
9445
9491
  }
9446
9492
  function comparePerRecordSection(local, remote) {
9447
9493
  const entries = [];
9448
- const localMulti = buildPerRecordMultiMap(local);
9449
- const remoteMulti = buildPerRecordMultiMap(remote);
9450
- for (const [key, localNotifs] of localMulti) {
9451
- const remoteNotifs = remoteMulti.get(key) ?? [];
9452
- const maxLen = Math.max(localNotifs.length, remoteNotifs.length);
9453
- for (let i = 0; i < maxLen; i++) {
9454
- const localNotif = localNotifs[i];
9455
- const remoteNotif = remoteNotifs[i];
9456
- if (localNotif && !remoteNotif) entries.push({
9494
+ for (const pair of pairByKeyInOrder(local, remote, (n) => n.filterCond)) switch (pair.kind) {
9495
+ case "localOnly":
9496
+ entries.push({
9457
9497
  type: "added",
9458
9498
  section: "perRecord",
9459
- name: perRecordLabel(localNotif),
9499
+ name: perRecordLabel(pair.local),
9460
9500
  details: "new notification"
9461
9501
  });
9462
- else if (!localNotif && remoteNotif) entries.push({
9502
+ break;
9503
+ case "remoteOnly":
9504
+ entries.push({
9463
9505
  type: "deleted",
9464
9506
  section: "perRecord",
9465
- name: perRecordLabel(remoteNotif),
9507
+ name: perRecordLabel(pair.remote),
9466
9508
  details: "removed"
9467
9509
  });
9468
- else if (localNotif && remoteNotif && !deepEqual(localNotif, remoteNotif)) {
9469
- const diffs = describePerRecordChanges(localNotif, remoteNotif);
9470
- entries.push({
9471
- type: "modified",
9472
- section: "perRecord",
9473
- name: perRecordLabel(localNotif),
9474
- details: diffs
9475
- });
9476
- }
9477
- }
9510
+ break;
9511
+ case "both": if (!deepEqual(pair.local, pair.remote)) entries.push({
9512
+ type: "modified",
9513
+ section: "perRecord",
9514
+ name: perRecordLabel(pair.local),
9515
+ details: describePerRecordChanges(pair.local, pair.remote)
9516
+ });
9478
9517
  }
9479
- for (const [key, remoteNotifs] of remoteMulti) if (!localMulti.has(key)) for (const remoteNotif of remoteNotifs) entries.push({
9480
- type: "deleted",
9481
- section: "perRecord",
9482
- name: perRecordLabel(remoteNotif),
9483
- details: "removed"
9484
- });
9485
9518
  return entries;
9486
9519
  }
9487
9520
  function compareReminderSection(local, remote) {
@@ -9637,8 +9670,6 @@ function isExecutableUserEqual(a, b) {
9637
9670
  }
9638
9671
  function compareActions(localAction, remoteAction) {
9639
9672
  const diffs = [];
9640
- if (localAction.from !== remoteAction.from) diffs.push(`from: ${remoteAction.from} -> ${localAction.from}`);
9641
- if (localAction.to !== remoteAction.to) diffs.push(`to: ${remoteAction.to} -> ${localAction.to}`);
9642
9673
  if (localAction.filterCond !== remoteAction.filterCond) diffs.push(`filterCond: "${remoteAction.filterCond}" -> "${localAction.filterCond}"`);
9643
9674
  if (localAction.type !== remoteAction.type) diffs.push(`type: ${remoteAction.type} -> ${localAction.type}`);
9644
9675
  if (!isExecutableUserEqual(localAction.executableUser, remoteAction.executableUser)) diffs.push(`executableUser: ${formatValue(remoteAction.executableUser)} -> ${formatValue(localAction.executableUser)}`);
@@ -9674,33 +9705,52 @@ function compareStates(local, remote, entries) {
9674
9705
  details: `assignee: ${remote.states[name].assignee.type}`
9675
9706
  });
9676
9707
  }
9708
+ /**
9709
+ * Identifies an action by name + from + to. kintone allows same-named actions
9710
+ * both from different states and as conditional branches from one state.
9711
+ * Repeats of the whole triple are not rejected either, so actions sharing a
9712
+ * triple are told apart by their order of appearance.
9713
+ */
9714
+ function transitionKey(action) {
9715
+ return JSON.stringify([
9716
+ action.name,
9717
+ action.from,
9718
+ action.to
9719
+ ]);
9720
+ }
9721
+ function actionLabel(action, index) {
9722
+ const label = describeProcessAction(action);
9723
+ return index === 0 ? label : `${label} #${index + 1}`;
9724
+ }
9677
9725
  function compareActionEntries(local, remote, entries) {
9678
- const localActionMap = new Map(local.actions.map((a) => [a.name, a]));
9679
- const remoteActionMap = new Map(remote.actions.map((a) => [a.name, a]));
9680
- for (const [name, localAction] of localActionMap) {
9681
- const remoteAction = remoteActionMap.get(name);
9682
- if (!remoteAction) entries.push({
9683
- type: "added",
9684
- category: "action",
9685
- name,
9686
- details: `${localAction.from} -> ${localAction.to}`
9687
- });
9688
- else {
9689
- const actionDiffs = compareActions(localAction, remoteAction);
9726
+ for (const pair of pairByKeyInOrder(local.actions, remote.actions, transitionKey)) switch (pair.kind) {
9727
+ case "localOnly":
9728
+ entries.push({
9729
+ type: "added",
9730
+ category: "action",
9731
+ name: actionLabel(pair.local, pair.index),
9732
+ details: `filterCond: "${pair.local.filterCond}"`
9733
+ });
9734
+ break;
9735
+ case "remoteOnly":
9736
+ entries.push({
9737
+ type: "deleted",
9738
+ category: "action",
9739
+ name: actionLabel(pair.remote, pair.index),
9740
+ details: `filterCond: "${pair.remote.filterCond}"`
9741
+ });
9742
+ break;
9743
+ case "both": {
9744
+ const actionDiffs = compareActions(pair.local, pair.remote);
9690
9745
  if (actionDiffs.length > 0) entries.push({
9691
9746
  type: "modified",
9692
9747
  category: "action",
9693
- name,
9748
+ name: actionLabel(pair.local, pair.index),
9694
9749
  details: actionDiffs.join("\n")
9695
9750
  });
9751
+ break;
9696
9752
  }
9697
9753
  }
9698
- for (const [name, remoteAction] of remoteActionMap) if (!localActionMap.has(name)) entries.push({
9699
- type: "deleted",
9700
- category: "action",
9701
- name,
9702
- details: `${remoteAction.from} -> ${remoteAction.to}`
9703
- });
9704
9754
  }
9705
9755
  function compareConfigs(local, remote) {
9706
9756
  const entries = [];
@@ -9758,24 +9808,27 @@ function describeRight(right) {
9758
9808
  });
9759
9809
  return perEntity.length > 0 ? perEntity.join(", ") : "no entities";
9760
9810
  }
9761
- function compareRightsForFilter(filterCond, localRights, remoteRights, entries) {
9762
- const maxLen = Math.max(localRights.length, remoteRights.length);
9763
- for (let i = 0; i < maxLen; i++) {
9764
- const localRight = localRights[i];
9765
- const remoteRight = remoteRights[i];
9766
- if (localRight && !remoteRight) entries.push({
9767
- type: "added",
9768
- filterCond,
9769
- details: describeRight(localRight)
9770
- });
9771
- else if (!localRight && remoteRight) entries.push({
9772
- type: "deleted",
9773
- filterCond,
9774
- details: describeRight(remoteRight)
9775
- });
9776
- else if (localRight && remoteRight) {
9777
- if (!isRightEqual(localRight, remoteRight)) {
9778
- const detail = localRight.entities.length !== remoteRight.entities.length ? `entities: ${remoteRight.entities.length} -> ${localRight.entities.length}` : `entities: ${describeRight(remoteRight)} -> ${describeRight(localRight)}`;
9811
+ const RecordPermissionDiffDetector = { detect: (local, remote) => {
9812
+ const entries = [];
9813
+ for (const pair of pairByKeyInOrder(local.rights, remote.rights, (r) => r.filterCond)) {
9814
+ const filterCond = pair.key;
9815
+ switch (pair.kind) {
9816
+ case "localOnly":
9817
+ entries.push({
9818
+ type: "added",
9819
+ filterCond,
9820
+ details: describeRight(pair.local)
9821
+ });
9822
+ break;
9823
+ case "remoteOnly":
9824
+ entries.push({
9825
+ type: "deleted",
9826
+ filterCond,
9827
+ details: describeRight(pair.remote)
9828
+ });
9829
+ break;
9830
+ case "both": if (!isRightEqual(pair.local, pair.remote)) {
9831
+ const detail = pair.local.entities.length !== pair.remote.entities.length ? `entities: ${pair.remote.entities.length} -> ${pair.local.entities.length}` : `entities: ${describeRight(pair.remote)} -> ${describeRight(pair.local)}`;
9779
9832
  entries.push({
9780
9833
  type: "modified",
9781
9834
  filterCond,
@@ -9784,17 +9837,6 @@ function compareRightsForFilter(filterCond, localRights, remoteRights, entries)
9784
9837
  }
9785
9838
  }
9786
9839
  }
9787
- }
9788
- const RecordPermissionDiffDetector = { detect: (local, remote) => {
9789
- const entries = [];
9790
- const localMulti = groupByKey(local.rights, (r) => r.filterCond);
9791
- const remoteMulti = groupByKey(remote.rights, (r) => r.filterCond);
9792
- for (const [filterCond, localRights] of localMulti) compareRightsForFilter(filterCond, localRights, remoteMulti.get(filterCond) ?? [], entries);
9793
- for (const [filterCond, remoteRights] of remoteMulti) if (!localMulti.has(filterCond)) for (const remoteRight of remoteRights) entries.push({
9794
- type: "deleted",
9795
- filterCond,
9796
- details: describeRight(remoteRight)
9797
- });
9798
9840
  return buildDiffResult(entries);
9799
9841
  } };
9800
9842
  //#endregion