Skip to content

Commit 52bca60

Browse files
authored
Add utils entrypoint and new InvariantRoute type that doesn't have React dependency (#36)
* Add invariant route that can be imported without react * Add flowtypes for new entrypoint * Fix missing type and exporting of types * Remove unneeded exports in index.js.flow * Remove isRedirect field on route * Fix merge confict not renaming method
1 parent 62cf80b commit 52bca60

File tree

10 files changed

+455
-315
lines changed

10 files changed

+455
-315
lines changed

.flowconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[ignore]
22

33
[include]
4+
<PROJECT_ROOT>/src/*.flow
45

56
[libs]
67

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@
4545
"build:cjs": "babel src --out-dir build/cjs --extensions \".ts,.tsx\" --source-maps inline --ignore src/__tests__ --presets @babel/env",
4646
"build:clean": "rm -rf ./build",
4747
"build:esm": "babel src --out-dir build/esm --extensions \".ts,.tsx\" --source-maps inline --ignore src/__tests__",
48-
"build:types-cjs": "tsc --emitDeclarationOnly --project tsconfig.build.json --outDir build/cjs && cp src/index.js.flow build/cjs",
49-
"build:types-esm": "tsc --emitDeclarationOnly --project tsconfig.build.json --outDir build/esm && cp src/index.js.flow build/esm",
48+
"build:types-cjs": "tsc --emitDeclarationOnly --project tsconfig.build.json --outDir build/cjs && cp src/*.flow build/cjs",
49+
"build:types-esm": "tsc --emitDeclarationOnly --project tsconfig.build.json --outDir build/esm && cp src/*.flow build/esm",
5050
"docs": "npx docsify-cli serve docs",
5151
"lint": "eslint --ext .ts,.tsx,.js src/",
5252
"lint:deps": "madge -c --extensions ts,tsx src",

src/common/types.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ export type Query = {
4444
[key: string]: string;
4545
};
4646

47+
export type MatchedInvariantRoute = {
48+
route: InvariantRoute;
49+
match: Match;
50+
};
51+
4752
export type MatchedRoute = {
4853
route: Route;
4954
match: Match;
@@ -106,25 +111,43 @@ export type RouterContext = {
106111
query: Query;
107112
};
108113

109-
export type Route = {
114+
/**
115+
* Invariant route
116+
*
117+
* Base type for route, which doesn't contain implementation details
118+
*/
119+
export type InvariantRoute = {
110120
path: string;
111121
exact?: boolean;
112122

113-
/** The component to render on match, typed explicitly */
114-
component: ComponentType<RouteContext>;
115-
116-
/** If present, must return true to include the route. */
117-
enabled?: () => boolean;
118-
119-
/** Signals that this is a redirect route, we need to handle these in a special way. */
120-
isRedirect?: boolean;
121-
122123
/** Used to prevent transitions between app groups */
123124
group?: string;
124125

125126
/** Unique name for the route */
126127
name: string;
127128

129+
/**
130+
* Query string matching. Each query param must match for the route to match.
131+
*
132+
* A query param can take the following shapes:
133+
* * query name only: 'foo' - matches if query name 'foo' is present
134+
* * query name matching value: 'foo=bar' - matches if query name 'foo' equals
135+
* 'bar' exactly
136+
* * query name matching regex: 'foo=(bar.+) - matches if query name 'foo' equals
137+
* regex '^(bar.+)$'. Note you must escape backslashes and wrap regex in parentheses.
138+
* * query name NOT matching value: 'foo!=bar' - matches if query name 'foo' does
139+
* not equal bar OR if query name 'foo' does not exist at all
140+
*/
141+
query?: string[];
142+
};
143+
144+
export type Route = InvariantRoute & {
145+
/** The component to render on match, typed explicitly */
146+
component: ComponentType<RouteContext>;
147+
148+
/** If present, must return true to include the route. */
149+
enabled?: () => boolean;
150+
128151
/**
129152
* Triggered before leaving the route, can trigger full page reload if returns (or resolves) false.
130153
* Defaults to true.
@@ -134,6 +157,7 @@ export type Route = {
134157
nextRouteMatch: MatchedRoute,
135158
props: any
136159
) => boolean | Promise<boolean>;
160+
137161
/**
138162
* Triggered before entering the route, can trigger full page reload if returns (or resolves) false.
139163
* Defaults to true.
@@ -143,19 +167,7 @@ export type Route = {
143167
nextRouteMatch: MatchedRoute,
144168
props: any
145169
) => boolean | Promise<boolean>;
146-
/**
147-
* Query string matching. Each query param must match for the route to match.
148-
*
149-
* A query param can take the following shapes:
150-
* * query name only: 'foo' - matches if query name 'foo' is present
151-
* * query name matching value: 'foo=bar' - matches if query name 'foo' equals
152-
* 'bar' exactly
153-
* * query name matching regex: 'foo=(bar.+) - matches if query name 'foo' equals
154-
* regex '^(bar.+)$'. Note you must escape backslashes and wrap regex in parentheses.
155-
* * query name NOT matching value: 'foo!=bar' - matches if query name 'foo' does
156-
* not equal bar OR if query name 'foo' does not exist at all
157-
*/
158-
query?: string[];
170+
159171
/**
160172
* The resources for the route
161173
*/
@@ -164,6 +176,7 @@ export type Route = {
164176

165177
export type HistoryAction = 'PUSH' | 'REPLACE' | 'POP' | '';
166178

179+
export type InvariantRoutes = InvariantRoute[];
167180
export type Routes = Route[];
168181

169182
export type NavigationType = 'container' | 'product';

src/common/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { default as matchRoute } from './match-route';
1+
export { default as matchRoute, matchInvariantRoute } from './match-route';
22
export { default as generatePath } from './generate-path';
33
export { createLegacyHistory } from './history';
44
export { isServerEnvironment } from './is-server-environment';

src/common/utils/match-route/index.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { qs } from 'url-parse';
22

3-
import { Match, MatchedRoute, MatchParams, Query, Routes } from '../../types';
3+
import {
4+
Match,
5+
InvariantRoutes,
6+
MatchedRoute,
7+
MatchParams,
8+
MatchedInvariantRoute,
9+
Query,
10+
Routes,
11+
} from '../../types';
412

513
import matchPath from './matchPath';
614

@@ -86,11 +94,11 @@ const matchQuery = (
8694
*
8795
* Note: This does not support nested routes at this stage.
8896
*/
89-
export default (
90-
routes: Routes,
97+
const matchRoute = <T extends Routes | InvariantRoutes>(
98+
routes: T,
9199
pathname: string,
92100
queryParams: MatchParams
93-
): MatchedRoute | null => {
101+
): (T extends Routes ? MatchedRoute : MatchedInvariantRoute) | null => {
94102
const queryParamObject =
95103
typeof queryParams === 'string'
96104
? (qs.parse(queryParams) as Query)
@@ -118,3 +126,15 @@ export default (
118126

119127
return matchedRoute;
120128
};
129+
130+
export const matchInvariantRoute = (
131+
routes: InvariantRoutes,
132+
pathname: string,
133+
queryParams: MatchParams
134+
): MatchedInvariantRoute | null => matchRoute(routes, pathname, queryParams);
135+
136+
export default (
137+
routes: Routes,
138+
pathname: string,
139+
queryParams: MatchParams
140+
): MatchedRoute | null => matchRoute(routes, pathname, queryParams);

0 commit comments

Comments
 (0)