Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .eslintignore

This file was deleted.

18 changes: 0 additions & 18 deletions .eslintrc.cjs

This file was deleted.

20 changes: 11 additions & 9 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
name: Deploy

on:
workflow_dispatch:
workflow_dispatch: {}
release:
types: [published]

jobs:
publish-npm:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v5

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 24
registry-url: https://registry.npmjs.org/
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
node-version-file: .node-version

- run: make

- run: pnpm publish --access=public --no-git-checks
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
- run: pnpm publish --access=public --no-git-checks --provenance
17 changes: 11 additions & 6 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ on:

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
version: [24]
os: [ubuntu-latest]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v5

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version-file: .node-version
node-version: ${{ matrix.version }}
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'

- run: make test
1 change: 0 additions & 1 deletion .node-version

This file was deleted.

13 changes: 13 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"jsxSingleQuote": false,
"printWidth": 80,
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"useTabs": false,
"semi": true,
"sortPackageJson": true,
"ignorePatterns": ["pnpm-lock.yaml", "node_modules", "dist", "build"],
}
4 changes: 0 additions & 4 deletions .prettierignore

This file was deleted.

7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"biome.enabled": false,
"prettier.enable": false,
"eslint.enable": false,
"oxc.enable": true,
"typescript.tsdk": "node_modules/typescript/lib",
}
3 changes: 2 additions & 1 deletion CREDITS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Credit to [@nikparo](https://github.com/nikparo) for "Running React parent effects before child effects"
Credit to [@nikparo](https://github.com/nikparo) for "Running React parent
effects before child effects"

```
// Sometimes you want to run parent effects before those of the children. E.g. when setting
Expand Down
23 changes: 6 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@

SRCS := $(shell find lib -print -name *.ts?)

all: build/main.js types
.PHONY: all
all: test

.PHONY: clean
clean:
pnpm tsc -b --clean
rm -rf dist build

.PHONY: distclean
distclean: clean
Expand All @@ -15,26 +13,17 @@ distclean: clean
.PHONY: test
test: node_modules
pnpm tsc --noEmit
pnpm vitest run
$(MAKE) build/main.js
pnpm vitest run --typecheck

.PRECIOUS: pnpm-lock.yaml
node_modules: pnpm-lock.yaml package.json
pnpm install

.PHONY: dev
dev: node_modules
pnpm vite dev

.PHONY: types
types: node_modules
pnpm tsc

build/main.js: node_modules $(SRCS) bundlesize.config.cjs
NODE_ENV=production pnpm vite build
npx bundlesize
pnpm vite dev --config examples/vite.config.ts examples

.PHONY: pretty
pretty:
pnpm eslint --fix .
pnpm prettier --write .
pnpm oxlint --fix .
pnpm oxfmt --write .
2 changes: 1 addition & 1 deletion __tests__/components/NavigationInsideEffect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type FC, useEffect } from 'react';
import { useNavigate } from '../../src/index.js';
import { useNavigate } from '@block65/mrr';
import { LocationDisplay } from '../main.test.js';

export const NavigationInsideEffect: FC = () => {
Expand Down
5 changes: 2 additions & 3 deletions __tests__/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import { expect, test } from 'vitest';
import type { ExtractRouteParams } from '../lib/types.js';
import { Route, Router, Routes, useRouteParams } from '../src/index.js';
import { namedRoute } from '../src/named-route.js';
import { Route, Router, Routes, useRouteParams } from '@block65/mrr';
import { namedRoute } from '@block65/mrr/named-route';

const login = namedRoute('/foo/:foo/bar/:bar?');

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const EffCee = (_: ExtractRouteParams<typeof login.path>) => {
const match = useRouteParams();
return <pre>{JSON.stringify(match, null, 2)}</pre>;
Expand Down
4 changes: 2 additions & 2 deletions __tests__/link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { render } from '@testing-library/react';
import type { AnchorHTMLAttributes, FC, PropsWithChildren } from 'react';
import { FormattedMessage, IntlProvider } from 'react-intl';
import { expect, test } from 'vitest';
import { Link, Router } from '../src/index.js';
import { namedRoute } from '../src/named-route.js';
import { Link, Router } from '@block65/mrr';
import { namedRoute } from '@block65/mrr/named-route';

const ComponentThatTakesProps: FC<
PropsWithChildren<AnchorHTMLAttributes<HTMLAnchorElement>>
Expand Down
4 changes: 2 additions & 2 deletions __tests__/main.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { expect, test } from 'vitest';
import { Link, Route, Router, Routes, useLocation } from '../src/index.js';
import { namedRoute } from '../src/named-route.js';
import { Link, Route, Router, Routes, useLocation } from '@block65/mrr';
import { namedRoute } from '@block65/mrr/named-route';

export const LocationDisplay = () => {
const [location] = useLocation();
Expand Down
63 changes: 63 additions & 0 deletions __tests__/named-route.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { assertType, expectTypeOf, test } from 'vitest';
import { namedRoute } from '@block65/mrr/named-route';

test('paramless route - build is optional', () => {
const route = namedRoute('/');
assertType<string>(route.build());
assertType<string>(route.build({ hash: '#foo' }));
});

test('parameterised route - params required', () => {
const route = namedRoute('/user/:id');
assertType<string>(route.build({ params: { id: '1' } }));

// @ts-expect-error - params is required
route.build();
// @ts-expect-error - params is required
route.build({});
// @ts-expect-error - id is required
route.build({ params: {} });
});

test('searchParams() narrows searchParams type', () => {
const route = namedRoute('/search').searchParams<{ q: string }>();

assertType<string>(route.build({ searchParams: { q: 'hello' } }));

// @ts-expect-error - wrong key
route.build({ searchParams: { wrong: 'nope' } });
// @ts-expect-error - missing required key
route.build({ searchParams: {} });
});

test('searchParams() with path params', () => {
const route = namedRoute('/user/:id').searchParams<{ tab: string }>();

assertType<string>(
route.build({ params: { id: '1' }, searchParams: { tab: 'posts' } }),
);

// @ts-expect-error - params still required
route.build({ searchParams: { tab: 'posts' } });
// @ts-expect-error - wrong searchParams key
route.build({ params: { id: '1' }, searchParams: { wrong: 'nope' } });
});

test('path type is preserved as literal', () => {
const route = namedRoute('/user/:id');
expectTypeOf(route.path).toEqualTypeOf<'/user/:id'>();
});

test('path type preserved through searchParams()', () => {
const route = namedRoute('/user/:id').searchParams<{ q: string }>();
expectTypeOf(route.path).toEqualTypeOf<'/user/:id'>();
});

test('searchParams is chainable', () => {
const route = namedRoute('/').searchParams<{ a: string }>();
const route2 = route.searchParams<{ b: string }>();

assertType<string>(route2.build({ searchParams: { b: 'yes' } }));
// @ts-expect-error - old type no longer valid
route2.build({ searchParams: { a: 'nope' } });
});
2 changes: 1 addition & 1 deletion __tests__/named-route.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';
import { expect, test } from 'vitest';
import { namedRoute } from '../src/named-route.js';
import { namedRoute } from '@block65/mrr/named-route';

const route1 = namedRoute('/');
const route2 = namedRoute('/test');
Expand Down
4 changes: 2 additions & 2 deletions __tests__/navigate.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import type { FC } from 'react';
import { expect, test } from 'vitest';
import { Route, Router, Routes, useNavigate } from '../src/index.js';
import { namedRoute } from '../src/named-route.js';
import { Route, Router, Routes, useNavigate } from '@block65/mrr';
import { namedRoute } from '@block65/mrr/named-route';
import { NavigationInsideEffect } from './components/NavigationInsideEffect.js';
import { LocationDisplay } from './main.test.js';

Expand Down
4 changes: 2 additions & 2 deletions __tests__/nested.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import '@testing-library/jest-dom';
import { render, screen, waitFor } from '@testing-library/react';
import type { FC } from 'react';
import { expect, test } from 'vitest';
import { namedRoute } from '../lib/named-route.js';
import { Route, Router, Routes } from '../src/index.js';
import { namedRoute } from '@block65/mrr/named-route';
import { Route, Router, Routes } from '@block65/mrr';
import { LocationDisplay } from './main.test.js';

test('wildcard routes + nested', async () => {
Expand Down
4 changes: 2 additions & 2 deletions __tests__/route.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import { useCallback, useEffect, type FC } from 'react';
import { expect, test, vi } from 'vitest';
import { namedRoute } from '../lib/named-route.js';
import { namedRoute } from '@block65/mrr/named-route';
import type { RouteComponentProps } from '../lib/types.js';
import {
Route,
Router,
Routes,
type SyntheticNavigateEvent,
} from '../src/index.js';
} from '@block65/mrr';

const login = namedRoute('/');

Expand Down
4 changes: 2 additions & 2 deletions __tests__/type-inference.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import { expect, test } from 'vitest';
import type { ExtractRouteParams } from '../lib/types.js';
import { Route, Router, Routes } from '../src/index.js';
import { namedRoute } from '../src/named-route.js';
import { Route, Router, Routes } from '@block65/mrr';
import { namedRoute } from '@block65/mrr/named-route';

const login = namedRoute('/foo/:foo');

Expand Down
14 changes: 0 additions & 14 deletions bundlesize.config.cjs

This file was deleted.

Loading