Skip to content

Commit 0cfecfe

Browse files
committed
fix: strip C0 chars before javascript: check; correct mustache-literal docs/tests
- Strip U+0000–U+001F (C0 controls) from the start of the trimmed href value before applying the javascript: check. The WHATWG URL parser removes these characters before scheme detection, so \x00javascript: resolves to the javascript: scheme even though String.prototype.trim() leaves them in place. - Fix invalid test syntax: href="{{"#"}}"` used double-quotes inside the surrounding attribute quotes, making it unparseable template syntax. Changed to single-quoted mustache: href="{{'#'}}". - Correct the peer-parity audit comment that said mustache-wrapped string literals were "dynamic and skipped" — getStaticAttrValue unwraps them, so they ARE validated. - Update docs to clarify only truly dynamic mustaches (PathExpressions, helpers, dynamic concat parts) are skipped; static literal mustaches (string/number/boolean) are validated.
1 parent 45fc64b commit 0cfecfe

4 files changed

Lines changed: 7 additions & 7 deletions

File tree

docs/rules/template-no-invalid-link-href.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ This rule **allows** the following:
4141
</template>
4242
```
4343

44-
Dynamic hrefs (mustache-valued) are not validated — we can't statically know the resolved URL.
44+
Mustache hrefs whose value is a **static literal** (string, number, or boolean) are validated — the rule unwraps them to their static value via `getStaticAttrValue`. Only **truly dynamic** mustaches (PathExpressions, helpers with arguments, or concat statements that include a dynamic part) are skipped, because we can't statically determine what they will resolve to at runtime.
4545

4646
## References
4747

617 Bytes
Binary file not shown.

tests/audit/anchor-is-valid-href-only/peer-parity.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,11 @@ ruleTester.run('audit:anchor-is-valid invalidHref (gts)', rule, {
120120
// === Upstream parity: string-literal expression wrapping "#" or js: ===
121121
// jsx-a11y: INVALID — `<a href={"#"} />` and `<a href={"javascript:void(0)"} />`
122122
// are flagged because `getPropValue` unwraps the literal.
123-
// Ours: we only statically resolve GlimmerTextNode / static ConcatStatement;
124-
// a bare `{{ "#" }}` mustache would be dynamic and skipped. The closest
125-
// Glimmer analogue that preserves the intent (a literal `#`) is the
126-
// direct form `href="#"`, already covered above.
127-
// No separate case — this collapses into the direct-string case in HBS.
123+
// Ours: INVALID — `getStaticAttrValue` unwraps a GlimmerMustacheStatement
124+
// whose sole part is a GlimmerStringLiteral, so `href={{"#"}}` and
125+
// `href={{"javascript:void(0)"}}` resolve to their static string values
126+
// and are validated the same as their direct text-node counterparts.
127+
// Parity with jsx-a11y; cases are covered in the main rule test file.
128128

129129
// === DIVERGENCE — "#!" (common hash-bang placeholder) ===
130130
// jsx-a11y: VALID — only exact `#` is flagged; `#!` passes through.

tests/lib/rules/template-no-invalid-link-href.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ ruleTester.run('template-no-invalid-link-href', rule, {
105105
// Single-part quoted-mustache (GlimmerConcatStatement wrapping a
106106
// literal) resolves the same way.
107107
{
108-
code: '<template><a href="{{"#"}}">Click</a></template>',
108+
code: "<template><a href=\"{{'#'}}\">Click</a></template>",
109109
output: null,
110110
errors: [{ messageId: 'invalidHref' }],
111111
},

0 commit comments

Comments
 (0)