Socket
Socket
Sign inDemoInstall

commonjs-walker

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

commonjs-walker - npm Package Compare versions

Comparing version 5.0.3 to 6.0.0

test/fixtures/walker/require-async/a

182

index.js

@@ -40,8 +40,10 @@ 'use strict';

makeDefault(options, 'allowCyclic', true);
makeDefault(options, 'strictRequire', true);
makeDefault(options, 'allowAbsolutePath', true);
makeDefault(options, 'allow_cyclic', true);
makeDefault(options, 'allow_non_literal_require', true);
makeDefault(options, 'comment_require', true);
makeDefault(options, 'require_resolve', true);
makeDefault(options, 'require_async', true);
makeDefault(options, 'extensions', EXTS_NODE);
if (!this._checkExts()) {
if (!this._check_extensions()) {
throw new Error('Invalid value of `options.extensions`');

@@ -51,2 +53,3 @@ }

this.callback = callback;
this._walk();
}

@@ -57,3 +60,3 @@

// Checks if the `options.extensions` is valid
Walker.prototype._checkExts = function() {
Walker.prototype._check_extensions = function() {
var exts = this.options.extensions;

@@ -71,3 +74,3 @@

Walker.prototype.walk = function() {
Walker.prototype._walk = function() {
var self = this;

@@ -94,4 +97,4 @@ var entry = this.entry;

var path = task.path;
// Each node must be created before `._parseFileDependencies()`
self._parseFileDependencies(path, function (err) {
// Each node must be created before `._parse_file_dependencies()`
self._parse_file_dependencies(path, function (err) {
if (err) {

@@ -106,3 +109,3 @@ return cb(err);

// `node` should be created before the task is running.
this._createNode(entry);
this._create_node(entry);
q.drain = cb;

@@ -117,20 +120,18 @@ // Adds initial task

// Actually, we do nothing
Walker.prototype._parseNodeFile = function(path, callback) {
this._parseJsonFile(path, callback);
};
// @param {Path} path Absolute path
Walker.prototype._parseJsonFile = function(path, callback) {
Walker.prototype._parse_file_dependencies = function(path, callback) {
var node = this._get_node(path);
var options = this.options;
var self = this;
parser.read(path, function (err, content) {
parser.parse(path, this.options, function (err, data) {
if (err) {
return callback(err);
}
node.require = {};
node.resolve = {};
node.async = {};
var node = self._getNode(path);
node.code = content;
node.dependencies = {};
callback(null);
async.each(['require', 'resolve', 'async'], function (type, done) {
self._parse_dependencies_by_type(path, data[type], type, done);
}, callback);
});

@@ -140,71 +141,54 @@ };

Walker.prototype._parseFileDependencies = function(path, callback) {
var node = this._getNode(path);
Walker.prototype._parse_dependencies_by_type = function(path, paths, type, callback) {
var self = this;
var options = this.options;
var self = this;
parser.parse(path, {
strictRequire: this.options.strictRequire
var node = this._get_node(path);
async.each(paths, function (dep, done) {
var origin = dep;
// @param {Object} data
// - code
// - path
// - dependencies
}, function (err, data) {
if (err) {
return callback(err);
if (dep.indexOf('/') === 0) {
var message = {
code: 'NOT_ALLOW_ABSOLUTE_PATH',
message: 'Requiring an absolute path "' + dep + '" is not allowed in "' + path + '"',
data: {
dependency: dep,
path: path
}
};
if (!options.allow_absolute_path) {
return done();
} else {
self.emit('warn', message);
}
}
node.code = data.code;
node.dependencies = {};
var dependencies = data.dependencies;
async.each(dependencies, function (dep, done) {
var origin = dep;
if (!self._is_relative_path(dep)) {
// we only map top level id for now
dep = self._solve_aliased_dependency(options['as'][dep], path) || dep;
}
if (dep.indexOf('/') === 0) {
var message = {
code: 'NOT_ALLOW_ABSOLUTE_PATH',
message: 'Requiring an absolute path "' + dep + '" is not allowed in "' + path + '"',
// package name, not a path
if (!self._is_relative_path(dep)) {
return self._deal_dependency(origin, dep, node, type, done);
}
resolve(dep, {
basedir: node_path.dirname(path),
extensions: options.extensions
}, function (err, real) {
if (err) {
return done({
code: 'MODULE_NOT_FOUND',
message: err.message,
stack: err.stack,
data: {
dependency: dep,
path: path
path: dep
}
};
if (!options.allowAbsolutePath) {
return done();
} else {
self.emit('warn', message);
}
});
}
if (!self._isRelativePath(dep)) {
// we only map top level id for now
dep = self._solveAliasedDependency(options['as'][dep], path) || dep;
}
// package name, not a path
if (!self._isRelativePath(dep)) {
return self._dealDependency(origin, dep, node, done);
}
resolve(dep, {
basedir: node_path.dirname(path),
extensions: options.extensions
}, function (err, real) {
if (err) {
return done({
code: 'MODULE_NOT_FOUND',
message: err.message,
stack: err.stack,
data: {
path: dep
}
});
}
self._dealDependency(origin, real, node, done);
});
}, callback);
});
self._deal_dependency(origin, real, node, type, done);
});
}, callback);
};

@@ -222,6 +206,6 @@

// @param {String} env_path the path of the current file
Walker.prototype._solveAliasedDependency = function(dep, env_path) {
Walker.prototype._solve_aliased_dependency = function(dep, env_path) {
var cwd = this.options.cwd;
if (!dep || !cwd || !this._isRelativePath(dep)) {
if (!dep || !cwd || !this._is_relative_path(dep)) {
return dep;

@@ -245,7 +229,7 @@ }

Walker.prototype._dealDependency = function(dep, real, node, callback) {
node.dependencies[dep] = real;
var sub_node = this._getNode(real);
Walker.prototype._deal_dependency = function(dep, real, node, type, callback) {
node[type][dep] = real;
var sub_node = this._get_node(real);
if (!sub_node) {
sub_node = this._createNode(real);
sub_node = this._create_node(real);
if (!sub_node.foreign) {

@@ -269,3 +253,3 @@ // only if the node is newly created.

code: 'CYCLIC_DEPENDENCY',
message: 'Cyclic dependency found: \n' + this._printCyclic(circular_trace),
message: 'Cyclic dependency found: \n' + this._print_cyclic(circular_trace),
data: {

@@ -277,3 +261,3 @@ trace: circular_trace,

if (!this.options.allowCyclic) {
if (!this.options.allow_cyclic) {
return callback(message);

@@ -293,3 +277,3 @@ } else {

// - package name for foreign module
Walker.prototype._createNode = function(id) {
Walker.prototype._create_node = function(id) {
var node = this.nodes[id];

@@ -300,5 +284,4 @@

id: id,
dependents: [],
entry: id === this.entry,
foreign: this._isForeign(id)
foreign: this._is_foreign(id)
};

@@ -310,8 +293,8 @@ }

Walker.prototype._isForeign = function(path) {
return !this._isAbsolutePath(path);
Walker.prototype._is_foreign = function(path) {
return !this._is_absolute_path(path);
};
Walker.prototype._isAbsolutePath = function(path) {
Walker.prototype._is_absolute_path = function(path) {
return node_path.resolve(path) === path.replace(/[\/\\]+$/, '');

@@ -321,3 +304,3 @@ };

Walker.prototype._isRelativePath = function(path) {
Walker.prototype._is_relative_path = function(path) {
// Actually, this method is called after the parser.js,

@@ -331,3 +314,3 @@ // and all paths are parsed from require(foo),

Walker.prototype._getNode = function(path) {
Walker.prototype._get_node = function(path) {
return this.nodes[path];

@@ -340,3 +323,3 @@ };

//
Walker.prototype._printCyclic = function(trace) {
Walker.prototype._print_cyclic = function(trace) {
var list = trace.map(function (node, index) {

@@ -356,2 +339,1 @@ return index + 1 + ': ' + node.id;

};

@@ -37,3 +37,3 @@ 'use strict';

var dependencies = from.dependencies;
var dependencies = from.require;
var deps_array = dependencies

@@ -40,0 +40,0 @@ ? Object.keys(dependencies)

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

parser.parse = function (path, options, callback) {
if (!parser._guess_is_js(path)) {
return callback(null, {
path: path,
require: [],
resolve: [],
async: []
});
}
parser.read(path, function (err, content) {

@@ -18,11 +27,3 @@ if (err) {

if (parser._isJson(path)) {
return callback(null, {
code: content,
path: path,
dependencies: []
});
}
parser._lexJs(content.toString(), function (err, ast) {
parser._lex_js(content.toString(), function (err, ast) {
if (err) {

@@ -39,5 +40,9 @@ return callback({

var dependencies = [];
var dependencies = {
normal: [],
resolve: [],
async: []
};
try {
parser._parseDependencies(ast, dependencies, options);
parser._parse_dependencies(ast, dependencies, options);
} catch(e) {

@@ -54,14 +59,12 @@ return callback({

// Removes duplicate items
dependencies = dependencies.reduce(function (prev, current) {
if (!~prev.indexOf(current)) {
prev.push(current);
}
return prev;
}, []);
if (options.comment_require) {
parser._parse_comments(ast, dependencies, options);
}
callback(null, {
code: content,
// code: content,
path: path,
dependencies: dependencies
require: parser._make_unique(dependencies.normal),
resolve: parser._make_unique(dependencies.resolve),
async: parser._make_unique(dependencies.async)
});

@@ -73,5 +76,21 @@ });

parser._make_unique = function (array) {
return array.reduce(function (prev, current) {
if (!~prev.indexOf(current)) {
prev.push(current);
}
return prev;
}, []);
};
var REGEX_EXT = /\.([a-z0-9]+)$/i;
// @returns {Boolean}
parser._isJson = function (path) {
return /\.json$/i.test(path);
parser._guess_is_js = function (path) {
var match = path.match(REGEX_EXT);
return match
? match[1] === 'js'
// if there is no extension
: true;
};

@@ -99,7 +118,8 @@

// Parses the content of a javascript to AST
parser._lexJs = function (content, callback) {
parser._lex_js = function (content, callback) {
var ast;
try {
ast = esprima.parse(content, {
loc: true
loc: true,
comment: true
});

@@ -115,5 +135,3 @@ } catch(e) {

// Parses AST and returns the dependencies
parser._parseDependencies = function (node, host, options) {
host || (host = []);
parser._parse_dependencies = function (node, dependencies, options) {
// Only arrays or objects has child node, or is a sub AST.

@@ -124,42 +142,107 @@ if (!node || Object(node) !== node) {

if (
node.type === 'CallExpression'
&& node.callee.type === 'Identifier'
&& node.callee.name === 'require'
) {
var args = node.arguments;
var loc = node.callee.loc.start;
var loc_text = locText(loc);
parser._check_dependency_node(node, function (node) {
return node.type === 'CallExpression'
&& node.callee.type === 'Identifier'
&& node.callee.name === 'require';
}, dependencies.normal, options, true)
var strict = options.strictRequire;
|| options.require_resolve && parser._check_dependency_node(node, function (node) {
return node.type === 'CallExpression'
&& node.callee.type === 'MemberExpression'
&& node.callee.object.name === 'require'
&& node.callee.property.name === 'resolve';
}, dependencies.resolve, options, true)
if (args.length === 0) {
parser._throw(strict, loc_text + 'Method `require` accepts one and only one parameter.');
return;
}
|| options.require_async && parser._check_dependency_node(node, function (node) {
return node.type === 'CallExpression'
&& node.callee.type === 'MemberExpression'
&& node.callee.object.name === 'require'
&& node.callee.property.name === 'async';
}, dependencies.async, options, false);
if (args.length > 1) {
parser._throw(strict, loc_text + 'Method `require` should not contains more than one parameters');
if (util.isArray(node)) {
node.forEach(function (sub) {
parser._parse_dependencies(sub, dependencies, options);
});
} else {
var key;
for (key in node) {
parser._parse_dependencies(node[key], dependencies, options);
}
}
};
var arg1 = args[0];
if (arg1.type !== 'Literal') {
parser._throw(strict, locText(arg1.loc.start) + 'Method `require` only accepts a string literal.' );
return;
}
parser._check_dependency_node = function (node, condition, deps_array, options, check_if_length_exceeded) {
if (!condition(node)) {
return;
}
host.push(arg1.value);
var args = node.arguments;
var loc = node.callee.loc.start;
var loc_text = generate_loc_text(loc);
var check_length = options.check_require_length;
if (args.length === 0) {
parser._throw(check_length, loc_text + 'Method `require` accepts one and only one parameter.');
}
if (util.isArray(node)) {
node.forEach(function (sub) {
parser._parseDependencies(sub, host, options);
});
if (check_if_length_exceeded && args.length > 1) {
parser._throw(check_length, loc_text + 'Method `require` should not contains more than one parameters');
}
var arg1 = args[0];
if (!arg1) {
return;
}
if (arg1.type !== 'Literal') {
parser._throw(!options.allow_non_literal_require, generate_loc_text(arg1.loc.start) + 'Method `require` only accepts a string literal.' );
} else {
var key;
for (key in node) {
parser._parseDependencies(node[key], host, options);
deps_array.push(arg1.value);
}
};
var REGEX_LEFT_PARENTHESIS_STRING = '\\s*\\(\\s*([\'"])([A-Za-z0-9_\\/\\-\\.]+)\\1\\s*';
var REGEX_PARENTHESIS_STRING = REGEX_LEFT_PARENTHESIS_STRING + '\\)';
var REGEX_REQUIRE =
new RegExp('@require' + REGEX_PARENTHESIS_STRING, 'g');
var REGEX_REQUIRE_RESOLVE =
new RegExp('@require\\.resolve' + REGEX_PARENTHESIS_STRING, 'g');
var REGEX_REQUIRE_ASYNC =
new RegExp('@require\\.async' + REGEX_LEFT_PARENTHESIS_STRING, 'g');
// Parses `@require`, `@require.resolve`, `@require.async` in comments
parser._parse_comments = function (ast, dependencies, options) {
var comments = ast.comments;
if (!comments) {
return;
}
comments.forEach(function (comment) {
parser._parse_by_regex(comment.value, REGEX_REQUIRE, dependencies.normal);
if (options.require_resolve) {
parser._parse_by_regex(comment.value, REGEX_REQUIRE_RESOLVE, dependencies.resolve);
}
if (options.require_async) {
parser._parse_by_regex(comment.value, REGEX_REQUIRE_ASYNC, dependencies.async);
}
});
};
// @param {string} content
// @param {RegExp} regex
// @param {*Array} matches
parser._parse_by_regex = function (content, regex, matches) {
var match;
while(match = regex.exec(content)){
matches.push(match[2]);
}

@@ -169,3 +252,3 @@ };

function locText (loc) {
function generate_loc_text (loc) {
return 'Line ' + loc.line + ': Column ' + loc.column + ': ';

@@ -180,2 +263,1 @@ }

};
{
"name": "commonjs-walker",
"version": "5.0.3",
"version": "6.0.0",
"description": "Analyzer and tree walker for commonjs.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -39,2 +39,3 @@ [![NPM version](https://badge.fury.io/js/commonjs-walker.png)](http://badge.fury.io/js/commonjs-walker)

|-- index.js
|-- a.png
|-- a

@@ -49,2 +50,3 @@ |-- index.json

require('b');
var image = require.resolve('./a.png')
```

@@ -72,11 +74,15 @@

entry: true,
dependencies: {
require: {
'./a': '/path/to/a/index.json',
'b': 'b'
},
code: <Buffer>
resolve: {
'./a.png': '/path/to/a.png'
}
},
'/path/to/a.png': {
require: {}
}
'/path/to/a/index.json': {
dependencies: {},
code: <Buffer>
require: {}
},

@@ -95,7 +101,11 @@ 'b': {

------ | ---- | ------- | ------------
allowCyclic | `Boolean` | true | whether should check cyclic dependencies
strictRequire | `Boolean` | true | whether should check the usage of method `require()`. If true, the argument of `require()` must be an literal string.
allowAbsolutePath | `Boolean` | true | whether should allow to require an absolute path.
allow_cyclic | `Boolean` | true | whether should check cyclic dependencies
check_require_length | `Boolean` | false | whether should check the `arguments.length` of method `require()`
allow_non_literal_require | `Boolean` | true | whether should check the usage of method `require()`. If false, the argument of `require()` must be an literal string.
comment_require | `Boolean` | true | whether should parse `@require()`, `@require.resolve` and `@require.async` in comments.
require_resolve | `Boolean` | true | whether should analysis the usage of `require.resolve()`.
require_async | `Boolean` | true | whether should record the usage of `require.async()`.
allow_absolute_path | `Boolean` | true | whether should allow to require an absolute path.
extensions | `Array` | `['.js', '.json', '.node']` | see `options.extensions` section
as | `Object` | `{}` | An object map that define the alias of the parameter of `require`
as | `Object` | `{}` | An object map that define the alias of the parameter of `require`

@@ -122,5 +132,5 @@ <!-- parseForeignModule | `Boolean` | true | will try to resolve foreign modules by `require.resolve()`. Set this option to false to handle foreign modules yourself. -->

{
allowCyclic: false,
strictRequire: true,
allowAbsolutePath: false,
allow_cyclic: false,
strict_require: true,
allow_absolute_path: false,
extensions: ['.js', '.json']

@@ -140,12 +150,7 @@ }

foreign | `Boolean` | whether the current module is from a foreign package.
require | `Object` |
resolve | `Object` |
async | `Object` |
<!-- dependents | `Array.<String>` | the dependent modules. If there's no dependents, it will be `[]` -->
#### If `foreign` is `false`
Property | Type | Description
-------- | ---- | -----------
code | `Buffer` | the file content of the current module.
dependencies | `Object.<id: path>` | `id` is the argument of `require(id)`. `path` is the resolved absolute path by `id`. If the module has no dependencies, it will be `{}`
## Class: walker.Error

@@ -152,0 +157,0 @@

@@ -33,3 +33,3 @@ 'use strict';

var b = {
dependencies: {
require: {
'./c': '/c'

@@ -42,3 +42,3 @@ }

'/c': {
dependencies: {}
require: {}
}

@@ -57,3 +57,3 @@ };

name: 'b',
dependencies: {
require: {
'./c': '/c',

@@ -65,3 +65,3 @@ './e': '/e'

name: 'c',
dependencies: {
require: {
'./d': '/d',

@@ -68,0 +68,0 @@ './a': '/a'

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

expect(err).to.equal(null);
expect(entry.code.toString()).to.equal("require('abc');");
expect(nodes['abc'].foreign).to.equal(true);

@@ -26,3 +25,3 @@ }

expect(err).to.equal(null);
var dep = entry.dependencies['./a'];
var dep = entry.require['./a'];
expect(dep).to.equal( node_path.join(root, 'one-dep', 'a.js') );

@@ -35,3 +34,3 @@ }

options: {
allowCyclic: false
allow_cyclic: false
},

@@ -46,3 +45,3 @@ expect: function (err, path, nodes, entry) {

options: {
allowCyclic: true
allow_cyclic: true
},

@@ -94,2 +93,5 @@ file: 'circular/index.js',

file: 'error-require/a.js',
options: {
check_require_length: true
},
expect: function (err, path, nodes, entry) {

@@ -107,3 +109,3 @@ expect(err).to.not.equal(null);

var real = node_path.join( node_path.dirname(path), dep );
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -125,3 +127,3 @@ },

var real = node_path.join( node_path.dirname(path), dep ) + '.js';
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -136,3 +138,3 @@ },

var real = node_path.join( node_path.dirname(path), dep );
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -147,3 +149,3 @@ },

var real = node_path.join( node_path.dirname(path), dep ) + '.json';
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -160,3 +162,3 @@ },

var real = node_path.join( node_path.dirname(path), dep ) + '.node';
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -184,3 +186,3 @@ },

var real = node_path.join( node_path.dirname(path), dep ) + node_path.sep + 'index.js';
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -197,3 +199,3 @@ },

var real = node_path.join( node_path.dirname(path), dep ) + 'index.js';
expect(entry.dependencies[dep]).to.equal(real);
expect(entry.require[dep]).to.equal(real);
}

@@ -228,4 +230,4 @@ },

var a = node_path.join( node_path.dirname(path), 'a.js' );
expect('a' in entry.dependencies).to.equal(true);
expect(entry.dependencies['a']).to.equal(a);
expect('a' in entry.require).to.equal(true);
expect(entry.require['a']).to.equal(a);
}

@@ -243,3 +245,3 @@ },

expect(err).to.equal(null);
expect(entry.dependencies['a']).to.equal('b');
expect(entry.require['a']).to.equal('b');
}

@@ -258,4 +260,60 @@ },

expect(err).to.equal(null);
expect(entry.dependencies['abc']).to.equal(node_path.join(node_path.dirname(path), './dep.js'));
expect(entry.require['abc']).to.equal(node_path.join(node_path.dirname(path), './dep.js'));
}
},
{
desc: '#21: require.resolve',
options: {
},
file: 'require-resolve/entry.js',
expect: function (err, path, nodes, entry) {
expect(entry.resolve['./a']).to.equal(node_path.join(node_path.dirname(path), './a'));
expect(entry.resolve['./b']).to.equal(node_path.join(node_path.dirname(path), './b.js'));
expect(entry.require['./c']).to.equal(node_path.join(node_path.dirname(path), './c.js'));
}
},
{
desc: '#21: require.resolve: false',
options: {
require_resolve: false
},
file: 'require-resolve/entry.js',
expect: function (err, path, nodes, entry) {
expect('./a' in entry.resolve).to.equal(false);
expect('./b' in entry.resolve).to.equal(false);
expect(entry.require['./c']).to.equal(node_path.join(node_path.dirname(path), './c.js'));
}
},
{
desc: '#21: require.async',
options: {
},
file: 'require-async/entry.js',
expect: function (err, path, nodes, entry) {
expect(entry.async['./a']).to.equal(node_path.join(node_path.dirname(path), './a'));
expect(entry.async['./b']).to.equal(node_path.join(node_path.dirname(path), './b.js'));
expect(entry.require['./c']).to.equal(node_path.join(node_path.dirname(path), './c.js'));
}
},
{
desc: '#21: require.async: false',
options: {
require_async: false
},
file: 'require-async/entry.js',
expect: function (err, path, nodes, entry) {
expect('./a' in entry.async).to.equal(false);
expect('./b' in entry.async).to.equal(false);
expect(entry.require['./c']).to.equal(node_path.join(node_path.dirname(path), './c.js'));
}
}, {
desc: '#21: require in comments',
options: {
},
file: 'require-async/entry-comment.js',
expect: function (err, path, nodes, entry) {
expect(entry.require['./a']).to.equal(node_path.join(node_path.dirname(path), './a'));
expect(entry.resolve['./b']).to.equal(node_path.join(node_path.dirname(path), './b.js'));
expect(entry.async['./c.js']).to.equal(node_path.join(node_path.dirname(path), './c.js'));
}
}

@@ -296,5 +354,5 @@ ];

if (noOptions) {
walker(file, callback).walk();
walker(file, callback);
} else {
walker(file, options, callback).walk();
walker(file, options, callback);
}

@@ -301,0 +359,0 @@ });

@@ -13,3 +13,3 @@ 'use strict';

options: {
strictRequire: true
check_require_length: true
},

@@ -22,3 +22,3 @@ deps: ['../abc', 'abc', './abc']

options: {
strictRequire: true
check_require_length: true
},

@@ -31,6 +31,4 @@ error: true

options: {
strictRequire: false
},
deps: ['abc']
},

@@ -41,3 +39,3 @@ {

options: {
strictRequire: true
check_require_length: true
},

@@ -51,3 +49,2 @@ error: true

options: {
strictRequire: false
},

@@ -71,3 +68,3 @@ deps: ['../abc', './abc']

if (util.isArray(c.deps)) {
expect(result.dependencies.sort()).to.deep.equal(c.deps.sort());
expect(result.require.sort()).to.deep.equal(c.deps.sort());
}

@@ -74,0 +71,0 @@ });

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