Skip to content

Commit

Permalink
If there is no query or dynamic mapping provide empty object rather
Browse files Browse the repository at this point in the history
than undefined. Update documentation to match.
  • Loading branch information
Peter Hunnisett committed Oct 25, 2019
1 parent 43d303d commit b83457b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 35 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ npm install --save apprun # peer dependency
```
### Pretty Links

As of 0.4.0, this router supports arbitrary depth path segments, dynamic path segments, and query strings along with HTML5 History.
As of version 0.4.0, this router supports arbitrary depth path segments, dynamic path segments, and query strings along with HTML5 History.

#### Pretty Links and HTML5 History

Expand Down Expand Up @@ -47,7 +47,7 @@ import { IPrettyRoute } from "apprun-router/pretty";

#### Query strings

Query strings (the part of the URI after a ?) are supported, generally, with no extra effort. By default the separator is a `&`, but this can be changed using the `setPrettyLinkQuerySeparator` method. This change affects all routes.
Query strings (the part of the URI after a ?) are supported, generally, with no extra effort. By default the field separator is a `&`, but this can be changed using the `setPrettyLinkQuerySeparator` method. This change affects all routes.

```
import {setPrettyLinkQuerySeparator} from "apprun-router/pretty";
Expand All @@ -70,14 +70,15 @@ class YourComponent extends Component {
...
update = {
"EVENT_NAME": (state: any, dynamicSegments: IPrettyRouteDynamicSegments | undefined, queries: IPrettyRouteQueries | undefined) => state
"EVENT_NAME": (state: any, dynamicSegments: IPrettyRouteDynamicSegments, queries: IPrettyRouteQueries) => state
};
....
}
```

Any found query fields will be provided as a mapping `{field1: value1, etc}`. If there is no query string, and hence no fields, the mapping will be empty (`{}`).

#### Dynamic segments

Dynamic segments (generic path segments) are supported. Unsurprisingly, they require a small amount of configuration.
Expand All @@ -98,7 +99,7 @@ class YourComponent extends Component {
state: any = {};
update = {
[addDynamicRoute(URL_FOO)]: (state: any, dynamicSegments: IPrettyRouteDynamicSegments | undefined, queries: IPrettyRouteQueries | undefined) => {
[addDynamicRoute(URL_FOO)]: (state: any, dynamicSegments: IPrettyRouteDynamicSegments, queries: IPrettyRouteQueries) => {
return {
dynamicSegments: dynamicSegments,
queries: queries,
Expand All @@ -121,6 +122,8 @@ In this example there are a few points to recognize:

3. If for some reason you no longer need a dynamic route, you will have to remove it using the `removeDynamicRoute` method. In the case of the example above it would be `removeDynamicRoute(URL_FOO)`.

4. If the route is entirely static the dynamic parameter provided to the update method will be an empty mapping (`{}`).


##### Downside of the dynamic segments implementation

Expand Down
10 changes: 4 additions & 6 deletions src/pretty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface IPrettyRouteDynamicSegments {
}

export interface IPrettyRouteQueries {
[field: string]: string | undefined;
[field: string]: string;
}

const dynamicRoutes: IPrettyRouteDynamicSegments = {};
Expand Down Expand Up @@ -79,13 +79,13 @@ function prettyLinkRouter(url: string, popstate: boolean = false): void {
const origUrl = url;

// Any queries?
let queries: {[name: string]: string} | undefined;
let queries: IPrettyRouteQueries = {};

const queryPos = url.search(/\?/);
if(queryPos >= 0) {
const queryStr = url.substring(queryPos + 1);
const queryStrings = queryStr.split(prettyLinkQuerySeparator);
queries = {};

for(const query of queryStrings) {
const [field, value] = query.split("=");
queries[field] = value;
Expand All @@ -95,7 +95,7 @@ function prettyLinkRouter(url: string, popstate: boolean = false): void {
}

// Any dynamic segements?
let dynamic: {[name: string]: string} | undefined;
let dynamic: IPrettyRouteDynamicSegments = {};
const matchingDynamicRoute = Object.keys(dynamicRoutes).find((route) => {
return url.startsWith(route + "/");
});
Expand All @@ -105,8 +105,6 @@ function prettyLinkRouter(url: string, popstate: boolean = false): void {

console.assert(dynamicParams.length === urlDynamicParams.length, `expected dynamic and actual dynamic length don't match ${dynamicParams.length} vs. ${urlDynamicParams.length}`);

dynamic = {};

// First param will always be a "", so ignore it.
for(let i = 1; i < dynamicParams.length; ++i) {
// Is this parameter in the dynamic section actually dynamic?
Expand Down
48 changes: 24 additions & 24 deletions test/pretty.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,56 +22,56 @@ const urlStatic = "/basic";
const urlStaticWithQuery = "/foo";
const urlStaticWithQueryStatic = "/foo";
const urlStaticWithQueryExample = "/foo?bar=7";
const urlStaticWithQueryExampleDynamicArgs = undefined;
const urlStaticWithQueryExampleQueryArgs = {bar: "7"};
const urlStaticWithQueryExampleDynamicArgs: IPrettyRouteDynamicSegments = {};
const urlStaticWithQueryExampleQueryArgs: IPrettyRouteQueries = {bar: "7"};

const urlStaticWithSlashWithQuery = "/foo/";
const urlStaticWithSlashWithQueryStatic = "/foo/";
const urlStaticWithSlashWithQueryExample = "/foo/?bar=9";
const urlStaticWithSlashWithQueryExampleDynamicArgs = undefined;
const urlStaticWithSlashWithQueryExampleQueryArgs = {bar: "9"};
const urlStaticWithSlashWithQueryExampleDynamicArgs: IPrettyRouteDynamicSegments = {};
const urlStaticWithSlashWithQueryExampleQueryArgs: IPrettyRouteQueries = {bar: "9"};

const urlStaticWithMultipleQuery = "/foo";
const urlStaticWithMultipleQueryStatic = "/foo";
const urlStaticWithMultipleQueryExample = "/foo?name=fred&age=88";
const urlStaticWithMultipleQueryExampleDynamicArgs = undefined;
const urlStaticWithMultipleQueryExampleQueryArgs = {name: "fred", age: "88"};
const urlStaticWithMultipleQueryExampleDynamicArgs: IPrettyRouteDynamicSegments = {};
const urlStaticWithMultipleQueryExampleQueryArgs: IPrettyRouteQueries = {name: "fred", age: "88"};

const urlStaticWithMultipleQueryUnusualSeparation = "/foo";
const urlStaticWithMultipleQueryUnusualSeparationStatic = "/foo";
const urlStaticWithMultipleQueryUnusualSeparationExample = "/foo?name=bob;age=99";
const urlStaticWithMultipleQueryUnusualSeparationExampleDynamicArgs = undefined;
const urlStaticWithMultipleQueryUnusualSeparationExampleQueryArgs = {name: "bob", age: "99"};
const urlStaticWithMultipleQueryUnusualSeparationExampleDynamicArgs: IPrettyRouteDynamicSegments = {};
const urlStaticWithMultipleQueryUnusualSeparationExampleQueryArgs: IPrettyRouteQueries = {name: "bob", age: "99"};

const urlOneDynamicSegments = "/foo/:bar";
const urlOneDynamicSegmentsStatic = "/foo";
const urlOneDynamicSegmentsExample = "/foo/fred";
const urlOneDynamicSegmentsExampleDynamicArgs = {bar: "fred"};
const urlOneDynamicSegmentsExampleQueryArgs = undefined;
const urlOneDynamicSegmentsExampleDynamicArgs: IPrettyRouteDynamicSegments = {bar: "fred"};
const urlOneDynamicSegmentsExampleQueryArgs: IPrettyRouteQueries = {};

const urlStaticSimilarToOneDynamicSegments = "/foobar";
const urlStaticSimilarToOneDynamicSegmentsStatic = "/foobar";
const urlStaticSimilarToOneDynamicSegmentsExample = "/foobar";
const urlStaticSimilarToOneDynamicSegmentsExampleDynamicArgs = undefined;
const urlStaticSimilarToOneDynamicSegmentsExampleQueryArgs = undefined;
const urlStaticSimilarToOneDynamicSegmentsExampleDynamicArgs: IPrettyRouteDynamicSegments = {};
const urlStaticSimilarToOneDynamicSegmentsExampleQueryArgs: IPrettyRouteQueries = {};

const urlTwoDynamicSegments = "/foo/:bar/:baz";
const urlTwoDynamicSegmentsStatic = "/foo";
const urlTwoDynamicSegmentsExample = "/foo/fred/barney";
const urlTwoDynamicSegmentsExampleDynamicArgs = {bar: "fred", baz: "barney"};
const urlTwoDynamicSegmentsExampleQueryArgs = undefined;
const urlTwoDynamicSegmentsExampleDynamicArgs: IPrettyRouteDynamicSegments = {bar: "fred", baz: "barney"};
const urlTwoDynamicSegmentsExampleQueryArgs: IPrettyRouteQueries = {};

const urlTwoDynamicSegmentsAndQuery = "/foo/:bar/:baz";
const urlTwoDynamicSegmentsAndQueryStatic = "/foo";
const urlTwoDynamicSegmentsAndQueryStaticExample = "/foo/seg1/seg2?boo=8";
const urlTwoDynamicSegmentsAndQueryStaticExampleDynamicArgs = {bar: "seg1", baz: "seg2"};
const urlTwoDynamicSegmentsAndQueryStaticExampleQueryArgs = {boo: "8"};
const urlTwoDynamicSegmentsAndQueryStaticExampleDynamicArgs: IPrettyRouteDynamicSegments = {bar: "seg1", baz: "seg2"};
const urlTwoDynamicSegmentsAndQueryStaticExampleQueryArgs: IPrettyRouteQueries = {boo: "8"};

const urlTwoDynamicSegmentsWithStaticAndQuery = "/foo/:bar/foo2/:baz";
const urlTwoDynamicSegmentsWithStaticAndQueryStatic = "/foo";
const urlTwoDynamicSegmentsWithStaticAndQueryStaticExample = "/foo/crazy/foo2/food?planet=earth&kingdom=bacteria";
const urlTwoDynamicSegmentsWithStaticAndQueryStaticExampleDynamicArgs = {bar: "crazy", baz: "food"};
const urlTwoDynamicSegmentsWithStaticAndQueryStaticExampleQueryArgs = {planet: "earth", kingdom: "bacteria"};
const urlTwoDynamicSegmentsWithStaticAndQueryStaticExampleDynamicArgs: IPrettyRouteDynamicSegments = {bar: "crazy", baz: "food"};
const urlTwoDynamicSegmentsWithStaticAndQueryStaticExampleQueryArgs: IPrettyRouteQueries = {planet: "earth", kingdom: "bacteria"};

describe("pretty router", () => {
it("should overwrite the default router simply by importing", () => {
Expand Down Expand Up @@ -252,9 +252,9 @@ describe("pretty router - link clicking", () => {

class TestComponent extends Component {
public update = {
[URL_FOO]: (_: any, dynamicSegments: IPrettyRouteDynamicSegments | undefined, queries: IPrettyRouteQueries | undefined) => {
expect(dynamicSegments).toEqual(undefined);
expect(queries).toEqual(undefined);
[URL_FOO]: (_: any, dynamicSegments: IPrettyRouteDynamicSegments, queries: IPrettyRouteQueries) => {
expect(dynamicSegments).toEqual({});
expect(queries).toEqual({});

test.unmount();
div.remove();
Expand Down Expand Up @@ -289,7 +289,7 @@ describe("pretty router - link clicking", () => {

class TestComponent extends Component {
public update = {
[addDynamicRoute(URL_FOO)]: (_: any, dynamicSegments: IPrettyRouteDynamicSegments | undefined, queries: IPrettyRouteQueries | undefined) => {
[addDynamicRoute(URL_FOO)]: (_: any, dynamicSegments: IPrettyRouteDynamicSegments, queries: IPrettyRouteQueries) => {
expect(dynamicSegments).toEqual(URL_DYNAMICS);
expect(queries).toEqual(URL_QUERIES);

Expand Down Expand Up @@ -328,7 +328,7 @@ describe("pretty router - link clicking", () => {

app.run("route", urlTwoDynamicSegmentsWithStaticAndQueryStaticExample);

expect(router404EventFn).toHaveBeenCalledWith(url404, undefined, urlTwoDynamicSegmentsWithStaticAndQueryStaticExampleQueryArgs);
expect(router404EventFn).toHaveBeenCalledWith(url404, {}, urlTwoDynamicSegmentsWithStaticAndQueryStaticExampleQueryArgs);

app.off(ROUTER_404_EVENT, router404EventFn);
});
Expand Down Expand Up @@ -400,7 +400,7 @@ describe("pretty router - dynamic segments", () => {
app.run("route", urlTwoDynamicSegmentsExample);

expect(routerEventFn).toHaveBeenCalled();
expect(router404EventFn).toHaveBeenCalledWith(urlTwoDynamicSegmentsExample, undefined, undefined);
expect(router404EventFn).toHaveBeenCalledWith(urlTwoDynamicSegmentsExample, {}, {});
expect(routerRouteFn).not.toHaveBeenCalled();

app.off(ROUTER_EVENT, routerEventFn);
Expand Down

0 comments on commit b83457b

Please sign in to comment.