vyrn

std/vyx-hints

2 exports, from std/vyx-hints.vyrn.

Accessibility, security and performance rules for .vyx components.

The library holds no privilege: it parses with std/vyx's vyxParseTemplate and reports through std/hints, so a project swaps in its own rules by changing one import. The second import runs the checks; the namespace it binds is unused.

import { vyxHints } from "std/vyx-hints"
import * as _hints from vyxHints("./app/widgets")

To configure, pass a JSON file; a generator reads only under the paths it is given:

import { vyxHintsConfigured } from "std/vyx-hints"
import * as _hints from vyxHintsConfigured("./app/widgets", "./vyrn.json")
{ "hints": { "perf/img-size": "off", "a11y/img-alt": "error" } }

Only rules the template's own text decides are here (docs/research/vyx-hints.md ranks the rest). A rule that needs a rendered page, the author's intent, or a view across component boundaries would fire when unsure. Nine rules are errors: sec/inline-handler, sec/unsafe-url, and seven html-validate ports that keep its "error" preset severity. The rest are warnings.

Dependencies

The import graph shows the whole library.

Imported by
gen fn vyxHints(dir: String) -> String

Checks every <Name>.vyx under dir at default severities. Emits //@diag reports and one declaration for the import to bind.

gen fn vyxHintsConfigured(dir: String, config: String) -> String

vyxHints under the "hints" object of the JSON document at config. A config that cannot be read or is refused by policyOf is an error, and no file is checked.

Tests

28 test blocks in std/vyx-hints.vyrn. CI runs all of them.

Test names
  • img without alt fires; alt="" and :alt do not
  • an unsized image fires; a sized one does not
  • a click handler on a non-interactive element fires unless it is made reachable
  • an inline on* handler is an error; @click and data- attributes are not
  • a literal javascript: URL is an error; http, relative and dynamic are not
  • a positive tabindex fires; 0 and -1 do not
  • a static id inside a v-for fires; outside one, or bound, it does not
  • target=_blank without noreferrer fires
  • an empty control fires; content or an aria-label names it
  • an unlabelled input fires; a wrapping label, an id or an aria-label names it
  • a handler button inside a form fires unless it names its type
  • a static style attribute is an error; a bound :style is not
  • autoplay fires on audio and video only
  • a th without scope fires; col, row and a bound scope do not
  • an input without type fires; any type, static or bound, does not
  • a tr directly inside a table fires; one inside thead, tbody or tfoot does not
  • content inside a void element fires; a self-closed void does not
  • an external script or sheet without integrity fires; a local one does not
  • an attribute foreign to its element fires; every owned space does not
  • an entity in text fires; plain text, a bare ampersand and interpolation do not
  • a waiver that waives nothing fires; one that earns its keep does not
  • a misspelled aria attribute fires; the vocabulary and bound values do not
  • a removed attribute fires on its element and nowhere else
  • an unknown element fires; the vocabulary, custom elements and foreign content do not
  • a removed element fires; its replacement does not
  • a component call is not an HTML element
  • configuration turns a rule off and moves another to error
  • a template that does not parse earns no advice

Examples

    No example program imports this module.