@ggui-ai/ui-gen 0.19.0 → 0.20.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.
@@ -20,6 +20,7 @@ import { Readable } from 'stream';
20
20
  import { pipeline } from 'stream/promises';
21
21
  import { createBrotliDecompress, createUnzip } from 'zlib';
22
22
  import { LUCIDE_ICON_NAMES, maxWidth } from '@ggui-ai/design';
23
+ import { primeInputs } from '@ggui-ai/ui-visual-tester/prime-inputs';
23
24
  import git from 'isomorphic-git';
24
25
  import { Volume, createFsFromVolume } from 'memfs';
25
26
  import { createPatch, applyPatch } from 'diff';
@@ -11048,6 +11049,46 @@ function runRootWidthCap(input) {
11048
11049
  )
11049
11050
  ];
11050
11051
  }
11052
+ var LABEL_SPECIAL_CHAR = /[^a-z0-9\s]/i;
11053
+ var normText = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
11054
+ var alnumText = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
11055
+ function visibleText(sourceCode) {
11056
+ const jsx = (sourceCode.match(/>([^<>]*)</g) ?? []).map((m2) => m2.slice(1, -1).replace(/\{[^}]*\}/g, " ")).join(" ");
11057
+ let attrs = "";
11058
+ const attrRx = /\b(?:aria-label|placeholder|title|alt)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
11059
+ let m;
11060
+ while ((m = attrRx.exec(sourceCode)) !== null) attrs += " " + (m[1] ?? m[2] ?? "");
11061
+ return jsx + " " + attrs;
11062
+ }
11063
+ function findDroppedActionLabels(sourceCode, contract) {
11064
+ const actionSpec = contract?.actionSpec;
11065
+ if (actionSpec === void 0) return [];
11066
+ if (/\.label\b/.test(sourceCode)) return [];
11067
+ const vis = visibleText(sourceCode);
11068
+ const normVis = normText(vis);
11069
+ const alnumVis = alnumText(vis);
11070
+ const out = [];
11071
+ for (const [name, entry] of Object.entries(actionSpec)) {
11072
+ const label = entry.label;
11073
+ if (typeof label !== "string" || label.length === 0 || label === name) continue;
11074
+ if (!LABEL_SPECIAL_CHAR.test(label)) continue;
11075
+ if (alnumText(label).length < 3) continue;
11076
+ if (normVis.includes(normText(label))) continue;
11077
+ if (alnumVis.includes(alnumText(label))) out.push({ name, label });
11078
+ }
11079
+ return out;
11080
+ }
11081
+ function runActionLabelDropped(input) {
11082
+ if (input.compiledCode === null) return [];
11083
+ return findDroppedActionLabels(input.sourceCode, input.contract).map(
11084
+ ({ name, label }) => mkIssue(
11085
+ "universal.action_label_dropped",
11086
+ `The action "${name}" declares label "${label}", but the rendered control appears to drop its "${label.replace(/[a-z0-9\s]/gi, "").trim()}": the label's words are in the generated source, the full label is not \u2014 a transcription drop (ggui#1190).`,
11087
+ `Render the label EXACTLY as the contract states it \u2014 button text should be the verbatim \`actionSpec.${name}.label\`, or render it from data (\`{x.label}\`), never a re-typed copy that drops "&", "/", "+", etc.`,
11088
+ "warn"
11089
+ )
11090
+ );
11091
+ }
11051
11092
  var UNIVERSAL_CHECKS = [
11052
11093
  {
11053
11094
  id: "universal.icon_name_known",
@@ -11073,6 +11114,12 @@ var UNIVERSAL_CHECKS = [
11073
11114
  values: ALL_RENDER_VALUES,
11074
11115
  run: runRootWidthCap
11075
11116
  },
11117
+ {
11118
+ id: "universal.action_label_dropped",
11119
+ axis: "render",
11120
+ values: ALL_RENDER_VALUES,
11121
+ run: runActionLabelDropped
11122
+ },
11076
11123
  {
11077
11124
  id: "universal.terminal_action_unguarded",
11078
11125
  axis: "render",
@@ -15635,8 +15682,6 @@ function editableSurface(el) {
15635
15682
  function parentLink(node) {
15636
15683
  return node;
15637
15684
  }
15638
-
15639
- // src/harness/check/runtime-render/render-check.ts
15640
15685
  async function runRenderCheck(input) {
15641
15686
  const g = hostGlobals();
15642
15687
  if ("window" in g && "document" in g) {
@@ -15815,6 +15860,10 @@ async function runRenderCheckInProcess(input) {
15815
15860
  let actionsChecked = 0;
15816
15861
  let streamsChecked = 0;
15817
15862
  try {
15863
+ try {
15864
+ primeInputs(renderResult.container);
15865
+ } catch {
15866
+ }
15818
15867
  if (input.contract?.actionSpec) {
15819
15868
  const actionSpec = input.contract.actionSpec;
15820
15869
  for (const [name, entry] of Object.entries(actionSpec)) {