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

@jsenv/util

Package Overview
Dependencies
Maintainers
2
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jsenv/util - npm Package Compare versions

Comparing version 3.1.0 to 3.2.0

src/collectFiles.js

897

dist/commonjs/main.js

@@ -11,2 +11,449 @@ 'use strict';

const assertUrlLike = (value, name = "url") => {
if (typeof value !== "string") {
throw new TypeError(`${name} must be a url string, got ${value}`);
}
if (isWindowsPathnameSpecifier(value)) {
throw new TypeError(`${name} must be a url but looks like a windows pathname, got ${value}`);
}
if (!hasScheme(value)) {
throw new TypeError(`${name} must be a url and no scheme found, got ${value}`);
}
};
const isWindowsPathnameSpecifier = specifier => {
const firstChar = specifier[0];
if (!/[a-zA-Z]/.test(firstChar)) return false;
const secondChar = specifier[1];
if (secondChar !== ":") return false;
const thirdChar = specifier[2];
return thirdChar === "/" || thirdChar === "\\";
};
const hasScheme = specifier => /^[a-zA-Z]+:/.test(specifier);
// https://git-scm.com/docs/gitignore
const applySpecifierPatternMatching = ({
specifier,
url,
...rest
} = {}) => {
assertUrlLike(specifier, "specifier");
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 ---
specifier, url`);
}
return applyPatternMatching(specifier, url);
};
const applyPatternMatching = (pattern, string) => {
let patternIndex = 0;
let index = 0;
let remainingPattern = pattern;
let remainingString = string; // eslint-disable-next-line no-constant-condition
while (true) {
// pattern consumed and string consumed
if (remainingPattern === "" && remainingString === "") {
// pass because string fully matched pattern
return pass({
patternIndex,
index
});
} // pattern consumed, string not consumed
if (remainingPattern === "" && remainingString !== "") {
// fails because string longer than expected
return fail({
patternIndex,
index
});
} // 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
});
} // fail because string shorted than expected
return fail({
patternIndex,
index
});
} // from this point pattern and string are not consumed
// fast path trailing slash
if (remainingPattern === "/") {
// pass because trailing slash matches remaining
return pass({
patternIndex: patternIndex + 1,
index: string.length
});
} // fast path trailing '**'
if (remainingPattern === "**") {
// pass because trailing ** matches remaining
return pass({
patternIndex: patternIndex + 2,
index: string.length
});
} // pattern leading **
if (remainingPattern.slice(0, 2) === "**") {
// consumes "**"
remainingPattern = remainingPattern.slice(2);
patternIndex += 2;
if (remainingPattern[0] === "/") {
// consumes "/"
remainingPattern = remainingPattern.slice(1);
patternIndex += 1;
} // pattern ending with ** always match remaining string
if (remainingPattern === "") {
return pass({
patternIndex,
index: string.length
});
}
const skipResult = skipUntilMatch({
pattern: remainingPattern,
string: remainingString
});
if (!skipResult.matched) {
return fail({
patternIndex: patternIndex + skipResult.patternIndex,
index: index + skipResult.index
});
}
return pass({
patternIndex: pattern.length,
index: string.length
});
}
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 !== '/'
if (remainingPattern === "") {
const slashIndex = remainingString.indexOf("/");
if (slashIndex > -1) {
return fail({
patternIndex,
index: index + slashIndex
});
}
return pass({
patternIndex,
index: string.length
});
} // the next char must not the one expected by remainingPattern[0]
// because * is greedy and expect to skip one char
if (remainingPattern[0] === remainingString[0]) {
return fail({
patternIndex: patternIndex - "*".length,
index
});
}
const skipResult = skipUntilMatch({
pattern: remainingPattern,
string: remainingString,
skippablePredicate: remainingString => remainingString[0] !== "/"
});
if (!skipResult.matched) {
return fail({
patternIndex: patternIndex + skipResult.patternIndex,
index: index + skipResult.index
});
}
return pass({
patternIndex: pattern.length,
index: string.length
});
}
if (remainingPattern[0] !== remainingString[0]) {
return fail({
patternIndex,
index
});
} // consumes next char
remainingPattern = remainingPattern.slice(1);
remainingString = remainingString.slice(1);
patternIndex += 1;
index += 1;
continue;
}
};
const skipUntilMatch = ({
pattern,
string,
skippablePredicate = () => true
}) => {
let index = 0;
let remainingString = string;
let bestMatch = null; // eslint-disable-next-line no-constant-condition
while (true) {
const matchAttempt = applyPatternMatching(pattern, remainingString);
if (matchAttempt.matched) {
bestMatch = matchAttempt;
break;
}
const skippable = skippablePredicate(remainingString);
bestMatch = fail({
patternIndex: bestMatch ? Math.max(bestMatch.patternIndex, matchAttempt.patternIndex) : matchAttempt.patternIndex,
index: index + matchAttempt.index
});
if (!skippable) {
break;
} // search against the next unattempted string
remainingString = remainingString.slice(matchAttempt.index + 1);
index += matchAttempt.index + 1;
if (remainingString === "") {
bestMatch = { ...bestMatch,
index: string.length
};
break;
}
continue;
}
return bestMatch;
};
const pass = ({
patternIndex,
index
}) => {
return {
matched: true,
index,
patternIndex
};
};
const fail = ({
patternIndex,
index
}) => {
return {
matched: false,
index,
patternIndex
};
};
const isPlainObject = value => {
if (value === null) {
return false;
}
if (typeof value === "object") {
if (Array.isArray(value)) {
return false;
}
return true;
}
return false;
};
const metaMapToSpecifierMetaMap = (metaMap, ...rest) => {
if (!isPlainObject(metaMap)) {
throw new TypeError(`metaMap must be a plain object, got ${metaMap}`);
}
if (rest.length) {
throw new Error(`received more arguments than expected.
--- number of arguments received ---
${1 + rest.length}
--- number of arguments expected ---
1`);
}
const specifierMetaMap = {};
Object.keys(metaMap).forEach(metaKey => {
const specifierValueMap = metaMap[metaKey];
if (!isPlainObject(specifierValueMap)) {
throw new TypeError(`metaMap value must be plain object, got ${specifierValueMap} for ${metaKey}`);
}
Object.keys(specifierValueMap).forEach(specifier => {
const metaValue = specifierValueMap[specifier];
const meta = {
[metaKey]: metaValue
};
specifierMetaMap[specifier] = specifier in specifierMetaMap ? { ...specifierMetaMap[specifier],
...meta
} : meta;
});
});
return specifierMetaMap;
};
const assertSpecifierMetaMap = value => {
if (!isPlainObject(value)) {
throw new TypeError(`specifierMetaMap must be a plain object, got ${value}`);
} // we could ensure it's key/value pair of url like key/object or null values
};
const normalizeSpecifierMetaMap = (specifierMetaMap, url, ...rest) => {
assertSpecifierMetaMap(specifierMetaMap);
assertUrlLike(url, "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 specifierMetaMapNormalized = {};
Object.keys(specifierMetaMap).forEach(specifier => {
const specifierResolved = String(new URL(specifier, url));
specifierMetaMapNormalized[specifierResolved] = specifierMetaMap[specifier];
});
return specifierMetaMapNormalized;
};
const urlCanContainsMetaMatching = ({
url,
specifierMetaMap,
predicate,
...rest
}) => {
assertUrlLike(url, "url"); // the function was meants to be used on url ending with '/'
if (!url.endsWith("/")) {
throw new Error(`url should end with /, got ${url}`);
}
assertSpecifierMetaMap(specifierMetaMap);
if (typeof predicate !== "function") {
throw new TypeError(`predicate must be a function, got ${predicate}`);
}
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, specifierMetaMap, predicate`);
} // for full match we must create an object to allow pattern to override previous ones
let fullMatchMeta = {};
let someFullMatch = false; // for partial match, any meta satisfying predicate will be valid because
// we don't know for sure if pattern will still match for a file inside pathname
const partialMatchMetaArray = [];
Object.keys(specifierMetaMap).forEach(specifier => {
const meta = specifierMetaMap[specifier];
const {
matched,
index
} = applySpecifierPatternMatching({
specifier,
url
});
if (matched) {
someFullMatch = true;
fullMatchMeta = { ...fullMatchMeta,
...meta
};
} else if (someFullMatch === false && index >= url.length) {
partialMatchMetaArray.push(meta);
}
});
if (someFullMatch) {
return Boolean(predicate(fullMatchMeta));
}
return partialMatchMetaArray.some(partialMatchMeta => predicate(partialMatchMeta));
};
const urlToMeta = ({
url,
specifierMetaMap,
...rest
} = {}) => {
assertUrlLike(url);
assertSpecifierMetaMap(specifierMetaMap);
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, specifierMetaMap`);
}
return Object.keys(specifierMetaMap).reduce((previousMeta, specifier) => {
const {
matched
} = applySpecifierPatternMatching({
specifier,
url
});
if (matched) {
return { ...previousMeta,
...specifierMetaMap[specifier]
};
}
return previousMeta;
}, {});
};
const ensureUrlTrailingSlash = url => {

@@ -400,40 +847,52 @@ return url.endsWith("/") ? url : `${url}/`;

const {
mkdir
} = fs.promises;
const writeDirectory = async (destination, {
recursive = true,
allowUseless = false
} = {}) => {
const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
const destinationPath = urlToFileSystemPath(destinationUrl);
const destinationStats = await readFileSystemNodeStat(destinationUrl, {
nullIfNotFound: true,
followLink: false
});
const createCancellationToken = () => {
const register = callback => {
if (typeof callback !== "function") {
throw new Error(`callback must be a function, got ${callback}`);
}
if (destinationStats) {
if (destinationStats.isDirectory()) {
if (allowUseless) {
return;
}
return {
callback,
unregister: () => {}
};
};
throw new Error(`directory already exists at ${destinationPath}`);
}
const throwIfRequested = () => undefined;
const destinationType = statsToType(destinationStats);
throw new Error(`cannot write directory at ${destinationPath} because there is a ${destinationType}`);
return {
register,
cancellationRequested: false,
throwIfRequested
};
};
const createOperation = ({
cancellationToken = createCancellationToken(),
start,
...rest
}) => {
const unknownArgumentNames = Object.keys(rest);
if (unknownArgumentNames.length) {
throw new Error(`createOperation called with unknown argument names.
--- unknown argument names ---
${unknownArgumentNames}
--- possible argument names ---
cancellationToken
start`);
}
try {
await mkdir(destinationPath, {
recursive
cancellationToken.throwIfRequested();
const promise = new Promise(resolve => {
resolve(start());
});
const cancelPromise = new Promise((resolve, reject) => {
const cancelRegistration = cancellationToken.register(cancelError => {
cancelRegistration.unregister();
reject(cancelError);
});
} catch (error) {
if (allowUseless && error.code === "EEXIST") {
return;
}
throw error;
}
promise.then(cancelRegistration.unregister, () => {});
});
const operationPromise = Promise.race([promise, cancelPromise]);
return operationPromise;
};

@@ -491,2 +950,268 @@

const getCommonPathname = (pathname, otherPathname) => {
const firstDifferentCharacterIndex = findFirstDifferentCharacterIndex(pathname, otherPathname); // pathname and otherpathname are exactly the same
if (firstDifferentCharacterIndex === -1) {
return pathname;
}
const commonString = pathname.slice(0, firstDifferentCharacterIndex + 1); // the first different char is at firstDifferentCharacterIndex
if (pathname.charAt(firstDifferentCharacterIndex) === "/") {
return commonString;
}
if (otherPathname.charAt(firstDifferentCharacterIndex) === "/") {
return commonString;
}
const firstDifferentSlashIndex = commonString.lastIndexOf("/");
return pathname.slice(0, firstDifferentSlashIndex + 1);
};
const findFirstDifferentCharacterIndex = (string, otherString) => {
const maxCommonLength = Math.min(string.length, otherString.length);
let i = 0;
while (i < maxCommonLength) {
const char = string.charAt(i);
const otherChar = otherString.charAt(i);
if (char !== otherChar) {
return i;
}
i++;
}
if (string.length === otherString.length) {
return -1;
} // they differ at maxCommonLength
return maxCommonLength;
};
const pathnameToDirectoryPathname = pathname => {
if (pathname.endsWith("/")) {
return pathname;
}
const slashLastIndex = pathname.lastIndexOf("/");
if (slashLastIndex === -1) {
return "";
}
return pathname.slice(0, slashLastIndex + 1);
};
const urlToRelativeUrl = (urlArg, baseUrlArg) => {
const url = new URL(urlArg);
const baseUrl = new URL(baseUrlArg);
if (url.protocol !== baseUrl.protocol) {
return urlArg;
}
if (url.username !== baseUrl.username || url.password !== baseUrl.password) {
return urlArg.slice(url.protocol.length);
}
if (url.host !== baseUrl.host) {
return urlArg.slice(url.protocol.length);
}
const {
pathname,
hash,
search
} = url;
if (pathname === "/") {
return baseUrl.pathname.slice(1);
}
const {
pathname: basePathname
} = baseUrl;
const commonPathname = getCommonPathname(pathname, basePathname);
if (!commonPathname) {
return urlArg;
}
const specificPathname = pathname.slice(commonPathname.length);
const baseSpecificPathname = basePathname.slice(commonPathname.length);
const baseSpecificDirectoryPathname = pathnameToDirectoryPathname(baseSpecificPathname);
const relativeDirectoriesNotation = baseSpecificDirectoryPathname.replace(/.*?\//g, "../");
const relativePathname = `${relativeDirectoriesNotation}${specificPathname}`;
return `${relativePathname}${search}${hash}`;
};
const comparePathnames = (leftPathame, rightPathname) => {
const leftPartArray = leftPathame.split("/");
const rightPartArray = rightPathname.split("/");
const leftLength = leftPartArray.length;
const rightLength = rightPartArray.length;
const maxLength = Math.max(leftLength, rightLength);
let i = 0;
while (i < maxLength) {
const leftPartExists = i in leftPartArray;
const rightPartExists = i in rightPartArray; // longer comes first
if (!leftPartExists) return +1;
if (!rightPartExists) return -1;
const leftPartIsLast = i === leftPartArray.length - 1;
const rightPartIsLast = i === rightPartArray.length - 1; // folder comes first
if (leftPartIsLast && !rightPartIsLast) return +1;
if (!leftPartIsLast && rightPartIsLast) return -1;
const leftPart = leftPartArray[i];
const rightPart = rightPartArray[i];
i++; // local comparison comes first
const comparison = leftPart.localeCompare(rightPart);
if (comparison !== 0) return comparison;
}
if (leftLength < rightLength) return +1;
if (leftLength > rightLength) return -1;
return 0;
};
const collectFiles = async ({
cancellationToken = createCancellationToken(),
directoryUrl,
specifierMetaMap,
predicate,
matchingFileOperation = () => null
}) => {
const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
if (typeof predicate !== "function") {
throw new TypeError(`predicate must be a function, got ${predicate}`);
}
if (typeof matchingFileOperation !== "function") {
throw new TypeError(`matchingFileOperation must be a function, got ${matchingFileOperation}`);
}
const specifierMetaMapNormalized = normalizeSpecifierMetaMap(specifierMetaMap, rootDirectoryUrl);
const matchingFileResultArray = [];
const visitDirectory = async directoryUrl => {
const directoryItems = await createOperation({
cancellationToken,
start: () => readDirectory(directoryUrl)
});
await Promise.all(directoryItems.map(async directoryItem => {
const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`;
const directoryChildNodeStats = await createOperation({
cancellationToken,
start: () => readFileSystemNodeStat(directoryChildNodeUrl, {
// we ignore symlink because recursively traversed
// so symlinked file will be discovered.
// Moreover if they lead outside of directoryPath it can become a problem
// like infinite recursion of whatever.
// that we could handle using an object of pathname already seen but it will be useless
// because directoryPath is recursively traversed
followLink: false
})
});
if (directoryChildNodeStats.isDirectory()) {
const subDirectoryUrl = `${directoryChildNodeUrl}/`;
if (!urlCanContainsMetaMatching({
url: subDirectoryUrl,
specifierMetaMap: specifierMetaMapNormalized,
predicate
})) {
return;
}
await visitDirectory(subDirectoryUrl);
return;
}
if (directoryChildNodeStats.isFile()) {
const meta = urlToMeta({
url: directoryChildNodeUrl,
specifierMetaMap: specifierMetaMapNormalized
});
if (!predicate(meta)) return;
const relativeUrl = urlToRelativeUrl(directoryChildNodeUrl, rootDirectoryUrl);
const operationResult = await createOperation({
cancellationToken,
start: () => matchingFileOperation({
cancellationToken,
relativeUrl,
meta,
fileStats: directoryChildNodeStats
})
});
matchingFileResultArray.push({
relativeUrl,
meta,
fileStats: directoryChildNodeStats,
operationResult
});
return;
}
}));
};
await visitDirectory(rootDirectoryUrl); // When we operate on thoose files later it feels more natural
// to perform operation in the same order they appear in the filesystem.
// It also allow to get a predictable return value.
// For that reason we sort matchingFileResultArray
matchingFileResultArray.sort((leftFile, rightFile) => {
return comparePathnames(leftFile.relativeUrl, rightFile.relativeUrl);
});
return matchingFileResultArray;
};
const {
mkdir
} = fs.promises;
const writeDirectory = async (destination, {
recursive = true,
allowUseless = false
} = {}) => {
const destinationUrl = assertAndNormalizeDirectoryUrl(destination);
const destinationPath = urlToFileSystemPath(destinationUrl);
const destinationStats = await readFileSystemNodeStat(destinationUrl, {
nullIfNotFound: true,
followLink: false
});
if (destinationStats) {
if (destinationStats.isDirectory()) {
if (allowUseless) {
return;
}
throw new Error(`directory already exists at ${destinationPath}`);
}
const destinationType = statsToType(destinationStats);
throw new Error(`cannot write directory at ${destinationPath} because there is a ${destinationType}`);
}
try {
await mkdir(destinationPath, {
recursive
});
} catch (error) {
if (allowUseless && error.code === "EEXIST") {
return;
}
throw error;
}
};
const resolveUrl = (specifier, baseUrl) => {

@@ -790,103 +1515,2 @@ if (typeof baseUrl === "undefined") {

const getCommonPathname = (pathname, otherPathname) => {
const firstDifferentCharacterIndex = findFirstDifferentCharacterIndex(pathname, otherPathname); // pathname and otherpathname are exactly the same
if (firstDifferentCharacterIndex === -1) {
return pathname;
}
const commonString = pathname.slice(0, firstDifferentCharacterIndex + 1); // the first different char is at firstDifferentCharacterIndex
if (pathname.charAt(firstDifferentCharacterIndex) === "/") {
return commonString;
}
if (otherPathname.charAt(firstDifferentCharacterIndex) === "/") {
return commonString;
}
const firstDifferentSlashIndex = commonString.lastIndexOf("/");
return pathname.slice(0, firstDifferentSlashIndex + 1);
};
const findFirstDifferentCharacterIndex = (string, otherString) => {
const maxCommonLength = Math.min(string.length, otherString.length);
let i = 0;
while (i < maxCommonLength) {
const char = string.charAt(i);
const otherChar = otherString.charAt(i);
if (char !== otherChar) {
return i;
}
i++;
}
if (string.length === otherString.length) {
return -1;
} // they differ at maxCommonLength
return maxCommonLength;
};
const pathnameToDirectoryPathname = pathname => {
if (pathname.endsWith("/")) {
return pathname;
}
const slashLastIndex = pathname.lastIndexOf("/");
if (slashLastIndex === -1) {
return "";
}
return pathname.slice(0, slashLastIndex + 1);
};
const urlToRelativeUrl = (urlArg, baseUrlArg) => {
const url = new URL(urlArg);
const baseUrl = new URL(baseUrlArg);
if (url.protocol !== baseUrl.protocol) {
return urlArg;
}
if (url.username !== baseUrl.username || url.password !== baseUrl.password) {
return urlArg.slice(url.protocol.length);
}
if (url.host !== baseUrl.host) {
return urlArg.slice(url.protocol.length);
}
const {
pathname,
hash,
search
} = url;
if (pathname === "/") {
return baseUrl.pathname.slice(1);
}
const {
pathname: basePathname
} = baseUrl;
const commonPathname = getCommonPathname(pathname, basePathname);
if (!commonPathname) {
return urlArg;
}
const specificPathname = pathname.slice(commonPathname.length);
const baseSpecificPathname = basePathname.slice(commonPathname.length);
const baseSpecificDirectoryPathname = pathnameToDirectoryPathname(baseSpecificPathname);
const relativeDirectoriesNotation = baseSpecificDirectoryPathname.replace(/.*?\//g, "../");
const relativePathname = `${relativeDirectoriesNotation}${specificPathname}`;
return `${relativePathname}${search}${hash}`;
};
const ensureParentDirectories = async destination => {

@@ -1390,2 +2014,3 @@ const destinationUrl = assertAndNormalizeFileUrl(destination);

exports.applySpecifierPatternMatching = applySpecifierPatternMatching;
exports.assertAndNormalizeDirectoryUrl = assertAndNormalizeDirectoryUrl;

@@ -1396,2 +2021,4 @@ exports.assertAndNormalizeFileUrl = assertAndNormalizeFileUrl;

exports.bufferToEtag = bufferToEtag;
exports.collectFiles = collectFiles;
exports.comparePathnames = comparePathnames;
exports.copyFileSystemNode = copyFileSystemNode;

@@ -1404,3 +2031,5 @@ exports.ensureEmptyDirectory = ensureEmptyDirectory;

exports.isFileSystemPath = isFileSystemPath;
exports.metaMapToSpecifierMetaMap = metaMapToSpecifierMetaMap;
exports.moveFileSystemNode = moveFileSystemNode;
exports.normalizeSpecifierMetaMap = normalizeSpecifierMetaMap;
exports.readDirectory = readDirectory;

@@ -1416,4 +2045,6 @@ exports.readFile = readFile;

exports.testFileSystemNodePermissions = testFileSystemNodePermissions;
exports.urlCanContainsMetaMatching = urlCanContainsMetaMatching;
exports.urlIsInsideOf = urlIsInsideOf;
exports.urlToFileSystemPath = urlToFileSystemPath;
exports.urlToMeta = urlToMeta;
exports.urlToRelativeUrl = urlToRelativeUrl;

@@ -1420,0 +2051,0 @@ exports.writeDirectory = writeDirectory;

@@ -0,1 +1,12 @@

// we won't internalize @jsenv/url-meta
// so that @jsenv/url-meta does not becomes nodejs specific
// but there functions could be inside this repository
export {
applySpecifierPatternMatching,
metaMapToSpecifierMetaMap,
normalizeSpecifierMetaMap,
urlCanContainsMetaMatching,
urlToMeta,
} from "@jsenv/url-meta"
export { assertAndNormalizeDirectoryUrl } from "./src/assertAndNormalizeDirectoryUrl.js"

@@ -6,2 +17,4 @@ export { assertAndNormalizeFileUrl } from "./src/assertAndNormalizeFileUrl.js"

export { bufferToEtag } from "./src/bufferToEtag.js"
export { collectFiles } from "./src/collectFiles.js"
export { comparePathnames } from "./src/comparePathnames.js"
export { ensureEmptyDirectory } from "./src/ensureEmptyDirectory.js"

@@ -8,0 +21,0 @@ export { ensureWindowsDriveLetter } from "./src/ensureWindowsDriveLetter.js"

8

package.json
{
"name": "@jsenv/util",
"version": "3.1.0",
"version": "3.2.0",
"description": "Set of functions often needed when using Node.js.",

@@ -45,3 +45,6 @@ "license": "MIT",

},
"dependencies": {},
"dependencies": {
"@jsenv/cancellation": "1.3.0",
"@jsenv/url-meta": "5.1.0"
},
"devDependencies": {

@@ -52,2 +55,3 @@ "@jsenv/assert": "1.2.1",

"@jsenv/eslint-config": "12.1.0",
"@jsenv/git-hooks": "1.2.0",
"@jsenv/github-release-package": "1.1.1",

@@ -54,0 +58,0 @@ "@jsenv/node-module-import-map": "10.0.1",

@@ -22,2 +22,4 @@ # util

- [bufferToEtag](#bufferToEtag)
- [collectFiles](#collectFiles)
- [comparePathnames](#comparePathnames)
- [copyFileSystemNode](#copyFileSystemNode)

@@ -163,2 +165,37 @@ - [ensureEmptyDirectory](#ensureEmptyDirectory)

### collectFiles
`collectFiles` is an async function collectings a subset of files inside a directory.
```js
import { collectFiles } from "@jsenv/util"
const files = await collectFiles({
directoryUrl: "file:///Users/you/directory",
specifierMetaMap: {
"./**/*.js": {
whatever: 42,
},
},
predicate: (meta) => {
return meta.whatever === 42
},
})
```
— source code at [src/collectFiles.js](./src/collectFiles.js).
### comparePathnames
`comparePathnames` is a function compare two pathnames and returning which pathnames comes first in a filesystem.
```js
import { comparePathnames } from "@jsenv/util"
const pathnames = ["a/b.js", "a.js"]
pathnames.sort(comparePathnames)
```
— source code at [src/comparePathnames.js](./src/comparePathnames.js).
### copyFileSystemNode

@@ -165,0 +202,0 @@

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