Skip to content

Commit e70291d

Browse files
committed
Add new version release notes and fix ./foo pattern link
1 parent 7be8470 commit e70291d

6 files changed

Lines changed: 136 additions & 14 deletions

File tree

.github/workflows/release.yml

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
permissions:
1313
contents: write
14+
packages: write
1415

1516
steps:
1617
- name: Checkout code
@@ -53,7 +54,7 @@ jobs:
5354
echo "label=Release" >> $GITHUB_OUTPUT
5455
elif [[ "${GITHUB_REF}" == refs/heads/release/* || "${GITHUB_REF}" == refs/heads/hotfix/* ]]; then
5556
echo "channel=rc" >> $GITHUB_OUTPUT
56-
echo "prerelease=false" >> $GITHUB_OUTPUT
57+
echo "prerelease=true" >> $GITHUB_OUTPUT
5758
echo "draft=true" >> $GITHUB_OUTPUT
5859
echo "label=RC" >> $GITHUB_OUTPUT
5960
elif [ "${GITHUB_REF}" = "refs/heads/develop" ]; then
@@ -80,6 +81,24 @@ jobs:
8081
echo "::error::Releases are only supported from master, develop, feature/*, release/*, and hotfix/* branches."
8182
exit 1
8283
84+
- name: Validate NuGet version channel
85+
if: steps.release_channel.outputs.channel != 'none'
86+
shell: bash
87+
run: |
88+
if [ "${GITHUB_REF}" = "refs/heads/master" ]; then
89+
if [[ "${VERSION}" == *-* ]]; then
90+
echo "::error::Master releases must produce a stable NuGet version, but GitVersion returned '${VERSION}'."
91+
exit 1
92+
fi
93+
94+
exit 0
95+
fi
96+
97+
if [[ "${VERSION}" != *-* ]]; then
98+
echo "::error::Non-master releases must produce a prerelease NuGet version, but GitVersion returned '${VERSION}'."
99+
exit 1
100+
fi
101+
83102
- name: Restore dependencies
84103
run: dotnet restore --artifacts-path=/tmp/artifacts/blazor-hashrouting
85104

@@ -191,17 +210,26 @@ jobs:
191210
"${release_args[@]}"
192211
fi
193212
194-
- name: Push package to NuGet
213+
- name: Push package to GitHub Packages
195214
if: steps.release_channel.outputs.channel != 'none'
196215
shell: bash
216+
run: |
217+
dotnet nuget push "/tmp/artifacts/blazor-hashrouting/package/release/Blazor.HashRouting.${VERSION}.nupkg" \
218+
--api-key "${{ secrets.GITHUB_TOKEN }}" \
219+
--source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
220+
--skip-duplicate
221+
222+
- name: Push package to NuGet
223+
if: steps.release_channel.outputs.channel == 'stable'
224+
shell: bash
197225
run: |
198226
dotnet nuget push "/tmp/artifacts/blazor-hashrouting/package/release/Blazor.HashRouting.${VERSION}.nupkg" \
199227
--api-key "${{ secrets.NUGET_API_KEY }}" \
200228
--source "https://api.nuget.org/v3/index.json" \
201229
--skip-duplicate
202230
203231
- name: Push symbols to NuGet
204-
if: steps.release_channel.outputs.channel != 'none'
232+
if: steps.release_channel.outputs.channel == 'stable'
205233
shell: bash
206234
run: |
207235
dotnet nuget push "/tmp/artifacts/blazor-hashrouting/package/release/Blazor.HashRouting.${VERSION}.snupkg" \

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ builder.Services.AddHashRouting(options =>
3838
## URL shape
3939

4040
- Root route: `/#/`
41-
- Nested route: `/#/settings`
42-
- Base-path route: `/proxy/app/#/settings`
41+
- Nested route: `/#/foo`
42+
- Base-path route: `/proxy/app/#/foo`
43+
44+
## Relative links
45+
46+
Relative anchor `href` values such as `./bar` are resolved relative to the application base URI, not the current hash route.
47+
48+
For example, from `/#/foo`, an anchor with `href="./bar"` canonicalizes to `/#/bar`, not `/#/foo/bar`.
4349

4450
## Supported environments
4551

release-notes/1.1.0-rc.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Blazor.HashRouting {{VERSION}}
2+
3+
## Summary
4+
5+
Release candidate build for the `{{MAJOR_MINOR_PATCH}}` line of `Blazor.HashRouting`.
6+
7+
This release improves link behavior for hash-routed applications by canonicalizing internal anchor `href` values to `/#/...` URLs so browser-managed actions such as middle-click, right-click open in new tab, and copied links continue to resolve through the hash router.
8+
9+
## Highlights
10+
11+
- Canonicalizes internal anchor `href` values to hash-route URLs
12+
- Preserves opt-out behavior for links that use non-`_self` targets or `download`
13+
- Keeps browser-managed navigation aligned with intercepted left-click navigation
14+
- Continues to support base-path deployments such as `/proxy/app/#/settings`
15+
16+
## Relative link resolution
17+
18+
Relative anchor `href` values such as `./bar` are resolved relative to the application base URI, not the current hash route.
19+
20+
For example, from `/#/foo`, an anchor with `href="./bar"` canonicalizes to `/#/bar`, not `/#/foo/bar`.
21+
22+
## Installation
23+
24+
```bash
25+
dotnet add package Blazor.HashRouting --version {{NUGET_VERSION}}
26+
```

release-notes/1.1.0.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Blazor.HashRouting {{VERSION}}
2+
3+
## Summary
4+
5+
Stable release for the `{{MAJOR_MINOR_PATCH}}` line of `Blazor.HashRouting`.
6+
7+
This release improves link behavior for hash-routed applications by canonicalizing internal anchor `href` values to `/#/...` URLs so browser-managed actions such as middle-click, right-click open in new tab, and copied links continue to resolve through the hash router.
8+
9+
## Highlights
10+
11+
- Canonicalizes internal anchor `href` values to hash-route URLs
12+
- Preserves opt-out behavior for links that use non-`_self` targets or `download`
13+
- Keeps browser-managed navigation aligned with intercepted left-click navigation
14+
- Continues to support base-path deployments such as `/proxy/app/#/settings`
15+
16+
## Relative link resolution
17+
18+
Relative anchor `href` values such as `./bar` are resolved relative to the application base URI, not the current hash route.
19+
20+
For example, from `/#/foo`, an anchor with `href="./bar"` canonicalizes to `/#/bar`, not `/#/foo/bar`.
21+
22+
## Installation
23+
24+
```bash
25+
dotnet add package Blazor.HashRouting --version {{NUGET_VERSION}}
26+
```

src/Blazor.HashRouting/wwwroot/hash-routing.module.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,8 @@ function attachHandlers() {
139139
return;
140140
}
141141

142-
let absoluteHrefUrl;
143-
try {
144-
absoluteHrefUrl = new URL(anchor.href, hashRoutingState.baseUri || document.baseURI);
145-
} catch {
142+
const absoluteHrefUrl = tryCreateAnchorAbsoluteHrefUrl(anchor);
143+
if (!absoluteHrefUrl) {
146144
return;
147145
}
148146

@@ -234,14 +232,13 @@ function rewriteAnchorsForNode(node) {
234232
}
235233

236234
function rewriteAnchorHref(anchor) {
237-
if (!hashRoutingState.options.interceptInternalLinks || anchor.hasAttribute("download")) {
235+
const target = anchor.getAttribute("target");
236+
if (!hashRoutingState.options.interceptInternalLinks || anchor.hasAttribute("download") || (target && target !== "_self")) {
238237
return;
239238
}
240239

241-
let absoluteHrefUrl;
242-
try {
243-
absoluteHrefUrl = new URL(anchor.href, hashRoutingState.baseUri || document.baseURI);
244-
} catch {
240+
const absoluteHrefUrl = tryCreateAnchorAbsoluteHrefUrl(anchor);
241+
if (!absoluteHrefUrl) {
245242
return;
246243
}
247244

@@ -263,6 +260,19 @@ function rewriteAnchorHref(anchor) {
263260
anchor.setAttribute("href", hashAbsoluteUri);
264261
}
265262

263+
function tryCreateAnchorAbsoluteHrefUrl(anchor) {
264+
const href = anchor.getAttribute("href");
265+
if (!href) {
266+
return null;
267+
}
268+
269+
try {
270+
return new URL(href, hashRoutingState.baseUri || document.baseURI);
271+
} catch {
272+
return null;
273+
}
274+
}
275+
266276
async function processBrowserNavigation(rawLocation, interceptedLink) {
267277
if (hashRoutingState.processingBrowserNavigation) {
268278
return;

test/Blazor.HashRouting.Test/HashRoutingJavaScriptBehaviorTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ public void GIVEN_InternalAnchorPresentBeforeInitialization_WHEN_InitializeCalle
111111
_target.GetAnchorHref(anchorIndex).Should().Be("http://localhost/#/details/ABC?tab=Peers");
112112
}
113113

114+
[Fact]
115+
public void GIVEN_InternalAnchorWithDotSlashHref_WHEN_InitializeCalled_THEN_AnchorHrefIsCanonicalizedToHashRoute()
116+
{
117+
var anchorIndex = _target.AppendAnchor("./tags");
118+
119+
_target.Initialize(
120+
"http://localhost/",
121+
"http://localhost/#/cookies",
122+
"http://localhost/cookies");
123+
124+
_target.GetAnchorHref(anchorIndex).Should().Be("http://localhost/#/tags");
125+
}
126+
114127
[Fact]
115128
public void GIVEN_InternalAnchorAddedAfterInitialization_WHEN_AnchorObserved_THEN_AnchorHrefIsCanonicalizedToHashRoute()
116129
{
@@ -143,6 +156,19 @@ public void GIVEN_InternalAnchor_WHEN_InitializeCalledWithLinkInterceptionDisabl
143156
_target.GetAnchorHref(anchorIndex).Should().Be("http://localhost/settings");
144157
}
145158

159+
[Fact]
160+
public void GIVEN_InternalAnchorWithNonSelfTarget_WHEN_InitializeCalled_THEN_AnchorHrefRemainsPathRoute()
161+
{
162+
var anchorIndex = _target.AppendAnchor("settings", "_blank");
163+
164+
_target.Initialize(
165+
"http://localhost/",
166+
"http://localhost/#/",
167+
"http://localhost/");
168+
169+
_target.GetAnchorHref(anchorIndex).Should().Be("http://localhost/settings");
170+
}
171+
146172
private sealed class HashRoutingJavaScriptTestHost
147173
{
148174
private readonly Engine _engine;

0 commit comments

Comments
 (0)