@goflag/cli 0.2.7 → 0.2.9

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/README.md CHANGED
@@ -16,9 +16,11 @@ on the site. A human cannot check those on 400 pages. That is the whole job.
16
16
  ## What it checks
17
17
 
18
18
  - **Broken links** — scrapes every crawled page, dedupes targets globally (a footer link on 500 pages is probed once), and checks each with `HEAD`→`GET` fallback, redirect-chain/loop detection, soft-404 and anti-bot (403/429) triage. Broken links are mapped back to the pages that reference them.
19
- - **Missing translation pages** — builds a `route × locale` matrix and flags every route that exists in one locale but is missing in another, plus hreflang reciprocity gaps (`A → B` with no `B → A`), missing `x-default`, and locale tags naming a language, script or region that does not exist. Rows are keyed by pathname, unless your sitemap declares its translation clusters with `xhtml:link` — then those declarations decide which URLs are one page, whatever their slugs, and the run reports `diagnostics.declaredClusters`.
19
+ - **Missing translation pages** — builds a `route × locale` matrix and flags every route that exists in one locale but is missing in another, plus hreflang reciprocity gaps (`A → B` with no `B → A`), missing `x-default`, and locale tags naming a language, script or region that does not exist. Rows are keyed by pathname, unless the site declares its translation clusters — either with `xhtml:link` in the sitemap, or with reciprocal `hreflang` between two crawled pages' `<head>`. Then those declarations decide which URLs are one page, whatever their slugs, and the run reports `diagnostics.declaredClusters`. The sitemap source survives `--coverage structural`, where the two locales of a slug-translating family are rarely both sampled; the `<head>` source needs both pages in hand and is what fixes the common site that declares properly there and nothing in its sitemap.
20
20
  - **robots.txt policy** — flags a site that forbids crawling while its pages ask to be indexed. The two declarations cannot both hold, and robots.txt wins, so the meta tag is never even read.
21
21
  - **SEO metadata** — lints each page's `<head>` for the handful of mistakes that actually hurt in search and social and are invisible in a browser: missing/oversized `<title>` and description, missing/relative canonical, missing `og:title`/`og:description`/`og:image`, missing viewport, and contradictory `robots`/`googlebot`/`X-Robots-Tag` directives.
22
+ - **Open Graph, past its presence** — a declared `og:image` is judged as well as counted: relative URLs no crawler can resolve, an undeclared size (so the first share of a URL renders without the image), a shape far from the 1.91:1 the card is cropped to, a missing `og:image:alt`, and — the one no tag check can reach — whether the URL actually serves an image at all. On a translated page, `og:locale` and `og:locale:alternate` are checked against the hreflang cluster — two vocabularies for one fact, which nothing in a build keeps in step.
23
+ - **Icons** — whether anything declares one at all (nothing in a spec requires it, which is why nothing complains), whether iOS has an `apple-touch-icon` to use instead of screenshotting the page, whether the Web App Manifest and the `<head>` contradict each other about the same file, whether every declared icon answers with an image, whether a `sizes` attribute describes the file it points at (a `.ico` carrying 16, 32 and 48 declared as `48x48` advertises a third of itself), and whether the origin actually serves `/favicon.ico` — a 200 of HTML from a catch-all route does not count. Two icon lists that merely differ are the normal case and are not reported.
22
24
  - **Unreachable pages** — a page the crawl reached that answered non-2xx, or that never answered at all (timeout, reset, DNS failure — recorded as `status: 0`), is reported in `unreachablePages`. goflag asks a second time, from the back of the queue, before calling a page unreachable. Each one is an `error`-severity finding: it turns the verdict red, counts toward `--max-debt`, and fails the build even under `--fail-on error`. A page that silently dropped out of the audited set is what poisons a baseline, so it is reported rather than warned about.
23
25
 
24
26
  **Which pages get audited.** When goflag finds a sitemap it does not audit every URL in it. It groups URLs that share a path shape — and therefore a template — into families, audits every page that stands alone, and samples three pages per family. A cap answers "how many" and never "which": on a site of thousands of pages built from thirty templates, the first 200 pages a crawl reaches are four templates out of thirty.
@@ -138,14 +140,27 @@ npx @goflag/cli rules > rules.json
138
140
 
139
141
  `rules` answers a question about goflag rather than about a site: no URL, no
140
142
  crawl, no network. Every entry carries its scope, severity and summary; the
141
- eleven page rules and four prose rules also carry a rigor, the documents they
142
- cite and — where a remedy is a line of code — a fix snippet. The three site
143
- rules carry none of those three: `SiteRule` has no rigor field yet, and the
144
- catalogue emits `rigor: null` with an empty `sources` rather than inventing an
145
- authority nobody assigned. Write your consumer against that. The same document
143
+ twenty-three page rules and four prose rules also carry a rigor, the documents they
144
+ cite and — where a remedy is a line of code — a fix snippet. Cross-page rules
145
+ may carry them too, and one does; the three that predate the field still emit
146
+ `rigor: null` with an empty `sources`, because choosing their citations is work
147
+ nobody has done and inventing an authority is worse than admitting the gap.
148
+ Write your consumer against that. The same document
146
149
  ships inside the package as `rules.json`, if you would rather read it than run
147
150
  anything.
148
151
 
152
+ The flag list below is data too:
153
+
154
+ ```sh
155
+ npx @goflag/cli flags > flags.json
156
+ ```
157
+
158
+ Same idea, one step further: `flags` prints the very table `goflag --help` is
159
+ rendered from and the argument parser dispatches on, so a flag cannot exist in
160
+ one and not the other. Each entry carries its long and short forms, its argument
161
+ placeholder, its default, the group it belongs to and any flag it requires. It
162
+ ships inside the package as `flags.json` as well.
163
+
149
164
  It deliberately omits the message a finding prints — that is built at audit time
150
165
  from what the page actually says, so a static copy would be a sample rather than
151
166
  a fact, and a sample presented as the truth is how this project's own
@@ -424,6 +439,17 @@ goflag https://example.com --ignore-holes /legal --ignore-holes "/blog/**"
424
439
  Suppressed gaps are counted in `diagnostics.ignoredHoles`, so a quiet report
425
440
  never means "nothing was wrong" by accident.
426
441
 
442
+ The opposite failure is quieter still. A cell in the matrix can be filled by an
443
+ `hreflang` on another page and by nothing else — not crawled, not listed in your
444
+ sitemap — and a filled cell reads as a translation that exists. A page
445
+ advertising a translation the site does not serve therefore plugs the very gap
446
+ it should reveal. Those cells are counted in
447
+ `diagnostics.unverifiedAlternates`, and goflag deliberately does **not** act on
448
+ them: refusing to believe an alternate the sitemap omits would invent holes on
449
+ every site using `@goflag/next`'s `sitemap: false` on purpose. Read that number
450
+ next to `missingTranslations` — a `0` beside a non-zero count is the one place
451
+ this report can be quietly wrong.
452
+
427
453
  ## In CI
428
454
 
429
455
  Two moments are worth auditing, and they answer different questions.
@@ -455,7 +481,7 @@ Three rules, whichever you use:
455
481
  stages: [build, deploy, audit]
456
482
 
457
483
  variables:
458
- GOFLAG_VERSION: "0.2.7"
484
+ GOFLAG_VERSION: "0.2.9"
459
485
 
460
486
  # Before the merge: build the branch, let goflag boot it, audit that.
461
487
  seo:mr:
@@ -507,7 +533,7 @@ jobs:
507
533
  - run: corepack enable && pnpm install --frozen-lockfile
508
534
  - run: pnpm build
509
535
  - run: |
510
- npx --yes @goflag/cli@0.2.7 http://localhost:3000 \
536
+ npx --yes @goflag/cli@0.2.9 http://localhost:3000 \
511
537
  --start "pnpm start" --static --no-external \
512
538
  --baseline .goflag/baseline.json --regressions-only --max-debt 41 \
513
539
  --report goflag-report.json