fix(cli): #1709 guard frontmatter title/label/id decode so a literal % cannot crash the build - #1710
Conversation
thescientist13
left a comment
There was a problem hiding this comment.
Awesome!
I wonder if we should try and handle this for the source plugin functionality too? 🤔
|
Checked the source-plugin path ( So no change needed for correctness. If you'd like symmetry anyway — e.g. guard the |
4c37a76 to
8d4e4e2
Compare
|
hmm, I think we should probably align the two APIs so the expectation is consistent for users, as opposed to having two different behaviors depending on which API you use. But then I also think, is there a gap in this for dynamic routing too? Thinking maybe specifically around get static paths handling, in that should // src/pages/product/[id].js
export async function getStaticPaths() {
const products = await getProducts();
return products.map((product) => {
return {
// return as many other params as you want
params: {
id: product.id,
name: product.name,
},
};
});
}That said, I could see the case being made that for Dynamic Routing and Source Plugins, since it's more of a BYOC (bring your own content) strategy, it could be stated that providing properly encoded values is an exercise left to the user, but then I also wonder why not just have Greenwood take care of the things it most needs to care about, like route in both these cases. So I think I would prefer at least for the things that Greenwood actually cares about / needs to use (e.g. route, label, title) should be handled, and / or we should clearly document what is handled by Greenwood in these cases, and what needs to be handled by the user. WDYT? |
524f551 to
2bcd855
Compare
|
Agreed on aligning the two APIs — done in 2bcd855 on this branch: external source-plugin nodes now run On your dynamic routing question — good instinct, and it's real, just not where I expected. The params themselves are fine (the decode added in #1714 is guarded), but a Since that's squarely in #1714's territory, I pushed 87957b3 there: a shared For docs, I'd propose stating it as: Greenwood normalizes the fields it owns — |
| // frontmatter values (e.g. "100% Complete") can contain a bare "%" that throws | ||
| // URIError and aborts the whole build, so fall back to the original string | ||
| // https://github.com/ProjectEvergreen/greenwood/issues/1709 | ||
| function safeDecodeURIComponent(value) { |
There was a problem hiding this comment.
why do think we need a try catch here? I notice in https://github.com/ProjectEvergreen/greenwood/pull/1714/changes#diff-9433f3990fd9cc31af7c346493e74ea36240f71dbd389a27d2ea659aae74bc6aR56 we didn't make a wrapper functions.
I notice in that other PR we just check for value, so not sure if there is a risk, should we create a helper function (maybe in url utils) that can be used in all these cases? 🤔
There was a problem hiding this comment.
The try/catch is the actual fix rather than defensive padding — decodeURIComponent throws URIError on any string containing a % that doesn't start a valid escape sequence ("100% Complete"), and that throw is what was killing the build in #1709. A value check can't catch it: the title ? ... : title ternary guards null/undefined, which is a different failure mode.
#1714 has the same guard, just inline instead of named — the Object.fromEntries map in getParamsFromSegment wraps each decodeURIComponent(value) in a try/catch for the same reason (a literal % in a getStaticPaths param).
Agreed a shared helper is the right home — done in 96de833: safeDecodeURIComponent now lives in lib/url-utils.js and graph.js imports it. Once #1714 lands I'll follow up to swap its inline try/catch over to the helper so every decode site goes through the one function.
And 👍 on the docs side — I'll open an issue for the frontmatter-encoding expectations.
There was a problem hiding this comment.
The try/catch is the actual fix rather than defensive padding
ah, interesting approach. thanks for the explanation
|
Yeah, if you wanted to make an issue / PR on the docs side, that would be great, just better guide developers on what is expected in which scenarios. 👍 |
|
Docs side is up: ProjectEvergreen/www.greenwoodjs.dev#291 tracks it, with the wording in ProjectEvergreen/www.greenwoodjs.dev#292 — a Special Characters section on the frontmatter page and a param-encoding note under Dynamic Prerendering. Flagged there that it should merge alongside or after the release line carrying this PR and #1714. |
…de so a literal % cannot crash the build
96de833 to
9b99b95
Compare
Related Issue
Resolves #1709
Documentation
N/A — no user-facing documentation changes (bug fix only).
Summary of Changes
safeDecodeURIComponenthelper inpackages/cli/src/lifecycles/graph.jsthat wrapsdecodeURIComponentin atry/catch and returns the original string on
URIError.id,label, andtitledecodes so validpercent-encoded filenames still decode, but a literal
%in frontmatter(e.g.
100% Complete,Save 20%) can no longer crash the build.packages/cli/test/cases/build.default.frontmatter-percent/with a fixturepage whose frontmatter title/label contain
%, asserting the build succeedsand the title reaches the output verbatim.
before; only the previously-fatal malformed-input path now falls back to the
raw string.