diff --git a/.claude/skills/pr/SKILL.md b/.claude/skills/pr/SKILL.md deleted file mode 100644 index 6d0af41..0000000 --- a/.claude/skills/pr/SKILL.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -name: pr -description: Create a pull request for the current branch using `gh`. Use this skill whenever the user wants to open a PR, push their branch for review, or says "/pr". Before creating the PR, it checks that the CHANGELOG.md [Unreleased] section reflects the changes and that the README docs are up-to-date, updating them and committing if needed. For release PRs (branches with a version bump commit), it also converts [Unreleased] to a versioned release entry and ensures the version bump is the tip commit. -model: claude-sonnet-4-6 -context: fork ---- - -# PR Skill - -Create a well-documented pull request, ensuring the changelog and docs are current before opening it. - -## Process - -### 1. Understand the changes - -Run in parallel: -- `git log main..HEAD --oneline` — commits on this branch -- `git diff main...HEAD -- src/` — what changed in source -- `git diff main...HEAD -- CHANGELOG.md README.md packages/esroute/README.md packages/esroute-lit/README.md` — what docs already changed - -If `git log main..HEAD` is empty, tell the user there's nothing to PR and stop. - -If there are uncommitted changes in `src/` (shown by `git status`), commit them automatically using the commit skill before proceeding — they're part of the work being PR'd. - -### 2. Detect a version bump (release PR) - -Check whether any commit on this branch touched a `package.json` version field: - -```bash -git log main..HEAD --oneline --diff-filter=M -- packages/esroute/package.json packages/esroute-lit/package.json -``` - -If this returns output, this is a **release PR**. Read the new version from `packages/esroute/package.json`. - -### 3. Check and update the CHANGELOG - -Open `CHANGELOG.md` and look at the `[Unreleased]` section. - -**It needs an entry if** there are any user-visible changes: new features, bug fixes, behavior changes, API additions or removals. It does not need an entry for test-only changes, internal refactors with no observable effect, or CI/tooling changes. - -If the `[Unreleased]` section is missing entries that match the changes, add them: - -```markdown -## [Unreleased] - -### Added -- Brief description of new capability (closes #N if applicable) - -### Fixed -- Brief description of what was broken and how it was fixed (closes #N if applicable) - -### Changed -- Brief description of behavioral or API change - -### Removed -- Brief description of removed feature or API -``` - -Only include sections that apply. Keep entries concise — one line per item. - -**If this is a release PR**, also promote `[Unreleased]` to a versioned heading. After ensuring entries are present, transform the top of the changelog from: - -```markdown -## [Unreleased] - - -``` - -to: - -```markdown -## [Unreleased] - -## [X.Y.Z] - YYYY-MM-DD - - -``` - -where `X.Y.Z` is the version from `packages/esroute/package.json` and `YYYY-MM-DD` is today's date. The `[Unreleased]` section is left empty above it. - -### 4. Check the README docs - -Scan for changes that affect the public API or documented behavior: - -- New exports in `src/index.ts` -- Changed type signatures that users interact with -- New options or methods on `createRouter` / `NavOpts` / `router` -- Changed defaults or behavior - -If a documented example is now wrong, or a new feature has no documentation, update the relevant README (`packages/esroute/README.md` or `packages/esroute-lit/README.md`). Don't add documentation for internal implementation details. - -### 5. Commit any doc updates - -If you changed CHANGELOG.md or any README, commit those files: - -```bash -git add CHANGELOG.md packages/esroute/README.md packages/esroute-lit/README.md -git commit -m "docs: update changelog and readme for PR" -``` - -Only commit docs files here — not source changes. - -### 6. Ensure the version bump is the tip commit (release PRs only) - -The version bump commit must be the most recent commit on the branch — the CI publisher uses it as the release trigger. Check: - -```bash -git log main..HEAD --format="%H" -- packages/esroute/package.json packages/esroute-lit/package.json | head -1 -``` - -If that hash does not match `git rev-parse HEAD`, the version bump is not at the tip. Reorder silently using cherry-pick: - -```bash -CURRENT_BRANCH=$(git branch --show-current) -VERSION_COMMIT=$(git log main..HEAD --format="%H" -- packages/esroute/package.json packages/esroute-lit/package.json | head -1) - -# All other commits in original order -OTHER_COMMITS=$(git log --reverse main..HEAD --format="%H" | grep -v "^${VERSION_COMMIT}$") - -# Rebuild branch on top of main with version bump last -git checkout -B ${CURRENT_BRANCH}_reorder main -echo "$OTHER_COMMITS" | xargs -r git cherry-pick -git cherry-pick $VERSION_COMMIT -git branch -M ${CURRENT_BRANCH}_reorder $CURRENT_BRANCH -``` - -Verify with `git log main..HEAD --oneline` that the version bump commit now appears first (topmost = most recent). - -### 7. Push and create the PR - -Push the branch (use `--force-with-lease` to handle the reorder case safely): - -```bash -git push -u origin HEAD --force-with-lease -``` - -Then create the PR targeting `main`: - -```bash -gh pr create --base main --title "" --body "$(cat <<'EOF' -## Summary -<bullet points: what this PR does and why> - -## Changes -<bullet points: key technical changes — types, behavior, API> - -## Changelog -<paste the versioned release section, or [Unreleased] entries, or "No user-visible changes."> -EOF -)" -``` - -**Title format**: for release PRs use `release: vX.Y.Z`. For non-release PRs, match the dominant commit type (`fix: ...`, `feat: ...`) or plain imperative. Keep it under 72 characters. - -**Body**: be factual and brief. The summary explains the *why*, the changes section explains the *what*. Don't pad with filler. - -### 8. Return the PR URL - -After `gh pr create` succeeds, show the user the URL. - -## Guidelines - -- Uncommitted source changes are always committed automatically — don't ask. -- Never bump version numbers — that's handled separately before invoking this skill. -- Don't add changelog entries for `test:`, `ci:`, `build:`, or `chore:` commits unless they change observable behavior. diff --git a/.gitignore b/.gitignore index 204948b..3d60a24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.claude node_modules dist demo/demo.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 373841a..8720a2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.12.3] - 2026-04-02 + ### Fixed - `router.go()` no longer exposes the `state` option for routes where no state type is declared, preventing accidental state passing on untyped routes diff --git a/packages/esroute-lit/package.json b/packages/esroute-lit/package.json index 382cbac..f00cc4d 100644 --- a/packages/esroute-lit/package.json +++ b/packages/esroute-lit/package.json @@ -1,8 +1,16 @@ { "name": "@esroute/lit", - "version": "0.12.2", + "version": "0.12.3", "description": "A small efficient client-side routing library for lit, written in TypeScript.", + "type": "module", + "types": "dist/index.d.ts", "main": "dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "sideEffects": false, "license": "MIT", "author": "Sven Rogge <mail@sven-rogge.com>", @@ -22,7 +30,7 @@ "typescript": "^5.4.5" }, "dependencies": { - "esroute": "^0.12.2", + "esroute": "^0.12.3", "lit": "^3.1.1" } } diff --git a/packages/esroute-lit/src/index.ts b/packages/esroute-lit/src/index.ts index ec3803b..065694d 100644 --- a/packages/esroute-lit/src/index.ts +++ b/packages/esroute-lit/src/index.ts @@ -1,2 +1,2 @@ export * from "esroute"; -export * from "./render-routes-directive"; +export * from "./render-routes-directive.js"; diff --git a/packages/esroute-lit/src/render-routes-directive.spec.ts b/packages/esroute-lit/src/render-routes-directive.spec.ts index 33fa1c3..38a3c82 100644 --- a/packages/esroute-lit/src/render-routes-directive.spec.ts +++ b/packages/esroute-lit/src/render-routes-directive.spec.ts @@ -1,7 +1,7 @@ import { createRouter } from "esroute"; import { html, render } from "lit"; import { beforeEach, describe, expect, it } from "vitest"; -import { renderRoutes } from "./render-routes-directive"; +import { renderRoutes } from "./render-routes-directive.js"; const router = createRouter<any>({ routes: { diff --git a/packages/esroute/package.json b/packages/esroute/package.json index f678caa..ba5870a 100644 --- a/packages/esroute/package.json +++ b/packages/esroute/package.json @@ -1,9 +1,16 @@ { "name": "esroute", - "version": "0.12.2", + "version": "0.12.3", "description": "A small efficient framework-agnostic client-side routing library, written in TypeScript.", + "type": "module", "types": "dist/index.d.ts", "main": "dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "sideEffects": false, "license": "MIT", "author": "Sven Rogge <mail@sven-rogge.com>", diff --git a/packages/esroute/src/index.ts b/packages/esroute/src/index.ts index c111d83..b3ad0ad 100644 --- a/packages/esroute/src/index.ts +++ b/packages/esroute/src/index.ts @@ -1,5 +1,5 @@ -export * from "./nav-opts"; -export * from "./route-resolver"; -export * from "./router"; -export * from "./routes"; -export * from "./scroll-restoration"; +export * from "./nav-opts.js"; +export * from "./route-resolver.js"; +export * from "./router.js"; +export * from "./routes.js"; +export * from "./scroll-restoration.js"; diff --git a/packages/esroute/src/nav-opts.spec.ts b/packages/esroute/src/nav-opts.spec.ts index c77d187..aa53790 100644 --- a/packages/esroute/src/nav-opts.spec.ts +++ b/packages/esroute/src/nav-opts.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { NavOpts } from "./nav-opts"; +import { NavOpts } from "./nav-opts.js"; describe("NavOpts", () => { describe("properties", () => { diff --git a/packages/esroute/src/route-resolver.spec.ts b/packages/esroute/src/route-resolver.spec.ts index 3e2aab8..a9eed64 100644 --- a/packages/esroute/src/route-resolver.spec.ts +++ b/packages/esroute/src/route-resolver.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it, vi } from "vitest"; -import { NavOpts } from "./nav-opts"; -import { resolve } from "./route-resolver"; -import { Routes } from "./routes"; +import { NavOpts } from "./nav-opts.js"; +import { resolve } from "./route-resolver.js"; +import { Routes } from "./routes.js"; describe("Resolver", () => { const notFound = vi.fn(); diff --git a/packages/esroute/src/route-resolver.ts b/packages/esroute/src/route-resolver.ts index 9a63fb6..95e7b08 100644 --- a/packages/esroute/src/route-resolver.ts +++ b/packages/esroute/src/route-resolver.ts @@ -1,5 +1,5 @@ -import { NavOpts } from "./nav-opts"; -import { Resolve, Routes } from "./routes"; +import { NavOpts } from "./nav-opts.js"; +import { Resolve, Routes } from "./routes.js"; export interface Resolved<T, S = any> { /** The resolved value of the route. */ diff --git a/packages/esroute/src/router.spec.ts b/packages/esroute/src/router.spec.ts index 46bba91..fdbfade 100644 --- a/packages/esroute/src/router.spec.ts +++ b/packages/esroute/src/router.spec.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi, type Mock } from "vitest"; -import { NavOpts } from "./nav-opts"; -import { Routes } from "./routes"; -import { createRouter } from "./router"; +import { NavOpts } from "./nav-opts.js"; +import { Routes } from "./routes.js"; +import { createRouter } from "./router.js"; // Define routes with proper typing to verify RoutePaths inference // Note: "fail" route is included for testing error handling diff --git a/packages/esroute/src/router.ts b/packages/esroute/src/router.ts index bb193e3..259d396 100644 --- a/packages/esroute/src/router.ts +++ b/packages/esroute/src/router.ts @@ -1,5 +1,5 @@ -import { NavMeta, NavOpts, PathOrHref, StrictNavMeta } from "./nav-opts"; -import { Resolved, resolve } from "./route-resolver"; +import { NavMeta, NavOpts, PathOrHref, StrictNavMeta } from "./nav-opts.js"; +import { Resolved, resolve } from "./route-resolver.js"; import { Resolve, Routes, @@ -8,7 +8,7 @@ import { HandlerFor, StateOf, NeedsState, -} from "./routes"; +} from "./routes.js"; export type OnResolveListener<T, S = any> = (resolved: Resolved<T, S>) => void; export interface Router<T = any, S = any, R extends RawRoutes = RawRoutes> { @@ -97,7 +97,7 @@ export interface RouterConf<T = any, S = any, R extends RawRoutes = RawRoutes> { export const createRouter = <T = any, S = any, R extends RawRoutes = RawRoutes>({ routes = {} as R & Routes<T, S>, - notFound = ({ go }) => go([]), + notFound = ({ go }: NavOpts<S>) => go([]), noClick = false, onResolve, }: RouterConf<T, S, R> = {}): Router<T, S, R> => { diff --git a/packages/esroute/src/routes.ts b/packages/esroute/src/routes.ts index ad2cdc3..f9822a7 100644 --- a/packages/esroute/src/routes.ts +++ b/packages/esroute/src/routes.ts @@ -1,4 +1,4 @@ -import { NavOpts } from "./nav-opts"; +import { NavOpts } from "./nav-opts.js"; export type RawRoutes = { [k: string]: RawRoutes | ((...args: any[]) => any); diff --git a/packages/esroute/src/scroll-restoration.ts b/packages/esroute/src/scroll-restoration.ts index 0970167..b5689ef 100644 --- a/packages/esroute/src/scroll-restoration.ts +++ b/packages/esroute/src/scroll-restoration.ts @@ -1,4 +1,4 @@ -import { NavOpts } from "./nav-opts"; +import { NavOpts } from "./nav-opts.js"; export const restoreHandling = ({ container = document.scrollingElement ?? document.body, diff --git a/tsconfig.json b/tsconfig.json index 576be45..85a671a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { "target": "es2019", - "module": "esnext", + "module": "node16", "moduleDetection": "force", - "moduleResolution": "bundler", + "moduleResolution": "node16", "declaration": true, "declarationMap": true, "sourceMap": true,