Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@jsenv/url-meta

Package Overview
Dependencies
Maintainers
2
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jsenv/url-meta - npm Package Compare versions

Comparing version 6.0.3 to 6.1.0

408

dist/esmodule/jsenv_url_meta.js

@@ -26,36 +26,107 @@ const assertUrlLike = (value, name = "url") => {

// https://git-scm.com/docs/gitignore
/*
*
* Link to things doing pattern matching:
* https://git-scm.com/docs/gitignore
* https://github.com/kaelzhang/node-ignore
*/
/** @module jsenv_url_meta **/
/**
* An object representing the result of applying a pattern to an url
* @typedef {Object} MatchResult
* @property {boolean} matched Indicates if url matched pattern
* @property {number} patternIndex Index where pattern stopped matching url, otherwise pattern.length
* @property {number} urlIndex Index where url stopped matching pattern, otherwise url.length
* @property {Array} matchGroups Array of strings captured during pattern matching
*/
/**
* Apply a pattern to an url
* @param {Object} applyPatternMatchingParams
* @param {string} applyPatternMatchingParams.pattern "*", "**" and trailing slash have special meaning
* @param {string} applyPatternMatchingParams.url a string representing an url
* @return {MatchResult}
*/
const applyPatternMatching = ({
pattern,
url,
...rest
} = {}) => {
url
}) => {
assertUrlLike(pattern, "pattern");
assertUrlLike(url, "url");
if (Object.keys(rest).length) {
throw new Error(`received more parameters than expected.
--- name of unexpected parameters ---
${Object.keys(rest)}
--- name of expected parameters ---
pattern, url`);
}
return applyMatching(pattern, url);
const {
matched,
patternIndex,
index,
groups
} = applyMatching(pattern, url);
const matchGroups = [];
let groupIndex = 0;
groups.forEach(group => {
if (group.name) {
matchGroups[group.name] = group.string;
} else {
matchGroups[groupIndex] = group.string;
groupIndex++;
}
});
return {
matched,
patternIndex,
urlIndex: index,
matchGroups
};
};
const applyMatching = (pattern, string) => {
const groups = [];
let patternIndex = 0;
let index = 0;
let remainingPattern = pattern;
let remainingString = string; // eslint-disable-next-line no-constant-condition
let remainingString = string;
let restoreIndexes = true;
while (true) {
const consumePattern = count => {
const subpattern = remainingPattern.slice(0, count);
remainingPattern = remainingPattern.slice(count);
patternIndex += count;
return subpattern;
};
const consumeString = count => {
const substring = remainingString.slice(0, count);
remainingString = remainingString.slice(count);
index += count;
return substring;
};
const consumeRemainingString = () => {
return consumeString(remainingString.length);
};
let matched;
const iterate = () => {
const patternIndexBefore = patternIndex;
const indexBefore = index;
matched = matchOne();
if (matched === undefined) {
consumePattern(1);
consumeString(1);
iterate();
return;
}
if (matched === false && restoreIndexes) {
patternIndex = patternIndexBefore;
index = indexBefore;
}
};
const matchOne = () => {
// pattern consumed and string consumed
if (remainingPattern === "" && remainingString === "") {
// pass because string fully matched pattern
return pass({
patternIndex,
index
});
return true; // string fully matched pattern
} // pattern consumed, string not consumed

@@ -65,8 +136,4 @@

if (remainingPattern === "" && remainingString !== "") {
// fails because string longer than expected
return fail({
patternIndex,
index
});
} // from this point pattern is not consumed
return false; // fails because string longer than expected
} // -- from this point pattern is not consumed --
// string consumed, pattern not consumed

@@ -76,16 +143,16 @@

if (remainingString === "") {
// pass because trailing "**" is optional
if (remainingPattern === "**") {
return pass({
patternIndex: patternIndex + 2,
index
// trailing "**" is optional
consumePattern(2);
return true;
}
if (remainingPattern === "*") {
groups.push({
string: ""
});
} // fail because string shorted than expected
}
return fail({
patternIndex,
index
});
} // from this point pattern and string are not consumed
return false; // fail because string shorter than expected
} // -- from this point pattern and string are not consumed --
// fast path trailing slash

@@ -95,14 +162,12 @@

if (remainingPattern === "/") {
// pass because trailing slash matches remaining
if (remainingString[0] === "/") {
return pass({
patternIndex: patternIndex + 1,
index: string.length
// trailing slash match remaining
consumePattern(1);
groups.push({
string: consumeRemainingString()
});
return true;
}
return fail({
patternIndex,
index
});
return false;
} // fast path trailing '**'

@@ -112,7 +177,5 @@

if (remainingPattern === "**") {
// pass because trailing ** matches remaining
return pass({
patternIndex: patternIndex + 2,
index: string.length
});
consumePattern(2);
consumeRemainingString();
return true;
} // pattern leading **

@@ -122,10 +185,6 @@

if (remainingPattern.slice(0, 2) === "**") {
// consumes "**"
remainingPattern = remainingPattern.slice(2);
patternIndex += 2;
consumePattern(2); // consumes "**"
if (remainingPattern[0] === "/") {
// consumes "/"
remainingPattern = remainingPattern.slice(1);
patternIndex += 1;
consumePattern(1); // consumes "/"
} // pattern ending with ** always match remaining string

@@ -135,6 +194,4 @@

if (remainingPattern === "") {
return pass({
patternIndex,
index: string.length
});
consumeRemainingString();
return true;
}

@@ -144,47 +201,40 @@

pattern: remainingPattern,
string: remainingString
string: remainingString,
canSkipSlash: true
});
if (!skipResult.matched) {
return fail({
patternIndex: patternIndex + skipResult.patternIndex,
index: index + skipResult.index
});
}
return pass({
patternIndex: pattern.length,
index: string.length
});
groups.push(...skipResult.groups);
consumePattern(skipResult.patternIndex);
consumeRemainingString();
restoreIndexes = false;
return skipResult.matched;
}
if (remainingPattern[0] === "*") {
// consumes "*"
remainingPattern = remainingPattern.slice(1);
patternIndex += 1; // la c'est plus délicat, il faut que remainingString
// ne soit composé que de truc !== '/'
consumePattern(1); // consumes "*"
if (remainingPattern === "") {
// matches everything except '/'
const slashIndex = remainingString.indexOf("/");
if (slashIndex > -1) {
return fail({
patternIndex,
index: index + slashIndex
if (slashIndex === -1) {
groups.push({
string: consumeRemainingString()
});
return true;
}
return pass({
patternIndex,
index: string.length
groups.push({
string: consumeString(slashIndex)
});
return false;
} // the next char must not the one expected by remainingPattern[0]
// because * is greedy and expect to skip one char
// because * is greedy and expect to skip at least one char
if (remainingPattern[0] === remainingString[0]) {
return fail({
patternIndex: patternIndex - "*".length,
index
groups.push({
string: ""
});
patternIndex = patternIndex - 1;
return false;
}

@@ -195,32 +245,25 @@

string: remainingString,
skippablePredicate: remainingString => remainingString[0] !== "/"
canSkipSlash: false
});
if (!skipResult.matched) {
return fail({
patternIndex: patternIndex + skipResult.patternIndex,
index: index + skipResult.index
});
}
return pass({
patternIndex: pattern.length,
index: string.length
});
groups.push(skipResult.group, ...skipResult.groups);
consumePattern(skipResult.patternIndex);
consumeString(skipResult.index);
restoreIndexes = false;
return skipResult.matched;
}
if (remainingPattern[0] !== remainingString[0]) {
return fail({
patternIndex,
index
});
} // consumes next char
return false;
}
return undefined;
};
remainingPattern = remainingPattern.slice(1);
remainingString = remainingString.slice(1);
patternIndex += 1;
index += 1;
continue;
}
iterate();
return {
matched,
patternIndex,
index,
groups
};
};

@@ -231,76 +274,61 @@

string,
skippablePredicate = () => true
canSkipSlash
}) => {
let index = 0;
let remainingString = string;
let bestMatch = null; // eslint-disable-next-line no-constant-condition
let longestMatchRange = null;
while (true) {
const tryToMatch = () => {
const matchAttempt = applyMatching(pattern, remainingString);
if (matchAttempt.matched) {
bestMatch = matchAttempt;
break;
return {
matched: true,
patternIndex: matchAttempt.patternIndex,
index: index + matchAttempt.index,
groups: matchAttempt.groups,
group: {
string: remainingString === "" ? string : string.slice(0, -remainingString.length)
}
};
}
const skippable = skippablePredicate(remainingString);
bestMatch = fail({
patternIndex: bestMatch ? Math.max(bestMatch.patternIndex, matchAttempt.patternIndex) : matchAttempt.patternIndex,
index: index + matchAttempt.index
});
const matchAttemptIndex = matchAttempt.index;
const matchRange = {
patternIndex: matchAttempt.patternIndex,
index,
length: matchAttemptIndex,
groups: matchAttempt.groups
};
if (!skippable) {
break;
} // search against the next unattempted string
if (!longestMatchRange || longestMatchRange.length < matchRange.length) {
longestMatchRange = matchRange;
}
const nextIndex = matchAttemptIndex + 1;
const canSkip = nextIndex < remainingString.length && (canSkipSlash || remainingString[0] !== "/");
remainingString = remainingString.slice(matchAttempt.index + 1);
index += matchAttempt.index + 1;
if (remainingString === "") {
bestMatch = { ...bestMatch,
index: string.length
};
break;
if (canSkip) {
// search against the next unattempted string
index += nextIndex;
remainingString = remainingString.slice(nextIndex);
return tryToMatch();
}
continue;
}
return bestMatch;
};
const pass = ({
patternIndex,
index
}) => {
return {
matched: true,
index,
patternIndex
return {
matched: false,
patternIndex: longestMatchRange.patternIndex,
index: longestMatchRange.index + longestMatchRange.length,
groups: longestMatchRange.groups,
group: {
string: string.slice(0, longestMatchRange.index)
}
};
};
};
const fail = ({
patternIndex,
index
}) => {
return {
matched: false,
index,
patternIndex
};
return tryToMatch();
};
const normalizeStructuredMetaMap = (structuredMetaMap, baseUrl, ...rest) => {
const normalizeStructuredMetaMap = (structuredMetaMap, baseUrl) => {
assertUrlLike(baseUrl, "url");
if (rest.length) {
throw new Error(`received more arguments than expected.
--- number of arguments received ---
${2 + rest.length}
--- number of arguments expected ---
2`);
}
const structuredMetaMapNormalized = {};

@@ -345,3 +373,3 @@ Object.keys(structuredMetaMap).forEach(metaProperty => {

const structuredMetaMapToMetaMap = (structuredMetaMap, ...rest) => {
const structuredMetaMapToMetaMap = structuredMetaMap => {
if (!isPlainObject(structuredMetaMap)) {

@@ -351,10 +379,2 @@ throw new TypeError(`structuredMetaMap must be a plain object, got ${structuredMetaMap}`);

if (rest.length) {
throw new Error(`received more arguments than expected.
--- number of arguments received ---
${1 + rest.length}
--- number of arguments expected ---
1`);
}
const metaMap = {};

@@ -384,4 +404,3 @@ Object.keys(structuredMetaMap).forEach(metaProperty => {

structuredMetaMap,
predicate,
...rest
predicate
}) => {

@@ -398,10 +417,2 @@ assertUrlLike(url, "url"); // the function was meants to be used on url ending with '/'

if (Object.keys(rest).length) {
throw new Error(`received more parameters than expected.
--- name of unexpected parameters ---
${Object.keys(rest)}
--- name of expected parameters ---
url, structuredMetaMap, predicate`);
}
const metaMap = structuredMetaMapToMetaMap(structuredMetaMap); // for full match we must create an object to allow pattern to override previous ones

@@ -416,6 +427,3 @@

const meta = metaMap[pattern];
const {
matched,
index
} = applyPatternMatching({
const matchResult = applyPatternMatching({
pattern,

@@ -425,3 +433,3 @@ url

if (matched) {
if (matchResult.matched) {
someFullMatch = true;

@@ -431,3 +439,3 @@ fullMatchMeta = { ...fullMatchMeta,

};
} else if (someFullMatch === false && index >= url.length) {
} else if (someFullMatch === false && matchResult.urlIndex >= url.length) {
partialMatchMetaArray.push(meta);

@@ -446,15 +454,5 @@ }

url,
structuredMetaMap,
...rest
} = {}) => {
structuredMetaMap
}) => {
assertUrlLike(url);
if (Object.keys(rest).length) {
throw new Error(`received more parameters than expected.
--- name of unexpected parameters ---
${Object.keys(rest)}
--- name of expected parameters ---
url, structuredMetaMap`);
}
const metaMap = structuredMetaMapToMetaMap(structuredMetaMap);

@@ -461,0 +459,0 @@ return Object.keys(metaMap).reduce((previousMeta, pattern) => {

{
"name": "@jsenv/url-meta",
"version": "6.0.3",
"version": "6.1.0",
"description": "Associate data to urls using patterns",

@@ -10,4 +10,10 @@ "license": "MIT",

},
"author": {
"name": "dmail",
"email": "dmaillard06@gmail.com",
"url": "https://twitter.com/damienmaillard"
},
"publishConfig": {
"access": "public"
"access": "public",
"registry": "https://registry.npmjs.org"
},

@@ -32,4 +38,4 @@ "engines": {

"scripts": {
"dev": "node ./script/dev/start_dev_server.mjs",
"eslint": "node ./node_modules/eslint/bin/eslint.js . --ext=.html,.js,.mjs,.cjs",
"dev": "node ./script/dev/dev.mjs",
"eslint": "npx eslint . --ext=.html,.js,.mjs,.cjs",
"importmap": "node ./script/importmap/importmap.mjs",

@@ -46,13 +52,13 @@ "test": "node --unhandled-rejections=strict ./script/test/test.mjs",

"devDependencies": {
"@jsenv/assert": "2.4.1",
"@jsenv/assert": "2.5.2",
"@jsenv/babel-preset": "1.1.2",
"@jsenv/core": "25.1.1",
"@jsenv/core": "25.4.7",
"@jsenv/eslint-config": "16.0.9",
"@jsenv/file-size-impact": "12.1.1",
"@jsenv/github-release-package": "1.2.3",
"@jsenv/importmap-eslint-resolver": "5.2.2",
"@jsenv/file-size-impact": "12.1.7",
"@jsenv/github-release-package": "1.3.4",
"@jsenv/importmap-eslint-resolver": "5.2.5",
"@jsenv/importmap-node-module": "5.1.0",
"@jsenv/package-publish": "1.6.2",
"@jsenv/performance-impact": "2.2.1",
"eslint": "8.6.0",
"@jsenv/package-publish": "1.7.2",
"@jsenv/performance-impact": "2.2.7",
"eslint": "8.7.0",
"eslint-plugin-html": "6.2.0",

@@ -63,2 +69,2 @@ "eslint-plugin-import": "2.25.4",

}
}
}

@@ -1,13 +0,5 @@

# url-meta
# url-meta [![npm package](https://img.shields.io/npm/v/@jsenv/url-meta.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/url-meta) [![github ci](https://github.com/jsenv/url-meta/workflows/main/badge.svg)](https://github.com/jsenv/url-meta/actions?workflow=main) [![codecov coverage](https://codecov.io/gh/jsenv/url-meta/branch/master/graph/badge.svg)](https://codecov.io/gh/jsenv/url-meta)
Associate data to urls using patterns.
_@jsenv/url-meta_ allows to associate value to urls using pattern matching.
[![npm package](https://img.shields.io/npm/v/@jsenv/url-meta.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/url-meta)
[![github ci](https://github.com/jsenv/url-meta/workflows/main/badge.svg)](https://github.com/jsenv/url-meta/actions?workflow=main)
[![codecov coverage](https://codecov.io/gh/jsenv/url-meta/branch/master/graph/badge.svg)](https://codecov.io/gh/jsenv/url-meta)
# Presentation
`@jsenv/url-meta` allows to associate value to urls using pattern matching.
```js

@@ -53,16 +45,2 @@ import { urlToMeta } from "@jsenv/url-meta"

# Pattern matching example
Table showing if a pattern matches when applied to `"file:///directory/file.js"`
| pattern | matches? |
| ---------------------------- | -------- |
| `file:///directory/*.js` | true |
| `file:///directory/**/*.js` | true |
| `file:///**/*.js` | true |
| `file:///directory` | false |
| `file:///directory/` | true |
| `file:///directory/file.js` | true |
| `file:///directory/file.jsx` | false |
# metaMap and structuredMetaMap

@@ -77,3 +55,2 @@

}
const structuredMetaMap = {

@@ -87,7 +64,7 @@ visible: {

_structuredMetaMap_ allows to group patterns per property which are easier to read and compose. For this reason it's the object structure used by our API.
_structuredMetaMap_ allows to group patterns per property which are easier to read and compose. For this reason it's the object structure used by _@jsenv/url-meta_ API.
# applyPatternMatching
`applyPatternMatching` is a function returning a `matchResult` indicating if and how a `pattern` matches an `url`.
_applyPatternMatching_ is a function returning a _matchResult_ indicating if and how a _pattern_ matches an _url_.

@@ -101,3 +78,2 @@ ```js

})
matchResult.matched // true

@@ -108,23 +84,42 @@ ```

`pattern` parameter is a string looking like an url but where `*` and `**` can be used so that one specifier can match several url. This parameter is **required**.
_pattern_ parameter is a string looking like an url but where `*` and `**` can be used so that one specifier can match several url.
This parameter is **required**.
## url
`url` parameter is a string representing a url. This parameter is **required**.
_url_ parameter is a string representing a url.
This parameter is **required**.
## matchResult
`matchResult` represents if and how a `pattern` matches an `url`.
_matchResult_ represents if and how a _pattern_ matches an _url_.
### Matching example
```js
import { applyPatternMatching } from "@jsenv/url-meta"
const fullMatch = applyPatternMatching({
pattern: "file:///**/*",
url: "file://Users/directory/file.js",
url: "file:///Users/directory/file.js",
})
fullMatch // { matched: true, index: 31, patternIndex: 12 }
console.log(JSON.stringify(fullMatch, null, " "))
```
fullMatch object indicates `pattern` fully matched `url`.
```json
{
"matched": true,
"patternIndex": 12,
"urlIndex": 31,
"matchGroups": ["file.js"]
}
```
### Partial matching example
```js
import { applyPatternMatching } from "@jsenv/url-meta"
const partialMatch = applyPatternMatching({

@@ -134,10 +129,17 @@ pattern: "file:///*.js",

})
partialMatch // { matched: false, index: 14, patternIndex: 14 }
console.log(JSON.stringify(partialMatch, null, " "))
```
partialMatch object indicates `pattern` matched `url` until comparing `url[14]` with `pattern[14]`.
```json
{
"matched": false,
"patternIndex": 12,
"urlIndex": 15,
"matchGroups": ["file"]
}
```
# normalizeStructuredMetaMap
`normalizeStructuredMetaMap` is a function resolving a `structuredMetaMap` against an `url`.
_normalizeStructuredMetaMap_ is a function resolving _structuredMetaMap_ keys against an _url_.

@@ -170,3 +172,3 @@ ```js

`urlCanContainsMetaMatching` is a function designed to ignore directory content that would never have specific metas.
_urlCanContainsMetaMatching_ is a function designed to ignore directory content that would never have specific metas.

@@ -200,3 +202,3 @@ ```js

`urlToMeta` is a function returning an object being the composition of all meta where `pattern` matched the `url`.
_urlToMeta_ is a function returning an object being the composition of all meta where _pattern_ matched the _url_.

@@ -214,9 +216,7 @@ ```js

}
const urlA = "file:///src/file.js"
const urlB = "file:///src/file.json"
console.log(
`${urlA}: ${JSON.stringify(
urlToMeta({ url: urlA, specifierMetaMap }),
urlToMeta({ url: urlA, structuredMetaMap }),
null,

@@ -228,3 +228,3 @@ " ",

`${urlB}: ${JSON.stringify(
urlToMeta({ url: urlB, specifierMetaMap }),
urlToMeta({ url: urlB, structuredMetaMap }),
null,

@@ -241,3 +241,3 @@ " ",

"insideSrc": true,
"extensionIsJs": true,
"extensionIsJs": true
}

@@ -244,0 +244,0 @@ file:///src/file.json: {

@@ -1,20 +0,51 @@

// https://git-scm.com/docs/gitignore
// https://github.com/kaelzhang/node-ignore
/*
*
* Link to things doing pattern matching:
* https://git-scm.com/docs/gitignore
* https://github.com/kaelzhang/node-ignore
*/
import { assertUrlLike } from "./internal/assertUrlLike.js"
export const applyPatternMatching = ({ pattern, url, ...rest } = {}) => {
/** @module jsenv_url_meta **/
/**
* An object representing the result of applying a pattern to an url
* @typedef {Object} MatchResult
* @property {boolean} matched Indicates if url matched pattern
* @property {number} patternIndex Index where pattern stopped matching url, otherwise pattern.length
* @property {number} urlIndex Index where url stopped matching pattern, otherwise url.length
* @property {Array} matchGroups Array of strings captured during pattern matching
*/
/**
* Apply a pattern to an url
* @param {Object} applyPatternMatchingParams
* @param {string} applyPatternMatchingParams.pattern "*", "**" and trailing slash have special meaning
* @param {string} applyPatternMatchingParams.url a string representing an url
* @return {MatchResult}
*/
export const applyPatternMatching = ({ pattern, url }) => {
assertUrlLike(pattern, "pattern")
assertUrlLike(url, "url")
if (Object.keys(rest).length) {
throw new Error(`received more parameters than expected.
--- name of unexpected parameters ---
${Object.keys(rest)}
--- name of expected parameters ---
pattern, url`)
const { matched, patternIndex, index, groups } = applyMatching(pattern, url)
const matchGroups = []
let groupIndex = 0
groups.forEach((group) => {
if (group.name) {
matchGroups[group.name] = group.string
} else {
matchGroups[groupIndex] = group.string
groupIndex++
}
})
return {
matched,
patternIndex,
urlIndex: index,
matchGroups,
}
return applyMatching(pattern, url)
}
const applyMatching = (pattern, string) => {
const groups = []
let patternIndex = 0

@@ -24,232 +55,193 @@ let index = 0

let remainingString = string
let restoreIndexes = true
// eslint-disable-next-line no-constant-condition
while (true) {
const consumePattern = (count) => {
const subpattern = remainingPattern.slice(0, count)
remainingPattern = remainingPattern.slice(count)
patternIndex += count
return subpattern
}
const consumeString = (count) => {
const substring = remainingString.slice(0, count)
remainingString = remainingString.slice(count)
index += count
return substring
}
const consumeRemainingString = () => {
return consumeString(remainingString.length)
}
let matched
const iterate = () => {
const patternIndexBefore = patternIndex
const indexBefore = index
matched = matchOne()
if (matched === undefined) {
consumePattern(1)
consumeString(1)
iterate()
return
}
if (matched === false && restoreIndexes) {
patternIndex = patternIndexBefore
index = indexBefore
}
}
const matchOne = () => {
// pattern consumed and string consumed
if (remainingPattern === "" && remainingString === "") {
// pass because string fully matched pattern
return pass({
patternIndex,
index,
})
return true // string fully matched pattern
}
// pattern consumed, string not consumed
if (remainingPattern === "" && remainingString !== "") {
// fails because string longer than expected
return fail({
patternIndex,
index,
})
return false // fails because string longer than expected
}
// from this point pattern is not consumed
// -- from this point pattern is not consumed --
// string consumed, pattern not consumed
if (remainingString === "") {
// pass because trailing "**" is optional
if (remainingPattern === "**") {
return pass({
patternIndex: patternIndex + 2,
index,
})
// trailing "**" is optional
consumePattern(2)
return true
}
// fail because string shorted than expected
return fail({
patternIndex,
index,
})
if (remainingPattern === "*") {
groups.push({ string: "" })
}
return false // fail because string shorter than expected
}
// from this point pattern and string are not consumed
// -- from this point pattern and string are not consumed --
// fast path trailing slash
if (remainingPattern === "/") {
// pass because trailing slash matches remaining
if (remainingString[0] === "/") {
return pass({
patternIndex: patternIndex + 1,
index: string.length,
})
// trailing slash match remaining
consumePattern(1)
groups.push({ string: consumeRemainingString() })
return true
}
return fail({
patternIndex,
index,
})
return false
}
// fast path trailing '**'
if (remainingPattern === "**") {
// pass because trailing ** matches remaining
return pass({
patternIndex: patternIndex + 2,
index: string.length,
})
consumePattern(2)
consumeRemainingString()
return true
}
// pattern leading **
if (remainingPattern.slice(0, 2) === "**") {
// consumes "**"
remainingPattern = remainingPattern.slice(2)
patternIndex += 2
consumePattern(2) // consumes "**"
if (remainingPattern[0] === "/") {
// consumes "/"
remainingPattern = remainingPattern.slice(1)
patternIndex += 1
consumePattern(1) // consumes "/"
}
// pattern ending with ** always match remaining string
if (remainingPattern === "") {
return pass({
patternIndex,
index: string.length,
})
consumeRemainingString()
return true
}
const skipResult = skipUntilMatch({
pattern: remainingPattern,
string: remainingString,
canSkipSlash: true,
})
if (!skipResult.matched) {
return fail({
patternIndex: patternIndex + skipResult.patternIndex,
index: index + skipResult.index,
})
}
return pass({
patternIndex: pattern.length,
index: string.length,
})
groups.push(...skipResult.groups)
consumePattern(skipResult.patternIndex)
consumeRemainingString()
restoreIndexes = false
return skipResult.matched
}
if (remainingPattern[0] === "*") {
// consumes "*"
remainingPattern = remainingPattern.slice(1)
patternIndex += 1
// la c'est plus délicat, il faut que remainingString
// ne soit composé que de truc !== '/'
consumePattern(1) // consumes "*"
if (remainingPattern === "") {
// matches everything except '/'
const slashIndex = remainingString.indexOf("/")
if (slashIndex > -1) {
return fail({
patternIndex,
index: index + slashIndex,
})
if (slashIndex === -1) {
groups.push({ string: consumeRemainingString() })
return true
}
return pass({
patternIndex,
index: string.length,
})
groups.push({ string: consumeString(slashIndex) })
return false
}
// the next char must not the one expected by remainingPattern[0]
// because * is greedy and expect to skip one char
// because * is greedy and expect to skip at least one char
if (remainingPattern[0] === remainingString[0]) {
return fail({
patternIndex: patternIndex - "*".length,
index,
})
groups.push({ string: "" })
patternIndex = patternIndex - 1
return false
}
const skipResult = skipUntilMatch({
pattern: remainingPattern,
string: remainingString,
skippablePredicate: (remainingString) => remainingString[0] !== "/",
canSkipSlash: false,
})
if (!skipResult.matched) {
return fail({
patternIndex: patternIndex + skipResult.patternIndex,
index: index + skipResult.index,
})
}
return pass({
patternIndex: pattern.length,
index: string.length,
})
groups.push(skipResult.group, ...skipResult.groups)
consumePattern(skipResult.patternIndex)
consumeString(skipResult.index)
restoreIndexes = false
return skipResult.matched
}
if (remainingPattern[0] !== remainingString[0]) {
return fail({
patternIndex,
index,
})
return false
}
return undefined
}
iterate()
// consumes next char
remainingPattern = remainingPattern.slice(1)
remainingString = remainingString.slice(1)
patternIndex += 1
index += 1
continue
return {
matched,
patternIndex,
index,
groups,
}
}
const skipUntilMatch = ({
pattern,
string,
skippablePredicate = () => true,
}) => {
const skipUntilMatch = ({ pattern, string, canSkipSlash }) => {
let index = 0
let remainingString = string
let bestMatch = null
// eslint-disable-next-line no-constant-condition
while (true) {
let longestMatchRange = null
const tryToMatch = () => {
const matchAttempt = applyMatching(pattern, remainingString)
if (matchAttempt.matched) {
bestMatch = matchAttempt
break
return {
matched: true,
patternIndex: matchAttempt.patternIndex,
index: index + matchAttempt.index,
groups: matchAttempt.groups,
group: {
string:
remainingString === ""
? string
: string.slice(0, -remainingString.length),
},
}
}
const skippable = skippablePredicate(remainingString)
bestMatch = fail({
patternIndex: bestMatch
? Math.max(bestMatch.patternIndex, matchAttempt.patternIndex)
: matchAttempt.patternIndex,
index: index + matchAttempt.index,
})
if (!skippable) {
break
const matchAttemptIndex = matchAttempt.index
const matchRange = {
patternIndex: matchAttempt.patternIndex,
index,
length: matchAttemptIndex,
groups: matchAttempt.groups,
}
// search against the next unattempted string
remainingString = remainingString.slice(matchAttempt.index + 1)
index += matchAttempt.index + 1
if (remainingString === "") {
bestMatch = {
...bestMatch,
index: string.length,
}
break
if (!longestMatchRange || longestMatchRange.length < matchRange.length) {
longestMatchRange = matchRange
}
continue
const nextIndex = matchAttemptIndex + 1
const canSkip =
nextIndex < remainingString.length &&
(canSkipSlash || remainingString[0] !== "/")
if (canSkip) {
// search against the next unattempted string
index += nextIndex
remainingString = remainingString.slice(nextIndex)
return tryToMatch()
}
return {
matched: false,
patternIndex: longestMatchRange.patternIndex,
index: longestMatchRange.index + longestMatchRange.length,
groups: longestMatchRange.groups,
group: {
string: string.slice(0, longestMatchRange.index),
},
}
}
return bestMatch
return tryToMatch()
}
const pass = ({ patternIndex, index }) => {
return {
matched: true,
index,
patternIndex,
}
}
const fail = ({ patternIndex, index }) => {
return {
matched: false,
index,
patternIndex,
}
}

@@ -8,3 +8,2 @@ import { isPlainObject } from "./isPlainObject.js"

}
if (checkComposition) {

@@ -11,0 +10,0 @@ const plainObject = value

import { isPlainObject } from "./isPlainObject.js"
export const structuredMetaMapToMetaMap = (structuredMetaMap, ...rest) => {
export const structuredMetaMapToMetaMap = (structuredMetaMap) => {
if (!isPlainObject(structuredMetaMap)) {

@@ -9,10 +9,2 @@ throw new TypeError(

}
if (rest.length) {
throw new Error(`received more arguments than expected.
--- number of arguments received ---
${1 + rest.length}
--- number of arguments expected ---
1`)
}
const metaMap = {}

@@ -19,0 +11,0 @@ Object.keys(structuredMetaMap).forEach((metaProperty) => {

import { assertUrlLike } from "./internal/assertUrlLike.js"
export const normalizeStructuredMetaMap = (
structuredMetaMap,
baseUrl,
...rest
) => {
export const normalizeStructuredMetaMap = (structuredMetaMap, baseUrl) => {
assertUrlLike(baseUrl, "url")
if (rest.length) {
throw new Error(`received more arguments than expected.
--- number of arguments received ---
${2 + rest.length}
--- number of arguments expected ---
2`)
}
const structuredMetaMapNormalized = {}

@@ -18,0 +6,0 @@ Object.keys(structuredMetaMap).forEach((metaProperty) => {

@@ -9,3 +9,2 @@ import { assertUrlLike } from "./internal/assertUrlLike.js"

predicate,
...rest
}) => {

@@ -20,12 +19,3 @@ assertUrlLike(url, "url")

}
if (Object.keys(rest).length) {
throw new Error(`received more parameters than expected.
--- name of unexpected parameters ---
${Object.keys(rest)}
--- name of expected parameters ---
url, structuredMetaMap, predicate`)
}
const metaMap = structuredMetaMapToMetaMap(structuredMetaMap)
// for full match we must create an object to allow pattern to override previous ones

@@ -37,10 +27,9 @@ let fullMatchMeta = {}

const partialMatchMetaArray = []
Object.keys(metaMap).forEach((pattern) => {
const meta = metaMap[pattern]
const { matched, index } = applyPatternMatching({
const matchResult = applyPatternMatching({
pattern,
url,
})
if (matched) {
if (matchResult.matched) {
someFullMatch = true

@@ -51,11 +40,9 @@ fullMatchMeta = {

}
} else if (someFullMatch === false && index >= url.length) {
} else if (someFullMatch === false && matchResult.urlIndex >= url.length) {
partialMatchMetaArray.push(meta)
}
})
if (someFullMatch) {
return Boolean(predicate(fullMatchMeta))
}
return partialMatchMetaArray.some((partialMatchMeta) =>

@@ -62,0 +49,0 @@ predicate(partialMatchMeta),

@@ -5,12 +5,4 @@ import { assertUrlLike } from "./internal/assertUrlLike.js"

export const urlToMeta = ({ url, structuredMetaMap, ...rest } = {}) => {
export const urlToMeta = ({ url, structuredMetaMap }) => {
assertUrlLike(url)
if (Object.keys(rest).length) {
throw new Error(`received more parameters than expected.
--- name of unexpected parameters ---
${Object.keys(rest)}
--- name of expected parameters ---
url, structuredMetaMap`)
}
const metaMap = structuredMetaMapToMetaMap(structuredMetaMap)

@@ -17,0 +9,0 @@ return Object.keys(metaMap).reduce((previousMeta, pattern) => {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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