Give every blog post a canonical URL - #55
Merged
Merged
Conversation
These posts get syndicated. A readm3 release went to dev.to an hour ago with --canonical-url pointing back at the blog, which is right, but the blog page it points at made no claim about itself. The original was the one page in the set staying quiet, which is the wrong way round: the copy asserts where the original is and the original does not confirm it. So `blog-post` now writes `<link rel="canonical">`. The URL is the post's own, built from a new `siteUrl` config field once `createPost` knows the file name, because that is the only point where both halves exist. `--canonical` overrides it for the case where the original really is somewhere else. `siteUrl` is validated rather than repaired: anything that is not an absolute http(s) URL is dropped, and a trailing slash is trimmed. A canonical pointing somewhere wrong is worse than no canonical at all, because search engines act on it, so `javascript:`, a bare host and a relative path all resolve to null and the tag is omitted. It is null by default, and `new` says so once rather than guessing a URL for a blog it knows nothing about. Nothing changes for a blog with no siteUrl configured: no tag, same page. 711 tests pass. `src/free-names.ts` has two pre-existing exactOptionalPropertyTypes errors on master; they are untouched here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GNpSGiTnfodDyCQ3MU6Nsk
ThreatCrush Security Scan10 finding(s) HIGH/CRITICAL: 2 | MEDIUM: 4 | LOW: 4
Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The blog gets syndicated to dev.to and Hashnode, and those copies point
rel="canonical"back here. Until now the page they point at made no claimabout itself, so the original was the one page in the set staying quiet. This
fixes that end.
What changed
blog-postwrites<link rel="canonical">into each post's head. The URL isthe post's own, assembled from a new
siteUrlconfig field at the one momentboth halves exist — inside
createPost, which is where the file name isdecided.
--canonical URLoverrides it for a post whose original genuinelylives elsewhere.
siteUrl is validated, not repaired
Anything that is not an absolute http(s) URL is dropped to null and the tag is
omitted: a bare host, a relative path,
javascript:,ftp://, a non-string.A canonical pointing somewhere wrong is worse than none, because search engines
act on it. Trailing slashes are trimmed so the joined URL has exactly one.
It defaults to null, and
blog-post newmentions it once when it is unsetrather than inventing a URL for a blog it knows nothing about. A blog with no
siteUrlrenders exactly the page it rendered before.BLOG_SITE_URLoverrides the file, matching the other config fields.Verified
of the URL, self-canonical from
siteUrl, explicit override, the no-configcase, and every rejected URL shape
blog-post newend to end against a scratch blog and read the output:<link rel="canonical" href="https://example.com/blog/001-post.html">from aconfigured
siteUrlofhttps://example.com/blog/Version bumped to 0.28.0 (v0.27.0 is already tagged).
Note:
src/free-names.tshas two pre-existingexactOptionalPropertyTypeserrors on master. I confirmed the file is byte-identical to
origin/masterandleft it alone rather than widening this diff.
🤖 Generated with Claude Code
https://claude.ai/code/session_01GNpSGiTnfodDyCQ3MU6Nsk