Skip to content

Commit

Permalink
make second names argument mandatory for regexes
Browse files Browse the repository at this point in the history
  • Loading branch information
snd committed May 13, 2019
1 parent 6b49532 commit 4408b70
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 68 deletions.
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,21 +204,17 @@ unnamed wildcards are not collected.
## make pattern from regex

```javascript
> const pattern = new UrlPattern(/^\/api\/(.*)$/);
```

if the pattern was created from a regex an array of the captured groups is returned on a match:
> const pattern = new UrlPattern(/^\/api\/(.*)$/, ["path"]);
```javascript
> pattern.match("/api/users");
["users"]
{path: "users"}
> pattern.match("/apiii/test");
undefined
```

when making a pattern from a regex
you can pass an array of keys as the second argument.
you have to pass an array of keys as the second argument.
returns objects on match with each key mapped to a captured value:

```javascript
Expand Down
53 changes: 26 additions & 27 deletions src/url-pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default class UrlPattern {
public readonly isRegex: boolean;
public readonly regex: RegExp;
public readonly ast?: Array<Ast<any>>;
public readonly names?: string[];
public readonly names: string[];

constructor(pattern: string, options?: IUserInputOptions);
constructor(pattern: RegExp, groupNames?: string[]);
Expand All @@ -51,22 +51,25 @@ export default class UrlPattern {
// handle regex pattern and return early
if (pattern instanceof RegExp) {
this.regex = pattern;
if (optionsOrGroupNames != null) {
if (!Array.isArray(optionsOrGroupNames)) {
throw new TypeError([
"if first argument is a RegExp the second argument",
"may be an Array<String> of group names",
"but you provided something else",
].join(" "));
}
const groupCount = regexGroupCount(this.regex);
if (optionsOrGroupNames.length !== groupCount) {
throw new Error([
`regex contains ${ groupCount } groups`,
`but array of group names contains ${ optionsOrGroupNames.length }`,
].join(" "));
}
this.names = optionsOrGroupNames;
if (optionsOrGroupNames == null || !Array.isArray(optionsOrGroupNames)) {
throw new TypeError([
"if first argument is a RegExp the second argument",
"must be an Array<String> of group names",
].join(" "));
}
const groupCount = regexGroupCount(this.regex);
if (optionsOrGroupNames.length !== groupCount) {
throw new Error([
`regex contains ${ groupCount } groups`,
`but array of group names contains ${ optionsOrGroupNames.length }`,
].join(" "));
}
this.names = optionsOrGroupNames;
const regexNameIndex = indexOfDuplicateElement(this.names);
if (regexNameIndex !== -1) {
throw new Error(
`duplicate name "${ this.names[regexNameIndex] }" in pattern. names must be unique`,
);
}
return;
}
Expand Down Expand Up @@ -114,24 +117,20 @@ export default class UrlPattern {
}
}

public match(url: string): { [index: string]: string } | string[] | undefined {
public match(url: string): { [index: string]: string } | undefined {
const match = this.regex.exec(url);
if (match == null) {
return;
}

const groups = match.slice(1);
if (this.names != null) {
const mergedNamesAndGroups: { [index: string]: string } = {};
for (let i = 0; i < this.names.length; i++) {
if (groups[i] != null) {
mergedNamesAndGroups[this.names[i]] = groups[i];
}
const mergedNamesAndGroups: { [index: string]: string } = {};
for (let i = 0; i < this.names.length; i++) {
if (groups[i] != null) {
mergedNamesAndGroups[this.names[i]] = groups[i];
}
return mergedNamesAndGroups;
} else {
return groups;
}
return mergedNamesAndGroups;
}

public stringify(params?: object): string {
Expand Down
9 changes: 4 additions & 5 deletions test/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,9 @@ tape("regex names", (t: tape.Test) => {
try {
new UntypedUrlPattern(/x/, 5);
} catch (error) {
t.equal(error.message, [
"if first argument is a RegExp the second argument may be an Array<String>",
"of group names but you provided something else",
].join(" "));
t.equal(error.message,
"if first argument is a RegExp the second argument must be an Array<String> of group names",
);
}
try {
new UrlPattern(/(((foo)bar(boo))far)/, []);
Expand All @@ -137,7 +136,7 @@ tape("regex names", (t: tape.Test) => {

tape("stringify regex", (t: tape.Test) => {
t.plan(1);
const pattern = new UrlPattern(/x/);
const pattern = new UrlPattern(/x/, []);
try {
pattern.stringify();
} catch (error) {
Expand Down
32 changes: 5 additions & 27 deletions test/match-fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ tape("match", (t: tape.Test) => {
pattern = new UrlPattern(".foo");
t.equals(pattern.match(".bar.foo"), undefined);

pattern = new UrlPattern(/foo/);
pattern = new UrlPattern(/foo/, []);
t.deepEqual(pattern.match("foo"), []);

pattern = new UrlPattern(/\/foo\/(.*)/);
t.deepEqual(pattern.match("/foo/bar"), ["bar"]);

pattern = new UrlPattern(/\/foo\/(.*)/);
t.deepEqual(pattern.match("/foo/"), [""]);
pattern = new UrlPattern(/\/foo\/(.*)/, ["path"]);
t.deepEqual(pattern.match("/foo/bar"), {path: "bar"});
t.deepEqual(pattern.match("/foo/"), {path: ""});

pattern = new UrlPattern("/user/:userId/task/:taskId");
t.deepEqual(pattern.match("/user/10/task/52"), {
Expand Down Expand Up @@ -308,27 +306,7 @@ tape("match", (t: tape.Test) => {
scheme: "https",
});

let regex = /\/ip\/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
pattern = new UrlPattern(regex);
t.equal(undefined, pattern.match("10.10.10.10"));
t.equal(undefined, pattern.match("ip/10.10.10.10"));
t.equal(undefined, pattern.match("/ip/10.10.10."));
t.equal(undefined, pattern.match("/ip/10."));
t.equal(undefined, pattern.match("/ip/"));
t.deepEqual(pattern.match("/ip/10.10.10.10"), ["10", "10", "10", "10"]);
t.deepEqual(pattern.match("/ip/127.0.0.1"), ["127", "0", "0", "1"]);

regex = /\/ip\/((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/;
pattern = new UrlPattern(regex);
t.equal(undefined, pattern.match("10.10.10.10"));
t.equal(undefined, pattern.match("ip/10.10.10.10"));
t.equal(undefined, pattern.match("/ip/10.10.10."));
t.equal(undefined, pattern.match("/ip/10."));
t.equal(undefined, pattern.match("/ip/"));
t.deepEqual(pattern.match("/ip/10.10.10.10"), ["10.10.10.10"]);
t.deepEqual(pattern.match("/ip/127.0.0.1"), ["127.0.0.1"]);

regex = /\/ip\/((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/;
const regex = /\/ip\/((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/;
pattern = new UrlPattern(regex, ["ip"]);
t.equal(undefined, pattern.match("10.10.10.10"));
t.equal(undefined, pattern.match("ip/10.10.10.10"));
Expand Down
4 changes: 2 additions & 2 deletions test/readme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ tape("domain example", (t: tape.Test) => {
});

tape("regex example", (t: tape.Test) => {
const pattern = new UrlPattern(/^\/api\/(.*)$/);
t.deepEqual(pattern.match("/api/users"), ["users"]);
const pattern = new UrlPattern(/^\/api\/(.*)$/, ["path"]);
t.deepEqual(pattern.match("/api/users"), {path: "users"});
t.equal(pattern.match("/apiii/users"), undefined);
t.end();
});
Expand Down

0 comments on commit 4408b70

Please sign in to comment.