path-to-regex
Advanced tools
Comparing version 1.0.1 to 1.1.1
148
index.js
module.exports = Regex; | ||
const escapeRe = /([$.+*?=!:[\]{}(|)/\\])/g; | ||
/** | ||
@@ -19,3 +23,2 @@ * Класс Regex [description]. | ||
splitters: options.splitters||"/", | ||
escapeChars: options.escapeChars||"/", | ||
fromStart: options.fromStart||true, | ||
@@ -57,12 +60,76 @@ toEnd: options.toEnd||true | ||
this.path = path; | ||
this.regstr = path | ||
.replace(/([\.])/g, a=>{return "\\"+a}) | ||
.replace(/:([a-z]\w*)(\((.*?)\))?/gi,(str,id,a,pat)=>{ | ||
const pattern = (pat?pat:"[^"+this.escapeChars(this.options.splitters)+"]+?"); | ||
this.keys.push({key:id,pattern:pattern}); | ||
return "(?<"+id+">"+pattern+")"; | ||
}); | ||
this.regstr = ""; | ||
let offset = 0; | ||
let count = 0; | ||
path.replace(/:([a-z]\w*)(\((.*?)\))?([\?\*\+])?/gi,(str,key,a,pat,quant,index,string)=>{ | ||
// console.log("-----------------------------"); | ||
// console.log("str:", str); | ||
// console.log("key:",key); | ||
// console.log("a:",a); | ||
// console.log("pat:",pat); | ||
// console.log("quant:",quant); | ||
// console.log("index:",index); | ||
// console.log("string:",string); | ||
const pattern = (pat?pat:"[^"+this.escape(this.options.splitters)+"]+"); | ||
const isMultiple = (quant==="*" || quant==="+")?true:false; | ||
const isRequired = (quant!=="*" && quant!=="?")?true:false; | ||
const quantifier = quant?quant:""; | ||
const startChar = path.charAt(index-1); | ||
const isStarted = this.splitter(startChar); | ||
const isStoped = (index+str.length>=path.length)?true:this.splitter(path.charAt(index+str.length)); | ||
const isToken = isStarted && isStoped; | ||
if( index > offset ){ | ||
const text = path.substring(offset,index); | ||
const regstr = this.escape(text); | ||
this.regstr+=regstr; | ||
} | ||
count++; | ||
if( !isRequired && isStarted || isMultiple ){ | ||
this.regstr+="?"; | ||
} | ||
const regstr = | ||
isMultiple? | ||
isToken? | ||
"((?:\\"+startChar+""+pattern+")"+quantifier+")": | ||
"((?:"+pattern+"\\"+startChar+"?)"+quantifier+")": | ||
isToken? | ||
"("+pattern+")"+quantifier: | ||
"("+pattern+")"+quantifier; | ||
this.regstr+=regstr; | ||
const data = { | ||
key: key, | ||
multiple: isMultiple, | ||
required: isRequired, | ||
index: count, | ||
pattern: pattern | ||
}; | ||
if( isMultiple ) | ||
data.regexp = new RegExp(pattern, this.options.case?"g":"gi" ); | ||
this.keys.push(data); | ||
offset = index+str.length; | ||
return str; | ||
}); | ||
if( offset < path.length-1 ){ | ||
const text = path.substring(offset); | ||
const regstr = this.escape(text); | ||
this.regstr+=regstr; | ||
} | ||
this.regexp = new RegExp( | ||
(this.options.fromStart?"^":"")+ | ||
this.regstr+ | ||
"["+this.escape(this.options.splitters)+"]?"+ | ||
(this.options.toEnd?"$":"") | ||
@@ -77,12 +144,21 @@ , | ||
/** | ||
* Метод преобразует строку с шаблоном пути, включающим в себя строковое представление регулярных выражений | ||
* и указадели на идентификаторы ключей в стиле Express.js в регулярное выражение | ||
* @param {string} path Строка содержащая шаблон пути. Может содержать в себе регулярные выражения и объявление ключей типа :id. Поведение имитирует аналогичный функционал библиотеки Express.js v.5.x | ||
* Метод экранирует все спец символы указанные в глобальной для модуля, переменной escapeRe | ||
* @param {string} text Любая строка | ||
* @return {string} Строка text, в которой все символы указанные в переменной escapeRe заэкранированы | ||
*/ | ||
Regex.prototype.escapeChars = function (string) { | ||
const re = new RegExp( "(["+this.options.escapeChars+this.options.splitters+"])", "g" ); | ||
return string.replace( re ,char=>{ return "\\"+char; }); | ||
Regex.prototype.escape = function(text) { | ||
return text.replace(escapeRe,s=>{return "\\"+s}); | ||
} | ||
/** | ||
* Метод проверяет является ли char одним из разделителей указанных в this.options.splitters | ||
* @param {string} char Cтрока содержащая в себе проверяемый символ (длинна строки должна быть равна 1) | ||
* @return {boolean} Если проверяемый символ является одним из символов указанных в this.options.splitters то true иначе false | ||
*/ | ||
Regex.prototype.splitter = function(char) { | ||
return !!(this.options.splitters.indexOf(char)+1); | ||
} | ||
Regex.prototype.match = function(path) { | ||
@@ -95,4 +171,46 @@ // console.log("Regex.match 01"); | ||
// console.log("Regex.match 03", result); | ||
return result.groups||{}; | ||
const data = {}; | ||
this.keys.forEach(item=>{ | ||
let isMultiple = false; | ||
// console.log("--------------"); | ||
// console.log(result[item.index]); | ||
if( data[item.key] ) | ||
isMultiple = true; | ||
if( data[item.key] && !Array.isArray(data[item.key]) ){ | ||
isMultiple = true; | ||
data[item.key] = [data[item.key]]; | ||
} | ||
if( item.multiple && !data[item.key] ){ | ||
isMultiple = true; | ||
data[item.key] = []; | ||
} | ||
// console.log("key match 01", item.key, item.multiple, isMultiple); | ||
if( !isMultiple && !item.multiple){ | ||
data[item.key] = result[item.index]; | ||
return; | ||
} | ||
// console.log("key match 02"); | ||
if( isMultiple && !item.multiple && result[item.index] ){ | ||
data[item.key].push(result[item.index]); | ||
return; | ||
} | ||
// console.log("key match 03", result); | ||
if(result[item.index]) | ||
result[item.index].replace(item.regexp, str=>{ | ||
data[item.key].push(str); | ||
}); | ||
}); | ||
return data; | ||
}; | ||
{ | ||
"name": "path-to-regex", | ||
"version": "1.0.1", | ||
"version": "1.1.1", | ||
"description": "Turn a path string such as /user/:id or /user/:id(\\d+) into a regular expression", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
182
README.md
@@ -33,14 +33,182 @@ # path-to-regex | ||
## Samples | ||
#### Demonstration of processing a simple key identifier `:keyname` | ||
```javascript | ||
var pathToRegex = require('path-to-regex'); | ||
let parser = new pathToRegex('/foo/:bar'); | ||
// parser.regexp: /^\/foo\/([^\/]+)[\/]?$/ | ||
var matcher = new pathToRegex('/foo/:bar'); | ||
// matcher.regexp = /^\/foo\/(?<bar>[^\/]+?)$/ | ||
// matcher.keys = [{key:'bar',pattern:'[^\\/]+?'}] | ||
let result = regex.match('/foo/asd'); // result: { bar: 'asd' } | ||
var result = matcher.match('/foo/12345'); | ||
// result = { bar: '12345' } | ||
let result = regex.match('/foo/123'); // result: { bar: '123' } | ||
let result = regex.match('/foo/123/bar'); // result: undefined | ||
``` | ||
#### Demonstration of processing a key identifier with a specific content `:keyname(\\d+)` | ||
```javascript | ||
let parser = new pathToRegex('/foo/:bar(\\d+)'); | ||
// parser.regexp: /^\/foo\/(\d+)[\/]?$/ | ||
let result = regex.match('/foo/123'); // result: { bar: '123' } | ||
let result = regex.match('/foo/asd'); // result: undefined | ||
let result = regex.match('/foo/123asd'); // result: undefined | ||
let result = regex.match('/foo/123/bar'); // result: undefined | ||
``` | ||
#### Demonstration of processing a multiple key identifiers `:keyname1 ... :keyname2` | ||
```javascript | ||
let parser = new pathToRegex('/user/:foo/:bar'); | ||
// parser.regexp: /^\/user\/([^\/]+)\/([^\/]+)[\/]?$/ | ||
let result = regex.match('/user/123/asd'); // result: { foo: '123', bar: 'asd' } | ||
let result = regex.match('/user/asd/123'); // result: { foo: 'asd', bar: '123' } | ||
``` | ||
#### Demonstration of processing a key identifiers with a repeated names `:keyname(\\d+) ... :keyname(\d+)` | ||
```javascript | ||
let parser = new pathToRegex('/foo/:bar/:bar'); | ||
// parser.regexp: /^\/foo\/([^\/]+)\/([^\/]+)[\/]?$/ | ||
let result = regex.match('/foo/123/asd'); // result: { bar: [ '123', 'asd' ] } | ||
let result = regex.match('/foo/asd/123'); // result: { bar: [ 'asd', '123' ] } | ||
``` | ||
#### Demonstration of processing a key identifier with a quantifier `?` | ||
```javascript | ||
let parser = new pathToRegex('/foo/:bar?'); | ||
// parser.regexp: /^\/foo\/?([^\/]+)?[\/]?$/ | ||
let result = regex.match('/foo/123'); // result: { bar: '123' } | ||
let result = regex.match('/foo/'); // result: { bar: undefined } | ||
let result = regex.match('/foo'); // result: { bar: undefined } | ||
``` | ||
#### Demonstration of processing a key identifier with a quantifiers `*` and `+` | ||
```javascript | ||
let parser = new pathToRegex('/foo/:bar*'); | ||
// parser.regexp: /^\/foo\/?((?:\/[^\/]+)*)[\/]?$/ | ||
let result = regex.match('/foo'); // result: { bar: [] } | ||
let result = regex.match('/foo/'); // result: { bar: [] } | ||
let result = regex.match('/foo/123'); // result: { bar: [ '123' ] } | ||
let result = regex.match('/foo/123/456'); // result: { bar: [ '123', '456' ] } | ||
let result = regex.match('/foo/123/456/'); // result: { bar: [ '123', '456' ] } | ||
let parser = new pathToRegex('/foo/ids: :bar*/:count?'); | ||
// parser.regexp: /^\/foo\/ids\: ?((?:[^\/]+\ ?)*)\/?([^\/]+)?[\/]?$/ | ||
let result = regex.match('/foo/ids: 123 456 789'); // result: { bar: [ '123 456 789' ], count: undefined } | ||
let result = regex.match('/foo/ids: 123 456 789/3'); // result: { bar: [ '123 456 789' ], count: '3' } | ||
let parser = new pathToRegex('/foo/:bar+'); | ||
// parser.regexp: /^\/foo\/?((?:\/[^\/]+)+)[\/]?$/ | ||
let result = regex.match('/foo'); // result: undefined | ||
let result = regex.match('/foo/'); // result: undefined | ||
let result = regex.match('/foo/123'); // result: { bar: [ '123' ] } | ||
let result = regex.match('/foo/123/456'); // result: { bar: [ '123', '456' ] } | ||
let result = regex.match('/foo/123/456/'); // result: { bar: [ '123', '456' ] } | ||
let parser = new pathToRegex('/foo/ids-,:bar+/:count?'); | ||
// parser.regexp: /^\/foo\/ids-,?((?:[^\/]+\,?)+)\/?([^\/]+)?[\/]?$/ | ||
let result = regex.match('/foo/ids-123,456,789'); // result: { bar: [ '123,456,789' ], count: undefined } | ||
let result = regex.match('/foo/ids-123,456,789/3'); // result: { bar: [ '123,456,789' ], count: '3' } | ||
``` | ||
#### Demonstration of processing a key identifier with all features | ||
```javascript | ||
let parser = new pathToRegex('/user/:id/bar/:key(\\d+):post?fak/:key(\d+)*:foo+/test/pictures-,:multi(\w+?\.png)*/:key?'); | ||
// parser.regexp: /^\/user\/([^\/]+)\/bar\/(\d+)([^\/]+)?fak\/?((?:\d+\/?)*)?((?:[^\/]+\*?)+)\/test\/pictures-,?((?:\w+?\.png\,?)*)\/?([^\/]+)?[\/]?$/ | ||
let result = regex.match('/user/123/bar/111qwertyfak/222foo/test/pictures-p01.png,p02.png,p03.png'); | ||
/* result: | ||
{ id: '123', | ||
key: [ '111', '222' ], | ||
post: 'qwerty', | ||
foo: [ 'foo' ], | ||
multi: [ 'p01.png', 'p02.png', 'p03.png' ] } | ||
*/ | ||
let result = regex.match('/user/123/bar/111qwertyfak/222foo/test/pictures-p01.png,p02.png,p03.png/333'); | ||
/* result: | ||
{ id: '123', | ||
key: [ '111', '222', '333' ], | ||
post: 'qwerty', | ||
foo: [ 'foo' ], | ||
multi: [ 'p01.png', 'p02.png', 'p03.png' ] } | ||
*/ | ||
let parser = new pathToRegex('/user/:id/bar/:key(\\d+):post?fak/:key(\d+)*:foo+/test/pictures- :multi(\w+?\.png)*/:key*'); | ||
// parser.regexp: /^\/user\/([^\/]+)\/bar\/(\d+)([^\/]+)?fak\/?((?:\d+\/?)*)?((?:[^\/]+\*?)+)\/test\/pictures- ?((?:\w+?\.png\ ?)*)\/?((?:\/[^\/]+)*)[\/]?$/ | ||
let result = regex.match('/user/123/bar/111fak/222foo/test/pictures-p01.png p02.png p03.png'); | ||
/* result: | ||
{ id: '123', | ||
key: [ '111', '222' ], | ||
post: undefined, | ||
foo: [ 'foo' ], | ||
multi: [ 'p01.png', 'p02.png', 'p03.png' ] } | ||
*/ | ||
let result = regex.match('/user/123/bar/111fak/222foo/test/pictures-p01.png p02.png p03.png/333'); | ||
/* result: | ||
{ id: '123', | ||
key: [ '111', '222', '333' ], | ||
post: undefined, | ||
foo: [ 'foo' ], | ||
multi: [ 'p01.png', 'p02.png', 'p03.png' ] } | ||
*/ | ||
let result = regex.match('/user/123/bar/111fak/222foo/test/pictures-p01.png p02.png p03.png/333/444/'); | ||
/* result: | ||
{ id: '123', | ||
key: [ '111', '222', '333', '444' ], | ||
post: undefined, | ||
foo: [ 'foo' ], | ||
multi: [ 'p01.png', 'p02.png', 'p03.png' ] } | ||
*/ | ||
``` | ||
... documentation in processed | ||
@@ -50,2 +218,4 @@ | ||
[![NPM](https://nodei.co/npm/path-to-regex.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/path-to-regex/) | ||
[npm-image]: https://img.shields.io/npm/v/path-to-regex.svg?style=flat | ||
@@ -52,0 +222,0 @@ [npm-url]: https://npmjs.org/package/path-to-regex |
@@ -0,1 +1,3 @@ | ||
const PathToRegex = require("../index.js"); | ||
const chai = require('chai'); | ||
@@ -7,5 +9,5 @@ const assert = chai.assert; | ||
const PathToRegex = require("../index.js"); | ||
describe("Тестируем модуль преобразования пути в RegExp", function() { | ||
@@ -75,8 +77,6 @@ | ||
const params = re3.match("/foo/123/bar/456"); | ||
console.log("REGEX:", "\t\t"+re3.regexp, "\t\t", re3.regexp, "\t\t", re3.regstr, "\t\t", re3.path, "\t\t", re3.keys); | ||
console.log("REGEX:", "\t\t", params); | ||
assert.equal( !!params, true); | ||
}); | ||
it("соотносим RegExp /^\\/foo\/(?<fooid>[^\\/]+?)\\/bar\\/(?<barid>[^\\/]+?)$/ (путь \"/foo/:fooid/bar/:barid\" ) со строками \"/foo/111/bar/222\" \"/foo/id1/bar/id22\" и проверяем наличие ключей fooid и barid и соответствие их значений", function() { | ||
it("соотносим RegExp /^\\/foo\\/(?<fooid>[^\\/]+?)\\/bar\\/(?<barid>[^\\/]+?)$/ (путь \"/foo/:fooid/bar/:barid\" ) со строками \"/foo/111/bar/222\" \"/foo/id1/bar/id22\" и проверяем наличие ключей fooid и barid и соответствие их значений", function() { | ||
const params1 = re3.match("/foo/111/bar/222"); | ||
@@ -88,4 +88,25 @@ const params2 = re3.match("/foo/id1/bar/id22"); | ||
assert.equal( params2.barid, "id22"); | ||
}); | ||
const re4 = new PathToRegex("/user/:id(\\d+)"); | ||
console.log("REGEX:", "\t\t"+re4.regexp, "\t\t", re4.regexp, "\t\t", re4.regstr, "\t\t", re4.path); | ||
// console.log("REGEX:", "\t\t"+re3.regexp, "\t\t", re3.regexp, "\t\t", re3.regstr, "\t\t", re3.path, "\t\t", re3.keys); | ||
// console.log("REGEX:", "\t\t", params); | ||
it("создаем RegExp из \"/user/:id(\\\\d+)\"", function() { | ||
assert.equal( re4 instanceof PathToRegex, true); | ||
assert.equal( ""+re4.regexp, ""+/^\/user\/(?<id>\d+)$/ ); | ||
}); | ||
it("соотносим RegExp /^\\/user\\/(?<id>\\d+)$/ (путь \"/user/:id(\\\\d+)\" ) со строками \"/\" \"/user\" \"/user/123\" \"/user/123/foo\" \"/user/aaa\" ", function() { | ||
assert.equal( !!re4.match("/"), false); | ||
assert.equal( !!re4.match("/user"), false); | ||
const params = re4.match("/user/123"); | ||
assert.equal( !!params, true); | ||
assert.equal( params.id, "123"); | ||
assert.equal( !!re4.match("/user/123/foo"), false); | ||
assert.equal( !!re4.match("/user/aaa"), false); | ||
}); | ||
}); |
AI-detected possible typosquat
Supply chain riskAI has identified this package as a potential typosquat of a more popular package. This suggests that the package may be intentionally mimicking another package's name, description, or other metadata.
Found 1 instance in 1 package
20820
259
226
0