Socket
Socket
Sign inDemoInstall

fast-glob

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-glob - npm Package Compare versions

Comparing version 2.0.4 to 2.1.0

out/adapters/fs-stream.d.ts

20

out/index.js

@@ -11,12 +11,2 @@ "use strict";

/**
* Returns a set of works based on provided tasks and class of the reader.
*/
function getWorks(source, _Reader, opts) {
var patterns = [].concat(source);
var options = optionsManager.prepare(opts);
var tasks = taskManager.generate(patterns, options);
var reader = new _Reader(options);
return tasks.map(reader.read, reader);
}
/**
* Synchronous API.

@@ -45,1 +35,11 @@ */

exports.stream = stream;
/**
* Returns a set of works based on provided tasks and class of the reader.
*/
function getWorks(source, _Reader, opts) {
var patterns = [].concat(source);
var options = optionsManager.prepare(opts);
var tasks = taskManager.generate(patterns, options);
var reader = new _Reader(options);
return tasks.map(reader.read, reader);
}

@@ -56,2 +56,6 @@ import { EntryItem } from '../types/entries';

/**
* Enable expansion of brace patterns.
*/
brace: boolean;
/**
* Disable matching with globstars (`**`).

@@ -61,2 +65,6 @@ */

/**
* Enable matching with globstars (`**`).
*/
globstar: boolean;
/**
* Disable extglob support, so that extglobs are regarded as literal characters.

@@ -66,6 +74,14 @@ */

/**
* Use a case-insensitive regex for matching files.
* Enable extglob support, so that extglobs are regarded as literal characters.
*/
extension: boolean;
/**
* Disable a case-insensitive regex for matching files.
*/
nocase: boolean;
/**
* Enable a case-insensitive regex for matching files.
*/
case: boolean;
/**
* Allow glob patterns without slashes to match a file path based on its basename.

@@ -72,0 +88,0 @@ * For example, `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.

@@ -17,5 +17,9 @@ "use strict";

nobrace: false,
brace: true,
noglobstar: false,
globstar: true,
noext: false,
extension: true,
nocase: false,
case: true,
matchBase: false,

@@ -27,4 +31,14 @@ transform: null

}
opts.brace = !opts.nobrace;
opts.globstar = !opts.noglobstar;
opts.extension = !opts.noext;
opts.case = !opts.nocase;
if (options) {
opts.brace = ('brace' in options ? options.brace : opts.brace);
opts.globstar = ('globstar' in options ? options.globstar : opts.globstar);
opts.extension = ('extension' in options ? options.extension : opts.extension);
opts.case = ('case' in options ? options.case : opts.case);
}
return opts;
}
exports.prepare = prepare;

@@ -5,2 +5,3 @@ import { Pattern, PatternsGroup } from '../types/patterns';

base: string;
dynamic: boolean;
patterns: Pattern[];

@@ -10,30 +11,29 @@ positive: Pattern[];

}
export declare type TaskGroup = Record<string, ITask>;
/**
* Returns grouped patterns by base directory of each pattern.
* Generate tasks based on parent directory of each pattern.
*/
export declare function groupPatternsByParentDirectory(patterns: Pattern[]): PatternsGroup;
export declare function generate(patterns: Pattern[], options: IOptions): ITask[];
/**
* Convert positive patterns to tasks.
* Convert patterns to tasks based on parent directory of each pattern.
*/
export declare function makePositiveTaskGroup(positive: PatternsGroup): TaskGroup;
export declare function convertPatternsToTasks(positive: Pattern[], negative: Pattern[], dynamic: boolean): ITask[];
/**
* Convert negative patterns to tasks.
* Return only positive patterns.
*/
export declare function makeNegativeTaskGroup(negative: PatternsGroup): TaskGroup;
export declare function getPositivePatterns(patterns: Pattern[]): Pattern[];
/**
* Returns merged positive and negative task groups.
*
* Just two rules:
* - If a positive task group has a pair in the negative group, then merge it.
* - If a negative task group has a global base task, then merge them to full positive group.
* Retrun only negative patterns.
*/
export declare function mergeTaskGroups(positive: TaskGroup, negative: TaskGroup): TaskGroup;
export declare function getNegativePatternsAsPositive(patterns: Pattern[], ignore: Pattern[]): Pattern[];
/**
* Returns builded tasks for provided patterns groups.
* Group patterns by base directory of each pattern.
*/
export declare function makeTasks(positive: PatternsGroup, negative: PatternsGroup): ITask[];
export declare function groupPatternsByBaseDirectory(patterns: Pattern[]): PatternsGroup;
/**
* Generate tasks for provided patterns based on base directory of each pattern.
* Convert group of patterns to tasks.
*/
export declare function generate(patterns: Pattern[], options: IOptions): ITask[];
export declare function convertPatternGroupsToTasks(positive: PatternsGroup, negative: PatternsGroup, dynamic: boolean): ITask[];
/**
* Create a task for positive and negative patterns.
*/
export declare function convertPatternGroupToTask(base: string, positive: Pattern[], negative: Pattern[], dynamic: boolean): ITask;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var objectUtils = require("../utils/object");
var patternUtils = require("../utils/pattern");
/**
* Returns grouped patterns by base directory of each pattern.
* Generate tasks based on parent directory of each pattern.
*/
function groupPatternsByParentDirectory(patterns) {
return patterns.reduce(function (collection, pattern) {
var parent = patternUtils.getBaseDirectory(pattern);
if (!collection[parent]) {
collection[parent] = [];
}
collection[parent].push(pattern);
return collection;
}, {});
function generate(patterns, options) {
var unixPatterns = patterns.map(patternUtils.unixifyPattern);
var unixIgnore = options.ignore.map(patternUtils.unixifyPattern);
var positivePatterns = getPositivePatterns(unixPatterns);
var negativePatterns = getNegativePatternsAsPositive(unixPatterns, unixIgnore);
var staticPatterns = positivePatterns.filter(patternUtils.isStaticPattern);
var dynamicPatterns = positivePatterns.filter(patternUtils.isDynamicPattern);
var staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false);
var dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true);
return staticTasks.concat(dynamicTasks);
}
exports.groupPatternsByParentDirectory = groupPatternsByParentDirectory;
exports.generate = generate;
/**
* Convert positive patterns to tasks.
* Convert patterns to tasks based on parent directory of each pattern.
*/
function makePositiveTaskGroup(positive) {
return Object.keys(positive).reduce(function (collection, base) {
var positivePatterns = [].concat(positive[base]);
collection[base] = {
base: base,
patterns: positivePatterns,
positive: positivePatterns,
negative: []
};
return collection;
}, {});
function convertPatternsToTasks(positive, negative, dynamic) {
var positivePatternsGroup = groupPatternsByBaseDirectory(positive);
var negativePatternsGroup = groupPatternsByBaseDirectory(negative);
// When we have a global group – there is no reason to divide the patterns into independent tasks.
// In this case, the global task covers the rest.
if ('.' in positivePatternsGroup) {
var task = convertPatternGroupToTask('.', positive, negative, dynamic);
return [task];
}
return convertPatternGroupsToTasks(positivePatternsGroup, negativePatternsGroup, dynamic);
}
exports.makePositiveTaskGroup = makePositiveTaskGroup;
exports.convertPatternsToTasks = convertPatternsToTasks;
/**
* Convert negative patterns to tasks.
* Return only positive patterns.
*/
function makeNegativeTaskGroup(negative) {
return Object.keys(negative).reduce(function (collection, base) {
var negativePatterns = [].concat(negative[base]);
collection[base] = {
base: base,
patterns: negativePatterns.map(patternUtils.convertToNegativePattern),
positive: [],
negative: negativePatterns
};
return collection;
}, {});
function getPositivePatterns(patterns) {
return patternUtils.getPositivePatterns(patterns);
}
exports.makeNegativeTaskGroup = makeNegativeTaskGroup;
exports.getPositivePatterns = getPositivePatterns;
/**
* Returns merged positive and negative task groups.
*
* Just two rules:
* - If a positive task group has a pair in the negative group, then merge it.
* - If a negative task group has a global base task, then merge them to full positive group.
* Retrun only negative patterns.
*/
function mergeTaskGroups(positive, negative) {
var group = positive;
var globalNegativePatterns = '.' in negative ? negative['.'].negative : [];
Object.keys(group).forEach(function (base) {
if (base in negative) {
group[base].patterns = group[base].patterns.concat(negative[base].negative.map(patternUtils.convertToNegativePattern));
group[base].negative = group[base].negative.concat(negative[base].negative);
function getNegativePatternsAsPositive(patterns, ignore) {
var negative = patternUtils.getNegativePatterns(patterns);
var positive = negative.map(patternUtils.convertToPositivePattern).concat(ignore);
return positive.map(patternUtils.trimTrailingSlashGlobStar);
}
exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive;
/**
* Group patterns by base directory of each pattern.
*/
function groupPatternsByBaseDirectory(patterns) {
return patterns.reduce(function (collection, pattern) {
var base = patternUtils.getBaseDirectory(pattern);
if (base in collection) {
collection[base].push(pattern);
}
if (globalNegativePatterns.length !== 0) {
group[base].patterns = group[base].patterns.concat(globalNegativePatterns.map(patternUtils.convertToNegativePattern));
group[base].negative = group[base].negative.concat(globalNegativePatterns);
else {
collection[base] = [pattern];
}
});
return group;
return collection;
}, {});
}
exports.mergeTaskGroups = mergeTaskGroups;
exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory;
/**
* Returns builded tasks for provided patterns groups.
* Convert group of patterns to tasks.
*/
function makeTasks(positive, negative) {
var positiveTaskGroup = makePositiveTaskGroup(positive);
var negativeTaskGroup = makeNegativeTaskGroup(negative);
var groups = mergeTaskGroups(positiveTaskGroup, negativeTaskGroup);
return objectUtils.values(groups);
function convertPatternGroupsToTasks(positive, negative, dynamic) {
var globalNegative = '.' in negative ? negative['.'] : [];
return Object.keys(positive).map(function (base) {
var localNegative = base in negative ? negative[base] : [];
var fullNegative = localNegative.concat(globalNegative);
return convertPatternGroupToTask(base, positive[base], fullNegative, dynamic);
});
}
exports.makeTasks = makeTasks;
exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks;
/**
* Generate tasks for provided patterns based on base directory of each pattern.
* Create a task for positive and negative patterns.
*/
function generate(patterns, options) {
var unixPatterns = patterns.map(patternUtils.unixifyPattern);
var positive = patternUtils.getPositivePatterns(unixPatterns);
if (positive.length === 0) {
return [];
}
var ignore = options.ignore;
var negative = patternUtils.getNegativePatterns(unixPatterns)
.map(patternUtils.convertToPositivePattern)
.concat(ignore)
.map(patternUtils.trimTrailingSlashGlobStar);
var positiveGroup = groupPatternsByParentDirectory(positive);
var negativeGroup = groupPatternsByParentDirectory(negative);
// When we have a global group – there is no reason to divide the patterns into independent tasks because the first task covers the rest.
if ('.' in positiveGroup) {
var task = {
base: '.',
patterns: [].concat(positive, negative.map(patternUtils.convertToNegativePattern)),
positive: positive,
negative: negative
};
return [task];
}
return makeTasks(positiveGroup, negativeGroup);
function convertPatternGroupToTask(base, positive, negative, dynamic) {
return {
base: base,
dynamic: dynamic,
patterns: [].concat(positive, negative.map(patternUtils.convertToNegativePattern)),
positive: positive,
negative: negative
};
}
exports.generate = generate;
exports.convertPatternGroupToTask = convertPatternGroupToTask;

@@ -6,11 +6,19 @@ /// <reference types="node" />

import { EntryItem } from '../types/entries';
export default class ReaderAsync extends Reader {
export default class ReaderAsync extends Reader<Promise<EntryItem[]>> {
/**
* Use async API to read entries for Task.
*/
read(task: ITask): Promise<EntryItem[]>;
/**
* Returns founded paths.
*/
api(root: string, options: readdir.Options): NodeJS.ReadableStream;
api(root: string, task: ITask, options: readdir.Options): NodeJS.ReadableStream;
/**
* Use sync API to read entries for Task.
* Api for dynamic tasks.
*/
read(task: ITask): Promise<EntryItem[]>;
dynamicApi(root: string, options: readdir.Options): NodeJS.ReadableStream;
/**
* Api for static tasks.
*/
staticApi(task: ITask): NodeJS.ReadableStream;
}

@@ -15,2 +15,3 @@ "use strict";

var reader_1 = require("./reader");
var fs_stream_1 = require("../adapters/fs-stream");
var ReaderAsync = /** @class */ (function (_super) {

@@ -22,10 +23,4 @@ __extends(ReaderAsync, _super);

/**
* Returns founded paths.
* Use async API to read entries for Task.
*/
ReaderAsync.prototype.api = function (root, options) {
return readdir.readdirStreamStat(root, options);
};
/**
* Use sync API to read entries for Task.
*/
ReaderAsync.prototype.read = function (task) {

@@ -37,3 +32,3 @@ var _this = this;

return new Promise(function (resolve, reject) {
var stream = _this.api(root, options);
var stream = _this.api(root, task, options);
stream.on('error', function (err) {

@@ -47,4 +42,27 @@ _this.isEnoentCodeError(err) ? resolve([]) : reject(err);

};
/**
* Returns founded paths.
*/
ReaderAsync.prototype.api = function (root, task, options) {
if (task.dynamic) {
return this.dynamicApi(root, options);
}
return this.staticApi(task);
};
/**
* Api for dynamic tasks.
*/
ReaderAsync.prototype.dynamicApi = function (root, options) {
return readdir.readdirStreamStat(root, options);
};
/**
* Api for static tasks.
*/
ReaderAsync.prototype.staticApi = function (task) {
var fsAdapter = new fs_stream_1.default(this.options);
var filter = this.entryFilter.getFilter(['**'], task.negative);
return fsAdapter.read(task.patterns, filter);
};
return ReaderAsync;
}(reader_1.default));
exports.default = ReaderAsync;

@@ -5,11 +5,19 @@ /// <reference types="node" />

import { ITask } from '../managers/tasks';
export default class ReaderStream extends Reader {
export default class ReaderStream extends Reader<NodeJS.ReadableStream> {
/**
* Use stream API to read entries for Task.
*/
read(task: ITask): NodeJS.ReadableStream;
/**
* Returns founded paths.
*/
api(root: string, options: readdir.Options): NodeJS.ReadableStream;
api(root: string, task: ITask, options: readdir.Options): NodeJS.ReadableStream;
/**
* Use stream API to read entries for Task.
* Api for dynamic tasks.
*/
read(task: ITask): NodeJS.ReadableStream;
dynamicApi(root: string, options: readdir.Options): NodeJS.ReadableStream;
/**
* Api for static tasks.
*/
staticApi(task: ITask): NodeJS.ReadableStream;
}

@@ -16,2 +16,3 @@ "use strict";

var reader_1 = require("./reader");
var fs_stream_1 = require("../adapters/fs-stream");
var TransformStream = /** @class */ (function (_super) {

@@ -35,8 +36,2 @@ __extends(TransformStream, _super);

/**
* Returns founded paths.
*/
ReaderStream.prototype.api = function (root, options) {
return readdir.readdirStreamStat(root, options);
};
/**
* Use stream API to read entries for Task.

@@ -49,3 +44,3 @@ */

var transform = new TransformStream(this);
var readable = this.api(root, options);
var readable = this.api(root, task, options);
return readable

@@ -55,4 +50,27 @@ .once('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); })

};
/**
* Returns founded paths.
*/
ReaderStream.prototype.api = function (root, task, options) {
if (task.dynamic) {
return this.dynamicApi(root, options);
}
return this.staticApi(task);
};
/**
* Api for dynamic tasks.
*/
ReaderStream.prototype.dynamicApi = function (root, options) {
return readdir.readdirStreamStat(root, options);
};
/**
* Api for static tasks.
*/
ReaderStream.prototype.staticApi = function (task) {
var fsAdapter = new fs_stream_1.default(this.options);
var filter = this.entryFilter.getFilter(['**'], task.negative);
return fsAdapter.read(task.patterns, filter);
};
return ReaderStream;
}(reader_1.default));
exports.default = ReaderStream;

@@ -5,11 +5,19 @@ import * as readdir from '@mrmlnc/readdir-enhanced';

import { Entry, EntryItem } from '../types/entries';
export default class ReaderSync extends Reader {
export default class ReaderSync extends Reader<EntryItem[]> {
/**
* Use sync API to read entries for Task.
*/
read(task: ITask): EntryItem[];
/**
* Returns founded paths.
*/
api(root: string, options: readdir.Options): Entry[];
api(root: string, task: ITask, options: readdir.Options): Entry[];
/**
* Use sync API to read entries for Task.
* Api for dynamic tasks.
*/
read(task: ITask): EntryItem[];
dynamicApi(root: string, options: readdir.Options): Entry[];
/**
* Api for static tasks.
*/
staticApi(task: ITask): Entry[];
}

@@ -15,2 +15,3 @@ "use strict";

var reader_1 = require("./reader");
var fs_sync_1 = require("../adapters/fs-sync");
var ReaderSync = /** @class */ (function (_super) {

@@ -22,8 +23,2 @@ __extends(ReaderSync, _super);

/**
* Returns founded paths.
*/
ReaderSync.prototype.api = function (root, options) {
return readdir.readdirSyncStat(root, options);
};
/**
* Use sync API to read entries for Task.

@@ -35,3 +30,3 @@ */

try {
var entries = this.api(root, options);
var entries = this.api(root, task, options);
return entries.map(this.transform, this);

@@ -46,4 +41,27 @@ }

};
/**
* Returns founded paths.
*/
ReaderSync.prototype.api = function (root, task, options) {
if (task.dynamic) {
return this.dynamicApi(root, options);
}
return this.staticApi(task);
};
/**
* Api for dynamic tasks.
*/
ReaderSync.prototype.dynamicApi = function (root, options) {
return readdir.readdirSyncStat(root, options);
};
/**
* Api for static tasks.
*/
ReaderSync.prototype.staticApi = function (task) {
var fsAdapter = new fs_sync_1.default(this.options);
var filter = this.entryFilter.getFilter(['**'], task.negative);
return fsAdapter.read(task.patterns, filter);
};
return ReaderSync;
}(reader_1.default));
exports.default = ReaderSync;
/// <reference types="micromatch" />
/// <reference types="node" />
import micromatch = require('micromatch');
import DeepFilter from './filters/deep';
import EntryFilter from './filters/entry';
import { IOptions } from '../managers/options';

@@ -8,7 +10,7 @@ import { ITask } from '../managers/tasks';

import { Entry, EntryItem } from '../types/entries';
export default abstract class Reader {
export default abstract class Reader<T> {
readonly options: IOptions;
readonly entryFilter: EntryFilter;
readonly deepFilter: DeepFilter;
private readonly micromatchOptions;
private readonly entryFilter;
private readonly deepFilter;
constructor(options: IOptions);

@@ -18,3 +20,3 @@ /**

*/
abstract read(_task: ITask): any;
abstract read(_task: ITask): T;
/**

@@ -21,0 +23,0 @@ * Returns root path to scanner.

@@ -36,6 +36,6 @@ "use strict";

dot: this.options.dot,
nobrace: this.options.nobrace,
noglobstar: this.options.noglobstar,
noext: this.options.noext,
nocase: this.options.nocase,
nobrace: !this.options.brace,
noglobstar: !this.options.globstar,
noext: !this.options.extension,
nocase: !this.options.case,
matchBase: this.options.matchBase

@@ -42,0 +42,0 @@ };

@@ -5,1 +5,5 @@ /**

export declare function isDotDirectory(path: string): boolean;
/**
* Return naive depth of provided filepath.
*/
export declare function getDepth(filepath: string): number;

@@ -12,1 +12,8 @@ "use strict";

exports.isDotDirectory = isDotDirectory;
/**
* Return naive depth of provided filepath.
*/
function getDepth(filepath) {
return filepath.split('/').length;
}
exports.getDepth = getDepth;

@@ -5,2 +5,10 @@ /// <reference types="micromatch" />

/**
* Return true for static pattern.
*/
export declare function isStaticPattern(pattern: Pattern): boolean;
/**
* Return true for pattern that looks like glob.
*/
export declare function isDynamicPattern(pattern: Pattern): boolean;
/**
* Convert a windows «path» to a unix-style «path».

@@ -7,0 +15,0 @@ */

@@ -14,5 +14,20 @@ "use strict";

var globParent = require("glob-parent");
var isGlob = require("is-glob");
var micromatch = require("micromatch");
var GLOBSTAR = '**';
/**
* Return true for static pattern.
*/
function isStaticPattern(pattern) {
return !isDynamicPattern(pattern);
}
exports.isStaticPattern = isStaticPattern;
/**
* Return true for pattern that looks like glob.
*/
function isDynamicPattern(pattern) {
return isGlob(pattern);
}
exports.isDynamicPattern = isDynamicPattern;
/**
* Convert a windows «path» to a unix-style «path».

@@ -28,3 +43,3 @@ */

function convertToPositivePattern(pattern) {
return pattern.slice(1);
return isNegativePattern(pattern) ? pattern.slice(1) : pattern;
}

@@ -31,0 +46,0 @@ exports.convertToPositivePattern = convertToPositivePattern;

{
"name": "fast-glob",
"version": "2.0.4",
"version": "2.1.0",
"description": "Is a faster `node-glob` alternative",

@@ -30,2 +30,3 @@ "license": "MIT",

"@types/globby": "^6.1.0",
"@types/is-glob": "^4.0.0",
"@types/merge2": "^1.1.4",

@@ -52,5 +53,6 @@ "@types/micromatch": "^3.1.0",

"@mrmlnc/readdir-enhanced": "^2.2.1",
"glob-parent": "3.1.0",
"merge2": "1.2.1",
"micromatch": "3.1.5"
"glob-parent": "^3.1.0",
"is-glob": "^4.0.0",
"merge2": "^1.2.1",
"micromatch": "^3.1.8"
},

@@ -57,0 +59,0 @@ "scripts": {

@@ -81,3 +81,3 @@ # :rocket: fast-glob

See [options](https://github.com/mrmlnc/fast-glob#Options) section for more detailed information.
See [options](#options-1) section for more detailed information.

@@ -178,2 +178,9 @@ ### fg.sync(patterns, [options])

#### brace
* Type: `boolean`
* Default: `true`
The [`nobrace`](#nobrace) option without double-negation. This option has a higher priority then `nobrace`.
#### noglobstar

@@ -186,2 +193,9 @@

#### globstar
* Type: `boolean`
* Default: `true`
The [`noglobstar`](#noglobstar) option without double-negation. This option has a higher priority then `noglobstar`.
#### noext

@@ -194,2 +208,9 @@

#### extension
* Type: `boolean`
* Default: `true`
The [`noext`](#noext) option without double-negation. This option has a higher priority then `noext`.
#### nocase

@@ -200,4 +221,11 @@

Use a case-insensitive regex for matching files.
Disable a case-insensitive regex for matching files.
#### case
* Type: `boolean`
* Default: `true`
The [`nocase`](#nocase) option without double-negation. This option has a higher priority then `nocase`.
#### matchBase

@@ -275,6 +303,6 @@

| `nounique` | [`unique`](#unique) |
| `nobrace` | [`nobrace`](#nobrace) |
| `noglobstar` | [`noglobstar`](#noglobstar) |
| `noext` | [`noext`](#noext) |
| `nocase` | [`nocase`](#nocase) |
| `nobrace` | [`nobrace`](#nobrace) or [`brace`](#brace) |
| `noglobstar` | [`noglobstar`](#noglobstar) or [`globstar`](#globstar) |
| `noext` | [`noext`](#noext) or [`extension`](#extension) |
| `nocase` | [`nocase`](#nocase) or [`case`](#case) |
| `matchBase` | [`matchbase`](#matchbase) |

@@ -281,0 +309,0 @@ | `nodir` | [`onlyFiles`](#onlyfiles) |

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