@ggui-ai/ui-gen 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/adapters/generation-dispatch.js +252 -108
  2. package/dist/adapters/generation-dispatch.js.map +1 -1
  3. package/dist/adapters/index.js.map +1 -1
  4. package/dist/advanced/index.js +261 -113
  5. package/dist/advanced/index.js.map +1 -1
  6. package/dist/boilerplate.js +27 -3
  7. package/dist/boilerplate.js.map +1 -1
  8. package/dist/check/index.js +70 -0
  9. package/dist/check/index.js.map +1 -1
  10. package/dist/evaluation/axis-checks/index.js +50 -0
  11. package/dist/evaluation/axis-checks/index.js.map +1 -1
  12. package/dist/evaluation/axis-checks/registry.js +50 -0
  13. package/dist/evaluation/axis-checks/registry.js.map +1 -1
  14. package/dist/evaluation/index.js +50 -0
  15. package/dist/evaluation/index.js.map +1 -1
  16. package/dist/harness/index.js +27 -3
  17. package/dist/harness/index.js.map +1 -1
  18. package/dist/harness/prompts.js +4 -0
  19. package/dist/harness/prompts.js.map +1 -1
  20. package/dist/harness/runtime.js +27 -3
  21. package/dist/harness/runtime.js.map +1 -1
  22. package/dist/harness/types-public.js +27 -3
  23. package/dist/harness/types-public.js.map +1 -1
  24. package/dist/index.js +261 -113
  25. package/dist/index.js.map +1 -1
  26. package/package.json +12 -12
  27. package/src/boilerplate/free-design-prompt.ts +2 -0
  28. package/src/boilerplate/generate.ts +8 -1
  29. package/src/boilerplate/hard-sections.ts +31 -2
  30. package/src/boilerplate/system-prompt.ts +2 -0
  31. package/src/boilerplate/templates/layouts/fullscreen-desktop.tsx.tmpl +5 -3
  32. package/src/boilerplate/templates/layouts/fullscreen-mobile.tsx.tmpl +3 -3
  33. package/src/boilerplate/templates/layouts/fullscreen-universal.tsx.tmpl +5 -3
  34. package/src/check/run-tier0.ts +152 -0
  35. package/src/contract-context.ts +13 -0
  36. package/src/evaluation/axis-checks/checks/universal.ts +64 -0
@@ -9,7 +9,7 @@ import { contentHash } from '@ggui-ai/protocol/content-hash';
9
9
  import { createRequire } from 'module';
10
10
  import { fileURLToPath, pathToFileURL } from 'url';
11
11
  import { runSandboxed } from '@ggui-ai/sandbox';
12
- import ts2 from 'typescript';
12
+ import ts6 from 'typescript';
13
13
  import path, { dirname, resolve, join, basename } from 'path';
14
14
  import { Linter } from 'eslint';
15
15
  import { consumedTokenManifest } from '@ggui-ai/design/themes';
@@ -2933,53 +2933,53 @@ var init_render_check_host = __esm({
2933
2933
  }
2934
2934
  });
2935
2935
  function extractWireCallSites(code) {
2936
- const sf = ts2.createSourceFile(
2936
+ const sf = ts6.createSourceFile(
2937
2937
  "component.tsx",
2938
2938
  code,
2939
- ts2.ScriptTarget.Latest,
2939
+ ts6.ScriptTarget.Latest,
2940
2940
  /*setParentNodes*/
2941
2941
  true,
2942
- ts2.ScriptKind.TSX
2942
+ ts6.ScriptKind.TSX
2943
2943
  );
2944
2944
  const sites = [];
2945
2945
  function visit(node) {
2946
- if (ts2.isCallExpression(node)) {
2946
+ if (ts6.isCallExpression(node)) {
2947
2947
  const callee = node.expression;
2948
- if (ts2.isIdentifier(callee)) {
2948
+ if (ts6.isIdentifier(callee)) {
2949
2949
  const kind = HOOK_TO_KIND[callee.text];
2950
2950
  if (kind) {
2951
2951
  const firstArg = node.arguments[0];
2952
- if (firstArg && ts2.isStringLiteral(firstArg)) {
2952
+ if (firstArg && ts6.isStringLiteral(firstArg)) {
2953
2953
  sites.push({ kind, name: firstArg.text });
2954
2954
  }
2955
2955
  }
2956
2956
  }
2957
2957
  }
2958
- ts2.forEachChild(node, visit);
2958
+ ts6.forEachChild(node, visit);
2959
2959
  }
2960
2960
  visit(sf);
2961
2961
  return sites;
2962
2962
  }
2963
2963
  function extractWireImports(code) {
2964
- const sf = ts2.createSourceFile(
2964
+ const sf = ts6.createSourceFile(
2965
2965
  "component.tsx",
2966
2966
  code,
2967
- ts2.ScriptTarget.Latest,
2967
+ ts6.ScriptTarget.Latest,
2968
2968
  /*setParentNodes*/
2969
2969
  true,
2970
- ts2.ScriptKind.TSX
2970
+ ts6.ScriptKind.TSX
2971
2971
  );
2972
2972
  const imported = /* @__PURE__ */ new Set();
2973
2973
  for (const stmt of sf.statements) {
2974
- if (!ts2.isImportDeclaration(stmt)) continue;
2974
+ if (!ts6.isImportDeclaration(stmt)) continue;
2975
2975
  const moduleSpecifier = stmt.moduleSpecifier;
2976
- if (!ts2.isStringLiteral(moduleSpecifier)) continue;
2976
+ if (!ts6.isStringLiteral(moduleSpecifier)) continue;
2977
2977
  if (moduleSpecifier.text !== "@ggui-ai/wire") continue;
2978
2978
  const clause = stmt.importClause;
2979
2979
  if (!clause) continue;
2980
2980
  const bindings = clause.namedBindings;
2981
2981
  if (!bindings) continue;
2982
- if (!ts2.isNamedImports(bindings)) continue;
2982
+ if (!ts6.isNamedImports(bindings)) continue;
2983
2983
  for (const el of bindings.elements) {
2984
2984
  imported.add(el.name.text);
2985
2985
  }
@@ -3057,11 +3057,11 @@ var init_extract_wire_calls = __esm({
3057
3057
  }
3058
3058
  });
3059
3059
  function extractPropsInterface(code) {
3060
- const sf = ts2.createSourceFile("component.tsx", code, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
3060
+ const sf = ts6.createSourceFile("component.tsx", code, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TSX);
3061
3061
  const props = [];
3062
3062
  function visitMembers(members) {
3063
3063
  for (const member of members) {
3064
- if (ts2.isPropertySignature(member) && member.name) {
3064
+ if (ts6.isPropertySignature(member) && member.name) {
3065
3065
  const name = member.name.getText(sf);
3066
3066
  const type = member.type ? member.type.getText(sf) : "unknown";
3067
3067
  const optional = !!member.questionToken;
@@ -3070,17 +3070,17 @@ function extractPropsInterface(code) {
3070
3070
  }
3071
3071
  }
3072
3072
  function visit(node) {
3073
- if (ts2.isInterfaceDeclaration(node) && node.name.text === "Props") {
3073
+ if (ts6.isInterfaceDeclaration(node) && node.name.text === "Props") {
3074
3074
  visitMembers(node.members);
3075
3075
  return;
3076
3076
  }
3077
- if (ts2.isTypeAliasDeclaration(node) && node.name.text === "Props") {
3078
- if (ts2.isTypeLiteralNode(node.type)) {
3077
+ if (ts6.isTypeAliasDeclaration(node) && node.name.text === "Props") {
3078
+ if (ts6.isTypeLiteralNode(node.type)) {
3079
3079
  visitMembers(node.type.members);
3080
3080
  }
3081
3081
  return;
3082
3082
  }
3083
- ts2.forEachChild(node, visit);
3083
+ ts6.forEachChild(node, visit);
3084
3084
  }
3085
3085
  visit(sf);
3086
3086
  return props.length > 0 ? props : null;
@@ -3293,12 +3293,12 @@ function generateFix(code, message, sourceLine) {
3293
3293
  }
3294
3294
  }
3295
3295
  function parseAndStore(vfs, virtualPath, content) {
3296
- const sourceFile = ts2.createSourceFile(
3296
+ const sourceFile = ts6.createSourceFile(
3297
3297
  virtualPath,
3298
3298
  content,
3299
- ts2.ScriptTarget.ES2020,
3299
+ ts6.ScriptTarget.ES2020,
3300
3300
  true,
3301
- virtualPath.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS
3301
+ virtualPath.endsWith(".tsx") ? ts6.ScriptKind.TSX : ts6.ScriptKind.TS
3302
3302
  );
3303
3303
  vfs.set(virtualPath, { content, sourceFile });
3304
3304
  }
@@ -3440,12 +3440,12 @@ function resolveModuleName(vfs, name, containingFile) {
3440
3440
  return { resolvedModule: void 0 };
3441
3441
  }
3442
3442
  function createVfsHost(vfs, componentCode) {
3443
- const componentFile = ts2.createSourceFile(
3443
+ const componentFile = ts6.createSourceFile(
3444
3444
  "Component.tsx",
3445
3445
  componentCode,
3446
- ts2.ScriptTarget.ES2020,
3446
+ ts6.ScriptTarget.ES2020,
3447
3447
  true,
3448
- ts2.ScriptKind.TSX
3448
+ ts6.ScriptKind.TSX
3449
3449
  );
3450
3450
  const host = {
3451
3451
  getSourceFile(fileName) {
@@ -3500,7 +3500,7 @@ function resolved(resolvedFileName) {
3500
3500
  resolvedModule: {
3501
3501
  resolvedFileName,
3502
3502
  isExternalLibraryImport: true,
3503
- extension: ts2.Extension.Dts
3503
+ extension: ts6.Extension.Dts
3504
3504
  }
3505
3505
  };
3506
3506
  }
@@ -3522,18 +3522,18 @@ async function typecheck(code, dtsMap) {
3522
3522
  const prefixedCode = SYNTHETIC_PREFIX + code;
3523
3523
  const lineOffset = SYNTHETIC_PREFIX.split("\n").length - 1;
3524
3524
  const host = createVfsHost(effectiveVfs, prefixedCode);
3525
- const program = ts2.createProgram(["Component.tsx"], COMPILER_OPTIONS, host);
3526
- const diagnostics = ts2.getPreEmitDiagnostics(program);
3525
+ const program = ts6.createProgram(["Component.tsx"], COMPILER_OPTIONS, host);
3526
+ const diagnostics = ts6.getPreEmitDiagnostics(program);
3527
3527
  const errors = [];
3528
3528
  const warnings = [];
3529
3529
  for (const diag of diagnostics) {
3530
3530
  if (diag.file && diag.file.fileName !== "Component.tsx") continue;
3531
3531
  if (!diag.file) continue;
3532
- const diagLine = ts2.getLineAndCharacterOfPosition(diag.file, diag.start ?? 0).line;
3532
+ const diagLine = ts6.getLineAndCharacterOfPosition(diag.file, diag.start ?? 0).line;
3533
3533
  if (diagLine < lineOffset) continue;
3534
- const rawLine = diag.file ? ts2.getLineAndCharacterOfPosition(diag.file, diag.start ?? 0).line + 1 : 0;
3534
+ const rawLine = diag.file ? ts6.getLineAndCharacterOfPosition(diag.file, diag.start ?? 0).line + 1 : 0;
3535
3535
  const line = Math.max(1, rawLine - lineOffset);
3536
- const message = ts2.flattenDiagnosticMessageText(diag.messageText, "\n");
3536
+ const message = ts6.flattenDiagnosticMessageText(diag.messageText, "\n");
3537
3537
  const code_ = diag.code;
3538
3538
  const sourceLines = diag.file.text.split("\n");
3539
3539
  const sourceLine = rawLine >= 1 && rawLine <= sourceLines.length ? sourceLines[rawLine - 1]?.trim() ?? "" : "";
@@ -3580,8 +3580,8 @@ var init_type_checker = __esm({
3580
3580
  ]);
3581
3581
  vfsCache = null;
3582
3582
  COMPILER_OPTIONS = {
3583
- target: ts2.ScriptTarget.ES2020,
3584
- module: ts2.ModuleKind.ESNext,
3583
+ target: ts6.ScriptTarget.ES2020,
3584
+ module: ts6.ModuleKind.ESNext,
3585
3585
  // Classic React JSX mode. The synthetic prefix (SYNTHETIC_PREFIX)
3586
3586
  // supplies `import React from 'react'` plus a `declare global` JSX
3587
3587
  // namespace shim: `@types/react` v19 removed the *global* `JSX`
@@ -3589,8 +3589,8 @@ var init_type_checker = __esm({
3589
3589
  // for `JSX.IntrinsicElements` and the `key`/`ref` carve-out. Without
3590
3590
  // the shim, `<div>` degrades to `any` and every typed component
3591
3591
  // falsely rejects the intrinsic `key` prop.
3592
- jsx: ts2.JsxEmit.React,
3593
- moduleResolution: ts2.ModuleResolutionKind.Bundler,
3592
+ jsx: ts6.JsxEmit.React,
3593
+ moduleResolution: ts6.ModuleResolutionKind.Bundler,
3594
3594
  strict: false,
3595
3595
  strictNullChecks: true,
3596
3596
  // Catch undefined.foo() errors that cause runtime crashes
@@ -3732,17 +3732,17 @@ var init_react_linter = __esm({
3732
3732
  }
3733
3733
  });
3734
3734
  function stripComments(code) {
3735
- const scanner = ts2.createScanner(
3736
- ts2.ScriptTarget.Latest,
3735
+ const scanner = ts6.createScanner(
3736
+ ts6.ScriptTarget.Latest,
3737
3737
  /* skipTrivia */
3738
3738
  false,
3739
- ts2.LanguageVariant.JSX,
3739
+ ts6.LanguageVariant.JSX,
3740
3740
  code
3741
3741
  );
3742
3742
  let out = "";
3743
- for (let token = scanner.scan(); token !== ts2.SyntaxKind.EndOfFileToken; token = scanner.scan()) {
3743
+ for (let token = scanner.scan(); token !== ts6.SyntaxKind.EndOfFileToken; token = scanner.scan()) {
3744
3744
  const text = scanner.getTokenText();
3745
- out += token === ts2.SyntaxKind.SingleLineCommentTrivia || token === ts2.SyntaxKind.MultiLineCommentTrivia ? text.replace(/[^\n]/g, " ") : text;
3745
+ out += token === ts6.SyntaxKind.SingleLineCommentTrivia || token === ts6.SyntaxKind.MultiLineCommentTrivia ? text.replace(/[^\n]/g, " ") : text;
3746
3746
  }
3747
3747
  return out;
3748
3748
  }
@@ -3765,20 +3765,20 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode
3765
3765
  "Link"
3766
3766
  ]);
3767
3767
  const HANDLER_ATTRS = ["onClick", "onChange", "onPress", "onSelect"];
3768
- const sf = ts2.createSourceFile(
3768
+ const sf = ts6.createSourceFile(
3769
3769
  "source.tsx",
3770
3770
  sourceCode,
3771
- ts2.ScriptTarget.Latest,
3771
+ ts6.ScriptTarget.Latest,
3772
3772
  /* setParentNodes */
3773
3773
  true,
3774
- ts2.ScriptKind.TSX
3774
+ ts6.ScriptKind.TSX
3775
3775
  );
3776
3776
  function tagNameText(node) {
3777
- return ts2.isIdentifier(node.tagName) ? node.tagName.text : void 0;
3777
+ return ts6.isIdentifier(node.tagName) ? node.tagName.text : void 0;
3778
3778
  }
3779
3779
  function attrExpression(node, attrName) {
3780
3780
  for (const attr of node.attributes.properties) {
3781
- if (ts2.isJsxAttribute(attr) && ts2.isIdentifier(attr.name) && attr.name.text === attrName && attr.initializer !== void 0 && ts2.isJsxExpression(attr.initializer)) {
3781
+ if (ts6.isJsxAttribute(attr) && ts6.isIdentifier(attr.name) && attr.name.text === attrName && attr.initializer !== void 0 && ts6.isJsxExpression(attr.initializer)) {
3782
3782
  return attr.initializer.expression;
3783
3783
  }
3784
3784
  }
@@ -3790,19 +3790,19 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode
3790
3790
  if (anyElementIsInteractive) return true;
3791
3791
  if (!TRAIT_HOST_TAGS.has(tag)) return false;
3792
3792
  const asExpr = attrExpression(node, "as");
3793
- return asExpr !== void 0 && ts2.isIdentifier(asExpr) && TRAITS_THAT_FIRE.has(asExpr.text);
3793
+ return asExpr !== void 0 && ts6.isIdentifier(asExpr) && TRAITS_THAT_FIRE.has(asExpr.text);
3794
3794
  }
3795
3795
  function extractCalleeName(expr) {
3796
3796
  if (expr === void 0) return void 0;
3797
- if (ts2.isIdentifier(expr)) return expr.text;
3798
- if (ts2.isArrowFunction(expr) || ts2.isFunctionExpression(expr)) {
3797
+ if (ts6.isIdentifier(expr)) return expr.text;
3798
+ if (ts6.isArrowFunction(expr) || ts6.isFunctionExpression(expr)) {
3799
3799
  const body = expr.body;
3800
- if (ts2.isCallExpression(body) && ts2.isIdentifier(body.expression)) {
3800
+ if (ts6.isCallExpression(body) && ts6.isIdentifier(body.expression)) {
3801
3801
  return body.expression.text;
3802
3802
  }
3803
- if (ts2.isBlock(body)) {
3803
+ if (ts6.isBlock(body)) {
3804
3804
  for (const stmt of body.statements) {
3805
- if (ts2.isExpressionStatement(stmt) && ts2.isCallExpression(stmt.expression) && ts2.isIdentifier(stmt.expression.expression)) {
3805
+ if (ts6.isExpressionStatement(stmt) && ts6.isCallExpression(stmt.expression) && ts6.isIdentifier(stmt.expression.expression)) {
3806
3806
  return stmt.expression.expression.text;
3807
3807
  }
3808
3808
  }
@@ -3814,7 +3814,7 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode
3814
3814
  let found;
3815
3815
  function walk(node) {
3816
3816
  if (found !== void 0) return;
3817
- const opening = ts2.isJsxElement(node) ? node.openingElement : ts2.isJsxSelfClosingElement(node) ? node : void 0;
3817
+ const opening = ts6.isJsxElement(node) ? node.openingElement : ts6.isJsxSelfClosingElement(node) ? node : void 0;
3818
3818
  if (opening !== void 0) {
3819
3819
  const tag = tagNameText(opening);
3820
3820
  if (tag !== void 0 && (anyElementIsInteractive || INTERACTIVE_DESCENDANTS.has(tag))) {
@@ -3830,13 +3830,13 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode
3830
3830
  }
3831
3831
  }
3832
3832
  }
3833
- ts2.forEachChild(node, walk);
3833
+ ts6.forEachChild(node, walk);
3834
3834
  }
3835
- ts2.forEachChild(outer, walk);
3835
+ ts6.forEachChild(outer, walk);
3836
3836
  return found;
3837
3837
  }
3838
3838
  function visit(node) {
3839
- if (ts2.isJsxElement(node) && isTraitHostWithFiringAs(node.openingElement)) {
3839
+ if (ts6.isJsxElement(node) && isTraitHostWithFiringAs(node.openingElement)) {
3840
3840
  const outerCallee = extractCalleeName(attrExpression(node.openingElement, "onClick")) ?? extractCalleeName(attrExpression(node.openingElement, "onPress"));
3841
3841
  if (outerCallee !== void 0 && bindings.has(outerCallee)) {
3842
3842
  const match = findMatchingInteractiveDescendant(node, outerCallee);
@@ -3857,7 +3857,7 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode
3857
3857
  }
3858
3858
  }
3859
3859
  }
3860
- ts2.forEachChild(node, visit);
3860
+ ts6.forEachChild(node, visit);
3861
3861
  }
3862
3862
  visit(sf);
3863
3863
  return issues;
@@ -3876,6 +3876,63 @@ function isGadgetExportImported(source, pkg, exportName) {
3876
3876
  }
3877
3877
  return false;
3878
3878
  }
3879
+ function detectComponentNeverReturns(sourceCode) {
3880
+ const sf = ts6.createSourceFile(
3881
+ "source.tsx",
3882
+ sourceCode,
3883
+ ts6.ScriptTarget.Latest,
3884
+ /* setParentNodes */
3885
+ true,
3886
+ ts6.ScriptKind.TSX
3887
+ );
3888
+ const isFunctionLike = (n) => ts6.isFunctionDeclaration(n) || ts6.isFunctionExpression(n) || ts6.isArrowFunction(n) || ts6.isMethodDeclaration(n) || ts6.isClassDeclaration(n) || ts6.isClassExpression(n);
3889
+ function resolveTopLevel(name) {
3890
+ for (const st of sf.statements) {
3891
+ if (ts6.isFunctionDeclaration(st) && st.name?.text === name) return st;
3892
+ if (ts6.isVariableStatement(st)) {
3893
+ for (const decl of st.declarationList.declarations) {
3894
+ if (ts6.isIdentifier(decl.name) && decl.name.text === name && decl.initializer !== void 0 && (ts6.isArrowFunction(decl.initializer) || ts6.isFunctionExpression(decl.initializer))) {
3895
+ return decl.initializer;
3896
+ }
3897
+ }
3898
+ }
3899
+ }
3900
+ return void 0;
3901
+ }
3902
+ let component;
3903
+ for (const st of sf.statements) {
3904
+ if (ts6.isFunctionDeclaration(st) && st.modifiers?.some((m) => m.kind === ts6.SyntaxKind.DefaultKeyword)) {
3905
+ component = st;
3906
+ break;
3907
+ }
3908
+ if (ts6.isExportAssignment(st) && st.isExportEquals !== true) {
3909
+ const expr = st.expression;
3910
+ if (ts6.isArrowFunction(expr) || ts6.isFunctionExpression(expr)) component = expr;
3911
+ else if (ts6.isIdentifier(expr)) component = resolveTopLevel(expr.text);
3912
+ break;
3913
+ }
3914
+ }
3915
+ if (component === void 0) return null;
3916
+ const body = component.body;
3917
+ if (body === void 0 || !ts6.isBlock(body)) return null;
3918
+ let returnsValue = false;
3919
+ let jsxStatementLine;
3920
+ const visit = (node) => {
3921
+ if (returnsValue) return;
3922
+ if (ts6.isReturnStatement(node)) {
3923
+ if (node.expression !== void 0) returnsValue = true;
3924
+ return;
3925
+ }
3926
+ if (jsxStatementLine === void 0 && ts6.isExpressionStatement(node) && (ts6.isJsxElement(node.expression) || ts6.isJsxFragment(node.expression) || ts6.isJsxSelfClosingElement(node.expression))) {
3927
+ jsxStatementLine = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
3928
+ }
3929
+ node.forEachChild((child) => {
3930
+ if (!isFunctionLike(child)) visit(child);
3931
+ });
3932
+ };
3933
+ for (const st of body.statements) if (!isFunctionLike(st)) visit(st);
3934
+ return returnsValue ? null : { jsxStatementLine };
3935
+ }
3879
3936
  async function runTier0Checks(sourceCode, contract, buildErrors, gadgetTypes, designMode = DEFAULT_DESIGN_MODE) {
3880
3937
  const issues = [];
3881
3938
  const lines = sourceCode.split("\n");
@@ -4295,6 +4352,19 @@ ${errorDetail}`,
4295
4352
  fix: "Add export default function Component(props: Props) { ... }"
4296
4353
  });
4297
4354
  }
4355
+ const neverReturns = detectComponentNeverReturns(sourceCode);
4356
+ if (neverReturns !== null) {
4357
+ issues.push({
4358
+ tier: 0,
4359
+ result: "fail",
4360
+ category: "compile",
4361
+ subcategory: "renders-nothing",
4362
+ severity: "critical",
4363
+ description: neverReturns.jsxStatementLine === void 0 ? "The component never returns its tree \u2014 it renders a blank frame" : `The component never returns its tree: the JSX at line ${neverReturns.jsxStatementLine} sits at statement position, so it is built and thrown away and the frame renders blank`,
4364
+ fix: "Wrap the tree in the return the boilerplate gave you: `return (` before the root element and `);` after it.",
4365
+ ...neverReturns.jsxStatementLine === void 0 ? {} : { line: neverReturns.jsxStatementLine }
4366
+ });
4367
+ }
4298
4368
  if (contract) {
4299
4369
  try {
4300
4370
  const contractIssues = validateAllContracts(sourceCode, contract);
@@ -10855,6 +10925,50 @@ function runViewportSized(input) {
10855
10925
  )
10856
10926
  ];
10857
10927
  }
10928
+ var TERMINAL_WORDS = /* @__PURE__ */ new Set([
10929
+ "submit",
10930
+ "confirm",
10931
+ "approve",
10932
+ "schedule",
10933
+ "reserve",
10934
+ "book",
10935
+ "pay",
10936
+ "checkout",
10937
+ "purchase",
10938
+ "order"
10939
+ ]);
10940
+ var TERMINAL_LABEL_RX = /\b(submit|confirm|approve|schedule|reserve|book|pay|checkout|purchase|place\s+order)\b/i;
10941
+ var GUARD_RX = /\b(disabled|aria-disabled)\s*=/;
10942
+ function nameWords(name) {
10943
+ return name.split(/(?=[A-Z])|[_\-\s]+/).map((w) => w.toLowerCase()).filter((w) => w.length > 0);
10944
+ }
10945
+ function findUnguardedTerminalControls(sourceCode) {
10946
+ if (GUARD_RX.test(sourceCode)) return [];
10947
+ const names = /* @__PURE__ */ new Set();
10948
+ for (const m of sourceCode.matchAll(/useAction(?:<[^>]*>)?\(\s*['"`]([^'"`]+)['"`]/g)) {
10949
+ const name = m[1] ?? "";
10950
+ if (nameWords(name).some((w) => TERMINAL_WORDS.has(w))) names.add(name);
10951
+ }
10952
+ for (const m of sourceCode.matchAll(/>([^<>{}]{1,60})<\/Button>/g)) {
10953
+ const label = (m[1] ?? "").replace(/\s+/g, " ").trim();
10954
+ if (label.length > 0 && TERMINAL_LABEL_RX.test(label)) names.add(label.slice(0, 40));
10955
+ }
10956
+ return [...names];
10957
+ }
10958
+ function runTerminalActionUnguarded(input) {
10959
+ if (input.compiledCode === null) return [];
10960
+ const found = findUnguardedTerminalControls(input.sourceCode);
10961
+ if (found.length === 0) return [];
10962
+ const list = found.map((t) => `"${t}"`).join(", ");
10963
+ return [
10964
+ mkIssue(
10965
+ "universal.terminal_action_unguarded",
10966
+ `${list} reads as an action the user means once, and nothing in this component disables the control after it fires \u2014 a double-click sends it twice.`,
10967
+ 'Hold the fired state (`const [submitted, setSubmitted] = useState(false)`), set it in the handler, and pass `disabled={submitted}` to that control with a word that says so ("Submitted"). If the action IS meant to repeat \u2014 sending a message, adding an item \u2014 leave it armed and ignore this.',
10968
+ "warn"
10969
+ )
10970
+ ];
10971
+ }
10858
10972
  var UNIVERSAL_CHECKS = [
10859
10973
  {
10860
10974
  id: "universal.icon_name_known",
@@ -10874,6 +10988,12 @@ var UNIVERSAL_CHECKS = [
10874
10988
  values: ALL_RENDER_VALUES,
10875
10989
  run: runViewportSized
10876
10990
  },
10991
+ {
10992
+ id: "universal.terminal_action_unguarded",
10993
+ axis: "render",
10994
+ values: ALL_RENDER_VALUES,
10995
+ run: runTerminalActionUnguarded
10996
+ },
10877
10997
  {
10878
10998
  id: "universal.accent_text_ink",
10879
10999
  axis: "render",
@@ -12739,7 +12859,8 @@ type ${typeName} = ${tsType};`
12739
12859
  );
12740
12860
  const callSig = tsType === "void" ? "() => void \u2014 fire and forget" : `(data: ${tsType}) => void`;
12741
12861
  const toolHint = tool ? ` \u2192 nextStep: ${tool}` : "";
12742
- actionHookCalls.push(` const ${key} = useAction<${typeName}>('${key}'); // ${callSig}${toolHint}`);
12862
+ const onceHint = " \u2014 if this is meant ONCE, disable its control after it fires";
12863
+ actionHookCalls.push(` const ${key} = useAction<${typeName}>('${key}'); // ${callSig}${toolHint}${onceHint}`);
12743
12864
  }
12744
12865
  const streamChannels = contract?.streamSpec ?? {};
12745
12866
  const streamChannelEntries = Object.entries(streamChannels);
@@ -13085,12 +13206,33 @@ Rules:
13085
13206
  3. Default values come from the current request \u2014 so the component renders correctly standalone.
13086
13207
  4. Copy comes from the props. NEVER invent display text the contract does not carry \u2014 no eyebrow / kicker / overline (a \`<Text caps>\` label), no helper line, no status text, no tagline. A caps label exists only when a prop supplies its text (\`<Text caps>{props.section}</Text>\`); a heading's fallback is the request's own words, never a slogan of your own. Text the agent cannot change is chatter on every render.
13087
13208
  5. Props interface must be typed and exported.`;
13088
- var FRAME_SIZING = `## Sizing \u2014 the frame owns the height
13209
+ var TERMINAL_ACTIONS = `## Actions the user means once
13210
+
13211
+ A second press is a mistake only when it would make a SECOND THING HAPPEN IN THE WORLD \u2014 a second booking, a second charge, a second order, a second application sent. If pressing again would only write the SAME STATE AGAIN \u2014 saving, updating, renaming, setting a preference, toggling \u2014 nothing is duplicated and the control stays armed.
13212
+
13213
+ Guard a control only where you have evidence, not a feeling about the verb: the request itself names a one-time commitment \u2014 "submit the application", "place the order", "confirm the booking".
13214
+
13215
+ **When in doubt, leave it armed.** A control the user cannot press a second time has lost them something that worked \u2014 save, edit, save again is ordinary. A control left armed is only what every interface does by default.
13216
+
13217
+ When you do guard one:
13218
+ - Hold a small piece of state for it and set it in the handler: \`const [submitted, setSubmitted] = useState(false)\`.
13219
+ - \`disabled={submitted}\` on the control that fires it, and say so in the label or beside it ("Submitted", "Request sent") \u2014 a control that is disabled without explanation reads as broken.
13220
+ - A card re-rendered with new props starts fresh; the state above lives with the component, not with the request.
13221
+
13222
+ Nothing in the wire DECLARES one-shot-ness yet, which is why the test is what a second press would DO \u2014 not how final the word sounds.`;
13223
+ var FRAME_SIZING = `## Sizing \u2014 the frame owns the height and the width
13089
13224
 
13090
13225
  The host sizes the iframe; the component never sizes itself to the viewport. NEVER write \`100vh\` / \`100dvh\` / \`100svh\` (or an \`h-screen\` / \`min-h-screen\` class) as a height on any element:
13091
13226
  - An inline card takes its natural height. A content-sized frame is measured FROM the content, so a \`100vh\` root can never shrink and grows the frame on every re-measure.
13092
13227
  - Under fullscreen the frame already stretches your root to its full height. Centre inside it with flex (\`display: flex; flex-direction: column; justify-content: center\`), never with a viewport height.
13093
- - To fill a parent that has a height use \`height: 100%\` or \`flex: 1\`; a viewport unit is only ever a \`max-height\` cap on a scroll region.`;
13228
+ - To fill a parent that has a height use \`height: 100%\` or \`flex: 1\`; a viewport unit is only ever a \`max-height\` cap on a scroll region.
13229
+
13230
+ The width works the same way, and the mistake is the mirror image: **your outermost element FILLS the frame; a width cap belongs INSIDE it, on the column that holds text.**
13231
+
13232
+ - Never put \`maxWidth\` (or a \`max-w-*\` class) on the element you return at the top. On a wide canvas that turns your card into a narrow strip with the frame's ground on either side of it, and on a narrow one it does nothing \u2014 the same composition reading differently at two sizes.
13233
+ - DO cap the reading measure inside: a column of prose is easiest to read at 60\u201370 characters, so wrap the TEXT in a \`<Container maxWidth="sm">\` (or your own \`max-width\`) and leave the root filling. A hero band, a toolbar, a table or an image then still uses the whole width, which is what makes a wide card look composed rather than padded.
13234
+ - Centre that inner column with the container's own centring, not by shrinking the root.
13235
+ - **They are two different elements.** Even when the whole card is one column of text, the root still fills and the column sits INSIDE it \u2014 \`<Box padding="lg"><Container maxWidth="sm">\u2026</Container></Box>\`, never a root that is itself the container. A centred card is centring inside a filled frame, not a shrunken frame.`;
13094
13236
  var COMPONENT_STRUCTURE = `## Component Structure
13095
13237
 
13096
13238
  Keep JSX nesting depth to 3\u20135 levels. When deeper, extract repeated/complex sections into helper components \u2014 named functions defined above the main Component in the same file. Helpers take data + callbacks via props; they don't own state.
@@ -13302,6 +13444,7 @@ ${axisSection}
13302
13444
  CONTRACT_SURFACE,
13303
13445
  DEFENSIVE_CODING,
13304
13446
  GESTURE_ROUTING,
13447
+ TERMINAL_ACTIONS,
13305
13448
  FREE_GESTURE_SURFACE,
13306
13449
  ANTI_PATTERNS,
13307
13450
  CROSS_REFERENCE_RULES,
@@ -13332,11 +13475,11 @@ ${inputs.primitivesDoc}`
13332
13475
  }
13333
13476
  var VIRTUAL_DTS_PATH = "/__gadget__.d.ts";
13334
13477
  var EXTRACTOR_COMPILER_OPTIONS = {
13335
- target: ts2.ScriptTarget.ESNext,
13336
- module: ts2.ModuleKind.ESNext,
13337
- moduleResolution: ts2.ModuleResolutionKind.Bundler,
13478
+ target: ts6.ScriptTarget.ESNext,
13479
+ module: ts6.ModuleKind.ESNext,
13480
+ moduleResolution: ts6.ModuleResolutionKind.Bundler,
13338
13481
  allowJs: false,
13339
- jsx: ts2.JsxEmit.ReactJSX,
13482
+ jsx: ts6.JsxEmit.ReactJSX,
13340
13483
  noEmit: true,
13341
13484
  esModuleInterop: true,
13342
13485
  // skipLibCheck so an unresolvable wrapper-internal import (the
@@ -13348,31 +13491,31 @@ var EXTRACTOR_COMPILER_OPTIONS = {
13348
13491
  var callSignatureCache = /* @__PURE__ */ new Map();
13349
13492
  var componentPropsCache = /* @__PURE__ */ new Map();
13350
13493
  function buildExtractorContext(dtsContent, names) {
13351
- const sourceFile = ts2.createSourceFile(
13494
+ const sourceFile = ts6.createSourceFile(
13352
13495
  VIRTUAL_DTS_PATH,
13353
13496
  dtsContent,
13354
- ts2.ScriptTarget.ESNext,
13497
+ ts6.ScriptTarget.ESNext,
13355
13498
  /* setParentNodes */
13356
13499
  true,
13357
- ts2.ScriptKind.TS
13500
+ ts6.ScriptKind.TS
13358
13501
  );
13359
- const defaultLibName = ts2.getDefaultLibFileName(EXTRACTOR_COMPILER_OPTIONS);
13502
+ const defaultLibName = ts6.getDefaultLibFileName(EXTRACTOR_COMPILER_OPTIONS);
13360
13503
  const host = {
13361
13504
  getSourceFile(fileName) {
13362
13505
  if (fileName === VIRTUAL_DTS_PATH) return sourceFile;
13363
- const libContent = ts2.sys.readFile(
13364
- ts2.getDefaultLibFilePath(EXTRACTOR_COMPILER_OPTIONS).replace(
13506
+ const libContent = ts6.sys.readFile(
13507
+ ts6.getDefaultLibFilePath(EXTRACTOR_COMPILER_OPTIONS).replace(
13365
13508
  /[^/\\]+$/,
13366
13509
  fileName
13367
13510
  )
13368
13511
  );
13369
13512
  if (libContent !== void 0) {
13370
- return ts2.createSourceFile(
13513
+ return ts6.createSourceFile(
13371
13514
  fileName,
13372
13515
  libContent,
13373
- ts2.ScriptTarget.ESNext,
13516
+ ts6.ScriptTarget.ESNext,
13374
13517
  true,
13375
- ts2.ScriptKind.TS
13518
+ ts6.ScriptKind.TS
13376
13519
  );
13377
13520
  }
13378
13521
  return void 0;
@@ -13396,14 +13539,14 @@ function buildExtractorContext(dtsContent, names) {
13396
13539
  },
13397
13540
  fileExists(f) {
13398
13541
  if (f === VIRTUAL_DTS_PATH) return true;
13399
- return ts2.sys.fileExists(f);
13542
+ return ts6.sys.fileExists(f);
13400
13543
  },
13401
13544
  readFile(f) {
13402
13545
  if (f === VIRTUAL_DTS_PATH) return dtsContent;
13403
- return ts2.sys.readFile(f);
13546
+ return ts6.sys.readFile(f);
13404
13547
  }
13405
13548
  };
13406
- const program = ts2.createProgram(
13549
+ const program = ts6.createProgram(
13407
13550
  [VIRTUAL_DTS_PATH],
13408
13551
  EXTRACTOR_COMPILER_OPTIONS,
13409
13552
  host
@@ -13421,9 +13564,9 @@ function buildExtractorContext(dtsContent, names) {
13421
13564
  }
13422
13565
  const MAX_DEPTH2 = 4;
13423
13566
  function renderType(t, depth) {
13424
- const plain = () => checker.typeToString(t, void 0, ts2.TypeFormatFlags.NoTruncation);
13567
+ const plain = () => checker.typeToString(t, void 0, ts6.TypeFormatFlags.NoTruncation);
13425
13568
  if (depth >= MAX_DEPTH2) return plain();
13426
- if ((t.getFlags() & ts2.TypeFlags.Boolean) !== 0) return "boolean";
13569
+ if ((t.getFlags() & ts6.TypeFlags.Boolean) !== 0) return "boolean";
13427
13570
  if (t.isUnion()) {
13428
13571
  return t.types.map((member) => renderType(member, depth)).join(" | ");
13429
13572
  }
@@ -13437,13 +13580,13 @@ function buildExtractorContext(dtsContent, names) {
13437
13580
  const params = cs.getParameters().map((p) => {
13438
13581
  const decl = p.valueDeclaration ?? p.declarations?.[0];
13439
13582
  const pType = decl !== void 0 ? checker.getTypeOfSymbolAtLocation(p, decl) : checker.getDeclaredTypeOfSymbol(p);
13440
- const optional = decl !== void 0 && ts2.isParameter(decl) && (decl.questionToken !== void 0 || decl.initializer !== void 0);
13583
+ const optional = decl !== void 0 && ts6.isParameter(decl) && (decl.questionToken !== void 0 || decl.initializer !== void 0);
13441
13584
  return `${p.getName()}${optional ? "?" : ""}: ${renderType(pType, depth + 1)}`;
13442
13585
  }).join(", ");
13443
13586
  const ret = renderType(cs.getReturnType(), depth + 1);
13444
13587
  return `(${params}) => ${ret}`;
13445
13588
  }
13446
- const isObject = (t.getFlags() & ts2.TypeFlags.Object) !== 0;
13589
+ const isObject = (t.getFlags() & ts6.TypeFlags.Object) !== 0;
13447
13590
  const isArrayOrTuple = checker.isArrayType(t) || checker.isTupleType(t);
13448
13591
  const typeArgs = t.typeArguments;
13449
13592
  if (symbol !== void 0 && isObject && !isArrayOrTuple && !isWrapperLocal(symbol) && typeArgs !== void 0 && typeArgs.length > 0) {
@@ -13456,7 +13599,7 @@ function buildExtractorContext(dtsContent, names) {
13456
13599
  const body = props.map((p) => {
13457
13600
  const decl = p.valueDeclaration ?? p.declarations?.[0];
13458
13601
  const pType = decl !== void 0 ? checker.getTypeOfSymbolAtLocation(p, decl) : checker.getDeclaredTypeOfSymbol(p);
13459
- const optional = (p.getFlags() & ts2.SymbolFlags.Optional) !== 0;
13602
+ const optional = (p.getFlags() & ts6.SymbolFlags.Optional) !== 0;
13460
13603
  return `${p.getName()}${optional ? "?" : ""}: ${renderType(pType, depth + 1)}`;
13461
13604
  }).join("; ");
13462
13605
  return `{ ${body} }`;
@@ -13471,7 +13614,7 @@ function buildExtractorContext(dtsContent, names) {
13471
13614
  const name = symbol.getName();
13472
13615
  if (!requested.has(name)) continue;
13473
13616
  if (signaturesByName.has(name)) continue;
13474
- const resolved2 = (symbol.flags & ts2.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
13617
+ const resolved2 = (symbol.flags & ts6.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
13475
13618
  const declarations = resolved2.getDeclarations();
13476
13619
  if (declarations === void 0 || declarations.length === 0) continue;
13477
13620
  const declaration = declarations[0];
@@ -13486,7 +13629,7 @@ function printCallSignature(sig, ctx) {
13486
13629
  const params = sig.getParameters().map((p) => {
13487
13630
  const decl = p.valueDeclaration ?? p.declarations?.[0];
13488
13631
  const pType = decl !== void 0 ? ctx.checker.getTypeOfSymbolAtLocation(p, decl) : ctx.checker.getDeclaredTypeOfSymbol(p);
13489
- const optional = decl !== void 0 && ts2.isParameter(decl) && (decl.questionToken !== void 0 || decl.initializer !== void 0);
13632
+ const optional = decl !== void 0 && ts6.isParameter(decl) && (decl.questionToken !== void 0 || decl.initializer !== void 0);
13490
13633
  return `${p.getName()}${optional ? "?" : ""}: ${ctx.renderType(pType, 0)}`;
13491
13634
  }).join(", ");
13492
13635
  const ret = ctx.renderType(sig.getReturnType(), 0);
@@ -13700,6 +13843,7 @@ ${axisSection}
13700
13843
  CONTRACT_SURFACE,
13701
13844
  DEFENSIVE_CODING,
13702
13845
  GESTURE_ROUTING,
13846
+ TERMINAL_ACTIONS,
13703
13847
  INTERACTIVE_TRAITS,
13704
13848
  ANTI_PATTERNS,
13705
13849
  CROSS_REFERENCE_RULES,
@@ -15091,7 +15235,7 @@ var HOST_CLICK_TAGS = /* @__PURE__ */ new Set(["button", "a", "div", "span", "li
15091
15235
  var HOST_CHANGE_TAGS = /* @__PURE__ */ new Set(["select", "input", "textarea"]);
15092
15236
  function findWiring(input) {
15093
15237
  const { sourceCode, hookName, hookArg } = input;
15094
- const sf = ts2.createSourceFile("Component.tsx", sourceCode, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
15238
+ const sf = ts6.createSourceFile("Component.tsx", sourceCode, ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TSX);
15095
15239
  const hookBindings = findHookBindings(sf, hookName, hookArg);
15096
15240
  if (hookBindings.length === 0) {
15097
15241
  return {
@@ -15114,7 +15258,7 @@ function findWiring(input) {
15114
15258
  const customPropElements = [];
15115
15259
  const submitButton = { found: false };
15116
15260
  function visit(node) {
15117
- if (ts2.isJsxAttribute(node) && node.initializer) {
15261
+ if (ts6.isJsxAttribute(node) && node.initializer) {
15118
15262
  const attrName = node.name.getText(sf);
15119
15263
  const initRefs = findReferencedNames(node.initializer, callableNames);
15120
15264
  if (initRefs.size > 0) {
@@ -15152,19 +15296,19 @@ function findWiring(input) {
15152
15296
  }
15153
15297
  }
15154
15298
  }
15155
- if (ts2.isJsxOpeningLikeElement(node)) {
15299
+ if (ts6.isJsxOpeningLikeElement(node)) {
15156
15300
  const tag = getTagName(node);
15157
15301
  if ((tag ?? "").toLowerCase() === "button") {
15158
15302
  const typeAttr = node.attributes.properties.find(
15159
- (p) => ts2.isJsxAttribute(p) && p.name.getText(sf) === "type"
15303
+ (p) => ts6.isJsxAttribute(p) && p.name.getText(sf) === "type"
15160
15304
  );
15161
- if (typeAttr && ts2.isJsxAttribute(typeAttr) && typeAttr.initializer) {
15305
+ if (typeAttr && ts6.isJsxAttribute(typeAttr) && typeAttr.initializer) {
15162
15306
  const v = typeAttr.initializer.getText(sf).toLowerCase();
15163
15307
  if (v.includes("submit")) submitButton.found = true;
15164
15308
  }
15165
15309
  }
15166
15310
  }
15167
- ts2.forEachChild(node, visit);
15311
+ ts6.forEachChild(node, visit);
15168
15312
  }
15169
15313
  visit(sf);
15170
15314
  if (sawClickOnHost) {
@@ -15201,32 +15345,32 @@ function findWiring(input) {
15201
15345
  function findHookBindings(sf, hookName, hookArg) {
15202
15346
  const bindings = [];
15203
15347
  function visit(node) {
15204
- if (ts2.isVariableDeclaration(node) && node.initializer && ts2.isCallExpression(node.initializer)) {
15348
+ if (ts6.isVariableDeclaration(node) && node.initializer && ts6.isCallExpression(node.initializer)) {
15205
15349
  const call = node.initializer;
15206
15350
  const callee = call.expression.getText(sf);
15207
15351
  if (callee !== hookName) {
15208
- ts2.forEachChild(node, visit);
15352
+ ts6.forEachChild(node, visit);
15209
15353
  return;
15210
15354
  }
15211
15355
  const firstArg = call.arguments[0];
15212
- if (!firstArg || !ts2.isStringLiteral(firstArg)) {
15213
- ts2.forEachChild(node, visit);
15356
+ if (!firstArg || !ts6.isStringLiteral(firstArg)) {
15357
+ ts6.forEachChild(node, visit);
15214
15358
  return;
15215
15359
  }
15216
15360
  if (firstArg.text !== hookArg) {
15217
- ts2.forEachChild(node, visit);
15361
+ ts6.forEachChild(node, visit);
15218
15362
  return;
15219
15363
  }
15220
- if (ts2.isIdentifier(node.name)) {
15364
+ if (ts6.isIdentifier(node.name)) {
15221
15365
  bindings.push(node.name.text);
15222
- } else if (ts2.isObjectBindingPattern(node.name)) {
15366
+ } else if (ts6.isObjectBindingPattern(node.name)) {
15223
15367
  for (const elem of node.name.elements) {
15224
15368
  const target = elem.name;
15225
- if (ts2.isIdentifier(target)) bindings.push(target.text);
15369
+ if (ts6.isIdentifier(target)) bindings.push(target.text);
15226
15370
  }
15227
15371
  }
15228
15372
  }
15229
- ts2.forEachChild(node, visit);
15373
+ ts6.forEachChild(node, visit);
15230
15374
  }
15231
15375
  visit(sf);
15232
15376
  return bindings;
@@ -15234,24 +15378,24 @@ function findHookBindings(sf, hookName, hookArg) {
15234
15378
  function expandAliases(sf, bindings) {
15235
15379
  const all = new Set(bindings);
15236
15380
  function visit(node) {
15237
- if (ts2.isVariableDeclaration(node) && node.initializer && ts2.isIdentifier(node.name)) {
15381
+ if (ts6.isVariableDeclaration(node) && node.initializer && ts6.isIdentifier(node.name)) {
15238
15382
  const newName = node.name.text;
15239
15383
  const init = node.initializer;
15240
- if (ts2.isIdentifier(init) && all.has(init.text)) {
15384
+ if (ts6.isIdentifier(init) && all.has(init.text)) {
15241
15385
  all.add(newName);
15242
15386
  }
15243
- if (ts2.isArrowFunction(init) || ts2.isFunctionExpression(init)) {
15387
+ if (ts6.isArrowFunction(init) || ts6.isFunctionExpression(init)) {
15244
15388
  if (bodyReferences(init.body, all)) {
15245
15389
  all.add(newName);
15246
15390
  }
15247
15391
  }
15248
- if (ts2.isCallExpression(init)) {
15392
+ if (ts6.isCallExpression(init)) {
15249
15393
  if (bodyReferences(init, all)) {
15250
15394
  all.add(newName);
15251
15395
  }
15252
15396
  }
15253
15397
  }
15254
- ts2.forEachChild(node, visit);
15398
+ ts6.forEachChild(node, visit);
15255
15399
  }
15256
15400
  visit(sf);
15257
15401
  return all;
@@ -15260,11 +15404,11 @@ function bodyReferences(body, names) {
15260
15404
  let found = false;
15261
15405
  function walk(n) {
15262
15406
  if (found) return;
15263
- if (ts2.isIdentifier(n) && names.has(n.text)) {
15407
+ if (ts6.isIdentifier(n) && names.has(n.text)) {
15264
15408
  found = true;
15265
15409
  return;
15266
15410
  }
15267
- ts2.forEachChild(n, walk);
15411
+ ts6.forEachChild(n, walk);
15268
15412
  }
15269
15413
  walk(body);
15270
15414
  return found;
@@ -15272,16 +15416,16 @@ function bodyReferences(body, names) {
15272
15416
  function findReferencedNames(node, names) {
15273
15417
  const found = /* @__PURE__ */ new Set();
15274
15418
  function walk(n) {
15275
- if (ts2.isIdentifier(n) && names.has(n.text)) {
15419
+ if (ts6.isIdentifier(n) && names.has(n.text)) {
15276
15420
  found.add(n.text);
15277
15421
  }
15278
- ts2.forEachChild(n, walk);
15422
+ ts6.forEachChild(n, walk);
15279
15423
  }
15280
15424
  walk(node);
15281
15425
  return found;
15282
15426
  }
15283
15427
  function getTagName(el) {
15284
- if (ts2.isJsxOpeningLikeElement(el)) {
15428
+ if (ts6.isJsxOpeningLikeElement(el)) {
15285
15429
  return el.tagName.getText();
15286
15430
  }
15287
15431
  return null;