Repository navigation
Specifying branch name as a path param instead of a query param #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,9 @@ export function parseRoute(path) { | |
| return { | ||
| username: parts[0] || null, | ||
| repository: parts[1] || null, | ||
| branch: parts[2] || DEFAULT_BRANCH | ||
| // Join all branch segments, matching classifyRoute (paths such as | ||
| // /alice/repo/feature/login); default when none are present. | ||
| branch: parts.length > 2 ? parts.slice(2).join('/') : DEFAULT_BRANCH | ||
| }; | ||
| } | ||
|
|
||
|
|
@@ -44,7 +46,7 @@ export function isValidGitHubName(name) { | |
|
|
||
| // Classify a path into a route the application knows how to render. | ||
| export function classifyRoute(path) { | ||
| const { username, repository, branch } = parseRoute(path); | ||
| const { username, repository } = parseRoute(path); | ||
|
|
||
| if (!username) { | ||
| return { type: 'landing' }; | ||
|
|
@@ -71,33 +73,35 @@ export function classifyRoute(path) { | |
| } | ||
|
|
||
| const parts = path.split('/').filter(Boolean); | ||
| if (parts.length > 3) { | ||
| return { type: 'not-found' }; | ||
| } | ||
|
|
||
| // Path-injection guard: the branch segment is interpolated into raw | ||
| // content URLs; reject values like ".." that browsers would normalize | ||
| // into a different path. (Multi-segment branches are not expressible in | ||
| // classifyRoute paths — those arrive via ?branch= on the shell.) | ||
| if (!isValidGitHubName(branch)) { | ||
| // Branch names may contain slashes, so every segment beyond user/repo | ||
| // belongs to the branch name. Path-injection guard: each segment is | ||
| // interpolated into raw content URLs, so reject values like ".." that | ||
| // browsers would normalize into a different path. | ||
| const branchParts = parts.slice(2); | ||
| if (branchParts.some(part => !isValidGitHubName(part))) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Use a branch-specific validation rule. For a valid branch such as 🤖 Prompt for AI Agents |
||
| return { type: 'not-found' }; | ||
| } | ||
|
|
||
| return { type: 'report', username, repository, branch }; | ||
| return { | ||
| type: 'report', | ||
| username, | ||
| repository, | ||
| branch: branchParts.length ? branchParts.join('/') : DEFAULT_BRANCH | ||
| }; | ||
| } | ||
|
|
||
| export function buildReportUrl(username, repository, branch = DEFAULT_BRANCH) { | ||
| const base = `/${encodeURIComponent(username)}/${encodeURIComponent(repository)}`; | ||
| return branch === DEFAULT_BRANCH ? base : `${base}/${encodeURIComponent(branch)}`; | ||
| if (branch === DEFAULT_BRANCH) return base; | ||
| // Encode each slash-delimited component while preserving the separators: | ||
| // a slashed branch like "feature/login" must stay real path segments so | ||
| // classifyRoute and the 404-shell deep-link render recognize the URL. | ||
| const branchPath = branch.split('/').map(encodeURIComponent).join('/'); | ||
| return `${base}/${branchPath}`; | ||
|
Comment on lines
+100
to
+101
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '1,150p' lib/routes.js
rg -n 'isValidGitHubName|classifyRoute|parseRoute|branch|decodeURIComponent' app/not-found.jsx lib/routes.js tests/unit/routes.test.js tests/integration/not-found.test.jsx
sed -n '1,180p' app/not-found.jsx
sed -n '1,240p' tests/unit/routes.test.jsRepository: refactorfirst/refactorfirst.github.io Length of output: 25318 🏁 Script executed: sed -n '1,180p' tests/integration/not-found.test.jsx
printf '\n--- route consumers and pathname setup ---\n'
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'usePathname' app lib components tests
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'classifyRoute(' app lib components tests
printf '\n--- package versions and route tests ---\n'
sed -n '1,180p' package.json
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'release%candidate' .
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'feature/-hotfix' .Repository: refactorfirst/refactorfirst.github.io Length of output: 10318 🏁 Script executed: sed -n '1,180p' tests/integration/not-found.test.jsx
printf '\n--- pathname and classifier consumers ---\n'
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'usePathname' app lib components tests || true
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'classifyRoute(' app lib components tests || true
printf '\n--- package versions and focused cases ---\n'
sed -n '1,180p' package.json
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'release%candidate' . || true
rg -n -F --glob '*.{js,jsx,ts,tsx}' -- 'feature/-hotfix' . || trueRepository: refactorfirst/refactorfirst.github.io Length of output: 10319 Decode branch components before branch validation.
Decode each branch component once at the routing boundary. Use a shared branch-specific validator in 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| export function buildRepositoryListUrl(fullName) { | ||
| const [username, repository] = String(fullName).split('/'); | ||
| return buildReportUrl(username, repository); | ||
| } | ||
|
|
||
| export function getQueryParam(search, name) { | ||
| const params = new URLSearchParams(search || ''); | ||
| const value = params.get(name); | ||
| return value === null ? null : value; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Serve successful branch reports from a success response.
For an unlisted branch, this code renders the report inside
404.html, but the original URL still returns HTTP 404. Changingdocument.titledoes not change that response. Search crawlers do not index URLs that return 4xx, and Next.js documents anoindexmeta tag for 404 pages. Serve a success shell at the branch URL, or retain a redirect to a successful report URL where the host cannot provide one. (developers.google.com)🤖 Prompt for AI Agents