@yahoo/uds-create-config 5.51.0 → 5.52.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.
@@ -28,6 +28,7 @@ import { linkedDirMigration } from "../migrations/20261020182408_linked_dir.js";
28
28
  import { lintSettingsMigration } from "../migrations/20261020183330_lint_settings.js";
29
29
  import { directLayerCompositesMigration } from "../migrations/20261022124223_direct_layer_composites.js";
30
30
  import { cssContentScriptsMigration } from "../migrations/20261022152120_css_content_scripts.js";
31
+ import { linkTypeMigration } from "../migrations/20261022184639_link_type.js";
31
32
  import { CanvasRole } from "../entities/system/CanvasRole.js";
32
33
  import { GlobalStyle } from "../entities/system/GlobalStyle.js";
33
34
  import { Guidance } from "../entities/system/Guidance.js";
@@ -189,5 +190,6 @@ if (!registeredSchemaMigrations().has(20261020183330)) {
189
190
  registerSchemaMigrations(directLayerCompositesMigration);
190
191
  }
191
192
  if (!registeredSchemaMigrations().has(20261022152120)) registerSchemaMigrations(cssContentScriptsMigration);
193
+ if (!registeredSchemaMigrations().has(20261022184639)) registerSchemaMigrations(linkTypeMigration);
192
194
  //#endregion
193
195
  export { System };
@@ -20,6 +20,7 @@ const NATIVE_ACTIVATIONS = [
20
20
  const NativeModifier = defineEntity({
21
21
  kind: "modifier",
22
22
  entityName: "NativeModifier",
23
+ answeredHere: true,
23
24
  fields: z.object({
24
25
  type: z.enum(NATIVE_ACTIVATIONS),
25
26
  value: z.union([z.string(), z.number()])
@@ -109,6 +109,10 @@ declare const LinkedSystemDefinition: EntityClass<z.ZodObject<{
109
109
  systemId: z.ZodOptional<z.ZodString>;
110
110
  modules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
111
111
  name: z.ZodOptional<z.ZodString>;
112
+ type: z.ZodOptional<z.ZodEnum<{
113
+ linked: "linked";
114
+ hybrid: "hybrid";
115
+ }>>;
112
116
  version: z.ZodOptional<z.ZodString>;
113
117
  }, z.core.$strict>, z.ZodObject<Record<never, never>, z.core.$strip>, "linked-system", {
114
118
  readonly link: {
@@ -332,7 +332,7 @@ const LinkedSystemDefinition = defineEntity({
332
332
  input: linkInput,
333
333
  readOnly: true,
334
334
  label: "Plan a link",
335
- description: "What `link` with the same input replaces — rows of yours deleted so the source shows through, every path another linked system provides (`linked`, turned into extensions when `onLinked` says take), and members left alone because they are already here from the same origin. Writes nothing.",
335
+ description: "What `link` with the same input replaces — rows of yours deleted so the source shows through, every path another linked system provides (`linked`, turned into extensions when `onLinked` says take), members left alone because they are already here from the same origin, paths another linked system declares that the link reaches as a different entity (`settled`), whose row stays, and why the config would refuse the link (`blocked`), a collision it would leave among them. Writes nothing.",
336
336
  scope: "item",
337
337
  title: (entity) => `Plan a link from ${entity}`,
338
338
  example: linkExample,
@@ -374,7 +374,7 @@ const LinkedSystemDefinition = defineEntity({
374
374
  input: unlinkInput,
375
375
  readOnly: true,
376
376
  label: "Plan an unlink",
377
- description: "What `unlink` with the same input removes — the minted rows the narrower declaration no longer reaches, with the linked rows taken along because they point at them named in `cascade` — and why the config would refuse it. Writes nothing.",
377
+ description: "What `unlink` with the same input removes — the minted rows the narrower declaration no longer reaches, with the linked rows taken along because they point at them named in `cascade` — and why the config would refuse it, a collision it would leave among them. Writes nothing.",
378
378
  scope: "item",
379
379
  title: (entity) => `Plan unlinking from ${entity}`,
380
380
  example: pinExample,
@@ -739,6 +739,22 @@ const LinkedSystemDefinition = defineEntity({
739
739
  /** Display only, never identity: what to call this source in the UI. Defaults to the slug. */
740
740
  name: z.string().optional().describe("Display only. Defaults to the slug."),
741
741
  /**
742
+ * How this source joins the system. `linked`, the default, brings in everything a linked entity
743
+ * references as a row from this link, and refuses a path another link offers as a different
744
+ * entity. `hybrid` brings in only what no other link offers: where another link offers a path, that
745
+ * link's row stands and what this one brings uses it, while a component it renders stays this
746
+ * source's own.
747
+ *
748
+ * A product moving from one system to another adds the new one as `hybrid`: taking Yahoo OS's
749
+ * `Popover` over the v3 Bridge keeps the product's tokens from the Bridge, and the Popover renders
750
+ * Yahoo OS's own Button. Once the old link is gone, the new one can become `linked`.
751
+ *
752
+ * OPEN: motion presets and composites don't follow it yet. A taken component plays this system's
753
+ * motion preset of the name it uses, and a composite is the source's in a style rule and this
754
+ * system's as a prop.
755
+ */
756
+ type: z.enum(["linked", "hybrid"]).optional().describe("How this source joins the system: `linked` (the default) brings in everything its entities reference and refuses a path another link offers differently; `hybrid` brings in only what no other link offers and uses this system's tokens wherever it has one of the same name."),
757
+ /**
742
758
  * The exact published version every ref through this link resolves against.
743
759
  *
744
760
  * For a `configPath` link this is **observed rather than pinned**: push records what the sibling was
@@ -808,6 +824,7 @@ displayName: ({ member, path }) => typeof member.name === "string" && member.nam
808
824
  accessor: accessor ?? kind,
809
825
  path
810
826
  }),
827
+ sourceType: (body) => body.type === "hybrid" ? "hybrid" : "linked",
811
828
  bulkExcludes: ({ body, kind, accessor, path }) => excludes({
812
829
  declared: body.link,
813
830
  accessor: accessor ?? kind,
@@ -55,6 +55,7 @@ const Modifier = defineEntity({
55
55
  }),
56
56
  groupFields: modifierGroupFields,
57
57
  uniqueLeaves: true,
58
+ answeredHere: true,
58
59
  invariants: (config) => modifierInvariants(config)
59
60
  });
60
61
  /** A path's last segment. */
@@ -1,6 +1,6 @@
1
1
  import { EntityAddress } from "../../framework/plan.js";
2
2
  import { LinkDeclaration } from "./LinkedSystem.js";
3
- import { Config, Patch, TreeNode } from "../../framework/Config.js";
3
+ import { Config, Patch, SettledSource, SourceCollision, TreeNode } from "../../framework/Config.js";
4
4
 
5
5
  //#region src/entities/system/link-plan.d.ts
6
6
  /** What one op names, keyed by accessor the way the pin's `link` is: every entry of the kind, or the
@@ -42,6 +42,14 @@ interface LinkPlan {
42
42
  readonly extended: readonly EntityAddress[];
43
43
  /** Members already here from the source's own origin, left alone and kept out of the declaration. */
44
44
  readonly shared: readonly EntityAddress[];
45
+ /** Paths another pin offers that a `hybrid` link reaches as a different entity. The other pin's
46
+ * row stays at the path, and what the link brings is drawn with it. */
47
+ readonly settled: readonly SettledSource[];
48
+ /** Why the config would refuse the link. `undefined` when it would go through. */
49
+ readonly blocked?: string;
50
+ /** The paths the link would leave two linked systems offering as different entities, when that is
51
+ * why it's refused. */
52
+ readonly collisions?: readonly SourceCollision[];
45
53
  readonly patches: readonly Patch[];
46
54
  }
47
55
  interface UnlinkPlanInput {
@@ -58,6 +66,9 @@ interface UnlinkPlan {
58
66
  readonly cascade: readonly EntityAddress[];
59
67
  /** Why the config would refuse. `undefined` when it would go through. */
60
68
  readonly blocked?: string;
69
+ /** The paths the unlink would leave two linked systems offering as different entities, when that
70
+ * is why it's refused. */
71
+ readonly collisions?: readonly SourceCollision[];
61
72
  readonly patches: readonly Patch[];
62
73
  }
63
74
  interface BreakPlanInput {
@@ -109,15 +120,16 @@ interface SourceRowState {
109
120
  readonly sharedOrigin?: string;
110
121
  }
111
122
  /**
112
- * Link paths of a source: the declaration that mints them, then the edits that let them show through
123
+ * Link paths of a source: the declaration that mints them, and the edits that let them show through
113
124
  * where this config already holds something.
114
125
  *
115
- * The declaration goes first. A row of this config's own that other rows point at can only be deleted
116
- * once the declaration covers the path, since the config refuses a delete that leaves a referrer
117
- * dangling. A row held through another pin is not deleted — that pin's declaration would mint it
118
- * again, and declaring one path on two pins is a collision nothing derives. With `onLinked: 'take'` it
119
- * becomes an extension through this pin: a row of this config's own that shadows the other pin's and
120
- * follows this source. With `'keep'` it stays with the other pin and out of the declaration. A member
126
+ * A row held through another pin is not deleted — that pin's declaration would mint it again, and
127
+ * declaring one path on two pins is a collision nothing derives. With `onLinked: 'take'` it becomes an
128
+ * extension through this pin: a row of this config's own that shadows the other pin's and follows
129
+ * this source. The extensions are written before the declaration, so it never finds the path declared
130
+ * twice. With `'keep'` it stays with the other pin and out of the declaration. A row of this config's
131
+ * own that other rows point at is deleted after the declaration, since the config refuses a delete
132
+ * that leaves a referrer dangling until the declaration covers the path. A member
121
133
  * already here from the source's own origin is left alone and kept out of the declaration, so a
122
134
  * folder that holds one is declared by its other members.
123
135
  */
@@ -1,4 +1,4 @@
1
- import { rejectData } from "../../framework/rejection.js";
1
+ import { isConfigRejection, rejectData } from "../../framework/rejection.js";
2
2
  import { collectRefs, isMintedRow, ref, sourceOf, splitRef } from "../../framework/utils/refs.js";
3
3
  import { blockedBy } from "../../framework/plan.js";
4
4
  import { excludedCondition } from "../../framework/source-integrity.js";
@@ -58,15 +58,16 @@ function declaredElsewhere({ config, slug, kind, path }) {
58
58
  }
59
59
  }
60
60
  /**
61
- * Link paths of a source: the declaration that mints them, then the edits that let them show through
61
+ * Link paths of a source: the declaration that mints them, and the edits that let them show through
62
62
  * where this config already holds something.
63
63
  *
64
- * The declaration goes first. A row of this config's own that other rows point at can only be deleted
65
- * once the declaration covers the path, since the config refuses a delete that leaves a referrer
66
- * dangling. A row held through another pin is not deleted — that pin's declaration would mint it
67
- * again, and declaring one path on two pins is a collision nothing derives. With `onLinked: 'take'` it
68
- * becomes an extension through this pin: a row of this config's own that shadows the other pin's and
69
- * follows this source. With `'keep'` it stays with the other pin and out of the declaration. A member
64
+ * A row held through another pin is not deleted — that pin's declaration would mint it again, and
65
+ * declaring one path on two pins is a collision nothing derives. With `onLinked: 'take'` it becomes an
66
+ * extension through this pin: a row of this config's own that shadows the other pin's and follows
67
+ * this source. The extensions are written before the declaration, so it never finds the path declared
68
+ * twice. With `'keep'` it stays with the other pin and out of the declaration. A row of this config's
69
+ * own that other rows point at is deleted after the declaration, since the config refuses a delete
70
+ * that leaves a referrer dangling until the declaration covers the path. A member
70
71
  * already here from the source's own origin is left alone and kept out of the declaration, so a
71
72
  * folder that holds one is declared by its other members.
72
73
  */
@@ -85,6 +86,9 @@ function planLink({ config, input }) {
85
86
  const linked = [];
86
87
  const extended = [];
87
88
  const shared = [];
89
+ /** Rows held through another pin, written as extensions through this one. */
90
+ const takes = [];
91
+ /** Rows of this config's own that make way for the source's. */
88
92
  const shadows = [];
89
93
  /** Per accessor, what the declaration gains: the kind whole, or paths. */
90
94
  const gains = /* @__PURE__ */ new Map();
@@ -144,7 +148,7 @@ function planLink({ config, input }) {
144
148
  kind,
145
149
  path
146
150
  });
147
- shadows.push({
151
+ takes.push({
148
152
  kind,
149
153
  operation: minted ? "create" : "replace",
150
154
  path,
@@ -233,10 +237,14 @@ function planLink({ config, input }) {
233
237
  }
234
238
  declared = Object.keys(next).length === 0 ? current : next;
235
239
  }
236
- const patches = [...declares, ...shadows];
240
+ const patches = [
241
+ ...takes,
242
+ ...declares,
243
+ ...shadows
244
+ ];
237
245
  return {
238
246
  declared,
239
- arriving: arrivals({
247
+ ...outcome({
240
248
  config,
241
249
  slug,
242
250
  patches,
@@ -250,12 +258,27 @@ function planLink({ config, input }) {
250
258
  patches
251
259
  };
252
260
  }
261
+ /** What a plan reports of a refusal: its message, and the collisions when that's what it names. */
262
+ function refusal(error) {
263
+ const collisions = error.issues.flatMap((issue) => issue.collisions ?? []);
264
+ return {
265
+ blocked: error.message,
266
+ ...collisions.length > 0 ? { collisions } : {}
267
+ };
268
+ }
269
+ const addressed = (rows) => new Set(rows.map(({ kind, path }) => `${kind}:${path}`));
253
270
  /**
254
- * The rows a link mints, read by running its patches on a scratch config and deriving: what is held
255
- * through the pin afterwards and was not before. Nothing when the op would refuse; the op says why.
271
+ * What a link leaves, read by running its patches on a scratch config and deriving: the rows held
272
+ * through the pin afterwards that were not before, and the paths settled afterwards that were not
273
+ * before. When the config would refuse the patches, a collision they would leave among them,
274
+ * nothing arrives and `blocked` says why.
256
275
  */
257
- function arrivals({ config, slug, patches, named }) {
258
- if (patches.length === 0) return [];
276
+ function outcome({ config, slug, patches, named }) {
277
+ const nothing = {
278
+ arriving: [],
279
+ settled: []
280
+ };
281
+ if (patches.length === 0) return nothing;
259
282
  const through = (at) => {
260
283
  const held = /* @__PURE__ */ new Set();
261
284
  for (const kind of at.borrowableKinds(slug)) for (const item of at.list(kind)) if (item.borrowedFrom === slug) held.add(`${kind}:${item.path}`);
@@ -264,8 +287,12 @@ function arrivals({ config, slug, patches, named }) {
264
287
  let after;
265
288
  try {
266
289
  after = config.applyAll(patches).withDerivedRows();
267
- } catch {
268
- return [];
290
+ } catch (error) {
291
+ if (!isConfigRejection(error)) return nothing;
292
+ return {
293
+ ...nothing,
294
+ ...refusal(error)
295
+ };
269
296
  }
270
297
  const before = through(config);
271
298
  const arriving = [];
@@ -283,7 +310,11 @@ function arrivals({ config, slug, patches, named }) {
283
310
  })
284
311
  });
285
312
  }
286
- return arriving;
313
+ const settledBefore = addressed(config.settledSources());
314
+ return {
315
+ arriving,
316
+ settled: after.settledSources().filter(({ kind, path }) => !settledBefore.has(`${kind}:${path}`))
317
+ };
287
318
  }
288
319
  /**
289
320
  * Stop drawing paths of a source. The declaration narrows, or clears, and the rows it minted retire
@@ -345,10 +376,17 @@ function planUnlink({ config, input }) {
345
376
  data: { link: declared === void 0 ? null : declared }
346
377
  });
347
378
  }
348
- let blocked = blockedBy(() => config.applyAll(patches));
379
+ let after;
380
+ let refused = {};
381
+ try {
382
+ after = config.applyAll(patches);
383
+ } catch (error) {
384
+ if (!isConfigRejection(error)) throw error;
385
+ refused = refusal(error);
386
+ }
387
+ let { blocked } = refused;
349
388
  const removed = [];
350
- if (blocked === void 0) {
351
- const after = config.applyAll(patches);
389
+ if (after) {
352
390
  for (const kind of config.borrowableKinds(slug)) for (const item of config.list(kind)) {
353
391
  if (item.borrowedFrom !== slug) continue;
354
392
  if (after.resolve(kind, item.path)?.borrowedFrom === slug) continue;
@@ -364,6 +402,7 @@ function planUnlink({ config, input }) {
364
402
  removed,
365
403
  cascade,
366
404
  ...blocked === void 0 ? {} : { blocked },
405
+ ...refused.collisions ? { collisions: refused.collisions } : {},
367
406
  patches
368
407
  };
369
408
  }
@@ -9,7 +9,7 @@ import { RefGraph, TraverseOptions } from "./ref-graph.js";
9
9
  import { FieldsSchema } from "./utils/field-schema.js";
10
10
  import { SubEntityClass } from "./defineSubEntity.js";
11
11
  import { LocalOverlay, SourceAnswer, SourceOverlay, SourceResolver, SourceState } from "./sources.js";
12
- import { EntityKind, LayerKey } from "./registry.js";
12
+ import { EntityKind, LayerKey, SourceType } from "./registry.js";
13
13
  import { AuthoredEntry } from "./utils/group.js";
14
14
  import { EntityClass } from "./defineEntity.js";
15
15
  import { BreakPlan, LinkPlan, SourceRowState, UnlinkPlan } from "../entities/system/link-plan.js";
@@ -73,7 +73,7 @@ interface RecordedSource {
73
73
  * The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
74
74
  * that replaced it (see `detectedWireVersion`).
75
75
  */
76
- declare const SERIALIZED_CONFIG_VERSION = 20261022152120;
76
+ declare const SERIALIZED_CONFIG_VERSION = 20261022184639;
77
77
  interface SerializedConfig {
78
78
  /** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
79
79
  readonly version: number;
@@ -567,6 +567,26 @@ interface ConfigState {
567
567
  type ListOptions = {
568
568
  readonly retired?: boolean;
569
569
  };
570
+ /** A path offered as different entities with nothing able to keep it: two or more pins, or a
571
+ * `linked` pin and a row of this config's own ({@link Config.collidingSources}). */
572
+ interface SourceCollision {
573
+ readonly kind: string;
574
+ readonly path: string;
575
+ /** The slugs of the pins offering it. */
576
+ readonly slugs: readonly string[];
577
+ /** This config's own row at the path is one of the entities. */
578
+ readonly local?: true;
579
+ }
580
+ /** A path a `hybrid` pin reaches as a different entity from the one another pin offers there: the
581
+ * other pin's row stands at the path ({@link Config.settledSources}). */
582
+ interface SettledSource {
583
+ readonly kind: string;
584
+ readonly path: string;
585
+ /** The slug of the pin whose row stands at the path. */
586
+ readonly kept: string;
587
+ /** The slugs of the pins that reach a different entity there. */
588
+ readonly over: readonly string[];
589
+ }
570
590
  declare class Config {
571
591
  #private;
572
592
  /** All of this config's state. `protected`, not a `#private` field, so a derived config can be
@@ -1093,8 +1113,8 @@ declare class Config {
1093
1113
  /**
1094
1114
  * Whether patches on kinds that name no source can change the rows a derive mints between `before`
1095
1115
  * and `after`: they wrote a pin (an edit to a minted row lands in its pin's `options`), or a row
1096
- * they touched points at a source, changes which source-qualified refs it holds, or appears or
1097
- * vanishes at a path a source offers. An authored style bag's keys are this config's own
1116
+ * they touched points at a source, changes which source-qualified refs it holds, appears or vanishes
1117
+ * at a path a source offers, or is a row of this config's own that a linked pin reaches. An authored style bag's keys are this config's own
1098
1118
  * properties, so they don't count.
1099
1119
  *
1100
1120
  * Asked of the patches' own paths rather than of every row, so a batch pays per patch.
@@ -2216,11 +2236,21 @@ declare class Config {
2216
2236
  * and its sources are fixed.
2217
2237
  */
2218
2238
  private computeSourceClosure;
2239
+ /**
2240
+ * A refusal for a pin patch that would leave paths two sources offer as different entities, which
2241
+ * derive neither and fail the build. Named here, when the patch is made, with the two ways out.
2242
+ */
2243
+ private assertNoNewCollisions;
2244
+ /** {@link assertNoNewCollisions} against the collisions a derivation already found. */
2245
+ private assertNoNewCollisionsIn;
2219
2246
  /**
2220
2247
  * A refusal for a patch whose derive pass would retire a minted row that something authored here
2221
2248
  * still points at. A minted row has no body of its own, so once it goes the referrer dangles;
2222
2249
  * copying what is used, or breaking the link with `keep`, is how the value stays.
2223
2250
  *
2251
+ * A row retired because two sources now offer its path as different entities is refused as that
2252
+ * collision instead, since resolving the collision is what keeps the row.
2253
+ *
2224
2254
  * `action` names what is refused, after "Cannot": a pin patch removes the link, and any other patch
2225
2255
  * that reaches derivation — a deleted extension whose source reached the row — says what it did.
2226
2256
  */
@@ -2273,6 +2303,8 @@ declare class Config {
2273
2303
  * A session derives every value it advances to, so without the mark the same edit would pay for two
2274
2304
  * derive passes: this one and the session's. The mark covers this instance only, and any later
2275
2305
  * write is a new config, so each edit still gets exactly one pass, as it did from the session alone.
2306
+ *
2307
+ * `before` is the config the edit was made on, when the edit is refused for a collision it adds.
2276
2308
  */
2277
2309
  private derivedForEdit;
2278
2310
  /**
@@ -2296,11 +2328,13 @@ declare class Config {
2296
2328
  * So neither derives, and this names them. The way out is an authored row at that path extending the
2297
2329
  * one you meant, which settles it as an ordinary local shadow and is reviewable in a diff.
2298
2330
  */
2299
- collidingSources(): {
2300
- kind: string;
2301
- path: string;
2302
- slugs: string[];
2303
- }[];
2331
+ collidingSources(): SourceCollision[];
2332
+ /**
2333
+ * The paths a `hybrid` pin reaches as a different entity from the one another pin offers there.
2334
+ * The other pin's row stands at the path, and what the hybrid pin brings is drawn with it
2335
+ * ({@link drawsWithLocalRow}). Nothing here is refused, so this is what says the two differ.
2336
+ */
2337
+ settledSources(): readonly SettledSource[];
2304
2338
  /**
2305
2339
  * The derivation made for the snapshot this one came from, when this edit could not have changed
2306
2340
  * it: the same sources, no change to a pin or to which paths exist, and every row that did change
@@ -2313,8 +2347,9 @@ declare class Config {
2313
2347
  */
2314
2348
  private inheritedDerivation;
2315
2349
  /**
2316
- * Same paths in the same order, and every row that changed is authored on both sides and reaches
2317
- * the same sources the same way — see {@link inheritedDerivation}. Order counts because the walk
2350
+ * Same paths in the same order, and every row that changed is authored on both sides, isn't one a
2351
+ * linked pin reaches (`shadowed`), and reaches the same sources the same way — see
2352
+ * {@link inheritedDerivation}. Order counts because the walk
2318
2353
  * visits rows in stored order and mints in the order it reaches them, and key order is meaning
2319
2354
  * downstream.
2320
2355
  */
@@ -2325,13 +2360,15 @@ declare class Config {
2325
2360
  */
2326
2361
  private derivationFacts;
2327
2362
  /**
2328
- * Which of several sources offering `target` takes it, when exactly one pin's `link` declares it and
2329
- * every other source only reaches it through a borrowed style bag. `undefined` leaves it a collision.
2363
+ * Which of several sources offering `target` takes it. `undefined` leaves it a collision.
2364
+ *
2365
+ * A path one pin's `link` declares goes to that pin when every other source only reaches it and
2366
+ * either holds the same entity there or is `hybrid`, which brings in only what no other pin offers.
2367
+ * A `linked` source reaching a different entity at a declared path is a collision.
2330
2368
  *
2331
- * A reaching source counts only while its copy reads the same as the declarer's: one system built on
2332
- * another, pinned beside that other, reaches the same entity twice. Identity can't be traced instead,
2333
- * because an attached sibling arrives with what it borrowed inlined to literals. A copy that reads
2334
- * differently is its own entity, and picking either would hide the other.
2369
+ * A path no pin declares goes to the first `linked` source when every `linked` source holding it
2370
+ * reads the same entity, the `hybrid` ones yielding to them. With only `hybrid` sources it goes to
2371
+ * the first on the same condition. Two pins declaring one path is a collision either way.
2335
2372
  */
2336
2373
  private declaringClaimant;
2337
2374
  /**
@@ -2340,6 +2377,29 @@ declare class Config {
2340
2377
  * to literals and no pointer is left to trace.
2341
2378
  */
2342
2379
  private sameEntityThrough;
2380
+ /** Whether `other`'s entity at `kind:path` reads as `body`, spelled the way this config spells it. */
2381
+ private sameEntityAs;
2382
+ /** How `slug`'s source joins this config ({@link EntityKind.sourceType}): `linked` unless its pin
2383
+ * says otherwise. */
2384
+ sourceTypeOf(slug: string): SourceType;
2385
+ /**
2386
+ * Whether a value `slug` brings is drawn with this config's row at `kind:path` rather than declared
2387
+ * under the pin's own name: a token that something taken through `slug` names.
2388
+ *
2389
+ * A `hybrid` pin binds to any row here that isn't its own, authored or held through another pin, so
2390
+ * what it brings uses this config's values. A `linked` pin binds only to a row held through another
2391
+ * pin that is the same entity, the way {@link heldThroughAnotherPin} reads it; a different one there
2392
+ * is a collision, and a row this config authored is its own entity under the same name.
2393
+ */
2394
+ drawsWithLocalRow({
2395
+ slug,
2396
+ kind,
2397
+ path
2398
+ }: {
2399
+ slug: string;
2400
+ kind: string;
2401
+ path: string;
2402
+ }): boolean;
2343
2403
  /**
2344
2404
  * Whether `slug`'s entity at `kind:path` is one this config already holds through another pin, so a
2345
2405
  * qualified `path@slug` would be a second spelling of the same entity.
@@ -2792,4 +2852,4 @@ declare class Config {
2792
2852
  protected hydrateFrom(stored: StoredConfig, options?: HydrationOptions): this;
2793
2853
  }
2794
2854
  //#endregion
2795
- export { AppliedOp, AttachedSources, BatchReceipt, Config, CssGrammar, Edition, HydrationOptions, ListOptions, LiveConfig, Patch, RecordedSource, SERIALIZED_CONFIG_VERSION, SerializedConfig, SkippedOp, SourcesBySlug, StoredConfig, SubPatch, TreeNode };
2855
+ export { AppliedOp, AttachedSources, BatchReceipt, Config, CssGrammar, Edition, HydrationOptions, ListOptions, LiveConfig, Patch, RecordedSource, SERIALIZED_CONFIG_VERSION, SerializedConfig, SettledSource, SkippedOp, SourceCollision, SourcesBySlug, StoredConfig, SubPatch, TreeNode };