@wavelengthusaf/client-router 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/elements/RouteElement.d.ts +11 -0
- package/dist/src/elements/RouteElement.d.ts.map +1 -0
- package/dist/src/elements/RouterElement.d.ts +12 -0
- package/dist/src/elements/RouterElement.d.ts.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/models/CompiledRoute.d.ts +7 -0
- package/dist/src/models/CompiledRoute.d.ts.map +1 -0
- package/dist/src/models/MatchedRoute.d.ts +7 -0
- package/dist/src/models/MatchedRoute.d.ts.map +1 -0
- package/dist/src/models/RouteComponent.d.ts +6 -0
- package/dist/src/models/RouteComponent.d.ts.map +1 -0
- package/dist/src/models/RouteContext.d.ts +7 -0
- package/dist/src/models/RouteContext.d.ts.map +1 -0
- package/dist/src/models/RouteDefinition.d.ts +6 -0
- package/dist/src/models/RouteDefinition.d.ts.map +1 -0
- package/dist/src/models/RouteGuard.d.ts +3 -0
- package/dist/src/models/RouteGuard.d.ts.map +1 -0
- package/dist/src/models/RouteParams.d.ts +4 -0
- package/dist/src/models/RouteParams.d.ts.map +1 -0
- package/dist/src/models/index.d.ts +9 -0
- package/dist/src/models/index.d.ts.map +1 -0
- package/dist/src/router/Router.d.ts +20 -0
- package/dist/src/router/Router.d.ts.map +1 -0
- package/dist/src/utils/compileRoute.d.ts +3 -0
- package/dist/src/utils/compileRoute.d.ts.map +1 -0
- package/dist/src/utils/index.d.ts +4 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/matchRoute.d.ts +3 -0
- package/dist/src/utils/matchRoute.d.ts.map +1 -0
- package/package.json +7 -1
- package/.gitlab-ci.yml +0 -84
- package/.husky/pre-commit +0 -38
- package/.storybook/main.ts +0 -16
- package/.storybook/manager.ts +0 -7
- package/.storybook/preview.ts +0 -23
- package/.storybook/theme.ts +0 -30
- package/.storybook/vitest.setup.ts +0 -7
- package/eslint.config.mjs +0 -89
- package/index.ts +0 -15
- package/prettier.config.ts +0 -30
- package/src/elements/RouteElement.ts +0 -67
- package/src/elements/RouterElement.ts +0 -97
- package/src/elements/__tests__/RouteElement.test.ts +0 -89
- package/src/elements/__tests__/RouterElement.test.ts +0 -253
- package/src/index.ts +0 -15
- package/src/models/CompiledRoute.ts +0 -7
- package/src/models/MatchedRoute.ts +0 -7
- package/src/models/RouteComponent.ts +0 -6
- package/src/models/RouteContext.ts +0 -7
- package/src/models/RouteDefinition.ts +0 -6
- package/src/models/RouteGuard.ts +0 -6
- package/src/models/RouteParams.ts +0 -3
- package/src/models/index.ts +0 -17
- package/src/router/Router.ts +0 -225
- package/src/router/__tests__/Router.test.ts +0 -464
- package/src/stories/RouterElement.stories.test.ts +0 -310
- package/src/stories/RouterElement.stories.ts +0 -208
- package/src/utils/__tests__/compileRoute.test.ts +0 -97
- package/src/utils/__tests__/matchRoute.test.ts +0 -180
- package/src/utils/compileRoute.ts +0 -37
- package/src/utils/index.ts +0 -4
- package/src/utils/matchRoute.ts +0 -37
- package/tsconfig.build.json +0 -20
- package/tsconfig.json +0 -55
- package/vitest.config.ts +0 -34
- package/vitest.setup.ts +0 -3
- package/vitest.shims.d.ts +0 -1
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { matchRoute } from '../matchRoute.ts';
|
|
3
|
-
|
|
4
|
-
function route(path: string, paramNames: string[] = []) {
|
|
5
|
-
return {
|
|
6
|
-
routeDefinition: { path },
|
|
7
|
-
pattern: new RegExp(`^${path.replace(':id', '([^/]+)')}$`),
|
|
8
|
-
paramNames,
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
describe('matchRoute', () => {
|
|
13
|
-
describe('basic matching', () => {
|
|
14
|
-
it.each([
|
|
15
|
-
{
|
|
16
|
-
routes: [route('/home')],
|
|
17
|
-
path: '/home',
|
|
18
|
-
expected: '/home',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
routes: [route('/about')],
|
|
22
|
-
path: '/about',
|
|
23
|
-
expected: '/about',
|
|
24
|
-
},
|
|
25
|
-
])('matches static route %#', ({ routes, path, expected }) => {
|
|
26
|
-
// @ts-expect-error (passing wrong parameters)
|
|
27
|
-
const result = matchRoute(routes, path);
|
|
28
|
-
|
|
29
|
-
expect(result?.routeDefinition.path).toBe(expected);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('params', () => {
|
|
34
|
-
it('extracts single param', () => {
|
|
35
|
-
const routes = [
|
|
36
|
-
{
|
|
37
|
-
routeDefinition: { path: '/users/:id' },
|
|
38
|
-
pattern: /^\/users\/([^/]+)$/,
|
|
39
|
-
paramNames: ['id'],
|
|
40
|
-
},
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
// @ts-expect-error (passing wrong parameters)
|
|
44
|
-
const result = matchRoute(routes, '/users/123');
|
|
45
|
-
|
|
46
|
-
expect(result?.routeParams).toEqual({
|
|
47
|
-
id: '123',
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('extracts multiple params', () => {
|
|
52
|
-
const routes = [
|
|
53
|
-
{
|
|
54
|
-
routeDefinition: { path: '/a/:x/b/:y' },
|
|
55
|
-
pattern: /^\/a\/([^/]+)\/b\/([^/]+)$/,
|
|
56
|
-
paramNames: ['x', 'y'],
|
|
57
|
-
},
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
// @ts-expect-error (passing wrong parameters)
|
|
61
|
-
const result = matchRoute(routes, '/a/1/b/2');
|
|
62
|
-
|
|
63
|
-
expect(result?.routeParams).toEqual({
|
|
64
|
-
x: '1',
|
|
65
|
-
y: '2',
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('priority', () => {
|
|
71
|
-
it('returns first matching route', () => {
|
|
72
|
-
const routes = [
|
|
73
|
-
{
|
|
74
|
-
routeDefinition: { path: '/users' },
|
|
75
|
-
pattern: /^\/users$/,
|
|
76
|
-
paramNames: [],
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
routeDefinition: { path: '/users/:id' },
|
|
80
|
-
pattern: /^\/users\/([^/]+)$/,
|
|
81
|
-
paramNames: ['id'],
|
|
82
|
-
},
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
// @ts-expect-error (passing wrong parameters)
|
|
86
|
-
const result = matchRoute(routes, '/users');
|
|
87
|
-
|
|
88
|
-
expect(result?.routeDefinition.path).toBe('/users');
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('no match', () => {
|
|
93
|
-
it('returns null when no routes match', () => {
|
|
94
|
-
const routes = [
|
|
95
|
-
{
|
|
96
|
-
routeDefinition: { path: '/a' },
|
|
97
|
-
pattern: /^\/a$/,
|
|
98
|
-
paramNames: [],
|
|
99
|
-
},
|
|
100
|
-
];
|
|
101
|
-
|
|
102
|
-
// @ts-expect-error (passing wrong parameters)
|
|
103
|
-
const result = matchRoute(routes, '/b');
|
|
104
|
-
|
|
105
|
-
expect(result).toBeNull();
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('decodeURIComponent', () => {
|
|
110
|
-
it('decodes encoded values', () => {
|
|
111
|
-
const routes = [
|
|
112
|
-
{
|
|
113
|
-
routeDefinition: { path: '/search/:query' },
|
|
114
|
-
pattern: /^\/search\/([^/]+)$/,
|
|
115
|
-
paramNames: ['query'],
|
|
116
|
-
},
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
// @ts-expect-error (passing wrong parameters)
|
|
120
|
-
const result = matchRoute(routes, '/search/hello%20world');
|
|
121
|
-
|
|
122
|
-
expect(result?.routeParams.query).toBe('hello world');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe('undefined capture safety', () => {
|
|
127
|
-
it('skips param assignment when capture group is undefined', () => {
|
|
128
|
-
const routes = [
|
|
129
|
-
{
|
|
130
|
-
routeDefinition: { path: '/test/:id/:missing' },
|
|
131
|
-
pattern: /^\/test\/([^/]+)$/,
|
|
132
|
-
paramNames: ['id', 'missing'],
|
|
133
|
-
},
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
// @ts-expect-error (passing wrong parameters)
|
|
137
|
-
const result = matchRoute(routes, '/test/123');
|
|
138
|
-
|
|
139
|
-
expect(result).not.toBeNull();
|
|
140
|
-
expect(result!.routeParams).toEqual({
|
|
141
|
-
id: '123',
|
|
142
|
-
// missing should NOT exist
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('malformed encoding', () => {
|
|
148
|
-
it('does not throw on bad encoding', () => {
|
|
149
|
-
const routes = [
|
|
150
|
-
{
|
|
151
|
-
routeDefinition: { path: '/test/:id' },
|
|
152
|
-
pattern: /^\/test\/([^/]+)$/,
|
|
153
|
-
paramNames: ['id'],
|
|
154
|
-
},
|
|
155
|
-
];
|
|
156
|
-
|
|
157
|
-
// @ts-expect-error (passing wrong parameters)
|
|
158
|
-
const bad = () => matchRoute(routes, '/test/%E0%A4%A');
|
|
159
|
-
|
|
160
|
-
expect(bad).not.toThrow();
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
describe('strict matching', () => {
|
|
165
|
-
it('does not match partial paths', () => {
|
|
166
|
-
const routes = [
|
|
167
|
-
{
|
|
168
|
-
routeDefinition: { path: '/users/:id' },
|
|
169
|
-
pattern: /^\/users\/([^/]+)$/,
|
|
170
|
-
paramNames: ['id'],
|
|
171
|
-
},
|
|
172
|
-
];
|
|
173
|
-
|
|
174
|
-
// @ts-expect-error (passing wrong parameters)
|
|
175
|
-
expect(matchRoute(routes, '/users/123/extra')).toBeNull();
|
|
176
|
-
// @ts-expect-error (passing wrong parameters)
|
|
177
|
-
expect(matchRoute(routes, '/users')).toBeNull();
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { CompiledRoute, RouteDefinition } from '../models/index.ts';
|
|
2
|
-
|
|
3
|
-
function escapeRegex(str: string): string {
|
|
4
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function compileRoute(routeDefinition: RouteDefinition): CompiledRoute {
|
|
8
|
-
const paramNames: string[] = [];
|
|
9
|
-
|
|
10
|
-
if (routeDefinition.path === '*') {
|
|
11
|
-
return {
|
|
12
|
-
routeDefinition,
|
|
13
|
-
pattern: /^.*$/,
|
|
14
|
-
paramNames,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const pattern = routeDefinition.path
|
|
19
|
-
.split('/')
|
|
20
|
-
.map((segment) => {
|
|
21
|
-
const match = /^:([a-zA-Z_]\w*)$/.exec(segment);
|
|
22
|
-
|
|
23
|
-
if (match) {
|
|
24
|
-
paramNames.push(match[1]!);
|
|
25
|
-
return '([^/]+)';
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return escapeRegex(segment);
|
|
29
|
-
})
|
|
30
|
-
.join('\\/');
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
routeDefinition,
|
|
34
|
-
pattern: new RegExp(`^${pattern}$`),
|
|
35
|
-
paramNames,
|
|
36
|
-
};
|
|
37
|
-
}
|
package/src/utils/index.ts
DELETED
package/src/utils/matchRoute.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CompiledRoute,
|
|
3
|
-
MatchedRoute,
|
|
4
|
-
RouteParams,
|
|
5
|
-
} from '../models/index.ts';
|
|
6
|
-
|
|
7
|
-
export function matchRoute(
|
|
8
|
-
compiledRoutes: CompiledRoute[],
|
|
9
|
-
pathname: string,
|
|
10
|
-
): MatchedRoute | null {
|
|
11
|
-
for (const compiledRoute of compiledRoutes) {
|
|
12
|
-
const match: RegExpMatchArray | null = compiledRoute.pattern.exec(pathname);
|
|
13
|
-
|
|
14
|
-
if (!match) continue;
|
|
15
|
-
|
|
16
|
-
const routeParams: RouteParams = {};
|
|
17
|
-
|
|
18
|
-
compiledRoute.paramNames.forEach((name, i) => {
|
|
19
|
-
const value: string | undefined = match[i + 1];
|
|
20
|
-
|
|
21
|
-
if (value === undefined) return;
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
routeParams[name] = decodeURIComponent(value);
|
|
25
|
-
} catch {
|
|
26
|
-
routeParams[name] = value;
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
routeDefinition: compiledRoute.routeDefinition,
|
|
32
|
-
routeParams,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return null;
|
|
37
|
-
}
|
package/tsconfig.build.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"declarationMap": true,
|
|
6
|
-
"emitDeclarationOnly": true
|
|
7
|
-
},
|
|
8
|
-
"include": ["src/**/*.ts"],
|
|
9
|
-
"exclude": [
|
|
10
|
-
"node_modules",
|
|
11
|
-
"dist",
|
|
12
|
-
"coverage",
|
|
13
|
-
"vitest.config.ts",
|
|
14
|
-
"vitest.setup.ts",
|
|
15
|
-
"vitest.shims.d.ts",
|
|
16
|
-
".storybook",
|
|
17
|
-
"**/*.test.ts",
|
|
18
|
-
"src/**/*.stories.ts"
|
|
19
|
-
]
|
|
20
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
// File Layout
|
|
5
|
-
"rootDir": ".",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
|
|
8
|
-
// Environment Settings
|
|
9
|
-
// See also https://aka.ms/tsconfig/module
|
|
10
|
-
"module": "nodenext",
|
|
11
|
-
"target": "esnext",
|
|
12
|
-
"types": [],
|
|
13
|
-
// For nodejs:
|
|
14
|
-
// "lib": ["esnext"],
|
|
15
|
-
// "types": ["node"],
|
|
16
|
-
// and npm install -D @types/node
|
|
17
|
-
|
|
18
|
-
// Other Outputs
|
|
19
|
-
"sourceMap": true,
|
|
20
|
-
"declaration": true,
|
|
21
|
-
"declarationMap": true,
|
|
22
|
-
"emitDeclarationOnly": true,
|
|
23
|
-
|
|
24
|
-
// Stricter Typechecking Options
|
|
25
|
-
"noUncheckedIndexedAccess": true,
|
|
26
|
-
"exactOptionalPropertyTypes": true,
|
|
27
|
-
"allowImportingTsExtensions": true,
|
|
28
|
-
|
|
29
|
-
// Style Options
|
|
30
|
-
// "noImplicitReturns": true,
|
|
31
|
-
// "noImplicitOverride": true,
|
|
32
|
-
// "noUnusedLocals": true,
|
|
33
|
-
// "noUnusedParameters": true,
|
|
34
|
-
// "noFallthroughCasesInSwitch": true,
|
|
35
|
-
// "noPropertyAccessFromIndexSignature": true,
|
|
36
|
-
|
|
37
|
-
// Recommended Options
|
|
38
|
-
"strict": true,
|
|
39
|
-
// "jsx": "react-jsx",
|
|
40
|
-
"verbatimModuleSyntax": true,
|
|
41
|
-
"isolatedModules": true,
|
|
42
|
-
"noUncheckedSideEffectImports": true,
|
|
43
|
-
"moduleDetection": "force",
|
|
44
|
-
"skipLibCheck": true
|
|
45
|
-
},
|
|
46
|
-
"exclude": [
|
|
47
|
-
"node_modules",
|
|
48
|
-
"dist",
|
|
49
|
-
"coverage",
|
|
50
|
-
"vitest.config.ts",
|
|
51
|
-
"vitest.setup.ts",
|
|
52
|
-
"vitest.shims.d.ts",
|
|
53
|
-
".storybook"
|
|
54
|
-
]
|
|
55
|
-
}
|
package/vitest.config.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import { defineConfig } from 'vitest/config';
|
|
4
|
-
|
|
5
|
-
const dirname =
|
|
6
|
-
typeof __dirname !== 'undefined'
|
|
7
|
-
? __dirname
|
|
8
|
-
: path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
|
|
10
|
-
export default defineConfig({
|
|
11
|
-
resolve: {
|
|
12
|
-
alias: {
|
|
13
|
-
'@': path.resolve(dirname, './src'),
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
test: {
|
|
17
|
-
environment: 'jsdom',
|
|
18
|
-
globals: true,
|
|
19
|
-
setupFiles: ['./vitest.setup.ts'],
|
|
20
|
-
include: ['src/**/*.test.ts'],
|
|
21
|
-
browser: {
|
|
22
|
-
enabled: false,
|
|
23
|
-
},
|
|
24
|
-
coverage: {
|
|
25
|
-
provider: 'v8',
|
|
26
|
-
thresholds: {
|
|
27
|
-
lines: 90,
|
|
28
|
-
functions: 90,
|
|
29
|
-
branches: 90,
|
|
30
|
-
statements: 90,
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
});
|
package/vitest.setup.ts
DELETED
package/vitest.shims.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="@vitest/browser-playwright" />
|