New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

boring-router

Package Overview
Dependencies
Maintainers
1
Versions
108
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

boring-router - npm Package Compare versions

Comparing version 0.3.0-alpha.4 to 0.3.0-alpha.5

77

bld/library/route-match.d.ts
import { History } from 'history';
import { Dict } from 'tslang';
import { Dict, EmptyObjectPatch, OmitValueOfKey } from 'tslang';
import { RouteSource } from './router';
/**
* Route match interception callback.
* @return Return `true` or `undefined` to do nothing; return `false` to ignore
* this match; return a full path to redirect.
* Route match before enter callback.
* @return Return `true` or `undefined` to do nothing; return `false` to revert
* this history change; return full path to redirect.
*/
export declare type RouteMatchInterception = () => string | boolean | void;
export declare type RouteMatchReaction = () => void;
export declare type RouteMatchBeforeEnter<TRouteMatch extends RouteMatch = RouteMatch> = (next: OmitValueOfKey<TRouteMatch, Exclude<keyof RouteMatch, keyof MatchingRouteMatch>>) => string | boolean | void;
/**
* Route match before leave callback.
* @return Return `true` or `undefined` to do nothing; return `false` to revert
* this history change.
*/
export declare type RouteMatchBeforeLeave = () => boolean | void;
export declare type RouteMatchAfterEnter = () => void;
export declare type RouteMatchAfterLeave = () => void;
export declare type RouteMatchServiceFactory<TRouteMatch extends RouteMatch> = (match: TRouteMatch) => IRouteService<TRouteMatch>;
export interface IRouteService<TRouteMatch extends RouteMatch = RouteMatch> {
beforeEnter?: RouteMatchBeforeEnter<TRouteMatch>;
afterEnter?: RouteMatchAfterEnter;
beforeLeave?: RouteMatchBeforeLeave;
afterLeave?: RouteMatchAfterLeave;
}
export declare type GeneralFragmentDict = Dict<string | undefined>;
export declare type GeneralQueryDict = Dict<string | undefined>;
export declare type GeneralParamDict = Dict<string | undefined>;
export interface RouteMatchOptions {
export interface RouteMatchSharedOptions {
match: string | RegExp;
query: Dict<boolean> | undefined;
}
export interface RouteMatchOptions extends RouteMatchSharedOptions {
exact: boolean;
}
export declare class RouteMatch<TParamDict extends GeneralParamDict = GeneralParamDict> {
declare abstract class RouteMatchShared<TParamDict extends GeneralParamDict = GeneralParamDict> {
/**

@@ -24,12 +41,4 @@ * Name of this `RouteMatch`, correspondent to the field name of route

readonly $name: string;
constructor(name: string, history: History, { match, query, exact }: RouteMatchOptions);
constructor(name: string, source: RouteSource, parent: RouteMatchShared | undefined, history: History, { match, query }: RouteMatchSharedOptions);
/**
* A reactive value indicates whether this route is matched.
*/
readonly $matched: boolean;
/**
* A reactive value indicates whether this route is exactly matched.
*/
readonly $exact: boolean;
/**
* A dictionary of the combination of query string and fragments.

@@ -44,25 +53,37 @@ */

*/
$ref(params?: Partial<TParamDict>, preserveQuery?: boolean): string;
$ref(params?: Partial<TParamDict> & EmptyObjectPatch, preserveQuery?: boolean): string;
/**
* Perform a `history.push()` with `this.$ref(params, preserveQuery)`.
*/
$push(params?: Partial<TParamDict>, preserveQuery?: boolean): void;
$push(params?: Partial<TParamDict> & EmptyObjectPatch, preserveQuery?: boolean): void;
/**
* Perform a `history.replace()` with `this.$ref(params, preserveQuery)`.
*/
$replace(params?: Partial<TParamDict>, preserveQuery?: boolean): void;
$replace(params?: Partial<TParamDict> & EmptyObjectPatch, preserveQuery?: boolean): void;
}
export declare class MatchingRouteMatch<TParamDict extends GeneralParamDict = GeneralParamDict> extends RouteMatchShared<TParamDict> {
constructor(name: string, source: RouteSource, parent: RouteMatchShared<TParamDict> | undefined, origin: RouteMatch<TParamDict>, history: History, options: RouteMatchSharedOptions);
/**
* Intercept route matching if this `RouteMatch` matches.
* @param interception The interception callback.
* @param exact Intercept only if it's an exact match.
* A reactive value indicates whether this route is exactly matched.
*/
$intercept(interception: RouteMatchInterception, exact?: boolean): void;
readonly $exact: boolean;
}
export declare class RouteMatch<TParamDict extends GeneralParamDict = GeneralParamDict> extends RouteMatchShared<TParamDict> {
constructor(name: string, source: RouteSource, parent: RouteMatch | undefined, history: History, { exact, ...sharedOptions }: RouteMatchOptions);
/**
* Perform a reaction if this `RouteMatch` matches.
* @param reaction A callback to perform this reaction.
* @param exact Perform this reaction only if it's an exact match.
* A reactive value indicates whether this route is matched.
*/
$react(reaction: RouteMatchReaction, exact?: boolean): void;
readonly $matched: boolean;
/**
* A reactive value indicates whether this route is exactly matched.
*/
readonly $exact: boolean;
$beforeEnter(callback: RouteMatchBeforeEnter<this>): this;
$beforeLeave(callback: RouteMatchBeforeLeave): this;
$afterEnter(callback: RouteMatchAfterEnter): this;
$afterLeave(callback: RouteMatchAfterLeave): this;
$service(factory: RouteMatchServiceFactory<this>): this;
static fragment: RegExp;
static rest: RegExp;
}
export {};

@@ -6,11 +6,7 @@ "use strict";

const _utils_1 = require("./@utils");
class RouteMatch {
constructor(name, history, { match, query, exact }) {
/** @internal */
this._interceptionEntries = [];
/** @internal */
this._matched = false;
/** @internal */
this._exact = false;
class RouteMatchShared {
constructor(name, source, parent, history, { match, query }) {
this.$name = name;
this._source = source;
this._parent = parent;
this._history = history;

@@ -24,22 +20,48 @@ if (match instanceof RegExp && match.global) {

}
this._allowExact = exact;
}
/**
* A reactive value indicates whether this route is matched.
*/
get $matched() {
return this._matched;
}
/**
* A reactive value indicates whether this route is exactly matched.
*/
get $exact() {
return this._exact;
}
/**
* A dictionary of the combination of query string and fragments.
*/
get $params() {
return this._params;
return Object.assign({}, this._paramFragments, this._query);
}
/** @internal */
get _fragment() {
let entry = this._getMatchEntry(this._source);
return entry && entry.fragment;
}
/** @internal */
get _paramFragments() {
let parent = this._parent;
let upperFragmentDict = parent && parent._paramFragments;
let matchPattern = this._matchPattern;
let fragment = this._fragment;
return Object.assign({}, upperFragmentDict, (typeof matchPattern === 'string'
? undefined
: { [this.$name]: fragment }));
}
/** @internal */
get _pathFragments() {
let parent = this._parent;
let upperFragmentDict = parent && parent._pathFragments;
let matchPattern = this._matchPattern;
let fragment = this._fragment;
return Object.assign({}, upperFragmentDict, {
[this.$name]: typeof matchPattern === 'string' ? matchPattern : fragment,
});
}
/** @internal */
get _query() {
let queryKeys = this._queryKeys;
let sourceQueryDict = this._source.queryDict;
return queryKeys
? queryKeys.reduce((dict, key) => {
let value = sourceQueryDict[key];
if (value !== undefined) {
dict[key] = sourceQueryDict[key];
}
return dict;
}, {})
: undefined;
}
/**

@@ -53,2 +75,3 @@ * Generates a string reference that can be used for history navigation.

let fragmentDict = this._pathFragments;
let sourceQueryDict = this._source.queryDict;
let paramKeySet = new Set(Object.keys(params));

@@ -66,3 +89,2 @@ let path = Object.keys(fragmentDict)

.join('');
let sourceQueryDict = this._sourceQuery;
let query = new URLSearchParams([

@@ -74,3 +96,3 @@ ...(preserveQuery

]).toString();
return path + (query ? `?${query}` : '');
return `${path}${query ? `?${query}` : ''}`;
}

@@ -91,121 +113,200 @@ /**

}
}
tslib_1.__decorate([
mobx_1.computed
], RouteMatchShared.prototype, "$params", null);
tslib_1.__decorate([
mobx_1.computed
], RouteMatchShared.prototype, "_fragment", null);
tslib_1.__decorate([
mobx_1.computed
], RouteMatchShared.prototype, "_paramFragments", null);
tslib_1.__decorate([
mobx_1.computed
], RouteMatchShared.prototype, "_pathFragments", null);
tslib_1.__decorate([
mobx_1.computed
], RouteMatchShared.prototype, "_query", null);
class MatchingRouteMatch extends RouteMatchShared {
constructor(name, source, parent, origin, history, options) {
super(name, source, parent, history, options);
this._origin = origin;
}
/**
* Intercept route matching if this `RouteMatch` matches.
* @param interception The interception callback.
* @param exact Intercept only if it's an exact match.
* A reactive value indicates whether this route is exactly matched.
*/
$intercept(interception, exact = false) {
this._interceptionEntries.push({
interception,
exact,
});
get $exact() {
let entry = this._getMatchEntry();
return !!entry && entry.exact;
}
/** @internal */
_getMatchEntry() {
return this._origin._getMatchEntry(this._source);
}
}
exports.MatchingRouteMatch = MatchingRouteMatch;
class RouteMatch extends RouteMatchShared {
constructor(name, source, parent, history, _a) {
var { exact } = _a, sharedOptions = tslib_1.__rest(_a, ["exact"]);
super(name, source, parent, history, sharedOptions);
/** @internal */
this._beforeEnterCallbacks = [];
/** @internal */
this._beforeLeaveCallbacks = [];
/** @internal */
this._afterEnterCallbacks = [];
/** @internal */
this._afterLeaveCallbacks = [];
/** @internal */
this._matched = false;
/** @internal */
this._exactlyMatched = false;
this._allowExact = exact;
}
/**
* Perform a reaction if this `RouteMatch` matches.
* @param reaction A callback to perform this reaction.
* @param exact Perform this reaction only if it's an exact match.
* A reactive value indicates whether this route is matched.
*/
$react(reaction, exact = false) {
mobx_1.autorun(() => {
if (exact ? this.$exact : this.$matched) {
_utils_1.then(() => reaction());
}
});
get $matched() {
return this._matched;
}
/**
* A reactive value indicates whether this route is exactly matched.
*/
get $exact() {
return this._exactlyMatched;
}
$beforeEnter(callback) {
this._beforeEnterCallbacks.push(callback);
return this;
}
$beforeLeave(callback) {
this._beforeLeaveCallbacks.push(callback);
return this;
}
$afterEnter(callback) {
this._afterEnterCallbacks.push(callback);
return this;
}
$afterLeave(callback) {
this._afterLeaveCallbacks.push(callback);
return this;
}
$service(factory) {
if (this._service) {
throw new Error(`Service has already been defined for "${this.$name}"`);
}
this._service = factory(this);
return this;
}
/** @internal */
_match(rest) {
if (!rest) {
return {
fragment: undefined,
rest: '',
};
}
if (!rest.startsWith('/')) {
throw new Error(`Expecting rest of path to be started with "/", but got ${JSON.stringify(rest)} instead`);
}
rest = rest.slice(1);
let pattern = this._matchPattern;
if (typeof pattern === 'string') {
if (_utils_1.isPathPrefix(rest, pattern)) {
return {
fragment: pattern,
rest: rest.slice(pattern.length),
};
_match(upperRest) {
let fragment;
let rest;
if (upperRest) {
if (!upperRest.startsWith('/')) {
throw new Error(`Expecting rest of path to be started with "/", but got ${JSON.stringify(upperRest)} instead`);
}
else {
return {
fragment: undefined,
rest: '',
};
}
}
else {
let groups = pattern.exec(rest);
if (groups) {
let matched = groups[0];
if (!_utils_1.isPathPrefix(rest, matched)) {
throw new Error(`Invalid regular expression pattern, expecting rest of path to be started with "/" after match (matched ${JSON.stringify(matched)} out of ${JSON.stringify(rest)})`);
upperRest = upperRest.slice(1);
let pattern = this._matchPattern;
if (typeof pattern === 'string') {
if (_utils_1.isPathPrefix(upperRest, pattern)) {
fragment = pattern;
rest = upperRest.slice(pattern.length);
}
return {
fragment: matched,
rest: rest.slice(matched.length),
};
else {
fragment = undefined;
rest = '';
}
}
else {
return {
fragment: undefined,
rest: '',
};
let groups = pattern.exec(upperRest);
if (groups) {
let matched = groups[0];
if (!_utils_1.isPathPrefix(upperRest, matched)) {
throw new Error(`Invalid regular expression pattern, expecting rest of path to be started with "/" after match (matched ${JSON.stringify(matched)} out of ${JSON.stringify(upperRest)})`);
}
fragment = matched;
rest = upperRest.slice(matched.length);
}
else {
fragment = undefined;
rest = '';
}
}
}
else {
fragment = undefined;
rest = '';
}
let matched = fragment !== undefined;
let exactlyMatched = matched && rest === '';
if (exactlyMatched && (this._children && !this._allowExact)) {
matched = false;
exactlyMatched = false;
}
return {
matched,
exactlyMatched,
fragment,
rest,
};
}
/** @internal */
_intercept(exact) {
let entries = this._interceptionEntries;
if (!exact) {
entries = entries.filter(entry => !entry.exact);
}
for (let { interception } of entries) {
let result = interception();
if (result === true || result === undefined) {
continue;
}
_beforeLeave() {
for (let callback of this._beforeLeaveCallbacks) {
let result = callback();
if (result === false) {
return false;
}
if (typeof result === 'string') {
}
let service = this._service;
if (service && service.beforeLeave) {
service.beforeLeave();
}
return true;
}
/** @internal */
_beforeEnter() {
let next = this._matching;
for (let callback of this._beforeEnterCallbacks) {
let result = callback(next);
if (typeof result === 'string' || result === false) {
return result;
}
throw new Error('Invalid interception result');
}
return undefined;
let service = this._service;
if (service && service.beforeEnter) {
service.beforeEnter(next);
}
return true;
}
/** @internal */
_update(matched, exact, fragment, upperPathFragmentDict, upperParamFragmentDict, sourceQueryDict) {
let name = this.$name;
let matchPattern = this._matchPattern;
let pathFragmentDict = Object.assign({}, upperPathFragmentDict, { [name]: typeof matchPattern === 'string' ? matchPattern : fragment });
let paramFragmentDict = Object.assign({}, upperParamFragmentDict, (typeof matchPattern === 'string' ? undefined : { [name]: fragment }));
this._pathFragments = pathFragmentDict;
let queryKeys = this._queryKeys;
let queryDict = queryKeys
? matched
? queryKeys.reduce((dict, key) => {
let value = sourceQueryDict[key];
if (value !== undefined) {
dict[key] = sourceQueryDict[key];
}
return dict;
}, {})
: {}
: undefined;
this._sourceQuery = sourceQueryDict;
this._params = Object.assign({}, paramFragmentDict, queryDict);
_afterLeave() {
for (let callback of this._afterLeaveCallbacks) {
callback();
}
let service = this._service;
if (service && service.afterLeave) {
service.afterLeave();
}
}
/** @internal */
_afterEnter() {
for (let callback of this._afterEnterCallbacks) {
callback();
}
let service = this._service;
if (service && service.afterEnter) {
service.afterEnter();
}
}
/** @internal */
_update(matched, exactlyMatched) {
this._matched = matched;
this._exact = exact;
return {
pathFragmentDict,
paramFragmentDict,
};
this._exactlyMatched = exactlyMatched;
}
/** @internal */
_getMatchEntry(source) {
return source.matchToMatchEntryMap.get(this);
}
}

@@ -219,7 +320,4 @@ RouteMatch.fragment = /[^/]+/;

mobx_1.observable
], RouteMatch.prototype, "_exact", void 0);
tslib_1.__decorate([
mobx_1.observable
], RouteMatch.prototype, "_params", void 0);
], RouteMatch.prototype, "_exactlyMatched", void 0);
exports.RouteMatch = RouteMatch;
//# sourceMappingURL=route-match.js.map
import { History } from 'history';
import { RouteMatch } from './route-match';
import { GeneralQueryDict, RouteMatch } from './route-match';
import { RouteSchemaDict } from './schema';

@@ -11,5 +11,10 @@ export declare type FragmentMatcherCallback = (key: string) => string;

} ? TMatch extends string ? never : T : never;
interface RouteSchemaChildrenPartial<TRouteSchemaDict> {
interface RouteSchemaChildrenSection<TRouteSchemaDict> {
$children: TRouteSchemaDict;
}
export declare type NestedRouteSchemaDictType<TRouteSchema> = TRouteSchema extends RouteSchemaChildrenSection<infer TNestedRouteSchemaDict> ? TNestedRouteSchemaDict : {};
interface RouteSchemaExtensionSection<TRouteMatchExtension> {
$extension: TRouteMatchExtension;
}
export declare type RouteMatchExtensionType<TRouteSchema> = TRouteSchema extends RouteSchemaExtensionSection<infer TRouteMatchExtension> ? TRouteMatchExtension : {};
export declare type RouteMatchFragmentType<TRouteSchemaDict, TFragmentKey extends string> = {

@@ -20,3 +25,3 @@ [K in Extract<keyof TRouteSchemaDict, string>]: RouteMatchType<TRouteSchemaDict[K], TFragmentKey | FilterRouteMatchNonStringFragment<TRouteSchemaDict[K], K>>;

[K in TFragmentKey]: string;
}> & (TRouteSchema extends RouteSchemaChildrenPartial<infer TNestedRouteSchemaDict> ? RouteMatchFragmentType<TNestedRouteSchemaDict, TFragmentKey> : {});
}> & RouteMatchFragmentType<NestedRouteSchemaDictType<TRouteSchema>, TFragmentKey> & RouteMatchExtensionType<TRouteSchema>;
export declare type RouterType<TRouteSchemaDict> = Router & RouteMatchFragmentType<TRouteSchemaDict, never>;

@@ -28,2 +33,6 @@ export interface RouteMatchEntry {

}
export interface RouteSource {
matchToMatchEntryMap: Map<RouteMatch, RouteMatchEntry>;
queryDict: GeneralQueryDict;
}
export interface RouterOptions {

@@ -35,7 +44,10 @@ /**

fragmentMatcher?: FragmentMatcherCallback;
/** Default path on error. */
default?: string;
}
export declare class Router {
private constructor();
private _revert;
static create<TSchema extends RouteSchemaDict>(schema: TSchema, history: History, options?: RouterOptions): RouterType<TSchema>;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const history_1 = require("history");
const hyphenate_1 = tslib_1.__importDefault(require("hyphenate"));
const mobx_1 = require("mobx");
const _utils_1 = require("./@utils");

@@ -9,5 +11,20 @@ const route_match_1 = require("./route-match");

class Router {
constructor(schema, history, { fragmentMatcher }) {
constructor(schema, history, { fragmentMatcher, default: defaultPath = '/' }) {
/** @internal */
this._onLocationChange = ({ pathname, search }) => {
this._source = mobx_1.observable({
matchToMatchEntryMap: new Map(),
queryDict: {},
});
/** @internal */
this._matchingSource = mobx_1.observable({
matchToMatchEntryMap: new Map(),
queryDict: {},
});
/** @internal */
this._onLocationChange = ({ pathname, search }, action) => {
let history = this._history;
let location = history.location;
if (history_1.locationsAreEqual(this._location, location)) {
return;
}
let searchParams = new URLSearchParams(search);

@@ -18,60 +35,87 @@ let queryDict = Array.from(searchParams).reduce((dict, [key, value]) => {

}, {});
let matchResult = this._match(this, pathname);
if (typeof matchResult === 'string') {
this._history.replace(matchResult);
return;
let routeMatchEntries = this._match(this, pathname) || [];
let matchToMatchEntryMap = new Map(routeMatchEntries.map((entry) => [entry.match, entry]));
Object.assign(this._matchingSource, {
matchToMatchEntryMap,
queryDict,
});
// Prepare previous/next match set
let previousMatchSet = new Set(this._source.matchToMatchEntryMap.keys());
let nextMatchSet = new Set(matchToMatchEntryMap.keys());
let leavingMatchSet = new Set(previousMatchSet);
for (let match of nextMatchSet) {
leavingMatchSet.delete(match);
}
let routeMatchEntryMap = new Map(matchResult
? matchResult.map((entry) => [entry.match, entry])
: undefined);
this._update(this, routeMatchEntryMap, {}, {}, queryDict);
let enteringMatchSet = new Set(nextMatchSet);
for (let match of previousMatchSet) {
enteringMatchSet.delete(match);
}
// Process before hooks
for (let match of Array.from(leavingMatchSet).reverse()) {
let result = match._beforeLeave();
if (!result) {
this._revert(action);
return;
}
}
for (let match of enteringMatchSet) {
let result = match._beforeEnter();
if (typeof result === 'string') {
history.replace(result);
return;
}
if (!result) {
this._revert(action);
return;
}
}
this._location = location;
Object.assign(this._source, this._matchingSource);
// Update
for (let match of leavingMatchSet) {
match._update(false, false);
}
for (let match of nextMatchSet) {
let { exact } = matchToMatchEntryMap.get(match);
match._update(true, exact);
}
// Process after hooks
for (let match of leavingMatchSet) {
match._afterLeave();
}
for (let match of enteringMatchSet) {
match._afterEnter();
}
};
this._history = history;
this._location = history_1.parsePath(defaultPath);
this._fragmentMatcher =
fragmentMatcher || DEFAULT_FRAGMENT_MATCHER_CALLBACK;
this._children = this._build(this, schema);
this._update(this, new Map(), {}, {}, {});
this._children = this._build(schema, this);
_utils_1.then(() => {
history.listen(this._onLocationChange);
this._onLocationChange(history.location);
this._onLocationChange(history.location, 'POP');
});
}
_revert(action) {
let history = this._history;
let location = this._location;
switch (action) {
case 'PUSH':
history.goBack();
break;
case 'POP':
case 'REPLACE':
history.replace(location);
break;
}
}
/** @internal */
_match(target, upperRest) {
for (let routeMatch of target._children || []) {
let { fragment, rest } = routeMatch._match(upperRest);
let matched = fragment !== undefined;
let exact = matched && rest === '';
if (matched) {
let interceptionResult = routeMatch._intercept(exact);
if (typeof interceptionResult === 'string') {
return interceptionResult;
}
else if (interceptionResult === false) {
matched = false;
exact = false;
}
}
let { matched, exactlyMatched, fragment, rest } = routeMatch._match(upperRest);
if (!matched) {
continue;
}
if (exact) {
if (!routeMatch._children || routeMatch._allowExact) {
return [
{
match: routeMatch,
fragment: fragment,
exact: true,
},
];
}
else {
continue;
}
}
let result = this._match(routeMatch, rest);
if (typeof result === 'string') {
return result;
}
else if (result) {
if (exactlyMatched) {
return [

@@ -81,7 +125,18 @@ {

fragment: fragment,
exact: false,
exact: true,
},
...result,
];
}
let result = this._match(routeMatch, rest);
if (!result) {
continue;
}
return [
{
match: routeMatch,
fragment: fragment,
exact: false,
},
...result,
];
}

@@ -91,24 +146,7 @@ return undefined;

/** @internal */
_update(target, routeMatchEntryMap, upperPathFragmentDict, upperParamFragmentDict, sourceQueryDict) {
for (let routeMatch of target._children || []) {
let entry = routeMatchEntryMap.get(routeMatch);
let matched;
let exact;
let fragment;
if (entry) {
matched = true;
exact = entry.exact;
fragment = entry.fragment;
}
else {
matched = false;
exact = false;
}
let { pathFragmentDict, paramFragmentDict } = routeMatch._update(matched, exact, fragment, upperPathFragmentDict, upperParamFragmentDict, sourceQueryDict);
this._update(routeMatch, routeMatchEntryMap, pathFragmentDict, paramFragmentDict, sourceQueryDict);
}
}
/** @internal */
_build(target, schemaDict) {
_build(schemaDict, parent, matchingParent) {
let routeMatches = [];
let source = this._source;
let matchingSource = this._matchingSource;
let history = this._history;
for (let [key, schema] of Object.entries(schemaDict)) {

@@ -118,14 +156,31 @@ if (typeof schema === 'boolean') {

}
let { $match: match = this._fragmentMatcher(key), $query: query, $exact: exact = false, $children: children, } = schema;
let routeMatch = new route_match_1.RouteMatch(key, this._history, {
let { $match: match = this._fragmentMatcher(key), $query: query, $exact: exact = false, $children: children, $extension: extension = {}, } = schema;
let options = {
match,
query,
exact,
});
};
let routeMatch = new route_match_1.RouteMatch(key, source, parent instanceof route_match_1.RouteMatch ? parent : undefined, history, options);
mobx_1.extendObservable(routeMatch, extension);
let matchingRouteMatch = new route_match_1.MatchingRouteMatch(key, matchingSource, matchingParent, routeMatch, history, options);
for (let key of Object.keys(extension)) {
Object.defineProperty(matchingRouteMatch, key, {
get() {
return routeMatch[key];
},
set(value) {
routeMatch[key] = value;
},
});
}
routeMatch._matching = matchingRouteMatch;
routeMatches.push(routeMatch);
target[key] = routeMatch;
parent[key] = routeMatch;
if (matchingParent) {
matchingParent[key] = matchingRouteMatch;
}
if (!children) {
continue;
}
routeMatch._children = this._build(routeMatch, children);
routeMatch._children = this._build(children, routeMatch, matchingRouteMatch);
}

@@ -138,3 +193,6 @@ return routeMatches;

}
tslib_1.__decorate([
mobx_1.observable
], Router.prototype, "_matchingSource", void 0);
exports.Router = Router;
//# sourceMappingURL=router.js.map

@@ -11,4 +11,5 @@ import { Dict } from 'tslang';

$children?: RouteSchemaDict;
$extension?: object;
}
export declare type RouteSchemaDict = Dict<RouteSchema | boolean>;
export declare function schema<T extends RouteSchemaDict>(schema: T): T;

@@ -5,2 +5,7 @@ # Changelog

### Changes
- Added hooks `$beforeEnter`, `$afterEnter`, `$beforeLeave` and `$afterLeave`.
- Added service `$service`.
### Breaking changes

@@ -10,3 +15,3 @@

- By default, the router will no longer match a route if it has children but the path is ended at the route itself. For example, if the path is `/account`, and route `account` has `$children`, `account` will not be matched by default. An option `$exact` is added for this scenario, and applies only to route schema with `$children`.
- `RouteMatch#$action` has been replaced with `RouteMatch#$react`.
- `RouteMatch#$action` has been removed, see hooks for alternatives.

@@ -13,0 +18,0 @@ ## [0.2.1] - 2018-9-5

{
"name": "boring-router",
"version": "0.3.0-alpha.4",
"version": "0.3.0-alpha.5",
"description": "A light-weight, type-safe, yet reactive router service using MobX.",

@@ -42,3 +42,3 @@ "repository": {

"jest": "^23.5.0",
"mobx": "^5.1.0",
"mobx": "^5.5.0",
"mobx-react": "^5.2.5",

@@ -58,4 +58,4 @@ "prettier": "^1.13.7",

"hyphenate": "^0.2.4",
"tslang": "^0.1.7"
"tslang": "^0.1.9"
}
}

@@ -212,12 +212,29 @@ [![NPM Package](https://badge.fury.io/js/boring-router.svg)](https://www.npmjs.com/package/boring-router)

- [Reaction](examples/reaction/main.tsx)
- [Hooks](examples/hooks/main.tsx)
Take a reaction on route match.
Add hooks to route match.
```tsx
router.account.$react(() => {
router.about.$replace({source: 'reaction'});
router.account.$beforeEnter(() => {
return router.about.$ref();
});
```
- [Service](examples/service/main.tsx)
Add service to route match.
```tsx
router.account.$service(match => {
return {
beforeEnter() {
match.account = new Account();
},
afterLeave() {
match.account = undefined;
},
};
});
```
### Run an example

@@ -224,0 +241,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc