Match-id-e51d4589cde12b17ff1c8a88cd583ba7e7d5b6f3
This commit is contained in:
commit
74715c2565
|
@ -1,9 +1,10 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||
import execute from 'rollup-plugin-execute';
|
||||
import fs from 'fs';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
@ -19,20 +20,31 @@ if (!fs.existsSync(path.join(output, 'connectRouter'))) {
|
|||
fs.mkdirSync(path.join(output, 'connectRouter'), { recursive: true });
|
||||
}
|
||||
|
||||
const routerBuildConfig = {
|
||||
input: { router: routerEntry },
|
||||
output: [
|
||||
const routerBuildConfig = mode => {
|
||||
const prod = mode.startsWith('prod');
|
||||
const outputList = [
|
||||
{
|
||||
dir: path.resolve(output, 'router/cjs'),
|
||||
sourcemap: 'inline',
|
||||
file: path.join(output, `router/cjs/router.${prod ? 'min.' : ''}js`),
|
||||
sourcemap: 'true',
|
||||
format: 'cjs',
|
||||
},
|
||||
{
|
||||
dir: path.resolve(output, 'router/esm'),
|
||||
sourcemap: 'inline',
|
||||
format: 'esm',
|
||||
file: path.join(output, `router/umd/router.${prod ? 'min.' : ''}js`),
|
||||
name: `HorizonRouter`,
|
||||
sourcemap: 'true',
|
||||
format: 'umd',
|
||||
},
|
||||
],
|
||||
];
|
||||
if (!prod) {
|
||||
outputList.push({
|
||||
file: path.join(output, `router/esm/router.js`),
|
||||
sourcemap: 'true',
|
||||
format: 'esm',
|
||||
});
|
||||
}
|
||||
return {
|
||||
input: routerEntry,
|
||||
output: outputList,
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
extensions,
|
||||
|
@ -45,23 +57,36 @@ const routerBuildConfig = {
|
|||
extensions,
|
||||
}),
|
||||
execute('npm run build-types-router'),
|
||||
prod && terser(),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const connectRouterConfig = {
|
||||
input: { connectRouter: connectRouterEntry },
|
||||
output: [
|
||||
const connectRouterConfig = mode => {
|
||||
const prod = mode.startsWith('prod');
|
||||
const outputList = [
|
||||
{
|
||||
dir: path.resolve(output, 'connectRouter/cjs'),
|
||||
sourcemap: 'inline',
|
||||
file: path.join(output, `connectRouter/cjs/connectRouter.${prod ? 'min.' : ''}js`),
|
||||
sourcemap: 'true',
|
||||
format: 'cjs',
|
||||
},
|
||||
{
|
||||
dir: path.resolve(output, 'connectRouter/esm'),
|
||||
sourcemap: 'inline',
|
||||
format: 'esm',
|
||||
file: path.join(output, `connectRouter/umd/connectRouter.${prod ? 'min.' : ''}js`),
|
||||
name: 'HorizonRouter',
|
||||
sourcemap: 'true',
|
||||
format: 'umd',
|
||||
},
|
||||
],
|
||||
];
|
||||
if (!prod) {
|
||||
outputList.push({
|
||||
file: path.join(output, `connectRouter/esm/connectRouter.js`),
|
||||
sourcemap: 'true',
|
||||
format: 'esm',
|
||||
});
|
||||
}
|
||||
return {
|
||||
input: connectRouterEntry,
|
||||
output: outputList,
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
extensions,
|
||||
|
@ -74,6 +99,7 @@ const connectRouterConfig = {
|
|||
extensions,
|
||||
}),
|
||||
execute('npm run build-types-all'),
|
||||
prod && terser(),
|
||||
copyFiles([
|
||||
{
|
||||
from: path.join(__dirname, 'src/configs/package.json'),
|
||||
|
@ -81,9 +107,9 @@ const connectRouterConfig = {
|
|||
},
|
||||
]),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function copyFiles(copyPairs) {
|
||||
return {
|
||||
name: 'copy-files',
|
||||
|
@ -96,5 +122,9 @@ function copyFiles(copyPairs) {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
export default [routerBuildConfig, connectRouterConfig];
|
||||
export default [
|
||||
routerBuildConfig('dev'),
|
||||
routerBuildConfig('prod'),
|
||||
connectRouterConfig('dev'),
|
||||
connectRouterConfig('prod'),
|
||||
];
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import { Action, Path } from '../history/types';
|
||||
type Location = Partial<Path>;
|
||||
export declare enum ActionName {
|
||||
LOCATION_CHANGE = "$horizon-router/LOCATION_CHANGE",
|
||||
CALL_HISTORY_METHOD = "$horizon-router/CALL_HISTORY_METHOD"
|
||||
}
|
||||
export type ActionMessage = {
|
||||
type: ActionName.LOCATION_CHANGE;
|
||||
payload: {
|
||||
location: Location;
|
||||
action: Action;
|
||||
isFirstRendering: boolean;
|
||||
};
|
||||
} | {
|
||||
type: ActionName.CALL_HISTORY_METHOD;
|
||||
payload: {
|
||||
method: string;
|
||||
args: any;
|
||||
};
|
||||
};
|
||||
export declare const onLocationChanged: (location: Location, action: Action, isFirstRendering?: boolean) => ActionMessage;
|
||||
export declare const push: (...args: any) => ActionMessage;
|
||||
export declare const replace: (...args: any) => ActionMessage;
|
||||
export declare const go: (...args: any) => ActionMessage;
|
||||
export {};
|
|
@ -1,3 +0,0 @@
|
|||
import { ActionMessage } from './actions';
|
||||
import { History } from '../history/types';
|
||||
export declare function routerMiddleware(history: History): (_: any) => (next: any) => (action: ActionMessage) => any;
|
|
@ -1,11 +0,0 @@
|
|||
export { getConnectedRouter } from './connectedRouter';
|
||||
export declare const connectRouter: (history: import("../router").History<unknown>) => (state?: {
|
||||
location: Partial<import("../router").Location<unknown>> & {
|
||||
query?: Record<string, any>;
|
||||
};
|
||||
action: import("../history/types").Action;
|
||||
}, { type, payload }?: {
|
||||
type?: import("./actions").ActionName;
|
||||
payload?: any;
|
||||
}) => any;
|
||||
export { routerMiddleware } from './dispatch';
|
|
@ -1,16 +0,0 @@
|
|||
import { ActionName } from './actions';
|
||||
import { Action, History } from '../history/types';
|
||||
import { Location } from '../router';
|
||||
type LocationWithQuery = Partial<Location> & {
|
||||
query?: Record<string, any>;
|
||||
};
|
||||
type InitRouterState = {
|
||||
location: LocationWithQuery;
|
||||
action: Action;
|
||||
};
|
||||
type Payload = {
|
||||
type?: ActionName;
|
||||
payload?: any;
|
||||
};
|
||||
export declare function createConnectRouter(): (history: History) => (state?: InitRouterState, { type, payload }?: Payload) => any;
|
||||
export {};
|
|
@ -1,10 +0,0 @@
|
|||
import { HistoryProps, Listener, Navigation, Prompt } from './types';
|
||||
import transitionManager from './transitionManager';
|
||||
export declare function getBaseHistory<S>(transitionManager: transitionManager<S>, setListener: (delta: number) => void, browserHistory: History): {
|
||||
go: (step: number) => void;
|
||||
goBack: () => void;
|
||||
goForward: () => void;
|
||||
listen: (listener: Listener<S>) => () => void;
|
||||
block: (prompt?: Prompt<S>) => () => void;
|
||||
getUpdateStateFunc: (historyProps: HistoryProps<S>) => (nextState: Navigation<S> | undefined) => void;
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
import { BaseOption, DefaultStateType, History } from './types';
|
||||
export type BrowserHistoryOption = {
|
||||
/**
|
||||
* forceRefresh为True时跳转时会强制刷新页面
|
||||
*/
|
||||
forceRefresh?: boolean;
|
||||
} & BaseOption;
|
||||
export declare function createBrowserHistory<S = DefaultStateType>(options?: BrowserHistoryOption): History<S>;
|
|
@ -1,4 +0,0 @@
|
|||
export declare function isBrowser(): boolean;
|
||||
export declare function getDefaultConfirmation(message: string, callBack: (result: boolean) => void): void;
|
||||
export declare function isSupportHistory(): boolean;
|
||||
export declare function isSupportsPopState(): boolean;
|
|
@ -1,7 +0,0 @@
|
|||
import { BaseOption, DefaultStateType, History } from './types';
|
||||
export type urlHashType = 'slash' | 'noslash';
|
||||
type HashHistoryOption = {
|
||||
hashType?: urlHashType;
|
||||
} & BaseOption;
|
||||
export declare function createHashHistory<S = DefaultStateType>(option?: HashHistoryOption): History<S>;
|
||||
export {};
|
|
@ -1,11 +0,0 @@
|
|||
import { Action, CallBackFunc, ConfirmationFunc, Listener, Location, Navigation, Prompt, TManager } from './types';
|
||||
declare class TransitionManager<S> implements TManager<S> {
|
||||
private prompt;
|
||||
private listeners;
|
||||
constructor();
|
||||
setPrompt(prompt: Prompt<S>): () => void;
|
||||
addListener(func: Listener<S>): () => void;
|
||||
notifyListeners(args: Navigation<S>): void;
|
||||
confirmJumpTo(location: Location<S>, action: Action, userConfirmationFunc: ConfirmationFunc, callBack: CallBackFunc): void;
|
||||
}
|
||||
export default TransitionManager;
|
|
@ -1,56 +0,0 @@
|
|||
export type BaseOption = {
|
||||
basename?: string;
|
||||
getUserConfirmation?: ConfirmationFunc;
|
||||
};
|
||||
export interface HistoryProps<T = unknown> {
|
||||
readonly action: Action;
|
||||
readonly location: Location<T>;
|
||||
length: number;
|
||||
}
|
||||
export interface History<T = unknown> extends HistoryProps<T> {
|
||||
createHref(path: Partial<Path>): string;
|
||||
push(to: To, state?: T): void;
|
||||
replace(to: To, state?: T): void;
|
||||
listen(listener: Listener<T>): () => void;
|
||||
block(prompt: Prompt<T>): () => void;
|
||||
go(index: number): void;
|
||||
goBack(): void;
|
||||
goForward(): void;
|
||||
}
|
||||
export declare enum Action {
|
||||
pop = "POP",
|
||||
push = "PUSH",
|
||||
replace = "REPLACE"
|
||||
}
|
||||
export declare enum EventType {
|
||||
PopState = "popstate",
|
||||
HashChange = "hashchange"
|
||||
}
|
||||
export type Path = {
|
||||
pathname: string;
|
||||
search: string;
|
||||
hash: string;
|
||||
};
|
||||
export type HistoryState<T> = {
|
||||
state?: T;
|
||||
key: string;
|
||||
};
|
||||
export type DefaultStateType = unknown;
|
||||
export type Location<T = unknown> = Path & HistoryState<T>;
|
||||
export type To = string | Partial<Path>;
|
||||
export interface Listener<T = unknown> {
|
||||
(navigation: Navigation<T>): void;
|
||||
}
|
||||
export interface Navigation<T = unknown> {
|
||||
action: Action;
|
||||
location: Location<T>;
|
||||
}
|
||||
export type Prompt<S> = string | boolean | null | ((location: Location<S>, action: Action) => void);
|
||||
export type CallBackFunc = (isJump: boolean) => void;
|
||||
export type ConfirmationFunc = (message: string, callBack: CallBackFunc) => void;
|
||||
export interface TManager<S> {
|
||||
setPrompt(next: Prompt<S>): () => void;
|
||||
addListener(func: (navigation: Navigation<S>) => void): () => void;
|
||||
notifyListeners(args: Navigation<S>): void;
|
||||
confirmJumpTo(location: Location<S>, action: Action, userConfirmationFunc: ConfirmationFunc, callBack: CallBackFunc): void;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { Action, Location, Path, To } from './types';
|
||||
export declare function createPath(path: Partial<Path>): string;
|
||||
export declare function parsePath(url: string): Partial<Path>;
|
||||
export declare function createLocation<S>(current: string | Location, to: To, state?: S, key?: string): Readonly<Location<S>>;
|
||||
export declare function isLocationEqual(p1: Partial<Path>, p2: Partial<Path>): boolean;
|
||||
export declare function addHeadSlash(path: string): string;
|
||||
export declare function stripHeadSlash(path: string): string;
|
||||
export declare function normalizeSlash(path: string): string;
|
||||
export declare function hasBasename(path: string, prefix: string): Boolean;
|
||||
export declare function stripBasename(path: string, prefix: string): string;
|
||||
export declare function createMemoryRecord<T, S>(initVal: S, fn: (arg: S) => T): {
|
||||
getDelta: (to: S, form: S) => number;
|
||||
addRecord: (current: S, newRecord: S, action: Action) => void;
|
||||
};
|
|
@ -1,2 +0,0 @@
|
|||
declare function warning(condition: any, message: string): void;
|
||||
export default warning;
|
|
@ -1,12 +0,0 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { ConfirmationFunc } from '../history/types';
|
||||
export type BaseRouterProps = {
|
||||
basename: string;
|
||||
getUserConfirmation: ConfirmationFunc;
|
||||
children?: ReactNode;
|
||||
};
|
||||
export type BrowserRouterProps = BaseRouterProps & {
|
||||
forceRefresh: boolean;
|
||||
};
|
||||
declare function BrowserRouter<P extends Partial<BrowserRouterProps>>(props: P): JSX.Element;
|
||||
export default BrowserRouter;
|
|
@ -1,7 +0,0 @@
|
|||
import { BaseRouterProps } from './BrowserRouter';
|
||||
import { urlHashType } from '../history/hashHistory';
|
||||
export type HashRouterProps = BaseRouterProps & {
|
||||
hashType: urlHashType;
|
||||
};
|
||||
declare function HashRouter<P extends Partial<HashRouterProps>>(props: P): JSX.Element;
|
||||
export default HashRouter;
|
|
@ -1,18 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Location } from './index';
|
||||
export type LinkProps = {
|
||||
component?: React.ComponentType<any>;
|
||||
to: Partial<Location> | string | ((location: Location) => string | Partial<Location>);
|
||||
replace?: boolean;
|
||||
tag?: string;
|
||||
/**
|
||||
* @deprecated
|
||||
* React16以后不再需要该属性
|
||||
**/
|
||||
innerRef?: React.Ref<HTMLAnchorElement>;
|
||||
} & React.AnchorHTMLAttributes<HTMLAnchorElement>;
|
||||
declare function Link<P extends LinkProps>(props: P): React.DOMElement<{
|
||||
href: string;
|
||||
onClick: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
||||
} & Omit<P, "replace" | "to" | "component" | "onClick" | "target">, Element>;
|
||||
export default Link;
|
|
@ -1,10 +0,0 @@
|
|||
import type { LinkProps } from './Link';
|
||||
import { Location } from './index';
|
||||
import { Matched } from './matcher/parser';
|
||||
type NavLinkProps = {
|
||||
to: Partial<Location> | string | ((location: Location) => string | Partial<Location>);
|
||||
isActive?: (match: Matched | null, location: Location) => boolean;
|
||||
[key: string]: any;
|
||||
} & LinkProps;
|
||||
declare function NavLink<P extends NavLinkProps>(props: P): JSX.Element;
|
||||
export default NavLink;
|
|
@ -1,8 +0,0 @@
|
|||
import { Location } from './index';
|
||||
import { Action } from '../history/types';
|
||||
type PromptProps = {
|
||||
message?: string | ((location: Partial<Location>, action: Action) => void);
|
||||
when?: boolean | ((location: Partial<Location>) => boolean);
|
||||
};
|
||||
declare function Prompt<P extends PromptProps>(props: P): JSX.Element;
|
||||
export default Prompt;
|
|
@ -1,13 +0,0 @@
|
|||
import { Matched } from './matcher/parser';
|
||||
import { Location } from './index';
|
||||
export type RedirectProps = {
|
||||
to: string | Partial<Location>;
|
||||
push?: boolean;
|
||||
path?: string;
|
||||
from?: string;
|
||||
exact?: boolean;
|
||||
strict?: boolean;
|
||||
readonly computed?: Matched | null;
|
||||
};
|
||||
declare function Redirect<P extends RedirectProps>(props: P): JSX.Element;
|
||||
export default Redirect;
|
|
@ -1,23 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { History, Location } from './index';
|
||||
import { Matched } from './matcher/parser';
|
||||
import { GetURLParams } from './matcher/types';
|
||||
export type RouteComponentProps<P extends Record<string, any> = {}, S = unknown> = RouteChildrenProps<P, S>;
|
||||
export type RouteChildrenProps<P extends Record<string, any> = {}, S = unknown> = {
|
||||
history: History<S>;
|
||||
location: Location<S>;
|
||||
match: Matched<P> | null;
|
||||
};
|
||||
export type RouteProps<P extends Record<string, any> = {}, Path extends string = string> = {
|
||||
location?: Location;
|
||||
component?: React.ComponentType<RouteComponentProps<P>> | React.ComponentType<any> | undefined;
|
||||
children?: ((props: RouteChildrenProps<P>) => React.ReactNode) | React.ReactNode;
|
||||
render?: (props: RouteComponentProps<P>) => React.ReactNode;
|
||||
path?: Path | Path[];
|
||||
exact?: boolean;
|
||||
sensitive?: boolean;
|
||||
strict?: boolean;
|
||||
computed?: Matched<P>;
|
||||
};
|
||||
declare function Route<Path extends string, P extends Record<string, any> = GetURLParams<Path>>(props: RouteProps<P, Path>): JSX.Element;
|
||||
export default Route;
|
|
@ -1,8 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { History } from '../history/types';
|
||||
export type RouterProps = {
|
||||
history: History;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
declare function Router<P extends RouterProps>(props: P): JSX.Element;
|
||||
export default Router;
|
|
@ -1,8 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Location } from './index';
|
||||
export type SwitchProps = {
|
||||
location?: Location;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
declare function Switch<P extends SwitchProps>(props: P): React.ReactElement | null;
|
||||
export default Switch;
|
|
@ -1 +0,0 @@
|
|||
import '@testing-library/jest-dom';
|
|
@ -1,8 +0,0 @@
|
|||
import { History, Location } from '../index';
|
||||
export declare let historyHook: History;
|
||||
export declare let locationHook: Location;
|
||||
export declare const LocationDisplay: () => JSX.Element;
|
||||
export declare const Test_Demo: () => JSX.Element;
|
||||
export declare const Test_Demo2: () => JSX.Element;
|
||||
export declare const Test_Demo3: () => JSX.Element;
|
||||
export declare const Test_Demo4: () => JSX.Element;
|
|
@ -1,10 +0,0 @@
|
|||
/// <reference types="react" />
|
||||
import { History, Location } from './index';
|
||||
import { Matched } from './matcher/parser';
|
||||
export type RouterContextValue = {
|
||||
history: History;
|
||||
location: Location;
|
||||
match: Matched | null;
|
||||
};
|
||||
declare const RouterContext: import("react").Context<RouterContextValue>;
|
||||
export default RouterContext;
|
|
@ -1,8 +0,0 @@
|
|||
import { Matched, Params } from './matcher/parser';
|
||||
import { History } from '../history/types';
|
||||
import { Location } from './index';
|
||||
declare function useHistory<S>(): History<S>;
|
||||
declare function useLocation<S>(): Location<S>;
|
||||
declare function useParams<P>(): Params<P> | {};
|
||||
declare function useRouteMatch<P>(path?: string): Matched<P> | null;
|
||||
export { useHistory, useLocation, useParams, useRouteMatch };
|
|
@ -1,20 +0,0 @@
|
|||
import { Location as HLocation } from '../history/types';
|
||||
type Location<S = unknown> = Omit<HLocation<S>, 'key'>;
|
||||
export { Location };
|
||||
export type { History } from '../history/types';
|
||||
export { createBrowserHistory } from '../history/browerHistory';
|
||||
export { createHashHistory } from '../history/hashHistory';
|
||||
export { default as __RouterContext } from './context';
|
||||
export { matchPath, generatePath } from './matcher/parser';
|
||||
export { useHistory, useLocation, useParams, useRouteMatch } from './hooks';
|
||||
export { default as Route } from './Route';
|
||||
export { default as Router } from './Router';
|
||||
export { default as Switch } from './Switch';
|
||||
export { default as Redirect } from './Redirect';
|
||||
export { default as Prompt } from './Prompt';
|
||||
export { default as withRouter } from './withRouter';
|
||||
export { default as HashRouter } from './HashRouter';
|
||||
export { default as BrowserRouter } from './BrowserRouter';
|
||||
export { default as Link } from './Link';
|
||||
export { default as NavLink } from './NavLink';
|
||||
export type { RouteComponentProps, RouteChildrenProps, RouteProps } from './Route';
|
|
@ -1,23 +0,0 @@
|
|||
import { Location as HLocation } from '../history/types';
|
||||
type Location<S = unknown> = Omit<HLocation<S>, 'key'>;
|
||||
export { Location };
|
||||
export type { History } from '../history/types';
|
||||
export { createBrowserHistory } from '../history/browerHistory';
|
||||
export { createHashHistory } from '../history/hashHistory';
|
||||
export { default as __RouterContext } from './context';
|
||||
export { matchPath, generatePath } from './matcher/parser';
|
||||
export { useHistory, useLocation, useParams, useRouteMatch } from './hooks';
|
||||
export { default as Route } from './Route';
|
||||
export { default as Router } from './Router';
|
||||
export { default as Switch } from './Switch';
|
||||
export { default as Redirect } from './Redirect';
|
||||
export { default as Prompt } from './Prompt';
|
||||
export { default as withRouter } from './withRouter';
|
||||
export { default as HashRouter } from './HashRouter';
|
||||
export { default as BrowserRouter } from './BrowserRouter';
|
||||
export { default as Link } from './Link';
|
||||
export { default as NavLink } from './NavLink';
|
||||
export type { RouteComponentProps, RouteChildrenProps, RouteProps } from './Route';
|
||||
export { connectRouter, routerMiddleware } from '../connect-router';
|
||||
export declare const ConnectedRouter: any;
|
||||
export declare const ConnectedHRouter: any;
|
|
@ -1,7 +0,0 @@
|
|||
export type LifeCycleProps = {
|
||||
onMount?: () => void;
|
||||
onUpdate?: (prevProps?: LifeCycleProps) => void;
|
||||
onUnmount?: () => void;
|
||||
data?: any;
|
||||
};
|
||||
export declare function LifeCycle(props: LifeCycleProps): any;
|
|
@ -1 +0,0 @@
|
|||
export {};
|
|
@ -1 +0,0 @@
|
|||
export {};
|
|
@ -1,2 +0,0 @@
|
|||
import { Token } from './types';
|
||||
export declare function lexer(path: string): Token[];
|
|
@ -1,18 +0,0 @@
|
|||
import { GetURLParams, Parser, ParserOption } from './types';
|
||||
export type Params<P> = {
|
||||
[K in keyof P]?: P[K];
|
||||
};
|
||||
export type Matched<P = any> = {
|
||||
score: number[];
|
||||
params: Params<P>;
|
||||
path: string;
|
||||
url: string;
|
||||
isExact: boolean;
|
||||
};
|
||||
export declare function createPathParser<Str extends string>(pathname: Str, option?: ParserOption): Parser<GetURLParams<Str>>;
|
||||
export declare function createPathParser<P = unknown>(pathname: string, option?: ParserOption): Parser<P>;
|
||||
/**
|
||||
* @description 依次使用pathname与pattern进行匹配,根据匹配分数取得分数最高结果
|
||||
*/
|
||||
export declare function matchPath<P = any>(pathname: string, pattern: string | string[], option?: ParserOption): Matched<P> | null;
|
||||
export declare function generatePath<P = any>(path: string, params: Params<P>): string;
|
|
@ -1,36 +0,0 @@
|
|||
import { Matched, Params } from './parser';
|
||||
export type Token = {
|
||||
type: TokenType;
|
||||
value: string;
|
||||
};
|
||||
export declare enum TokenType {
|
||||
Delimiter = "delimiter",
|
||||
Static = "static",
|
||||
Param = "param",
|
||||
WildCard = "wildcard",
|
||||
LBracket = "(",
|
||||
RBracket = ")",
|
||||
Pattern = "pattern"
|
||||
}
|
||||
export interface Parser<P> {
|
||||
regexp: RegExp;
|
||||
keys: string[];
|
||||
parse(url: string): Matched<P> | null;
|
||||
compile(params: Params<P>): string;
|
||||
}
|
||||
export type ParserOption = {
|
||||
caseSensitive?: boolean;
|
||||
strictMode?: boolean;
|
||||
exact?: boolean;
|
||||
};
|
||||
type ClearLeading<U extends string> = U extends `/${infer R}` ? ClearLeading<R> : U;
|
||||
type ClearTailing<U extends string> = U extends `${infer L}/` ? ClearTailing<L> : U;
|
||||
type ParseParam<Param extends string> = Param extends `:${infer R}` ? {
|
||||
[K in R]: string;
|
||||
} : {};
|
||||
type MergeParams<OneParam extends Record<string, any>, OtherParam extends Record<string, any>> = {
|
||||
readonly [Key in keyof OneParam | keyof OtherParam]?: string;
|
||||
};
|
||||
type ParseURLString<Str extends string> = Str extends `${infer Param}/${infer Rest}` ? MergeParams<ParseParam<Param>, ParseURLString<ClearLeading<Rest>>> : ParseParam<Str>;
|
||||
export type GetURLParams<U extends string> = ParseURLString<ClearLeading<ClearTailing<U>>>;
|
||||
export {};
|
|
@ -1,6 +0,0 @@
|
|||
/**
|
||||
* @description 将url中的//转换为/
|
||||
*/
|
||||
export declare function cleanPath(path: string): string;
|
||||
export declare function scoreCompare(score1: number[], score2: number[]): number;
|
||||
export declare function escapeStr(str: string): string;
|
|
@ -1,3 +0,0 @@
|
|||
import * as React from 'react';
|
||||
declare function withRouter<C extends React.ComponentType>(Component: C): (props: any) => JSX.Element;
|
||||
export default withRouter;
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"module": "./esm/connectRouter.js",
|
||||
"main": "./cjs/connectRouter.js",
|
||||
"types": "./@types/router/index2.d.ts",
|
||||
"peerDependencies": {
|
||||
"react-redux": "^6.0.0 || ^7.1.0",
|
||||
"redux": "^3.6.0 || ^4.0.0"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@cloudsop/horizon-router",
|
||||
"version": "0.0.12",
|
||||
"version": "1.0.5-alpha",
|
||||
"description": "router for horizon framework, a part of horizon-ecosystem",
|
||||
"main": "./router/cjs/router.js",
|
||||
"module": "./router/esm/router.js",
|
||||
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"build": "rollup -c build.js",
|
||||
"bulid": "rollup -c build.js",
|
||||
"build-types-router": "tsc -p src/router/index.ts --emitDeclarationOnly --declaration --declarationDir ./router/@types --skipLibCheck",
|
||||
"build-types-all": "tsc -p src/router/index2.ts --emitDeclarationOnly --declaration --declarationDir ./connectRouter/@types --skipLibCheck"
|
||||
},
|
||||
|
@ -67,10 +67,11 @@
|
|||
"rollup": "2.79.1",
|
||||
"rollup-plugin-execute": "^1.1.1",
|
||||
"ts-jest": "29.0.3",
|
||||
"typescript": "4.9.3"
|
||||
"typescript": "4.9.3",
|
||||
"rollup-plugin-terser": "^5.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cloudsop/horizon": "^0.0.52",
|
||||
"@cloudsop/horizon": "*",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import { Action, Path } from '../history/types';
|
||||
type Location = Partial<Path>;
|
||||
export declare enum ActionName {
|
||||
LOCATION_CHANGE = "$horizon-router/LOCATION_CHANGE",
|
||||
CALL_HISTORY_METHOD = "$horizon-router/CALL_HISTORY_METHOD"
|
||||
}
|
||||
export type ActionMessage = {
|
||||
type: ActionName.LOCATION_CHANGE;
|
||||
payload: {
|
||||
location: Location;
|
||||
action: Action;
|
||||
isFirstRendering: boolean;
|
||||
};
|
||||
} | {
|
||||
type: ActionName.CALL_HISTORY_METHOD;
|
||||
payload: {
|
||||
method: string;
|
||||
args: any;
|
||||
};
|
||||
};
|
||||
export declare const onLocationChanged: (location: Location, action: Action, isFirstRendering?: boolean) => ActionMessage;
|
||||
export declare const push: (...args: any) => ActionMessage;
|
||||
export declare const replace: (...args: any) => ActionMessage;
|
||||
export declare const go: (...args: any) => ActionMessage;
|
||||
export {};
|
|
@ -1,3 +0,0 @@
|
|||
import { ActionMessage } from './actions';
|
||||
import { History } from '../history/types';
|
||||
export declare function routerMiddleware(history: History): (_: any) => (next: any) => (action: ActionMessage) => any;
|
|
@ -1,11 +0,0 @@
|
|||
export { getConnectedRouter } from './connectedRouter';
|
||||
export declare const connectRouter: (history: import("../router").History<unknown>) => (state?: {
|
||||
location: Partial<import("../router").Location<unknown>> & {
|
||||
query?: Record<string, any>;
|
||||
};
|
||||
action: import("../history/types").Action;
|
||||
}, { type, payload }?: {
|
||||
type?: import("./actions").ActionName;
|
||||
payload?: any;
|
||||
}) => any;
|
||||
export { routerMiddleware } from './dispatch';
|
|
@ -1,16 +0,0 @@
|
|||
import { ActionName } from './actions';
|
||||
import { Action, History } from '../history/types';
|
||||
import { Location } from '../router';
|
||||
type LocationWithQuery = Partial<Location> & {
|
||||
query?: Record<string, any>;
|
||||
};
|
||||
type InitRouterState = {
|
||||
location: LocationWithQuery;
|
||||
action: Action;
|
||||
};
|
||||
type Payload = {
|
||||
type?: ActionName;
|
||||
payload?: any;
|
||||
};
|
||||
export declare function createConnectRouter(): (history: History) => (state?: InitRouterState, { type, payload }?: Payload) => any;
|
||||
export {};
|
|
@ -1,10 +0,0 @@
|
|||
import { HistoryProps, Listener, Navigation, Prompt } from './types';
|
||||
import transitionManager from './transitionManager';
|
||||
export declare function getBaseHistory<S>(transitionManager: transitionManager<S>, setListener: (delta: number) => void, browserHistory: History): {
|
||||
go: (step: number) => void;
|
||||
goBack: () => void;
|
||||
goForward: () => void;
|
||||
listen: (listener: Listener<S>) => () => void;
|
||||
block: (prompt?: Prompt<S>) => () => void;
|
||||
getUpdateStateFunc: (historyProps: HistoryProps<S>) => (nextState: Navigation<S> | undefined) => void;
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
import { BaseOption, DefaultStateType, History } from './types';
|
||||
export type BrowserHistoryOption = {
|
||||
/**
|
||||
* forceRefresh为True时跳转时会强制刷新页面
|
||||
*/
|
||||
forceRefresh?: boolean;
|
||||
} & BaseOption;
|
||||
export declare function createBrowserHistory<S = DefaultStateType>(options?: BrowserHistoryOption): History<S>;
|
|
@ -1,4 +0,0 @@
|
|||
export declare function isBrowser(): boolean;
|
||||
export declare function getDefaultConfirmation(message: string, callBack: (result: boolean) => void): void;
|
||||
export declare function isSupportHistory(): boolean;
|
||||
export declare function isSupportsPopState(): boolean;
|
|
@ -1,7 +0,0 @@
|
|||
import { BaseOption, DefaultStateType, History } from './types';
|
||||
export type urlHashType = 'slash' | 'noslash';
|
||||
type HashHistoryOption = {
|
||||
hashType?: urlHashType;
|
||||
} & BaseOption;
|
||||
export declare function createHashHistory<S = DefaultStateType>(option?: HashHistoryOption): History<S>;
|
||||
export {};
|
|
@ -1,11 +0,0 @@
|
|||
import { Action, CallBackFunc, ConfirmationFunc, Listener, Location, Navigation, Prompt, TManager } from './types';
|
||||
declare class TransitionManager<S> implements TManager<S> {
|
||||
private prompt;
|
||||
private listeners;
|
||||
constructor();
|
||||
setPrompt(prompt: Prompt<S>): () => void;
|
||||
addListener(func: Listener<S>): () => void;
|
||||
notifyListeners(args: Navigation<S>): void;
|
||||
confirmJumpTo(location: Location<S>, action: Action, userConfirmationFunc: ConfirmationFunc, callBack: CallBackFunc): void;
|
||||
}
|
||||
export default TransitionManager;
|
|
@ -1,56 +0,0 @@
|
|||
export type BaseOption = {
|
||||
basename?: string;
|
||||
getUserConfirmation?: ConfirmationFunc;
|
||||
};
|
||||
export interface HistoryProps<T = unknown> {
|
||||
readonly action: Action;
|
||||
readonly location: Location<T>;
|
||||
length: number;
|
||||
}
|
||||
export interface History<T = unknown> extends HistoryProps<T> {
|
||||
createHref(path: Partial<Path>): string;
|
||||
push(to: To, state?: T): void;
|
||||
replace(to: To, state?: T): void;
|
||||
listen(listener: Listener<T>): () => void;
|
||||
block(prompt: Prompt<T>): () => void;
|
||||
go(index: number): void;
|
||||
goBack(): void;
|
||||
goForward(): void;
|
||||
}
|
||||
export declare enum Action {
|
||||
pop = "POP",
|
||||
push = "PUSH",
|
||||
replace = "REPLACE"
|
||||
}
|
||||
export declare enum EventType {
|
||||
PopState = "popstate",
|
||||
HashChange = "hashchange"
|
||||
}
|
||||
export type Path = {
|
||||
pathname: string;
|
||||
search: string;
|
||||
hash: string;
|
||||
};
|
||||
export type HistoryState<T> = {
|
||||
state?: T;
|
||||
key: string;
|
||||
};
|
||||
export type DefaultStateType = unknown;
|
||||
export type Location<T = unknown> = Path & HistoryState<T>;
|
||||
export type To = string | Partial<Path>;
|
||||
export interface Listener<T = unknown> {
|
||||
(navigation: Navigation<T>): void;
|
||||
}
|
||||
export interface Navigation<T = unknown> {
|
||||
action: Action;
|
||||
location: Location<T>;
|
||||
}
|
||||
export type Prompt<S> = string | boolean | null | ((location: Location<S>, action: Action) => void);
|
||||
export type CallBackFunc = (isJump: boolean) => void;
|
||||
export type ConfirmationFunc = (message: string, callBack: CallBackFunc) => void;
|
||||
export interface TManager<S> {
|
||||
setPrompt(next: Prompt<S>): () => void;
|
||||
addListener(func: (navigation: Navigation<S>) => void): () => void;
|
||||
notifyListeners(args: Navigation<S>): void;
|
||||
confirmJumpTo(location: Location<S>, action: Action, userConfirmationFunc: ConfirmationFunc, callBack: CallBackFunc): void;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { Action, Location, Path, To } from './types';
|
||||
export declare function createPath(path: Partial<Path>): string;
|
||||
export declare function parsePath(url: string): Partial<Path>;
|
||||
export declare function createLocation<S>(current: string | Location, to: To, state?: S, key?: string): Readonly<Location<S>>;
|
||||
export declare function isLocationEqual(p1: Partial<Path>, p2: Partial<Path>): boolean;
|
||||
export declare function addHeadSlash(path: string): string;
|
||||
export declare function stripHeadSlash(path: string): string;
|
||||
export declare function normalizeSlash(path: string): string;
|
||||
export declare function hasBasename(path: string, prefix: string): Boolean;
|
||||
export declare function stripBasename(path: string, prefix: string): string;
|
||||
export declare function createMemoryRecord<T, S>(initVal: S, fn: (arg: S) => T): {
|
||||
getDelta: (to: S, form: S) => number;
|
||||
addRecord: (current: S, newRecord: S, action: Action) => void;
|
||||
};
|
|
@ -1,2 +0,0 @@
|
|||
declare function warning(condition: any, message: string): void;
|
||||
export default warning;
|
|
@ -1,12 +0,0 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { ConfirmationFunc } from '../history/types';
|
||||
export type BaseRouterProps = {
|
||||
basename: string;
|
||||
getUserConfirmation: ConfirmationFunc;
|
||||
children?: ReactNode;
|
||||
};
|
||||
export type BrowserRouterProps = BaseRouterProps & {
|
||||
forceRefresh: boolean;
|
||||
};
|
||||
declare function BrowserRouter<P extends Partial<BrowserRouterProps>>(props: P): JSX.Element;
|
||||
export default BrowserRouter;
|
|
@ -1,7 +0,0 @@
|
|||
import { BaseRouterProps } from './BrowserRouter';
|
||||
import { urlHashType } from '../history/hashHistory';
|
||||
export type HashRouterProps = BaseRouterProps & {
|
||||
hashType: urlHashType;
|
||||
};
|
||||
declare function HashRouter<P extends Partial<HashRouterProps>>(props: P): JSX.Element;
|
||||
export default HashRouter;
|
|
@ -1,18 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Location } from './index';
|
||||
export type LinkProps = {
|
||||
component?: React.ComponentType<any>;
|
||||
to: Partial<Location> | string | ((location: Location) => string | Partial<Location>);
|
||||
replace?: boolean;
|
||||
tag?: string;
|
||||
/**
|
||||
* @deprecated
|
||||
* React16以后不再需要该属性
|
||||
**/
|
||||
innerRef?: React.Ref<HTMLAnchorElement>;
|
||||
} & React.AnchorHTMLAttributes<HTMLAnchorElement>;
|
||||
declare function Link<P extends LinkProps>(props: P): React.DOMElement<{
|
||||
href: string;
|
||||
onClick: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
||||
} & Omit<P, "replace" | "to" | "component" | "onClick" | "target">, Element>;
|
||||
export default Link;
|
|
@ -1,10 +0,0 @@
|
|||
import type { LinkProps } from './Link';
|
||||
import { Location } from './index';
|
||||
import { Matched } from './matcher/parser';
|
||||
type NavLinkProps = {
|
||||
to: Partial<Location> | string | ((location: Location) => string | Partial<Location>);
|
||||
isActive?: (match: Matched | null, location: Location) => boolean;
|
||||
[key: string]: any;
|
||||
} & LinkProps;
|
||||
declare function NavLink<P extends NavLinkProps>(props: P): JSX.Element;
|
||||
export default NavLink;
|
|
@ -1,8 +0,0 @@
|
|||
import { Location } from './index';
|
||||
import { Action } from '../history/types';
|
||||
type PromptProps = {
|
||||
message?: string | ((location: Partial<Location>, action: Action) => void);
|
||||
when?: boolean | ((location: Partial<Location>) => boolean);
|
||||
};
|
||||
declare function Prompt<P extends PromptProps>(props: P): JSX.Element;
|
||||
export default Prompt;
|
|
@ -1,13 +0,0 @@
|
|||
import { Matched } from './matcher/parser';
|
||||
import { Location } from './index';
|
||||
export type RedirectProps = {
|
||||
to: string | Partial<Location>;
|
||||
push?: boolean;
|
||||
path?: string;
|
||||
from?: string;
|
||||
exact?: boolean;
|
||||
strict?: boolean;
|
||||
readonly computed?: Matched | null;
|
||||
};
|
||||
declare function Redirect<P extends RedirectProps>(props: P): JSX.Element;
|
||||
export default Redirect;
|
|
@ -1,23 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { History, Location } from './index';
|
||||
import { Matched } from './matcher/parser';
|
||||
import { GetURLParams } from './matcher/types';
|
||||
export type RouteComponentProps<P extends Record<string, any> = {}, S = unknown> = RouteChildrenProps<P, S>;
|
||||
export type RouteChildrenProps<P extends Record<string, any> = {}, S = unknown> = {
|
||||
history: History<S>;
|
||||
location: Location<S>;
|
||||
match: Matched<P> | null;
|
||||
};
|
||||
export type RouteProps<P extends Record<string, any> = {}, Path extends string = string> = {
|
||||
location?: Location;
|
||||
component?: React.ComponentType<RouteComponentProps<P>> | React.ComponentType<any> | undefined;
|
||||
children?: ((props: RouteChildrenProps<P>) => React.ReactNode) | React.ReactNode;
|
||||
render?: (props: RouteComponentProps<P>) => React.ReactNode;
|
||||
path?: Path | Path[];
|
||||
exact?: boolean;
|
||||
sensitive?: boolean;
|
||||
strict?: boolean;
|
||||
computed?: Matched<P>;
|
||||
};
|
||||
declare function Route<Path extends string, P extends Record<string, any> = GetURLParams<Path>>(props: RouteProps<P, Path>): JSX.Element;
|
||||
export default Route;
|
|
@ -1,8 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { History } from '../history/types';
|
||||
export type RouterProps = {
|
||||
history: History;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
declare function Router<P extends RouterProps>(props: P): JSX.Element;
|
||||
export default Router;
|
|
@ -1,8 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { Location } from './index';
|
||||
export type SwitchProps = {
|
||||
location?: Location;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
declare function Switch<P extends SwitchProps>(props: P): React.ReactElement | null;
|
||||
export default Switch;
|
|
@ -1 +0,0 @@
|
|||
import '@testing-library/jest-dom';
|
|
@ -1,8 +0,0 @@
|
|||
import { History, Location } from '../index';
|
||||
export declare let historyHook: History;
|
||||
export declare let locationHook: Location;
|
||||
export declare const LocationDisplay: () => JSX.Element;
|
||||
export declare const Test_Demo: () => JSX.Element;
|
||||
export declare const Test_Demo2: () => JSX.Element;
|
||||
export declare const Test_Demo3: () => JSX.Element;
|
||||
export declare const Test_Demo4: () => JSX.Element;
|
|
@ -1,10 +0,0 @@
|
|||
/// <reference types="react" />
|
||||
import { History, Location } from './index';
|
||||
import { Matched } from './matcher/parser';
|
||||
export type RouterContextValue = {
|
||||
history: History;
|
||||
location: Location;
|
||||
match: Matched | null;
|
||||
};
|
||||
declare const RouterContext: import("react").Context<RouterContextValue>;
|
||||
export default RouterContext;
|
|
@ -1,8 +0,0 @@
|
|||
import { Matched, Params } from './matcher/parser';
|
||||
import { History } from '../history/types';
|
||||
import { Location } from './index';
|
||||
declare function useHistory<S>(): History<S>;
|
||||
declare function useLocation<S>(): Location<S>;
|
||||
declare function useParams<P>(): Params<P> | {};
|
||||
declare function useRouteMatch<P>(path?: string): Matched<P> | null;
|
||||
export { useHistory, useLocation, useParams, useRouteMatch };
|
|
@ -1,20 +0,0 @@
|
|||
import { Location as HLocation } from '../history/types';
|
||||
type Location<S = unknown> = Omit<HLocation<S>, 'key'>;
|
||||
export { Location };
|
||||
export type { History } from '../history/types';
|
||||
export { createBrowserHistory } from '../history/browerHistory';
|
||||
export { createHashHistory } from '../history/hashHistory';
|
||||
export { default as __RouterContext } from './context';
|
||||
export { matchPath, generatePath } from './matcher/parser';
|
||||
export { useHistory, useLocation, useParams, useRouteMatch } from './hooks';
|
||||
export { default as Route } from './Route';
|
||||
export { default as Router } from './Router';
|
||||
export { default as Switch } from './Switch';
|
||||
export { default as Redirect } from './Redirect';
|
||||
export { default as Prompt } from './Prompt';
|
||||
export { default as withRouter } from './withRouter';
|
||||
export { default as HashRouter } from './HashRouter';
|
||||
export { default as BrowserRouter } from './BrowserRouter';
|
||||
export { default as Link } from './Link';
|
||||
export { default as NavLink } from './NavLink';
|
||||
export type { RouteComponentProps, RouteChildrenProps, RouteProps } from './Route';
|
|
@ -1,23 +0,0 @@
|
|||
import { Location as HLocation } from '../history/types';
|
||||
type Location<S = unknown> = Omit<HLocation<S>, 'key'>;
|
||||
export { Location };
|
||||
export type { History } from '../history/types';
|
||||
export { createBrowserHistory } from '../history/browerHistory';
|
||||
export { createHashHistory } from '../history/hashHistory';
|
||||
export { default as __RouterContext } from './context';
|
||||
export { matchPath, generatePath } from './matcher/parser';
|
||||
export { useHistory, useLocation, useParams, useRouteMatch } from './hooks';
|
||||
export { default as Route } from './Route';
|
||||
export { default as Router } from './Router';
|
||||
export { default as Switch } from './Switch';
|
||||
export { default as Redirect } from './Redirect';
|
||||
export { default as Prompt } from './Prompt';
|
||||
export { default as withRouter } from './withRouter';
|
||||
export { default as HashRouter } from './HashRouter';
|
||||
export { default as BrowserRouter } from './BrowserRouter';
|
||||
export { default as Link } from './Link';
|
||||
export { default as NavLink } from './NavLink';
|
||||
export type { RouteComponentProps, RouteChildrenProps, RouteProps } from './Route';
|
||||
export { connectRouter, routerMiddleware } from '../connect-router';
|
||||
export declare const ConnectedRouter: any;
|
||||
export declare const ConnectedHRouter: any;
|
|
@ -1,7 +0,0 @@
|
|||
export type LifeCycleProps = {
|
||||
onMount?: () => void;
|
||||
onUpdate?: (prevProps?: LifeCycleProps) => void;
|
||||
onUnmount?: () => void;
|
||||
data?: any;
|
||||
};
|
||||
export declare function LifeCycle(props: LifeCycleProps): any;
|
|
@ -1 +0,0 @@
|
|||
export {};
|
|
@ -1 +0,0 @@
|
|||
export {};
|
|
@ -1 +0,0 @@
|
|||
export {};
|
|
@ -1,2 +0,0 @@
|
|||
import { Token } from './types';
|
||||
export declare function lexer(path: string): Token[];
|
|
@ -1,18 +0,0 @@
|
|||
import { GetURLParams, Parser, ParserOption } from './types';
|
||||
export type Params<P> = {
|
||||
[K in keyof P]?: P[K];
|
||||
};
|
||||
export type Matched<P = any> = {
|
||||
score: number[];
|
||||
params: Params<P>;
|
||||
path: string;
|
||||
url: string;
|
||||
isExact: boolean;
|
||||
};
|
||||
export declare function createPathParser<Str extends string>(pathname: Str, option?: ParserOption): Parser<GetURLParams<Str>>;
|
||||
export declare function createPathParser<P = unknown>(pathname: string, option?: ParserOption): Parser<P>;
|
||||
/**
|
||||
* @description 依次使用pathname与pattern进行匹配,根据匹配分数取得分数最高结果
|
||||
*/
|
||||
export declare function matchPath<P = any>(pathname: string, pattern: string | string[], option?: ParserOption): Matched<P> | null;
|
||||
export declare function generatePath<P = any>(path: string, params: Params<P>): string;
|
|
@ -1,36 +0,0 @@
|
|||
import { Matched, Params } from './parser';
|
||||
export type Token = {
|
||||
type: TokenType;
|
||||
value: string;
|
||||
};
|
||||
export declare enum TokenType {
|
||||
Delimiter = "delimiter",
|
||||
Static = "static",
|
||||
Param = "param",
|
||||
WildCard = "wildcard",
|
||||
LBracket = "(",
|
||||
RBracket = ")",
|
||||
Pattern = "pattern"
|
||||
}
|
||||
export interface Parser<P> {
|
||||
regexp: RegExp;
|
||||
keys: string[];
|
||||
parse(url: string): Matched<P> | null;
|
||||
compile(params: Params<P>): string;
|
||||
}
|
||||
export type ParserOption = {
|
||||
caseSensitive?: boolean;
|
||||
strictMode?: boolean;
|
||||
exact?: boolean;
|
||||
};
|
||||
type ClearLeading<U extends string> = U extends `/${infer R}` ? ClearLeading<R> : U;
|
||||
type ClearTailing<U extends string> = U extends `${infer L}/` ? ClearTailing<L> : U;
|
||||
type ParseParam<Param extends string> = Param extends `:${infer R}` ? {
|
||||
[K in R]: string;
|
||||
} : {};
|
||||
type MergeParams<OneParam extends Record<string, any>, OtherParam extends Record<string, any>> = {
|
||||
readonly [Key in keyof OneParam | keyof OtherParam]?: string;
|
||||
};
|
||||
type ParseURLString<Str extends string> = Str extends `${infer Param}/${infer Rest}` ? MergeParams<ParseParam<Param>, ParseURLString<ClearLeading<Rest>>> : ParseParam<Str>;
|
||||
export type GetURLParams<U extends string> = ParseURLString<ClearLeading<ClearTailing<U>>>;
|
||||
export {};
|
|
@ -1,6 +0,0 @@
|
|||
/**
|
||||
* @description 将url中的//转换为/
|
||||
*/
|
||||
export declare function cleanPath(path: string): string;
|
||||
export declare function scoreCompare(score1: number[], score2: number[]): number;
|
||||
export declare function escapeStr(str: string): string;
|
|
@ -1,3 +0,0 @@
|
|||
import * as React from 'react';
|
||||
declare function withRouter<C extends React.ComponentType>(Component: C): (props: any) => JSX.Element;
|
||||
export default withRouter;
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import { connect, ReactReduxContext } from 'react-redux';
|
||||
import { Store } from 'redux';
|
||||
import { reduxAdapter } from '@cloudsop/horizon';
|
||||
|
@ -28,7 +28,8 @@ function ConnectedRouterWithoutMemo<S>(props: ConnectedRouter<S>) {
|
|||
const { getLocation } = stateReader(storeType);
|
||||
|
||||
// 监听store变化
|
||||
const unsubscribe = store.subscribe(() => {
|
||||
const unsubscribe = useRef<null | (() => void)>(
|
||||
store.subscribe(() => {
|
||||
// 获取redux State中的location信息
|
||||
const {
|
||||
pathname: pathnameInStore,
|
||||
|
@ -62,7 +63,8 @@ function ConnectedRouterWithoutMemo<S>(props: ConnectedRouter<S>) {
|
|||
stateInStore,
|
||||
);
|
||||
}
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const handleLocationChange = (args: Navigation<S>, isFirstRendering: boolean = false) => {
|
||||
const { location, action } = args;
|
||||
|
@ -70,12 +72,12 @@ function ConnectedRouterWithoutMemo<S>(props: ConnectedRouter<S>) {
|
|||
};
|
||||
|
||||
// 监听history更新
|
||||
const unListen = () => history.listen(handleLocationChange);
|
||||
const unListen = useRef<null | (() => void)>(history.listen(handleLocationChange));
|
||||
|
||||
useLayoutEffect(() => {
|
||||
return () => {
|
||||
unListen();
|
||||
unsubscribe();
|
||||
unListen.current && unListen.current();
|
||||
unsubscribe.current && unsubscribe.current();
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
|
|
@ -3,3 +3,4 @@ import { createConnectRouter } from './reducer';
|
|||
export { getConnectedRouter } from './connectedRouter';
|
||||
export const connectRouter = createConnectRouter();
|
||||
export { routerMiddleware } from './dispatch';
|
||||
export { push, go, replace } from './actions';
|
|
@ -6,7 +6,6 @@ import { Location, matchPath } from './index';
|
|||
import { Matched } from './matcher/parser';
|
||||
import Context from './context';
|
||||
import { parsePath } from '../history/utils';
|
||||
import { escapeStr } from './matcher/utils';
|
||||
|
||||
type NavLinkProps = {
|
||||
to: Partial<Location> | string | ((location: Location) => string | Partial<Location>);
|
||||
|
@ -23,10 +22,9 @@ function NavLink<P extends NavLinkProps>(props: P) {
|
|||
|
||||
const toLocation = typeof to === 'function' ? to(context.location) : to;
|
||||
|
||||
const { pathname: path } = typeof toLocation === 'string' ? parsePath(toLocation) : toLocation;
|
||||
// 把正则表达式的特殊符号加两个反斜杠进行转义
|
||||
const escapedPath = path ? escapeStr(path) : '';
|
||||
const match = escapedPath ? matchPath(context.location.pathname, escapedPath) : null;
|
||||
const { pathname } = typeof toLocation === 'string' ? parsePath(toLocation) : toLocation;
|
||||
|
||||
const match = pathname ? matchPath(context.location.pathname, pathname) : null;
|
||||
|
||||
const isLinkActive = match && isActive ? isActive(match, context.location) : false;
|
||||
|
||||
|
|
|
@ -16,17 +16,19 @@ function Router<P extends RouterProps>(props: P) {
|
|||
const pendingLocation = useRef<Location | null>(null);
|
||||
|
||||
// 在Router加载时就监听history地址变化,以保证在始渲染时重定向能正确触发
|
||||
let unListen: null | (() => void) = history.listen(arg => {
|
||||
const unListen = useRef<null | (() => void)>(
|
||||
history.listen(arg => {
|
||||
pendingLocation.current = arg.location;
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
// 模拟componentDidMount和componentWillUnmount
|
||||
useLayoutEffect(() => {
|
||||
if (unListen) {
|
||||
unListen();
|
||||
if (unListen.current) {
|
||||
unListen.current();
|
||||
}
|
||||
// 监听history中的位置变化
|
||||
unListen = history.listen(arg => {
|
||||
unListen.current = history.listen(arg => {
|
||||
setLocation(arg.location);
|
||||
});
|
||||
|
||||
|
@ -35,9 +37,9 @@ function Router<P extends RouterProps>(props: P) {
|
|||
}
|
||||
|
||||
return () => {
|
||||
if (unListen) {
|
||||
unListen();
|
||||
unListen = null;
|
||||
if (unListen.current) {
|
||||
unListen.current();
|
||||
unListen.current = null;
|
||||
pendingLocation.current = null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -31,15 +31,9 @@ function Switch<P extends SwitchProps>(props: P): React.ReactElement | null {
|
|||
|
||||
// node可能是Route和Redirect
|
||||
if (node.type === Route) {
|
||||
const props = node.props as RouteProps;
|
||||
strict = props.strict;
|
||||
sensitive = props.sensitive;
|
||||
path = props.path;
|
||||
({ strict, sensitive, path } = node.props as RouteProps);
|
||||
} else if (node.type === Redirect) {
|
||||
const props = node.props as RedirectProps;
|
||||
path = props.path;
|
||||
strict = props.strict;
|
||||
from = props.from;
|
||||
({ path, strict, from } = node.props as RedirectProps);
|
||||
}
|
||||
|
||||
const exact = node.props.exact;
|
||||
|
|
|
@ -40,6 +40,6 @@ export type { RouteComponentProps, RouteChildrenProps, RouteProps } from './Rout
|
|||
|
||||
// ============================ Connect-router ============================
|
||||
|
||||
export { connectRouter, routerMiddleware } from '../connect-router';
|
||||
export { connectRouter, routerMiddleware, push, go, replace } from '../connect-router';
|
||||
export const ConnectedRouter = getConnectedRouter('Redux');
|
||||
export const ConnectedHRouter = getConnectedRouter('HorizonXCompat');
|
|
@ -53,6 +53,20 @@ describe('path lexer Test', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('dynamic params with pattern 2', () => {
|
||||
const tokens = lexer('/www.a.com/:b(abc|xyz)/*');
|
||||
expect(tokens).toStrictEqual([
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'www.a.com' },
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'param', value: 'b' },
|
||||
{ type: '(', value: '(' },
|
||||
{ type: 'pattern', value: 'abc|xyz' },
|
||||
{ type: ')', value: ')' },
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'wildcard', value: '*' },
|
||||
]);
|
||||
});
|
||||
it('wildcard params test', () => {
|
||||
const tokens = lexer('/www.a.com/:b');
|
||||
expect(tokens).toStrictEqual([
|
||||
|
@ -62,4 +76,45 @@ describe('path lexer Test', () => {
|
|||
{ type: 'param', value: 'b' },
|
||||
]);
|
||||
});
|
||||
it('wildcard in end of static param', () => {
|
||||
const tokens = lexer('/abc*');
|
||||
expect(tokens).toStrictEqual([
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'abc' },
|
||||
{ type: 'pattern', value: '*' },
|
||||
]);
|
||||
});
|
||||
it('wildcard in end of static param 2', () => {
|
||||
const tokens = lexer('/abc*/xyz*');
|
||||
expect(tokens).toStrictEqual([
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'abc' },
|
||||
{ type: 'pattern', value: '*' },
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'xyz' },
|
||||
{ type: 'pattern', value: '*' },
|
||||
]);
|
||||
});
|
||||
it('url contain optional param at end', () => {
|
||||
const tokens = lexer('/user/:name?');
|
||||
expect(tokens).toEqual([
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'user' },
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'param', value: 'name' },
|
||||
{ type: 'pattern', value: '?' },
|
||||
]);
|
||||
});
|
||||
it('url contain optional param at middle', () => {
|
||||
const tokens = lexer('/user/:name?/profile');
|
||||
expect(tokens).toEqual([
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'user' },
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'param', value: 'name' },
|
||||
{ type: 'pattern', value: '?' },
|
||||
{ type: 'delimiter', value: '/' },
|
||||
{ type: 'static', value: 'profile' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -34,10 +34,13 @@ describe('parser test', () => {
|
|||
const parser = createPathParser('/www.a.com/a/*', { exact: true });
|
||||
const params = parser.parse('/www.a.com/a/b1/c1/d1');
|
||||
const params1 = parser.parse('/www.a.com/a/b1/c1/');
|
||||
const params2 = parser.parse('/www.a.com/a/b1/');
|
||||
expect(params!.params).toStrictEqual({ '*': ['b1', 'c1', 'd1'] });
|
||||
expect(params!.score).toStrictEqual([10, 10, 3, 3, 3]);
|
||||
expect(params1!.params).toStrictEqual({ '*': ['b1', 'c1'] });
|
||||
expect(params1!.score).toStrictEqual([10, 10, 3, 3]);
|
||||
expect(params2!.params).toStrictEqual({ '*': ['b1'] });
|
||||
expect(params2!.score).toStrictEqual([10, 10, 3]);
|
||||
});
|
||||
|
||||
it('compile wildcard', function () {
|
||||
|
@ -191,9 +194,30 @@ describe('parser test', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('wildcard after dynamic param with pattern', () => {
|
||||
const parser = createPathParser('/detail/:action(info)/*');
|
||||
const res = parser.parse('/detail/info/123');
|
||||
expect(res).toEqual({
|
||||
isExact: true,
|
||||
path: '/detail/:action(info)/*',
|
||||
url: '/detail/info/123',
|
||||
score: [10, 6, 3],
|
||||
params: { action: 'info', '*': ['123'] },
|
||||
});
|
||||
});
|
||||
it('dynamic param with regexp pattern after wildcard', () => {
|
||||
const parser = createPathParser('/detail/*/:action(\\d+)');
|
||||
const res = parser.parse('/detail/abc/xyz/123');
|
||||
expect(res).toEqual({
|
||||
isExact: true,
|
||||
path: '/detail/*/:action(\\d+)',
|
||||
url: '/detail/abc/xyz/123',
|
||||
score: [10, 3, 3, 6],
|
||||
params: { action: '123', '*': ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
it('dynamic param with regexp pattern', () => {
|
||||
const parser = createPathParser('/detail/:action(\\d+)');
|
||||
console.log(parser.regexp);
|
||||
const res = parser.parse('/detail/123');
|
||||
expect(res).toEqual({
|
||||
isExact: true,
|
||||
|
@ -245,4 +269,121 @@ describe('parser test', () => {
|
|||
c: 'abc',
|
||||
});
|
||||
});
|
||||
it('support wildcard "*" in end of static path 1', function () {
|
||||
const parser = createPathParser('/home*');
|
||||
const res = parser.parse('/homeAbc/a123');
|
||||
expect(res).toEqual({
|
||||
isExact: true,
|
||||
path: '/home*',
|
||||
url: '/homeAbc/a123',
|
||||
score: [10],
|
||||
params: { '0': 'Abc/a123' },
|
||||
});
|
||||
});
|
||||
it('support wildcard "*" in url and dynamic param at end', function () {
|
||||
const parser = createPathParser('/home*/:a+');
|
||||
const res = parser.parse('/homeAbc/a');
|
||||
expect(res).toEqual({
|
||||
path: '/home*/:a+',
|
||||
url: '/homeAbc/a',
|
||||
isExact: true,
|
||||
score: [10, 6],
|
||||
params: { '0': 'Abc', a: 'a' },
|
||||
});
|
||||
});
|
||||
it('parse url with optional param 1', () => {
|
||||
const parser = createPathParser('/catalog/logical-view/:pageType/:viewName?');
|
||||
const res = parser.parse('/catalog/logical-view/create');
|
||||
expect(res).toStrictEqual({
|
||||
isExact: true,
|
||||
path: '/catalog/logical-view/:pageType/:viewName?',
|
||||
url: '/catalog/logical-view/create',
|
||||
score: [10, 10, 6, 6],
|
||||
params: { pageType: 'create', viewName: undefined },
|
||||
});
|
||||
const res2 = parser.parse('/catalog/logical-view/create/view1');
|
||||
expect(res2).toStrictEqual({
|
||||
isExact: true,
|
||||
path: '/catalog/logical-view/:pageType/:viewName?',
|
||||
url: '/catalog/logical-view/create/view1',
|
||||
score: [10, 10, 6, 6],
|
||||
params: { pageType: 'create', viewName: 'view1' },
|
||||
});
|
||||
});
|
||||
it('parse url with wildcard param 1', () => {
|
||||
const parser = createPathParser('/home/:p*');
|
||||
const res = parser.parse('/home/123');
|
||||
expect(res).toStrictEqual({
|
||||
path: '/home/:p*',
|
||||
url: '/home/123',
|
||||
isExact: true,
|
||||
params: { p: '123' },
|
||||
score: [10, 6],
|
||||
});
|
||||
const res2 = parser.parse('/home/123/456');
|
||||
expect(res2).toStrictEqual({
|
||||
path: '/home/:p*',
|
||||
url: '/home/123/456',
|
||||
isExact: true,
|
||||
params: { p: '123/456' },
|
||||
score: [10, 6],
|
||||
});
|
||||
});
|
||||
it('parse url with wildcard param in middle of URL', () => {
|
||||
const parser = createPathParser('/home/:p*/link');
|
||||
const res = parser.parse('/home/123/link');
|
||||
expect(res).toStrictEqual({
|
||||
path: '/home/:p*/link',
|
||||
url: '/home/123/link',
|
||||
isExact: true,
|
||||
params: { p: '123' },
|
||||
score: [10, 6, 10],
|
||||
});
|
||||
const res2 = parser.parse('/home/link');
|
||||
expect(res2).toStrictEqual({
|
||||
path: '/home/:p*/link',
|
||||
url: '/home/link',
|
||||
isExact: true,
|
||||
params: { p: undefined },
|
||||
score: [10, 6, 10],
|
||||
});
|
||||
});
|
||||
it('parse url with optional param 2', () => {
|
||||
const parser = createPathParser('/user/:userid?/profile');
|
||||
const res = parser.parse('/user/profile');
|
||||
expect(res).toStrictEqual({
|
||||
isExact: true,
|
||||
params: { userid: undefined },
|
||||
path: '/user/:userid?/profile',
|
||||
score: [10, 6, 10],
|
||||
url: '/user/profile',
|
||||
});
|
||||
const res2 = parser.parse('/user/123/profile');
|
||||
expect(res2).toStrictEqual({
|
||||
isExact: true,
|
||||
params: { userid: '123' },
|
||||
path: '/user/:userid?/profile',
|
||||
score: [10, 6, 10],
|
||||
url: '/user/123/profile',
|
||||
});
|
||||
});
|
||||
it('complex url pattern test 1', function () {
|
||||
const parser = createPathParser('/dump/taskList/:action(add|config)/lifecyclePolicy/:name?');
|
||||
const res = parser.parse('/dump/taskList/add/lifecyclePolicy/');
|
||||
expect(res).toStrictEqual({
|
||||
isExact: true,
|
||||
path: '/dump/taskList/:action(add|config)/lifecyclePolicy/:name?',
|
||||
url: '/dump/taskList/add/lifecyclePolicy/',
|
||||
score: [10, 10, 6, 10, 6],
|
||||
params: { action: 'add', name: undefined },
|
||||
});
|
||||
const res1 = parser.parse('/dump/taskList/add/lifecyclePolicy/new');
|
||||
expect(res1).toStrictEqual({
|
||||
isExact: true,
|
||||
path: '/dump/taskList/:action(add|config)/lifecyclePolicy/:name?',
|
||||
url: '/dump/taskList/add/lifecyclePolicy/new',
|
||||
score: [10, 10, 6, 10, 6],
|
||||
params: { action: 'add', name: 'new' },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Token, TokenType } from './types';
|
||||
import { cleanPath } from './utils';
|
||||
|
||||
const validChar = /[^/:*()]/;
|
||||
const validChar = /[^/:()*?$^+]/;
|
||||
|
||||
// 对Url模板进行词法解析,解析结果为Tokens
|
||||
export function lexer(path: string): Token[] {
|
||||
|
@ -66,6 +66,11 @@ export function lexer(path: string): Token[] {
|
|||
skipChar(1);
|
||||
continue;
|
||||
}
|
||||
if (['*', '?', '$', '^', '+'].includes(curChar)) {
|
||||
tokens.push({ type: TokenType.Pattern, value: curChar });
|
||||
skipChar(1);
|
||||
continue;
|
||||
}
|
||||
if (validChar.test(curChar)) {
|
||||
tokens.push({ type: TokenType.Pattern, value: getLiteral() });
|
||||
continue;
|
||||
|
|
|
@ -39,6 +39,12 @@ const BASE_PARAM_PATTERN = '[^/]+';
|
|||
|
||||
const DefaultDelimiter = '/#?';
|
||||
|
||||
/**
|
||||
* URL匹配整体流程
|
||||
* 1.词法解析,将URL模板解析为Token
|
||||
* 2.使用Token生成正则表达式
|
||||
* 3.利用正则表达式解析URL中参数或填充URL模板
|
||||
*/
|
||||
export function createPathParser<Str extends string>(pathname: Str, option?: ParserOption): Parser<GetURLParams<Str>>;
|
||||
export function createPathParser<P = unknown>(pathname: string, option?: ParserOption): Parser<P>;
|
||||
export function createPathParser<P = unknown>(pathname: string, option: ParserOption = defaultOption): Parser<P> {
|
||||
|
@ -47,12 +53,7 @@ export function createPathParser<P = unknown>(pathname: string, option: ParserOp
|
|||
strictMode = defaultOption.strictMode,
|
||||
exact = defaultOption.exact,
|
||||
} = option;
|
||||
/**
|
||||
* URL匹配整体流程
|
||||
* 1.词法解析,将URL模板解析为Token
|
||||
* 2.使用Token生成正则表达式
|
||||
* 3.利用正则表达式解析URL中参数或填充URL模板
|
||||
*/
|
||||
|
||||
let pattern = '^';
|
||||
const keys: string[] = [];
|
||||
const scores: number[] = [];
|
||||
|
@ -61,29 +62,61 @@ export function createPathParser<P = unknown>(pathname: string, option: ParserOp
|
|||
const onlyHasWildCard = tokens.length === 1 && tokens[0].type === TokenType.WildCard;
|
||||
const tokenCount = tokens.length;
|
||||
const lastToken = tokens[tokenCount - 1];
|
||||
let asteriskCount = 0;
|
||||
|
||||
/**
|
||||
* 用于支持URL中的可选参数/:parma?
|
||||
* @description 向前扫描到下一个分隔符/,检查其中是否有?
|
||||
* @param currentIdx
|
||||
*/
|
||||
const lookToNextDelimiter = (currentIdx: number): boolean => {
|
||||
let hasOptionalParam = false;
|
||||
while (currentIdx < tokens.length && tokens[currentIdx].type !== TokenType.Delimiter) {
|
||||
if (tokens[currentIdx].value === '?' || tokens[currentIdx].value === '*') {
|
||||
hasOptionalParam = true;
|
||||
}
|
||||
currentIdx++;
|
||||
}
|
||||
return hasOptionalParam;
|
||||
};
|
||||
for (let tokenIdx = 0; tokenIdx < tokenCount; tokenIdx++) {
|
||||
const token = tokens[tokenIdx];
|
||||
const nextToken = tokens[tokenIdx + 1];
|
||||
switch (token.type) {
|
||||
case TokenType.Delimiter:
|
||||
pattern += '/';
|
||||
const hasOptional = lookToNextDelimiter(tokenIdx + 1);
|
||||
pattern += `/${hasOptional ? '?' : ''}`;
|
||||
break;
|
||||
case TokenType.Static:
|
||||
pattern += token.value.replace(REGEX_CHARS_RE, '\\$&');
|
||||
if (nextToken && nextToken.type === TokenType.Pattern) {
|
||||
pattern += `(.${nextToken.value})`;
|
||||
keys.push(String(asteriskCount));
|
||||
asteriskCount++;
|
||||
}
|
||||
scores.push(MatchScore.static);
|
||||
break;
|
||||
case TokenType.Param:
|
||||
// 动态参数支持形如/:param、/:param*、/:param?、/:param(\\d+)的形式
|
||||
let paramRegexp = '';
|
||||
if (nextToken && nextToken.type === TokenType.LBracket) {
|
||||
if (nextToken) {
|
||||
switch (nextToken.type) {
|
||||
case TokenType.LBracket:
|
||||
// 跳过当前Token和左括号
|
||||
tokenIdx += 2;
|
||||
while (tokens[tokenIdx].type !== TokenType.RBracket) {
|
||||
paramRegexp += tokens[tokenIdx].value;
|
||||
tokenIdx++;
|
||||
}
|
||||
paramRegexp = `(${paramRegexp})`;
|
||||
break;
|
||||
case TokenType.Pattern:
|
||||
tokenIdx++;
|
||||
paramRegexp += `(${nextToken.value === '*' ? '.*' : BASE_PARAM_PATTERN})${nextToken.value}`;
|
||||
break;
|
||||
}
|
||||
pattern += paramRegexp ? `((?:${paramRegexp}))` : `(${BASE_PARAM_PATTERN})`;
|
||||
}
|
||||
pattern += paramRegexp ? `(?:${paramRegexp})` : `(${BASE_PARAM_PATTERN})`;
|
||||
keys.push(token.value);
|
||||
scores.push(MatchScore.param);
|
||||
break;
|
||||
|
@ -139,7 +172,7 @@ export function createPathParser<P = unknown>(pathname: string, option: ParserOp
|
|||
...new Array(value.length).fill(MatchScore.wildcard),
|
||||
);
|
||||
} else {
|
||||
params[key] = param ? param : [];
|
||||
params[key] = param ? param : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue