@goflag/cli 0.2.8 → 0.2.10
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 +43 -8
- package/dist/{chunk-SKX7UCGC.js → chunk-DKGBLJ4H.js} +2004 -422
- package/dist/chunk-DKGBLJ4H.js.map +1 -0
- package/dist/cli.js +6 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +96 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/rules.json +653 -4
- package/dist/chunk-SKX7UCGC.js.map +0 -1
package/README.md
CHANGED
|
@@ -17,8 +17,12 @@ on the site. A human cannot check those on 400 pages. That is the whole job.
|
|
|
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
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
|
-
- **robots.txt policy** — flags a site that forbids crawling while its pages ask to be indexed
|
|
20
|
+
- **robots.txt policy** — the file is parsed to RFC 9309, not scanned: every group, every rule, every line it could not read, each with its number. goflag flags a site that forbids crawling while its pages ask to be indexed — site-wide, and now per path, which is the quiet version nothing was watching. It also reports the file that errors (a 5xx there is read as a site-wide ban), one over the 500 KiB a parser must honour, a typo that silently deletes the rule you meant to write, a redirect handing your crawl policy to another origin, and a `Sitemap:` that is not a full URL.
|
|
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.
|
|
24
|
+
- **Sitemap** — whether there is one, whether it parses (an HTML error page served with a 200 reads as healthy to anything that only checks the status), whether it lists anything, and whether an index can reach its children. Each entry is judged too: a `<loc>` that is not absolute, entries on another host or another protocol, a `<lastmod>` that is not a W3C Datetime or is dated in the future, a `changefreq` or `priority` outside the values the protocol defines.
|
|
25
|
+
- **Where the two files meet the crawl** — the contradictions no single artefact shows. A sitemap entry that `robots.txt` forbids fetching, one whose page declares `noindex`, one whose canonical points elsewhere, one that 404s or redirects, and the indexable pages the crawl found that the sitemap never lists. Entry probing answers from the crawl and the link audit before it fetches anything, so a well-built site costs almost no extra requests — and when the caps stop it short, the finding says how many went unchecked rather than implying the rest are fine. Nothing is broken when you look at either half alone, which is why nobody finds these by reading.
|
|
22
26
|
- **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
27
|
|
|
24
28
|
**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,11 +142,12 @@ npx @goflag/cli rules > rules.json
|
|
|
138
142
|
|
|
139
143
|
`rules` answers a question about goflag rather than about a site: no URL, no
|
|
140
144
|
crawl, no network. Every entry carries its scope, severity and summary; the
|
|
141
|
-
|
|
142
|
-
cite and — where a remedy is a line of code — a fix snippet.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
twenty-three page rules and four prose rules also carry a rigor, the documents they
|
|
146
|
+
cite and — where a remedy is a line of code — a fix snippet. Cross-page rules
|
|
147
|
+
may carry them too, and the robots family does; the three hreflang and sitemap
|
|
148
|
+
rules that predate the field still emit `rigor: null` with an empty `sources`,
|
|
149
|
+
because choosing their citations is work nobody has done and inventing an
|
|
150
|
+
authority is worse than admitting the gap. Write your consumer against that. The same document
|
|
146
151
|
ships inside the package as `rules.json`, if you would rather read it than run
|
|
147
152
|
anything.
|
|
148
153
|
|
|
@@ -324,6 +329,36 @@ description on a page that has none, because `description.missing` already
|
|
|
324
329
|
says that. They never count toward the summary, the verdict, or the exit
|
|
325
330
|
code: nobody has judged them yet.
|
|
326
331
|
|
|
332
|
+
### Every finding says how authoritative it is
|
|
333
|
+
|
|
334
|
+
A finding carries the rule's `rigor`, the documents behind it, what the page
|
|
335
|
+
actually said and what a passing page looks like — in the JSON, not only in the
|
|
336
|
+
opt-in conformance view:
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"ruleId": "title.length",
|
|
341
|
+
"severity": "warning",
|
|
342
|
+
"rigor": "heuristic",
|
|
343
|
+
"sources": ["google-title-link", "moz-title-tag"],
|
|
344
|
+
"expected": "10–60 characters",
|
|
345
|
+
"observed": 65
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
That distinction is the whole point of the rigor axis, and it is meant to be
|
|
350
|
+
acted on: a `spec-required` finding and a `heuristic` one are not the same
|
|
351
|
+
work, and a report read in CI — or by an agent that does not have the rule
|
|
352
|
+
registry — could not tell them apart otherwise. `--summary` shows it per rule,
|
|
353
|
+
where it costs one tag instead of one per finding:
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
warn title.length [heuristic] ×3
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Severity says what your build should do; rigor says who says so. A profile
|
|
360
|
+
changes the first and never the second.
|
|
361
|
+
|
|
327
362
|
### Gate on regressions, not on perfection
|
|
328
363
|
|
|
329
364
|
A plain run fails on any finding, which is unusable on a site that is not clean
|
|
@@ -478,7 +513,7 @@ Three rules, whichever you use:
|
|
|
478
513
|
stages: [build, deploy, audit]
|
|
479
514
|
|
|
480
515
|
variables:
|
|
481
|
-
GOFLAG_VERSION: "0.2.
|
|
516
|
+
GOFLAG_VERSION: "0.2.10"
|
|
482
517
|
|
|
483
518
|
# Before the merge: build the branch, let goflag boot it, audit that.
|
|
484
519
|
seo:mr:
|
|
@@ -530,7 +565,7 @@ jobs:
|
|
|
530
565
|
- run: corepack enable && pnpm install --frozen-lockfile
|
|
531
566
|
- run: pnpm build
|
|
532
567
|
- run: |
|
|
533
|
-
npx --yes @goflag/cli@0.2.
|
|
568
|
+
npx --yes @goflag/cli@0.2.10 http://localhost:3000 \
|
|
534
569
|
--start "pnpm start" --static --no-external \
|
|
535
570
|
--baseline .goflag/baseline.json --regressions-only --max-debt 41 \
|
|
536
571
|
--report goflag-report.json
|