carrick 0.3.133 → 0.3.134

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 (64) hide show
  1. package/dist/contract.d.ts +6 -0
  2. package/dist/contract.js.map +1 -1
  3. package/dist/hook/post-edit.d.ts +10 -5
  4. package/dist/hook/post-edit.js +80 -23
  5. package/dist/hook/post-edit.js.map +1 -1
  6. package/dist/hook/refresh.d.ts +23 -3
  7. package/dist/hook/refresh.js +48 -6
  8. package/dist/hook/refresh.js.map +1 -1
  9. package/dist/hook/reuse.d.ts +7 -21
  10. package/dist/hook/reuse.js +23 -36
  11. package/dist/hook/reuse.js.map +1 -1
  12. package/dist/hook/session-start.js +15 -2
  13. package/dist/hook/session-start.js.map +1 -1
  14. package/dist/hook/stop.js.map +1 -1
  15. package/dist/init/agents-section.js +1 -1
  16. package/dist/init/agents-section.js.map +1 -1
  17. package/dist/init/doctor.js +4 -0
  18. package/dist/init/doctor.js.map +1 -1
  19. package/dist/init/hosted.d.ts +1 -0
  20. package/dist/init/hosted.js +4 -1
  21. package/dist/init/hosted.js.map +1 -1
  22. package/dist/init/remove.js +7 -1
  23. package/dist/init/remove.js.map +1 -1
  24. package/dist/init/repo-copies.js +3 -1
  25. package/dist/init/repo-copies.js.map +1 -1
  26. package/dist/init/run.d.ts +1 -1
  27. package/dist/init/run.js +10 -2
  28. package/dist/init/run.js.map +1 -1
  29. package/dist/init/task-skills.d.ts +22 -1
  30. package/dist/init/task-skills.js +65 -1
  31. package/dist/init/task-skills.js.map +1 -1
  32. package/dist/render.d.ts +41 -16
  33. package/dist/render.js +91 -102
  34. package/dist/render.js.map +1 -1
  35. package/package.json +10 -9
  36. package/plugin/.claude-plugin/plugin.json +1 -1
  37. package/sidecar/dist/src/capture/anchors.js +18 -1
  38. package/sidecar/dist/src/capture/api.d.ts +17 -4
  39. package/sidecar/dist/src/capture/check-workspace.js +1 -1
  40. package/sidecar/dist/src/capture/check.d.ts +44 -0
  41. package/sidecar/dist/src/capture/check.js +112 -10
  42. package/sidecar/dist/src/capture/installed-package.d.ts +5 -0
  43. package/sidecar/dist/src/capture/installed-package.js +64 -6
  44. package/sidecar/dist/src/capture/paths-rewrite.js +3 -3
  45. package/sidecar/dist/src/capture/result-label.d.ts +42 -0
  46. package/sidecar/dist/src/capture/result-label.js +91 -0
  47. package/sidecar/dist/src/capture/self-check.js +13 -2
  48. package/sidecar/dist/src/index.js +116 -4
  49. package/sidecar/dist/src/infer-cache.d.ts +125 -0
  50. package/sidecar/dist/src/infer-cache.js +244 -0
  51. package/sidecar/dist/src/library-claims.js +42 -4
  52. package/sidecar/dist/src/node-index.d.ts +53 -0
  53. package/sidecar/dist/src/node-index.js +100 -0
  54. package/sidecar/dist/src/project-loader.d.ts +11 -0
  55. package/sidecar/dist/src/project-loader.js +15 -0
  56. package/sidecar/dist/src/result-candidates.d.ts +28 -0
  57. package/sidecar/dist/src/result-candidates.js +209 -0
  58. package/sidecar/dist/src/type-inferrer.d.ts +27 -0
  59. package/sidecar/dist/src/type-inferrer.js +175 -43
  60. package/sidecar/dist/src/types.d.ts +52 -0
  61. package/sidecar/dist/src/unwidened.js +10 -1
  62. package/sidecar/dist/src/validators.d.ts +919 -197
  63. package/sidecar/dist/src/validators.js +32 -0
  64. package/templates/skills/carrick-reuse.md +11 -0
@@ -30,6 +30,7 @@ import { readResponseModes } from './response-modes.js';
30
30
  import { functionAtLine } from './function-line-index.js';
31
31
  import { attributedDeclaration, installedPackageOf } from './declaration-attribution.js';
32
32
  import { endLineOf, startLineOf } from './line-index.js';
33
+ import { callsOf, descendantsOf, descendantsOnLine, descendantsOnLines, wrap, } from './node-index.js';
33
34
  import { elapsedMs, inferTiming, phaseClock, timedPhase } from './infer-timing.js';
34
35
  import { StatedParams } from './stated-params.js';
35
36
  import { bindingToleratesAbsence, handlerToleratesAbsentBody } from './absent-body.js';
@@ -933,7 +934,49 @@ export class TypeInferrer {
933
934
  // ===========================================================================
934
935
  // Inference Methods by Kind
935
936
  // ===========================================================================
937
+ /**
938
+ * carrick#2824: a located response expression that sits in ANOTHER route's
939
+ * handler is not this row's. A model can locate `response` at a line that
940
+ * belongs to the next registration in the same module; reading that node
941
+ * publishes the other route's reply. Returns the request with its locator
942
+ * dropped, so it is answered by the registration on its own line, when:
943
+ * 1. a registration R sits on the request's line;
944
+ * 2. the located node is outside R and outside R's handler;
945
+ * 3. some ancestor of the node is a registration whose handler contains it.
946
+ * Anything else is returned unchanged. Matches on node shape, no names.
947
+ */
948
+ withoutForeignLocator(sourceFile, request) {
949
+ const node = this.resolveTargetNode(sourceFile, request);
950
+ if (!node)
951
+ return request;
952
+ const atLine = this.registrationAtLine(sourceFile, request.line_number);
953
+ if (!atLine)
954
+ return request;
955
+ const within = (inner, outer) => inner.getPos() >= outer.getPos() && inner.getEnd() <= outer.getEnd();
956
+ if (within(node, atLine.registration) || within(node, atLine.handler)) {
957
+ return request;
958
+ }
959
+ const inOtherHandler = node.getAncestors().some((ancestor) => {
960
+ if (!Node.isCallExpression(ancestor) && !Node.isObjectLiteralExpression(ancestor)) {
961
+ return false;
962
+ }
963
+ const handler = this.resolveRegisteredHandler(ancestor);
964
+ return handler !== undefined && within(node, handler);
965
+ });
966
+ if (!inOtherHandler)
967
+ return request;
968
+ this.log(`Located expression at ${request.file_path}:${request.expression_line ?? request.line_number} ` +
969
+ `sits in another registration's handler; answering by the registration on line ${request.line_number}`);
970
+ return {
971
+ ...request,
972
+ span_start: undefined,
973
+ span_end: undefined,
974
+ expression_text: undefined,
975
+ expression_line: undefined,
976
+ };
977
+ }
936
978
  inferFunctionReturn(sourceFile, request, extractionConfig) {
979
+ request = this.withoutForeignLocator(sourceFile, request);
937
980
  // A `function_return` request can point at a route REGISTRATION: that is
938
981
  // the shape the scanner sends for a route whose handler RETURNS its
939
982
  // payload. The containing-function walk below then resolves the function
@@ -948,6 +991,16 @@ export class TypeInferrer {
948
991
  }
949
992
  const func = this.resolveContainingFunction(sourceFile, request);
950
993
  if (!func) {
994
+ // carrick#807: a file route exported as a call to a route builder
995
+ // (`export const x = builder(options, async () => ...)`) starts no
996
+ // function at its line; the handler follows the options object. Where a
997
+ // registration sits on the line, read the handler it hands in, as the
998
+ // line-only `response_body` path does.
999
+ const atLine = this.registrationAtLine(sourceFile, request.line_number);
1000
+ if (atLine) {
1001
+ this.log(`Line ${request.line_number} is a route registration; following handler return`);
1002
+ return this.buildFunctionReturnInferredType(request, atLine.handler, extractionConfig, true);
1003
+ }
951
1004
  this.log(`No function found for request at ${request.file_path}:${request.line_number}`);
952
1005
  return null;
953
1006
  }
@@ -1263,6 +1316,7 @@ export class TypeInferrer {
1263
1316
  return undefined;
1264
1317
  }
1265
1318
  inferResponseBody(sourceFile, request, extractionConfig) {
1319
+ request = this.withoutForeignLocator(sourceFile, request);
1266
1320
  const node = this.resolveTargetNode(sourceFile, request);
1267
1321
  if (!node) {
1268
1322
  // Line-only anchor (no span, no expression text) — the shape the scanner
@@ -1998,6 +2052,78 @@ export class TypeInferrer {
1998
2052
  return undefined;
1999
2053
  return accept(parent) ? parent : undefined;
2000
2054
  }
2055
+ /**
2056
+ * A call's result read through the library store's label (carrick#2818):
2057
+ * `whole` is the awaited type, `member` is that member of every non-nullish
2058
+ * constituent of it, and `parse` is the awaited return of that method as the
2059
+ * call returns it (a thenable's own `json()` is not on what it resolves to).
2060
+ * A part the type lacks is a decided abstain, so the capture's own re-read
2061
+ * of the raw call does not publish the envelope in its place.
2062
+ */
2063
+ labelledCallResult(request, callExpr, label) {
2064
+ const location = this.getNodeLocation(callExpr);
2065
+ const raw = callExpr.getType();
2066
+ const awaited = this.awaitedBeyondPromise(raw) ?? this.unwrapPromiseType(raw);
2067
+ const missing = (what) => this.decidedAbstain(request, location, {
2068
+ path: '',
2069
+ kind: 'unknown',
2070
+ reason: 'result_member_missing',
2071
+ detail: `the library's label names ${what}, which this call's type does not have`,
2072
+ });
2073
+ let read;
2074
+ if ('whole' in label) {
2075
+ read = [awaited];
2076
+ }
2077
+ else if ('member' in label) {
2078
+ const name = label.member[0];
2079
+ read = [];
2080
+ const constituents = awaited.isUnion() ? awaited.getUnionTypes() : [awaited];
2081
+ for (const constituent of constituents) {
2082
+ if (isNullishType(constituent))
2083
+ continue;
2084
+ const held = this.readMemberType(constituent, name, callExpr);
2085
+ if (!held)
2086
+ return missing(`the member '${name}'`);
2087
+ for (const part of held.isUnion() ? held.getUnionTypes() : [held]) {
2088
+ if (!isNullishType(part))
2089
+ read.push(part);
2090
+ }
2091
+ }
2092
+ if (read.length === 0)
2093
+ return missing(`the member '${name}'`);
2094
+ }
2095
+ else {
2096
+ const method = (this.readMemberType(raw, label.parse, callExpr) ??
2097
+ this.readMemberType(awaited, label.parse, callExpr));
2098
+ const signature = method
2099
+ ?.getCallSignatures()
2100
+ .find((candidate) => candidate.getParameters().every((parameter) => {
2101
+ const declaration = parameter.getDeclarations()[0];
2102
+ return (!!declaration &&
2103
+ Node.isParameterDeclaration(declaration) &&
2104
+ (declaration.hasQuestionToken() ||
2105
+ declaration.hasInitializer() ||
2106
+ declaration.isRestParameter()));
2107
+ }));
2108
+ if (!signature)
2109
+ return missing(`the method '${label.parse}'`);
2110
+ const returned = signature.getReturnType();
2111
+ const parsed = this.awaitedBeyondPromise(returned) ?? this.unwrapPromiseType(returned);
2112
+ // A type parameter of the method that nothing at the call instantiates
2113
+ // (`json<J>()`) states no type: the caller supplies it.
2114
+ if (parsed.isTypeParameter())
2115
+ return missing(`a concrete type from '${label.parse}'`);
2116
+ read = [parsed];
2117
+ }
2118
+ const texts = [];
2119
+ for (const part of read) {
2120
+ const text = this.structuralTextFromType(part, callExpr) ?? typeText(part, callExpr);
2121
+ if (!texts.includes(text))
2122
+ texts.push(text);
2123
+ }
2124
+ const anchor = read.length === 1 ? this.unwrapArrayLevels(this.unwrapPromiseType(read[0])) : undefined;
2125
+ return this.createInferredType(request, texts.join(' | '), false, location, undefined, anchor ? this.primaryTypeSymbol(anchor.element) : undefined, anchor?.depth, anchor ? this.primaryTypeSymbolSource(anchor.element) : undefined);
2126
+ }
2001
2127
  inferCallResult(sourceFile, request, extractionConfig) {
2002
2128
  const callExpr = this.resolveTargetCallExpression(sourceFile, request);
2003
2129
  // A call's result is read off the call. A locator that finds no call names
@@ -2007,6 +2133,12 @@ export class TypeInferrer {
2007
2133
  this.log(`Call-result locator at ${request.file_path}:${request.line_number} finds no call; leaving unresolved`);
2008
2134
  return null;
2009
2135
  }
2136
+ // carrick#2818: the library store labels which part of this call's result
2137
+ // holds the response body. The label is the library's own statement, so it
2138
+ // is read before any wrapper rule of the service's extraction config.
2139
+ if (request.result) {
2140
+ return this.labelledCallResult(request, callExpr, request.result);
2141
+ }
2010
2142
  // Walk up from the already-found call expression instead of re-searching
2011
2143
  const func = this.findContainingFunctionForNode(callExpr);
2012
2144
  const use = this.resolveCallResultTerminalNode(callExpr, func);
@@ -4624,6 +4756,14 @@ export class TypeInferrer {
4624
4756
  }
4625
4757
  return readings;
4626
4758
  }
4759
+ /**
4760
+ * The type of `type`'s member `name` at `node`, or `undefined` when the type
4761
+ * has no such member. The one property read the payload-property rules and
4762
+ * the library store's result label (carrick#2818) share.
4763
+ */
4764
+ readMemberType(type, name, node) {
4765
+ return type.getProperty(name)?.getTypeAtLocation(node);
4766
+ }
4627
4767
  /**
4628
4768
  * Extract the payload type from a matched wrapper. Returns null when the
4629
4769
  * rule matched the wrapper but no payload is recoverable from generics or
@@ -4696,11 +4836,10 @@ export class TypeInferrer {
4696
4836
  if (rule.payloadPropertyPath && rule.payloadPropertyPath.length > 0) {
4697
4837
  let currentType = type;
4698
4838
  for (const propName of rule.payloadPropertyPath) {
4699
- const prop = currentType.getProperty(propName);
4700
- if (!prop) {
4839
+ const propType = this.readMemberType(currentType, propName, node);
4840
+ if (!propType) {
4701
4841
  break;
4702
4842
  }
4703
- const propType = prop.getTypeAtLocation(node);
4704
4843
  currentType = propType;
4705
4844
  }
4706
4845
  if (currentType !== type) {
@@ -6730,10 +6869,10 @@ export class TypeInferrer {
6730
6869
  * registration node itself, so the schema anchors need both halves.
6731
6870
  */
6732
6871
  registrationAtLine(sourceFile, line) {
6733
- for (const node of sourceFile.getDescendants()) {
6734
- if ((Node.isCallExpression(node) ||
6735
- Node.isObjectLiteralExpression(node)) &&
6736
- startLineOf(node) === line) {
6872
+ for (const entry of descendantsOnLine(sourceFile, line)) {
6873
+ if (entry.kind === SyntaxKind.CallExpression ||
6874
+ entry.kind === SyntaxKind.ObjectLiteralExpression) {
6875
+ const node = wrap(sourceFile, entry);
6737
6876
  const handler = this.resolveRegisteredHandler(node);
6738
6877
  if (handler) {
6739
6878
  return { registration: node, handler };
@@ -9307,20 +9446,23 @@ export class TypeInferrer {
9307
9446
  * 5. Return smallest matching node closest to target line
9308
9447
  */
9309
9448
  findNodeByText(sourceFile, expressionText, lineNumber, searchRadius = 5) {
9310
- const allNodes = sourceFile.getDescendants().filter((node) => {
9311
- if (Node.isSourceFile(node))
9312
- return false;
9313
- if (node.getKind() === SyntaxKind.SyntaxList)
9314
- return false;
9315
- return true;
9316
- });
9317
- return this.matchByText(allNodes, expressionText, lineNumber, searchRadius);
9449
+ // Only the window's nodes are wrapped: `matchByText` keeps no other.
9450
+ const inWindow = lineNumber
9451
+ ? descendantsOnLines(sourceFile, lineNumber - searchRadius, lineNumber + searchRadius)
9452
+ : descendantsOf(sourceFile);
9453
+ const nodes = inWindow
9454
+ .filter((entry) => entry.kind !== SyntaxKind.SyntaxList)
9455
+ .map((entry) => wrap(sourceFile, entry));
9456
+ return this.matchByText(nodes, expressionText, lineNumber, searchRadius);
9318
9457
  }
9319
9458
  /**
9320
9459
  * Find a CallExpression by matching expression text near a target line.
9321
9460
  */
9322
9461
  findCallExpressionByText(sourceFile, expressionText, lineNumber, searchRadius = 5) {
9323
- const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
9462
+ const inWindow = lineNumber
9463
+ ? callsOf(sourceFile).filter((entry) => entry.line >= lineNumber - searchRadius && entry.line <= lineNumber + searchRadius)
9464
+ : callsOf(sourceFile);
9465
+ const callExpressions = inWindow.map((entry) => wrap(sourceFile, entry));
9324
9466
  return this.matchByText(callExpressions, expressionText, lineNumber, searchRadius);
9325
9467
  }
9326
9468
  /**
@@ -9606,23 +9748,15 @@ export class TypeInferrer {
9606
9748
  });
9607
9749
  }
9608
9750
  findNodeAtSpan(sourceFile, spanStart, spanEnd) {
9609
- const allNodes = sourceFile.getDescendants();
9610
- const containing = allNodes.filter((node) => {
9611
- if (Node.isSourceFile(node))
9612
- return false;
9613
- // Skip SyntaxList nodes as they have unreliable types
9614
- if (node.getKind() === SyntaxKind.SyntaxList)
9615
- return false;
9616
- const start = node.getStart();
9617
- const end = node.getEnd();
9618
- return start <= spanStart && spanEnd <= end;
9619
- });
9751
+ const containing = descendantsOf(sourceFile).filter(
9752
+ // Skip SyntaxList nodes as they have unreliable types
9753
+ (entry) => entry.kind !== SyntaxKind.SyntaxList && entry.start <= spanStart && spanEnd <= entry.end);
9620
9754
  if (containing.length === 0) {
9621
9755
  return undefined;
9622
9756
  }
9623
- return containing.reduce((best, current) => {
9624
- const bestRange = best.getEnd() - best.getStart();
9625
- const currentRange = current.getEnd() - current.getStart();
9757
+ const best = containing.reduce((best, current) => {
9758
+ const bestRange = best.end - best.start;
9759
+ const currentRange = current.end - current.start;
9626
9760
  // Prefer exact matches, then smallest containing
9627
9761
  const bestDelta = Math.abs(bestRange - (spanEnd - spanStart));
9628
9762
  const currentDelta = Math.abs(currentRange - (spanEnd - spanStart));
@@ -9635,10 +9769,9 @@ export class TypeInferrer {
9635
9769
  // span published `any` as its request body. Descendants follow their
9636
9770
  // ancestors in `getDescendants()` order, so a tied later node inside the
9637
9771
  // current best is the deeper one.
9638
- return current.getStart() >= best.getStart() && current.getEnd() <= best.getEnd()
9639
- ? current
9640
- : best;
9772
+ return current.start >= best.start && current.end <= best.end ? current : best;
9641
9773
  });
9774
+ return wrap(sourceFile, best);
9642
9775
  }
9643
9776
  findCallExpressionAtSpan(sourceFile, spanStart, spanEnd) {
9644
9777
  // Tolerate the SWC span convention (#336): the scanner sends raw SWC
@@ -9658,23 +9791,18 @@ export class TypeInferrer {
9658
9791
  // more and the slack only widens the candidate set. Removing it is
9659
9792
  // carrick#823, which wants its own before/after.
9660
9793
  const SPAN_SLACK = 2;
9661
- const callExpressions = sourceFile
9662
- .getDescendantsOfKind(SyntaxKind.CallExpression);
9663
- const candidates = callExpressions.filter((expr) => {
9664
- const start = expr.getStart();
9665
- const end = expr.getEnd();
9666
- return start - SPAN_SLACK <= spanStart && spanEnd <= end + SPAN_SLACK;
9667
- });
9794
+ const candidates = callsOf(sourceFile).filter((entry) => entry.start - SPAN_SLACK <= spanStart && spanEnd <= entry.end + SPAN_SLACK);
9668
9795
  if (candidates.length === 0) {
9669
9796
  return undefined;
9670
9797
  }
9671
- return candidates.reduce((best, current) => {
9672
- const bestRange = best.getEnd() - best.getStart();
9673
- const currentRange = current.getEnd() - current.getStart();
9798
+ const best = candidates.reduce((best, current) => {
9799
+ const bestRange = best.end - best.start;
9800
+ const currentRange = current.end - current.start;
9674
9801
  const bestDelta = Math.abs(bestRange - (spanEnd - spanStart));
9675
9802
  const currentDelta = Math.abs(currentRange - (spanEnd - spanStart));
9676
9803
  return currentDelta < bestDelta ? current : best;
9677
9804
  });
9805
+ return wrap(sourceFile, best);
9678
9806
  }
9679
9807
  // ===========================================================================
9680
9808
  // Type Utilities
@@ -9845,3 +9973,7 @@ function nodeAtSpan(span) {
9845
9973
  }
9846
9974
  return node;
9847
9975
  }
9976
+ /** `undefined`, `null` and `void`: what a labelled read removes (carrick#2818). */
9977
+ function isNullishType(type) {
9978
+ return type.isUndefined() || type.isNull() || type.getText() === 'void';
9979
+ }
@@ -3,6 +3,7 @@
3
3
  * These types define the JSON messages exchanged between Rust and the Node.js sidecar
4
4
  */
5
5
  import type { ResponseModes } from './response-modes.js';
6
+ import type { ResultLabel } from './capture/api.js';
6
7
  /**
7
8
  * The kind of type inference to perform
8
9
  */
@@ -543,6 +544,8 @@ export type LibraryClaim = {
543
544
  key_labels?: Record<string, KeyLabel>;
544
545
  name_scope?: NameScope;
545
546
  picker?: string;
547
+ /** Which part of what the maker returns holds the value its function resolves to; read by a `result` claim, never by this one. */
548
+ result?: ResultShape;
546
549
  } | {
547
550
  /** A member that returns a receiver bound to a name (a channel, room or queue). */
548
551
  kind: 'scope';
@@ -603,6 +606,23 @@ export type LibraryClaim = {
603
606
  yields?: Yields;
604
607
  /** Route fields (#2474 R0), `receive` only: where the handler's request holds its path and method. */
605
608
  request?: RequestAt;
609
+ /** Which part of what the call returns holds the response; read by a `result` claim, never by this one. */
610
+ result?: ResultShape;
611
+ } | {
612
+ /**
613
+ * Which part of what a call returns holds the response body, judged over
614
+ * every overload of `member` (after `path`) on the receiver; `member`
615
+ * null is the receiver itself called (carrick#2817). `form` says whether
616
+ * the call is a maker's or an op's.
617
+ */
618
+ kind: 'result';
619
+ form: 'make' | 'op';
620
+ member: string | null;
621
+ path?: string[];
622
+ on?: ClaimOn;
623
+ of?: string;
624
+ picker?: string;
625
+ result: ResultShape;
606
626
  } | {
607
627
  /** A name the library emits itself, spelled in one of `member`'s parameters. */
608
628
  kind: 'reserved';
@@ -713,6 +733,11 @@ export interface InferRequestItem {
713
733
  param_name?: string;
714
734
  /** The member of a request options literal that carries the body (`request_config`). */
715
735
  member?: string;
736
+ /**
737
+ * carrick#2818: the library store's label for the call's result, naming the
738
+ * part that holds the response body. Read for `call_result`.
739
+ */
740
+ result?: ResultLabel;
716
741
  }
717
742
  /**
718
743
  * Response status
@@ -1005,7 +1030,34 @@ export interface SurfaceKey {
1005
1030
  export interface SurfaceSignature {
1006
1031
  params: SurfaceParam[];
1007
1032
  returns: string;
1033
+ /**
1034
+ * Which parts of the awaited return could hold the response body
1035
+ * (carrick#2817). Left out of the surface hash. Absent when the signature
1036
+ * returns nothing.
1037
+ */
1038
+ result_candidates?: SurfaceResultCandidates;
1008
1039
  }
1040
+ /** What a signature's return offers as its result, by rule R (`result-candidates.ts`). */
1041
+ export interface SurfaceResultCandidates {
1042
+ /** The caller supplies the whole return as a type argument: `whole` is the only candidate. */
1043
+ whole_decided: boolean;
1044
+ /** Properties that carry a type parameter of the signature, sorted. */
1045
+ members: string[];
1046
+ /** Methods with no required argument that return a bare type parameter of their own, sorted. */
1047
+ parse: string[];
1048
+ }
1049
+ /**
1050
+ * Which part of what a call returns holds the response the server sent:
1051
+ * exactly one of the whole awaited return, one member of it, or the awaited
1052
+ * return of one of its parse methods (carrick#2817).
1053
+ */
1054
+ export type ResultShape = {
1055
+ whole: true;
1056
+ } | {
1057
+ member: [string];
1058
+ } | {
1059
+ parse: string;
1060
+ };
1009
1061
  export interface SurfaceMember {
1010
1062
  name: string;
1011
1063
  /** Declared by the receiver's home packages (not only inherited from another package). */
@@ -303,12 +303,21 @@ export function mapBack(pos, insertions) {
303
303
  }
304
304
  return pos - shift;
305
305
  }
306
+ /**
307
+ * Diagnostics about how the program was assembled (a file outside `rootDir`,
308
+ * a file missing from a composite project's list, an output that would
309
+ * overwrite its input), not about the text of the file they are reported on.
310
+ * The compiler attaches them to an import or a root file, and whether one is
311
+ * present depends on which program build ran last, so a before/after
312
+ * comparison would read it as added by a rewrite (carrick#2898).
313
+ */
314
+ const PROGRAM_ASSEMBLY_CODES = new Set([6059, 6305, 6307]);
306
315
  /** Syntactic and semantic diagnostics reported in this file. */
307
316
  export function fileDiagnostics(sourceFile) {
308
317
  const program = sourceFile.getProject().getProgram().compilerObject;
309
318
  const node = sourceFile.compilerNode;
310
319
  return [...program.getSyntacticDiagnostics(node), ...program.getSemanticDiagnostics(node)]
311
- .filter((d) => d.file === node && d.start !== undefined)
320
+ .filter((d) => d.file === node && d.start !== undefined && !PROGRAM_ASSEMBLY_CODES.has(d.code))
312
321
  .map((d) => ({
313
322
  start: d.start,
314
323
  code: d.code,