@revisium/schema-toolkit 0.18.0 → 0.19.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.
@@ -1412,12 +1412,7 @@ var ChangeCoalescer = class {
1412
1412
  hasParentChange(change, allChanges, path) {
1413
1413
  for (const other of allChanges) {
1414
1414
  if (other === change) continue;
1415
- if (other.type === "modified") {
1416
- if (!this.isTypeChangeReplacement(other)) {
1417
- continue;
1418
- }
1419
- }
1420
- if (change.type === "moved" && other.type === "added") {
1415
+ if (this.shouldSkipParentCandidate(change, other)) {
1421
1416
  continue;
1422
1417
  }
1423
1418
  const otherPath = this.getChangePath(other);
@@ -1427,9 +1422,24 @@ var ChangeCoalescer = class {
1427
1422
  }
1428
1423
  return false;
1429
1424
  }
1425
+ shouldSkipParentCandidate(change, other) {
1426
+ if (other.type === "modified" && !this.isTypeChangeReplacement(other)) {
1427
+ return true;
1428
+ }
1429
+ if (change.type === "moved" && other.type === "added") {
1430
+ return true;
1431
+ }
1432
+ if (change.type === "moved" && other.type === "moved") {
1433
+ return this.hasIndependentRename(change);
1434
+ }
1435
+ return false;
1436
+ }
1430
1437
  isTypeChangeReplacement(change) {
1431
1438
  return change.baseNode.nodeType() !== change.currentNode.nodeType();
1432
1439
  }
1440
+ hasIndependentRename(change) {
1441
+ return change.baseNode.name() !== change.currentNode.name();
1442
+ }
1433
1443
  isAffectedByMove(change, movedPaths) {
1434
1444
  if (change.type !== "modified") {
1435
1445
  return false;
@@ -2019,19 +2029,31 @@ var PatchGenerator = class {
2019
2029
  return { prerequisiteAdds, regularAdds };
2020
2030
  }
2021
2031
  generateMovePatches(moved) {
2032
+ const movedNodeIds = this.collectMovedNodeIds(moved);
2033
+ const sorted = this.sortMovesParentFirst(moved);
2022
2034
  const patches = [];
2023
- for (const change of moved) {
2035
+ const appliedMoves = [];
2036
+ for (const change of sorted) {
2024
2037
  const basePath = this.baseTree.pathOf(change.baseNode.id());
2025
2038
  const currentPath = this.currentTree.pathOf(change.currentNode.id());
2039
+ const adjustedFrom = this.adjustFromPath(
2040
+ basePath.asJsonPointer(),
2041
+ appliedMoves
2042
+ );
2026
2043
  patches.push({
2027
2044
  op: "move",
2028
- from: basePath.asJsonPointer(),
2045
+ from: adjustedFrom,
2029
2046
  path: currentPath.asJsonPointer()
2030
2047
  });
2048
+ appliedMoves.push({
2049
+ from: adjustedFrom,
2050
+ to: currentPath.asJsonPointer()
2051
+ });
2031
2052
  const modifyPatch = this.generateModifyAfterMove(
2032
2053
  change.baseNode,
2033
2054
  change.currentNode,
2034
- currentPath.asJsonPointer()
2055
+ currentPath.asJsonPointer(),
2056
+ movedNodeIds
2035
2057
  );
2036
2058
  if (modifyPatch) {
2037
2059
  patches.push(modifyPatch);
@@ -2039,10 +2061,29 @@ var PatchGenerator = class {
2039
2061
  }
2040
2062
  return patches;
2041
2063
  }
2042
- generateModifyAfterMove(baseNode, currentNode, currentPath) {
2064
+ sortMovesParentFirst(moved) {
2065
+ return [...moved].sort((a, b) => {
2066
+ const pathA = this.baseTree.pathOf(a.baseNode.id()).asJsonPointer();
2067
+ const pathB = this.baseTree.pathOf(b.baseNode.id()).asJsonPointer();
2068
+ return pathA.length - pathB.length;
2069
+ });
2070
+ }
2071
+ adjustFromPath(fromPath, appliedMoves) {
2072
+ let adjusted = fromPath;
2073
+ for (const move of appliedMoves) {
2074
+ if (adjusted.startsWith(move.from + "/")) {
2075
+ adjusted = move.to + adjusted.slice(move.from.length);
2076
+ }
2077
+ }
2078
+ return adjusted;
2079
+ }
2080
+ generateModifyAfterMove(baseNode, currentNode, currentPath, siblingMovedIds) {
2043
2081
  if (areNodesContentEqual(currentNode, baseNode, this.context)) {
2044
2082
  return null;
2045
2083
  }
2084
+ if (this.isDifferenceExplainedByMoves(currentNode, baseNode, siblingMovedIds)) {
2085
+ return null;
2086
+ }
2046
2087
  const currentSchema = this.serializer.serializeNode(
2047
2088
  currentNode,
2048
2089
  this.currentTree
@@ -2053,6 +2094,42 @@ var PatchGenerator = class {
2053
2094
  value: currentSchema
2054
2095
  };
2055
2096
  }
2097
+ isDifferenceExplainedByMoves(currentNode, baseNode, movedIds) {
2098
+ if (!currentNode.isObject() || !baseNode.isObject()) {
2099
+ return false;
2100
+ }
2101
+ const currentProps = currentNode.properties();
2102
+ const baseProps = baseNode.properties();
2103
+ if (currentProps.length !== baseProps.length) {
2104
+ return false;
2105
+ }
2106
+ for (const prop of currentProps) {
2107
+ const matchByName = baseProps.find((b) => b.name() === prop.name());
2108
+ if (matchByName) {
2109
+ if (!this.areNodesEqualAccountingMoves(prop, matchByName, movedIds)) {
2110
+ return false;
2111
+ }
2112
+ continue;
2113
+ }
2114
+ if (!movedIds.has(prop.id())) {
2115
+ return false;
2116
+ }
2117
+ const matchById = baseProps.find((b) => b.id() === prop.id());
2118
+ if (!matchById) {
2119
+ return false;
2120
+ }
2121
+ if (!this.areNodesEqualAccountingMoves(prop, matchById, movedIds)) {
2122
+ return false;
2123
+ }
2124
+ }
2125
+ return true;
2126
+ }
2127
+ areNodesEqualAccountingMoves(currentNode, baseNode, movedIds) {
2128
+ if (areNodesContentEqual(currentNode, baseNode, this.context)) {
2129
+ return true;
2130
+ }
2131
+ return this.isDifferenceExplainedByMoves(currentNode, baseNode, movedIds);
2132
+ }
2056
2133
  generateAddPatches(added, movedNodeIds) {
2057
2134
  const patches = [];
2058
2135
  for (const change of added) {
@@ -2240,7 +2317,9 @@ var PatchEnricher = class {
2240
2317
  constructor(currentTree, baseTree) {
2241
2318
  this.currentTree = currentTree;
2242
2319
  this.baseTree = baseTree;
2320
+ this.extractors = this.buildExtractors();
2243
2321
  }
2322
+ extractors;
2244
2323
  enrich(patch) {
2245
2324
  const fieldName = this.getFieldNameFromPath(patch.path);
2246
2325
  if (patch.op === "add") {
@@ -2257,18 +2336,13 @@ var PatchEnricher = class {
2257
2336
  enrichAddPatch(patch, fieldName) {
2258
2337
  const currentNode = this.getNodeAtPath(this.currentTree, patch.path);
2259
2338
  if (!currentNode) {
2260
- return { patch, fieldName, metadataChanges: [] };
2339
+ return { patch, fieldName, propertyChanges: [] };
2261
2340
  }
2262
- const metadata = this.computeAddMetadata(currentNode);
2263
- return {
2264
- patch,
2265
- fieldName,
2266
- metadataChanges: this.computeMetadataChanges(metadata),
2267
- ...metadata
2268
- };
2341
+ const propertyChanges = this.computeAddPropertyChanges(currentNode);
2342
+ return { patch, fieldName, propertyChanges };
2269
2343
  }
2270
2344
  enrichRemovePatch(patch, fieldName) {
2271
- return { patch, fieldName, metadataChanges: [] };
2345
+ return { patch, fieldName, propertyChanges: [] };
2272
2346
  }
2273
2347
  enrichMovePatch(patch, fieldName) {
2274
2348
  const fromPath = patch.from;
@@ -2276,98 +2350,98 @@ var PatchEnricher = class {
2276
2350
  const movesIntoArray = this.movesIntoArrayBoundary(fromPath, patch.path);
2277
2351
  const baseNode = this.getNodeAtPath(this.baseTree, fromPath);
2278
2352
  const currentNode = this.getNodeAtPath(this.currentTree, patch.path);
2279
- const formulaChange = this.computeFormulaChange(baseNode, currentNode);
2280
- const metadataChanges = [];
2281
- if (formulaChange) {
2282
- metadataChanges.push("formula");
2283
- }
2353
+ const propertyChanges = this.computePropertyChanges(baseNode, currentNode);
2284
2354
  return {
2285
2355
  patch,
2286
2356
  fieldName,
2287
- metadataChanges,
2357
+ propertyChanges,
2288
2358
  isRename: isRename || void 0,
2289
- movesIntoArray: movesIntoArray || void 0,
2290
- formulaChange
2359
+ movesIntoArray: movesIntoArray || void 0
2291
2360
  };
2292
2361
  }
2293
2362
  enrichReplacePatch(patch, fieldName) {
2294
2363
  const baseNode = this.getNodeAtPath(this.baseTree, patch.path);
2295
2364
  const currentNode = this.getNodeAtPath(this.currentTree, patch.path);
2296
2365
  const isArrayMetadataPatch = baseNode?.isArray() && currentNode?.isArray();
2297
- const formulaChange = this.computeFormulaChange(baseNode, currentNode);
2298
- const defaultChange = isArrayMetadataPatch ? void 0 : this.computeDefaultChange(baseNode, currentNode);
2299
- const descriptionChange = this.computeDescriptionChange(baseNode, currentNode);
2300
- const deprecatedChange = this.computeDeprecatedChange(baseNode, currentNode);
2301
- const foreignKeyChange = this.computeForeignKeyChange(baseNode, currentNode);
2302
- const contentMediaTypeChange = this.computeContentMediaTypeChange(baseNode, currentNode);
2303
- const metadataChanges = this.computeMetadataChanges({
2304
- formulaChange,
2305
- defaultChange,
2306
- descriptionChange,
2307
- deprecatedChange,
2308
- foreignKeyChange,
2309
- contentMediaTypeChange
2310
- });
2366
+ const skipProperties = isArrayMetadataPatch ? ["default"] : [];
2367
+ const propertyChanges = this.computePropertyChanges(
2368
+ baseNode,
2369
+ currentNode,
2370
+ { skipProperties }
2371
+ );
2311
2372
  return {
2312
2373
  patch,
2313
2374
  fieldName,
2314
- metadataChanges,
2315
- typeChange: this.computeTypeChange(baseNode, currentNode, isArrayMetadataPatch),
2316
- formulaChange,
2317
- defaultChange,
2318
- descriptionChange,
2319
- deprecatedChange,
2320
- foreignKeyChange,
2321
- contentMediaTypeChange
2375
+ propertyChanges,
2376
+ typeChange: this.computeTypeChange(baseNode, currentNode, isArrayMetadataPatch)
2322
2377
  };
2323
2378
  }
2324
- computeAddMetadata(node) {
2325
- const result = {};
2326
- const formula = node.formula();
2327
- if (formula) {
2328
- result.formulaChange = {
2329
- fromFormula: void 0,
2330
- toFormula: this.getFormulaExpression(formula, this.currentTree, node.id()),
2331
- fromVersion: void 0,
2332
- toVersion: formula.version()
2333
- };
2334
- }
2335
- const defaultValue = node.defaultValue();
2336
- if (defaultValue !== void 0 && isPrimitiveDefault(defaultValue)) {
2337
- result.defaultChange = {
2338
- fromDefault: void 0,
2339
- toDefault: defaultValue
2340
- };
2341
- }
2342
- const meta = node.metadata();
2343
- if (meta.description) {
2344
- result.descriptionChange = {
2345
- fromDescription: void 0,
2346
- toDescription: meta.description
2347
- };
2348
- }
2349
- if (meta.deprecated) {
2350
- result.deprecatedChange = {
2351
- fromDeprecated: void 0,
2352
- toDeprecated: meta.deprecated
2353
- };
2354
- }
2355
- const foreignKey = node.foreignKey();
2356
- if (foreignKey) {
2357
- result.foreignKeyChange = {
2358
- fromForeignKey: void 0,
2359
- toForeignKey: foreignKey
2360
- };
2361
- }
2362
- const contentMediaType = node.contentMediaType();
2363
- if (contentMediaType) {
2364
- result.contentMediaTypeChange = {
2365
- fromContentMediaType: void 0,
2366
- toContentMediaType: contentMediaType
2367
- };
2379
+ buildExtractors() {
2380
+ return [
2381
+ {
2382
+ property: "formula",
2383
+ extract: (node, tree) => {
2384
+ const formula = node?.formula();
2385
+ if (!formula || !node) {
2386
+ return void 0;
2387
+ }
2388
+ return FormulaSerializer.serializeExpression(tree, node.id(), formula, { strict: false });
2389
+ },
2390
+ compare: (from, to) => from === to
2391
+ },
2392
+ {
2393
+ property: "default",
2394
+ extract: (node) => {
2395
+ const value = node?.defaultValue();
2396
+ return isPrimitiveDefault(value) ? value : void 0;
2397
+ }
2398
+ },
2399
+ {
2400
+ property: "description",
2401
+ extract: (node) => node?.metadata().description
2402
+ },
2403
+ {
2404
+ property: "deprecated",
2405
+ extract: (node) => node?.metadata().deprecated
2406
+ },
2407
+ {
2408
+ property: "foreignKey",
2409
+ extract: (node) => node?.foreignKey()
2410
+ },
2411
+ {
2412
+ property: "contentMediaType",
2413
+ extract: (node) => node?.contentMediaType()
2414
+ },
2415
+ {
2416
+ property: "ref",
2417
+ extract: (node) => node?.ref()
2418
+ },
2419
+ {
2420
+ property: "title",
2421
+ extract: (node) => node?.metadata().title
2422
+ }
2423
+ ];
2424
+ }
2425
+ computePropertyChanges(baseNode, currentNode, options) {
2426
+ const skipSet = options?.skipProperties;
2427
+ const result = [];
2428
+ for (const extractor of this.extractors) {
2429
+ if (skipSet?.includes(extractor.property)) {
2430
+ continue;
2431
+ }
2432
+ const from = extractor.extract(baseNode, this.baseTree);
2433
+ const to = extractor.extract(currentNode, this.currentTree);
2434
+ const areEqual = extractor.compare ? extractor.compare(from, to) : from === to;
2435
+ if (!areEqual) {
2436
+ result.push({ property: extractor.property, from, to });
2437
+ }
2368
2438
  }
2369
2439
  return result;
2370
2440
  }
2441
+ computeAddPropertyChanges(node) {
2442
+ const allChanges = this.computePropertyChanges(null, node);
2443
+ return allChanges.filter((change) => change.to !== void 0);
2444
+ }
2371
2445
  computeTypeChange(baseNode, currentNode, ignoreItems) {
2372
2446
  if (!baseNode || !currentNode) {
2373
2447
  return void 0;
@@ -2386,98 +2460,6 @@ var PatchEnricher = class {
2386
2460
  }
2387
2461
  return void 0;
2388
2462
  }
2389
- computeFormulaChange(baseNode, currentNode) {
2390
- const baseFormula = baseNode?.formula();
2391
- const currentFormula = currentNode?.formula();
2392
- const baseExpr = baseFormula && baseNode ? this.getFormulaExpression(baseFormula, this.baseTree, baseNode.id()) : void 0;
2393
- const currentExpr = currentFormula && currentNode ? this.getFormulaExpression(currentFormula, this.currentTree, currentNode.id()) : void 0;
2394
- const baseVersion = baseFormula?.version();
2395
- const currentVersion = currentFormula?.version();
2396
- if (baseExpr !== currentExpr || baseVersion !== currentVersion) {
2397
- return {
2398
- fromFormula: baseExpr,
2399
- toFormula: currentExpr,
2400
- fromVersion: baseVersion,
2401
- toVersion: currentVersion
2402
- };
2403
- }
2404
- return void 0;
2405
- }
2406
- getFormulaExpression(formula, tree, nodeId) {
2407
- return FormulaSerializer.serializeExpression(tree, nodeId, formula, { strict: false });
2408
- }
2409
- computeDefaultChange(baseNode, currentNode) {
2410
- const baseDefault = baseNode?.defaultValue();
2411
- const currentDefault = currentNode?.defaultValue();
2412
- const safeBaseDefault = isPrimitiveDefault(baseDefault) ? baseDefault : void 0;
2413
- const safeCurrentDefault = isPrimitiveDefault(
2414
- currentDefault
2415
- ) ? currentDefault : void 0;
2416
- if (safeBaseDefault !== safeCurrentDefault) {
2417
- return {
2418
- fromDefault: safeBaseDefault,
2419
- toDefault: safeCurrentDefault
2420
- };
2421
- }
2422
- return void 0;
2423
- }
2424
- computeDescriptionChange(baseNode, currentNode) {
2425
- const baseDesc = baseNode?.metadata().description;
2426
- const currentDesc = currentNode?.metadata().description;
2427
- if (baseDesc !== currentDesc) {
2428
- return { fromDescription: baseDesc, toDescription: currentDesc };
2429
- }
2430
- return void 0;
2431
- }
2432
- computeDeprecatedChange(baseNode, currentNode) {
2433
- const baseDeprecated = baseNode?.metadata().deprecated;
2434
- const currentDeprecated = currentNode?.metadata().deprecated;
2435
- if (baseDeprecated !== currentDeprecated) {
2436
- return { fromDeprecated: baseDeprecated, toDeprecated: currentDeprecated };
2437
- }
2438
- return void 0;
2439
- }
2440
- computeForeignKeyChange(baseNode, currentNode) {
2441
- const baseFk = baseNode?.foreignKey();
2442
- const currentFk = currentNode?.foreignKey();
2443
- if (baseFk !== currentFk) {
2444
- return { fromForeignKey: baseFk, toForeignKey: currentFk };
2445
- }
2446
- return void 0;
2447
- }
2448
- computeContentMediaTypeChange(baseNode, currentNode) {
2449
- const baseMediaType = baseNode?.contentMediaType();
2450
- const currentMediaType = currentNode?.contentMediaType();
2451
- if (baseMediaType !== currentMediaType) {
2452
- return {
2453
- fromContentMediaType: baseMediaType,
2454
- toContentMediaType: currentMediaType
2455
- };
2456
- }
2457
- return void 0;
2458
- }
2459
- computeMetadataChanges(changes) {
2460
- const result = [];
2461
- if (changes.formulaChange) {
2462
- result.push("formula");
2463
- }
2464
- if (changes.defaultChange) {
2465
- result.push("default");
2466
- }
2467
- if (changes.descriptionChange) {
2468
- result.push("description");
2469
- }
2470
- if (changes.deprecatedChange) {
2471
- result.push("deprecated");
2472
- }
2473
- if (changes.foreignKeyChange) {
2474
- result.push("foreignKey");
2475
- }
2476
- if (changes.contentMediaTypeChange) {
2477
- result.push("contentMediaType");
2478
- }
2479
- return result;
2480
- }
2481
2463
  getNodeType(node) {
2482
2464
  if (node.isArray()) {
2483
2465
  const items = node.items();
@@ -2955,5 +2937,5 @@ function buildArrayItemsPath(parentPath) {
2955
2937
  }
2956
2938
 
2957
2939
  export { AbstractBasePath, ChangeCoalescer, ChangeCollector, CompositeRule, EMPTY_METADATA, EMPTY_PATH, EnumValidator, FIELD_NAME_ERROR_MESSAGE, ForeignKeyValidator, FormulaChangeDetector, FormulaDependencyIndex, FormulaPath, FormulaPathBuilder, FormulaSerializer, ItemsSegment, MaxLengthValidator, MaximumValidator, MinLengthValidator, MinimumValidator, NULL_NODE, NodePathIndex, ParsedFormula, PatchBuilder, PatchEnricher, PatchGenerator, PatternValidator, PropertySegment, RequiredValidator, ResolvedDependency, SchemaDiff, SchemaPropertyRule, SchemaSerializer, SchemaTruthyRule, ValidationEngine, ValidatorRegistry, ValidatorResolver, areNodesContentEqual, areNodesEqual, coalesceChanges, collectChanges, createArrayNode, createBooleanNode, createDefaultValidatorRegistry, createMobxProvider, createNumberNode, createObjectNode, createPath, createRefNode, createSchemaTree, createStringNode, createValidationEngine, isValidFieldName, jsonPointerToPath, jsonPointerToSegments, jsonPointerToSimplePath, makeAutoObservable, makeObservable, observable, reaction, resetReactivityProvider, runInAction, setReactivityProvider, validateFormulas, validateSchema };
2958
- //# sourceMappingURL=chunk-5FFJ2R3L.js.map
2959
- //# sourceMappingURL=chunk-5FFJ2R3L.js.map
2940
+ //# sourceMappingURL=chunk-R6VYCHY2.js.map
2941
+ //# sourceMappingURL=chunk-R6VYCHY2.js.map