@revisium/schema-toolkit 0.14.3 → 0.15.0
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 +1 -1
- package/dist/{chunk-DJ4JPKI4.js → chunk-2NRQPOQY.js} +126 -218
- package/dist/chunk-2NRQPOQY.js.map +1 -0
- package/dist/chunk-3IKI64T2.js +3 -0
- package/dist/{chunk-H7W4QNMA.js.map → chunk-3IKI64T2.js.map} +1 -1
- package/dist/chunk-5WZ4YPH5.cjs +2209 -0
- package/dist/chunk-5WZ4YPH5.cjs.map +1 -0
- package/dist/chunk-A4E524UU.cjs +2179 -0
- package/dist/chunk-A4E524UU.cjs.map +1 -0
- package/dist/{chunk-L5MLJEC7.js → chunk-CYTPQYVM.js} +2 -2
- package/dist/chunk-CYTPQYVM.js.map +1 -0
- package/dist/chunk-F4UBBZAL.js +2147 -0
- package/dist/chunk-F4UBBZAL.js.map +1 -0
- package/dist/{chunk-B22UU3JK.cjs → chunk-GAPLSVZN.cjs} +2 -2
- package/dist/chunk-GAPLSVZN.cjs.map +1 -0
- package/dist/chunk-OP35BPMU.js +2178 -0
- package/dist/chunk-OP35BPMU.js.map +1 -0
- package/dist/chunk-TBFTADML.cjs +4 -0
- package/dist/{chunk-ODCH3PP2.cjs.map → chunk-TBFTADML.cjs.map} +1 -1
- package/dist/chunk-WSPFHUHU.cjs +130 -0
- package/dist/chunk-WSPFHUHU.cjs.map +1 -0
- package/dist/{chunk-VX5C5YMF.cjs → chunk-XS47N22X.cjs} +125 -218
- package/dist/chunk-XS47N22X.cjs.map +1 -0
- package/dist/chunk-YFWOURZL.js +128 -0
- package/dist/chunk-YFWOURZL.js.map +1 -0
- package/dist/{chunk-KJCURW4D.js → chunk-ZBPUTF3Q.js} +3 -3
- package/dist/chunk-ZBPUTF3Q.js.map +1 -0
- package/dist/{chunk-GF3XXYOS.cjs → chunk-ZRNFSUOV.cjs} +3 -3
- package/dist/chunk-ZRNFSUOV.cjs.map +1 -0
- package/dist/computeValueDiff-CDwbNw8F.d.ts +5 -0
- package/dist/computeValueDiff-CNT84rwK.d.cts +5 -0
- package/dist/core/index.cjs +474 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +313 -0
- package/dist/core/index.d.ts +313 -0
- package/dist/core/index.js +336 -0
- package/dist/core/index.js.map +1 -0
- package/dist/formula/index.d.cts +1 -1
- package/dist/formula/index.d.ts +1 -1
- package/dist/index.cjs +166 -44
- package/dist/index.d.cts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +7 -5
- package/dist/{json-patch.types-CYt9TCu3.d.ts → json-patch.types-DTUHS9SV.d.ts} +1 -1
- package/dist/{json-patch.types-DUcWbQRY.d.cts → json-patch.types-eltVqnWC.d.cts} +1 -1
- package/dist/{json-string.store-CcZ197KO.d.cts → json-string.store-DKlkc1u_.d.cts} +1 -1
- package/dist/{json-string.store-DckDcMVN.d.ts → json-string.store-DMrHPJ3v.d.ts} +1 -1
- package/dist/json-value-patch.types-CjBpq5VF.d.cts +24 -0
- package/dist/json-value-patch.types-U2y_ugm1.d.ts +24 -0
- package/dist/lib/index.cjs +40 -39
- package/dist/lib/index.d.cts +6 -7
- package/dist/lib/index.d.ts +6 -7
- package/dist/lib/index.js +4 -3
- package/dist/mocks/index.cjs +1 -1
- package/dist/mocks/index.d.cts +2 -2
- package/dist/mocks/index.d.ts +2 -2
- package/dist/mocks/index.js +1 -1
- package/dist/model/index.cjs +125 -2
- package/dist/model/index.d.cts +582 -4
- package/dist/model/index.d.ts +582 -4
- package/dist/model/index.js +5 -2
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +25 -1
- package/dist/plugins/index.d.ts +25 -1
- package/dist/plugins/index.js +1 -1
- package/dist/{schema.types-CLHMJmkJ.d.cts → schema.types-ZX5fUW1X.d.cts} +6 -0
- package/dist/{schema.types-CLHMJmkJ.d.ts → schema.types-ZX5fUW1X.d.ts} +6 -0
- package/dist/types/index.cjs +5 -5
- package/dist/types/index.d.cts +8 -29
- package/dist/types/index.d.ts +8 -29
- package/dist/types/index.js +3 -3
- package/dist/{value-diff.types-BRoI_kGE.d.cts → types-C_GxaUve.d.cts} +4 -4
- package/dist/{value-diff.types-BRoI_kGE.d.ts → types-C_GxaUve.d.ts} +4 -4
- package/dist/types-CwJ2OWO_.d.cts +183 -0
- package/dist/types-XDWz0V1v.d.ts +183 -0
- package/package.json +14 -1
- package/dist/chunk-B22UU3JK.cjs.map +0 -1
- package/dist/chunk-DJ4JPKI4.js.map +0 -1
- package/dist/chunk-GF3XXYOS.cjs.map +0 -1
- package/dist/chunk-H7W4QNMA.js +0 -3
- package/dist/chunk-KJCURW4D.js.map +0 -1
- package/dist/chunk-L5MLJEC7.js.map +0 -1
- package/dist/chunk-ODCH3PP2.cjs +0 -4
- package/dist/chunk-SBJFTOWW.js +0 -3
- package/dist/chunk-SBJFTOWW.js.map +0 -1
- package/dist/chunk-VX5C5YMF.cjs.map +0 -1
- package/dist/chunk-XAFOMEOK.cjs +0 -4
- package/dist/chunk-XAFOMEOK.cjs.map +0 -1
|
@@ -0,0 +1,2179 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var formula = require('@revisium/formula');
|
|
4
|
+
|
|
5
|
+
// src/core/schema-node/types.ts
|
|
6
|
+
var EMPTY_METADATA = Object.freeze({});
|
|
7
|
+
|
|
8
|
+
// src/core/schema-node/NullNode.ts
|
|
9
|
+
var NullNodeImpl = class {
|
|
10
|
+
id() {
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
name() {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
nodeType() {
|
|
17
|
+
return "null";
|
|
18
|
+
}
|
|
19
|
+
metadata() {
|
|
20
|
+
return EMPTY_METADATA;
|
|
21
|
+
}
|
|
22
|
+
isObject() {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
isArray() {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
isPrimitive() {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
isRef() {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
isNull() {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
property() {
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
properties() {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
items() {
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
ref() {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
formula() {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
hasFormula() {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
defaultValue() {
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
foreignKey() {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
clone() {
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
setName(_name) {
|
|
65
|
+
}
|
|
66
|
+
setMetadata(_metadata) {
|
|
67
|
+
}
|
|
68
|
+
addChild(_node) {
|
|
69
|
+
}
|
|
70
|
+
removeChild(_name) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
setItems(_node) {
|
|
74
|
+
}
|
|
75
|
+
setDefaultValue(_value) {
|
|
76
|
+
}
|
|
77
|
+
setFormula(_formula) {
|
|
78
|
+
}
|
|
79
|
+
setForeignKey(_key) {
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var NULL_NODE = new NullNodeImpl();
|
|
83
|
+
|
|
84
|
+
// src/core/schema-node/BaseNode.ts
|
|
85
|
+
var BaseNode = class {
|
|
86
|
+
constructor(_id, name, metadata = EMPTY_METADATA) {
|
|
87
|
+
this._id = _id;
|
|
88
|
+
this._name = name;
|
|
89
|
+
this._metadata = metadata;
|
|
90
|
+
}
|
|
91
|
+
_name;
|
|
92
|
+
_metadata;
|
|
93
|
+
id() {
|
|
94
|
+
return this._id;
|
|
95
|
+
}
|
|
96
|
+
name() {
|
|
97
|
+
return this._name;
|
|
98
|
+
}
|
|
99
|
+
metadata() {
|
|
100
|
+
return this._metadata;
|
|
101
|
+
}
|
|
102
|
+
isObject() {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
isArray() {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
isPrimitive() {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
isRef() {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
isNull() {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
property(_name) {
|
|
118
|
+
return NULL_NODE;
|
|
119
|
+
}
|
|
120
|
+
properties() {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
items() {
|
|
124
|
+
return NULL_NODE;
|
|
125
|
+
}
|
|
126
|
+
ref() {
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
formula() {
|
|
130
|
+
return void 0;
|
|
131
|
+
}
|
|
132
|
+
hasFormula() {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
defaultValue() {
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
foreignKey() {
|
|
139
|
+
return void 0;
|
|
140
|
+
}
|
|
141
|
+
setName(name) {
|
|
142
|
+
this._name = name;
|
|
143
|
+
}
|
|
144
|
+
setMetadata(metadata) {
|
|
145
|
+
this._metadata = metadata;
|
|
146
|
+
}
|
|
147
|
+
addChild(_node) {
|
|
148
|
+
}
|
|
149
|
+
removeChild(_name) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
setItems(_node) {
|
|
153
|
+
}
|
|
154
|
+
setDefaultValue(_value) {
|
|
155
|
+
}
|
|
156
|
+
setFormula(_formula) {
|
|
157
|
+
}
|
|
158
|
+
setForeignKey(_key) {
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/core/schema-node/ObjectNode.ts
|
|
163
|
+
var ObjectNode = class _ObjectNode extends BaseNode {
|
|
164
|
+
_children;
|
|
165
|
+
constructor(id, name, children = [], metadata = EMPTY_METADATA) {
|
|
166
|
+
super(id, name, metadata);
|
|
167
|
+
this._children = [...children];
|
|
168
|
+
}
|
|
169
|
+
nodeType() {
|
|
170
|
+
return "object";
|
|
171
|
+
}
|
|
172
|
+
isObject() {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
property(name) {
|
|
176
|
+
return this._children.find((child) => child.name() === name) ?? NULL_NODE;
|
|
177
|
+
}
|
|
178
|
+
properties() {
|
|
179
|
+
return this._children;
|
|
180
|
+
}
|
|
181
|
+
clone() {
|
|
182
|
+
return new _ObjectNode(
|
|
183
|
+
this.id(),
|
|
184
|
+
this.name(),
|
|
185
|
+
this._children.map((child) => child.clone()),
|
|
186
|
+
this.metadata()
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
addChild(node) {
|
|
190
|
+
this._children.push(node);
|
|
191
|
+
}
|
|
192
|
+
removeChild(name) {
|
|
193
|
+
const index = this._children.findIndex((child) => child.name() === name);
|
|
194
|
+
if (index === -1) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
this._children.splice(index, 1);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
function createObjectNode(id, name, children = [], metadata = EMPTY_METADATA) {
|
|
202
|
+
return new ObjectNode(id, name, children, metadata);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/core/schema-node/ArrayNode.ts
|
|
206
|
+
var ArrayNode = class _ArrayNode extends BaseNode {
|
|
207
|
+
_items;
|
|
208
|
+
constructor(id, name, items, metadata = EMPTY_METADATA) {
|
|
209
|
+
super(id, name, metadata);
|
|
210
|
+
this._items = items;
|
|
211
|
+
}
|
|
212
|
+
nodeType() {
|
|
213
|
+
return "array";
|
|
214
|
+
}
|
|
215
|
+
isArray() {
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
properties() {
|
|
219
|
+
return [this._items];
|
|
220
|
+
}
|
|
221
|
+
items() {
|
|
222
|
+
return this._items;
|
|
223
|
+
}
|
|
224
|
+
clone() {
|
|
225
|
+
return new _ArrayNode(
|
|
226
|
+
this.id(),
|
|
227
|
+
this.name(),
|
|
228
|
+
this._items.clone(),
|
|
229
|
+
this.metadata()
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
setItems(node) {
|
|
233
|
+
this._items = node;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
function createArrayNode(id, name, items, metadata = EMPTY_METADATA) {
|
|
237
|
+
return new ArrayNode(id, name, items, metadata);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/core/schema-node/PrimitiveNode.ts
|
|
241
|
+
var PrimitiveNode = class extends BaseNode {
|
|
242
|
+
_defaultValue;
|
|
243
|
+
_foreignKey;
|
|
244
|
+
_formula;
|
|
245
|
+
constructor(id, name, options = {}) {
|
|
246
|
+
super(id, name, options.metadata ?? EMPTY_METADATA);
|
|
247
|
+
this._defaultValue = options.defaultValue;
|
|
248
|
+
this._foreignKey = options.foreignKey;
|
|
249
|
+
this._formula = options.formula;
|
|
250
|
+
}
|
|
251
|
+
isPrimitive() {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
formula() {
|
|
255
|
+
return this._formula;
|
|
256
|
+
}
|
|
257
|
+
hasFormula() {
|
|
258
|
+
return this._formula !== void 0;
|
|
259
|
+
}
|
|
260
|
+
defaultValue() {
|
|
261
|
+
return this._defaultValue;
|
|
262
|
+
}
|
|
263
|
+
foreignKey() {
|
|
264
|
+
return this._foreignKey;
|
|
265
|
+
}
|
|
266
|
+
setDefaultValue(value) {
|
|
267
|
+
this._defaultValue = value;
|
|
268
|
+
}
|
|
269
|
+
setFormula(formula) {
|
|
270
|
+
this._formula = formula;
|
|
271
|
+
}
|
|
272
|
+
setForeignKey(key) {
|
|
273
|
+
this._foreignKey = key;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// src/core/schema-node/StringNode.ts
|
|
278
|
+
var StringNode = class _StringNode extends PrimitiveNode {
|
|
279
|
+
constructor(id, name, options = {}) {
|
|
280
|
+
super(id, name, options);
|
|
281
|
+
}
|
|
282
|
+
nodeType() {
|
|
283
|
+
return "string";
|
|
284
|
+
}
|
|
285
|
+
clone() {
|
|
286
|
+
return new _StringNode(this.id(), this.name(), this.cloneOptions());
|
|
287
|
+
}
|
|
288
|
+
cloneOptions() {
|
|
289
|
+
return {
|
|
290
|
+
defaultValue: this._defaultValue,
|
|
291
|
+
foreignKey: this._foreignKey,
|
|
292
|
+
formula: this._formula,
|
|
293
|
+
metadata: this._metadata
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
function createStringNode(id, name, options = {}) {
|
|
298
|
+
return new StringNode(id, name, options);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/core/schema-node/NumberNode.ts
|
|
302
|
+
var NumberNode = class _NumberNode extends PrimitiveNode {
|
|
303
|
+
constructor(id, name, options = {}) {
|
|
304
|
+
super(id, name, options);
|
|
305
|
+
}
|
|
306
|
+
nodeType() {
|
|
307
|
+
return "number";
|
|
308
|
+
}
|
|
309
|
+
clone() {
|
|
310
|
+
return new _NumberNode(this.id(), this.name(), this.cloneOptions());
|
|
311
|
+
}
|
|
312
|
+
cloneOptions() {
|
|
313
|
+
return {
|
|
314
|
+
defaultValue: this._defaultValue,
|
|
315
|
+
formula: this._formula,
|
|
316
|
+
metadata: this._metadata
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
function createNumberNode(id, name, options = {}) {
|
|
321
|
+
return new NumberNode(id, name, options);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/core/schema-node/BooleanNode.ts
|
|
325
|
+
var BooleanNode = class _BooleanNode extends PrimitiveNode {
|
|
326
|
+
constructor(id, name, options = {}) {
|
|
327
|
+
super(id, name, options);
|
|
328
|
+
}
|
|
329
|
+
nodeType() {
|
|
330
|
+
return "boolean";
|
|
331
|
+
}
|
|
332
|
+
clone() {
|
|
333
|
+
return new _BooleanNode(this.id(), this.name(), this.cloneOptions());
|
|
334
|
+
}
|
|
335
|
+
cloneOptions() {
|
|
336
|
+
return {
|
|
337
|
+
defaultValue: this._defaultValue,
|
|
338
|
+
formula: this._formula,
|
|
339
|
+
metadata: this._metadata
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
function createBooleanNode(id, name, options = {}) {
|
|
344
|
+
return new BooleanNode(id, name, options);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/core/schema-node/RefNode.ts
|
|
348
|
+
var RefNode = class _RefNode extends BaseNode {
|
|
349
|
+
_ref;
|
|
350
|
+
constructor(id, name, ref, metadata = EMPTY_METADATA) {
|
|
351
|
+
super(id, name, metadata);
|
|
352
|
+
if (!ref) {
|
|
353
|
+
throw new Error("RefNode requires a non-empty ref");
|
|
354
|
+
}
|
|
355
|
+
this._ref = ref;
|
|
356
|
+
}
|
|
357
|
+
nodeType() {
|
|
358
|
+
return "ref";
|
|
359
|
+
}
|
|
360
|
+
isRef() {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
ref() {
|
|
364
|
+
return this._ref;
|
|
365
|
+
}
|
|
366
|
+
clone() {
|
|
367
|
+
return new _RefNode(this.id(), this.name(), this._ref, this.metadata());
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
function createRefNode(id, name, ref, metadata = EMPTY_METADATA) {
|
|
371
|
+
return new RefNode(id, name, ref, metadata);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/core/path/PathSegment.ts
|
|
375
|
+
var PropertySegment = class {
|
|
376
|
+
constructor(name) {
|
|
377
|
+
this.name = name;
|
|
378
|
+
}
|
|
379
|
+
isProperty() {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
isItems() {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
propertyName() {
|
|
386
|
+
return this.name;
|
|
387
|
+
}
|
|
388
|
+
equals(other) {
|
|
389
|
+
return other.isProperty() && other.propertyName() === this.name;
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
var ItemsSegment = class {
|
|
393
|
+
isProperty() {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
isItems() {
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
propertyName() {
|
|
400
|
+
throw new Error("Items segment has no property name");
|
|
401
|
+
}
|
|
402
|
+
equals(other) {
|
|
403
|
+
return other.isItems();
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// src/core/base-path/AbstractBasePath.ts
|
|
408
|
+
var AbstractBasePath = class {
|
|
409
|
+
constructor(segs) {
|
|
410
|
+
this.segs = segs;
|
|
411
|
+
}
|
|
412
|
+
segments() {
|
|
413
|
+
return this.segs;
|
|
414
|
+
}
|
|
415
|
+
equals(other) {
|
|
416
|
+
const otherSegs = other.segments();
|
|
417
|
+
if (this.segs.length !== otherSegs.length) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
for (let i = 0; i < this.segs.length; i++) {
|
|
421
|
+
const a = this.segs[i];
|
|
422
|
+
const b = otherSegs[i];
|
|
423
|
+
if (!a || !b || !a.equals(b)) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
isEmpty() {
|
|
430
|
+
return this.segs.length === 0;
|
|
431
|
+
}
|
|
432
|
+
length() {
|
|
433
|
+
return this.segs.length;
|
|
434
|
+
}
|
|
435
|
+
isChildOf(parent) {
|
|
436
|
+
const parentSegs = parent.segments();
|
|
437
|
+
if (this.segs.length <= parentSegs.length) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
for (let i = 0; i < parentSegs.length; i++) {
|
|
441
|
+
const a = this.segs[i];
|
|
442
|
+
const b = parentSegs[i];
|
|
443
|
+
if (!a || !b || !a.equals(b)) {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// src/core/path/Path.ts
|
|
452
|
+
var PathImpl = class _PathImpl extends AbstractBasePath {
|
|
453
|
+
asJsonPointer() {
|
|
454
|
+
return this.segs.map(
|
|
455
|
+
(seg) => seg.isProperty() ? `/properties/${seg.propertyName()}` : "/items"
|
|
456
|
+
).join("");
|
|
457
|
+
}
|
|
458
|
+
asSimple() {
|
|
459
|
+
const parts = [];
|
|
460
|
+
for (const seg of this.segs) {
|
|
461
|
+
if (seg.isProperty()) {
|
|
462
|
+
parts.push(seg.propertyName());
|
|
463
|
+
} else if (seg.isItems()) {
|
|
464
|
+
if (parts.length > 0) {
|
|
465
|
+
const lastIndex = parts.length - 1;
|
|
466
|
+
const lastPart = parts[lastIndex];
|
|
467
|
+
if (lastPart !== void 0) {
|
|
468
|
+
parts[lastIndex] = lastPart + "[*]";
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
parts.push("[*]");
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return parts.join(".");
|
|
476
|
+
}
|
|
477
|
+
parent() {
|
|
478
|
+
if (this.segs.length <= 1) {
|
|
479
|
+
return EMPTY_PATH;
|
|
480
|
+
}
|
|
481
|
+
return new _PathImpl(this.segs.slice(0, -1));
|
|
482
|
+
}
|
|
483
|
+
child(name) {
|
|
484
|
+
return new _PathImpl([...this.segs, new PropertySegment(name)]);
|
|
485
|
+
}
|
|
486
|
+
childItems() {
|
|
487
|
+
return new _PathImpl([...this.segs, new ItemsSegment()]);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
var EMPTY_PATH = new PathImpl([]);
|
|
491
|
+
function createPath(segments) {
|
|
492
|
+
return segments.length === 0 ? EMPTY_PATH : new PathImpl(segments);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/core/path/PathParser.ts
|
|
496
|
+
function jsonPointerToSegments(pointer) {
|
|
497
|
+
if (pointer === "" || pointer === "/") {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
const parts = pointer.split("/").filter(Boolean);
|
|
501
|
+
const segments = [];
|
|
502
|
+
let i = 0;
|
|
503
|
+
while (i < parts.length) {
|
|
504
|
+
const part = parts[i];
|
|
505
|
+
if (part === "properties") {
|
|
506
|
+
const name = parts[i + 1];
|
|
507
|
+
if (name === void 0 || name === "") {
|
|
508
|
+
throw new Error(
|
|
509
|
+
`Invalid path: 'properties' segment requires a name in path ${pointer}`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
segments.push(new PropertySegment(name));
|
|
513
|
+
i += 2;
|
|
514
|
+
} else if (part === "items") {
|
|
515
|
+
segments.push(new ItemsSegment());
|
|
516
|
+
i += 1;
|
|
517
|
+
} else {
|
|
518
|
+
throw new Error(`Invalid path segment: ${part} in path ${pointer}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return segments;
|
|
522
|
+
}
|
|
523
|
+
function jsonPointerToPath(pointer) {
|
|
524
|
+
return createPath(jsonPointerToSegments(pointer));
|
|
525
|
+
}
|
|
526
|
+
function jsonPointerToSimplePath(pointer) {
|
|
527
|
+
return jsonPointerToPath(pointer).asSimple();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// src/core/schema-tree/TreeNodeIndex.ts
|
|
531
|
+
var TreeNodeIndex = class {
|
|
532
|
+
nodeIndex = /* @__PURE__ */ new Map();
|
|
533
|
+
pathIndex = /* @__PURE__ */ new Map();
|
|
534
|
+
rebuild(rootNode) {
|
|
535
|
+
this.nodeIndex.clear();
|
|
536
|
+
this.pathIndex.clear();
|
|
537
|
+
this.collectNodes(rootNode, EMPTY_PATH);
|
|
538
|
+
}
|
|
539
|
+
getNode(id) {
|
|
540
|
+
return this.nodeIndex.get(id) ?? NULL_NODE;
|
|
541
|
+
}
|
|
542
|
+
getPath(id) {
|
|
543
|
+
return this.pathIndex.get(id) ?? EMPTY_PATH;
|
|
544
|
+
}
|
|
545
|
+
countNodes() {
|
|
546
|
+
return this.nodeIndex.size;
|
|
547
|
+
}
|
|
548
|
+
nodeIds() {
|
|
549
|
+
return this.nodeIndex.keys();
|
|
550
|
+
}
|
|
551
|
+
collectNodes(node, path) {
|
|
552
|
+
this.nodeIndex.set(node.id(), node);
|
|
553
|
+
this.pathIndex.set(node.id(), path);
|
|
554
|
+
if (node.isObject()) {
|
|
555
|
+
for (const child of node.properties()) {
|
|
556
|
+
this.collectNodes(child, path.child(child.name()));
|
|
557
|
+
}
|
|
558
|
+
} else if (node.isArray()) {
|
|
559
|
+
this.collectNodes(node.items(), path.childItems());
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
// src/core/schema-tree/SchemaTreeImpl.ts
|
|
565
|
+
var SchemaTreeImpl = class _SchemaTreeImpl {
|
|
566
|
+
constructor(rootNode) {
|
|
567
|
+
this.rootNode = rootNode;
|
|
568
|
+
this.index.rebuild(rootNode);
|
|
569
|
+
}
|
|
570
|
+
index = new TreeNodeIndex();
|
|
571
|
+
_replacements = /* @__PURE__ */ new Map();
|
|
572
|
+
root() {
|
|
573
|
+
return this.rootNode;
|
|
574
|
+
}
|
|
575
|
+
nodeById(id) {
|
|
576
|
+
return this.index.getNode(id);
|
|
577
|
+
}
|
|
578
|
+
pathOf(id) {
|
|
579
|
+
return this.index.getPath(id);
|
|
580
|
+
}
|
|
581
|
+
nodeAt(path) {
|
|
582
|
+
if (path.isEmpty()) {
|
|
583
|
+
return this.rootNode;
|
|
584
|
+
}
|
|
585
|
+
let current = this.rootNode;
|
|
586
|
+
for (const segment of path.segments()) {
|
|
587
|
+
if (current.isNull()) {
|
|
588
|
+
return NULL_NODE;
|
|
589
|
+
}
|
|
590
|
+
if (segment.isItems()) {
|
|
591
|
+
current = current.items();
|
|
592
|
+
} else {
|
|
593
|
+
current = current.property(segment.propertyName());
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return current;
|
|
597
|
+
}
|
|
598
|
+
nodeIds() {
|
|
599
|
+
return this.index.nodeIds();
|
|
600
|
+
}
|
|
601
|
+
countNodes() {
|
|
602
|
+
return this.index.countNodes();
|
|
603
|
+
}
|
|
604
|
+
clone() {
|
|
605
|
+
const cloned = new _SchemaTreeImpl(this.rootNode.clone());
|
|
606
|
+
for (const [oldId, newId] of this._replacements) {
|
|
607
|
+
cloned._replacements.set(oldId, newId);
|
|
608
|
+
}
|
|
609
|
+
return cloned;
|
|
610
|
+
}
|
|
611
|
+
trackReplacement(oldNodeId, newNodeId) {
|
|
612
|
+
this._replacements.set(oldNodeId, newNodeId);
|
|
613
|
+
}
|
|
614
|
+
replacements() {
|
|
615
|
+
return this._replacements.entries();
|
|
616
|
+
}
|
|
617
|
+
addChildTo(parentId, node) {
|
|
618
|
+
const parent = this.nodeById(parentId);
|
|
619
|
+
if (parent.isNull()) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (parent.isArray()) {
|
|
623
|
+
throw new Error("Cannot add child to array node. Use setItems instead.");
|
|
624
|
+
}
|
|
625
|
+
parent.addChild(node);
|
|
626
|
+
this.rebuildIndex();
|
|
627
|
+
}
|
|
628
|
+
removeNodeAt(path) {
|
|
629
|
+
if (path.isEmpty()) {
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
const parentPath = path.parent();
|
|
633
|
+
const parent = this.nodeAt(parentPath);
|
|
634
|
+
if (parent.isNull()) {
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
const lastSegment = path.segments().at(-1);
|
|
638
|
+
if (!lastSegment || lastSegment.isItems()) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
const removed = parent.removeChild(lastSegment.propertyName());
|
|
642
|
+
if (removed) {
|
|
643
|
+
this.rebuildIndex();
|
|
644
|
+
}
|
|
645
|
+
return removed;
|
|
646
|
+
}
|
|
647
|
+
renameNode(nodeId, newName) {
|
|
648
|
+
const node = this.nodeById(nodeId);
|
|
649
|
+
if (node.isNull()) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
node.setName(newName);
|
|
653
|
+
this.rebuildIndex();
|
|
654
|
+
}
|
|
655
|
+
moveNode(nodeId, newParentId) {
|
|
656
|
+
const node = this.nodeById(nodeId);
|
|
657
|
+
if (node.isNull()) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const currentPath = this.pathOf(nodeId);
|
|
661
|
+
if (currentPath.isEmpty()) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const currentParentPath = currentPath.parent();
|
|
665
|
+
const currentParent = this.nodeAt(currentParentPath);
|
|
666
|
+
if (currentParent.isNull()) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
if (currentParent.isArray()) {
|
|
670
|
+
throw new Error("Cannot move node from array. Array items cannot be moved.");
|
|
671
|
+
}
|
|
672
|
+
const newParent = this.nodeById(newParentId);
|
|
673
|
+
if (newParent.isNull()) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
if (newParent.isArray()) {
|
|
677
|
+
throw new Error("Cannot move node into array. Use setItems instead.");
|
|
678
|
+
}
|
|
679
|
+
const newParentPath = this.pathOf(newParentId);
|
|
680
|
+
if (newParentPath.equals(currentPath) || newParentPath.isChildOf(currentPath)) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
currentParent.removeChild(node.name());
|
|
684
|
+
newParent.addChild(node);
|
|
685
|
+
this.rebuildIndex();
|
|
686
|
+
}
|
|
687
|
+
setNodeAt(path, node) {
|
|
688
|
+
if (path.isEmpty()) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const parentPath = path.parent();
|
|
692
|
+
const parent = this.nodeAt(parentPath);
|
|
693
|
+
if (parent.isNull()) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const lastSegment = path.segments().at(-1);
|
|
697
|
+
if (!lastSegment) {
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (lastSegment.isItems()) {
|
|
701
|
+
parent.setItems(node);
|
|
702
|
+
} else {
|
|
703
|
+
parent.removeChild(lastSegment.propertyName());
|
|
704
|
+
node.setName(lastSegment.propertyName());
|
|
705
|
+
parent.addChild(node);
|
|
706
|
+
}
|
|
707
|
+
this.rebuildIndex();
|
|
708
|
+
}
|
|
709
|
+
rebuildIndex() {
|
|
710
|
+
this.index.rebuild(this.rootNode);
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
function createSchemaTree(root) {
|
|
714
|
+
return new SchemaTreeImpl(root);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// src/core/schema-diff/NodePathIndex.ts
|
|
718
|
+
var NodePathIndex = class {
|
|
719
|
+
_basePaths = /* @__PURE__ */ new Map();
|
|
720
|
+
_replacements = /* @__PURE__ */ new Map();
|
|
721
|
+
constructor(baseTree) {
|
|
722
|
+
for (const nodeId of baseTree.nodeIds()) {
|
|
723
|
+
this._basePaths.set(nodeId, baseTree.pathOf(nodeId));
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
hasBasePath(nodeId) {
|
|
727
|
+
return this._basePaths.has(nodeId);
|
|
728
|
+
}
|
|
729
|
+
getBasePath(nodeId) {
|
|
730
|
+
return this._basePaths.get(nodeId);
|
|
731
|
+
}
|
|
732
|
+
trackReplacement(oldNodeId, newNodeId) {
|
|
733
|
+
this._replacements.set(oldNodeId, newNodeId);
|
|
734
|
+
}
|
|
735
|
+
getReplacementNodeId(oldNodeId) {
|
|
736
|
+
return this._replacements.get(oldNodeId);
|
|
737
|
+
}
|
|
738
|
+
getOriginalNodeId(newNodeId) {
|
|
739
|
+
for (const [oldId, newId] of this._replacements) {
|
|
740
|
+
if (newId === newNodeId) {
|
|
741
|
+
return oldId;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return void 0;
|
|
745
|
+
}
|
|
746
|
+
isReplacement(nodeId) {
|
|
747
|
+
for (const newId of this._replacements.values()) {
|
|
748
|
+
if (newId === nodeId) {
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
get replacements() {
|
|
755
|
+
return this._replacements;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
// src/model/schema-formula/core/FormulaError.ts
|
|
760
|
+
var FormulaError = class extends Error {
|
|
761
|
+
constructor(message, nodeId, details) {
|
|
762
|
+
super(message);
|
|
763
|
+
this.nodeId = nodeId;
|
|
764
|
+
this.details = details;
|
|
765
|
+
this.name = "FormulaError";
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
// src/model/schema-formula/serialization/FormulaPathBuilder.ts
|
|
770
|
+
var FormulaPathBuilder = class {
|
|
771
|
+
buildWithArrayNotation(fromPath, toPath) {
|
|
772
|
+
const fromSegments = fromPath.parent().segments();
|
|
773
|
+
const toSegments = toPath.segments();
|
|
774
|
+
const commonLength = this.findCommonPrefixLength(fromSegments, toSegments);
|
|
775
|
+
const upCount = fromSegments.length - commonLength;
|
|
776
|
+
const parts = this.buildPartsWithArrayNotation(
|
|
777
|
+
upCount,
|
|
778
|
+
toSegments,
|
|
779
|
+
commonLength
|
|
780
|
+
);
|
|
781
|
+
return this.formatPartsWithArrayNotation(parts, toSegments);
|
|
782
|
+
}
|
|
783
|
+
findCommonPrefixLength(fromSegments, toSegments) {
|
|
784
|
+
const minLen = Math.min(fromSegments.length, toSegments.length);
|
|
785
|
+
let commonPrefixLen = 0;
|
|
786
|
+
for (let i = 0; i < minLen; i++) {
|
|
787
|
+
const fromSeg = fromSegments[i];
|
|
788
|
+
const toSeg = toSegments[i];
|
|
789
|
+
if (!fromSeg || !toSeg) {
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
if (fromSeg.isItems() && toSeg.isItems()) {
|
|
793
|
+
commonPrefixLen++;
|
|
794
|
+
} else if (fromSeg.isProperty() && toSeg.isProperty() && fromSeg.propertyName() === toSeg.propertyName()) {
|
|
795
|
+
commonPrefixLen++;
|
|
796
|
+
} else {
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return commonPrefixLen;
|
|
801
|
+
}
|
|
802
|
+
buildPartsWithArrayNotation(upCount, toSegments, startIndex) {
|
|
803
|
+
const parts = [];
|
|
804
|
+
for (let i = 0; i < upCount; i++) {
|
|
805
|
+
parts.push("..");
|
|
806
|
+
}
|
|
807
|
+
for (let i = startIndex; i < toSegments.length; i++) {
|
|
808
|
+
const seg = toSegments[i];
|
|
809
|
+
if (seg) {
|
|
810
|
+
if (seg.isProperty()) {
|
|
811
|
+
parts.push(seg.propertyName());
|
|
812
|
+
} else if (seg.isItems() && parts.length > 0) {
|
|
813
|
+
const lastPart = parts.at(-1);
|
|
814
|
+
if (lastPart && lastPart !== "..") {
|
|
815
|
+
parts[parts.length - 1] = lastPart + "[*]";
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return parts;
|
|
821
|
+
}
|
|
822
|
+
formatPartsWithArrayNotation(parts, toSegments) {
|
|
823
|
+
if (parts.length === 0) {
|
|
824
|
+
const lastSeg = toSegments.at(-1);
|
|
825
|
+
if (lastSeg?.isProperty()) {
|
|
826
|
+
return lastSeg.propertyName();
|
|
827
|
+
}
|
|
828
|
+
return "";
|
|
829
|
+
}
|
|
830
|
+
if (parts[0] === "..") {
|
|
831
|
+
return parts.join("/");
|
|
832
|
+
}
|
|
833
|
+
return parts.join(".");
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/model/schema-formula/serialization/FormulaSerializer.ts
|
|
838
|
+
var FormulaSerializer = class _FormulaSerializer {
|
|
839
|
+
constructor(tree, formulaNodeId, formula) {
|
|
840
|
+
this.tree = tree;
|
|
841
|
+
this.formulaNodeId = formulaNodeId;
|
|
842
|
+
this.formula = formula;
|
|
843
|
+
}
|
|
844
|
+
pathBuilder = new FormulaPathBuilder();
|
|
845
|
+
static toXFormula(tree, formulaNodeId, formula) {
|
|
846
|
+
const serializer = new _FormulaSerializer(tree, formulaNodeId, formula);
|
|
847
|
+
return {
|
|
848
|
+
version: 1,
|
|
849
|
+
expression: serializer.serialize()
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
static serializeExpression(tree, formulaNodeId, formula, options = {}) {
|
|
853
|
+
const serializer = new _FormulaSerializer(tree, formulaNodeId, formula);
|
|
854
|
+
return serializer.serialize(options);
|
|
855
|
+
}
|
|
856
|
+
serialize(options = {}) {
|
|
857
|
+
const replacements = this.buildPathReplacements(options);
|
|
858
|
+
const updatedAst = formula.replaceDependencies(this.formula.ast(), replacements);
|
|
859
|
+
return formula.serializeAst(updatedAst);
|
|
860
|
+
}
|
|
861
|
+
buildPathReplacements(options) {
|
|
862
|
+
const replacements = {};
|
|
863
|
+
const formulaPath = this.tree.pathOf(this.formulaNodeId);
|
|
864
|
+
const strict = options.strict ?? true;
|
|
865
|
+
for (const astPath of this.formula.astPaths()) {
|
|
866
|
+
const nodeId = this.formula.getNodeIdForAstPath(astPath);
|
|
867
|
+
if (!nodeId) {
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
const targetNode = this.tree.nodeById(nodeId);
|
|
871
|
+
if (targetNode.isNull()) {
|
|
872
|
+
if (strict) {
|
|
873
|
+
throw new FormulaError(
|
|
874
|
+
`Cannot serialize formula: target node not found`,
|
|
875
|
+
this.formulaNodeId,
|
|
876
|
+
`Target nodeId: ${nodeId}`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
const targetPath = this.tree.pathOf(nodeId);
|
|
882
|
+
const newPath = this.pathBuilder.buildWithArrayNotation(
|
|
883
|
+
formulaPath,
|
|
884
|
+
targetPath
|
|
885
|
+
);
|
|
886
|
+
if (this.needsReplacement(astPath, newPath)) {
|
|
887
|
+
replacements[astPath] = newPath;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return replacements;
|
|
891
|
+
}
|
|
892
|
+
needsReplacement(astPath, newPath) {
|
|
893
|
+
if (astPath === newPath) {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
const normalizedAstPath = this.normalizeArrayNotation(astPath);
|
|
897
|
+
const normalizedNewPath = this.normalizeArrayNotation(newPath);
|
|
898
|
+
return normalizedAstPath !== normalizedNewPath;
|
|
899
|
+
}
|
|
900
|
+
normalizeArrayNotation(path) {
|
|
901
|
+
return path.replaceAll(/\[\d+\]/g, "[*]");
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
// src/core/schema-diff/SchemaComparator.ts
|
|
906
|
+
function areNodesEqual(current, base, context) {
|
|
907
|
+
if (current.nodeType() !== base.nodeType()) {
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
if (current.name() !== base.name()) {
|
|
911
|
+
return false;
|
|
912
|
+
}
|
|
913
|
+
if (!areMetadataEqual(current, base)) {
|
|
914
|
+
return false;
|
|
915
|
+
}
|
|
916
|
+
if (current.isPrimitive()) {
|
|
917
|
+
return arePrimitivesEqual(current, base, context);
|
|
918
|
+
}
|
|
919
|
+
if (current.isObject()) {
|
|
920
|
+
return areObjectsEqual(current, base, context);
|
|
921
|
+
}
|
|
922
|
+
if (current.isArray()) {
|
|
923
|
+
return areArraysEqual(current, base, context);
|
|
924
|
+
}
|
|
925
|
+
if (current.isRef()) {
|
|
926
|
+
return current.ref() === base.ref();
|
|
927
|
+
}
|
|
928
|
+
return current.isNull() && base.isNull();
|
|
929
|
+
}
|
|
930
|
+
function areNodesContentEqual(current, base, context) {
|
|
931
|
+
if (current.nodeType() !== base.nodeType()) {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
if (!areMetadataEqual(current, base)) {
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
if (current.isPrimitive()) {
|
|
938
|
+
return arePrimitivesEqual(current, base, context);
|
|
939
|
+
}
|
|
940
|
+
if (current.isObject()) {
|
|
941
|
+
return areObjectsEqual(current, base, context);
|
|
942
|
+
}
|
|
943
|
+
if (current.isArray()) {
|
|
944
|
+
return areArraysEqual(current, base, context);
|
|
945
|
+
}
|
|
946
|
+
if (current.isRef()) {
|
|
947
|
+
return current.ref() === base.ref();
|
|
948
|
+
}
|
|
949
|
+
return current.isNull() && base.isNull();
|
|
950
|
+
}
|
|
951
|
+
function areMetadataEqual(current, base) {
|
|
952
|
+
const metaCurrent = current.metadata();
|
|
953
|
+
const metaBase = base.metadata();
|
|
954
|
+
return metaCurrent.title === metaBase.title && metaCurrent.description === metaBase.description && metaCurrent.deprecated === metaBase.deprecated;
|
|
955
|
+
}
|
|
956
|
+
function arePrimitivesEqual(current, base, context) {
|
|
957
|
+
if (current.defaultValue() !== base.defaultValue()) {
|
|
958
|
+
return false;
|
|
959
|
+
}
|
|
960
|
+
if (current.foreignKey() !== base.foreignKey()) {
|
|
961
|
+
return false;
|
|
962
|
+
}
|
|
963
|
+
const currentFormula = current.formula();
|
|
964
|
+
const baseFormula = base.formula();
|
|
965
|
+
if (currentFormula === void 0 && baseFormula === void 0) {
|
|
966
|
+
return true;
|
|
967
|
+
}
|
|
968
|
+
if (currentFormula === void 0 || baseFormula === void 0) {
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
return areFormulasEqual(
|
|
972
|
+
currentFormula,
|
|
973
|
+
baseFormula,
|
|
974
|
+
current.id(),
|
|
975
|
+
base.id(),
|
|
976
|
+
context
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
function areFormulasEqual(currentFormula, baseFormula, currentNodeId, baseNodeId, context) {
|
|
980
|
+
if (currentFormula.version() !== baseFormula.version()) {
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
const currentExpr = getSerializedExpression(
|
|
984
|
+
currentFormula,
|
|
985
|
+
context.currentTree,
|
|
986
|
+
currentNodeId
|
|
987
|
+
);
|
|
988
|
+
const baseExpr = getSerializedExpression(
|
|
989
|
+
baseFormula,
|
|
990
|
+
context.baseTree,
|
|
991
|
+
baseNodeId
|
|
992
|
+
);
|
|
993
|
+
return currentExpr === baseExpr;
|
|
994
|
+
}
|
|
995
|
+
function getSerializedExpression(formula, tree, nodeId) {
|
|
996
|
+
return FormulaSerializer.serializeExpression(tree, nodeId, formula, { strict: false });
|
|
997
|
+
}
|
|
998
|
+
function areObjectsEqual(current, base, context) {
|
|
999
|
+
const propsCurrent = current.properties();
|
|
1000
|
+
const propsBase = base.properties();
|
|
1001
|
+
if (propsCurrent.length !== propsBase.length) {
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
for (const propCurrent of propsCurrent) {
|
|
1005
|
+
const propBase = propsBase.find((p) => p.name() === propCurrent.name());
|
|
1006
|
+
if (!propBase || !areNodesEqual(propCurrent, propBase, context)) {
|
|
1007
|
+
return false;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
return true;
|
|
1011
|
+
}
|
|
1012
|
+
function areArraysEqual(current, base, context) {
|
|
1013
|
+
if (current.defaultValue() !== base.defaultValue()) {
|
|
1014
|
+
return false;
|
|
1015
|
+
}
|
|
1016
|
+
return areNodesEqual(current.items(), base.items(), context);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// src/core/schema-diff/ChangeCollector.ts
|
|
1020
|
+
var ChangeCollector = class {
|
|
1021
|
+
constructor(baseTree, currentTree, index) {
|
|
1022
|
+
this.baseTree = baseTree;
|
|
1023
|
+
this.currentTree = currentTree;
|
|
1024
|
+
this.index = index;
|
|
1025
|
+
this.context = { currentTree, baseTree };
|
|
1026
|
+
}
|
|
1027
|
+
context;
|
|
1028
|
+
collect() {
|
|
1029
|
+
const changes = [];
|
|
1030
|
+
this.collectFromCurrentTree(changes);
|
|
1031
|
+
this.collectRemovedNodes(changes);
|
|
1032
|
+
return changes;
|
|
1033
|
+
}
|
|
1034
|
+
collectFromCurrentTree(changes) {
|
|
1035
|
+
for (const nodeId of this.currentTree.nodeIds()) {
|
|
1036
|
+
const currentNode = this.currentTree.nodeById(nodeId);
|
|
1037
|
+
if (this.index.isReplacement(nodeId)) {
|
|
1038
|
+
const originalId = this.index.getOriginalNodeId(nodeId);
|
|
1039
|
+
if (originalId) {
|
|
1040
|
+
const baseNode2 = this.baseTree.nodeById(originalId);
|
|
1041
|
+
changes.push({
|
|
1042
|
+
type: "modified",
|
|
1043
|
+
baseNode: baseNode2,
|
|
1044
|
+
currentNode
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
continue;
|
|
1048
|
+
}
|
|
1049
|
+
const basePath = this.index.getBasePath(nodeId);
|
|
1050
|
+
if (!basePath) {
|
|
1051
|
+
changes.push({
|
|
1052
|
+
type: "added",
|
|
1053
|
+
baseNode: null,
|
|
1054
|
+
currentNode
|
|
1055
|
+
});
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
const currentPath = this.currentTree.pathOf(nodeId);
|
|
1059
|
+
const baseNode = this.baseTree.nodeById(nodeId);
|
|
1060
|
+
if (!basePath.equals(currentPath)) {
|
|
1061
|
+
changes.push({
|
|
1062
|
+
type: "moved",
|
|
1063
|
+
baseNode,
|
|
1064
|
+
currentNode
|
|
1065
|
+
});
|
|
1066
|
+
if (!areNodesContentEqual(currentNode, baseNode, this.context)) {
|
|
1067
|
+
changes.push({
|
|
1068
|
+
type: "modified",
|
|
1069
|
+
baseNode,
|
|
1070
|
+
currentNode
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
} else if (!areNodesEqual(currentNode, baseNode, this.context)) {
|
|
1074
|
+
changes.push({
|
|
1075
|
+
type: "modified",
|
|
1076
|
+
baseNode,
|
|
1077
|
+
currentNode
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
collectRemovedNodes(changes) {
|
|
1083
|
+
for (const nodeId of this.baseTree.nodeIds()) {
|
|
1084
|
+
if (this.index.getReplacementNodeId(nodeId)) {
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
const currentNode = this.currentTree.nodeById(nodeId);
|
|
1088
|
+
if (currentNode.isNull()) {
|
|
1089
|
+
const baseNode = this.baseTree.nodeById(nodeId);
|
|
1090
|
+
changes.push({
|
|
1091
|
+
type: "removed",
|
|
1092
|
+
baseNode,
|
|
1093
|
+
currentNode: null
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
function collectChanges(baseTree, currentTree, index) {
|
|
1100
|
+
return new ChangeCollector(baseTree, currentTree, index).collect();
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// src/core/schema-diff/ChangeCoalescer.ts
|
|
1104
|
+
var ChangeCoalescer = class {
|
|
1105
|
+
constructor(currentTree, index) {
|
|
1106
|
+
this.currentTree = currentTree;
|
|
1107
|
+
this.index = index;
|
|
1108
|
+
}
|
|
1109
|
+
coalesce(changes) {
|
|
1110
|
+
const moved = [];
|
|
1111
|
+
const added = [];
|
|
1112
|
+
const removed = [];
|
|
1113
|
+
const modified = [];
|
|
1114
|
+
const movedPaths = this.getMovedPaths(changes);
|
|
1115
|
+
for (const change of changes) {
|
|
1116
|
+
if (this.isNestedChange(change, changes, movedPaths)) {
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
switch (change.type) {
|
|
1120
|
+
case "moved":
|
|
1121
|
+
moved.push(change);
|
|
1122
|
+
break;
|
|
1123
|
+
case "added":
|
|
1124
|
+
added.push(change);
|
|
1125
|
+
break;
|
|
1126
|
+
case "removed":
|
|
1127
|
+
removed.push(change);
|
|
1128
|
+
break;
|
|
1129
|
+
case "modified":
|
|
1130
|
+
modified.push(change);
|
|
1131
|
+
break;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return { moved, added, removed, modified };
|
|
1135
|
+
}
|
|
1136
|
+
getMovedPaths(changes) {
|
|
1137
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1138
|
+
for (const change of changes) {
|
|
1139
|
+
if (change.type === "moved") {
|
|
1140
|
+
const basePath = this.index.getBasePath(change.baseNode.id());
|
|
1141
|
+
if (basePath) {
|
|
1142
|
+
paths.add(basePath.asJsonPointer());
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return paths;
|
|
1147
|
+
}
|
|
1148
|
+
isNestedChange(change, allChanges, movedPaths) {
|
|
1149
|
+
const path = this.getChangePath(change);
|
|
1150
|
+
if (this.hasParentChange(change, allChanges, path)) {
|
|
1151
|
+
return true;
|
|
1152
|
+
}
|
|
1153
|
+
if (this.isAffectedByMove(change, movedPaths)) {
|
|
1154
|
+
return true;
|
|
1155
|
+
}
|
|
1156
|
+
return false;
|
|
1157
|
+
}
|
|
1158
|
+
getChangePath(change) {
|
|
1159
|
+
if (change.type === "removed") {
|
|
1160
|
+
const basePath = this.index.getBasePath(change.baseNode.id());
|
|
1161
|
+
if (!basePath) {
|
|
1162
|
+
throw new Error(
|
|
1163
|
+
`Base path not found for removed node: ${change.baseNode.id()}`
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
return basePath;
|
|
1167
|
+
}
|
|
1168
|
+
return this.currentTree.pathOf(change.currentNode.id());
|
|
1169
|
+
}
|
|
1170
|
+
hasParentChange(change, allChanges, path) {
|
|
1171
|
+
for (const other of allChanges) {
|
|
1172
|
+
if (other === change) continue;
|
|
1173
|
+
if (other.type === "modified") {
|
|
1174
|
+
if (!this.isTypeChangeReplacement(other)) {
|
|
1175
|
+
continue;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
const otherPath = this.getChangePath(other);
|
|
1179
|
+
if (path.isChildOf(otherPath)) {
|
|
1180
|
+
return true;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
isTypeChangeReplacement(change) {
|
|
1186
|
+
return change.baseNode.nodeType() !== change.currentNode.nodeType();
|
|
1187
|
+
}
|
|
1188
|
+
isAffectedByMove(change, movedPaths) {
|
|
1189
|
+
if (change.type !== "modified") {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
const basePath = this.index.getBasePath(change.baseNode.id());
|
|
1193
|
+
if (!basePath) {
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
for (const movedPath of movedPaths) {
|
|
1197
|
+
if (basePath.asJsonPointer().startsWith(movedPath + "/") && basePath.asJsonPointer() !== movedPath) {
|
|
1198
|
+
return true;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return false;
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
function coalesceChanges(changes, currentTree, index) {
|
|
1205
|
+
return new ChangeCoalescer(currentTree, index).coalesce(changes);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// src/core/schema-diff/SchemaDiff.ts
|
|
1209
|
+
var SchemaDiff = class {
|
|
1210
|
+
_baseTree;
|
|
1211
|
+
_currentTree;
|
|
1212
|
+
_index;
|
|
1213
|
+
constructor(currentTree) {
|
|
1214
|
+
this._currentTree = currentTree;
|
|
1215
|
+
this._baseTree = currentTree.clone();
|
|
1216
|
+
this._index = new NodePathIndex(this._baseTree);
|
|
1217
|
+
}
|
|
1218
|
+
get baseTree() {
|
|
1219
|
+
return this._baseTree;
|
|
1220
|
+
}
|
|
1221
|
+
get currentTree() {
|
|
1222
|
+
return this._currentTree;
|
|
1223
|
+
}
|
|
1224
|
+
get index() {
|
|
1225
|
+
return this._index;
|
|
1226
|
+
}
|
|
1227
|
+
isDirty() {
|
|
1228
|
+
const changes = this.collectChanges();
|
|
1229
|
+
return changes.length > 0;
|
|
1230
|
+
}
|
|
1231
|
+
collectChanges() {
|
|
1232
|
+
return collectChanges(this._baseTree, this._currentTree, this._index);
|
|
1233
|
+
}
|
|
1234
|
+
coalesceChanges(changes) {
|
|
1235
|
+
const rawChanges = changes ?? this.collectChanges();
|
|
1236
|
+
return coalesceChanges(rawChanges, this._currentTree, this._index);
|
|
1237
|
+
}
|
|
1238
|
+
trackReplacement(oldNodeId, newNodeId) {
|
|
1239
|
+
this._index.trackReplacement(oldNodeId, newNodeId);
|
|
1240
|
+
}
|
|
1241
|
+
markAsSaved() {
|
|
1242
|
+
this._baseTree = this._currentTree.clone();
|
|
1243
|
+
this._index = new NodePathIndex(this._baseTree);
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1246
|
+
|
|
1247
|
+
// src/model/schema-formula/core/FormulaDependency.ts
|
|
1248
|
+
var ResolvedDependency = class {
|
|
1249
|
+
constructor(nodeId) {
|
|
1250
|
+
this.nodeId = nodeId;
|
|
1251
|
+
if (!nodeId) {
|
|
1252
|
+
throw new Error("ResolvedDependency requires a non-empty nodeId");
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
targetNodeId() {
|
|
1256
|
+
return this.nodeId;
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
var ARRAY_NOTATION_REGEX = /^([^[]+)\[(?:\d+|\*)?\]$/;
|
|
1260
|
+
var FormulaPath = class {
|
|
1261
|
+
constructor(basePath, relativePath) {
|
|
1262
|
+
this.basePath = basePath;
|
|
1263
|
+
this.relativePath = relativePath;
|
|
1264
|
+
}
|
|
1265
|
+
resolve() {
|
|
1266
|
+
let ast;
|
|
1267
|
+
try {
|
|
1268
|
+
const parseResult = formula.parseFormula(this.relativePath);
|
|
1269
|
+
ast = parseResult.ast;
|
|
1270
|
+
} catch {
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
return this.astToPath(ast, this.basePath);
|
|
1274
|
+
}
|
|
1275
|
+
astToPath(ast, base) {
|
|
1276
|
+
switch (ast.type) {
|
|
1277
|
+
case "Identifier":
|
|
1278
|
+
return base.child(ast.name);
|
|
1279
|
+
case "MemberExpression": {
|
|
1280
|
+
const objectPath = this.astToPath(ast.object, base);
|
|
1281
|
+
if (!objectPath) {
|
|
1282
|
+
return null;
|
|
1283
|
+
}
|
|
1284
|
+
return objectPath.child(ast.property);
|
|
1285
|
+
}
|
|
1286
|
+
case "IndexExpression":
|
|
1287
|
+
case "WildcardExpression": {
|
|
1288
|
+
const objectPath = this.astToPath(ast.object, base);
|
|
1289
|
+
if (!objectPath) {
|
|
1290
|
+
return null;
|
|
1291
|
+
}
|
|
1292
|
+
return objectPath.childItems();
|
|
1293
|
+
}
|
|
1294
|
+
case "RelativePath":
|
|
1295
|
+
return this.resolveRelativePathString(base, ast.path);
|
|
1296
|
+
case "RootPath":
|
|
1297
|
+
return this.resolveRootPath(ast.path);
|
|
1298
|
+
default:
|
|
1299
|
+
return null;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
resolveRelativePathString(base, path) {
|
|
1303
|
+
const parts = path.split("/");
|
|
1304
|
+
let result = base;
|
|
1305
|
+
for (const part of parts) {
|
|
1306
|
+
if (part === "..") {
|
|
1307
|
+
if (result.isEmpty()) {
|
|
1308
|
+
return null;
|
|
1309
|
+
}
|
|
1310
|
+
result = result.parent();
|
|
1311
|
+
} else if (part === ".") {
|
|
1312
|
+
continue;
|
|
1313
|
+
} else if (part) {
|
|
1314
|
+
result = result.child(part);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return result;
|
|
1318
|
+
}
|
|
1319
|
+
resolveRootPath(rootPath) {
|
|
1320
|
+
const path = rootPath.startsWith("/") ? rootPath.slice(1) : rootPath;
|
|
1321
|
+
if (!path) {
|
|
1322
|
+
return EMPTY_PATH;
|
|
1323
|
+
}
|
|
1324
|
+
try {
|
|
1325
|
+
return this.parseFormulaPath(path);
|
|
1326
|
+
} catch {
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
parseFormulaPath(formulaPath) {
|
|
1331
|
+
const parts = formulaPath.split(".");
|
|
1332
|
+
let result = EMPTY_PATH;
|
|
1333
|
+
for (const part of parts) {
|
|
1334
|
+
if (!part) {
|
|
1335
|
+
throw new Error(`Invalid path: empty segment`);
|
|
1336
|
+
}
|
|
1337
|
+
const match = ARRAY_NOTATION_REGEX.exec(part);
|
|
1338
|
+
if (match?.[1]) {
|
|
1339
|
+
result = result.child(match[1]).childItems();
|
|
1340
|
+
} else {
|
|
1341
|
+
result = result.child(part);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return result;
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1348
|
+
// src/model/schema-formula/parsing/ParsedFormula.ts
|
|
1349
|
+
var ParsedFormula = class {
|
|
1350
|
+
_expression;
|
|
1351
|
+
astNode;
|
|
1352
|
+
deps;
|
|
1353
|
+
astPathToNodeId;
|
|
1354
|
+
constructor(tree, formulaNodeId, expression) {
|
|
1355
|
+
this._expression = expression;
|
|
1356
|
+
const parseResult = formula.parseFormula(expression);
|
|
1357
|
+
this.astNode = parseResult.ast;
|
|
1358
|
+
const formulaPath = tree.pathOf(formulaNodeId);
|
|
1359
|
+
if (formulaPath.isEmpty() && tree.root().id() !== formulaNodeId) {
|
|
1360
|
+
throw new FormulaError("Formula node not found in tree", formulaNodeId);
|
|
1361
|
+
}
|
|
1362
|
+
const deps = [];
|
|
1363
|
+
const astPathToNodeId = /* @__PURE__ */ new Map();
|
|
1364
|
+
for (const depPath of parseResult.dependencies) {
|
|
1365
|
+
const targetNodeId = this.resolveDependencyPath(
|
|
1366
|
+
tree,
|
|
1367
|
+
formulaPath,
|
|
1368
|
+
depPath
|
|
1369
|
+
);
|
|
1370
|
+
if (!targetNodeId) {
|
|
1371
|
+
throw new FormulaError(
|
|
1372
|
+
`Cannot resolve formula dependency: ${depPath}`,
|
|
1373
|
+
formulaNodeId,
|
|
1374
|
+
"Path not found in schema"
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
if (targetNodeId === formulaNodeId) {
|
|
1378
|
+
throw new FormulaError(
|
|
1379
|
+
"Formula cannot reference itself",
|
|
1380
|
+
formulaNodeId,
|
|
1381
|
+
"Self-reference detected"
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
deps.push(new ResolvedDependency(targetNodeId));
|
|
1385
|
+
astPathToNodeId.set(depPath, targetNodeId);
|
|
1386
|
+
}
|
|
1387
|
+
this.deps = deps;
|
|
1388
|
+
this.astPathToNodeId = astPathToNodeId;
|
|
1389
|
+
}
|
|
1390
|
+
version() {
|
|
1391
|
+
return 1;
|
|
1392
|
+
}
|
|
1393
|
+
expression() {
|
|
1394
|
+
return this._expression;
|
|
1395
|
+
}
|
|
1396
|
+
ast() {
|
|
1397
|
+
return this.astNode;
|
|
1398
|
+
}
|
|
1399
|
+
dependencies() {
|
|
1400
|
+
return this.deps;
|
|
1401
|
+
}
|
|
1402
|
+
getNodeIdForAstPath(astPath) {
|
|
1403
|
+
return this.astPathToNodeId.get(astPath) ?? null;
|
|
1404
|
+
}
|
|
1405
|
+
astPaths() {
|
|
1406
|
+
return Array.from(this.astPathToNodeId.keys());
|
|
1407
|
+
}
|
|
1408
|
+
resolveDependencyPath(tree, formulaNodePath, depPath) {
|
|
1409
|
+
const basePath = this.getFormulaBasePath(formulaNodePath);
|
|
1410
|
+
const depFormulaPath = new FormulaPath(basePath, depPath);
|
|
1411
|
+
const targetPath = depFormulaPath.resolve();
|
|
1412
|
+
if (!targetPath) {
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
const targetNode = tree.nodeAt(targetPath);
|
|
1416
|
+
if (targetNode.isNull()) {
|
|
1417
|
+
return null;
|
|
1418
|
+
}
|
|
1419
|
+
return targetNode.id();
|
|
1420
|
+
}
|
|
1421
|
+
getFormulaBasePath(formulaPath) {
|
|
1422
|
+
let basePath = formulaPath;
|
|
1423
|
+
while (!basePath.isEmpty()) {
|
|
1424
|
+
const segs = basePath.segments();
|
|
1425
|
+
const lastSeg = segs[segs.length - 1];
|
|
1426
|
+
basePath = basePath.parent();
|
|
1427
|
+
if (!lastSeg?.isItems()) {
|
|
1428
|
+
break;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
return basePath;
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
|
|
1435
|
+
// src/model/schema-formula/store/FormulaDependencyIndex.ts
|
|
1436
|
+
var FormulaDependencyIndex = class {
|
|
1437
|
+
dependentsMap = /* @__PURE__ */ new Map();
|
|
1438
|
+
formulasByNodeId = /* @__PURE__ */ new Map();
|
|
1439
|
+
registerFormula(formulaNodeId, formula) {
|
|
1440
|
+
this.unregisterFormula(formulaNodeId);
|
|
1441
|
+
this.formulasByNodeId.set(formulaNodeId, formula);
|
|
1442
|
+
for (const dep of formula.dependencies()) {
|
|
1443
|
+
const targetId = dep.targetNodeId();
|
|
1444
|
+
let dependents = this.dependentsMap.get(targetId);
|
|
1445
|
+
if (!dependents) {
|
|
1446
|
+
dependents = /* @__PURE__ */ new Set();
|
|
1447
|
+
this.dependentsMap.set(targetId, dependents);
|
|
1448
|
+
}
|
|
1449
|
+
dependents.add(formulaNodeId);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
unregisterFormula(formulaNodeId) {
|
|
1453
|
+
this.formulasByNodeId.delete(formulaNodeId);
|
|
1454
|
+
for (const [targetId, dependents] of this.dependentsMap) {
|
|
1455
|
+
dependents.delete(formulaNodeId);
|
|
1456
|
+
if (dependents.size === 0) {
|
|
1457
|
+
this.dependentsMap.delete(targetId);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
getDependents(nodeId) {
|
|
1462
|
+
const dependents = this.dependentsMap.get(nodeId);
|
|
1463
|
+
return dependents ? Array.from(dependents) : [];
|
|
1464
|
+
}
|
|
1465
|
+
hasDependents(nodeId) {
|
|
1466
|
+
const dependents = this.dependentsMap.get(nodeId);
|
|
1467
|
+
return dependents !== void 0 && dependents.size > 0;
|
|
1468
|
+
}
|
|
1469
|
+
getFormula(nodeId) {
|
|
1470
|
+
return this.formulasByNodeId.get(nodeId) ?? null;
|
|
1471
|
+
}
|
|
1472
|
+
hasFormula(nodeId) {
|
|
1473
|
+
return this.formulasByNodeId.has(nodeId);
|
|
1474
|
+
}
|
|
1475
|
+
clear() {
|
|
1476
|
+
this.dependentsMap.clear();
|
|
1477
|
+
this.formulasByNodeId.clear();
|
|
1478
|
+
}
|
|
1479
|
+
forEachFormula(callback) {
|
|
1480
|
+
for (const [nodeId, formula] of this.formulasByNodeId) {
|
|
1481
|
+
callback(nodeId, formula);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
size() {
|
|
1485
|
+
return this.formulasByNodeId.size;
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
|
|
1489
|
+
// src/core/schema-serializer/SchemaSerializer.ts
|
|
1490
|
+
var SchemaSerializer = class {
|
|
1491
|
+
tree = null;
|
|
1492
|
+
excludeNodeIds = /* @__PURE__ */ new Set();
|
|
1493
|
+
serializeNode(node, tree, options) {
|
|
1494
|
+
this.tree = tree;
|
|
1495
|
+
this.excludeNodeIds = options?.excludeNodeIds ?? /* @__PURE__ */ new Set();
|
|
1496
|
+
try {
|
|
1497
|
+
return this.serialize(node);
|
|
1498
|
+
} finally {
|
|
1499
|
+
this.tree = null;
|
|
1500
|
+
this.excludeNodeIds = /* @__PURE__ */ new Set();
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
serializeTree(tree) {
|
|
1504
|
+
return this.serializeNode(tree.root(), tree);
|
|
1505
|
+
}
|
|
1506
|
+
serialize(node) {
|
|
1507
|
+
if (node.isNull()) {
|
|
1508
|
+
throw new Error("Cannot serialize null node");
|
|
1509
|
+
}
|
|
1510
|
+
if (node.isObject()) {
|
|
1511
|
+
return this.serializeObject(node);
|
|
1512
|
+
}
|
|
1513
|
+
if (node.isArray()) {
|
|
1514
|
+
return this.serializeArray(node);
|
|
1515
|
+
}
|
|
1516
|
+
if (node.isRef()) {
|
|
1517
|
+
return this.serializeRef(node);
|
|
1518
|
+
}
|
|
1519
|
+
return this.serializePrimitive(node);
|
|
1520
|
+
}
|
|
1521
|
+
serializeObject(node) {
|
|
1522
|
+
const properties = {};
|
|
1523
|
+
const required = [];
|
|
1524
|
+
for (const child of node.properties()) {
|
|
1525
|
+
if (this.shouldExclude(child)) {
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
properties[child.name()] = this.serialize(child);
|
|
1529
|
+
required.push(child.name());
|
|
1530
|
+
}
|
|
1531
|
+
const result = {
|
|
1532
|
+
type: "object" /* Object */,
|
|
1533
|
+
properties,
|
|
1534
|
+
additionalProperties: false,
|
|
1535
|
+
required
|
|
1536
|
+
};
|
|
1537
|
+
return this.addMetadata(result, node);
|
|
1538
|
+
}
|
|
1539
|
+
serializeArray(node) {
|
|
1540
|
+
const items = node.items();
|
|
1541
|
+
if (items.isNull()) {
|
|
1542
|
+
throw new Error("Array node must have items");
|
|
1543
|
+
}
|
|
1544
|
+
const result = {
|
|
1545
|
+
type: "array" /* Array */,
|
|
1546
|
+
items: this.serialize(items)
|
|
1547
|
+
};
|
|
1548
|
+
return this.addMetadata(result, node);
|
|
1549
|
+
}
|
|
1550
|
+
serializeRef(node) {
|
|
1551
|
+
const ref = node.ref();
|
|
1552
|
+
if (!ref) {
|
|
1553
|
+
throw new Error("Ref node must have a ref value");
|
|
1554
|
+
}
|
|
1555
|
+
const result = {
|
|
1556
|
+
$ref: ref
|
|
1557
|
+
};
|
|
1558
|
+
return this.addMetadata(result, node);
|
|
1559
|
+
}
|
|
1560
|
+
serializePrimitive(node) {
|
|
1561
|
+
const nodeType = node.nodeType();
|
|
1562
|
+
switch (nodeType) {
|
|
1563
|
+
case "string":
|
|
1564
|
+
return this.serializeString(node);
|
|
1565
|
+
case "number":
|
|
1566
|
+
return this.serializeNumber(node);
|
|
1567
|
+
case "boolean":
|
|
1568
|
+
return this.serializeBoolean(node);
|
|
1569
|
+
default:
|
|
1570
|
+
throw new Error(`Unknown primitive type: ${nodeType}`);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
serializeString(node) {
|
|
1574
|
+
const result = {
|
|
1575
|
+
type: "string" /* String */,
|
|
1576
|
+
default: node.defaultValue() ?? ""
|
|
1577
|
+
};
|
|
1578
|
+
const foreignKey = node.foreignKey();
|
|
1579
|
+
if (foreignKey) {
|
|
1580
|
+
result.foreignKey = foreignKey;
|
|
1581
|
+
}
|
|
1582
|
+
const formula = node.formula();
|
|
1583
|
+
if (formula) {
|
|
1584
|
+
result.readOnly = true;
|
|
1585
|
+
result["x-formula"] = this.serializeFormula(node, formula);
|
|
1586
|
+
}
|
|
1587
|
+
return this.addMetadata(result, node);
|
|
1588
|
+
}
|
|
1589
|
+
serializeNumber(node) {
|
|
1590
|
+
const result = {
|
|
1591
|
+
type: "number" /* Number */,
|
|
1592
|
+
default: node.defaultValue() ?? 0
|
|
1593
|
+
};
|
|
1594
|
+
const formula = node.formula();
|
|
1595
|
+
if (formula) {
|
|
1596
|
+
result.readOnly = true;
|
|
1597
|
+
result["x-formula"] = this.serializeFormula(node, formula);
|
|
1598
|
+
}
|
|
1599
|
+
return this.addMetadata(result, node);
|
|
1600
|
+
}
|
|
1601
|
+
serializeBoolean(node) {
|
|
1602
|
+
const result = {
|
|
1603
|
+
type: "boolean" /* Boolean */,
|
|
1604
|
+
default: node.defaultValue() ?? false
|
|
1605
|
+
};
|
|
1606
|
+
const formula = node.formula();
|
|
1607
|
+
if (formula) {
|
|
1608
|
+
result.readOnly = true;
|
|
1609
|
+
result["x-formula"] = this.serializeFormula(node, formula);
|
|
1610
|
+
}
|
|
1611
|
+
return this.addMetadata(result, node);
|
|
1612
|
+
}
|
|
1613
|
+
serializeFormula(node, formula) {
|
|
1614
|
+
if (!this.tree) {
|
|
1615
|
+
throw new Error(
|
|
1616
|
+
"Cannot serialize formula without tree context. Use serializeNode with tree."
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
return FormulaSerializer.toXFormula(this.tree, node.id(), formula);
|
|
1620
|
+
}
|
|
1621
|
+
addMetadata(schema, node) {
|
|
1622
|
+
const meta = node.metadata();
|
|
1623
|
+
if (meta.title) {
|
|
1624
|
+
schema.title = meta.title;
|
|
1625
|
+
}
|
|
1626
|
+
if (meta.description) {
|
|
1627
|
+
schema.description = meta.description;
|
|
1628
|
+
}
|
|
1629
|
+
if (meta.deprecated) {
|
|
1630
|
+
schema.deprecated = meta.deprecated;
|
|
1631
|
+
}
|
|
1632
|
+
return schema;
|
|
1633
|
+
}
|
|
1634
|
+
shouldExclude(node) {
|
|
1635
|
+
return this.excludeNodeIds.has(node.id());
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
|
|
1639
|
+
// src/core/schema-patch/PatchGenerator.ts
|
|
1640
|
+
var PatchGenerator = class {
|
|
1641
|
+
constructor(currentTree, baseTree) {
|
|
1642
|
+
this.currentTree = currentTree;
|
|
1643
|
+
this.baseTree = baseTree;
|
|
1644
|
+
this.context = { currentTree, baseTree };
|
|
1645
|
+
}
|
|
1646
|
+
serializer = new SchemaSerializer();
|
|
1647
|
+
context;
|
|
1648
|
+
generate(coalesced) {
|
|
1649
|
+
const movedNodeIds = this.collectMovedNodeIds(coalesced.moved);
|
|
1650
|
+
const movePatches = this.generateMovePatches(coalesced.moved);
|
|
1651
|
+
const addPatches = this.generateAddPatches(coalesced.added, movedNodeIds);
|
|
1652
|
+
const removePatches = this.generateRemovePatches(coalesced.removed);
|
|
1653
|
+
const { prerequisiteAdds, regularAdds } = this.partitionAddPatches(
|
|
1654
|
+
addPatches,
|
|
1655
|
+
movePatches
|
|
1656
|
+
);
|
|
1657
|
+
const childChangePaths = /* @__PURE__ */ new Set([
|
|
1658
|
+
...addPatches.map((p) => p.path),
|
|
1659
|
+
...removePatches.map((p) => p.path),
|
|
1660
|
+
...movePatches.flatMap((p) => [p.path, p.from ?? ""]).filter(Boolean)
|
|
1661
|
+
]);
|
|
1662
|
+
const replacePatches = this.generateReplacePatches(
|
|
1663
|
+
coalesced.modified,
|
|
1664
|
+
childChangePaths,
|
|
1665
|
+
movedNodeIds
|
|
1666
|
+
);
|
|
1667
|
+
return [
|
|
1668
|
+
...prerequisiteAdds,
|
|
1669
|
+
...movePatches,
|
|
1670
|
+
...replacePatches,
|
|
1671
|
+
...regularAdds,
|
|
1672
|
+
...removePatches
|
|
1673
|
+
];
|
|
1674
|
+
}
|
|
1675
|
+
collectMovedNodeIds(moved) {
|
|
1676
|
+
const nodeIds = /* @__PURE__ */ new Set();
|
|
1677
|
+
for (const change of moved) {
|
|
1678
|
+
nodeIds.add(change.currentNode.id());
|
|
1679
|
+
}
|
|
1680
|
+
return nodeIds;
|
|
1681
|
+
}
|
|
1682
|
+
partitionAddPatches(addPatches, movePatches) {
|
|
1683
|
+
const moveDestinations = movePatches.map((p) => jsonPointerToPath(p.path));
|
|
1684
|
+
const prerequisiteAdds = [];
|
|
1685
|
+
const regularAdds = [];
|
|
1686
|
+
for (const addPatch of addPatches) {
|
|
1687
|
+
const addPath = jsonPointerToPath(addPatch.path);
|
|
1688
|
+
const isPrerequisite = moveDestinations.some(
|
|
1689
|
+
(moveDest) => moveDest.isChildOf(addPath)
|
|
1690
|
+
);
|
|
1691
|
+
if (isPrerequisite) {
|
|
1692
|
+
prerequisiteAdds.push(addPatch);
|
|
1693
|
+
} else {
|
|
1694
|
+
regularAdds.push(addPatch);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
return { prerequisiteAdds, regularAdds };
|
|
1698
|
+
}
|
|
1699
|
+
generateMovePatches(moved) {
|
|
1700
|
+
const patches = [];
|
|
1701
|
+
for (const change of moved) {
|
|
1702
|
+
const basePath = this.baseTree.pathOf(change.baseNode.id());
|
|
1703
|
+
const currentPath = this.currentTree.pathOf(change.currentNode.id());
|
|
1704
|
+
patches.push({
|
|
1705
|
+
op: "move",
|
|
1706
|
+
from: basePath.asJsonPointer(),
|
|
1707
|
+
path: currentPath.asJsonPointer()
|
|
1708
|
+
});
|
|
1709
|
+
const modifyPatch = this.generateModifyAfterMove(
|
|
1710
|
+
change.baseNode,
|
|
1711
|
+
change.currentNode,
|
|
1712
|
+
currentPath.asJsonPointer()
|
|
1713
|
+
);
|
|
1714
|
+
if (modifyPatch) {
|
|
1715
|
+
patches.push(modifyPatch);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
return patches;
|
|
1719
|
+
}
|
|
1720
|
+
generateModifyAfterMove(baseNode, currentNode, currentPath) {
|
|
1721
|
+
if (areNodesContentEqual(currentNode, baseNode, this.context)) {
|
|
1722
|
+
return null;
|
|
1723
|
+
}
|
|
1724
|
+
const currentSchema = this.serializer.serializeNode(
|
|
1725
|
+
currentNode,
|
|
1726
|
+
this.currentTree
|
|
1727
|
+
);
|
|
1728
|
+
return {
|
|
1729
|
+
op: "replace",
|
|
1730
|
+
path: currentPath,
|
|
1731
|
+
value: currentSchema
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
generateAddPatches(added, movedNodeIds) {
|
|
1735
|
+
const patches = [];
|
|
1736
|
+
for (const change of added) {
|
|
1737
|
+
const currentPath = this.currentTree.pathOf(change.currentNode.id());
|
|
1738
|
+
const schema = this.serializer.serializeNode(
|
|
1739
|
+
change.currentNode,
|
|
1740
|
+
this.currentTree,
|
|
1741
|
+
{ excludeNodeIds: movedNodeIds }
|
|
1742
|
+
);
|
|
1743
|
+
patches.push({
|
|
1744
|
+
op: "add",
|
|
1745
|
+
path: currentPath.asJsonPointer(),
|
|
1746
|
+
value: schema
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
return patches;
|
|
1750
|
+
}
|
|
1751
|
+
generateRemovePatches(removed) {
|
|
1752
|
+
const patches = [];
|
|
1753
|
+
for (const change of removed) {
|
|
1754
|
+
const basePath = this.baseTree.pathOf(change.baseNode.id());
|
|
1755
|
+
patches.push({
|
|
1756
|
+
op: "remove",
|
|
1757
|
+
path: basePath.asJsonPointer()
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
return patches;
|
|
1761
|
+
}
|
|
1762
|
+
generateReplacePatches(modified, childChangePaths, movedNodeIds) {
|
|
1763
|
+
const patches = [];
|
|
1764
|
+
const replacedPaths = [];
|
|
1765
|
+
const childChangePathObjects = [...childChangePaths].map(jsonPointerToPath);
|
|
1766
|
+
for (const change of modified) {
|
|
1767
|
+
if (movedNodeIds.has(change.currentNode.id())) {
|
|
1768
|
+
continue;
|
|
1769
|
+
}
|
|
1770
|
+
const currentPath = this.currentTree.pathOf(change.currentNode.id());
|
|
1771
|
+
if (this.isChildOfAny(currentPath, replacedPaths)) {
|
|
1772
|
+
continue;
|
|
1773
|
+
}
|
|
1774
|
+
if (this.hasChildIn(currentPath, childChangePathObjects)) {
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
if (!this.isActuallyModified(change)) {
|
|
1778
|
+
continue;
|
|
1779
|
+
}
|
|
1780
|
+
if (change.currentNode.isArray()) {
|
|
1781
|
+
const arrayPatches = this.generateArrayReplacePatches(
|
|
1782
|
+
change.currentNode,
|
|
1783
|
+
change.baseNode,
|
|
1784
|
+
currentPath
|
|
1785
|
+
);
|
|
1786
|
+
patches.push(...arrayPatches);
|
|
1787
|
+
replacedPaths.push(currentPath);
|
|
1788
|
+
continue;
|
|
1789
|
+
}
|
|
1790
|
+
const schema = this.serializer.serializeNode(
|
|
1791
|
+
change.currentNode,
|
|
1792
|
+
this.currentTree
|
|
1793
|
+
);
|
|
1794
|
+
patches.push({
|
|
1795
|
+
op: "replace",
|
|
1796
|
+
path: currentPath.asJsonPointer(),
|
|
1797
|
+
value: schema
|
|
1798
|
+
});
|
|
1799
|
+
replacedPaths.push(currentPath);
|
|
1800
|
+
}
|
|
1801
|
+
return patches;
|
|
1802
|
+
}
|
|
1803
|
+
generateArrayReplacePatches(currentNode, baseNode, currentPath) {
|
|
1804
|
+
if (!baseNode.isArray()) {
|
|
1805
|
+
const schema = this.serializer.serializeNode(
|
|
1806
|
+
currentNode,
|
|
1807
|
+
this.currentTree
|
|
1808
|
+
);
|
|
1809
|
+
return [
|
|
1810
|
+
{
|
|
1811
|
+
op: "replace",
|
|
1812
|
+
path: currentPath.asJsonPointer(),
|
|
1813
|
+
value: schema
|
|
1814
|
+
}
|
|
1815
|
+
];
|
|
1816
|
+
}
|
|
1817
|
+
const patches = [];
|
|
1818
|
+
const metadataChanged = this.hasMetadataChanged(currentNode, baseNode);
|
|
1819
|
+
const itemsChanged = this.hasItemsChanged(currentNode, baseNode);
|
|
1820
|
+
if (metadataChanged) {
|
|
1821
|
+
const schema = this.serializer.serializeNode(
|
|
1822
|
+
currentNode,
|
|
1823
|
+
this.currentTree
|
|
1824
|
+
);
|
|
1825
|
+
patches.push({
|
|
1826
|
+
op: "replace",
|
|
1827
|
+
path: currentPath.asJsonPointer(),
|
|
1828
|
+
value: schema
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
if (itemsChanged) {
|
|
1832
|
+
const items = currentNode.items();
|
|
1833
|
+
const itemsPath = currentPath.childItems();
|
|
1834
|
+
const itemsSchema = this.serializer.serializeNode(
|
|
1835
|
+
items,
|
|
1836
|
+
this.currentTree
|
|
1837
|
+
);
|
|
1838
|
+
patches.push({
|
|
1839
|
+
op: "replace",
|
|
1840
|
+
path: itemsPath.asJsonPointer(),
|
|
1841
|
+
value: itemsSchema
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
return patches;
|
|
1845
|
+
}
|
|
1846
|
+
hasItemsChanged(currentNode, baseNode) {
|
|
1847
|
+
const items = currentNode.items();
|
|
1848
|
+
const baseItems = baseNode.items();
|
|
1849
|
+
const currentItemsSchema = this.serializer.serializeNode(
|
|
1850
|
+
items,
|
|
1851
|
+
this.currentTree
|
|
1852
|
+
);
|
|
1853
|
+
const baseItemsSchema = this.serializer.serializeNode(
|
|
1854
|
+
baseItems,
|
|
1855
|
+
this.baseTree
|
|
1856
|
+
);
|
|
1857
|
+
return JSON.stringify(currentItemsSchema) !== JSON.stringify(baseItemsSchema);
|
|
1858
|
+
}
|
|
1859
|
+
isChildOfAny(path, parents) {
|
|
1860
|
+
return parents.some((parent) => path.isChildOf(parent));
|
|
1861
|
+
}
|
|
1862
|
+
hasChildIn(path, candidates) {
|
|
1863
|
+
return candidates.some((candidate) => candidate.isChildOf(path));
|
|
1864
|
+
}
|
|
1865
|
+
isActuallyModified(change) {
|
|
1866
|
+
const currentSchema = this.serializer.serializeNode(
|
|
1867
|
+
change.currentNode,
|
|
1868
|
+
this.currentTree
|
|
1869
|
+
);
|
|
1870
|
+
const baseSchema = this.serializer.serializeNode(
|
|
1871
|
+
change.baseNode,
|
|
1872
|
+
this.baseTree
|
|
1873
|
+
);
|
|
1874
|
+
if (JSON.stringify(currentSchema) === JSON.stringify(baseSchema)) {
|
|
1875
|
+
return false;
|
|
1876
|
+
}
|
|
1877
|
+
if (change.currentNode.isObject() && this.hasOnlyChildChanges(change.currentNode, change.baseNode)) {
|
|
1878
|
+
return false;
|
|
1879
|
+
}
|
|
1880
|
+
if (change.currentNode.isArray() && this.hasOnlyItemsChanges(change.currentNode, change.baseNode)) {
|
|
1881
|
+
return false;
|
|
1882
|
+
}
|
|
1883
|
+
return true;
|
|
1884
|
+
}
|
|
1885
|
+
hasOnlyChildChanges(currentNode, baseNode) {
|
|
1886
|
+
if (!baseNode.isObject()) {
|
|
1887
|
+
return false;
|
|
1888
|
+
}
|
|
1889
|
+
if (this.hasMetadataChanged(currentNode, baseNode)) {
|
|
1890
|
+
return false;
|
|
1891
|
+
}
|
|
1892
|
+
return true;
|
|
1893
|
+
}
|
|
1894
|
+
hasMetadataChanged(currentNode, baseNode) {
|
|
1895
|
+
const currentMeta = currentNode.metadata();
|
|
1896
|
+
const baseMeta = baseNode.metadata();
|
|
1897
|
+
return currentMeta.title !== baseMeta.title || currentMeta.description !== baseMeta.description || currentMeta.deprecated !== baseMeta.deprecated;
|
|
1898
|
+
}
|
|
1899
|
+
hasOnlyItemsChanges(currentNode, baseNode) {
|
|
1900
|
+
if (!baseNode.isArray()) {
|
|
1901
|
+
return false;
|
|
1902
|
+
}
|
|
1903
|
+
if (this.hasMetadataChanged(currentNode, baseNode)) {
|
|
1904
|
+
return false;
|
|
1905
|
+
}
|
|
1906
|
+
const items = currentNode.items();
|
|
1907
|
+
const baseItems = baseNode.items();
|
|
1908
|
+
return items.id() === baseItems.id();
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
|
|
1912
|
+
// src/core/schema-patch/PatchEnricher.ts
|
|
1913
|
+
function isPrimitiveDefault(value) {
|
|
1914
|
+
const type = typeof value;
|
|
1915
|
+
return type === "string" || type === "number" || type === "boolean";
|
|
1916
|
+
}
|
|
1917
|
+
var PatchEnricher = class {
|
|
1918
|
+
constructor(currentTree, baseTree) {
|
|
1919
|
+
this.currentTree = currentTree;
|
|
1920
|
+
this.baseTree = baseTree;
|
|
1921
|
+
}
|
|
1922
|
+
enrich(patch) {
|
|
1923
|
+
const fieldName = this.getFieldNameFromPath(patch.path);
|
|
1924
|
+
if (patch.op === "add") {
|
|
1925
|
+
return this.enrichAddPatch(patch, fieldName);
|
|
1926
|
+
}
|
|
1927
|
+
if (patch.op === "remove") {
|
|
1928
|
+
return this.enrichRemovePatch(patch, fieldName);
|
|
1929
|
+
}
|
|
1930
|
+
if (patch.op === "move") {
|
|
1931
|
+
return this.enrichMovePatch(patch, fieldName);
|
|
1932
|
+
}
|
|
1933
|
+
return this.enrichReplacePatch(patch, fieldName);
|
|
1934
|
+
}
|
|
1935
|
+
enrichAddPatch(patch, fieldName) {
|
|
1936
|
+
const currentNode = this.getNodeAtPath(this.currentTree, patch.path);
|
|
1937
|
+
if (!currentNode) {
|
|
1938
|
+
return { patch, fieldName };
|
|
1939
|
+
}
|
|
1940
|
+
return {
|
|
1941
|
+
patch,
|
|
1942
|
+
fieldName,
|
|
1943
|
+
...this.computeAddMetadata(currentNode)
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
enrichRemovePatch(patch, fieldName) {
|
|
1947
|
+
return { patch, fieldName };
|
|
1948
|
+
}
|
|
1949
|
+
enrichMovePatch(patch, fieldName) {
|
|
1950
|
+
const fromPath = patch.from || "";
|
|
1951
|
+
const isRename = this.isRenameMove(fromPath, patch.path);
|
|
1952
|
+
const baseNode = this.getNodeAtPath(this.baseTree, fromPath);
|
|
1953
|
+
const currentNode = this.getNodeAtPath(this.currentTree, patch.path);
|
|
1954
|
+
const formulaChange = this.computeFormulaChange(baseNode, currentNode);
|
|
1955
|
+
return {
|
|
1956
|
+
patch,
|
|
1957
|
+
fieldName,
|
|
1958
|
+
isRename: isRename || void 0,
|
|
1959
|
+
formulaChange
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
enrichReplacePatch(patch, fieldName) {
|
|
1963
|
+
const baseNode = this.getNodeAtPath(this.baseTree, patch.path);
|
|
1964
|
+
const currentNode = this.getNodeAtPath(this.currentTree, patch.path);
|
|
1965
|
+
const isArrayMetadataPatch = baseNode?.isArray() && currentNode?.isArray();
|
|
1966
|
+
return {
|
|
1967
|
+
patch,
|
|
1968
|
+
fieldName,
|
|
1969
|
+
typeChange: this.computeTypeChange(baseNode, currentNode, isArrayMetadataPatch),
|
|
1970
|
+
formulaChange: this.computeFormulaChange(baseNode, currentNode),
|
|
1971
|
+
defaultChange: isArrayMetadataPatch ? void 0 : this.computeDefaultChange(baseNode, currentNode),
|
|
1972
|
+
descriptionChange: this.computeDescriptionChange(baseNode, currentNode),
|
|
1973
|
+
deprecatedChange: this.computeDeprecatedChange(baseNode, currentNode),
|
|
1974
|
+
foreignKeyChange: this.computeForeignKeyChange(baseNode, currentNode)
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
computeAddMetadata(node) {
|
|
1978
|
+
const result = {};
|
|
1979
|
+
const formula = node.formula();
|
|
1980
|
+
if (formula) {
|
|
1981
|
+
result.formulaChange = {
|
|
1982
|
+
fromFormula: void 0,
|
|
1983
|
+
toFormula: this.getFormulaExpression(formula, this.currentTree, node.id()),
|
|
1984
|
+
fromVersion: void 0,
|
|
1985
|
+
toVersion: formula.version()
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
const defaultValue = node.defaultValue();
|
|
1989
|
+
if (defaultValue !== void 0 && isPrimitiveDefault(defaultValue)) {
|
|
1990
|
+
result.defaultChange = {
|
|
1991
|
+
fromDefault: void 0,
|
|
1992
|
+
toDefault: defaultValue
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
const meta = node.metadata();
|
|
1996
|
+
if (meta.description) {
|
|
1997
|
+
result.descriptionChange = {
|
|
1998
|
+
fromDescription: void 0,
|
|
1999
|
+
toDescription: meta.description
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
if (meta.deprecated) {
|
|
2003
|
+
result.deprecatedChange = {
|
|
2004
|
+
fromDeprecated: void 0,
|
|
2005
|
+
toDeprecated: meta.deprecated
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
const foreignKey = node.foreignKey();
|
|
2009
|
+
if (foreignKey) {
|
|
2010
|
+
result.foreignKeyChange = {
|
|
2011
|
+
fromForeignKey: void 0,
|
|
2012
|
+
toForeignKey: foreignKey
|
|
2013
|
+
};
|
|
2014
|
+
}
|
|
2015
|
+
return result;
|
|
2016
|
+
}
|
|
2017
|
+
computeTypeChange(baseNode, currentNode, ignoreItems) {
|
|
2018
|
+
if (!baseNode || !currentNode) {
|
|
2019
|
+
return void 0;
|
|
2020
|
+
}
|
|
2021
|
+
const baseType = this.getNodeType(baseNode);
|
|
2022
|
+
const currentType = this.getNodeType(currentNode);
|
|
2023
|
+
if (ignoreItems) {
|
|
2024
|
+
const baseBaseType = baseNode.nodeType();
|
|
2025
|
+
const currentBaseType = currentNode.nodeType();
|
|
2026
|
+
if (baseBaseType === currentBaseType) {
|
|
2027
|
+
return void 0;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
if (baseType !== currentType) {
|
|
2031
|
+
return { fromType: baseType, toType: currentType };
|
|
2032
|
+
}
|
|
2033
|
+
return void 0;
|
|
2034
|
+
}
|
|
2035
|
+
computeFormulaChange(baseNode, currentNode) {
|
|
2036
|
+
const baseFormula = baseNode?.formula();
|
|
2037
|
+
const currentFormula = currentNode?.formula();
|
|
2038
|
+
const baseExpr = baseFormula && baseNode ? this.getFormulaExpression(baseFormula, this.baseTree, baseNode.id()) : void 0;
|
|
2039
|
+
const currentExpr = currentFormula && currentNode ? this.getFormulaExpression(currentFormula, this.currentTree, currentNode.id()) : void 0;
|
|
2040
|
+
const baseVersion = baseFormula?.version();
|
|
2041
|
+
const currentVersion = currentFormula?.version();
|
|
2042
|
+
if (baseExpr !== currentExpr || baseVersion !== currentVersion) {
|
|
2043
|
+
return {
|
|
2044
|
+
fromFormula: baseExpr,
|
|
2045
|
+
toFormula: currentExpr,
|
|
2046
|
+
fromVersion: baseVersion,
|
|
2047
|
+
toVersion: currentVersion
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
return void 0;
|
|
2051
|
+
}
|
|
2052
|
+
getFormulaExpression(formula, tree, nodeId) {
|
|
2053
|
+
return FormulaSerializer.serializeExpression(tree, nodeId, formula, { strict: false });
|
|
2054
|
+
}
|
|
2055
|
+
computeDefaultChange(baseNode, currentNode) {
|
|
2056
|
+
const baseDefault = baseNode?.defaultValue();
|
|
2057
|
+
const currentDefault = currentNode?.defaultValue();
|
|
2058
|
+
const safeBaseDefault = isPrimitiveDefault(baseDefault) ? baseDefault : void 0;
|
|
2059
|
+
const safeCurrentDefault = isPrimitiveDefault(
|
|
2060
|
+
currentDefault
|
|
2061
|
+
) ? currentDefault : void 0;
|
|
2062
|
+
if (safeBaseDefault !== safeCurrentDefault) {
|
|
2063
|
+
return {
|
|
2064
|
+
fromDefault: safeBaseDefault,
|
|
2065
|
+
toDefault: safeCurrentDefault
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
return void 0;
|
|
2069
|
+
}
|
|
2070
|
+
computeDescriptionChange(baseNode, currentNode) {
|
|
2071
|
+
const baseDesc = baseNode?.metadata().description;
|
|
2072
|
+
const currentDesc = currentNode?.metadata().description;
|
|
2073
|
+
if (baseDesc !== currentDesc) {
|
|
2074
|
+
return { fromDescription: baseDesc, toDescription: currentDesc };
|
|
2075
|
+
}
|
|
2076
|
+
return void 0;
|
|
2077
|
+
}
|
|
2078
|
+
computeDeprecatedChange(baseNode, currentNode) {
|
|
2079
|
+
const baseDeprecated = baseNode?.metadata().deprecated;
|
|
2080
|
+
const currentDeprecated = currentNode?.metadata().deprecated;
|
|
2081
|
+
if (baseDeprecated !== currentDeprecated) {
|
|
2082
|
+
return { fromDeprecated: baseDeprecated, toDeprecated: currentDeprecated };
|
|
2083
|
+
}
|
|
2084
|
+
return void 0;
|
|
2085
|
+
}
|
|
2086
|
+
computeForeignKeyChange(baseNode, currentNode) {
|
|
2087
|
+
const baseFk = baseNode?.foreignKey();
|
|
2088
|
+
const currentFk = currentNode?.foreignKey();
|
|
2089
|
+
if (baseFk !== currentFk) {
|
|
2090
|
+
return { fromForeignKey: baseFk, toForeignKey: currentFk };
|
|
2091
|
+
}
|
|
2092
|
+
return void 0;
|
|
2093
|
+
}
|
|
2094
|
+
getNodeType(node) {
|
|
2095
|
+
if (node.isArray()) {
|
|
2096
|
+
const items = node.items();
|
|
2097
|
+
return `array<${this.getNodeType(items)}>`;
|
|
2098
|
+
}
|
|
2099
|
+
return node.nodeType();
|
|
2100
|
+
}
|
|
2101
|
+
getFieldNameFromPath(jsonPointer) {
|
|
2102
|
+
try {
|
|
2103
|
+
return jsonPointerToPath(jsonPointer).asSimple();
|
|
2104
|
+
} catch {
|
|
2105
|
+
return "";
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
isRenameMove(fromPointer, toPointer) {
|
|
2109
|
+
try {
|
|
2110
|
+
const fromParent = jsonPointerToPath(fromPointer).parent();
|
|
2111
|
+
const toParent = jsonPointerToPath(toPointer).parent();
|
|
2112
|
+
return fromParent.equals(toParent);
|
|
2113
|
+
} catch {
|
|
2114
|
+
return false;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
getNodeAtPath(tree, jsonPointer) {
|
|
2118
|
+
try {
|
|
2119
|
+
const path = jsonPointerToPath(jsonPointer);
|
|
2120
|
+
const node = tree.nodeAt(path);
|
|
2121
|
+
return node.isNull() ? null : node;
|
|
2122
|
+
} catch {
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
|
|
2128
|
+
// src/core/schema-patch/PatchBuilder.ts
|
|
2129
|
+
var PatchBuilder = class {
|
|
2130
|
+
build(currentTree, baseTree) {
|
|
2131
|
+
const index = new NodePathIndex(baseTree);
|
|
2132
|
+
this.syncReplacements(currentTree, index);
|
|
2133
|
+
const rawChanges = collectChanges(baseTree, currentTree, index);
|
|
2134
|
+
const coalesced = coalesceChanges(rawChanges, currentTree, index);
|
|
2135
|
+
const generator = new PatchGenerator(currentTree, baseTree);
|
|
2136
|
+
const patches = generator.generate(coalesced);
|
|
2137
|
+
const enricher = new PatchEnricher(currentTree, baseTree);
|
|
2138
|
+
return patches.map((patch) => enricher.enrich(patch));
|
|
2139
|
+
}
|
|
2140
|
+
syncReplacements(tree, index) {
|
|
2141
|
+
for (const [oldId, newId] of tree.replacements()) {
|
|
2142
|
+
index.trackReplacement(oldId, newId);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
};
|
|
2146
|
+
|
|
2147
|
+
exports.AbstractBasePath = AbstractBasePath;
|
|
2148
|
+
exports.ChangeCoalescer = ChangeCoalescer;
|
|
2149
|
+
exports.ChangeCollector = ChangeCollector;
|
|
2150
|
+
exports.EMPTY_METADATA = EMPTY_METADATA;
|
|
2151
|
+
exports.EMPTY_PATH = EMPTY_PATH;
|
|
2152
|
+
exports.FormulaDependencyIndex = FormulaDependencyIndex;
|
|
2153
|
+
exports.ItemsSegment = ItemsSegment;
|
|
2154
|
+
exports.NULL_NODE = NULL_NODE;
|
|
2155
|
+
exports.NodePathIndex = NodePathIndex;
|
|
2156
|
+
exports.ParsedFormula = ParsedFormula;
|
|
2157
|
+
exports.PatchBuilder = PatchBuilder;
|
|
2158
|
+
exports.PatchEnricher = PatchEnricher;
|
|
2159
|
+
exports.PatchGenerator = PatchGenerator;
|
|
2160
|
+
exports.PropertySegment = PropertySegment;
|
|
2161
|
+
exports.SchemaDiff = SchemaDiff;
|
|
2162
|
+
exports.SchemaSerializer = SchemaSerializer;
|
|
2163
|
+
exports.areNodesContentEqual = areNodesContentEqual;
|
|
2164
|
+
exports.areNodesEqual = areNodesEqual;
|
|
2165
|
+
exports.coalesceChanges = coalesceChanges;
|
|
2166
|
+
exports.collectChanges = collectChanges;
|
|
2167
|
+
exports.createArrayNode = createArrayNode;
|
|
2168
|
+
exports.createBooleanNode = createBooleanNode;
|
|
2169
|
+
exports.createNumberNode = createNumberNode;
|
|
2170
|
+
exports.createObjectNode = createObjectNode;
|
|
2171
|
+
exports.createPath = createPath;
|
|
2172
|
+
exports.createRefNode = createRefNode;
|
|
2173
|
+
exports.createSchemaTree = createSchemaTree;
|
|
2174
|
+
exports.createStringNode = createStringNode;
|
|
2175
|
+
exports.jsonPointerToPath = jsonPointerToPath;
|
|
2176
|
+
exports.jsonPointerToSegments = jsonPointerToSegments;
|
|
2177
|
+
exports.jsonPointerToSimplePath = jsonPointerToSimplePath;
|
|
2178
|
+
//# sourceMappingURL=chunk-A4E524UU.cjs.map
|
|
2179
|
+
//# sourceMappingURL=chunk-A4E524UU.cjs.map
|