@ggui-ai/ui-gen 0.27.0 → 0.28.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.
@@ -146,10 +146,96 @@ function getInitialValuePropNames(contract) {
146
146
  }
147
147
  return names;
148
148
  }
149
+ function objectLiteralKeysAt(src, open) {
150
+ if (src[open] !== "{") return void 0;
151
+ const keys = [];
152
+ let depth = 0;
153
+ let expectKey = true;
154
+ for (let i = open; i < src.length; i++) {
155
+ const c = src[i];
156
+ if (c === '"' || c === "'" || c === "`") {
157
+ let j = i + 1;
158
+ while (j < src.length && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
159
+ if (depth === 1 && expectKey && /^\s*:/.test(src.slice(j + 1))) keys.push(src.slice(i + 1, j));
160
+ i = j;
161
+ expectKey = false;
162
+ continue;
163
+ }
164
+ if (c === "{" || c === "[" || c === "(") {
165
+ depth++;
166
+ if (depth === 1) expectKey = true;
167
+ continue;
168
+ }
169
+ if (c === "}" || c === "]" || c === ")") {
170
+ depth--;
171
+ if (depth === 0) return keys;
172
+ continue;
173
+ }
174
+ if (depth !== 1) continue;
175
+ if (c === ",") {
176
+ expectKey = true;
177
+ continue;
178
+ }
179
+ if (expectKey && /[A-Za-z_$]/.test(c ?? "")) {
180
+ const m = /^([A-Za-z_$][\w$]*)\s*(:|,|\})/.exec(src.slice(i));
181
+ if (m !== null && m[1] !== void 0) keys.push(m[1]);
182
+ expectKey = false;
183
+ }
184
+ }
185
+ return keys;
186
+ }
187
+ function callArgsAt(src, open) {
188
+ const args = [];
189
+ let depth = 0;
190
+ let start = open + 1;
191
+ for (let i = open; i < src.length; i++) {
192
+ const c = src[i];
193
+ if (c === '"' || c === "'" || c === "`") {
194
+ let j = i + 1;
195
+ while (j < src.length && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
196
+ i = j;
197
+ continue;
198
+ }
199
+ if (c === "(" || c === "{" || c === "[") depth++;
200
+ else if (c === ")" || c === "}" || c === "]") {
201
+ depth--;
202
+ if (depth === 0) {
203
+ args.push(src.slice(start, i));
204
+ return args;
205
+ }
206
+ } else if (c === "," && depth === 1) {
207
+ args.push(src.slice(start, i));
208
+ start = i + 1;
209
+ }
210
+ }
211
+ return args;
212
+ }
213
+ function initialStateKeys(src, argStart, argText) {
214
+ const lead = argText.length - argText.trimStart().length;
215
+ let at = argStart + lead;
216
+ let text = argText.trim();
217
+ const lazy = /^\(\s*\)\s*=>\s*\(?\s*/.exec(text);
218
+ if (lazy !== null) {
219
+ at += lazy[0].length;
220
+ text = text.slice(lazy[0].length);
221
+ }
222
+ if (text.startsWith("{")) return objectLiteralKeysAt(src, at) ?? [];
223
+ const ident = /^([A-Za-z_$][\w$]*)\s*\)?\s*$/.exec(text);
224
+ if (ident === null || ident[1] === void 0) return [];
225
+ const decls = [...src.matchAll(new RegExp(`(?:const|let|var)\\s+${ident[1]}\\s*(?::[^=]{1,200})?=\\s*`, "g"))];
226
+ const decl = decls.length === 1 ? decls[0] : void 0;
227
+ if (decl === void 0) return [];
228
+ return objectLiteralKeysAt(src, (decl.index ?? 0) + decl[0].length) ?? [];
229
+ }
149
230
  function collectStateKeys(src) {
150
231
  const keys = /* @__PURE__ */ new Set();
151
232
  const varRe = /const\s*\[\s*(\w+)\s*,\s*(\w+)\s*\]\s*=\s*useState/g;
152
233
  for (const m of src.matchAll(varRe)) keys.add(m[1]);
234
+ const contextRe = /const\s*\[\s*(\w+)\s*,\s*\w+\s*\]\s*=\s*useGguiContext\s*(?:<[^>]*>)?\s*\(\s*['"`](\w+)['"`]/g;
235
+ for (const m of src.matchAll(contextRe)) {
236
+ keys.add(m[1]);
237
+ keys.add(m[2]);
238
+ }
153
239
  const objRe = /useState(?:<[^>]*>)?\s*\(\s*\{([\s\S]*?)\}\s*\)/g;
154
240
  for (const m of src.matchAll(objRe)) {
155
241
  const keyRe = /(?:^|,)\s*(\w+)\s*:/g;
@@ -160,6 +246,16 @@ function collectStateKeys(src) {
160
246
  const keyRe = /(?:^|,)\s*(\w+)\s*:/g;
161
247
  for (const km of m[1].matchAll(keyRe)) keys.add(km[1]);
162
248
  }
249
+ for (const m of src.matchAll(/\b(useState|useReducer)\s*(?:<[^>]*>)?\s*\(/g)) {
250
+ const open = (m.index ?? 0) + m[0].length - 1;
251
+ const args = callArgsAt(src, open);
252
+ const which = m[1] === "useReducer" ? 1 : 0;
253
+ const arg = args[which];
254
+ if (arg === void 0) continue;
255
+ let argStart = open + 1;
256
+ for (let k = 0; k < which; k++) argStart += (args[k]?.length ?? 0) + 1;
257
+ for (const key of initialStateKeys(src, argStart, arg)) keys.add(key);
258
+ }
163
259
  return keys;
164
260
  }
165
261
  function mkIssue(subcategory, description, fix, result = "fail") {
@@ -772,7 +868,7 @@ function runNoHardcodedEntities(input) {
772
868
  mkIssue(
773
869
  "state.merge.no_hardcoded_entities",
774
870
  `Hardcoded entity array literal (multiple objects with "${idField}") in the component \u2014 entity data should come from state/props.`,
775
- `Remove the literal array. Seed state from props.{entityProp} and merge updates via stream.`
871
+ `Remove the literal array: this data comes from ${all.filter((e) => e.idField === idField).map((e) => `props.${e.name}`).join(" / ") || "props"}. Read it there (\`?? []\` for an absent value, never a literal default), seed state from it, and merge updates via stream.`
776
872
  )
777
873
  );
778
874
  }