@warp-drive-mirror/json-api 5.10.0-alpha.7 → 5.10.0-alpha.9

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.
@@ -912,7 +912,7 @@ function validateResourceDocument(reporter, doc) {
912
912
  }
913
913
 
914
914
  //#endregion
915
- //#region ../../node_modules/.pnpm/@embroider+macros@1.20.7/node_modules/@embroider/macros/src/addon/runtime.js
915
+ //#region ../../node_modules/.pnpm/@embroider+macros@1.21.1/node_modules/@embroider/macros/src/addon/runtime.js
916
916
  function config(packageRoot) {
917
917
  return runtimeConfig.packages[packageRoot];
918
918
  }
@@ -2216,20 +2216,89 @@ function getDefaultValue(schema, identifier, store) {
2216
2216
  if (transform?.defaultValue) return transform.defaultValue(options || null, identifier);
2217
2217
  }
2218
2218
  }
2219
- function calculateChangedKeys(cached, updates, fields) {
2220
- const changedKeys = /* @__PURE__ */ new Set();
2221
- const keys = Object.keys(updates);
2222
- const length = keys.length;
2223
- const localAttrs = cached.localAttrs;
2224
- const original = Object.assign(Object.create(null), cached.remoteAttrs, cached.inflightAttrs);
2225
- for (let i = 0; i < length; i++) {
2219
+ /**
2220
+ * Narrow `subset` to the members that survived {@link patchLocalAttributes}' pruning. Only called
2221
+ * when that pruning actually removed something, so the allocation is skipped on the common path
2222
+ * where a resource has no local edits at all.
2223
+ */
2224
+ function retainSurviving(subset, survivors) {
2225
+ if (!subset?.size) return subset;
2226
+ const result = /* @__PURE__ */ new Set();
2227
+ for (const key of subset) if (survivors.has(key)) result.add(key);
2228
+ return result.size ? result : void 0;
2229
+ }
2230
+ /**
2231
+ * Which projection each changed key moved, so the caller can notify on the matching channel:
2232
+ * `localOnly` and `remoteOnly` on theirs, `both` unscoped. `remoteChanged` is the union
2233
+ * {@link patchLocalAttributes} reconciles against.
2234
+ *
2235
+ * `undefined` rather than empty Sets: this runs on every `upsert`, and a resource where nothing
2236
+ * moved should cost no allocation.
2237
+ */
2238
+ const NO_PROJECTION_CHANGES = Object.freeze({
2239
+ localOnly: void 0,
2240
+ remoteOnly: void 0,
2241
+ both: void 0,
2242
+ remoteChanged: void 0
2243
+ });
2244
+ /**
2245
+ * The keys a merge could move: everything the payload carries, plus anything being promoted that
2246
+ * the payload did not mention. `null` when there is nothing to examine.
2247
+ *
2248
+ * `upsert` promotes nothing, so it gets the `Object.keys` array back unchanged. Only a commit
2249
+ * carrying both a payload and promoted attrs pays for a copy, and that is once per save rather
2250
+ * than once per resource in a document.
2251
+ */
2252
+ function candidateKeys(updates, promoted) {
2253
+ const updateKeys = updates ? Object.keys(updates) : null;
2254
+ const promotedKeys = promoted ? Object.keys(promoted) : null;
2255
+ if (!promotedKeys?.length) return updateKeys?.length ? updateKeys : null;
2256
+ if (!updateKeys?.length) return promotedKeys;
2257
+ const keys = updateKeys.slice();
2258
+ for (let i = 0; i < promotedKeys.length; i++) if (!(promotedKeys[i] in updates)) keys.push(promotedKeys[i]);
2259
+ return keys;
2260
+ }
2261
+ /**
2262
+ * Partition the keys an incoming payload touches by which projection each one moves.
2263
+ *
2264
+ * Takes the values rather than the `CachedResource` so it cannot observe the merge it is
2265
+ * describing: `prevRemote` is the remote state as it stands *before* `promoted` and `updates` are
2266
+ * applied, and the two callers merge different things. Reading them off `cached` would make the
2267
+ * result depend on whether the caller had already mutated it.
2268
+ */
2269
+ function calculateChangedKeys(prevRemote, localAttrs, updates, promoted, fields) {
2270
+ const keys = candidateKeys(updates, promoted);
2271
+ if (keys === null) return NO_PROJECTION_CHANGES;
2272
+ let localOnly;
2273
+ let remoteOnly;
2274
+ let both;
2275
+ let remoteChanged;
2276
+ for (let i = 0; i < keys.length; i++) {
2226
2277
  const key = keys[i];
2227
- if (!fields.has(key)) continue;
2228
- const value = updates[key];
2229
- if (localAttrs && localAttrs[key] !== void 0) continue;
2230
- if (original[key] !== value) changedKeys.add(key);
2231
- }
2232
- return changedKeys;
2278
+ const field = fields.get(key);
2279
+ if (!field || isRelationship(field)) continue;
2280
+ const isPromoted = promoted !== null && key in promoted;
2281
+ const isUpdated = updates !== void 0 && key in updates;
2282
+ const wasRemote = prevRemote ? prevRemote[key] : void 0;
2283
+ const nowRemote = isUpdated ? updates[key] : isPromoted ? promoted[key] : wasRemote;
2284
+ const localEdit = localAttrs ? localAttrs[key] : void 0;
2285
+ const isEdited = localEdit !== void 0;
2286
+ const wasLocal = isEdited ? localEdit : isPromoted ? promoted[key] : wasRemote;
2287
+ const nowLocal = isEdited ? localEdit : nowRemote;
2288
+ const remoteMoved = wasRemote !== nowRemote;
2289
+ const localMoved = wasLocal !== nowLocal;
2290
+ if (remoteMoved) {
2291
+ (remoteChanged ??= /* @__PURE__ */ new Set()).add(key);
2292
+ if (localMoved) (both ??= /* @__PURE__ */ new Set()).add(key);
2293
+ else (remoteOnly ??= /* @__PURE__ */ new Set()).add(key);
2294
+ } else if (localMoved) (localOnly ??= /* @__PURE__ */ new Set()).add(key);
2295
+ }
2296
+ return remoteChanged || localOnly ? {
2297
+ localOnly,
2298
+ remoteOnly,
2299
+ both,
2300
+ remoteChanged
2301
+ } : NO_PROJECTION_CHANGES;
2233
2302
  }
2234
2303
  function cacheIsEmpty(cached) {
2235
2304
  return !cached || cached.remoteAttrs === null && cached.inflightAttrs === null && cached.localAttrs === null;
@@ -2401,7 +2470,7 @@ function cacheUpsert(cache, identifier, data, calculateChanges) {
2401
2470
  cache._capabilities.notifyChange(identifier, "state", null);
2402
2471
  }
2403
2472
  const fields = getCacheFields(cache, identifier);
2404
- if (calculateChanges && existed && data.attributes) changedKeys = calculateChangedKeys(cached, data.attributes, fields);
2473
+ if (calculateChanges && existed && data.attributes) changedKeys = calculateChangedKeys(cached.remoteAttrs, cached.localAttrs, data.attributes, null, fields).remoteChanged;
2405
2474
  cached.remoteAttrs = Object.assign(cached.remoteAttrs || Object.create(null), data.attributes);
2406
2475
  if (cached.localAttrs) {
2407
2476
  if (patchLocalAttributes(cached, changedKeys)) cache._capabilities.notifyChange(identifier, "state", null);
@@ -2553,15 +2622,21 @@ function didCommit(cache, committedIdentifier, data, op) {
2553
2622
  if (data.relationships) setupRelationships(cache.__graph, fields, identifier, data);
2554
2623
  newCanonicalAttributes = data.attributes;
2555
2624
  }
2556
- const changedKeys = newCanonicalAttributes && calculateChangedKeys(cached, newCanonicalAttributes, fields);
2625
+ const changes = calculateChangedKeys(cached.remoteAttrs, cached.localAttrs, newCanonicalAttributes, cached.inflightAttrs, fields);
2557
2626
  cached.remoteAttrs = Object.assign(cached.remoteAttrs || Object.create(null), cached.inflightAttrs, newCanonicalAttributes);
2558
2627
  cached.inflightAttrs = null;
2559
- patchLocalAttributes(cached, changedKeys);
2628
+ const pruned = patchLocalAttributes(cached, changes.remoteChanged);
2560
2629
  if (cached.errors) {
2561
2630
  cached.errors = null;
2562
2631
  cache._capabilities.notifyChange(identifier, "errors", null);
2563
2632
  }
2564
- if (changedKeys?.size) cache._capabilities.notifyChange(identifier, "attributes", changedKeys);
2633
+ const { remoteChanged, localOnly } = changes;
2634
+ const reprune = pruned && remoteChanged !== void 0;
2635
+ const both = reprune ? retainSurviving(changes.both, remoteChanged) : changes.both;
2636
+ const remoteOnly = reprune ? retainSurviving(changes.remoteOnly, remoteChanged) : changes.remoteOnly;
2637
+ if (both?.size) cache._capabilities.notifyChange(identifier, "attributes", both);
2638
+ if (remoteOnly?.size) cache._capabilities.notifyChange(identifier, "attributes", remoteOnly, "remote");
2639
+ if (localOnly?.size) cache._capabilities.notifyChange(identifier, "attributes", localOnly, "local");
2565
2640
  cache._capabilities.notifyChange(identifier, "state", null);
2566
2641
  }
2567
2642
  function willCommit(cache, identifier) {