@suss/resolution 0.27.0 → 0.28.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/dist/index.d.cts CHANGED
@@ -1,5 +1,64 @@
1
1
  import * as _suss_datalog from '@suss/datalog';
2
- import { Database, Atom, Tuple, Proof, Rule } from '@suss/datalog';
2
+ import { Database, OnDemandRules, Atom, Tuple, Proof, Rule } from '@suss/datalog';
3
+
4
+ /**
5
+ * What a call's callee is, and when the rules settle on nothing, why.
6
+ *
7
+ * `resolves` comes back with a function and stays quiet otherwise, and a
8
+ * caller recording a gap needs the quiet cases told apart: a method on
9
+ * what a caller passed in is a different stop from a method on a value
10
+ * this run never read. So when the rules settle nothing, this walks down
11
+ * the facts the value was built from, one construct at a time, until it
12
+ * meets something that says where the value came from.
13
+ *
14
+ * Both halves are here because every language emits the same facts and
15
+ * meets the same stops. The words for an outcome stay with a language.
16
+ */
17
+
18
+ /** What a value a call is made through turns out to be. */
19
+ type CalleeOutcome =
20
+ /** One function in this run. */
21
+ {
22
+ readonly kind: "function";
23
+ readonly key: string;
24
+ }
25
+ /** One object in this run, which is a class where a language writes classes as objects. */
26
+ | {
27
+ readonly kind: "object";
28
+ readonly key: string;
29
+ }
30
+ /** More than one, so no single answer, and `sources` tells them apart. */
31
+ | {
32
+ readonly kind: "severalSources";
33
+ readonly sources: readonly string[];
34
+ }
35
+ /** A parameter, whose key is here so a caller can say whose parameter it is. */
36
+ | {
37
+ readonly kind: "callerSupplied";
38
+ readonly key: string;
39
+ }
40
+ /** Something a dependency built, or a name from a module this run never read. */
41
+ | {
42
+ readonly kind: "outsideRun";
43
+ }
44
+ /** Built in this run by something the rules could not follow through. */
45
+ | {
46
+ readonly kind: "unsettled";
47
+ }
48
+ /** Nothing in this run says anything about it. */
49
+ | {
50
+ readonly kind: "undeclared";
51
+ };
52
+ /**
53
+ * What each of these callees is. One batch, so evaluation runs per wave
54
+ * rather than per callee. A language whose adapter states rules of its
55
+ * own passes the program those rules were built into, so this runs over
56
+ * the same evaluation state the rest of that run uses.
57
+ */
58
+ declare function calleeOutcomes(db: Database, keys: readonly string[], program?: OnDemandRules): Map<string, CalleeOutcome>;
59
+ /** What one callee is, for a caller with a single key in hand. */
60
+ declare function calleeOutcomeOf(db: Database, key: string, program?: OnDemandRules): CalleeOutcome;
61
+ declare function writtenSourcesOf(db: Database, key: string): string[];
3
62
 
4
63
  /** The tuples of one relation, as strings, which is all a case compares. */
5
64
  type FactsOf = (relation: string) => string[][];
@@ -148,6 +207,84 @@ declare function mountPathsOf(edges: MountEdges, childId: string): readonly stri
148
207
  */
149
208
  declare function agreedMountPrefix(edges: MountEdges, childId: string): string | null;
150
209
 
210
+ /**
211
+ * Where a name is read, over whatever parse tree an adapter hands in.
212
+ *
213
+ * `valueLeftByWrites` needs to know whether a name's writes run once each
214
+ * in source order, and that answer comes from the tree: every write has to
215
+ * be a statement of the scope's own list, and nothing before the last of
216
+ * them may read the name. The walk is the same in every language, so it
217
+ * lives here and each adapter passes a description of its grammar.
218
+ *
219
+ * A description says four things: which node types spell a name, which
220
+ * of them open a body that runs later, how to enumerate a node's
221
+ * children, and which spellings of a name are reads rather than writes or
222
+ * declarations. Nothing here touches a parser.
223
+ */
224
+ /** The parts of a parse-tree node these walks read. */
225
+ interface ReadNode {
226
+ readonly type: string;
227
+ readonly text: string;
228
+ readonly startIndex: number;
229
+ }
230
+ /** What one language says about finding reads of a name in its trees. */
231
+ interface NameReads<N extends ReadNode> {
232
+ /** The node types a name is spelled with. Ruby has two, one of them `@name`. */
233
+ nameTypes: ReadonlySet<string>;
234
+ /**
235
+ * The types that open a body running later than the statements around
236
+ * it, so a function, a class, or a Ruby block. A read in there happens
237
+ * when something calls or enters the body, not where it is written.
238
+ */
239
+ laterBodies: ReadonlySet<string>;
240
+ /** A node's children, in source order. */
241
+ childrenOf: (node: N) => N[];
242
+ /**
243
+ * Whether a node spelling the name reads it, rather than being written
244
+ * to, declared, or spelled as somebody else's member.
245
+ */
246
+ isRead: (node: N) => boolean;
247
+ }
248
+ /** What one language says about which part of a chained expression is read first. */
249
+ interface ChainReads<N extends ReadNode> {
250
+ /** The node types a name is spelled with. Ruby has two, one of them `@name`. */
251
+ nameTypes: ReadonlySet<string>;
252
+ /**
253
+ * The part of an expression read before the rest of it, so a call's
254
+ * callee or a member read's object, or null when nothing is read before
255
+ * this node.
256
+ */
257
+ readFirst: (node: N) => N | null;
258
+ }
259
+ /** One write to a name, in the order it is written. */
260
+ interface OrderedWrite<N extends ReadNode> {
261
+ /** The node whose position orders this write among the scope's others. */
262
+ at: N;
263
+ /** Whether the write is a statement of the scope's own statement list. */
264
+ direct: boolean;
265
+ }
266
+ /**
267
+ * Whether the writes run once each, in the order they are written.
268
+ *
269
+ * They do when every one of them is a statement of the scope's own list.
270
+ * That list runs through once, top to bottom: nothing repeats and nothing
271
+ * is skipped. A write inside a branch, a loop, a block or a nested
272
+ * definition runs when something reaches it, and how many times is not a
273
+ * question this reads.
274
+ *
275
+ * The last write also has to be the one every read sees, so a read before
276
+ * it makes the answer depend on where the reader is, which the rules
277
+ * cannot express.
278
+ */
279
+ declare function writesRunInOrder<N extends ReadNode>(scope: N | null, name: string, writes: readonly OrderedWrite<N>[], rules: NameReads<N>): boolean;
280
+ /**
281
+ * Whether reading this expression starts by reading `name`, through
282
+ * however many calls, member reads and parentheses. That is what makes
283
+ * `query = query.filter(x)` a write narrowing what the other writes gave
284
+ * the name rather than one replacing it.
285
+ */
286
+ declare function startsAtName<N extends ReadNode>(node: N, name: string, rules: ChainReads<N>): boolean;
287
+
151
288
  /**
152
289
  * The tree-sitter adapters key a node by its file and byte span,
153
290
  * `file:start-end`. This finds the node a key refers to again, for an
@@ -167,6 +304,52 @@ interface SpannedNode<N> {
167
304
  */
168
305
  declare function nodeOfKey<N extends SpannedNode<N>>(rootsByFile: ReadonlyMap<string, N>, key: string): N | null;
169
306
 
307
+ /**
308
+ * The rules an adapter evaluates, and how a question is put to them.
309
+ *
310
+ * A demand-rewritten rule set is named by its shape, so two adapters
311
+ * that build the same array share one evaluation state and clearing
312
+ * under one of them resets the other. Every adapter builds its program
313
+ * here instead, and a language that states rules of its own gets one
314
+ * program of its own to pass around.
315
+ */
316
+
317
+ /**
318
+ * The facts that say somebody is asking. Each seeds one family of
319
+ * questions, and none of them is derived, so these are what a caller
320
+ * adds and what it takes back once it has read the answer.
321
+ */
322
+ declare const ASKING_RELATIONS: readonly string[];
323
+ /**
324
+ * The shared rules, whatever the language states of its own, and the
325
+ * questions, rewritten so a relation is derived only where a question
326
+ * reaches it. Built once per language and kept, because the rewrite
327
+ * does not depend on the facts.
328
+ *
329
+ * `SUSS_RESOLUTION_ON_DEMAND=0` runs the same rules unrestricted. Both
330
+ * settings give the same answers; they differ in how much never gets
331
+ * derived at all.
332
+ */
333
+ declare function resolutionProgram(languageRules?: readonly Rule[]): OnDemandRules;
334
+ /**
335
+ * What a caller takes back once it has read an answer: the question and
336
+ * every relation derived under it. Empty when nothing is demand-driven,
337
+ * since then the answers themselves are what clearing would remove.
338
+ */
339
+ declare function queryFacts(program: OnDemandRules): readonly string[];
340
+ /**
341
+ * Ask about these values, derive, and take the question back.
342
+ *
343
+ * Asking about everything in a project costs seconds on a large one and
344
+ * settles questions nobody has, so a caller lists the keys it needs. The
345
+ * answers stay in the database; the question and the chain that settled
346
+ * it go, so the next question does not derive over every question asked
347
+ * before it. What has already been asked is remembered, so asking twice
348
+ * costs nothing. That wants every fact in the database before the first
349
+ * question, which is how each adapter reads a project.
350
+ */
351
+ declare function askResolution(db: Database, keys: Iterable<string>, asking?: string, program?: OnDemandRules): void;
352
+
170
353
  /**
171
354
  * The result shape a why session hands back, shared by every language
172
355
  * adapter so the CLI reads one type regardless of which adapter
@@ -243,6 +426,55 @@ declare function singleAnswers(rows: Iterable<Tuple>, placeholders?: ReadonlySet
243
426
  /** The keys an adapter marked `placeholderValue`, for passing to `singleAnswers`. */
244
427
  declare function placeholderValues(db: Database): ReadonlySet<string>;
245
428
 
429
+ /**
430
+ * What a name written more than once comes down to.
431
+ *
432
+ * Each adapter reads writes out of a different parser, so the reading
433
+ * stays with the adapter and the decision lives here, over a
434
+ * description of the writes that nothing parser-shaped reaches. While
435
+ * each adapter decided for itself, the same source resolved in one
436
+ * language and not in another.
437
+ *
438
+ * Whether the writes run in order is a question about statement
439
+ * structure, and `writesRunInOrder` works that out beside this.
440
+ */
441
+ /** One write to a name, in the order it is written. */
442
+ interface NameWrite {
443
+ /**
444
+ * The key of the value written, or null when the write states no
445
+ * value of its own, as `count += 1` and `index++` do.
446
+ */
447
+ value: string | null;
448
+ /** Whether a later write is expected to replace this value: `null`, `undefined`, `None`, `nil`. */
449
+ placeholder: boolean;
450
+ /**
451
+ * The value's source text when it is built where it is written, so a
452
+ * call, a `new`, or an object or array literal. Null otherwise.
453
+ */
454
+ construction: string | null;
455
+ /**
456
+ * Whether the value is a call on the name being written, `query =
457
+ * query.filter(x)`, which leaves the name what the other writes gave
458
+ * it with a method applied. A call returning something of another kind
459
+ * is not told apart, and a narrowing written through a second name,
460
+ * `tmp = query.limit(1)` then `query = tmp`, is not recognized.
461
+ */
462
+ narrowsName: boolean;
463
+ }
464
+ /**
465
+ * The value a name comes down to, or null when the writes leave it
466
+ * undecided.
467
+ *
468
+ * With `ordered`, every write runs once in the order it is written and
469
+ * nothing reads the name in between, so the last write is what a reader
470
+ * sees. Otherwise the writes are candidates the caller cannot order,
471
+ * and they settle the name only when they all build the same thing.
472
+ *
473
+ * A write with no value of its own puts a hole in the sequence, and then
474
+ * no write can be called the last one. A narrowing write is set aside.
475
+ */
476
+ declare function valueLeftByWrites(writes: readonly NameWrite[], ordered: boolean): string | null;
477
+
246
478
  /**
247
479
  * The single expression a value was written as, once the caller has
248
480
  * asked the rules about `key`. A call to a project function is asked
@@ -299,4 +531,4 @@ declare const RESOLUTION_QUESTIONS: _suss_datalog.Rule[];
299
531
  /** The relations `RESOLUTION_QUESTIONS` answers into. */
300
532
  declare const ANSWER_RELATIONS: string[];
301
533
 
302
- export { ANSWER_RELATIONS, type CaseFiles, type ContractCase, type ContractOptions, type DescribeAtom, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, VALUE_STEP, type ValueLocation, type WhyExplained, agreedMountPrefix, checkFactContract, explainResolutionProof, explainResolvedKey, joinMountedPath, mountPathsOf, nodeOfKey, placeholderValues, renderExplanation, singleAnswers, writtenValueOf };
534
+ export { ANSWER_RELATIONS, ASKING_RELATIONS, type CalleeOutcome, type CaseFiles, type ChainReads, type ContractCase, type ContractOptions, type DescribeAtom, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, type NameReads, type NameWrite, type OrderedWrite, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ReadNode, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, VALUE_STEP, type ValueLocation, type WhyExplained, agreedMountPrefix, askResolution, calleeOutcomeOf, calleeOutcomes, checkFactContract, explainResolutionProof, explainResolvedKey, joinMountedPath, mountPathsOf, nodeOfKey, placeholderValues, queryFacts, renderExplanation, resolutionProgram, singleAnswers, startsAtName, valueLeftByWrites, writesRunInOrder, writtenSourcesOf, writtenValueOf };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,64 @@
1
1
  import * as _suss_datalog from '@suss/datalog';
2
- import { Database, Atom, Tuple, Proof, Rule } from '@suss/datalog';
2
+ import { Database, OnDemandRules, Atom, Tuple, Proof, Rule } from '@suss/datalog';
3
+
4
+ /**
5
+ * What a call's callee is, and when the rules settle on nothing, why.
6
+ *
7
+ * `resolves` comes back with a function and stays quiet otherwise, and a
8
+ * caller recording a gap needs the quiet cases told apart: a method on
9
+ * what a caller passed in is a different stop from a method on a value
10
+ * this run never read. So when the rules settle nothing, this walks down
11
+ * the facts the value was built from, one construct at a time, until it
12
+ * meets something that says where the value came from.
13
+ *
14
+ * Both halves are here because every language emits the same facts and
15
+ * meets the same stops. The words for an outcome stay with a language.
16
+ */
17
+
18
+ /** What a value a call is made through turns out to be. */
19
+ type CalleeOutcome =
20
+ /** One function in this run. */
21
+ {
22
+ readonly kind: "function";
23
+ readonly key: string;
24
+ }
25
+ /** One object in this run, which is a class where a language writes classes as objects. */
26
+ | {
27
+ readonly kind: "object";
28
+ readonly key: string;
29
+ }
30
+ /** More than one, so no single answer, and `sources` tells them apart. */
31
+ | {
32
+ readonly kind: "severalSources";
33
+ readonly sources: readonly string[];
34
+ }
35
+ /** A parameter, whose key is here so a caller can say whose parameter it is. */
36
+ | {
37
+ readonly kind: "callerSupplied";
38
+ readonly key: string;
39
+ }
40
+ /** Something a dependency built, or a name from a module this run never read. */
41
+ | {
42
+ readonly kind: "outsideRun";
43
+ }
44
+ /** Built in this run by something the rules could not follow through. */
45
+ | {
46
+ readonly kind: "unsettled";
47
+ }
48
+ /** Nothing in this run says anything about it. */
49
+ | {
50
+ readonly kind: "undeclared";
51
+ };
52
+ /**
53
+ * What each of these callees is. One batch, so evaluation runs per wave
54
+ * rather than per callee. A language whose adapter states rules of its
55
+ * own passes the program those rules were built into, so this runs over
56
+ * the same evaluation state the rest of that run uses.
57
+ */
58
+ declare function calleeOutcomes(db: Database, keys: readonly string[], program?: OnDemandRules): Map<string, CalleeOutcome>;
59
+ /** What one callee is, for a caller with a single key in hand. */
60
+ declare function calleeOutcomeOf(db: Database, key: string, program?: OnDemandRules): CalleeOutcome;
61
+ declare function writtenSourcesOf(db: Database, key: string): string[];
3
62
 
4
63
  /** The tuples of one relation, as strings, which is all a case compares. */
5
64
  type FactsOf = (relation: string) => string[][];
@@ -148,6 +207,84 @@ declare function mountPathsOf(edges: MountEdges, childId: string): readonly stri
148
207
  */
149
208
  declare function agreedMountPrefix(edges: MountEdges, childId: string): string | null;
150
209
 
210
+ /**
211
+ * Where a name is read, over whatever parse tree an adapter hands in.
212
+ *
213
+ * `valueLeftByWrites` needs to know whether a name's writes run once each
214
+ * in source order, and that answer comes from the tree: every write has to
215
+ * be a statement of the scope's own list, and nothing before the last of
216
+ * them may read the name. The walk is the same in every language, so it
217
+ * lives here and each adapter passes a description of its grammar.
218
+ *
219
+ * A description says four things: which node types spell a name, which
220
+ * of them open a body that runs later, how to enumerate a node's
221
+ * children, and which spellings of a name are reads rather than writes or
222
+ * declarations. Nothing here touches a parser.
223
+ */
224
+ /** The parts of a parse-tree node these walks read. */
225
+ interface ReadNode {
226
+ readonly type: string;
227
+ readonly text: string;
228
+ readonly startIndex: number;
229
+ }
230
+ /** What one language says about finding reads of a name in its trees. */
231
+ interface NameReads<N extends ReadNode> {
232
+ /** The node types a name is spelled with. Ruby has two, one of them `@name`. */
233
+ nameTypes: ReadonlySet<string>;
234
+ /**
235
+ * The types that open a body running later than the statements around
236
+ * it, so a function, a class, or a Ruby block. A read in there happens
237
+ * when something calls or enters the body, not where it is written.
238
+ */
239
+ laterBodies: ReadonlySet<string>;
240
+ /** A node's children, in source order. */
241
+ childrenOf: (node: N) => N[];
242
+ /**
243
+ * Whether a node spelling the name reads it, rather than being written
244
+ * to, declared, or spelled as somebody else's member.
245
+ */
246
+ isRead: (node: N) => boolean;
247
+ }
248
+ /** What one language says about which part of a chained expression is read first. */
249
+ interface ChainReads<N extends ReadNode> {
250
+ /** The node types a name is spelled with. Ruby has two, one of them `@name`. */
251
+ nameTypes: ReadonlySet<string>;
252
+ /**
253
+ * The part of an expression read before the rest of it, so a call's
254
+ * callee or a member read's object, or null when nothing is read before
255
+ * this node.
256
+ */
257
+ readFirst: (node: N) => N | null;
258
+ }
259
+ /** One write to a name, in the order it is written. */
260
+ interface OrderedWrite<N extends ReadNode> {
261
+ /** The node whose position orders this write among the scope's others. */
262
+ at: N;
263
+ /** Whether the write is a statement of the scope's own statement list. */
264
+ direct: boolean;
265
+ }
266
+ /**
267
+ * Whether the writes run once each, in the order they are written.
268
+ *
269
+ * They do when every one of them is a statement of the scope's own list.
270
+ * That list runs through once, top to bottom: nothing repeats and nothing
271
+ * is skipped. A write inside a branch, a loop, a block or a nested
272
+ * definition runs when something reaches it, and how many times is not a
273
+ * question this reads.
274
+ *
275
+ * The last write also has to be the one every read sees, so a read before
276
+ * it makes the answer depend on where the reader is, which the rules
277
+ * cannot express.
278
+ */
279
+ declare function writesRunInOrder<N extends ReadNode>(scope: N | null, name: string, writes: readonly OrderedWrite<N>[], rules: NameReads<N>): boolean;
280
+ /**
281
+ * Whether reading this expression starts by reading `name`, through
282
+ * however many calls, member reads and parentheses. That is what makes
283
+ * `query = query.filter(x)` a write narrowing what the other writes gave
284
+ * the name rather than one replacing it.
285
+ */
286
+ declare function startsAtName<N extends ReadNode>(node: N, name: string, rules: ChainReads<N>): boolean;
287
+
151
288
  /**
152
289
  * The tree-sitter adapters key a node by its file and byte span,
153
290
  * `file:start-end`. This finds the node a key refers to again, for an
@@ -167,6 +304,52 @@ interface SpannedNode<N> {
167
304
  */
168
305
  declare function nodeOfKey<N extends SpannedNode<N>>(rootsByFile: ReadonlyMap<string, N>, key: string): N | null;
169
306
 
307
+ /**
308
+ * The rules an adapter evaluates, and how a question is put to them.
309
+ *
310
+ * A demand-rewritten rule set is named by its shape, so two adapters
311
+ * that build the same array share one evaluation state and clearing
312
+ * under one of them resets the other. Every adapter builds its program
313
+ * here instead, and a language that states rules of its own gets one
314
+ * program of its own to pass around.
315
+ */
316
+
317
+ /**
318
+ * The facts that say somebody is asking. Each seeds one family of
319
+ * questions, and none of them is derived, so these are what a caller
320
+ * adds and what it takes back once it has read the answer.
321
+ */
322
+ declare const ASKING_RELATIONS: readonly string[];
323
+ /**
324
+ * The shared rules, whatever the language states of its own, and the
325
+ * questions, rewritten so a relation is derived only where a question
326
+ * reaches it. Built once per language and kept, because the rewrite
327
+ * does not depend on the facts.
328
+ *
329
+ * `SUSS_RESOLUTION_ON_DEMAND=0` runs the same rules unrestricted. Both
330
+ * settings give the same answers; they differ in how much never gets
331
+ * derived at all.
332
+ */
333
+ declare function resolutionProgram(languageRules?: readonly Rule[]): OnDemandRules;
334
+ /**
335
+ * What a caller takes back once it has read an answer: the question and
336
+ * every relation derived under it. Empty when nothing is demand-driven,
337
+ * since then the answers themselves are what clearing would remove.
338
+ */
339
+ declare function queryFacts(program: OnDemandRules): readonly string[];
340
+ /**
341
+ * Ask about these values, derive, and take the question back.
342
+ *
343
+ * Asking about everything in a project costs seconds on a large one and
344
+ * settles questions nobody has, so a caller lists the keys it needs. The
345
+ * answers stay in the database; the question and the chain that settled
346
+ * it go, so the next question does not derive over every question asked
347
+ * before it. What has already been asked is remembered, so asking twice
348
+ * costs nothing. That wants every fact in the database before the first
349
+ * question, which is how each adapter reads a project.
350
+ */
351
+ declare function askResolution(db: Database, keys: Iterable<string>, asking?: string, program?: OnDemandRules): void;
352
+
170
353
  /**
171
354
  * The result shape a why session hands back, shared by every language
172
355
  * adapter so the CLI reads one type regardless of which adapter
@@ -243,6 +426,55 @@ declare function singleAnswers(rows: Iterable<Tuple>, placeholders?: ReadonlySet
243
426
  /** The keys an adapter marked `placeholderValue`, for passing to `singleAnswers`. */
244
427
  declare function placeholderValues(db: Database): ReadonlySet<string>;
245
428
 
429
+ /**
430
+ * What a name written more than once comes down to.
431
+ *
432
+ * Each adapter reads writes out of a different parser, so the reading
433
+ * stays with the adapter and the decision lives here, over a
434
+ * description of the writes that nothing parser-shaped reaches. While
435
+ * each adapter decided for itself, the same source resolved in one
436
+ * language and not in another.
437
+ *
438
+ * Whether the writes run in order is a question about statement
439
+ * structure, and `writesRunInOrder` works that out beside this.
440
+ */
441
+ /** One write to a name, in the order it is written. */
442
+ interface NameWrite {
443
+ /**
444
+ * The key of the value written, or null when the write states no
445
+ * value of its own, as `count += 1` and `index++` do.
446
+ */
447
+ value: string | null;
448
+ /** Whether a later write is expected to replace this value: `null`, `undefined`, `None`, `nil`. */
449
+ placeholder: boolean;
450
+ /**
451
+ * The value's source text when it is built where it is written, so a
452
+ * call, a `new`, or an object or array literal. Null otherwise.
453
+ */
454
+ construction: string | null;
455
+ /**
456
+ * Whether the value is a call on the name being written, `query =
457
+ * query.filter(x)`, which leaves the name what the other writes gave
458
+ * it with a method applied. A call returning something of another kind
459
+ * is not told apart, and a narrowing written through a second name,
460
+ * `tmp = query.limit(1)` then `query = tmp`, is not recognized.
461
+ */
462
+ narrowsName: boolean;
463
+ }
464
+ /**
465
+ * The value a name comes down to, or null when the writes leave it
466
+ * undecided.
467
+ *
468
+ * With `ordered`, every write runs once in the order it is written and
469
+ * nothing reads the name in between, so the last write is what a reader
470
+ * sees. Otherwise the writes are candidates the caller cannot order,
471
+ * and they settle the name only when they all build the same thing.
472
+ *
473
+ * A write with no value of its own puts a hole in the sequence, and then
474
+ * no write can be called the last one. A narrowing write is set aside.
475
+ */
476
+ declare function valueLeftByWrites(writes: readonly NameWrite[], ordered: boolean): string | null;
477
+
246
478
  /**
247
479
  * The single expression a value was written as, once the caller has
248
480
  * asked the rules about `key`. A call to a project function is asked
@@ -299,4 +531,4 @@ declare const RESOLUTION_QUESTIONS: _suss_datalog.Rule[];
299
531
  /** The relations `RESOLUTION_QUESTIONS` answers into. */
300
532
  declare const ANSWER_RELATIONS: string[];
301
533
 
302
- export { ANSWER_RELATIONS, type CaseFiles, type ContractCase, type ContractOptions, type DescribeAtom, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, VALUE_STEP, type ValueLocation, type WhyExplained, agreedMountPrefix, checkFactContract, explainResolutionProof, explainResolvedKey, joinMountedPath, mountPathsOf, nodeOfKey, placeholderValues, renderExplanation, singleAnswers, writtenValueOf };
534
+ export { ANSWER_RELATIONS, ASKING_RELATIONS, type CalleeOutcome, type CaseFiles, type ChainReads, type ContractCase, type ContractOptions, type DescribeAtom, type ExplainOptions, type ExplainResolvedKeyOptions, type ExplainStats, FACT_CONTRACT_CASES, type FactsOf, type MountEdge, type MountEdges, NAMESPACE_IMPORT, NAMESPACE_IMPORT_NAME, type NameReads, type NameWrite, type OrderedWrite, RESOLUTION_QUESTIONS, RESOLUTION_RULES, RESULT_STEP, type ReadNode, type ResolutionExplanation, type ResolutionStep, type SpannedNode, type StepContext, type StepPhrase, VALUE_STEP, type ValueLocation, type WhyExplained, agreedMountPrefix, askResolution, calleeOutcomeOf, calleeOutcomes, checkFactContract, explainResolutionProof, explainResolvedKey, joinMountedPath, mountPathsOf, nodeOfKey, placeholderValues, queryFacts, renderExplanation, resolutionProgram, singleAnswers, startsAtName, valueLeftByWrites, writesRunInOrder, writtenSourcesOf, writtenValueOf };