@goflag/cli 0.2.10 → 0.2.12
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 +123 -43
- package/dist/{chunk-DKGBLJ4H.js → chunk-QKXUKHXB.js} +1087 -82
- package/dist/chunk-QKXUKHXB.js.map +1 -0
- package/dist/cli.js +118 -18
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +132 -2
- package/dist/index.js +3 -1
- package/flags.json +1 -1
- package/package.json +2 -2
- package/rules.json +105 -10
- package/dist/chunk-DKGBLJ4H.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# goflag
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> Point it at a URL and get four things: broken links, missing translation pages, a robots.txt that contradicts your pages, and missing or misconfigured SEO metadata. JSON-first.
|
|
3
|
+
A CLI that audits a site for broken links, missing translation pages, a robots.txt that contradicts your pages, and missing or misconfigured SEO metadata — and a Next.js library that produces the HTML it would have nothing to say about.
|
|
5
4
|
|
|
6
|
-
[](
|
|
5
|
+
[](https://github.com/tancredesimonin/goflag/blob/main/package.json)
|
|
7
6
|
[](#license)
|
|
8
7
|
|
|
9
8
|
Goflag crawls a site once and judges what it found. It is deliberately small: no dashboard, no config system, no social-preview gallery. Just the findings, as a machine-readable report you can pipe, diff, or gate CI on.
|
|
@@ -13,7 +12,24 @@ search: a `hreflang` that points at a 404, a canonical that silently
|
|
|
13
12
|
de-indexes a page, a `robots.txt` that contradicts every `<meta name="robots">`
|
|
14
13
|
on the site. A human cannot check those on 400 pages. That is the whole job.
|
|
15
14
|
|
|
16
|
-
##
|
|
15
|
+
## Getting started
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npx @goflag/cli https://example.com # one-off, nothing installed
|
|
19
|
+
pnpm add -D @goflag/cli # then: pnpm goflag https://example.com
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Install it as a dev dependency once you run it more than once — in a script, in
|
|
23
|
+
CI, in a git hook. `npx` is for trying it. The package is `@goflag/cli`; the
|
|
24
|
+
command it installs is `goflag`. Everything under the brand lives in the
|
|
25
|
+
`@goflag` scope; the bare `goflag` name on npm is a deprecated signpost pointing
|
|
26
|
+
here and carries no code.
|
|
27
|
+
|
|
28
|
+
- Node `>=22`.
|
|
29
|
+
- Nothing else for a static audit. Headless rendering needs Chromium, which is **not** installed with goflag — `playwright` is an optional peer dependency. Add it only if you audit client-rendered pages without `--static`: `pnpm add -D playwright && pnpm exec playwright install chromium`.
|
|
30
|
+
- Working in this repository instead of consuming it: `pnpm install`, then see [AGENTS.md](https://github.com/tancredesimonin/goflag/blob/main/AGENTS.md).
|
|
31
|
+
|
|
32
|
+
## What it does
|
|
17
33
|
|
|
18
34
|
- **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
35
|
- **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.
|
|
@@ -43,31 +59,11 @@ fails loudly rather than passing quietly. It is also why `--static` is the right
|
|
|
43
59
|
default in CI: it needs no browser, and it cannot mistake a broken page for a
|
|
44
60
|
fine one.
|
|
45
61
|
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
Requires Node `>=22`.
|
|
49
|
-
|
|
50
|
-
```sh
|
|
51
|
-
npx @goflag/cli https://example.com # one-off, nothing installed
|
|
52
|
-
pnpm add -D @goflag/cli # then: pnpm goflag https://example.com
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Install it as a dev dependency once you run it more than once — in a script, in
|
|
56
|
-
CI, in a git hook. `npx` is for trying it.
|
|
62
|
+
## Where it runs
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
under the brand lives in the `@goflag` scope; the bare `goflag` name on npm is a
|
|
60
|
-
deprecated signpost pointing here and carries no code.
|
|
64
|
+
Two packages ship to npm from a tag, published by GitLab CI over OIDC with no stored credential: `@goflag/cli` (`v*`) and `@goflag/next` (`next-v*`). The documentation site `apps/website` runs at [goflag.tech](https://goflag.tech), with `develop.goflag.tech` alongside it, both deployed with Kamal onto the shared OVH host described in the `infrastructure` repository.
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
`playwright` is an optional peer dependency. Add it only if you audit
|
|
64
|
-
client-rendered pages without `--static`:
|
|
65
|
-
|
|
66
|
-
```sh
|
|
67
|
-
pnpm add -D playwright && pnpm exec playwright install chromium
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Getting started
|
|
66
|
+
## Your first audit
|
|
71
67
|
|
|
72
68
|
Five steps, in this order. Each one is explained in full further down; this is
|
|
73
69
|
the sequence.
|
|
@@ -134,6 +130,19 @@ npx @goflag/cli https://example.com --report report.json # write JSON to a
|
|
|
134
130
|
|
|
135
131
|
The terminal view is just a render of that JSON.
|
|
136
132
|
|
|
133
|
+
### Four verbs
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
goflag <url> [options] # audit a site
|
|
137
|
+
goflag preview <url> # render its share cards, and look at them
|
|
138
|
+
goflag rules # print the rule catalogue as JSON
|
|
139
|
+
goflag flags # print the flag reference as JSON
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The last two answer a question about goflag rather than about a site, so they
|
|
143
|
+
take no URL and touch no network. `preview` takes one and audits like a normal
|
|
144
|
+
run — [what it writes](#goflag-preview--look-at-the-cards-before-you-ship-them) is further down.
|
|
145
|
+
|
|
137
146
|
### The catalogue is data too
|
|
138
147
|
|
|
139
148
|
```sh
|
|
@@ -141,15 +150,15 @@ npx @goflag/cli rules > rules.json
|
|
|
141
150
|
```
|
|
142
151
|
|
|
143
152
|
`rules` answers a question about goflag rather than about a site: no URL, no
|
|
144
|
-
crawl, no network.
|
|
145
|
-
twenty-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
because
|
|
150
|
-
authority is worse than admitting the gap. Write your consumer against
|
|
151
|
-
ships inside the package as `rules.json`, if you would
|
|
152
|
-
anything.
|
|
153
|
+
crawl, no network. It ships fifty-eight rules — twenty-five page rules,
|
|
154
|
+
twenty-eight site rules and five prose rules — and every entry carries its
|
|
155
|
+
scope, severity and summary. All but one also carry a rigor, the documents they
|
|
156
|
+
cite and, where a remedy is a line of code, a fix snippet. The exception is
|
|
157
|
+
`hreflang.sitemap-mismatch`, which emits `rigor: null` with an empty `sources`
|
|
158
|
+
because no specification says which of the two declarations is wrong; inventing
|
|
159
|
+
an authority there is worse than admitting the gap. Write your consumer against
|
|
160
|
+
that. The same document ships inside the package as `rules.json`, if you would
|
|
161
|
+
rather read it than run anything.
|
|
153
162
|
|
|
154
163
|
The flag list below is data too:
|
|
155
164
|
|
|
@@ -174,7 +183,8 @@ documentation site came to quote a message the engine had stopped printing.
|
|
|
174
183
|
--json Print the JSON report to stdout (nothing else).
|
|
175
184
|
--summary, -s Roll findings up (dedup by link/rule/code). Pairs with
|
|
176
185
|
--json for a compact payload; --report always writes
|
|
177
|
-
the full report regardless.
|
|
186
|
+
the full report regardless. Not available with
|
|
187
|
+
--baseline: there the diff is the answer.
|
|
178
188
|
--report <file> Write the JSON report to <file>.
|
|
179
189
|
--depth <n> How far to follow links out of each page (0 = follow
|
|
180
190
|
none). Sitemap URLs are seeded regardless, so --depth 0
|
|
@@ -435,6 +445,30 @@ should boot. In a monorepo audited from the root, point it at the package:
|
|
|
435
445
|
goflag http://localhost:3000 --start "pnpm start" --start-cwd apps/web
|
|
436
446
|
```
|
|
437
447
|
|
|
448
|
+
### `goflag preview` — look at the cards before you ship them
|
|
449
|
+
|
|
450
|
+
Some things are only settleable by looking. `og.image.representative` asks
|
|
451
|
+
whether the shared image survives being cropped to 1.91:1 — a question the
|
|
452
|
+
catalogue states and refuses to answer, because no rule can.
|
|
453
|
+
|
|
454
|
+
```sh
|
|
455
|
+
goflag preview http://localhost:3000 --start "pnpm start"
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
It audits like a normal run, then writes `.goflag/preview.html`: one
|
|
459
|
+
self-contained file showing what Google, Open Graph, X, LinkedIn, Slack, Discord
|
|
460
|
+
and WhatsApp make of each page, with the findings pinned on the cards they
|
|
461
|
+
concern and the page's JSON-LD shown beside them.
|
|
462
|
+
|
|
463
|
+
Each surface is labelled with how well its geometry is actually documented.
|
|
464
|
+
Three of the seven publish real numbers; Slack calls its own rendering a
|
|
465
|
+
"micro-approximation"; Discord publishes nothing; X's card documentation is not
|
|
466
|
+
reachable, and its shape changed twice since 2023. Drawing all seven with the
|
|
467
|
+
same confidence would be six unearned claims, so the file says which is which.
|
|
468
|
+
|
|
469
|
+
It never gates — it exits 0 unless the run itself failed — and it prints the
|
|
470
|
+
path it wrote, so `open "$(goflag preview http://localhost:3000)"` opens it.
|
|
471
|
+
|
|
438
472
|
### Multilingual sites
|
|
439
473
|
|
|
440
474
|
Discovery is seeded from the sitemap, not just from links. That matters because
|
|
@@ -513,7 +547,7 @@ Three rules, whichever you use:
|
|
|
513
547
|
stages: [build, deploy, audit]
|
|
514
548
|
|
|
515
549
|
variables:
|
|
516
|
-
GOFLAG_VERSION: "0.2.
|
|
550
|
+
GOFLAG_VERSION: "0.2.12"
|
|
517
551
|
|
|
518
552
|
# Before the merge: build the branch, let goflag boot it, audit that.
|
|
519
553
|
seo:mr:
|
|
@@ -565,7 +599,7 @@ jobs:
|
|
|
565
599
|
- run: corepack enable && pnpm install --frozen-lockfile
|
|
566
600
|
- run: pnpm build
|
|
567
601
|
- run: |
|
|
568
|
-
npx --yes @goflag/cli@0.2.
|
|
602
|
+
npx --yes @goflag/cli@0.2.12 http://localhost:3000 \
|
|
569
603
|
--start "pnpm start" --static --no-external \
|
|
570
604
|
--baseline .goflag/baseline.json --regressions-only --max-debt 41 \
|
|
571
605
|
--report goflag-report.json
|
|
@@ -612,6 +646,7 @@ console.log(report.summary);
|
|
|
612
646
|
```
|
|
613
647
|
packages/cli/ @goflag/cli, the CLI (installs the `goflag` command)
|
|
614
648
|
packages/next/ @goflag/next, the Next.js library (see below)
|
|
649
|
+
packages/og/ @goflag/og, the share cards and the favicon container
|
|
615
650
|
apps/website/ goflag.tech, the landing page and the documentation
|
|
616
651
|
tools/name-holder/ the bare `goflag` name on npm, a signpost to @goflag/cli
|
|
617
652
|
```
|
|
@@ -623,7 +658,7 @@ enforces it rather than trusting memory.
|
|
|
623
658
|
## The other half: `@goflag/next`
|
|
624
659
|
|
|
625
660
|
goflag tells you what is wrong. It does not tell you how to stop writing it
|
|
626
|
-
wrong. [`@goflag/next`](packages/next) is a route registry for the Next.js App
|
|
661
|
+
wrong. [`@goflag/next`](https://github.com/tancredesimonin/goflag/tree/main/packages/next) is a route registry for the Next.js App
|
|
627
662
|
Router that produces the HTML this auditor would have nothing to say about.
|
|
628
663
|
|
|
629
664
|
```ts
|
|
@@ -641,7 +676,32 @@ held in agreement by vigilance, and their disagreement is what goflag reports as
|
|
|
641
676
|
`hreflang.sitemap-mismatch`. Projecting both from one registry makes that
|
|
642
677
|
finding unrepresentable. Full documentation at
|
|
643
678
|
[goflag.tech/docs/next](https://goflag.tech/docs/next), and the API reference in
|
|
644
|
-
[`packages/next/README.md`](packages/next/README.md).
|
|
679
|
+
[`packages/next/README.md`](https://github.com/tancredesimonin/goflag/blob/main/packages/next/README.md).
|
|
680
|
+
|
|
681
|
+
## The picture: `@goflag/og`
|
|
682
|
+
|
|
683
|
+
Two of this catalogue's rules had no remedy to point at. `og.image.missing`
|
|
684
|
+
fired 24 times on one site and `og.image.alt` 46 times on another, and the fix
|
|
685
|
+
for both is "either an asset or a route you have to write" — which is how a rule
|
|
686
|
+
becomes permanent debt. [`@goflag/og`](packages/og) is that route, written once.
|
|
687
|
+
|
|
688
|
+
```tsx
|
|
689
|
+
// app/[locale]/opengraph-image.tsx
|
|
690
|
+
const image = ogImage(og, async ({ params }) => {
|
|
691
|
+
const { locale } = await params;
|
|
692
|
+
return { title: t("hero.title"), alt: t("meta.ogAlt") };
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
export const generateImageMetadata = image.generateImageMetadata;
|
|
696
|
+
export default image.render;
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
The core renders nothing: it returns a JSX tree that `next/og` — which already
|
|
700
|
+
embeds satori — turns into a PNG at build time, so nothing installs a second
|
|
701
|
+
renderer and a card can be unit-tested with no framework build. It also packs
|
|
702
|
+
the `favicon.ico` **no Next convention emits**, guarded so that a generated file
|
|
703
|
+
living in git is not dirtied by every commit. API reference in
|
|
704
|
+
[`packages/og/README.md`](packages/og/README.md).
|
|
645
705
|
|
|
646
706
|
## Develop locally
|
|
647
707
|
|
|
@@ -667,8 +727,28 @@ eslint once at the root and then fans out to any package that defines its own
|
|
|
667
727
|
across workspace packages with `pnpm -r`. To work on one package, filter:
|
|
668
728
|
`pnpm --filter @goflag/cli test`.
|
|
669
729
|
|
|
670
|
-
The engine is framework-agnostic and lives in [`packages/cli/src/lib/core/`](packages/cli/src/lib/core) (crawl, fetch/extract, link audit, i18n) and [`packages/cli/src/lib/rules/`](packages/cli/src/lib/rules) (SEO checks). The CLI shell — orchestration, the `GoflagReport` schema, and rendering — lives in [`packages/cli/src/report/`](packages/cli/src/report) and [`packages/cli/src/cli.ts`](packages/cli/src/cli.ts).
|
|
730
|
+
The engine is framework-agnostic and lives in [`packages/cli/src/lib/core/`](https://github.com/tancredesimonin/goflag/tree/main/packages/cli/src/lib/core) (crawl, fetch/extract, link audit, i18n) and [`packages/cli/src/lib/rules/`](https://github.com/tancredesimonin/goflag/tree/main/packages/cli/src/lib/rules) (SEO checks). The CLI shell — orchestration, the `GoflagReport` schema, and rendering — lives in [`packages/cli/src/report/`](https://github.com/tancredesimonin/goflag/tree/main/packages/cli/src/report) and [`packages/cli/src/cli.ts`](https://github.com/tancredesimonin/goflag/blob/main/packages/cli/src/cli.ts).
|
|
731
|
+
|
|
732
|
+
## Contributing
|
|
733
|
+
|
|
734
|
+
GitHub is a read-only mirror; the canonical repository and the CI are on GitLab,
|
|
735
|
+
so a pull request opened here cannot be merged. **Issues are the useful thing to
|
|
736
|
+
open on GitHub** — a wrong finding especially, which is the class of bug handled
|
|
737
|
+
first. [CONTRIBUTING.md](https://github.com/tancredesimonin/goflag/blob/main/CONTRIBUTING.md)
|
|
738
|
+
has the whole story, including what makes a report reproducible and what a rule
|
|
739
|
+
proposal needs. Vulnerabilities go to <hello@goflag.tech> rather than to an
|
|
740
|
+
issue — see
|
|
741
|
+
[SECURITY.md](https://github.com/tancredesimonin/goflag/blob/main/SECURITY.md).
|
|
671
742
|
|
|
672
743
|
## License
|
|
673
744
|
|
|
674
745
|
MIT.
|
|
746
|
+
|
|
747
|
+
## Learn more
|
|
748
|
+
|
|
749
|
+
- Strategy and goals: [STRATEGY.md](https://github.com/tancredesimonin/goflag/blob/main/STRATEGY.md)
|
|
750
|
+
- What comes next: [ROADMAP.md](https://github.com/tancredesimonin/goflag/blob/main/ROADMAP.md)
|
|
751
|
+
- Working in this repository (human or agent): [AGENTS.md](https://github.com/tancredesimonin/goflag/blob/main/AGENTS.md)
|
|
752
|
+
- The overall development plan: [docs/spec-and-lib-plan.md](https://github.com/tancredesimonin/goflag/blob/main/docs/spec-and-lib-plan.md)
|
|
753
|
+
- The rule catalogue and its architecture: [docs/rules-catalog-plan.md](https://github.com/tancredesimonin/goflag/blob/main/docs/rules-catalog-plan.md)
|
|
754
|
+
- Publishing `@goflag/next`: [docs/publishing.md](https://github.com/tancredesimonin/goflag/blob/main/docs/publishing.md)
|