@ggui-ai/ui-gen 0.15.0 → 0.16.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.
- package/dist/adapters/generation-dispatch.d.ts +21 -4
- package/dist/adapters/generation-dispatch.js +913 -350
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +26 -22
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +17 -12
- package/dist/advanced/index.js +966 -374
- package/dist/advanced/index.js.map +1 -1
- package/dist/boilerplate.d.ts +16 -1
- package/dist/boilerplate.js +579 -245
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +17 -3
- package/dist/check/index.js +32 -25
- package/dist/check/index.js.map +1 -1
- package/dist/{create-ui-generator-D6TKuv9V.d.ts → create-ui-generator-CCIeQaEe.d.ts} +77 -10
- package/dist/design-mode-BHEE7flj.d.ts +67 -0
- package/dist/{dispatch-BuZfTh9r.d.ts → dispatch-BA5dJcg-.d.ts} +4 -1
- package/dist/evaluation/axis-checks/index.d.ts +4 -3
- package/dist/evaluation/axis-checks/index.js +3 -1
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +2 -1
- package/dist/evaluation/axis-checks/registry.js +1 -0
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +143 -3
- package/dist/evaluation/index.js +3866 -92
- package/dist/evaluation/index.js.map +1 -1
- package/dist/{generate-BTfvELgl.d.ts → generate-8L_bc2iP.d.ts} +10 -1
- package/dist/harness/check/runtime-render/index.d.ts +2 -1
- package/dist/harness/index.d.ts +2 -1
- package/dist/harness/index.js +589 -248
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.d.ts +3 -3
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.d.ts +2 -1
- package/dist/harness/prompts.js +3 -0
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +17 -5
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +19 -3
- package/dist/harness/runtime.js +602 -261
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +28 -1
- package/dist/harness/types-public.js +589 -248
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +2 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +973 -372
- package/dist/index.js.map +1 -1
- package/dist/patch.d.ts +2 -1
- package/dist/{prompts-BVhtH3M1.d.ts → prompts-k6m6reqe.d.ts} +11 -1
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/tools/get-primitives-ts.d.ts +1 -1
- package/dist/tools/get-primitives-ts.js +1 -1
- package/dist/tools/get-primitives-ts.js.map +1 -1
- package/dist/{types-public-CkNWEov9.d.ts → types-public-D24JLJgl.d.ts} +49 -5
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +4 -4
- package/dist/validation/index.js.map +1 -1
- package/dist/workflows.d.ts +2 -1
- package/package.json +12 -12
- package/src/adapters/generation-dispatch.ts +57 -4
- package/src/adapters/provider-router.ts +7 -6
- package/src/adapters/tools.ts +5 -5
- package/src/advanced/generator.ts +11 -10
- package/src/advanced/index.ts +5 -4
- package/src/boilerplate/free-design-prompt.ts +329 -0
- package/src/boilerplate/generate.ts +10 -1
- package/src/boilerplate/hard-sections.ts +242 -0
- package/src/boilerplate/render.ts +32 -8
- package/src/boilerplate/system-prompt.ts +81 -229
- package/src/boilerplate/templates/base-free.tsx.tmpl +24 -0
- package/src/check/run-tier0.ts +80 -20
- package/src/coding-agent/tools.ts +8 -2
- package/src/contract-context.ts +28 -0
- package/src/create-harness.ts +11 -0
- package/src/create-ui-generator.ts +71 -25
- package/src/design-mode.ts +182 -0
- package/src/design-system-docs.ts +17 -13
- package/src/evaluation/axis-checks/dispatch.ts +4 -0
- package/src/evaluation/axis-checks/extras.ts +5 -0
- package/src/evaluation/cost-tracker.ts +2 -3
- package/src/evaluation/index.ts +46 -2
- package/src/evaluation/llm-evaluator.ts +77 -21
- package/src/evaluation/types-public.ts +103 -8
- package/src/evaluation/visual-evaluator.ts +301 -29
- package/src/harness/coding/dupe-break.ts +0 -0
- package/src/harness/coding/init-session.ts +1 -0
- package/src/harness/coding/run-coding-turn.ts +3 -0
- package/src/harness/coding/run-eval-round.ts +15 -2
- package/src/harness/llm-trace-sink.ts +3 -3
- package/src/harness/result-types.ts +15 -3
- package/src/harness/runtime.ts +18 -0
- package/src/harness/types-public.ts +27 -0
- package/src/index.ts +26 -0
- package/src/internal/extract-call-signatures.ts +2 -2
- package/src/providers/bedrock.ts +4 -4
- package/src/run-check.ts +1 -0
- package/src/tools/get-primitives-ts.ts +1 -1
- package/src/validation/allowed-imports.ts +8 -2
- package/src/validation/primitives.ts +1 -1
package/dist/check/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DataContract, JsonObject, PropsSpec, ActionSpec, StreamSpec } from '@ggui-ai/protocol';
|
|
2
|
-
import {
|
|
2
|
+
import { D as DesignMode } from '../design-mode-BHEE7flj.js';
|
|
3
|
+
import { b as EvalResult, E as EvalIssue } from '../types-public-D24JLJgl.js';
|
|
3
4
|
export { j as jsonSchemaTypeToTs } from '../json-schema-ts-CbB78b3n.js';
|
|
4
5
|
import '../axes-CzLEMDeB.js';
|
|
5
6
|
import '../types-BOvHNG7K.js';
|
|
@@ -223,10 +224,23 @@ declare function runTier0Checks(sourceCode: string, contract?: DataContract, bui
|
|
|
223
224
|
* resolves against the real declaration (strict option/return
|
|
224
225
|
* narrowing). Standard-library-only callers omit it.
|
|
225
226
|
*/
|
|
226
|
-
gadgetTypes?: Readonly<Record<string, string
|
|
227
|
+
gadgetTypes?: Readonly<Record<string, string>>,
|
|
228
|
+
/**
|
|
229
|
+
* Which triad produced the source. `constrained` (default) runs every
|
|
230
|
+
* leg exactly as before. `free` gates OFF the design-VOCABULARY legs —
|
|
231
|
+
* `raw-spacing`, `raw-pixels`, `numeric-spacing-prop`, the
|
|
232
|
+
* `stack-row-*` prop checks and `clickable-wrapper` — because raw
|
|
233
|
+
* elements, inline CSS and literal spacing are first-class there. It
|
|
234
|
+
* KEEPS every contract leg: `hex-color`, `hardcoded-color-fn`,
|
|
235
|
+
* `named-color`, `token-fallback`, `off-manifest-token`,
|
|
236
|
+
* `asset-color-pair` (color stays on the closed token manifest),
|
|
237
|
+
* imports, security, Props / default-export, wire_* and gadget checks,
|
|
238
|
+
* and the double-wired-action detector (retargeted at raw elements).
|
|
239
|
+
*/
|
|
240
|
+
designMode?: DesignMode): Promise<EvalIssue[]>;
|
|
227
241
|
/**
|
|
228
242
|
* Run tier 0 checks and return a full EvalResult with pass list.
|
|
229
243
|
*/
|
|
230
|
-
declare function runTier0(sourceCode: string, contract?: DataContract): Promise<EvalResult>;
|
|
244
|
+
declare function runTier0(sourceCode: string, contract?: DataContract, designMode?: DesignMode): Promise<EvalResult>;
|
|
231
245
|
|
|
232
246
|
export { type ContractIssue, type ReactLintDiagnostic, type TypeCheckDiagnostic, type TypeCheckResult, type WireCallSite, type WireImportReport, type WireImportSite, type WireKind, type WirePreservationReport, checkWireImports, checkWirePreservation, collectExpectedWires, extractPropsInterface, extractWireCallSites, extractWireImports, inferPropsSpecFromSampleData, lintReactHooks, propsSpecToTypeScript, runTier0, runTier0Checks, typecheck, validateActionSpecConformance, validateAllContracts, validatePropsAgainstSchema, validateStreamSpecConformance };
|
package/dist/check/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import ts4 from 'typescript';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { createRequire } from 'module';
|
|
5
|
+
import { FORBIDDEN_IMPORT_SPECIFIERS } from '@ggui-ai/design/rendering';
|
|
5
6
|
import { Linter } from 'eslint';
|
|
6
7
|
import { listContractGadgets, HOOK_NAME_RE } from '@ggui-ai/protocol';
|
|
7
8
|
import { consumedTokenManifest } from '@ggui-ai/design/themes';
|
|
@@ -395,8 +396,6 @@ function inferJsonSchema(value) {
|
|
|
395
396
|
}
|
|
396
397
|
return { type: "string" };
|
|
397
398
|
}
|
|
398
|
-
|
|
399
|
-
// src/validation/allowed-imports.ts
|
|
400
399
|
var ALLOWED_IMPORT_BASES = [
|
|
401
400
|
"react",
|
|
402
401
|
"react-dom",
|
|
@@ -405,13 +404,14 @@ var ALLOWED_IMPORT_BASES = [
|
|
|
405
404
|
"@ggui-ai/gadgets"
|
|
406
405
|
];
|
|
407
406
|
function isAllowedImport(specifier, gadgetPackages) {
|
|
407
|
+
if (FORBIDDEN_IMPORT_SPECIFIERS.includes(specifier)) return false;
|
|
408
408
|
for (const base of ALLOWED_IMPORT_BASES) {
|
|
409
409
|
if (specifier === base || specifier.startsWith(`${base}/`)) return true;
|
|
410
410
|
}
|
|
411
411
|
return gadgetPackages?.has(specifier) ?? false;
|
|
412
412
|
}
|
|
413
413
|
function describeAllowedImports() {
|
|
414
|
-
return "react, @ggui-ai/design, @ggui-ai/wire, @ggui-ai/gadgets, or a gadget package declared on the contract";
|
|
414
|
+
return "react, @ggui-ai/design, @ggui-ai/wire, @ggui-ai/gadgets, or a gadget package declared on the contract \u2014 never @ggui-ai/wire/internal (the writer side of the wire; components read useRender().isConnected)";
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
// src/check/type-checker.ts
|
|
@@ -877,6 +877,9 @@ function generateReactFix(ruleId, message) {
|
|
|
877
877
|
return "Fix the React violation.";
|
|
878
878
|
}
|
|
879
879
|
|
|
880
|
+
// src/design-mode.ts
|
|
881
|
+
var DEFAULT_DESIGN_MODE = "constrained";
|
|
882
|
+
|
|
880
883
|
// src/evaluation/types-public.ts
|
|
881
884
|
function priorityForIssue(category) {
|
|
882
885
|
if (category === "interactivity" || category === "accessibility" || category === "layout" || category === "loading" || category === "visual") {
|
|
@@ -904,10 +907,11 @@ function stripComments(code) {
|
|
|
904
907
|
}
|
|
905
908
|
return out;
|
|
906
909
|
}
|
|
907
|
-
function detectCertainDoubleWiredActions(sourceCode, actionBindings) {
|
|
910
|
+
function detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode = DEFAULT_DESIGN_MODE) {
|
|
908
911
|
const issues = [];
|
|
909
912
|
if (actionBindings.length === 0) return issues;
|
|
910
913
|
const bindings = new Set(actionBindings);
|
|
914
|
+
const anyElementIsInteractive = designMode === "free";
|
|
911
915
|
const TRAIT_HOST_TAGS = /* @__PURE__ */ new Set(["Card", "Box", "Stack", "Row"]);
|
|
912
916
|
const TRAITS_THAT_FIRE = /* @__PURE__ */ new Set(["Clickable", "Pressable"]);
|
|
913
917
|
const INTERACTIVE_DESCENDANTS = /* @__PURE__ */ new Set([
|
|
@@ -943,7 +947,9 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings) {
|
|
|
943
947
|
}
|
|
944
948
|
function isTraitHostWithFiringAs(node) {
|
|
945
949
|
const tag = tagNameText(node);
|
|
946
|
-
if (tag === void 0
|
|
950
|
+
if (tag === void 0) return false;
|
|
951
|
+
if (anyElementIsInteractive) return true;
|
|
952
|
+
if (!TRAIT_HOST_TAGS.has(tag)) return false;
|
|
947
953
|
const asExpr = attrExpression(node, "as");
|
|
948
954
|
return asExpr !== void 0 && ts4.isIdentifier(asExpr) && TRAITS_THAT_FIRE.has(asExpr.text);
|
|
949
955
|
}
|
|
@@ -972,7 +978,7 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings) {
|
|
|
972
978
|
const opening = ts4.isJsxElement(node) ? node.openingElement : ts4.isJsxSelfClosingElement(node) ? node : void 0;
|
|
973
979
|
if (opening !== void 0) {
|
|
974
980
|
const tag = tagNameText(opening);
|
|
975
|
-
if (tag !== void 0 && INTERACTIVE_DESCENDANTS.has(tag)) {
|
|
981
|
+
if (tag !== void 0 && (anyElementIsInteractive || INTERACTIVE_DESCENDANTS.has(tag))) {
|
|
976
982
|
for (const attrName of HANDLER_ATTRS) {
|
|
977
983
|
const callee = extractCalleeName(attrExpression(opening, attrName));
|
|
978
984
|
if (callee === expectedBinding) {
|
|
@@ -998,14 +1004,15 @@ function detectCertainDoubleWiredActions(sourceCode, actionBindings) {
|
|
|
998
1004
|
if (match !== void 0) {
|
|
999
1005
|
const outerTag = tagNameText(node.openingElement);
|
|
1000
1006
|
const outerLine = sf.getLineAndCharacterOfPosition(node.openingElement.getStart()).line + 1;
|
|
1007
|
+
const outerLabel = anyElementIsInteractive ? `<${outerTag}>` : `<${outerTag} as={...}>`;
|
|
1001
1008
|
issues.push({
|
|
1002
1009
|
tier: 0,
|
|
1003
1010
|
result: "fail",
|
|
1004
1011
|
category: "interactivity",
|
|
1005
1012
|
subcategory: "double-wired-action:certain",
|
|
1006
1013
|
severity: "critical",
|
|
1007
|
-
description: `Nested-interactive double-wire: outer
|
|
1008
|
-
fix: `Pick ONE surface for the gesture: either drop \`as={...}\` + onClick on the outer <${outerTag}> and let the inner <${match.tag}> own the gesture, OR remove the inner <${match.tag}> and let the outer <${outerTag} as={...}> own it. Don't wire both to the same useAction binding.`,
|
|
1014
|
+
description: `Nested-interactive double-wire: outer ${outerLabel} at line ${outerLine} and inner <${match.tag}> at line ${match.line} both dispatch the same useAction binding '${outerCallee}'. One user click on the inner control fires its handler AND bubbles to the outer handler \u2014 '${outerCallee}' dispatches TWICE, the action runs back-to-back, and a toggle-style action silently reverts the user's change.`,
|
|
1015
|
+
fix: anyElementIsInteractive ? `Pick ONE gesture surface for '${outerCallee}': either remove the onClick from the outer <${outerTag}> and let the inner <${match.tag}> own the gesture, OR drop the inner <${match.tag}>'s handler and let the outer <${outerTag}> own it. Never wire both to the same useAction binding \u2014 stopPropagation is not a fix.` : `Pick ONE surface for the gesture: either drop \`as={...}\` + onClick on the outer <${outerTag}> and let the inner <${match.tag}> own the gesture, OR remove the inner <${match.tag}> and let the outer <${outerTag} as={...}> own it. Don't wire both to the same useAction binding.`,
|
|
1009
1016
|
line: outerLine
|
|
1010
1017
|
});
|
|
1011
1018
|
}
|
|
@@ -1042,9 +1049,10 @@ function isGadgetExportImported(source, pkg, exportName) {
|
|
|
1042
1049
|
}
|
|
1043
1050
|
return false;
|
|
1044
1051
|
}
|
|
1045
|
-
async function runTier0Checks(sourceCode, contract, buildErrors, gadgetTypes) {
|
|
1052
|
+
async function runTier0Checks(sourceCode, contract, buildErrors, gadgetTypes, designMode = DEFAULT_DESIGN_MODE) {
|
|
1046
1053
|
const issues = [];
|
|
1047
1054
|
const lines = sourceCode.split("\n");
|
|
1055
|
+
const enforceDesignVocabulary = designMode === "constrained";
|
|
1048
1056
|
if (buildErrors && buildErrors.length > 0) {
|
|
1049
1057
|
const errorDetail = buildErrors.map((e) => {
|
|
1050
1058
|
const match = e.match(/<stdin>:(\d+):\d+: ERROR: (.+)/);
|
|
@@ -1173,7 +1181,7 @@ ${errorDetail}`,
|
|
|
1173
1181
|
subcategory: "hardcoded-color-fn",
|
|
1174
1182
|
severity: "critical",
|
|
1175
1183
|
description: `Hardcoded ${colorFnMatch[1]}() breaks theme switching \u2014 use design tokens.`,
|
|
1176
|
-
fix: "Replace with a primitive variant OR a
|
|
1184
|
+
fix: "Replace with a primitive variant OR a layering role: var(--ggui-color-container), var(--ggui-color-onContainer), var(--ggui-color-outline), etc.",
|
|
1177
1185
|
line: lineNum
|
|
1178
1186
|
});
|
|
1179
1187
|
}
|
|
@@ -1190,13 +1198,13 @@ ${errorDetail}`,
|
|
|
1190
1198
|
subcategory: "off-manifest-token",
|
|
1191
1199
|
severity: "critical",
|
|
1192
1200
|
description: `Token "${name}" is not in the design system's token manifest \u2014 no theme defines it, so it renders unset.`,
|
|
1193
|
-
fix: `Choose a token that exists: the closed vocabulary is the manifest the design-system docs list (colors: var(--ggui-color-primary-500), var(--ggui-color-
|
|
1201
|
+
fix: `Choose a token that exists: the closed vocabulary is the manifest the design-system docs list (colors: var(--ggui-color-primary-500), var(--ggui-color-onContainer), \u2026; spacing: var(--ggui-spacing-4); type: var(--ggui-font-size-sm)). Never invent a name and never add a literal fallback.`,
|
|
1194
1202
|
line: lineNum
|
|
1195
1203
|
});
|
|
1196
1204
|
}
|
|
1197
|
-
const rawSpacingMatch = line.match(
|
|
1205
|
+
const rawSpacingMatch = enforceDesignVocabulary ? line.match(
|
|
1198
1206
|
/\b(gap|padding|paddingX|paddingY|margin|radius)\s*=\s*["'][\d.]+(?:px|rem|em)["']/
|
|
1199
|
-
);
|
|
1207
|
+
) : null;
|
|
1200
1208
|
if (rawSpacingMatch) {
|
|
1201
1209
|
issues.push({
|
|
1202
1210
|
tier: 0,
|
|
@@ -1290,12 +1298,12 @@ ${errorDetail}`,
|
|
|
1290
1298
|
subcategory: "named-color",
|
|
1291
1299
|
severity: "critical",
|
|
1292
1300
|
description: `Hardcoded CSS named color "${named}" breaks theme switching \u2014 use design tokens.`,
|
|
1293
|
-
fix: `Replace with a typed slot (Text tone="muted" / Box surface="accent" / Badge variant="success") OR a semantic token: var(--ggui-color-
|
|
1301
|
+
fix: `Replace with a typed slot (Text tone="muted" / Box surface="accent" / Badge variant="success") OR a semantic token: var(--ggui-color-onSunken), var(--ggui-color-primary-500), etc. The keyword "${named}" maps to a fixed RGB; the operator's theme has no effect on it.`,
|
|
1294
1302
|
line: lineNum
|
|
1295
1303
|
});
|
|
1296
1304
|
}
|
|
1297
1305
|
}
|
|
1298
|
-
const pxMatch = line.match(/(?:padding|margin|gap|borderRadius)\s*:\s*['"]?\d+px/);
|
|
1306
|
+
const pxMatch = enforceDesignVocabulary ? line.match(/(?:padding|margin|gap|borderRadius)\s*:\s*['"]?\d+px/) : null;
|
|
1299
1307
|
if (pxMatch && !line.includes("var(--ggui-")) {
|
|
1300
1308
|
issues.push({
|
|
1301
1309
|
tier: 0,
|
|
@@ -1303,11 +1311,11 @@ ${errorDetail}`,
|
|
|
1303
1311
|
category: "tokens",
|
|
1304
1312
|
subcategory: "raw-pixels",
|
|
1305
1313
|
description: "Raw pixel value in spacing \u2014 must use design tokens",
|
|
1306
|
-
fix:
|
|
1314
|
+
fix: 'Replace with a bare var(--ggui-spacing-*) token \u2014 no literal fallback (the runtime injects every token) \u2014 or the scale name on the primitive prop (gap="md", padding="lg")',
|
|
1307
1315
|
line: lineNum
|
|
1308
1316
|
});
|
|
1309
1317
|
}
|
|
1310
|
-
const numericSpacingMatch = line.match(/\b(padding|paddingX|paddingY|gap|margin)\s*=\s*\{?\s*(\d+)\s*\}?/);
|
|
1318
|
+
const numericSpacingMatch = enforceDesignVocabulary ? line.match(/\b(padding|paddingX|paddingY|gap|margin)\s*=\s*\{?\s*(\d+)\s*\}?/) : null;
|
|
1311
1319
|
if (numericSpacingMatch && !line.includes("var(--ggui-")) {
|
|
1312
1320
|
issues.push({
|
|
1313
1321
|
tier: 0,
|
|
@@ -1321,7 +1329,7 @@ ${errorDetail}`,
|
|
|
1321
1329
|
}
|
|
1322
1330
|
}
|
|
1323
1331
|
const clickablePattern = /<(?:Card|Box|Stack|Row)\s[^>]*onClick/;
|
|
1324
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1332
|
+
for (let i = 0; enforceDesignVocabulary && i < lines.length; i++) {
|
|
1325
1333
|
if (clickablePattern.test(lines[i]) && !lines[i].includes("as={Clickable}") && !lines[i].includes("as={Pressable}")) {
|
|
1326
1334
|
issues.push({
|
|
1327
1335
|
tier: 0,
|
|
@@ -1334,9 +1342,8 @@ ${errorDetail}`,
|
|
|
1334
1342
|
});
|
|
1335
1343
|
}
|
|
1336
1344
|
}
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
].map((m) => m[1]).filter((name) => typeof name === "string");
|
|
1345
|
+
const bindingRe = designMode === "free" ? /(?:const|let)\s+(\w+)\s*=\s*useAction\s*(?:<[^>]*>)?\s*\(/g : /(?:const|let)\s+(\w+)\s*=\s*useAction\s*\(/g;
|
|
1346
|
+
const actionBindings = [...sourceCode.matchAll(bindingRe)].map((m) => m[1]).filter((name) => typeof name === "string");
|
|
1340
1347
|
for (const binding of actionBindings) {
|
|
1341
1348
|
const callSites = (sourceCode.match(new RegExp(`\\b${binding}\\s*\\(`, "g")) ?? []).length;
|
|
1342
1349
|
if (callSites >= 2) {
|
|
@@ -1352,7 +1359,7 @@ ${errorDetail}`,
|
|
|
1352
1359
|
}
|
|
1353
1360
|
if (actionBindings.length > 0) {
|
|
1354
1361
|
issues.push(
|
|
1355
|
-
...detectCertainDoubleWiredActions(sourceCode, actionBindings)
|
|
1362
|
+
...detectCertainDoubleWiredActions(sourceCode, actionBindings, designMode)
|
|
1356
1363
|
);
|
|
1357
1364
|
}
|
|
1358
1365
|
if (/\buseRender\s*\(/.test(sourceCode)) {
|
|
@@ -1397,7 +1404,7 @@ ${errorDetail}`,
|
|
|
1397
1404
|
const ALIGN_VALUES = /* @__PURE__ */ new Set(["start", "center", "end", "stretch"]);
|
|
1398
1405
|
const JUSTIFY_VALUES = /* @__PURE__ */ new Set(["start", "center", "end", "between", "around", "evenly"]);
|
|
1399
1406
|
const tagRegex = /<(Stack|Row)\b([^>]*)>/gs;
|
|
1400
|
-
for (const tag of sourceCode.matchAll(tagRegex)) {
|
|
1407
|
+
for (const tag of enforceDesignVocabulary ? sourceCode.matchAll(tagRegex) : []) {
|
|
1401
1408
|
const tagName = tag[1];
|
|
1402
1409
|
const attrs = tag[2];
|
|
1403
1410
|
const tagLine = sourceCode.slice(0, tag.index).split("\n").length;
|
|
@@ -1683,8 +1690,8 @@ Import \`${exportName}\` ONLY from '${use.package}' \u2014 that is the package i
|
|
|
1683
1690
|
}
|
|
1684
1691
|
return issues;
|
|
1685
1692
|
}
|
|
1686
|
-
async function runTier0(sourceCode, contract) {
|
|
1687
|
-
const issues = await runTier0Checks(sourceCode, contract);
|
|
1693
|
+
async function runTier0(sourceCode, contract, designMode = DEFAULT_DESIGN_MODE) {
|
|
1694
|
+
const issues = await runTier0Checks(sourceCode, contract, void 0, void 0, designMode);
|
|
1688
1695
|
const pass = [];
|
|
1689
1696
|
const failedCategories = new Set(issues.map((i) => i.category));
|
|
1690
1697
|
const tier0Categories = ["compile", "security", "contract", "types", "imports", "tokens"];
|