[3.x] Support pages with more output file extensions (epic)#2524
Draft
emmadesilva wants to merge 97 commits into
Draft
[3.x] Support pages with more output file extensions (epic)#2524emmadesilva wants to merge 97 commits into
emmadesilva wants to merge 97 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a static $outputFileExtension property (default '.html') to HydePage,
used by outputPath() instead of the hardcoded HTML suffix, along with an
outputFileExtension() accessor matching the existing static accessors.
InMemoryPage identifiers can now declare a '.json', '.txt', or '.xml'
extension to compile to that path as-is, so
InMemoryPage::make('robots.txt', contents: ...) outputs '_site/robots.txt'.
This formalizes the route key convention already used by the documentation
search index: only the HTML extension is implicit in route keys, and pages
compiled to non-HTML files keep their extension in the route key. The
DocumentationSearchIndex getOutputPath() override is now redundant and removed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds testOutputFileExtension to the BaseHydePageUnitTest contract with implementations for all page classes, HydePage baseline and child class override tests, and InMemoryPage tests covering identifier-declared extensions including edge cases like dotted identifiers and unsupported extensions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Covers the user path of registering pages like robots.txt in a kernel booting callback and having them compiled to their declared output paths through the standard build command, including route registration, nested paths, and view-based compilation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completes the route key convention for page classes declaring a non-HTML output file extension: RouteKey::fromPage() now appends the declared extension to the key (unless the identifier already ends with it), so the route key always equals the output path with only the HTML extension implicit. Without this, a class declaring '.txt' would get the route key 'robots' but the output path 'robots.txt', breaking route resolution. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the resolved design decisions (identifier allowlist chosen for InMemoryPage, route key extension handling in RouteKey::fromPage, no setter, redirects intentionally not special-cased) and rewords the breaking-change note to reflect that double-extension output was never practically relied upon. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2524 +/- ##
============================================
Coverage 100.00% 100.00%
- Complexity 1720 1791 +71
============================================
Files 175 179 +4
Lines 4308 4469 +161
============================================
+ Hits 4308 4469 +161 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Renames HydePage::$fileExtension to $sourceExtension, with the fileExtension() and setFileExtension() methods becoming sourceExtension() and setSourceExtension(). The old name was underspecified: it actually meant the source file extension, which becomes ambiguous now that pages also declare an output extension. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pairs $outputExtension with $sourceExtension so the two declarations read as the symmetrical concepts they are, and documents the accessor by its purpose (values like `.html` or `.txt`) rather than leading with the serialization detail of the leading dot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ternary compressed the domain distinction (only the HTML extension is implicit in route keys) to the point of needing a narrating comment. The expanded conditional makes the rule visible on its own; the broader route-key rule is documented on the RouteKey class. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renames InMemoryPage::identifierDeclaresOutputExtension() to identifierHasExplicitOutputExtension() and names the allowlist as the EXPLICIT_OUTPUT_EXTENSIONS constant, so subclasses can customize the recognized extensions by overriding data instead of replacing the algorithm. The docblocks now state the observable behavior (which extensions are recognized and what happens) instead of the vague "supported". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The helper returned either an extension or an empty-string sentinel, forcing the caller to concatenate an opaque fragment. Stating the whole route-key construction in one place makes the "only HTML is implicit" rule readable without control-flow-by-empty-string. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the breaking-change release note and upgrade step for the $fileExtension to $sourceExtension rename, and starts an upgrade script rules section in the planning document so the mechanical migrations the release-time upgrade script must perform are collected as we make them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The EXPLICIT_OUTPUT_EXTENSIONS constant is the advertised extension point for subclasses, so cover that overriding it both recognizes the custom extension and replaces the default list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Page classes can now compile to non-HTML files, so the accessor should not describe the output as HTML. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The renamed methods are public and non-final, so a subclass override of fileExtension() or setFileExtension() would silently stop being called once the framework calls sourceExtension(). The upgrade script rule and the upgrade guide now include renaming such declarations. Also moves the upgrade script rules to their own section at the end of the planning document instead of sitting under the empty v2-branch heading. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Appending to the identifier before joining the base route key produced keys like feed/.xml instead of feed.xml for non-HTML pages with an empty identifier and an output directory. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
outputExtension() returned the raw static property, so a typo like 'txt' (missing the dot) silently produced output paths like documenttxt. The accessor now throws an InvalidArgumentException for values that do not start with a dot or that contain path separators, matching the normalization the source extension setter already applies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A page class still declaring $fileExtension (or overriding the renamed methods) is not discoverable under the new API, so a build would succeed while silently omitting the entire page type — including unmodified vendor packages the upgrade script never touches. Discovery now throws an actionable exception naming the class and the rename. This is a temporary upgrade aid that can be removed in a future release. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A redirect declared for a path like legacy.json appears valid and produces a file, but the meta refresh markup cannot redirect when the file is served as non-HTML content. The configuration now fails fast with an InvalidConfigurationException instead of silently emitting a broken page. Revises the earlier document-only decision in the epic. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ends the coverage gap where only InMemoryPage was exercised through the full build: a custom page class with a .md source extension and a .txt output extension is now tested through source discovery, route registration, the build command, and the output file name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
[3.x] Support pages with more output file extensions (Add a robots.txt generator)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… default Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e method Removes HydePage::showInLlmsTxt() and its test contract entry. The generator now reads `llms` front matter defaulting to the page's sitemap inclusion, which already excludes generated non-HTML pages and redirects, keeping per-page control without adding public API to every page class. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The page types Hyde ships are known to the framework, so grouping them needed no user input to be correct. Dropping the config removes its validation, exception path, and drift guard, and leaves the llms config at two keys. Custom sections remain available by overriding the generator and rebinding it in the container. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drops the `llms` front matter key introduced alongside the generator. Leaving a page out of llms.txt does not stop AI services from reading it, as crawler access is governed by robots.txt, so the key could only ever mean "curate my index" — which is what `sitemap: false` already means. Front matter is public API we support for the life of the major version, and reintroducing the key later stays additive. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A page titled "Arrays [Advanced]" previously emitted a malformed Markdown link. Also documents and tests the ordering contract: sections in declaration order, pages in route order, which keeps numerically prefixed docs in their reading order. Makes the section map a method so generator overrides can compute it at runtime. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pins the documented answer to the one case the sitemap-derived rule cannot express: a page kept out of the sitemap for SEO reasons that should still reach an agent index. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This reverts commit 57b5c74.
[3.x] Support pages with more output file extensions (Add a llms.txt generator)
edee07f to
62feb3c
Compare
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.
Uh oh!
There was an error while loading. Please reload this page.