@unotest/web 0.42.0 → 0.43.1
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/CHANGELOG.md +477 -3
- package/README.md +37 -5
- package/dist/config/schema.d.ts +71 -36
- package/dist/config/schema.js +1 -1
- package/dist/driver/index.js +1 -1
- package/dist/dsl/index.d.ts +66 -2
- package/dist/dsl/index.js +1 -1
- package/dist/dsl/web-dsl-language-service.d.ts +1 -1
- package/dist/dsl/web-dsl-language-service.js +1 -1
- package/dist/inspection/page-inject.js +27 -3
- package/dist/{linter-Yf4gPe5J.d.ts → linter-BWSAYBQy.d.ts} +24 -0
- package/dist/mcp/server.js +1 -1
- package/dist/runner/cli.d.ts +1 -1
- package/dist/runner/cli.js +1 -1
- package/dist/runner/init/chrome-probe.js +1 -1
- package/dist/runner/init.js +1 -1
- package/dist/runner/install-chromium.js +1 -1
- package/dist/runner/prepare-fix.js +1 -1
- package/dist/runner/scaffold-workspace.js +1 -1
- package/dist/runner/serve-fixture.js +1 -1
- package/dist/runner/web-runner-adapter.js +1 -1
- package/guides/agent-integration.md +124 -7
- package/guides/dsl-reference.md +27 -0
- package/package.json +8 -8
|
@@ -2418,11 +2418,19 @@ function pickerOverlayAlgorithm(op) {
|
|
|
2418
2418
|
...extra.key !== void 0 ? { key: extra.key } : {}
|
|
2419
2419
|
});
|
|
2420
2420
|
}, "push");
|
|
2421
|
+
const SECRET_AUTOCOMPLETE = ["current-password", "new-password", "one-time-code"];
|
|
2422
|
+
const isSecretField = /* @__PURE__ */ __name((el) => {
|
|
2423
|
+
if ((el.getAttribute("type") ?? "").trim().toLowerCase() === "password") return true;
|
|
2424
|
+
const tokens = (el.getAttribute("autocomplete") ?? "").toLowerCase().split(/\s+/);
|
|
2425
|
+
return tokens.some((token) => SECRET_AUTOCOMPLETE.includes(token));
|
|
2426
|
+
}, "isSecretField");
|
|
2427
|
+
const hiddenValue = /* @__PURE__ */ __name((value) => `\u2039hidden, ${value.length} chars\u203A`, "hiddenValue");
|
|
2421
2428
|
const commitFill = /* @__PURE__ */ __name(() => {
|
|
2422
2429
|
const node = state.pendingFill;
|
|
2423
2430
|
state.pendingFill = null;
|
|
2424
2431
|
if (!node) return;
|
|
2425
|
-
const
|
|
2432
|
+
const typed = node.value ?? "";
|
|
2433
|
+
const value = isSecretField(node) ? hiddenValue(typed) : typed;
|
|
2426
2434
|
push(node, "fill", { placement: "append", value });
|
|
2427
2435
|
}, "commitFill");
|
|
2428
2436
|
const describe = /* @__PURE__ */ __name((node) => {
|
|
@@ -2596,6 +2604,21 @@ function serializeRuntimeDom() {
|
|
|
2596
2604
|
return tag === "input" && (name === "value" || name === "checked");
|
|
2597
2605
|
}
|
|
2598
2606
|
__name(isLiveControlledAttr, "isLiveControlledAttr");
|
|
2607
|
+
const SECRET_AUTOCOMPLETE = ["current-password", "new-password", "one-time-code"];
|
|
2608
|
+
function isSecretField(el) {
|
|
2609
|
+
if ((el.getAttribute("type") ?? "").trim().toLowerCase() === "password") return true;
|
|
2610
|
+
const tokens = (el.getAttribute("autocomplete") ?? "").toLowerCase().split(/\s+/);
|
|
2611
|
+
return tokens.some((token) => SECRET_AUTOCOMPLETE.includes(token));
|
|
2612
|
+
}
|
|
2613
|
+
__name(isSecretField, "isSecretField");
|
|
2614
|
+
function hiddenValue(value) {
|
|
2615
|
+
return `\u2039hidden, ${value.length} chars\u203A`;
|
|
2616
|
+
}
|
|
2617
|
+
__name(hiddenValue, "hiddenValue");
|
|
2618
|
+
function shownValue(el, value) {
|
|
2619
|
+
return isSecretField(el) ? hiddenValue(value) : value;
|
|
2620
|
+
}
|
|
2621
|
+
__name(shownValue, "shownValue");
|
|
2599
2622
|
function runtimeAttrs(el) {
|
|
2600
2623
|
const tag = el.tagName.toLowerCase();
|
|
2601
2624
|
if (tag !== "input") return "";
|
|
@@ -2604,7 +2627,7 @@ function serializeRuntimeDom() {
|
|
|
2604
2627
|
if (type === "checkbox" || type === "radio") {
|
|
2605
2628
|
return inp.checked ? " checked" : "";
|
|
2606
2629
|
}
|
|
2607
|
-
return ` value="${escAttr(inp.value)}"`;
|
|
2630
|
+
return ` value="${escAttr(shownValue(el, inp.value))}"`;
|
|
2608
2631
|
}
|
|
2609
2632
|
__name(runtimeAttrs, "runtimeAttrs");
|
|
2610
2633
|
function serialize(node) {
|
|
@@ -2624,6 +2647,7 @@ function serializeRuntimeDom() {
|
|
|
2624
2647
|
attrs += ` ${attr.name}="${escAttr(attr.value)}"`;
|
|
2625
2648
|
}
|
|
2626
2649
|
attrs += runtimeAttrs(el);
|
|
2650
|
+
if (tag === "noscript") return `<${tag}${attrs}></${tag}>`;
|
|
2627
2651
|
let html = `<${tag}${attrs}>`;
|
|
2628
2652
|
if (VOID.has(tag)) return html;
|
|
2629
2653
|
const sr = el.shadowRoot;
|
|
@@ -2633,7 +2657,7 @@ function serializeRuntimeDom() {
|
|
|
2633
2657
|
html += `</template>`;
|
|
2634
2658
|
}
|
|
2635
2659
|
if (tag === "textarea") {
|
|
2636
|
-
html += escText(el.value);
|
|
2660
|
+
html += escText(shownValue(el, el.value));
|
|
2637
2661
|
} else {
|
|
2638
2662
|
for (const c of Array.from(el.childNodes)) html += serialize(c);
|
|
2639
2663
|
}
|
|
@@ -7,6 +7,14 @@ interface LintDiagnostic {
|
|
|
7
7
|
message: string;
|
|
8
8
|
line: number;
|
|
9
9
|
col: number;
|
|
10
|
+
/** This diagnostic must stop a run before anything is driven, not just
|
|
11
|
+
* print. A rule sets it when proceeding would act on the WRONG target
|
|
12
|
+
* — the steps before the offending one would run against the wrong
|
|
13
|
+
* host and leave their side effects there. The CLI (whose pre-run lint
|
|
14
|
+
* is otherwise advisory) refuses on it; run_test already gates on
|
|
15
|
+
* errors and is unaffected. Rules opt in themselves, so no frontend
|
|
16
|
+
* keeps a list of rule ids. */
|
|
17
|
+
blocksRun?: true;
|
|
10
18
|
}
|
|
11
19
|
/** What the linter may ask about external variables (bare UPPER_SNAKE
|
|
12
20
|
* identifiers). A predicate, not a list, because the two callers hold
|
|
@@ -17,6 +25,22 @@ interface ExternalVariableLookup {
|
|
|
17
25
|
has(name: string): boolean;
|
|
18
26
|
/** Where `has` looked, for the diagnostic (`unotest/.env, unotest/.env.dev (no such file)`). */
|
|
19
27
|
describeSources?(): string;
|
|
28
|
+
/** Host policy of the environment this lookup describes (#199) — it
|
|
29
|
+
* answers why NAME must not be used as a HOST in `usage`, or undefined
|
|
30
|
+
* when the use is fine. Absent on a lookup with no project behind it,
|
|
31
|
+
* which leaves the rule off. Structural on purpose: the policy hands
|
|
32
|
+
* back a typed error and the linter needs only what it says, never the
|
|
33
|
+
* config layer it came from. */
|
|
34
|
+
hostPolicy?: {
|
|
35
|
+
rejectAsHost(name: string, usage: string): {
|
|
36
|
+
message: string;
|
|
37
|
+
} | undefined;
|
|
38
|
+
/** The base-URL variable, which the policy names itself — every
|
|
39
|
+
* relative `goto` in the file resolves against it. */
|
|
40
|
+
rejectBaseUrl(usage: string): {
|
|
41
|
+
message: string;
|
|
42
|
+
} | undefined;
|
|
43
|
+
};
|
|
20
44
|
}
|
|
21
45
|
interface LintOptions {
|
|
22
46
|
/** Per-rule severity override. Default severities live with each rule. */
|