carrick 0.3.70 → 0.3.73

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.
Files changed (55) hide show
  1. package/README.md +10 -2
  2. package/bin/carrick.mjs +4 -1
  3. package/dist/contract.d.ts +3 -0
  4. package/dist/contract.js.map +1 -1
  5. package/dist/init/doctor.d.ts +3 -1
  6. package/dist/init/doctor.js +33 -6
  7. package/dist/init/doctor.js.map +1 -1
  8. package/dist/init/install-id.d.ts +32 -0
  9. package/dist/init/install-id.js +118 -0
  10. package/dist/init/install-id.js.map +1 -0
  11. package/dist/init/mcp.d.ts +59 -5
  12. package/dist/init/mcp.js +133 -27
  13. package/dist/init/mcp.js.map +1 -1
  14. package/dist/init/remove.d.ts +4 -0
  15. package/dist/init/remove.js +26 -5
  16. package/dist/init/remove.js.map +1 -1
  17. package/dist/init/run.d.ts +8 -0
  18. package/dist/init/run.js +20 -2
  19. package/dist/init/run.js.map +1 -1
  20. package/dist/native.d.ts +25 -5
  21. package/dist/native.js +41 -10
  22. package/dist/native.js.map +1 -1
  23. package/dist/render.js +7 -2
  24. package/dist/render.js.map +1 -1
  25. package/package.json +6 -6
  26. package/sidecar/dist/src/capture/anchors.d.ts +15 -0
  27. package/sidecar/dist/src/capture/anchors.js +70 -5
  28. package/sidecar/dist/src/capture/api.d.ts +43 -4
  29. package/sidecar/dist/src/capture/check-classify.d.ts +2 -0
  30. package/sidecar/dist/src/capture/check-classify.js +28 -0
  31. package/sidecar/dist/src/capture/check-deep.js +1 -1
  32. package/sidecar/dist/src/capture/check-probe.d.ts +1 -1
  33. package/sidecar/dist/src/capture/check-probe.js +16 -0
  34. package/sidecar/dist/src/capture/deep-walk.d.ts +33 -6
  35. package/sidecar/dist/src/capture/deep-walk.js +81 -28
  36. package/sidecar/dist/src/capture/index.js +16 -6
  37. package/sidecar/dist/src/capture/installed-package.d.ts +58 -0
  38. package/sidecar/dist/src/capture/installed-package.js +311 -0
  39. package/sidecar/dist/src/capture/lockfile.d.ts +8 -0
  40. package/sidecar/dist/src/capture/lockfile.js +1 -1
  41. package/sidecar/dist/src/capture/node-builder.d.ts +27 -0
  42. package/sidecar/dist/src/capture/node-builder.js +107 -1
  43. package/sidecar/dist/src/capture/paths-rewrite.d.ts +23 -6
  44. package/sidecar/dist/src/capture/paths-rewrite.js +43 -11
  45. package/sidecar/dist/src/capture/self-check.js +12 -3
  46. package/sidecar/dist/src/capture/unresolved.d.ts +28 -0
  47. package/sidecar/dist/src/capture/unresolved.js +107 -0
  48. package/sidecar/dist/src/type-inferrer.d.ts +227 -30
  49. package/sidecar/dist/src/type-inferrer.js +926 -144
  50. package/sidecar/dist/src/type-structural-expander.d.ts +53 -3
  51. package/sidecar/dist/src/type-structural-expander.js +108 -19
  52. package/sidecar/dist/src/type-text-canonicalizer.d.ts +14 -0
  53. package/sidecar/dist/src/type-text-canonicalizer.js +23 -2
  54. package/sidecar/dist/src/validators.d.ts +10 -0
  55. package/sidecar/dist/src/validators.js +1 -0
@@ -135,6 +135,57 @@ export declare class TypeInferrer {
135
135
  */
136
136
  private resolveParamTarget;
137
137
  private inferResponseBody;
138
+ /**
139
+ * The wire representation a request's printed type takes. A route response
140
+ * is serialised as JSON by every sender this layer reads a payload out of,
141
+ * so it prints `toJSON()` results rather than the objects that declare them
142
+ * (carrick#1163). Everything else prints the declared type.
143
+ */
144
+ private wireFormatFor;
145
+ /** An inferred type for a payload read out of response sends. */
146
+ private inferredFromRecoveredPayload;
147
+ /**
148
+ * carrick#1161: type a route response from every send in the handler the
149
+ * locator anchors, rather than from the one send it names.
150
+ *
151
+ * The analyzer reports one response expression per row, and on a handler
152
+ * that guards before it succeeds that is the guard's body. So the located
153
+ * expression selects the HANDLER: the function that contains it, on a row
154
+ * whose line is a route registration. Its returned sends are enumerated
155
+ * (conditional branches split), each is classified by the status it states
156
+ * (`responseSiteStatus`), the error and redirect branches are dropped, and
157
+ * the success bodies are joined exactly as the payload walk joins return
158
+ * statements.
159
+ *
160
+ * Returns `undefined` when this does not apply, which leaves the caller's
161
+ * own reading of the located expression untouched:
162
+ * - the row's line is not a route registration;
163
+ * - the located expression is neither a send nor the argument of one;
164
+ * - that send is not one the handler returns;
165
+ * - it is a success send and the only one that survives, so the join would
166
+ * be the located body anyway;
167
+ * - no joined body is the located one (a text body beside JSON ones).
168
+ *
169
+ * When the located send is an error or redirect branch and no success body
170
+ * survives, the route sends no body a contract can describe: an explicit
171
+ * `unknown` with its reason, so no later locator re-run reads the error body
172
+ * or the redirect location back in.
173
+ */
174
+ private inferFromResponseSites;
175
+ /**
176
+ * True when `candidate` is a response send: a call or `new` whose result is
177
+ * transport machinery (by the extraction config's verified rule or the
178
+ * structural check), or whose callee this handler's own returns prove is a
179
+ * serialiser (`calleesProvenSerialiser`, which holds on a bare checkout).
180
+ */
181
+ private isResponseSend;
182
+ /**
183
+ * The send `node` is an argument of, looking through the wrappers that do
184
+ * not change a payload (parentheses, `as`, `satisfies`, `!`, `await`) and a
185
+ * `JSON.stringify` around the body. `undefined` when the parent call is not
186
+ * a send or `node` is its callee.
187
+ */
188
+ private sendReceivingArgument;
138
189
  private inferCallResult;
139
190
  private inferVariable;
140
191
  private inferExpression;
@@ -524,24 +575,45 @@ export declare class TypeInferrer {
524
575
  */
525
576
  private statesResponseInit;
526
577
  /**
527
- * True when an argument states a >= 400 status: an options object carrying
528
- * `status`/`statusCode`, or a bare status code (`send(body, 404)`).
578
+ * What a response send states about its HTTP status (carrick#1161).
529
579
  *
530
- * Read from the AST first: `{ status: 400 }` in an argument position widens
531
- * to `{ status: number }`, so the literal only survives syntactically. The
532
- * type check behind it catches `as const` and hoisted option objects.
580
+ * Read in order, and the first that states anything decides:
581
+ *
582
+ * 1. an argument past the body that carries a status: a numeric literal
583
+ * (`send(body, 404)`), an options object (`{ status: 401 }`), or any
584
+ * expression whose TYPE is a status literal or a union of them
585
+ * (`let code: 400 | 500`). A numeric argument whose type is a plain
586
+ * `number` states a status the source does not fix, which is
587
+ * `variable`: the branch fails open into the union and is logged.
588
+ * 2. the send call's own RESULT type, when a member of it is typed as a
589
+ * status literal. A framework that types its sends records the status
590
+ * there, and a redirect helper's default `302` is only visible there.
591
+ * A result whose status member spans success and error codes (the
592
+ * default of a typed `json(body, status?)`) says nothing either way.
593
+ *
594
+ * A status in the FIRST argument is a field of the body and is never read.
595
+ * No method or framework name is consulted anywhere.
533
596
  */
534
- private statesErrorStatus;
597
+ private responseSiteStatus;
535
598
  /**
536
- * The HTTP status an argument states, or `undefined`.
599
+ * The HTTP status codes an argument states, `'variable'` when it is a
600
+ * status-shaped value the source does not fix, or `undefined` when it says
601
+ * nothing about a status.
537
602
  *
538
603
  * Read from the AST first: `{ status: 400 }` in an argument position widens
539
604
  * to `{ status: number }`, so the literal only survives syntactically. The
540
- * type check behind it catches `as const` and hoisted option objects. Only
541
- * values in the HTTP range count — an arbitrary number named `status` on a
542
- * domain object (`{ status: 2 }`) states nothing about transport.
605
+ * type read behind it catches `as const`, hoisted option objects and
606
+ * literal-typed variables. Only values in the HTTP range count: an
607
+ * arbitrary number named `status` on a domain object (`{ status: 2 }`)
608
+ * states nothing about transport.
609
+ */
610
+ private statedStatusCodes;
611
+ /**
612
+ * Status codes a send call's result type records: the members (of the
613
+ * result, or of each part of an intersection result) typed as a status
614
+ * literal or a union of them. `undefined` when none is.
543
615
  */
544
- private statedStatusCode;
616
+ private sendResultStatusCodes;
545
617
  /**
546
618
  * Peel the wrappers that do not change an expression's payload: parentheses
547
619
  * and `await`. Unlike `unwrapExpressionNode` this KEEPS `as`/`satisfies`,
@@ -877,6 +949,11 @@ export declare class TypeInferrer {
877
949
  * the route declares its request nowhere we can read.
878
950
  */
879
951
  private requestContractFromRegistration;
952
+ /**
953
+ * An explicit request `InferredType` for a contract the route declares,
954
+ * carrying the provenance the reading recorded.
955
+ */
956
+ private declaredRequestInferredType;
880
957
  /**
881
958
  * The request contract a route DECLARES, in anchor order: the handler's
882
959
  * parameter annotation (a), the registration's schema object (b), then a
@@ -914,8 +991,9 @@ export declare class TypeInferrer {
914
991
  * The shape is a CALL among the registration's arguments whose own arguments
915
992
  * are a request part and a schema value. Neither the middleware's name nor
916
993
  * the schema library is checked: the part is read off the string literal, and
917
- * the schema is whatever exposes a parsed output (`schemaOutputTypeText`) —
918
- * the same test anchor (b) already applies to a `schema: { body: … }` object.
994
+ * the schema is whatever declares its types (`schemaContract`) — the same
995
+ * test anchor (b) already applies to a `schema: { body: … }` object. The
996
+ * contract is the schema's INPUT, what a caller sends (carrick#1101).
919
997
  *
920
998
  * `REQUEST_BODY_PARTS` is HTTP vocabulary for how a body is carried, not a
921
999
  * framework list. A middleware bound to any other part (`query`, `param`,
@@ -923,19 +1001,73 @@ export declare class TypeInferrer {
923
1001
  * at all is not read: publishing a query schema as the request contract would
924
1002
  * be the same confident-and-wrong answer this anchor exists to remove.
925
1003
  */
926
- private validatedBodyContractText;
1004
+ private validatedBodyContract;
1005
+ /**
1006
+ * The values a registration's validator middleware binds to a body part, in
1007
+ * argument order: every non-literal argument of a middleware call that names
1008
+ * a `REQUEST_BODY_PARTS` part. Whether each one IS a schema is the reader's
1009
+ * question (`schemaContract`), not this walk's.
1010
+ */
1011
+ private middlewareBodySchemaValues;
1012
+ /**
1013
+ * The contract of the schema a handler validates an untyped body read with
1014
+ * (carrick#1166), or null.
1015
+ *
1016
+ * `read` is the located expression: the read call, or the binding that holds
1017
+ * it. Every call in the enclosing function that takes that value as an
1018
+ * argument is a candidate, and the schema is the call's receiver
1019
+ * (`Schema.safeParse(body)`) or one of its other arguments
1020
+ * (`parse(Schema, body)`). A candidate counts only when it declares schema
1021
+ * types (`schemaOutputType` / `schemaInputType`), so a logger or a service
1022
+ * call the body is also handed to is never read as a contract. No method or
1023
+ * library name is matched.
1024
+ */
1025
+ private schemaConsumingRead;
1026
+ /**
1027
+ * The part a validated read names when that part is not a body, or
1028
+ * `undefined` (carrick#1166).
1029
+ *
1030
+ * The read is a call whose only argument is a string literal, and the
1031
+ * registration carries a validator middleware binding that same literal.
1032
+ * The part names match through the source's own literal, so no framework
1033
+ * vocabulary is assumed beyond `REQUEST_BODY_PARTS`, which already decides
1034
+ * what a body is for the middleware anchor.
1035
+ */
1036
+ private nonBodyValidatedPart;
1037
+ /**
1038
+ * The request contract behind a VALIDATED READ: a call inside a registered
1039
+ * handler whose type is exactly the parsed output of a body schema the
1040
+ * enclosing registration declares (carrick#1101).
1041
+ *
1042
+ * The read's own type is what validation hands the handler, the schema's
1043
+ * output, so a locator that lands on it would publish the output as the
1044
+ * request. The registration is found by walking the read's ancestors to each
1045
+ * call or registry object whose handler contains the read and which declares
1046
+ * a body schema (anchor (b) or (b2)). The match is on the printed type: only
1047
+ * a read whose structural text equals that schema's output is substituted, so
1048
+ * any other expression in the handler (a query read, a payload of a different
1049
+ * shape) keeps its own type.
1050
+ */
1051
+ private validatedReadRequestContract;
927
1052
  /**
928
1053
  * Anchor (b): the contract declared in the route's validation schema.
929
1054
  *
930
1055
  * `part` is `'body'` for the request contract and `'response'` for the
931
1056
  * response contract; a `response` entry keyed by status code resolves to its
932
- * success entry. Returns null when the registration carries no schema, when
933
- * the entry references something whose parsed output cannot be resolved, or
934
- * when the schema is a plain JSON-schema literal (whose own object type is
935
- * the JSON-Schema document, not the payload — emitting that would be worse
936
- * than abstaining).
1057
+ * success entry. The body reads the schema's input and the response its
1058
+ * output (carrick#1101). Returns null when the registration carries no
1059
+ * schema, when the entry references something whose declared types cannot be
1060
+ * resolved, or when the schema is a plain JSON-schema literal (whose own
1061
+ * object type is the JSON-Schema document, not the payload — emitting that
1062
+ * would be worse than abstaining).
1063
+ */
1064
+ private routeSchemaContract;
1065
+ /**
1066
+ * The value a route `schema` object declares for `part`, as a zero- or
1067
+ * one-element list: the `body` entry itself, or the success entry of a
1068
+ * status-keyed `response` map.
937
1069
  */
938
- private routeSchemaContractText;
1070
+ private routeSchemaEntryValues;
939
1071
  /**
940
1072
  * The `schema` object literal carried by a route registration: scan the
941
1073
  * registration call's arguments (or the registry object literal itself) for a
@@ -950,17 +1082,63 @@ export declare class TypeInferrer {
950
1082
  */
951
1083
  private successStatusEntry;
952
1084
  /**
953
- * The payload type a schema entry declares.
1085
+ * The payload type a schema entry declares, read in `direction`.
954
1086
  *
955
1087
  * The entry is either a REFERENCE call — `ref('CreateWidget')`, a
956
1088
  * name-to-schema indirection whose registry is the argument the ref function
957
- * was built from — or the schema value itself. Either way the payload is the
958
- * schema's parsed output: the return type of its `parse` method (the shape
959
- * every schema value exposes as its public validate-and-return API), falling
960
- * back to a declared `_output` member. A value with neither is not a schema
961
- * and yields null.
962
- */
963
- private schemaOutputTypeText;
1089
+ * was built from — or the schema value itself. A value that declares no type
1090
+ * in either direction is not a schema and yields null.
1091
+ *
1092
+ * `output` is the parsed value (`schemaOutputType`). `input` is what a caller
1093
+ * sends (`schemaInputType`), and a schema that declares no input member reads
1094
+ * its output instead, which is the whole of what is knowable about it.
1095
+ *
1096
+ * The input is decided member by member (carrick#1105). A member whose input
1097
+ * is `any`/`unknown` where the output is concrete is what a coercion declares
1098
+ * (it accepts any value and parses it into, say, a number). A top type in a
1099
+ * published contract disqualifies the whole row downstream, so THAT member
1100
+ * prints its output type, keeps the input key's optionality, and is recorded
1101
+ * as `coerced_input` provenance. Every other member keeps its input, so a
1102
+ * defaulted key beside a coerced one stays optional to send.
1103
+ *
1104
+ * Limits, each logged where it bites:
1105
+ * - the position walk is bounded (`walkTypePositions`), so a top type below
1106
+ * the bound is not compared and prints as the input declares it;
1107
+ * - a coerced position that cannot be substituted (its output is absent or
1108
+ * differs across union branches, or the printer cannot reach it inside a
1109
+ * tuple, behind a cycle or past the expansion depth) makes the row fall
1110
+ * back to the whole parsed output with every coerced member labelled. That
1111
+ * was the answer before the per-member reading, and it never publishes an
1112
+ * `unknown`.
1113
+ */
1114
+ private schemaContract;
1115
+ /**
1116
+ * Print a schema's input with each coerced position replaced by the output's
1117
+ * type at that position (carrick#1105). Null when any position cannot be
1118
+ * substituted: its output is missing or differs across union branches, or
1119
+ * the printer never reached it. A partial substitution would publish an
1120
+ * `unknown`, so it is not an answer.
1121
+ */
1122
+ private inputWithCoercedMembers;
1123
+ /**
1124
+ * Member positions inside `root` that are `any` or `unknown`, keyed by the
1125
+ * member-path notation the provenance entries use (`''` for the root,
1126
+ * `sub.field`, `items<0>` for an array element). Union and intersection
1127
+ * members share their parent's position, so `unknown | undefined` on an
1128
+ * optional key reads as `unknown` there.
1129
+ */
1130
+ private topTypePositions;
1131
+ /**
1132
+ * Visit every member position of `root`, in the notation `topTypePositions`
1133
+ * documents. `visit` returns false to stop descending below a position;
1134
+ * `unionPart` is true when the type is a union or intersection part visited
1135
+ * at its parent's position. Callables are not descended into.
1136
+ *
1137
+ * Bounded and cycle-safe. It only has to tell a schema's input apart from its
1138
+ * output, so a subtree past the bound is not compared, and that is logged:
1139
+ * a coercion below the bound prints as its input declares it.
1140
+ */
1141
+ private walkTypePositions;
964
1142
  /**
965
1143
  * Follow a schema REFERENCE call (`ref('CreateWidget')`) to the schema value
966
1144
  * it names.
@@ -975,12 +1153,31 @@ export declare class TypeInferrer {
975
1153
  private registrySchemaType;
976
1154
  /**
977
1155
  * The parsed output type of a schema value: the return type of its `parse`
978
- * method, else a declared `_output` member. Returns undefined when neither
979
- * carries a usable type — including when the schema library's own types are
1156
+ * method, else a declared `_output` member, else the Standard Schema member
1157
+ * `~standard.types.output` (a library that exposes nothing else). Returns
1158
+ * undefined when none carries a usable type — including when the schema library's own types are
980
1159
  * unavailable (an uninstalled dependency resolves the schema to `any`), which
981
1160
  * must abstain rather than publish `any` as a contract.
982
1161
  */
983
1162
  private schemaOutputType;
1163
+ /**
1164
+ * The input type of a schema value, what a caller may send (carrick#1101):
1165
+ * the Standard Schema member `~standard.types.input`, else a declared
1166
+ * `_input` member. Undefined when the schema declares neither.
1167
+ *
1168
+ * Unlike the output, an input of `unknown` is kept: it is a declared fact
1169
+ * (a coercion accepts any value), and `schemaContract` decides what to
1170
+ * publish for it. An `any` that is really an unresolved library still reads
1171
+ * as no input, because an unresolved schema type has no members to read.
1172
+ */
1173
+ private schemaInputType;
1174
+ /**
1175
+ * `~standard.types.<side>` on a schema value: the Standard Schema
1176
+ * specification's library-neutral statement of a schema's input and output
1177
+ * types. `types` is declared optional, so its `undefined` is stripped before
1178
+ * the side is read.
1179
+ */
1180
+ private standardSchemaType;
984
1181
  /**
985
1182
  * Find a node by matching expression text near a target line.
986
1183
  *