@goflag/cli 0.2.0 → 0.2.1

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
@@ -492,23 +492,44 @@ console.log(report.summary); // { brokenLinks, missingTranslations, seoIssues, v
492
492
  ## Repository layout
493
493
 
494
494
  ```
495
- packages/cli/ @goflag/cli — the CLI (installs the `goflag` command)
495
+ packages/cli/ @goflag/cli, the CLI (installs the `goflag` command)
496
+ packages/next/ @goflag/next, the Next.js library (see below)
497
+ apps/website/ goflag.tech, the landing page and the documentation
496
498
  tools/name-holder/ the bare `goflag` name on npm, a signpost to @goflag/cli
497
499
  ```
498
500
 
499
- That is the whole tree. `@goflag/next` (the Next.js library) and the
500
- documentation site are planned but deliberately absent: the workspace globs
501
- (`packages/*`, `apps/*`) are ready for them, and empty stubs for things that do
502
- not exist are how a repository accumulates code nobody calls.
501
+ That is the whole tree. Neither `packages/next` nor `apps/**` may import from
502
+ the CLI: the two products stay independently useful, and an ESLint rule
503
+ enforces it rather than trusting memory.
503
504
 
504
- When they land, they must not import from the CLI: the two products stay
505
- independently useful, and an ESLint rule enforces it rather than trusting
506
- memory.
505
+ ## The other half: `@goflag/next`
506
+
507
+ goflag tells you what is wrong. It does not tell you how to stop writing it
508
+ wrong. [`@goflag/next`](packages/next) is a route registry for the Next.js App
509
+ Router that produces the HTML this auditor would have nothing to say about.
510
+
511
+ ```ts
512
+ export const routes = site.routes({
513
+ home: { path: "" },
514
+ docs: collection(allDocs, { path: (d) => `/docs/${d.slug}`, locale: "en" }),
515
+ });
516
+
517
+ // app/sitemap.ts
518
+ export default () => routes.sitemap();
519
+ ```
520
+
521
+ A sitemap derived separately from the metadata is two derivations of one truth,
522
+ held in agreement by vigilance, and their disagreement is what goflag reports as
523
+ `hreflang.sitemap-mismatch`. Projecting both from one registry makes that
524
+ finding unrepresentable. Full documentation at
525
+ [goflag.tech/docs/next](https://goflag.tech/docs/next), and the API reference in
526
+ [`packages/next/README.md`](packages/next/README.md).
507
527
 
508
528
  ## Develop locally
509
529
 
510
- Requires pnpm `11.18.0` (pinned via `packageManager` — `corepack enable` picks
511
- it up). Run these from the repository root:
530
+ Requires pnpm, pinned via `packageManager` in the root `package.json` — run
531
+ `corepack enable` once and it picks up the right version by itself. Run these
532
+ from the repository root:
512
533
 
513
534
  ```sh
514
535
  pnpm install
@@ -1782,6 +1782,9 @@ function sortIssues(issues) {
1782
1782
 
1783
1783
  // src/lib/core/i18n.ts
1784
1784
  var BCP47_LOOSE = /^[a-z]{2,3}(-[a-z]{2}|-\d{3})?$/i;
1785
+ function localeIdentity(tag) {
1786
+ return tag.trim().toLowerCase();
1787
+ }
1785
1788
  function looksLikeLocaleSegment(segment) {
1786
1789
  return BCP47_LOOSE.test(segment);
1787
1790
  }
@@ -1823,7 +1826,7 @@ function buildI18nMatrix(pages, options = {}) {
1823
1826
  continue;
1824
1827
  }
1825
1828
  const { route } = splitRoute(altUrl.pathname);
1826
- const locale = alt.isXDefault ? "x-default" : alt.hreflang;
1829
+ const locale = alt.isXDefault ? "x-default" : localeIdentity(alt.hreflang);
1827
1830
  record(route || selfRoute, locale, altUrl.toString());
1828
1831
  }
1829
1832
  }
@@ -1857,14 +1860,15 @@ function reciprocityIssues(pages) {
1857
1860
  const url = page.fetch.finalUrl;
1858
1861
  const seenLocalesOnPage = /* @__PURE__ */ new Set();
1859
1862
  for (const alt of page.links.alternates) {
1860
- const locale = alt.isXDefault ? "x-default" : alt.hreflang;
1863
+ const raw = alt.isXDefault ? "x-default" : alt.hreflang;
1864
+ const locale = alt.isXDefault ? "x-default" : localeIdentity(alt.hreflang);
1861
1865
  seenLocalesOnPage.add(locale);
1862
1866
  if (!isValidLocale(locale)) {
1863
1867
  issues.push({
1864
1868
  code: "locale.invalid",
1865
1869
  url,
1866
- locale,
1867
- message: `\`hreflang="${locale}"\` is not a valid BCP 47 tag.`
1870
+ locale: raw,
1871
+ message: `\`hreflang="${raw}"\` is not a valid BCP 47 tag.`
1868
1872
  });
1869
1873
  continue;
1870
1874
  }
@@ -1923,7 +1927,7 @@ function dedupeBy(items, key) {
1923
1927
  function splitRoute(pathname) {
1924
1928
  const segments = pathname.split("/").filter(Boolean);
1925
1929
  if (segments.length > 0 && looksLikeLocaleSegment(segments[0])) {
1926
- const locale = segments[0];
1930
+ const locale = localeIdentity(segments[0]);
1927
1931
  const rest = segments.slice(1).join("/");
1928
1932
  return { route: rest ? `/${rest}` : "/", locale };
1929
1933
  }
@@ -4271,4 +4275,4 @@ export {
4271
4275
  summarize,
4272
4276
  Logger
4273
4277
  };
4274
- //# sourceMappingURL=chunk-GFM3YN5N.js.map
4278
+ //# sourceMappingURL=chunk-6WOWKLXY.js.map