@yahoo/uds-create-config 5.59.2 → 5.59.4

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.
@@ -8,7 +8,7 @@ import { storedStyleRules } from "./Component.js";
8
8
  import { sourceUnreachable } from "../../framework/sources.js";
9
9
  import { covers, excludes } from "./link-declaration.js";
10
10
  import { planCopy } from "./copy-plan.js";
11
- import { planBreak, planExclude, planLink, planUnlink, sourceRowStates } from "./link-plan.js";
11
+ import { planBreak, planExclude, planLink, planLinkApplied, planUnlink, sourceRowStates } from "./link-plan.js";
12
12
  import { z } from "zod";
13
13
  //#region src/entities/system/LinkedSystem.ts
14
14
  /**
@@ -316,7 +316,7 @@ const LinkedSystemDefinition = defineEntity({
316
316
  title: (entity) => `Link something from ${entity}`,
317
317
  example: linkExample,
318
318
  handler: (input, config) => {
319
- const { linked, patches } = planLink({
319
+ const { plan: { linked, patches }, after } = planLinkApplied({
320
320
  config,
321
321
  input: linkPlanInputOf(input)
322
322
  });
@@ -325,7 +325,7 @@ const LinkedSystemDefinition = defineEntity({
325
325
  rejectData(`Linking through "${String(input.path)}" reaches what another linked system provides: ${named.join(", ")}. Say whether to take them (\`onLinked: 'take'\`) or keep them where they come from (\`onLinked: 'keep'\`).`, ["onLinked"]);
326
326
  }
327
327
  if (patches.length === 0) return config;
328
- return config.applyAll(patches).withDerivedRows();
328
+ return after ?? config.applyAll(patches).withDerivedRows();
329
329
  }
330
330
  },
331
331
  "link-plan": {
@@ -73,6 +73,28 @@ function declaredElsewhere({ config, slug, kind, path }) {
73
73
  * folder that holds one is declared by its other members.
74
74
  */
75
75
  function planLink({ config, input }) {
76
+ return planLinkApplied({
77
+ config,
78
+ input
79
+ }).plan;
80
+ }
81
+ const applied = (config, patches) => {
82
+ try {
83
+ return { config: config.applyAll(patches).withDerivedRows() };
84
+ } catch (error) {
85
+ return isConfigRejection(error) ? { refused: error } : { failed: error };
86
+ }
87
+ };
88
+ /**
89
+ * {@link planLink}, and the config its patches leave when they apply, which is what `link` itself
90
+ * returns.
91
+ *
92
+ * A take is applied once. What it leaves is where the entries it strands are read, the edits that
93
+ * remove them are applied on top, and the outcome is read off the result, so neither the plan nor the
94
+ * `link` that follows it applies the whole of a take again. On a config that takes a whole system
95
+ * over another, each of those passes cost about a second.
96
+ */
97
+ function planLinkApplied({ config, input }) {
76
98
  const { path: slug } = input;
77
99
  const source = config.sourceFor(slug);
78
100
  if (!source) rejectData(`Cannot link through "${slug}" — nothing has resolved that link.`);
@@ -243,30 +265,36 @@ function planLink({ config, input }) {
243
265
  ...declares,
244
266
  ...shadows
245
267
  ];
246
- const { dropped, patches: drops } = takes.length > 0 ? directivesTakenFrom({
268
+ let result = planned.length > 0 ? applied(config, planned) : void 0;
269
+ if (takes.length > 0 && result && "failed" in result) throw result.failed;
270
+ const { dropped, patches: drops } = takes.length > 0 && result && "config" in result ? directivesTakenFrom({
247
271
  config,
248
272
  slug,
249
- patches: planned
273
+ after: result.config
250
274
  }) : {
251
275
  dropped: [],
252
276
  patches: []
253
277
  };
278
+ if (drops.length > 0 && result && "config" in result) result = applied(result.config, drops);
254
279
  const patches = [...planned, ...drops];
255
280
  return {
256
- declared,
257
- ...outcome({
258
- config,
259
- slug,
260
- patches,
261
- named: input.data
262
- }),
263
- replaces: addresses.length,
264
- addresses,
265
- linked,
266
- extended,
267
- dropped,
268
- shared,
269
- patches
281
+ plan: {
282
+ declared,
283
+ ...outcome({
284
+ config,
285
+ slug,
286
+ result,
287
+ named: input.data
288
+ }),
289
+ replaces: addresses.length,
290
+ addresses,
291
+ linked,
292
+ extended,
293
+ dropped,
294
+ shared,
295
+ patches
296
+ },
297
+ after: result && "config" in result ? result.config : void 0
270
298
  };
271
299
  }
272
300
  /**
@@ -280,19 +308,9 @@ function planLink({ config, input }) {
280
308
  * itself left behind: an entry that already applied to nothing is the build's to report, not this
281
309
  * take's to remove.
282
310
  *
283
- * Nothing when the take is refused; `outcome` says why.
311
+ * `after` is the config the take leaves. A take the config refuses has none, and `outcome` says why.
284
312
  */
285
- function directivesTakenFrom({ config, slug, patches }) {
286
- let after;
287
- try {
288
- after = config.applyAll(patches).withDerivedRows();
289
- } catch (error) {
290
- if (!isConfigRejection(error)) throw error;
291
- return {
292
- dropped: [],
293
- patches: []
294
- };
295
- }
313
+ function directivesTakenFrom({ config, slug, after }) {
296
314
  const key = (at) => `${at.slug}\u0000${at.accessor}\u0000${at.path}`;
297
315
  const already = new Set(danglingDirectives(config).map(key));
298
316
  const dropped = [];
@@ -342,32 +360,27 @@ function refusal(error) {
342
360
  }
343
361
  const addressed = (rows) => new Set(rows.map(({ kind, path }) => `${kind}:${path}`));
344
362
  /**
345
- * What a link leaves, read by running its patches on a scratch config and deriving: the rows held
346
- * through the pin afterwards that were not before, and the paths settled afterwards that were not
347
- * before. When the config would refuse the patches, a collision they would leave among them,
348
- * nothing arrives and `blocked` says why.
363
+ * What a link leaves, read off the scratch config its patches leave (`result`, absent when there are
364
+ * none): the rows held through the pin afterwards that were not before, and the paths settled
365
+ * afterwards that were not before. When the config would refuse the patches, a collision they would
366
+ * leave among them, nothing arrives and `blocked` says why.
349
367
  */
350
- function outcome({ config, slug, patches, named }) {
368
+ function outcome({ config, slug, result, named }) {
351
369
  const nothing = {
352
370
  arriving: [],
353
371
  settled: []
354
372
  };
355
- if (patches.length === 0) return nothing;
373
+ if (!result || "failed" in result) return nothing;
374
+ if ("refused" in result) return {
375
+ ...nothing,
376
+ ...refusal(result.refused)
377
+ };
356
378
  const through = (at) => {
357
379
  const held = /* @__PURE__ */ new Set();
358
380
  for (const kind of at.borrowableKinds(slug)) for (const item of at.list(kind)) if (item.borrowedFrom === slug) held.add(`${kind}:${item.path}`);
359
381
  return held;
360
382
  };
361
- let after;
362
- try {
363
- after = config.applyAll(patches).withDerivedRows();
364
- } catch (error) {
365
- if (!isConfigRejection(error)) return nothing;
366
- return {
367
- ...nothing,
368
- ...refusal(error)
369
- };
370
- }
383
+ const after = result.config;
371
384
  const before = through(config);
372
385
  const arriving = [];
373
386
  for (const key of through(after)) {
@@ -1074,4 +1087,4 @@ function sourceRowStates({ config, slug }) {
1074
1087
  return rows;
1075
1088
  }
1076
1089
  //#endregion
1077
- export { planBreak, planExclude, planLink, planUnlink, sourceRowStates };
1090
+ export { planBreak, planExclude, planLink, planLinkApplied, planUnlink, sourceRowStates };