@suss/resolution 0.20.0 → 0.21.1

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/README.md CHANGED
@@ -97,6 +97,18 @@ Each question is that one closure with its own stopping condition. So
97
97
  adding a construct is one step and every question gets it, and adding a
98
98
  question is a stopping condition and no steps at all.
99
99
 
100
+ The closure is written with the walk so far first and the next hop after
101
+ it: `reaches(x, z) <- reaches(x, y), stepsTo(y, z)`. The order matters
102
+ under demand. Every question here asks about one value, and with the
103
+ walk first, the demand stays on that value and each round extends the
104
+ walks it already has by one hop. Written hop first, `reaches(x, z) <-
105
+ stepsTo(x, y), reaches(y, z)`, a question about `x` becomes a question
106
+ about every `y` a hop leads to, so the closure is derived from every
107
+ value the walk passes through, and each new walk is joined back against
108
+ every hop that lands on its start. Extracting the TypeScript adapter's
109
+ own sources, the hop first order spent two seconds in the closure, and
110
+ the walk first order spends forty milliseconds.
111
+
100
112
  ## What comes out
101
113
 
102
114
  ```
@@ -200,6 +212,32 @@ The demand cone stays on the base facts named above. Nothing here pulls
200
212
  `reaches` or `callsInto`, so asking about a receiver does not price in
201
213
  call-graph closure.
202
214
 
215
+ ## The subject behind a registration
216
+
217
+ Discovery keeps asking one question: is this receiver the app, the
218
+ router, the thing built by calling what a library exports? Which
219
+ `.get(...)` calls are routes and which `.use(...)` calls are mounts
220
+ both hang on the answer, and every language feature that moves a value
221
+ is a place the receiver can be written: a class field, a destructured
222
+ name, a property on an object another file built. Enumerating those
223
+ spellings in a walker loses to the language, so the question is asked
224
+ of the rules instead.
225
+
226
+ The answer comes back in two relations, both seeded by
227
+ `wantedSubject`.
228
+ `wantedSubjectWritten` is the written-value walk from the asked
229
+ receiver, so the asking side can apply the single-answer policy over
230
+ everything the receiver could be. `wantedSubjectConstruction` keeps
231
+ only the answers that are a call or a `new`, and pairs each with where
232
+ its callee was imported from, through however many aliases the callee
233
+ went. The asking side checks that pair against the (module, name) a
234
+ pack declares: exactly one distinct construction with a matching
235
+ origin is the subject, none or several is a refusal.
236
+
237
+ The construction end needs no fact of its own. Every call is already a
238
+ `call` fact, a `new` expression included, and the join against
239
+ `comesFrom` is what makes one of them a subject seed.
240
+
203
241
  ## Explaining an answer
204
242
 
205
243
  Evaluate the same rules under `@suss/datalog`'s `witnesses` algebra and
package/dist/index.cjs CHANGED
@@ -631,9 +631,9 @@ var RESOLUTION_RULES = [
631
631
  [(0, import_datalog2.lit)("invokes", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("f")), (0, import_datalog2.lit)("returnsValue", (0, import_datalog2.variable)("f"), (0, import_datalog2.variable)("ret"))],
632
632
  "call result"
633
633
  ),
634
- // Where a walk gets to, and whether it ran a call on the way. A value
635
- // step keeps whatever the rest of the walk was, and a result step
636
- // makes the whole walk one that ran a call.
634
+ // Where a walk gets to, and whether it ran a call on the way. The walk
635
+ // so far comes first, so demand stays on the value asked about; the
636
+ // README says what the other order cost.
637
637
  (0, import_datalog2.rule)(
638
638
  "reaches",
639
639
  [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
@@ -643,27 +643,27 @@ var RESOLUTION_RULES = [
643
643
  "reaches",
644
644
  [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind")],
645
645
  [
646
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
647
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind"))
646
+ (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), VALUE_STEP),
647
+ (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), (0, import_datalog2.variable)("kind"))
648
648
  ]
649
649
  ),
650
- // Two rules rather than one leaving the rest of the walk's kind free.
651
- // A free kind is a second question about the same relation, and a
650
+ // Two rules rather than one leaving the next step's kind free. A free
651
+ // kind is a second question about the same relation, and a
652
652
  // demand-driven run then derives both to answer either.
653
653
  (0, import_datalog2.rule)(
654
654
  "reaches",
655
655
  [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP],
656
656
  [
657
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
658
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), VALUE_STEP)
657
+ (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
658
+ (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), VALUE_STEP)
659
659
  ]
660
660
  ),
661
661
  (0, import_datalog2.rule)(
662
662
  "reaches",
663
663
  [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"), RESULT_STEP],
664
664
  [
665
- (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
666
- (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), RESULT_STEP)
665
+ (0, import_datalog2.lit)("reaches", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y"), RESULT_STEP),
666
+ (0, import_datalog2.lit)("stepsTo", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"), RESULT_STEP)
667
667
  ]
668
668
  ),
669
669
  // What a value comes down to: the walk that never ran a call, stopped
@@ -1009,29 +1009,14 @@ var RESOLUTION_QUESTIONS = [
1009
1009
  // here demands reaches or callsInto. The chains are closures with
1010
1010
  // no depth bound: an alias run of any length resolves.
1011
1011
  (0, import_datalog2.rule)("callOriginChain", [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("x")], [(0, import_datalog2.lit)("wantedCallOrigin", (0, import_datalog2.variable)("x"))]),
1012
+ // The chain with at least one hop taken, which is what tells a
1013
+ // destructured binding apart from asking about a node directly. The
1014
+ // whole chain is the seed plus those hops.
1012
1015
  (0, import_datalog2.rule)(
1013
1016
  "callOriginChain",
1014
1017
  [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1015
- [(0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")), (0, import_datalog2.lit)("binds", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))]
1018
+ [(0, import_datalog2.lit)("callOriginChainStepped", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z"))]
1016
1019
  ),
1017
- (0, import_datalog2.rule)(
1018
- "callOriginChain",
1019
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1020
- [
1021
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1022
- (0, import_datalog2.lit)("endsHolding", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1023
- ]
1024
- ),
1025
- (0, import_datalog2.rule)(
1026
- "callOriginChain",
1027
- [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
1028
- [
1029
- (0, import_datalog2.lit)("callOriginChain", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("y")),
1030
- (0, import_datalog2.lit)("fallbackBranch", (0, import_datalog2.variable)("y"), (0, import_datalog2.variable)("z"))
1031
- ]
1032
- ),
1033
- // The chain with at least one hop taken, which is what tells a
1034
- // destructured binding apart from asking about a node directly.
1035
1020
  (0, import_datalog2.rule)(
1036
1021
  "callOriginChainStepped",
1037
1022
  [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("z")],
@@ -1162,6 +1147,23 @@ var RESOLUTION_QUESTIONS = [
1162
1147
  (0, import_datalog2.lit)("callsInto", (0, import_datalog2.variable)("g"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1163
1148
  ]
1164
1149
  ),
1150
+ // Subject identity, its own demand class; the README's subject
1151
+ // section says why the origin pair rides on the written-value walk.
1152
+ (0, import_datalog2.rule)(
1153
+ "wantedSubjectWritten",
1154
+ [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")],
1155
+ [(0, import_datalog2.lit)("wantedSubject", (0, import_datalog2.variable)("x")), (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r"))]
1156
+ ),
1157
+ (0, import_datalog2.rule)(
1158
+ "wantedSubjectConstruction",
1159
+ [(0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n")],
1160
+ [
1161
+ (0, import_datalog2.lit)("wantedSubject", (0, import_datalog2.variable)("x")),
1162
+ (0, import_datalog2.lit)("isWrittenAs", (0, import_datalog2.variable)("x"), (0, import_datalog2.variable)("r")),
1163
+ (0, import_datalog2.lit)("call", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("c")),
1164
+ (0, import_datalog2.lit)("comesFrom", (0, import_datalog2.variable)("c"), (0, import_datalog2.variable)("m"), (0, import_datalog2.variable)("n"))
1165
+ ]
1166
+ ),
1165
1167
  // The export table of one module, keyed by the module asked about.
1166
1168
  // The moduleExport rules flatten re-export chains of any length, and
1167
1169
  // the demand cone stays on export facts alone.
package/dist/index.js CHANGED
@@ -592,9 +592,9 @@ var RESOLUTION_RULES = [
592
592
  [lit("invokes", v("r"), v("f")), lit("returnsValue", v("f"), v("ret"))],
593
593
  "call result"
594
594
  ),
595
- // Where a walk gets to, and whether it ran a call on the way. A value
596
- // step keeps whatever the rest of the walk was, and a result step
597
- // makes the whole walk one that ran a call.
595
+ // Where a walk gets to, and whether it ran a call on the way. The walk
596
+ // so far comes first, so demand stays on the value asked about; the
597
+ // README says what the other order cost.
598
598
  rule(
599
599
  "reaches",
600
600
  [v("x"), v("z"), v("kind")],
@@ -604,27 +604,27 @@ var RESOLUTION_RULES = [
604
604
  "reaches",
605
605
  [v("x"), v("z"), v("kind")],
606
606
  [
607
- lit("stepsTo", v("x"), v("y"), VALUE_STEP),
608
- lit("reaches", v("y"), v("z"), v("kind"))
607
+ lit("reaches", v("x"), v("y"), VALUE_STEP),
608
+ lit("stepsTo", v("y"), v("z"), v("kind"))
609
609
  ]
610
610
  ),
611
- // Two rules rather than one leaving the rest of the walk's kind free.
612
- // A free kind is a second question about the same relation, and a
611
+ // Two rules rather than one leaving the next step's kind free. A free
612
+ // kind is a second question about the same relation, and a
613
613
  // demand-driven run then derives both to answer either.
614
614
  rule(
615
615
  "reaches",
616
616
  [v("x"), v("z"), RESULT_STEP],
617
617
  [
618
- lit("stepsTo", v("x"), v("y"), RESULT_STEP),
619
- lit("reaches", v("y"), v("z"), VALUE_STEP)
618
+ lit("reaches", v("x"), v("y"), RESULT_STEP),
619
+ lit("stepsTo", v("y"), v("z"), VALUE_STEP)
620
620
  ]
621
621
  ),
622
622
  rule(
623
623
  "reaches",
624
624
  [v("x"), v("z"), RESULT_STEP],
625
625
  [
626
- lit("stepsTo", v("x"), v("y"), RESULT_STEP),
627
- lit("reaches", v("y"), v("z"), RESULT_STEP)
626
+ lit("reaches", v("x"), v("y"), RESULT_STEP),
627
+ lit("stepsTo", v("y"), v("z"), RESULT_STEP)
628
628
  ]
629
629
  ),
630
630
  // What a value comes down to: the walk that never ran a call, stopped
@@ -970,29 +970,14 @@ var RESOLUTION_QUESTIONS = [
970
970
  // here demands reaches or callsInto. The chains are closures with
971
971
  // no depth bound: an alias run of any length resolves.
972
972
  rule("callOriginChain", [v("x"), v("x")], [lit("wantedCallOrigin", v("x"))]),
973
+ // The chain with at least one hop taken, which is what tells a
974
+ // destructured binding apart from asking about a node directly. The
975
+ // whole chain is the seed plus those hops.
973
976
  rule(
974
977
  "callOriginChain",
975
978
  [v("x"), v("z")],
976
- [lit("callOriginChain", v("x"), v("y")), lit("binds", v("y"), v("z"))]
979
+ [lit("callOriginChainStepped", v("x"), v("z"))]
977
980
  ),
978
- rule(
979
- "callOriginChain",
980
- [v("x"), v("z")],
981
- [
982
- lit("callOriginChain", v("x"), v("y")),
983
- lit("endsHolding", v("y"), v("z"))
984
- ]
985
- ),
986
- rule(
987
- "callOriginChain",
988
- [v("x"), v("z")],
989
- [
990
- lit("callOriginChain", v("x"), v("y")),
991
- lit("fallbackBranch", v("y"), v("z"))
992
- ]
993
- ),
994
- // The chain with at least one hop taken, which is what tells a
995
- // destructured binding apart from asking about a node directly.
996
981
  rule(
997
982
  "callOriginChainStepped",
998
983
  [v("x"), v("z")],
@@ -1123,6 +1108,23 @@ var RESOLUTION_QUESTIONS = [
1123
1108
  lit("callsInto", v("g"), v("m"), v("n"))
1124
1109
  ]
1125
1110
  ),
1111
+ // Subject identity, its own demand class; the README's subject
1112
+ // section says why the origin pair rides on the written-value walk.
1113
+ rule(
1114
+ "wantedSubjectWritten",
1115
+ [v("x"), v("r")],
1116
+ [lit("wantedSubject", v("x")), lit("isWrittenAs", v("x"), v("r"))]
1117
+ ),
1118
+ rule(
1119
+ "wantedSubjectConstruction",
1120
+ [v("x"), v("r"), v("m"), v("n")],
1121
+ [
1122
+ lit("wantedSubject", v("x")),
1123
+ lit("isWrittenAs", v("x"), v("r")),
1124
+ lit("call", v("r"), v("c")),
1125
+ lit("comesFrom", v("c"), v("m"), v("n"))
1126
+ ]
1127
+ ),
1126
1128
  // The export table of one module, keyed by the module asked about.
1127
1129
  // The moduleExport rules flatten re-export chains of any length, and
1128
1130
  // the demand cone stays on export facts alone.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/resolution",
3
- "version": "0.20.0",
3
+ "version": "0.21.1",
4
4
  "type": "module",
5
5
  "description": "Language-neutral rules for following a value to the function it comes down to.",
6
6
  "keywords": [
@@ -53,6 +53,6 @@
53
53
  "access": "public"
54
54
  },
55
55
  "dependencies": {
56
- "@suss/datalog": "0.20.0"
56
+ "@suss/datalog": "0.21.1"
57
57
  }
58
58
  }