@suss/adapter-typescript 0.22.2 → 0.22.3

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 (3) hide show
  1. package/dist/index.cjs +270 -247
  2. package/dist/index.js +266 -243
  3. package/package.json +6 -6
package/dist/index.cjs CHANGED
@@ -4658,6 +4658,26 @@ function resolveImportedLocalName(sourceFile, importModule, importName) {
4658
4658
  }
4659
4659
  return null;
4660
4660
  }
4661
+ function importedReferenceSpellings(sourceFile, importModule, importName) {
4662
+ const spellings = [];
4663
+ const localName = resolveImportedLocalName(
4664
+ sourceFile,
4665
+ importModule,
4666
+ importName
4667
+ );
4668
+ if (localName !== null) {
4669
+ spellings.push(localName);
4670
+ }
4671
+ if (!sourceFile.getFullText().includes(`.${importName}`)) {
4672
+ return spellings;
4673
+ }
4674
+ for (const root of importedRootsOf(sourceFile, [importModule])) {
4675
+ if (root !== importName) {
4676
+ spellings.push(`${root}.${importName}`);
4677
+ }
4678
+ }
4679
+ return spellings;
4680
+ }
4661
4681
 
4662
4682
  // src/discovery/resolveValue.ts
4663
4683
  var import_ts_morph19 = require("ts-morph");
@@ -8081,13 +8101,13 @@ function collectMethodsCalledOnCallResults(sourceFile) {
8081
8101
  return called;
8082
8102
  }
8083
8103
  function registrationSubjectsOf(sourceFile, importModule, importName, resolution) {
8084
- const importedLocalName = resolveImportedLocalName(
8104
+ const spellings = importedReferenceSpellings(
8085
8105
  sourceFile,
8086
8106
  importModule,
8087
8107
  importName
8088
8108
  );
8089
8109
  const subjects = /* @__PURE__ */ new Map();
8090
- if (importedLocalName === null) {
8110
+ if (spellings.length === 0) {
8091
8111
  return subjects;
8092
8112
  }
8093
8113
  sourceFile.forEachDescendant((node) => {
@@ -8097,7 +8117,7 @@ function registrationSubjectsOf(sourceFile, importModule, importName, resolution
8097
8117
  return;
8098
8118
  }
8099
8119
  const calleeText = import_ts_morph34.Node.isCallExpression(init) || import_ts_morph34.Node.isNewExpression(init) ? init.getExpression().getText() : null;
8100
- if (calleeText === importedLocalName) {
8120
+ if (calleeText !== null && spellings.includes(calleeText)) {
8101
8121
  subjects.set(node.getName(), init);
8102
8122
  }
8103
8123
  return;
@@ -8110,7 +8130,9 @@ function registrationSubjectsOf(sourceFile, importModule, importName, resolution
8110
8130
  return;
8111
8131
  }
8112
8132
  const typeText = typeNode.getText();
8113
- if (typeText === importedLocalName || typeText.startsWith(`${importedLocalName}<`)) {
8133
+ if (spellings.some(
8134
+ (spelling) => typeText === spelling || typeText.startsWith(`${spelling}<`)
8135
+ )) {
8114
8136
  subjects.set(node.getName(), creationSiteBehind(node, resolution));
8115
8137
  }
8116
8138
  });
@@ -8154,17 +8176,17 @@ function registrationSubjectIdsOf(sourceFile, matches, resolution) {
8154
8176
  return ids;
8155
8177
  }
8156
8178
  function unboundConstructionsOf(sourceFile, importModule, importName) {
8157
- const importedLocalName = resolveImportedLocalName(
8179
+ const spellings = importedReferenceSpellings(
8158
8180
  sourceFile,
8159
8181
  importModule,
8160
8182
  importName
8161
8183
  );
8162
- if (importedLocalName === null) {
8184
+ if (spellings.length === 0) {
8163
8185
  return [];
8164
8186
  }
8165
8187
  const constructions = [];
8166
8188
  sourceFile.forEachDescendant((node) => {
8167
- if ((import_ts_morph34.Node.isCallExpression(node) || import_ts_morph34.Node.isNewExpression(node)) && node.getExpression().getText() === importedLocalName && !import_ts_morph34.Node.isVariableDeclaration(node.getParent())) {
8189
+ if ((import_ts_morph34.Node.isCallExpression(node) || import_ts_morph34.Node.isNewExpression(node)) && spellings.includes(node.getExpression().getText()) && !import_ts_morph34.Node.isVariableDeclaration(node.getParent())) {
8168
8190
  constructions.push(node);
8169
8191
  }
8170
8192
  });
@@ -10195,199 +10217,12 @@ function tryMatchParameterCall(node, func, pattern, match) {
10195
10217
  return { node, terminal };
10196
10218
  }
10197
10219
 
10198
- // src/terminals/jsx.ts
10199
- var import_ts_morph46 = require("ts-morph");
10200
- function tryMatchJsxReturn(node, pattern) {
10201
- let expr;
10202
- let source;
10203
- if (import_ts_morph46.Node.isReturnStatement(node)) {
10204
- expr = node.getExpression();
10205
- source = node;
10206
- } else if (import_ts_morph46.Node.isArrowFunction(node)) {
10207
- const body = node.getBody();
10208
- if (body !== void 0 && !import_ts_morph46.Node.isBlock(body)) {
10209
- expr = body;
10210
- source = body;
10211
- }
10212
- }
10213
- if (expr === void 0 || source === void 0) {
10214
- return null;
10215
- }
10216
- const tree = jsxToRenderNode(expr);
10217
- if (tree === null) {
10218
- return null;
10219
- }
10220
- const component = tree.type === "element" ? tree.tag : "Fragment";
10221
- const terminal = {
10222
- kind: pattern.kind,
10223
- statusCode: null,
10224
- body: null,
10225
- exceptionType: null,
10226
- message: null,
10227
- component,
10228
- delegateTarget: null,
10229
- emitEvent: null,
10230
- renderTree: tree,
10231
- location: {
10232
- start: startLineOf(node),
10233
- end: endLineOf(node)
10234
- }
10235
- };
10236
- return { node, source, terminal };
10237
- }
10238
- function componentTargetOf(tagNode) {
10239
- if (!import_ts_morph46.Node.isIdentifier(tagNode) || !/^[A-Z]/.test(tagNode.getText())) {
10240
- return null;
10241
- }
10242
- const target = functionTargetOf(tagNode);
10243
- return target === null ? null : { file: target.file, name: target.name };
10244
- }
10245
- function jsxToRenderNode(node) {
10246
- if (import_ts_morph46.Node.isJsxElement(node)) {
10247
- const opening = node.getOpeningElement();
10248
- const tag = opening.getTagNameNode().getText();
10249
- const attrs = collectJsxAttributes(opening);
10250
- const target = componentTargetOf(opening.getTagNameNode());
10251
- const children = node.getJsxChildren().map(jsxChildToRenderNode).filter((n) => n !== null);
10252
- return {
10253
- type: "element",
10254
- tag,
10255
- children,
10256
- ...attrs !== null ? { attrs } : {},
10257
- ...target !== null ? { target } : {}
10258
- };
10259
- }
10260
- if (import_ts_morph46.Node.isJsxSelfClosingElement(node)) {
10261
- const tag = node.getTagNameNode().getText();
10262
- const attrs = collectJsxAttributes(node);
10263
- const target = componentTargetOf(node.getTagNameNode());
10264
- return {
10265
- type: "element",
10266
- tag,
10267
- children: [],
10268
- ...attrs !== null ? { attrs } : {},
10269
- ...target !== null ? { target } : {}
10270
- };
10271
- }
10272
- if (import_ts_morph46.Node.isJsxFragment(node)) {
10273
- const children = node.getJsxChildren().map(jsxChildToRenderNode).filter((n) => n !== null);
10274
- return { type: "element", tag: "Fragment", children };
10275
- }
10276
- if (import_ts_morph46.Node.isParenthesizedExpression(node)) {
10277
- return jsxToRenderNode(node.getExpression());
10278
- }
10279
- return null;
10280
- }
10281
- function collectJsxAttributes(opening) {
10282
- const entries = {};
10283
- for (const attr of opening.getAttributes()) {
10284
- if (import_ts_morph46.Node.isJsxSpreadAttribute(attr)) {
10285
- const exprText = attr.getExpression().getText();
10286
- entries[`...${exprText}`] = exprText;
10287
- continue;
10288
- }
10289
- if (!import_ts_morph46.Node.isJsxAttribute(attr)) {
10290
- continue;
10291
- }
10292
- const name = attr.getNameNode().getText();
10293
- const initializer = attr.getInitializer();
10294
- if (initializer === void 0) {
10295
- entries[name] = "";
10296
- continue;
10297
- }
10298
- if (import_ts_morph46.Node.isJsxExpression(initializer)) {
10299
- const inner = initializer.getExpression();
10300
- entries[name] = inner !== void 0 ? inner.getText() : "";
10301
- continue;
10302
- }
10303
- entries[name] = initializer.getText();
10304
- }
10305
- return Object.keys(entries).length > 0 ? entries : null;
10306
- }
10307
- function jsxChildToRenderNode(child) {
10308
- if (import_ts_morph46.Node.isJsxText(child)) {
10309
- const text = child.getLiteralText().trim();
10310
- if (text.length === 0) {
10311
- return null;
10312
- }
10313
- return { type: "text", value: text };
10314
- }
10315
- if (import_ts_morph46.Node.isJsxExpression(child)) {
10316
- const inner = child.getExpression();
10317
- if (inner === void 0) {
10318
- return null;
10319
- }
10320
- return jsxExpressionToRenderNode(inner);
10321
- }
10322
- if (import_ts_morph46.Node.isJsxElement(child) || import_ts_morph46.Node.isJsxSelfClosingElement(child) || import_ts_morph46.Node.isJsxFragment(child)) {
10323
- return jsxToRenderNode(child);
10324
- }
10325
- return null;
10326
- }
10327
- function jsxExpressionToRenderNode(expr) {
10328
- if (import_ts_morph46.Node.isParenthesizedExpression(expr)) {
10329
- return jsxExpressionToRenderNode(expr.getExpression());
10330
- }
10331
- if (import_ts_morph46.Node.isBinaryExpression(expr)) {
10332
- const op = expr.getOperatorToken().getText();
10333
- if (op === "&&") {
10334
- const right = renderAlternative(peelParens(expr.getRight()));
10335
- if (right.kind === "jsx") {
10336
- return {
10337
- type: "conditional",
10338
- condition: expr.getLeft().getText(),
10339
- whenTrue: right.node,
10340
- whenFalse: null
10341
- };
10342
- }
10343
- }
10344
- }
10345
- if (import_ts_morph46.Node.isConditionalExpression(expr)) {
10346
- const truthy = renderAlternative(peelParens(expr.getWhenTrue()));
10347
- const falsy = renderAlternative(peelParens(expr.getWhenFalse()));
10348
- if (truthy.kind === "jsx") {
10349
- return {
10350
- type: "conditional",
10351
- condition: expr.getCondition().getText(),
10352
- whenTrue: truthy.node,
10353
- whenFalse: falsy.kind === "jsx" ? falsy.node : null
10354
- };
10355
- }
10356
- if (falsy.kind === "jsx") {
10357
- return {
10358
- type: "conditional",
10359
- condition: `!(${expr.getCondition().getText()})`,
10360
- whenTrue: falsy.node,
10361
- whenFalse: null
10362
- };
10363
- }
10364
- }
10365
- return { type: "expression", sourceText: expr.getText() };
10366
- }
10367
- function renderAlternative(node) {
10368
- if (import_ts_morph46.Node.isNullLiteral(node)) {
10369
- return { kind: "noRender" };
10370
- }
10371
- if (import_ts_morph46.Node.isFalseLiteral(node)) {
10372
- return { kind: "noRender" };
10373
- }
10374
- if (import_ts_morph46.Node.isIdentifier(node) && node.getText() === "undefined") {
10375
- return { kind: "noRender" };
10376
- }
10377
- if (import_ts_morph46.Node.isJsxElement(node) || import_ts_morph46.Node.isJsxSelfClosingElement(node) || import_ts_morph46.Node.isJsxFragment(node)) {
10378
- const tree = jsxToRenderNode(node);
10379
- if (tree !== null) {
10380
- return { kind: "jsx", node: tree };
10381
- }
10382
- }
10383
- return { kind: "notStatic" };
10384
- }
10385
-
10386
- // src/terminals/returns.ts
10387
- var import_ts_morph51 = require("ts-morph");
10220
+ // src/terminals/extract.ts
10221
+ var import_ts_morph47 = require("ts-morph");
10222
+ var import_values5 = require("@suss/values");
10388
10223
 
10389
10224
  // src/shapes/shapes.ts
10390
- var import_ts_morph47 = require("ts-morph");
10225
+ var import_ts_morph46 = require("ts-morph");
10391
10226
 
10392
10227
  // src/shapes/typeShapes.ts
10393
10228
  var import_node_crypto = require("crypto");
@@ -10846,60 +10681,60 @@ function extractShapeWithArguments(node, substitutions) {
10846
10681
  }
10847
10682
  function extractShapeInner(node) {
10848
10683
  const unwrapped2 = peelSyntax(node);
10849
- if (boundArguments !== null && import_ts_morph47.Node.isIdentifier(unwrapped2)) {
10684
+ if (boundArguments !== null && import_ts_morph46.Node.isIdentifier(unwrapped2)) {
10850
10685
  const argument = boundArguments.get(unwrapped2.getText());
10851
10686
  if (argument !== void 0 && argument !== unwrapped2) {
10852
10687
  return extractShape(argument);
10853
10688
  }
10854
10689
  }
10855
- if (import_ts_morph47.Node.isObjectLiteralExpression(unwrapped2)) {
10690
+ if (import_ts_morph46.Node.isObjectLiteralExpression(unwrapped2)) {
10856
10691
  return shapeFromObjectLiteral(unwrapped2);
10857
10692
  }
10858
- if (import_ts_morph47.Node.isArrayLiteralExpression(unwrapped2)) {
10693
+ if (import_ts_morph46.Node.isArrayLiteralExpression(unwrapped2)) {
10859
10694
  return shapeFromArrayLiteral(unwrapped2);
10860
10695
  }
10861
- if (import_ts_morph47.Node.isStringLiteral(unwrapped2) || import_ts_morph47.Node.isNoSubstitutionTemplateLiteral(unwrapped2)) {
10696
+ if (import_ts_morph46.Node.isStringLiteral(unwrapped2) || import_ts_morph46.Node.isNoSubstitutionTemplateLiteral(unwrapped2)) {
10862
10697
  return { type: "literal", value: unwrapped2.getLiteralValue() };
10863
10698
  }
10864
- if (import_ts_morph47.Node.isTemplateExpression(unwrapped2)) {
10699
+ if (import_ts_morph46.Node.isTemplateExpression(unwrapped2)) {
10865
10700
  return { type: "text" };
10866
10701
  }
10867
- if (import_ts_morph47.Node.isNumericLiteral(unwrapped2)) {
10702
+ if (import_ts_morph46.Node.isNumericLiteral(unwrapped2)) {
10868
10703
  return numericLiteralShape(
10869
10704
  unwrapped2.getLiteralValue(),
10870
10705
  unwrapped2.getText()
10871
10706
  );
10872
10707
  }
10873
- if (import_ts_morph47.Node.isPrefixUnaryExpression(unwrapped2)) {
10708
+ if (import_ts_morph46.Node.isPrefixUnaryExpression(unwrapped2)) {
10874
10709
  const op = unwrapped2.getOperatorToken();
10875
- if (op === import_ts_morph47.SyntaxKind.MinusToken || op === import_ts_morph47.SyntaxKind.PlusToken) {
10710
+ if (op === import_ts_morph46.SyntaxKind.MinusToken || op === import_ts_morph46.SyntaxKind.PlusToken) {
10876
10711
  const inner = unwrapped2.getOperand();
10877
- if (import_ts_morph47.Node.isNumericLiteral(inner)) {
10712
+ if (import_ts_morph46.Node.isNumericLiteral(inner)) {
10878
10713
  const v3 = inner.getLiteralValue();
10879
- const signed = op === import_ts_morph47.SyntaxKind.MinusToken ? -v3 : v3;
10714
+ const signed = op === import_ts_morph46.SyntaxKind.MinusToken ? -v3 : v3;
10880
10715
  const rawBody = inner.getText();
10881
- const raw = op === import_ts_morph47.SyntaxKind.MinusToken ? `-${rawBody}` : rawBody;
10716
+ const raw = op === import_ts_morph46.SyntaxKind.MinusToken ? `-${rawBody}` : rawBody;
10882
10717
  return numericLiteralShape(signed, raw);
10883
10718
  }
10884
10719
  }
10885
10720
  }
10886
- if (import_ts_morph47.Node.isBigIntLiteral(unwrapped2)) {
10721
+ if (import_ts_morph46.Node.isBigIntLiteral(unwrapped2)) {
10887
10722
  return { type: "ref", name: "bigint" };
10888
10723
  }
10889
10724
  const kind = unwrapped2.getKind();
10890
- if (kind === import_ts_morph47.SyntaxKind.TrueKeyword) {
10725
+ if (kind === import_ts_morph46.SyntaxKind.TrueKeyword) {
10891
10726
  return { type: "literal", value: true };
10892
10727
  }
10893
- if (kind === import_ts_morph47.SyntaxKind.FalseKeyword) {
10728
+ if (kind === import_ts_morph46.SyntaxKind.FalseKeyword) {
10894
10729
  return { type: "literal", value: false };
10895
10730
  }
10896
- if (kind === import_ts_morph47.SyntaxKind.NullKeyword) {
10731
+ if (kind === import_ts_morph46.SyntaxKind.NullKeyword) {
10897
10732
  return { type: "null" };
10898
10733
  }
10899
- if (import_ts_morph47.Node.isIdentifier(unwrapped2) && unwrapped2.getText() === "undefined") {
10734
+ if (import_ts_morph46.Node.isIdentifier(unwrapped2) && unwrapped2.getText() === "undefined") {
10900
10735
  return { type: "undefined" };
10901
10736
  }
10902
- if (import_ts_morph47.Node.isConditionalExpression(unwrapped2)) {
10737
+ if (import_ts_morph46.Node.isConditionalExpression(unwrapped2)) {
10903
10738
  const whenTrue = extractShape(unwrapped2.getWhenTrue());
10904
10739
  const whenFalse = extractShape(unwrapped2.getWhenFalse());
10905
10740
  const variants = [];
@@ -10930,7 +10765,7 @@ function shapeFromArrayLiteral(arr) {
10930
10765
  }
10931
10766
  const shapes = [];
10932
10767
  for (const el of elements) {
10933
- if (import_ts_morph47.Node.isSpreadElement(el)) {
10768
+ if (import_ts_morph46.Node.isSpreadElement(el)) {
10934
10769
  const inner = el.getExpression();
10935
10770
  const innerShape = extractShape(inner);
10936
10771
  if (innerShape?.type === "array") {
@@ -10949,7 +10784,7 @@ function shapeFromObjectLiteral(obj) {
10949
10784
  const properties = {};
10950
10785
  const unresolvedSpreads = [];
10951
10786
  for (const prop of obj.getProperties()) {
10952
- if (import_ts_morph47.Node.isPropertyAssignment(prop)) {
10787
+ if (import_ts_morph46.Node.isPropertyAssignment(prop)) {
10953
10788
  const name = propertyName2(prop);
10954
10789
  if (name === null) {
10955
10790
  continue;
@@ -10965,7 +10800,7 @@ function shapeFromObjectLiteral(obj) {
10965
10800
  };
10966
10801
  continue;
10967
10802
  }
10968
- if (import_ts_morph47.Node.isShorthandPropertyAssignment(prop)) {
10803
+ if (import_ts_morph46.Node.isShorthandPropertyAssignment(prop)) {
10969
10804
  const name = prop.getName();
10970
10805
  const valueExpr = prop.getNameNode();
10971
10806
  properties[name] = extractShape(valueExpr) ?? {
@@ -10974,7 +10809,7 @@ function shapeFromObjectLiteral(obj) {
10974
10809
  };
10975
10810
  continue;
10976
10811
  }
10977
- if (import_ts_morph47.Node.isSpreadAssignment(prop)) {
10812
+ if (import_ts_morph46.Node.isSpreadAssignment(prop)) {
10978
10813
  const expr = prop.getExpression();
10979
10814
  const spreadShape = extractShape(expr);
10980
10815
  if (spreadShape?.type === "record") {
@@ -10993,7 +10828,7 @@ function shapeFromObjectLiteral(obj) {
10993
10828
  }
10994
10829
  function propertyName2(prop) {
10995
10830
  const nameNode = prop.getNameNode();
10996
- if (import_ts_morph47.Node.isIdentifier(nameNode) || import_ts_morph47.Node.isStringLiteral(nameNode) || import_ts_morph47.Node.isNoSubstitutionTemplateLiteral(nameNode) || import_ts_morph47.Node.isNumericLiteral(nameNode)) {
10831
+ if (import_ts_morph46.Node.isIdentifier(nameNode) || import_ts_morph46.Node.isStringLiteral(nameNode) || import_ts_morph46.Node.isNoSubstitutionTemplateLiteral(nameNode) || import_ts_morph46.Node.isNumericLiteral(nameNode)) {
10997
10832
  return nameNode.getText().replace(/^["']|["']$/g, "");
10998
10833
  }
10999
10834
  return null;
@@ -11019,22 +10854,20 @@ function collapseVariants2(shapes) {
11019
10854
  }
11020
10855
 
11021
10856
  // src/terminals/extract.ts
11022
- var import_ts_morph48 = require("ts-morph");
11023
- var import_values5 = require("@suss/values");
11024
10857
  function unwrapAs(node) {
11025
10858
  return peelSyntax(node);
11026
10859
  }
11027
10860
  function unwrapJsonStringify(node) {
11028
10861
  const outer = unwrapAs(node);
11029
- if (!import_ts_morph48.Node.isCallExpression(outer)) {
10862
+ if (!import_ts_morph47.Node.isCallExpression(outer)) {
11030
10863
  return node;
11031
10864
  }
11032
10865
  const callee = outer.getExpression();
11033
- if (!import_ts_morph48.Node.isPropertyAccessExpression(callee) || callee.getName() !== "stringify") {
10866
+ if (!import_ts_morph47.Node.isPropertyAccessExpression(callee) || callee.getName() !== "stringify") {
11034
10867
  return node;
11035
10868
  }
11036
10869
  const receiver = callee.getExpression();
11037
- if (!import_ts_morph48.Node.isIdentifier(receiver) || receiver.getText() !== "JSON") {
10870
+ if (!import_ts_morph47.Node.isIdentifier(receiver) || receiver.getText() !== "JSON") {
11038
10871
  return node;
11039
10872
  }
11040
10873
  const args = outer.getArguments();
@@ -11044,7 +10877,7 @@ function unwrapJsonStringify(node) {
11044
10877
  return unwrapAs(args[0]);
11045
10878
  }
11046
10879
  function substituted(value, ctx) {
11047
- if (ctx.substitutions === void 0 || !import_ts_morph48.Node.isIdentifier(value)) {
10880
+ if (ctx.substitutions === void 0 || !import_ts_morph47.Node.isIdentifier(value)) {
11048
10881
  return value;
11049
10882
  }
11050
10883
  return ctx.substitutions.get(value.getText()) ?? value;
@@ -11057,10 +10890,10 @@ function extractStatusCode(ctx) {
11057
10890
  if (result !== null) {
11058
10891
  return result;
11059
10892
  }
11060
- if (ctx.extraction.defaultStatusCode !== void 0) {
11061
- return { type: "literal", value: ctx.extraction.defaultStatusCode };
11062
- }
11063
- return null;
10893
+ return declaredStatusCode(ctx.extraction);
10894
+ }
10895
+ function declaredStatusCode(extraction) {
10896
+ return extraction.defaultStatusCode !== void 0 ? { type: "literal", value: extraction.defaultStatusCode } : null;
11064
10897
  }
11065
10898
  function matchConstructorCode(ctorText, codes) {
11066
10899
  const fullMatch = codes[ctorText];
@@ -11088,10 +10921,10 @@ function statusFromProperty(obj, name, ctx) {
11088
10921
  if (prop === void 0) {
11089
10922
  return null;
11090
10923
  }
11091
- if (import_ts_morph48.Node.isShorthandPropertyAssignment(prop)) {
10924
+ if (import_ts_morph47.Node.isShorthandPropertyAssignment(prop)) {
11092
10925
  return { type: "dynamic", sourceText: prop.getName() };
11093
10926
  }
11094
- if (!import_ts_morph48.Node.isPropertyAssignment(prop)) {
10927
+ if (!import_ts_morph47.Node.isPropertyAssignment(prop)) {
11095
10928
  return null;
11096
10929
  }
11097
10930
  const value = prop.getInitializer();
@@ -11114,7 +10947,7 @@ function extractStatusCodeFromRule(ctx) {
11114
10947
  return null;
11115
10948
  }
11116
10949
  const first = ctx.throwCallArgs?.[0];
11117
- if (first !== void 0 && import_ts_morph48.Node.isNumericLiteral(first)) {
10950
+ if (first !== void 0 && import_ts_morph47.Node.isNumericLiteral(first)) {
11118
10951
  const value = first.getLiteralValue();
11119
10952
  if (value >= 100 && value <= 599) {
11120
10953
  return { type: "literal", value };
@@ -11127,7 +10960,7 @@ function extractStatusCodeFromRule(ctx) {
11127
10960
  return null;
11128
10961
  }
11129
10962
  const arg = ctx.throwCallArgs[sc.position];
11130
- if (arg === void 0 || !import_ts_morph48.Node.isNewExpression(arg)) {
10963
+ if (arg === void 0 || !import_ts_morph47.Node.isNewExpression(arg)) {
11131
10964
  return null;
11132
10965
  }
11133
10966
  const ctorText = arg.getExpression().getText();
@@ -11136,7 +10969,7 @@ function extractStatusCodeFromRule(ctx) {
11136
10969
  if (sc.from === "argumentProperty") {
11137
10970
  const args = ctx.throwCallArgs ?? ctx.calls?.[0]?.getArguments();
11138
10971
  const arg = args?.[sc.position];
11139
- if (arg === void 0 || !import_ts_morph48.Node.isObjectLiteralExpression(arg)) {
10972
+ if (arg === void 0 || !import_ts_morph47.Node.isObjectLiteralExpression(arg)) {
11140
10973
  return null;
11141
10974
  }
11142
10975
  return statusFromProperty(arg, sc.name, ctx);
@@ -11146,8 +10979,8 @@ function extractStatusCodeFromRule(ctx) {
11146
10979
  return null;
11147
10980
  }
11148
10981
  for (const prop of ctx.returnedObj.getProperties()) {
11149
- if (!import_ts_morph48.Node.isPropertyAssignment(prop)) {
11150
- if (import_ts_morph48.Node.isShorthandPropertyAssignment(prop)) {
10982
+ if (!import_ts_morph47.Node.isPropertyAssignment(prop)) {
10983
+ if (import_ts_morph47.Node.isShorthandPropertyAssignment(prop)) {
11151
10984
  if (prop.getName() === sc.name) {
11152
10985
  const resolved = ctx.substitutions?.get(prop.getName());
11153
10986
  if (resolved !== void 0) {
@@ -11205,8 +11038,8 @@ function extractBody(ctx) {
11205
11038
  return null;
11206
11039
  }
11207
11040
  for (const prop of ctx.returnedObj.getProperties()) {
11208
- if (!import_ts_morph48.Node.isPropertyAssignment(prop)) {
11209
- if (import_ts_morph48.Node.isShorthandPropertyAssignment(prop)) {
11041
+ if (!import_ts_morph47.Node.isPropertyAssignment(prop)) {
11042
+ if (import_ts_morph47.Node.isShorthandPropertyAssignment(prop)) {
11210
11043
  if (prop.getName() === b.name) {
11211
11044
  const resolved = ctx.substitutions?.get(prop.getName());
11212
11045
  if (resolved !== void 0) {
@@ -11260,6 +11093,197 @@ function extractBody(ctx) {
11260
11093
  return null;
11261
11094
  }
11262
11095
 
11096
+ // src/terminals/jsx.ts
11097
+ var import_ts_morph48 = require("ts-morph");
11098
+ function tryMatchJsxReturn(node, pattern) {
11099
+ let expr;
11100
+ let source;
11101
+ if (import_ts_morph48.Node.isReturnStatement(node)) {
11102
+ expr = node.getExpression();
11103
+ source = node;
11104
+ } else if (import_ts_morph48.Node.isArrowFunction(node)) {
11105
+ const body = node.getBody();
11106
+ if (body !== void 0 && !import_ts_morph48.Node.isBlock(body)) {
11107
+ expr = body;
11108
+ source = body;
11109
+ }
11110
+ }
11111
+ if (expr === void 0 || source === void 0) {
11112
+ return null;
11113
+ }
11114
+ const tree = jsxToRenderNode(expr);
11115
+ if (tree === null) {
11116
+ return null;
11117
+ }
11118
+ const component = tree.type === "element" ? tree.tag : "Fragment";
11119
+ const terminal = {
11120
+ kind: pattern.kind,
11121
+ statusCode: null,
11122
+ body: null,
11123
+ exceptionType: null,
11124
+ message: null,
11125
+ component,
11126
+ delegateTarget: null,
11127
+ emitEvent: null,
11128
+ renderTree: tree,
11129
+ location: {
11130
+ start: startLineOf(node),
11131
+ end: endLineOf(node)
11132
+ }
11133
+ };
11134
+ return { node, source, terminal };
11135
+ }
11136
+ function componentTargetOf(tagNode) {
11137
+ if (!import_ts_morph48.Node.isIdentifier(tagNode) || !/^[A-Z]/.test(tagNode.getText())) {
11138
+ return null;
11139
+ }
11140
+ const target = functionTargetOf(tagNode);
11141
+ return target === null ? null : { file: target.file, name: target.name };
11142
+ }
11143
+ function jsxToRenderNode(node) {
11144
+ if (import_ts_morph48.Node.isJsxElement(node)) {
11145
+ const opening = node.getOpeningElement();
11146
+ const tag = opening.getTagNameNode().getText();
11147
+ const attrs = collectJsxAttributes(opening);
11148
+ const target = componentTargetOf(opening.getTagNameNode());
11149
+ const children = node.getJsxChildren().map(jsxChildToRenderNode).filter((n) => n !== null);
11150
+ return {
11151
+ type: "element",
11152
+ tag,
11153
+ children,
11154
+ ...attrs !== null ? { attrs } : {},
11155
+ ...target !== null ? { target } : {}
11156
+ };
11157
+ }
11158
+ if (import_ts_morph48.Node.isJsxSelfClosingElement(node)) {
11159
+ const tag = node.getTagNameNode().getText();
11160
+ const attrs = collectJsxAttributes(node);
11161
+ const target = componentTargetOf(node.getTagNameNode());
11162
+ return {
11163
+ type: "element",
11164
+ tag,
11165
+ children: [],
11166
+ ...attrs !== null ? { attrs } : {},
11167
+ ...target !== null ? { target } : {}
11168
+ };
11169
+ }
11170
+ if (import_ts_morph48.Node.isJsxFragment(node)) {
11171
+ const children = node.getJsxChildren().map(jsxChildToRenderNode).filter((n) => n !== null);
11172
+ return { type: "element", tag: "Fragment", children };
11173
+ }
11174
+ if (import_ts_morph48.Node.isParenthesizedExpression(node)) {
11175
+ return jsxToRenderNode(node.getExpression());
11176
+ }
11177
+ return null;
11178
+ }
11179
+ function collectJsxAttributes(opening) {
11180
+ const entries = {};
11181
+ for (const attr of opening.getAttributes()) {
11182
+ if (import_ts_morph48.Node.isJsxSpreadAttribute(attr)) {
11183
+ const exprText = attr.getExpression().getText();
11184
+ entries[`...${exprText}`] = exprText;
11185
+ continue;
11186
+ }
11187
+ if (!import_ts_morph48.Node.isJsxAttribute(attr)) {
11188
+ continue;
11189
+ }
11190
+ const name = attr.getNameNode().getText();
11191
+ const initializer = attr.getInitializer();
11192
+ if (initializer === void 0) {
11193
+ entries[name] = "";
11194
+ continue;
11195
+ }
11196
+ if (import_ts_morph48.Node.isJsxExpression(initializer)) {
11197
+ const inner = initializer.getExpression();
11198
+ entries[name] = inner !== void 0 ? inner.getText() : "";
11199
+ continue;
11200
+ }
11201
+ entries[name] = initializer.getText();
11202
+ }
11203
+ return Object.keys(entries).length > 0 ? entries : null;
11204
+ }
11205
+ function jsxChildToRenderNode(child) {
11206
+ if (import_ts_morph48.Node.isJsxText(child)) {
11207
+ const text = child.getLiteralText().trim();
11208
+ if (text.length === 0) {
11209
+ return null;
11210
+ }
11211
+ return { type: "text", value: text };
11212
+ }
11213
+ if (import_ts_morph48.Node.isJsxExpression(child)) {
11214
+ const inner = child.getExpression();
11215
+ if (inner === void 0) {
11216
+ return null;
11217
+ }
11218
+ return jsxExpressionToRenderNode(inner);
11219
+ }
11220
+ if (import_ts_morph48.Node.isJsxElement(child) || import_ts_morph48.Node.isJsxSelfClosingElement(child) || import_ts_morph48.Node.isJsxFragment(child)) {
11221
+ return jsxToRenderNode(child);
11222
+ }
11223
+ return null;
11224
+ }
11225
+ function jsxExpressionToRenderNode(expr) {
11226
+ if (import_ts_morph48.Node.isParenthesizedExpression(expr)) {
11227
+ return jsxExpressionToRenderNode(expr.getExpression());
11228
+ }
11229
+ if (import_ts_morph48.Node.isBinaryExpression(expr)) {
11230
+ const op = expr.getOperatorToken().getText();
11231
+ if (op === "&&") {
11232
+ const right = renderAlternative(peelParens(expr.getRight()));
11233
+ if (right.kind === "jsx") {
11234
+ return {
11235
+ type: "conditional",
11236
+ condition: expr.getLeft().getText(),
11237
+ whenTrue: right.node,
11238
+ whenFalse: null
11239
+ };
11240
+ }
11241
+ }
11242
+ }
11243
+ if (import_ts_morph48.Node.isConditionalExpression(expr)) {
11244
+ const truthy = renderAlternative(peelParens(expr.getWhenTrue()));
11245
+ const falsy = renderAlternative(peelParens(expr.getWhenFalse()));
11246
+ if (truthy.kind === "jsx") {
11247
+ return {
11248
+ type: "conditional",
11249
+ condition: expr.getCondition().getText(),
11250
+ whenTrue: truthy.node,
11251
+ whenFalse: falsy.kind === "jsx" ? falsy.node : null
11252
+ };
11253
+ }
11254
+ if (falsy.kind === "jsx") {
11255
+ return {
11256
+ type: "conditional",
11257
+ condition: `!(${expr.getCondition().getText()})`,
11258
+ whenTrue: falsy.node,
11259
+ whenFalse: null
11260
+ };
11261
+ }
11262
+ }
11263
+ return { type: "expression", sourceText: expr.getText() };
11264
+ }
11265
+ function renderAlternative(node) {
11266
+ if (import_ts_morph48.Node.isNullLiteral(node)) {
11267
+ return { kind: "noRender" };
11268
+ }
11269
+ if (import_ts_morph48.Node.isFalseLiteral(node)) {
11270
+ return { kind: "noRender" };
11271
+ }
11272
+ if (import_ts_morph48.Node.isIdentifier(node) && node.getText() === "undefined") {
11273
+ return { kind: "noRender" };
11274
+ }
11275
+ if (import_ts_morph48.Node.isJsxElement(node) || import_ts_morph48.Node.isJsxSelfClosingElement(node) || import_ts_morph48.Node.isJsxFragment(node)) {
11276
+ const tree = jsxToRenderNode(node);
11277
+ if (tree !== null) {
11278
+ return { kind: "jsx", node: tree };
11279
+ }
11280
+ }
11281
+ return { kind: "notStatic" };
11282
+ }
11283
+
11284
+ // src/terminals/returns.ts
11285
+ var import_ts_morph51 = require("ts-morph");
11286
+
11263
11287
  // src/terminals/helperResolution.ts
11264
11288
  var import_ts_morph49 = require("ts-morph");
11265
11289
  function resolveHelperReturn(call, resolveCallee2) {
@@ -11831,10 +11855,9 @@ function tryMatchReturnStatement(node, pattern, func, allPatterns) {
11831
11855
  return null;
11832
11856
  }
11833
11857
  function buildReturnTerminal(locationNode, pattern, body) {
11834
- const statusCode = pattern.extraction.defaultStatusCode !== void 0 ? { type: "literal", value: pattern.extraction.defaultStatusCode } : null;
11835
11858
  const terminal = {
11836
11859
  kind: pattern.kind,
11837
- statusCode,
11860
+ statusCode: declaredStatusCode(pattern.extraction),
11838
11861
  body,
11839
11862
  exceptionType: null,
11840
11863
  message: null,
@@ -12123,15 +12146,15 @@ function functionMayFallThrough(func) {
12123
12146
  }
12124
12147
  return true;
12125
12148
  }
12126
- function makeFallthroughTerminal(func) {
12149
+ function makeFallthroughTerminal(func, pattern) {
12127
12150
  const body = func.getBody();
12128
12151
  const anchor = body ?? func;
12129
12152
  const line = endLineOf(anchor);
12130
12153
  return {
12131
12154
  node: anchor,
12132
12155
  terminal: {
12133
- kind: "return",
12134
- statusCode: null,
12156
+ kind: pattern.kind,
12157
+ statusCode: declaredStatusCode(pattern.extraction),
12135
12158
  body: null,
12136
12159
  exceptionType: null,
12137
12160
  message: null,
@@ -12251,15 +12274,15 @@ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [],
12251
12274
  terminals.map(({ node }) => node),
12252
12275
  barriers
12253
12276
  );
12254
- const wantsFallthrough = terminalPatterns.some(
12277
+ const fallthroughPattern = terminalPatterns.find(
12255
12278
  (p) => p.match.type === "functionFallthrough"
12256
12279
  );
12257
- if (wantsFallthrough && functionMayFallThrough(func)) {
12280
+ if (fallthroughPattern !== void 0 && functionMayFallThrough(func)) {
12258
12281
  const hasDefaultTerminal = terminals.some(
12259
12282
  ({ node }) => (byTerminal.get(node) ?? []).some(isDefaultConditionList)
12260
12283
  );
12261
12284
  if (!hasDefaultTerminal) {
12262
- const synthetic = makeFallthroughTerminal(func);
12285
+ const synthetic = makeFallthroughTerminal(func, fallthroughPattern);
12263
12286
  terminals.push(synthetic);
12264
12287
  const pathResult = computePathConditions(
12265
12288
  func,