@firestartr/cli 2.11.0-snapshot-patch-claims → 2.11.0-snapshot-patch-claims-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +94 -50
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -166237,7 +166237,7 @@ function isRecord(value) {
|
|
|
166237
166237
|
// normalized pointer. Array appends (`add ... /-`) collide on the pointer plus
|
|
166238
166238
|
// the appended element's `name` when present, so several features can each add
|
|
166239
166239
|
// a distinct label to /providers/github/labels/- while the same label name from
|
|
166240
|
-
// two features
|
|
166240
|
+
// two features is silently deduplicated (or errors if values differ).
|
|
166241
166241
|
function writeIdentity(patch) {
|
|
166242
166242
|
const path = normalizePointer(patch.path);
|
|
166243
166243
|
if (patch.op === 'add' &&
|
|
@@ -166248,6 +166248,30 @@ function writeIdentity(patch) {
|
|
|
166248
166248
|
}
|
|
166249
166249
|
return path;
|
|
166250
166250
|
}
|
|
166251
|
+
// Check whether an array at `appendPath`'s parent already contains an element
|
|
166252
|
+
// whose `name` matches `value.name`. Used for the "claim wins" gate: when a
|
|
166253
|
+
// feature tries to append an array element that already exists in the claim,
|
|
166254
|
+
// the patch is silently dropped.
|
|
166255
|
+
function arrayElementExists(doc, appendPath, value) {
|
|
166256
|
+
if (!isRecord(value) || typeof value.name !== 'string')
|
|
166257
|
+
return false;
|
|
166258
|
+
const parentPath = appendPath.slice(0, -2); // strip trailing /-
|
|
166259
|
+
const segments = parentPath
|
|
166260
|
+
.split('/')
|
|
166261
|
+
.slice(1)
|
|
166262
|
+
.map((s) => s.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
166263
|
+
let cur = doc;
|
|
166264
|
+
for (const seg of segments) {
|
|
166265
|
+
if (cur === null || cur === undefined || typeof cur !== 'object')
|
|
166266
|
+
return false;
|
|
166267
|
+
if (!Object.prototype.hasOwnProperty.call(cur, seg))
|
|
166268
|
+
return false;
|
|
166269
|
+
cur = cur[seg];
|
|
166270
|
+
}
|
|
166271
|
+
if (!Array.isArray(cur))
|
|
166272
|
+
return false;
|
|
166273
|
+
return cur.some((el) => isRecord(el) && el.name === value.name);
|
|
166274
|
+
}
|
|
166251
166275
|
// fast-json-patch does not create intermediate containers for `add`, and
|
|
166252
166276
|
// appending to an array requires the array to already exist. Ensure every
|
|
166253
166277
|
// ancestor segment exists before applying an `add`: missing containers are
|
|
@@ -166277,9 +166301,7 @@ async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
|
|
|
166277
166301
|
if (envelopes.length === 0) {
|
|
166278
166302
|
return claimAfterDefaults;
|
|
166279
166303
|
}
|
|
166280
|
-
|
|
166281
|
-
const seenPaths = new Map();
|
|
166282
|
-
// Collect all patches for deduplication before any gate — normalize once so all gates and apply use same pointer
|
|
166304
|
+
// Normalize all patches once so every gate and the apply phase use the same pointers.
|
|
166283
166305
|
const normalizedEnvelopes = envelopes.map((env) => ({
|
|
166284
166306
|
feature: env.feature,
|
|
166285
166307
|
patches: env.patches.map((p) => ({
|
|
@@ -166288,8 +166310,50 @@ async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
|
|
|
166288
166310
|
_raw: p.path,
|
|
166289
166311
|
})),
|
|
166290
166312
|
}));
|
|
166291
|
-
|
|
166292
|
-
|
|
166313
|
+
// ── Phase 1: silently drop patches that should not be applied ──────────
|
|
166314
|
+
// • Array append whose element already exists in the claim → claim wins
|
|
166315
|
+
// • Duplicate identity with identical value across features → silent dedup
|
|
166316
|
+
const dropped = new Set(); // "envelopeIdx:patchIdx"
|
|
166317
|
+
const seenIdentities = new Map();
|
|
166318
|
+
for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
|
|
166319
|
+
const envelope = normalizedEnvelopes[ei];
|
|
166320
|
+
for (let pi = 0; pi < envelope.patches.length; pi++) {
|
|
166321
|
+
const patch = envelope.patches[pi];
|
|
166322
|
+
const key = `${ei}:${pi}`;
|
|
166323
|
+
// Array claim-wins: element already in claim → drop
|
|
166324
|
+
if (patch.op === 'add' && isAppendPointer(patch.path)) {
|
|
166325
|
+
if (arrayElementExists(claimAfterDefaults, patch.path, patch.value)) {
|
|
166326
|
+
dropped.add(key);
|
|
166327
|
+
continue;
|
|
166328
|
+
}
|
|
166329
|
+
}
|
|
166330
|
+
// Silent dedup: same identity + same value → drop
|
|
166331
|
+
const identity = writeIdentity(patch);
|
|
166332
|
+
const existing = seenIdentities.get(identity);
|
|
166333
|
+
if (existing) {
|
|
166334
|
+
if (JSON.stringify(existing.value) === JSON.stringify(patch.value)) {
|
|
166335
|
+
dropped.add(key);
|
|
166336
|
+
continue;
|
|
166337
|
+
}
|
|
166338
|
+
// Different value — kept here, caught as a violation in Phase 2.
|
|
166339
|
+
}
|
|
166340
|
+
else {
|
|
166341
|
+
seenIdentities.set(identity, {
|
|
166342
|
+
feature: envelope.feature,
|
|
166343
|
+
value: patch.value,
|
|
166344
|
+
});
|
|
166345
|
+
}
|
|
166346
|
+
}
|
|
166347
|
+
}
|
|
166348
|
+
// ── Phase 2: collect violations on non-dropped patches ─────────────────
|
|
166349
|
+
const violations = [];
|
|
166350
|
+
const seenForViolations = new Map(); // identity → feature
|
|
166351
|
+
for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
|
|
166352
|
+
const envelope = normalizedEnvelopes[ei];
|
|
166353
|
+
for (let pi = 0; pi < envelope.patches.length; pi++) {
|
|
166354
|
+
if (dropped.has(`${ei}:${pi}`))
|
|
166355
|
+
continue;
|
|
166356
|
+
const patch = envelope.patches[pi];
|
|
166293
166357
|
const path = patch.path;
|
|
166294
166358
|
const raw = patch._raw ?? path;
|
|
166295
166359
|
// Gate 1: protected path
|
|
@@ -166301,54 +166365,32 @@ async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
|
|
|
166301
166365
|
reason: 'protected-path',
|
|
166302
166366
|
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets protected claim path`,
|
|
166303
166367
|
});
|
|
166304
|
-
// continue to collect other violations for same patch (but avoid duplicate counting)
|
|
166305
166368
|
}
|
|
166306
|
-
// Gate
|
|
166307
|
-
// Array appends (`/-`) dedup by element name (see writeIdentity); all
|
|
166308
|
-
// other writes dedup by normalized pointer.
|
|
166369
|
+
// Gate 2: conflicting value from another feature
|
|
166309
166370
|
const identity = writeIdentity(patch);
|
|
166310
|
-
if (
|
|
166371
|
+
if (seenForViolations.has(identity)) {
|
|
166311
166372
|
violations.push({
|
|
166312
166373
|
feature: envelope.feature,
|
|
166313
166374
|
op: patch.op,
|
|
166314
166375
|
path,
|
|
166315
166376
|
reason: 'duplicate-path',
|
|
166316
|
-
conflictingFeature:
|
|
166317
|
-
message: `Feature '${envelope.feature}' and '${
|
|
166377
|
+
conflictingFeature: seenForViolations.get(identity),
|
|
166378
|
+
message: `Feature '${envelope.feature}' and '${seenForViolations.get(identity)}' both write to ${path} (deduplication)`,
|
|
166318
166379
|
});
|
|
166319
166380
|
}
|
|
166320
166381
|
else {
|
|
166321
|
-
|
|
166322
|
-
}
|
|
166323
|
-
// Gate
|
|
166324
|
-
if (['replace', 'remove'
|
|
166325
|
-
|
|
166326
|
-
|
|
166327
|
-
|
|
166328
|
-
|
|
166329
|
-
|
|
166330
|
-
|
|
166331
|
-
|
|
166332
|
-
|
|
166333
|
-
op: patch.op,
|
|
166334
|
-
path,
|
|
166335
|
-
reason: 'overwrite-protected',
|
|
166336
|
-
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) would overwrite user/default-declared value`,
|
|
166337
|
-
});
|
|
166338
|
-
}
|
|
166339
|
-
}
|
|
166340
|
-
else {
|
|
166341
|
-
// Path absent — check intermediate parent existence? For now exact path only.
|
|
166342
|
-
// If patch is `replace` to absent path, fast-json-patch will fail; we let that be an overwrite concern too.
|
|
166343
|
-
if (['replace', 'remove'].includes(patch.op)) {
|
|
166344
|
-
violations.push({
|
|
166345
|
-
feature: envelope.feature,
|
|
166346
|
-
op: patch.op,
|
|
166347
|
-
path,
|
|
166348
|
-
reason: 'overwrite-protected',
|
|
166349
|
-
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets absent path (replace/remove requires existing value)`,
|
|
166350
|
-
});
|
|
166351
|
-
}
|
|
166382
|
+
seenForViolations.set(identity, envelope.feature);
|
|
166383
|
+
}
|
|
166384
|
+
// Gate 3: replace / remove to an absent path
|
|
166385
|
+
if (['replace', 'remove'].includes(patch.op)) {
|
|
166386
|
+
if (!pointerExists(claimAfterDefaults, path)) {
|
|
166387
|
+
violations.push({
|
|
166388
|
+
feature: envelope.feature,
|
|
166389
|
+
op: patch.op,
|
|
166390
|
+
path,
|
|
166391
|
+
reason: 'overwrite-protected',
|
|
166392
|
+
message: `Feature '${envelope.feature}' patch ${patch.op} ${raw} (normalized ${path}) targets absent path (replace/remove requires existing value)`,
|
|
166393
|
+
});
|
|
166352
166394
|
}
|
|
166353
166395
|
}
|
|
166354
166396
|
}
|
|
@@ -166356,17 +166398,19 @@ async function stitchClaim(claimAfterDefaults, preCollectedEnvelopes) {
|
|
|
166356
166398
|
if (violations.length > 0) {
|
|
166357
166399
|
throw new StitchingError(violations);
|
|
166358
166400
|
}
|
|
166359
|
-
//
|
|
166401
|
+
// ── Phase 3: apply remaining patches ───────────────────────────────────
|
|
166360
166402
|
let stitched = JSON.parse(JSON.stringify(claimAfterDefaults));
|
|
166361
|
-
for (
|
|
166362
|
-
|
|
166403
|
+
for (let ei = 0; ei < normalizedEnvelopes.length; ei++) {
|
|
166404
|
+
const envelope = normalizedEnvelopes[ei];
|
|
166405
|
+
const patchesToApply = envelope.patches.filter((_, pi) => !dropped.has(`${ei}:${pi}`));
|
|
166406
|
+
if (patchesToApply.length === 0)
|
|
166363
166407
|
continue;
|
|
166364
|
-
for (const patch of
|
|
166408
|
+
for (const patch of patchesToApply) {
|
|
166365
166409
|
if (patch.op === 'add') {
|
|
166366
166410
|
stitched = ensureAddParents(stitched, patch);
|
|
166367
166411
|
}
|
|
166368
166412
|
}
|
|
166369
|
-
const result = fast_json_patch.applyPatch(stitched,
|
|
166413
|
+
const result = fast_json_patch.applyPatch(stitched, patchesToApply, false, false);
|
|
166370
166414
|
stitched = result.newDocument;
|
|
166371
166415
|
}
|
|
166372
166416
|
return stitched;
|
|
@@ -713815,7 +713859,7 @@ const crsStatusSubcommand = {
|
|
|
713815
713859
|
};
|
|
713816
713860
|
|
|
713817
713861
|
;// CONCATENATED MODULE: ./package.json
|
|
713818
|
-
const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-patch-claims"}');
|
|
713862
|
+
const package_namespaceObject = JSON.parse('{"i8":"2.11.0-snapshot-patch-claims-2"}');
|
|
713819
713863
|
;// CONCATENATED MODULE: ../../package.json
|
|
713820
713864
|
const package_namespaceObject_1 = {"i8":"2.10.0"};
|
|
713821
713865
|
// EXTERNAL MODULE: ../../node_modules/semver/index.js
|