diff --git a/README.md b/README.md
index 8f992b0..012546d 100644
--- a/README.md
+++ b/README.md
@@ -7,10 +7,8 @@
888 888 888 Y88b. Y88b d88P Y88b. 888 888 888 888
888 "Y888888 "Y8888P "Y8888P" "Y8888P "Y888888 888 888
-[PacScan](https://github.com/Skelp/node-pacscan) provide information about all available packages for your module at
-runtime.
-
-> This library is very much still in early development! Watch this space.
+[PacScan](https://github.com/Skelp/node-pacscan) provides information about all available packages for your module at
+runtime by scanning `node_modules` as opposed to digging into dependency trees.
[](https://travis-ci.org/Skelp/node-pacscan)
[](https://coveralls.io/github/Skelp/node-pacscan)
@@ -37,11 +35,65 @@ You'll need to have at least [Node.js](https://nodejs.org) 4 or newer.
### `pacscan([options])`
-TODO: Document
+Scans for all packages available to your module asynchronously, returning a `Promise` to retrieve all of the package
+information, each of which will be in a format similar to the following:
+
+``` javascript
+{
+ // The directory of the package
+ directory: '/path/to/my-example-package/node_modules/example-server',
+ // The file path of the "main" file for the package or null if it has none
+ main: '/path/to/my-example-package/node_modules/example-server/server.js',
+ // The name of the package
+ name: 'example-server',
+ // The version of the package
+ version: '3.2.1'
+}
+```
+
+The `options` parameter is entirely optional and supports the following:
+
+| Option | Description | Default Value |
+| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
+| `includeParents` | Whether the highest level package directory should be scanned or only the lowest level base directory. | `false` |
+| `knockknock` | Any options to be passed to [KnockKnock](https://github.com/Skelp/node-knockknock). `limit` will always be overridden to `1`. | `null` |
+| `path` | The file/directory path from where to derive the base directory to be scanned. Path to module that called PacScan will be used when `null`. | `null` |
+
+If you only want to list the packages available to your module/package:
+
+``` javascript
+const pacscan = require('pacscan')
+
+module.exports = function() {
+ pacscan()
+ .then((packages) => {
+ console.log(`${packages.length} packages found`)
+
+ // ...
+ })
+}
+```
+
+However, if you're calling PacScan from within a library that is most likely being included in another package as a
+dependency. In these cases, you might want to know all of the packages available in the base package (i.e. the highest
+level package that is not a dependency itself). All that you need to do for this is to enable the `includeParents`
+option.
### `pacscan.sync([options])`
-TODO: Document
+A synchronous alternative to `pacscan([options])`.
+
+``` javascript
+const pacscan = require('pacscan')
+
+module.exports = function() {
+ const packages = pacscan.sync()
+
+ console.log(`${packages.length} packages found`)
+
+ // ...
+}
+```
### `pacscan.version`
@@ -51,7 +103,7 @@ The current version of PacScan.
const pacscan = require('pacscan')
pacscan.version
-=> "0.1.0alpha"
+=> "0.1.0"
```
## Bugs
diff --git a/package.json b/package.json
index 6f4493d..f643960 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pacscan",
- "version": "0.1.0alpha",
+ "version": "0.1.0",
"description": "Scans for available packages",
"homepage": "https://github.com/Skelp/node-pacscan",
"bugs": {
@@ -23,6 +23,8 @@
},
"dependencies": {
"debug": "*",
+ "glob": "^7.1.1",
+ "knockknock": "^0.2.0",
"pkg-dir": "^1.0.0"
},
"devDependencies": {
@@ -31,15 +33,17 @@
"eslint": "^3.16.0",
"eslint-config-skelp": "^0.1.5",
"istanbul": "^0.4.5",
- "mocha": "^3.2.0"
+ "mkdirp": "^0.5.1",
+ "mocha": "^3.2.0",
+ "ncp": "^2.0.0",
+ "tmp": "^0.0.31"
},
"main": "src/pacscan.js",
"scripts": {
"report-coverage": "istanbul cover _mocha --report lcovonly -- -R spec \"test/**/*.spec.js\" && coveralls < coverage/lcov.info",
- "test": "npm run test-lint && npm run test-suite && npm run test-coverage",
- "test-coverage": "istanbul check-coverage",
- "test-lint": "eslint \"src/**/*.js\" \"test/**/*.js\"",
- "test-suite": "istanbul cover _mocha -- -R spec \"test/**/*.spec.js\""
+ "pretest": "eslint \"src/**/*.js\" \"test/**/*.js\"",
+ "test": "istanbul cover _mocha -- -R spec \"test/**/*.spec.js\"",
+ "posttest": "istanbul check-coverage"
},
"engines": {
"node": ">=4"
diff --git a/src/pacscan.js b/src/pacscan.js
index f72aba5..e7793ba 100644
--- a/src/pacscan.js
+++ b/src/pacscan.js
@@ -22,8 +22,536 @@
'use strict'
+const debug = require('debug')('pacscan')
+const fs = require('fs')
+const glob = require('glob')
+const path = require('path')
+const pkgDir = require('pkg-dir')
+const whoIsThere = require('knockknock')
+
const version = require('../package.json').version
+/**
+ * A cache containing the available package.json file paths mapped to directory paths.
+ *
+ * The intention of this cache is to speed up available package lookups for repeat callers by avoiding file system
+ * searches.
+ *
+ * @private
+ * @type {Map.}
+ */
+const availablePackagesCache = new Map()
+
+/**
+ * Scans for all available packages at either a given file/directory or at the module that called PacScan. It will find
+ * the base package for that file path and then find and extract simple information from all accessible
+ * package.json files, with the option to even find packages belonging to parent packages, where
+ * applicable.
+ *
+ * @private
+ */
+class PacScan {
+
+ /**
+ * Asynchronously finds all files that match the specified patterns using the glob options
+ * provided and passes the paths of these files to the callback function.
+ *
+ * This method returns a Promise chained using the callback function so that it can be
+ * returned by {@link PacScan#scan}.
+ *
+ * @param {string[]} patterns - the glob patterns to be used to target package.json files
+ * @param {Object} options - the glob options to be used
+ * @param {pacscan~PackagePathsCallback} callback - the function to be called with the package.json file
+ * paths
+ * @return {Promise.} The result of calling callback.
+ * @private
+ * @static
+ */
+ static _findPackagePaths(patterns, options, callback) {
+ const searches = patterns.map((pattern) => new Promise((resolve, reject) => {
+ glob(pattern, options, (error, filePaths) => {
+ /* istanbul ignore if */
+ if (error) {
+ reject(error)
+ } else {
+ resolve(filePaths)
+ }
+ })
+ }))
+
+ return Promise.all(searches)
+ .then((values) => {
+ let filePaths = []
+ values.forEach((value) => {
+ filePaths = filePaths.concat(value)
+ })
+
+ return filePaths
+ })
+ .then(callback)
+ }
+
+ /**
+ * Synchronously finds all files that match the specified patterns using the glob options
+ * provided and passes the paths of these files to the callback function.
+ *
+ * This method returns the return value of the callback function so that it can be returned by
+ * {@link PacScan#scan}.
+ *
+ * @param {string[]} patterns - the glob patterns to be used to target package.json files
+ * @param {Object} options - the glob options to be used
+ * @param {pacscan~PackagePathsCallback} callback - the function to be called with the package.json file
+ * paths
+ * @return {pacscan~Package[]} The result of calling callback.
+ * @private
+ * @static
+ */
+ static _findPackagePathsSync(patterns, options, callback) {
+ let filePaths = []
+ patterns.forEach((pattern) => {
+ filePaths = filePaths.concat(glob.sync(pattern, options))
+ })
+
+ return callback(filePaths)
+ }
+
+ /**
+ * Returns the information for the package installed in the directory at the path provided.
+ *
+ * This information contains dirPath as well as the name, version, and
+ * (absolute) path of the main file (if any) read from the package.json file.
+ *
+ * This method should only be called when it is known that dirPath contains a package.json
+ * file.
+ *
+ * @param {string} dirPath - the path of the installation directory for the package whose information is to be
+ * returned
+ * @return {pacscan~Package} The information for the package installed within dirPath.
+ * @private
+ * @static
+ */
+ static _getPackage(dirPath) {
+ debug('Attempting to retrieve information for package installed in directory: %s', dirPath)
+
+ const pkg = require(path.join(dirPath, 'package.json'))
+
+ return {
+ directory: dirPath,
+ main: pkg.main ? path.join(dirPath, pkg.main) : null,
+ name: pkg.name,
+ version: pkg.version
+ }
+ }
+
+ /**
+ * Parses the optional input options provided, normalizing options and applying default values, where
+ * needed.
+ *
+ * @param {?pacscan~Options} options - the input options to be parsed (may be null if none were provided)
+ * @return {pacscan~Options} A new options object parsed from options.
+ * @private
+ * @static
+ */
+ static _parseOptions(options) {
+ if (!options) {
+ options = {}
+ }
+
+ return {
+ includeParents: options.includeParents,
+ knockknock: options.knockknock,
+ path: options.path
+ }
+ }
+
+ /**
+ * Creates an instance of {@link PacScan} using the optional options provided.
+ *
+ * sync can be used to control whether package searches are performed synchronously or asynchronously.
+ *
+ * @param {boolean} sync - true if package searches should be synchronous or false if they
+ * should be asynchronous
+ * @param {pacscan~Options} [options] - the options to be used (may be null)
+ * @public
+ */
+ constructor(sync, options) {
+ /**
+ * Whether package searches initiated by this {@link PacScan} should be made synchronously.
+ *
+ * @private
+ * @type {boolean}
+ */
+ this._sync = sync
+
+ /**
+ * The parsed options for this {@link PacScan}.
+ *
+ * @private
+ * @type {pacscan~Options}
+ */
+ this._options = PacScan._parseOptions(options)
+ }
+
+ /**
+ * Searches for all available packages within the base directory and returns a summary of the information for these
+ * packages.
+ *
+ * This method will directly return the information for all available packages if this {@link PacScan} is synchronous.
+ * Otherwise, this method will return a Promise which will be resolved with the information for all
+ * available packages once they have been found.
+ *
+ * @return {pacscan~Package[]|Promise.} The information for all available packages (or a
+ * Promise resolved with them when asynchronous).
+ * @public
+ */
+ scan() {
+ return this._resolveBaseDirectory((dirPath) => {
+ debug('Scanning for available packages within directory: %s', dirPath)
+
+ return this._findAvailablePackagePaths(dirPath, (filePaths) => {
+ debug('Found %d available packages within directory: %s', filePaths.length, dirPath)
+
+ return filePaths.map((filePath) => {
+ const pkg = PacScan._getPackage(path.dirname(filePath))
+
+ return Object.assign({}, pkg)
+ })
+ })
+ })
+ }
+
+ /**
+ * Finds all package.json files that are available within the directory provided and passes the paths of
+ * these files to the callback function.
+ *
+ * The flow for this method differs based on whether this {@link PacScan} is synchronous.
+ *
+ * @param {string} dirPath - the path to the directory to be searched
+ * @param {pacscan~PackagePathsCallback} callback - the function to be called with the package.json file
+ * paths
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _findAvailablePackagePaths(dirPath, callback) {
+ if (availablePackagesCache.has(dirPath)) {
+ return callback(availablePackagesCache.get(dirPath))
+ }
+
+ debug('Attempting to find all packages files within directory: %s', dirPath)
+
+ const options = { cwd: dirPath, nodir: true, nosort: true }
+ const patterns = [
+ '**/node_modules/*/package.json',
+ '**/node_modules/@*/*/package.json'
+ ]
+ const packagePathFinder = PacScan[this._sync ? '_findPackagePathsSync' : '_findPackagePaths']
+
+ return packagePathFinder(patterns, options, (filePaths) => this._isPackageDirectory(dirPath, (isPackage) => {
+ if (isPackage) {
+ filePaths.unshift('package.json')
+ }
+
+ filePaths = filePaths
+ .sort()
+ .map((filePath) => path.join(dirPath, filePath))
+
+ availablePackagesCache.set(dirPath, filePaths)
+
+ debug('Found %d packages files within directory: %s', filePaths.length, dirPath)
+
+ return callback(filePaths)
+ }))
+ }
+
+ /**
+ * Finds the base directory from the specified filePath and passes the path to the base directory to the
+ * callback function.
+ *
+ * The base directory is basically the highest level package directory. This is determined by finding package
+ * directories and climbing the node_modules directories until it can't anymore. At that point, the base
+ * directory is found.
+ *
+ * This method should only be called when the includeParents option is enabled.
+ *
+ * @param {string} filePath - the file path from where the base directory should be found
+ * @param {pacscan~BaseDirectoryCallback} callback - the function to be called with the path to the base directory
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _findBaseDirectory(filePath, callback) {
+ return this._findPackageDirectory(filePath, (dirPath) => {
+ if (dirPath == null) {
+ return callback(null)
+ }
+
+ let parentDirPath = path.dirname(dirPath)
+ let parentDirName = path.basename(parentDirPath)
+
+ if (parentDirName.charAt(0) === '@') {
+ parentDirPath = path.dirname(parentDirPath)
+ parentDirName = path.basename(parentDirPath)
+ }
+
+ if (parentDirName === 'node_modules') {
+ return this._findBaseDirectory(parentDirPath, (parentPkgDirPath) => {
+ if (parentPkgDirPath != null) {
+ dirPath = parentPkgDirPath
+ }
+
+ return callback(dirPath)
+ })
+ }
+
+ return callback(dirPath)
+ })
+ }
+
+ /**
+ * Finds the information for module that was responsible for calling PacScan and passes it to the
+ * callback function.
+ *
+ * Consumers can control what modules/packages are considering during this search via the knockknock
+ * option, however, the limit will always be overridden to 1.
+ *
+ * The flow for this method differs based on whether this {@link PacScan} is synchronous.
+ *
+ * @param {pacscan~FindCallerCallback} callback - the function to be called with the caller information
+ * @return {pacscan~Package[]|Promise.} The result of calling callback
+ * @private
+ */
+ _findCaller(callback) {
+ const excludes = [ 'pacscan' ]
+ const options = Object.assign({}, this._options.knockknock, { limit: 1 })
+
+ options.excludes = options.excludes ? excludes.concat(options.excludes) : excludes
+
+ if (this._sync) {
+ return callback(whoIsThere.sync(options)[0])
+ }
+
+ return whoIsThere(options)
+ .then((callers) => callers[0])
+ .then(callback)
+ }
+
+ /**
+ * Finds the installation directory for the package containing the specified filePath and passes the
+ * directory path to the callback function.
+ *
+ * If filePath does not exist within a package, the directory path will be null.
+ *
+ * The flow for this method differs based on whether this {@link PacScan} is synchronous.
+ *
+ * @param {string} filePath - the path of the file whose package directory is to be found
+ * @param {pacscan~FindPackageDirectoryCallback} callback - the function to be called with the package directory path
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _findPackageDirectory(filePath, callback) {
+ if (this._sync) {
+ return callback(pkgDir.sync(filePath))
+ }
+
+ return pkgDir(filePath).then(callback)
+ }
+
+ /**
+ * Determines whether the specified filePath is a directory and passes the result to the
+ * callback function.
+ *
+ * @param {string} filePath - the path of the file to be checked
+ * @param {pacscan~IsDirectoryCallback} callback - the function to be called with the result
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _isDirectory(filePath, callback) {
+ if (this._sync) {
+ return callback(fs.statSync(filePath).isDirectory())
+ }
+
+ return new Promise((resolve, reject) => {
+ fs.stat(filePath, (error, stats) => {
+ /* istanbul ignore if */
+ if (error) {
+ reject(error)
+ } else {
+ resolve(stats.isDirectory())
+ }
+ })
+ })
+ .then(callback)
+ }
+
+ /**
+ * Determines whether the specified filePath is a package installation directory and passes the result
+ * to the callback function.
+ *
+ * @param {string} filePath - the path of the fiile to be checked
+ * @param {pacscan~IsPackageDirectoryCallback} callback - the function to be called with the result
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _isPackageDirectory(filePath, callback) {
+ return this._findPackageDirectory(filePath, (dirPath) => callback(filePath === dirPath))
+ }
+
+ /**
+ * Resolves the base directory from where the package scan should originate and passes the directory path to the
+ * callback function.
+ *
+ * If the path option is specified, it is treated as the base file (even if it's not a file). Otherwise,
+ * the module that was responsible for calling PacScan is found and will be treated as the base file instead.
+ *
+ * If the base file belongs to a package, its directory will be used in the next step. Otherwise, the directory of the
+ * base file is used instead.
+ *
+ * At this stage, we have a base directory, however, if the includeParents option is enabled, the
+ * dependency tree (based on directory structure, not package.json) is climbed to find the highest level
+ * base directory, where possible.
+ *
+ * @param {pacscan~BaseDirectoryCallback} callback - the function to be called with the base directory path
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _resolveBaseDirectory(callback) {
+ let packageResolver
+ if (this._options.path != null) {
+ packageResolver = this._resolvePackageFromPath.bind(this)
+ } else {
+ packageResolver = this._resolvePackageFromCaller.bind(this)
+ }
+
+ return packageResolver((filePath, pkg) => {
+ if (filePath == null) {
+ throw new Error('Could not resolve base directory as file was missing')
+ }
+
+ if (pkg == null) {
+ return this._isDirectory(filePath, (isDirectory) => {
+ const dirPath = isDirectory ? filePath : path.dirname(filePath)
+
+ debug('Unable to find package containing file "%s" so using directory as base: %s', filePath, dirPath)
+
+ return callback(dirPath)
+ })
+ }
+
+ const dirPath = pkg.directory
+
+ debug('Found package "%s" containing file: %s', pkg.name, filePath)
+
+ if (!this._options.includeParents) {
+ debug('Using installation directory for package containing file as base: %s', dirPath)
+
+ return callback(dirPath)
+ }
+
+ debug('Attempting to find base parent package installation directory from package "%s" to use as base', pkg.name)
+
+ return this._findBaseDirectory(dirPath, callback)
+ })
+ }
+
+ /**
+ * Resolves the package from the module that was responsible for calling PacScan and passes the module file path and
+ * package information to the callback function.
+ *
+ * If no caller information could be found, both the file path and package information will be null or,
+ * if the calling module does not belong to a package, only the package information will be null.
+ *
+ * @param {pacscan~ResolvePackageCallback} callback - the function to be called with the file path and package
+ * information derived from the calling module
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _resolvePackageFromCaller(callback) {
+ return this._findCaller((caller) => {
+ if (caller == null) {
+ return callback(null, null)
+ }
+
+ return callback(caller.file, caller.package)
+ })
+ }
+
+ /**
+ * Resolves the package from the path option and passes the path option and package
+ * information to the callback function.
+ *
+ * If the path option does not belong to a package, the package information will be null.
+ *
+ * @param {pacscan~ResolvePackageCallback} callback - the function to be called with the path option and
+ * package information
+ * @return {pacscan~Package[]|Promise.} The result of calling callback.
+ * @private
+ */
+ _resolvePackageFromPath(callback) {
+ const filePath = this._options.path
+
+ return this._findPackageDirectory(filePath, (dirPath) => {
+ const pkg = dirPath != null ? PacScan._getPackage(dirPath) : null
+
+ return callback(filePath, pkg)
+ })
+ }
+
+}
+
+/**
+ * Asynchronously resolves the base directory from either the path option or the module that was
+ * responsible for calling PacScan and then scans this directory for all packages available within it.
+ *
+ * The scan can also include packages from parent packages (for cases where the target module exists within a depedent
+ * package - e.g. exists within another package's node_modules directory) by enabling the
+ * includeParents option.
+ *
+ * The resolution of the calling module can be controlled at a more granular level by specifying knockknock
+ * options.
+ *
+ * @param {pacscan~Options} [options] - the options to be used (may be null)
+ * @return {Promise.} A Promise for retrieving the information for all available
+ * packages.
+ * @public
+ * @static
+ */
+module.exports = function scan(options) {
+ return Promise.resolve(new PacScan(false, options).scan())
+}
+
+/**
+ * Clears the cache containing available package.json file paths mapped to directory paths which is used to
+ * speed up package lookups for repeat callers by avoiding file system searches.
+ *
+ * This is primarily intended for testing purposes.
+ *
+ * @return {void}
+ * @protected
+ * @static
+ */
+module.exports.clearCache = function clearCache() {
+ availablePackagesCache.clear()
+}
+
+/**
+ * Synchronously resolves the base directory from either the path option or the module that was responsible
+ * for calling PacScan and then scans this directory for all packages available within it.
+ *
+ * The scan can also include packages from parent packages (for cases where the target module exists within a depedent
+ * package - e.g. exists within another package's node_modules directory) by enabling the
+ * includeParents option.
+ *
+ * The resolution of the calling module can be controlled at a more granular level by specifying knockknock
+ * options.
+ *
+ * @param {pacscan~Options} [options] - the options to be used (may be null)
+ * @return {pacscan~Package[]} The information for all available packages.
+ * @public
+ * @static
+ */
+module.exports.sync = function scanSync(options) {
+ return new PacScan(true, options).scan()
+}
+
/**
* The current version of PacScan.
*
@@ -32,3 +560,87 @@ const version = require('../package.json').version
* @type {string}
*/
module.exports.version = version
+
+/**
+ * Called with the path of a base directory.
+ *
+ * @callback pacscan~BaseDirectoryCallback
+ * @param {?string} dirPath - the path to the base directory (may be null if none could be found)
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Called with the information for the caller that was responsible for calling PacScan.
+ *
+ * @callback pacscan~FindCallerCallback
+ * @param {?knockknock~Caller} caller - the caller information (may be null if no caller could be found)
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Called with the path to the package installation directory containing a file.
+ *
+ * @callback pacscan~FindPackageDirectoryCallback
+ * @param {?string} dirPath - the path to the package installation directory (may be null if the file does
+ * not belong to a package)
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Called with whether a file path points to an existing directory.
+ *
+ * @callback pacscan~IsDirectoryCallback
+ * @param {boolean} isDirectory - true if the file path points to a directory; otherwise false
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Called with whether a file path points to a package installation directory.
+ *
+ * @callback pacscan~IsPackageDirectoryCallback
+ * @param {boolean} isPackage - true if the file path points to a pacakge installation directory; otherwise
+ * false
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Called with the absolute paths for all package.json files found within a directory.
+ *
+ * @callback pacscan~PackagePathsCallback
+ * @param {string[]} filePaths - the paths to all available package.json files
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Called with the file path and package information resolved from a file path.
+ *
+ * @callback pacscan~ResolvePackageCallback
+ * @param {?string} filePath - the path to the target file (may be null if it could not be resolved)
+ * @param {?pacscan~Package} pkg - the package information (may be null if it could not be resolved or the
+ * file does not belong to a package)
+ * @return {pacscan~Package[]|Promise.} The scan result.
+ */
+
+/**
+ * Contains some basic information for an individual package.
+ *
+ * @typedef {Object} pacscan~Package
+ * @property {string} directory - The path to the installation directory of the package.
+ * @property {?string} main - The path to the main file for the package (may be null if it has no
+ * main entry).
+ * @property {string} name - The name of the package.
+ * @property {string} version - The version of the package.
+ */
+
+/**
+ * The options to be used to scan for packages.
+ *
+ * @typedef {Object} pacscan~Options
+ * @property {boolean} [includeParents] - true if the highest level package directory should be scanned or
+ * false to scan only the initial base directory.
+ * @property {knockknock~Options} [knockknock] - The options to be passed to knockknock when attempting to
+ * determine the calling module (limit will always be overridden to 1).
+ * @property {string} [path] - The path of the file/directory from which the base directory to be scanned is derived.
+ * The base directory should be derived from the module that was responsible for calling PacScan if this is
+ * null.
+ */
diff --git a/test/fixtures/.gitignore b/test/fixtures/.gitignore
new file mode 100644
index 0000000..ddf3424
--- /dev/null
+++ b/test/fixtures/.gitignore
@@ -0,0 +1 @@
+!node_modules/
diff --git a/test/fixtures/flat/index.js b/test/fixtures/flat/index.js
new file mode 100644
index 0000000..6edce89
--- /dev/null
+++ b/test/fixtures/flat/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function flatFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function flatSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/@baz/buzz/package.json b/test/fixtures/flat/node_modules/@baz/buzz/package.json
new file mode 100644
index 0000000..4ad0088
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@baz/buzz/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@baz/buzz",
+ "version": "1.4.2",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/flat/node_modules/@baz/buzz/server.js b/test/fixtures/flat/node_modules/@baz/buzz/server.js
new file mode 100644
index 0000000..09dbd94
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@baz/buzz/server.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function bazBuzzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function bazBuzzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/@baz/fizz/index.js b/test/fixtures/flat/node_modules/@baz/fizz/index.js
new file mode 100644
index 0000000..4b98ed6
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@baz/fizz/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function bazFizzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function bazFizzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/@baz/fizz/package.json b/test/fixtures/flat/node_modules/@baz/fizz/package.json
new file mode 100644
index 0000000..1fe6f12
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@baz/fizz/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "@baz/fizz",
+ "version": "1.4.1",
+ "private": true
+}
diff --git a/test/fixtures/flat/node_modules/@fu/buzz/index.js b/test/fixtures/flat/node_modules/@fu/buzz/index.js
new file mode 100644
index 0000000..f54f71c
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@fu/buzz/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fuBuzzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fuBuzzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/@fu/buzz/package.json b/test/fixtures/flat/node_modules/@fu/buzz/package.json
new file mode 100644
index 0000000..97ad959
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@fu/buzz/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@fu/buzz",
+ "version": "1.3.2",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/flat/node_modules/@fu/fizz/index.js b/test/fixtures/flat/node_modules/@fu/fizz/index.js
new file mode 100644
index 0000000..c2d9a82
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@fu/fizz/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fuFizzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fuFizzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/@fu/fizz/package.json b/test/fixtures/flat/node_modules/@fu/fizz/package.json
new file mode 100644
index 0000000..06461db
--- /dev/null
+++ b/test/fixtures/flat/node_modules/@fu/fizz/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@fu/fizz",
+ "version": "1.3.1",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/flat/node_modules/bar/index.js b/test/fixtures/flat/node_modules/bar/index.js
new file mode 100644
index 0000000..cc9906b
--- /dev/null
+++ b/test/fixtures/flat/node_modules/bar/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function barFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function barSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/bar/package.json b/test/fixtures/flat/node_modules/bar/package.json
new file mode 100644
index 0000000..041b9ce
--- /dev/null
+++ b/test/fixtures/flat/node_modules/bar/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "bar",
+ "version": "1.2.0",
+ "main": "./index",
+ "private": true
+}
diff --git a/test/fixtures/flat/node_modules/foo/index.js b/test/fixtures/flat/node_modules/foo/index.js
new file mode 100644
index 0000000..be3cc72
--- /dev/null
+++ b/test/fixtures/flat/node_modules/foo/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fooFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fooSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/flat/node_modules/foo/package.json b/test/fixtures/flat/node_modules/foo/package.json
new file mode 100644
index 0000000..63620cc
--- /dev/null
+++ b/test/fixtures/flat/node_modules/foo/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "foo",
+ "version": "1.1.0",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/flat/package.json b/test/fixtures/flat/package.json
new file mode 100644
index 0000000..6d64ff5
--- /dev/null
+++ b/test/fixtures/flat/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "flat",
+ "version": "1.0.0",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/nested/index.js b/test/fixtures/nested/index.js
new file mode 100644
index 0000000..4ee51de
--- /dev/null
+++ b/test/fixtures/nested/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function nestedFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function nestedSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/index.js b/test/fixtures/nested/node_modules/foo/index.js
new file mode 100644
index 0000000..be3cc72
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fooFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fooSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/index.js b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/index.js
new file mode 100644
index 0000000..c2d9a82
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fuFizzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fuFizzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/package.json b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/package.json
new file mode 100644
index 0000000..4ad0088
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@baz/buzz",
+ "version": "1.4.2",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/server.js b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/server.js
new file mode 100644
index 0000000..09dbd94
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/server.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function bazBuzzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function bazBuzzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/package.json b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/package.json
new file mode 100644
index 0000000..06461db
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/@fu/fizz/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@fu/fizz",
+ "version": "1.3.1",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/bar/index.js b/test/fixtures/nested/node_modules/foo/node_modules/bar/index.js
new file mode 100644
index 0000000..cc9906b
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/bar/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function barFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function barSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz/index.js b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz/index.js
new file mode 100644
index 0000000..4b98ed6
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function bazFizzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function bazFizzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz/package.json b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz/package.json
new file mode 100644
index 0000000..1fe6f12
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "@baz/fizz",
+ "version": "1.4.1",
+ "private": true
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js
new file mode 100644
index 0000000..f54f71c
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fuBuzzFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fuBuzzSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/package.json b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/package.json
new file mode 100644
index 0000000..97ad959
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@fu/buzz",
+ "version": "1.3.2",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/nested/node_modules/foo/node_modules/bar/package.json b/test/fixtures/nested/node_modules/foo/node_modules/bar/package.json
new file mode 100644
index 0000000..041b9ce
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/node_modules/bar/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "bar",
+ "version": "1.2.0",
+ "main": "./index",
+ "private": true
+}
diff --git a/test/fixtures/nested/node_modules/foo/package.json b/test/fixtures/nested/node_modules/foo/package.json
new file mode 100644
index 0000000..63620cc
--- /dev/null
+++ b/test/fixtures/nested/node_modules/foo/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "foo",
+ "version": "1.1.0",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/nested/package.json b/test/fixtures/nested/package.json
new file mode 100644
index 0000000..ff28ce6
--- /dev/null
+++ b/test/fixtures/nested/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "nested",
+ "version": "1.0.0",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/single/index.js b/test/fixtures/single/index.js
new file mode 100644
index 0000000..c66e13d
--- /dev/null
+++ b/test/fixtures/single/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function singleFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function singleSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/single/package.json b/test/fixtures/single/package.json
new file mode 100644
index 0000000..5a68626
--- /dev/null
+++ b/test/fixtures/single/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "single",
+ "version": "1.0.0",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/fixtures/unpackaged-single/index.js b/test/fixtures/unpackaged-single/index.js
new file mode 100644
index 0000000..3c51c0d
--- /dev/null
+++ b/test/fixtures/unpackaged-single/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function unpackagedSingleFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function unpackagedSingleSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/unpackaged/index.js b/test/fixtures/unpackaged/index.js
new file mode 100644
index 0000000..759a85d
--- /dev/null
+++ b/test/fixtures/unpackaged/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function unpackagedFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function unpackagedSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/unpackaged/node_modules/foo/index.js b/test/fixtures/unpackaged/node_modules/foo/index.js
new file mode 100644
index 0000000..be3cc72
--- /dev/null
+++ b/test/fixtures/unpackaged/node_modules/foo/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function fooFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function fooSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/unpackaged/node_modules/foo/node_modules/bar/index.js b/test/fixtures/unpackaged/node_modules/foo/node_modules/bar/index.js
new file mode 100644
index 0000000..cc9906b
--- /dev/null
+++ b/test/fixtures/unpackaged/node_modules/foo/node_modules/bar/index.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+module.exports = function barFunction(pacscanPath, options) {
+ return require(pacscanPath)(options)
+}
+module.exports.sync = function barSyncFunction(pacscanPath, options) {
+ return require(pacscanPath).sync(options)
+}
diff --git a/test/fixtures/unpackaged/node_modules/foo/node_modules/bar/package.json b/test/fixtures/unpackaged/node_modules/foo/node_modules/bar/package.json
new file mode 100644
index 0000000..041b9ce
--- /dev/null
+++ b/test/fixtures/unpackaged/node_modules/foo/node_modules/bar/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "bar",
+ "version": "1.2.0",
+ "main": "./index",
+ "private": true
+}
diff --git a/test/fixtures/unpackaged/node_modules/foo/package.json b/test/fixtures/unpackaged/node_modules/foo/package.json
new file mode 100644
index 0000000..63620cc
--- /dev/null
+++ b/test/fixtures/unpackaged/node_modules/foo/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "foo",
+ "version": "1.1.0",
+ "main": "index.js",
+ "private": true
+}
diff --git a/test/helpers.js b/test/helpers.js
new file mode 100644
index 0000000..b59b237
--- /dev/null
+++ b/test/helpers.js
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+const mkdirp = require('mkdirp')
+const ncp = require('ncp').ncp
+const path = require('path')
+const tmp = require('tmp')
+
+/**
+ * The path to the temporary directory created from where fixtures should be run in isolation.
+ *
+ * This should only be accessed via {@link getTempDirectory} and will be null until that method is called
+ * for the first time.
+ *
+ * @private
+ * @type {?string}
+ */
+let tempDirPath
+
+/**
+ * Copies the contents of the fixture directory with the specified name to a temporary directory so that it
+ * can be run in isolation.
+ *
+ * @param {string} name - the name of the fixture whose directory is to be copied
+ * @return {Promise.} A Promise for retrieving the path to the temporary directory
+ * containing the fixture contents.
+ * @public
+ * @static
+ */
+exports.copyFixture = function copyFixture(name) {
+ return new Promise((resolve, reject) => {
+ const dirPath = exports.getFixtureDirectory(name)
+
+ mkdirp.sync(dirPath)
+
+ ncp(path.join(__dirname, 'fixtures', name), dirPath, (error) => {
+ if (error) {
+ reject(error)
+ } else {
+ resolve(dirPath)
+ }
+ })
+ })
+}
+
+/**
+ * Creates options to be used by tests.
+ *
+ * This is just a convenient method for ensuring that chai and mocha calls are always excluded from knockknock when
+ * trying to find the caller.
+ *
+ * @param {pacscan~Options} [options] - the options to be used (may be null)
+ * @return {pacscan~Options} The created options.
+ * @public
+ * @static
+ */
+exports.createOptions = function createOptions(options) {
+ if (!options) {
+ options = {}
+ }
+
+ const knockknock = Object.assign({}, options.knockknock)
+ knockknock.excludes = [ 'chai', 'mocha' ].concat(knockknock.excludes || [])
+
+ options.knockknock = knockknock
+
+ return options
+}
+
+/**
+ * Returns the path to the temporary directory containing the contents of the fixture directory with the specified
+ * name.
+ *
+ * @param {string} name - the name of the fixture whose temporary directory path is to be returned
+ * @return {string} The temporary directory path for the fixture with name.
+ * @public
+ * @static
+ */
+exports.getFixtureDirectory = function getFixtureDirectory(name) {
+ return path.join(exports.getTempDirectory(), 'fixtures', name)
+}
+
+/**
+ * Returns the path of the temporary directory created from where fixtures should be run in isolation.
+ *
+ * @return {string} The temporary directory path.
+ * @public
+ * @static
+ */
+exports.getTempDirectory = function getTempDirectory() {
+ if (tempDirPath == null) {
+ tmp.setGracefulCleanup()
+
+ tempDirPath = tmp.dirSync().name
+ }
+
+ return tempDirPath
+}
+
+/**
+ * Requires the file at the given path within the directory for the fixture with the specified name.
+ *
+ * Since fixture directories are copied to a temporary directory to be run in isolation, they are no longer able to
+ * easily find and require pacscan by themselves. For this reason, this method returns a proxy to these fixtures so that
+ * it can pass the absolute path to require pacscan within the fixture while also ensuring that the optons are passed
+ * through {@link createOptions}.
+ *
+ * @param {string} name - the name of the fixture containing the file to be required
+ * @param {string} filePath - the path of the file (relative to the fixture directory) to be required
+ * @return {Function} A proxy to be used to call the fixture (also contains a sync method).
+ * @public
+ * @static
+ */
+exports.requireFromFixture = function requireFromFixture(name, filePath) {
+ const fixture = require(exports.resolveFixtureFile(name, filePath))
+ const pacscanPath = path.resolve(__dirname, '../src/pacscan')
+
+ const proxy = function proxy(options) {
+ return fixture(pacscanPath, exports.createOptions(options))
+ }
+ proxy.sync = function proxySync(options) {
+ return fixture.sync(pacscanPath, exports.createOptions(options))
+ }
+
+ return proxy
+}
+
+/**
+ * Resolves the specified filePath to the temporary directory for the fixture with the specified
+ * name.
+ *
+ * @param {string} name - the name of the fixture to which filePath is to be resolved
+ * @param {string} filePath - the path of the file to be resolved
+ * @return {string} The resolve file path.
+ * @public
+ * @static
+ */
+exports.resolveFixtureFile = function resolveFixtureFile(name, filePath) {
+ return path.resolve(exports.getFixtureDirectory(name), filePath)
+}
+
+/**
+ * Resolves all file paths on the specified pkg to the fixtures directory so that they are
+ * absolute.
+ *
+ * @param {pacscan~Package} pkg - the expected package information whose file paths are to be resolved
+ * @return {pacscan~Package} A reference to the modified pkg.
+ * @public
+ * @static
+ */
+exports.resolvePackageForFixture = function resolvePackageForFixture(pkg) {
+ const dirPath = path.join(exports.getTempDirectory(), 'fixtures')
+
+ pkg.directory = path.resolve(dirPath, pkg.directory)
+ if (pkg.main != null) {
+ pkg.main = path.resolve(dirPath, pkg.main)
+ }
+
+ return pkg
+}
diff --git a/test/pacscan.flat.spec.js b/test/pacscan.flat.spec.js
new file mode 100644
index 0000000..5ab8901
--- /dev/null
+++ b/test/pacscan.flat.spec.js
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+const expect = require('chai').expect
+
+const helpers = require('./helpers')
+const pacscan = require('../src/pacscan')
+
+describe('pacscan:fixture:flat', () => {
+ before(() => helpers.copyFixture('flat'))
+
+ context('when asynchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base package', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const flat = helpers.requireFromFixture('flat', 'index.js')
+
+ return flat()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const flat = helpers.requireFromFixture('flat', 'index.js')
+
+ return flat({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within dependency package', () => {
+ it('should return promise for dependency package only', () => {
+ const foo = helpers.requireFromFixture('flat', 'node_modules/foo/index.js')
+
+ return foo()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const foo = helpers.requireFromFixture('flat', 'node_modules/foo/index.js')
+
+ return foo({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within scoped dependency package', () => {
+ it('should return promise for scoped dependency package only', () => {
+ const fizz = helpers.requireFromFixture('flat', 'node_modules/@fu/fizz/index.js')
+
+ return fizz()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const fizz = helpers.requireFromFixture('flat', 'node_modules/@fu/fizz/index.js')
+
+ return fizz({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+ })
+
+ context('when synchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base package', () => {
+ it('should return base package and its dependencies', () => {
+ const flat = helpers.requireFromFixture('flat', 'index.js')
+ const packages = flat.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const flat = helpers.requireFromFixture('flat', 'index.js')
+ const packages = flat.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within dependency package', () => {
+ it('should return dependency package only', () => {
+ const foo = helpers.requireFromFixture('flat', 'node_modules/foo/index.js')
+ const packages = foo.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const foo = helpers.requireFromFixture('flat', 'node_modules/foo/index.js')
+ const packages = foo.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within scoped dependency package', () => {
+ it('should return scoped dependency package only', () => {
+ const fizz = helpers.requireFromFixture('flat', 'node_modules/@fu/fizz/index.js')
+ const packages = fizz.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const fizz = helpers.requireFromFixture('flat', 'node_modules/@fu/fizz/index.js')
+ const packages = fizz.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+})
diff --git a/test/pacscan.nested.spec.js b/test/pacscan.nested.spec.js
new file mode 100644
index 0000000..db99988
--- /dev/null
+++ b/test/pacscan.nested.spec.js
@@ -0,0 +1,768 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+const expect = require('chai').expect
+
+const helpers = require('./helpers')
+const pacscan = require('../src/pacscan')
+
+describe('pacscan:fixture:nested', () => {
+ before(() => helpers.copyFixture('nested'))
+
+ context('when asynchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base package', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const nested = helpers.requireFromFixture('nested', 'index.js')
+
+ return nested()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const nested = helpers.requireFromFixture('nested', 'index.js')
+
+ return nested({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within dependency package', () => {
+ it('should return promise for dependency package and its dependencies only', () => {
+ const foo = helpers.requireFromFixture('nested', 'node_modules/foo/index.js')
+
+ return foo()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const foo = helpers.requireFromFixture('nested', 'node_modules/foo/index.js')
+
+ return foo({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within nested dependency package', () => {
+ it('should return promise for nested dependency package and its dependencies only', () => {
+ const bar = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/bar/index.js')
+
+ return bar()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const bar = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/bar/index.js')
+
+ return bar({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within scoped dependency package', () => {
+ it('should return promise for scoped dependency package and its dependencies only', () => {
+ const fizz = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/@fu/fizz/index.js')
+
+ return fizz()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package and its dependencies', () => {
+ const fizz = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/@fu/fizz/index.js')
+
+ return fizz({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+ })
+
+ context('when synchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base package', () => {
+ it('should return base package and its dependencies', () => {
+ const nested = helpers.requireFromFixture('nested', 'index.js')
+ const packages = nested.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const nested = helpers.requireFromFixture('nested', 'index.js')
+ const packages = nested.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within dependency package', () => {
+ it('should return dependency package and its dependencies only', () => {
+ const foo = helpers.requireFromFixture('nested', 'node_modules/foo/index.js')
+ const packages = foo.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const foo = helpers.requireFromFixture('nested', 'node_modules/foo/index.js')
+ const packages = foo.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within nested dependency package', () => {
+ it('should return nested dependency package and its dependencies only', () => {
+ const bar = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/bar/index.js')
+ const packages = bar.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const bar = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/bar/index.js')
+ const packages = bar.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within scoped dependency package', () => {
+ it('should return scoped dependency package and its dependencies only', () => {
+ const fizz = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/@fu/fizz/index.js')
+ const packages = fizz.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package and its dependencies', () => {
+ const fizz = helpers.requireFromFixture('nested', 'node_modules/foo/node_modules/@fu/fizz/index.js')
+ const packages = fizz.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/@fu/fizz',
+ main: 'nested/node_modules/foo/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz',
+ main: 'nested/node_modules/foo/node_modules/bar/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo/node_modules/bar',
+ main: 'nested/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested/node_modules/foo',
+ main: 'nested/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'nested',
+ main: 'nested/index.js',
+ name: 'nested',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+})
diff --git a/test/pacscan.single.spec.js b/test/pacscan.single.spec.js
new file mode 100644
index 0000000..ab5fb0e
--- /dev/null
+++ b/test/pacscan.single.spec.js
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+const expect = require('chai').expect
+
+const helpers = require('./helpers')
+const pacscan = require('../src/pacscan')
+
+describe('pacscan:fixture:single', () => {
+ before(() => helpers.copyFixture('single'))
+
+ context('when asynchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base package', () => {
+ it('should return promise for base package only', () => {
+ const single = helpers.requireFromFixture('single', 'index.js')
+
+ return single()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'single',
+ main: 'single/index.js',
+ name: 'single',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for base package only', () => {
+ const single = helpers.requireFromFixture('single', 'index.js')
+
+ return single({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'single',
+ main: 'single/index.js',
+ name: 'single',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('when synchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base package', () => {
+ it('should return base package only', () => {
+ const single = helpers.requireFromFixture('single', 'index.js')
+ const packages = single.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'single',
+ main: 'single/index.js',
+ name: 'single',
+ version: '1.0.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return base package only', () => {
+ const single = helpers.requireFromFixture('single', 'index.js')
+ const packages = single.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'single',
+ main: 'single/index.js',
+ name: 'single',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+})
diff --git a/test/pacscan.spec.js b/test/pacscan.spec.js
index 816c1ec..253ac9b 100644
--- a/test/pacscan.spec.js
+++ b/test/pacscan.spec.js
@@ -24,10 +24,369 @@
const expect = require('chai').expect
+const helpers = require('./helpers')
const pacscan = require('../src/pacscan')
const version = require('../package.json').version
describe('pacscan', () => {
+ before(() => {
+ return Promise.all([
+ helpers.copyFixture('flat'),
+ helpers.copyFixture('unpackaged')
+ ])
+ })
+
+ context('when asynchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from unknown source without "path"', () => {
+ it('should return promise rejected', () => {
+ return pacscan(helpers.createOptions())
+ .then(() => {
+ throw new Error('Expected promise to be rejected')
+ })
+ .catch((error) => {
+ expect(error.message).to.equal('Could not resolve base directory as file was missing')
+ })
+ })
+ })
+
+ context('and no options are provided', () => {
+ it('should use default options', () => {
+ return pacscan()
+ .then((packages) => {
+ // mocha modules are only excluded by helpers.createOptions, so will now be included
+ expect(packages).to.have.length.of.at.least(1)
+ })
+ })
+ })
+
+ context('and "path" targets package directory', () => {
+ it('should return promise for package and its dependencies', () => {
+ const dirPath = helpers.getFixtureDirectory('flat')
+
+ return pacscan(helpers.createOptions({ path: dirPath }))
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and "path" targets packaged file', () => {
+ it('should return promise for package and its dependencies', () => {
+ const filePath = helpers.resolveFixtureFile('flat', 'index.js')
+
+ return pacscan(helpers.createOptions({ path: filePath }))
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and "path" targets unpackaged directory', () => {
+ it('should return promise for dependencies only', () => {
+ const dirPath = helpers.getFixtureDirectory('unpackaged')
+
+ return pacscan(helpers.createOptions({ path: dirPath }))
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and "path" targets unpackaged file', () => {
+ it('should return promise for dependencies only', () => {
+ const filePath = helpers.resolveFixtureFile('unpackaged', 'index.js')
+
+ return pacscan(helpers.createOptions({ path: filePath }))
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('when synchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from unknown source without "path"', () => {
+ it('should throw error', () => {
+ expect(() => {
+ pacscan.sync(helpers.createOptions())
+ }).to.throw(Error, 'Could not resolve base directory as file was missing')
+ })
+ })
+
+ context('and no options are provided', () => {
+ it('should use default options', () => {
+ const packages = pacscan.sync()
+
+ // mocha modules are only excluded by helpers.createOptions, so will now be included
+ expect(packages).to.have.length.of.at.least(1)
+ })
+ })
+
+ context('and "path" targets package directory', () => {
+ it('should return package and its dependencies', () => {
+ const dirPath = helpers.getFixtureDirectory('flat')
+ const packages = pacscan.sync(helpers.createOptions({ path: dirPath }))
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+
+ context('and "path" targets packaged file', () => {
+ it('should return package and its dependencies', () => {
+ const filePath = helpers.resolveFixtureFile('flat', 'index.js')
+ const packages = pacscan.sync(helpers.createOptions({ path: filePath }))
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/buzz',
+ main: 'flat/node_modules/@baz/buzz/index.js',
+ name: '@baz/buzz',
+ version: '1.4.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@baz/fizz',
+ main: null,
+ name: '@baz/fizz',
+ version: '1.4.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/buzz',
+ main: 'flat/node_modules/@fu/buzz/index.js',
+ name: '@fu/buzz',
+ version: '1.3.2'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/@fu/fizz',
+ main: 'flat/node_modules/@fu/fizz/index.js',
+ name: '@fu/fizz',
+ version: '1.3.1'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/bar',
+ main: 'flat/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat/node_modules/foo',
+ main: 'flat/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'flat',
+ main: 'flat/index.js',
+ name: 'flat',
+ version: '1.0.0'
+ })
+ ])
+ })
+ })
+
+ context('and "path" targets unpackaged directory', () => {
+ it('should return dependencies only', () => {
+ const dirPath = helpers.getFixtureDirectory('unpackaged')
+ const packages = pacscan.sync(helpers.createOptions({ path: dirPath }))
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+
+ context('and "path" targets unpackaged file', () => {
+ it('should return dependencies only', () => {
+ const filePath = helpers.resolveFixtureFile('unpackaged', 'index.js')
+ const packages = pacscan.sync(helpers.createOptions({ path: filePath }))
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+
describe('.version', () => {
it('should match package version', () => {
expect(pacscan.version).to.equal(version)
diff --git a/test/pacscan.unpackaged-single.spec.js b/test/pacscan.unpackaged-single.spec.js
new file mode 100644
index 0000000..64bc302
--- /dev/null
+++ b/test/pacscan.unpackaged-single.spec.js
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+const expect = require('chai').expect
+
+const helpers = require('./helpers')
+const pacscan = require('../src/pacscan')
+
+describe('pacscan:fixture:unpackaged-single', () => {
+ before(() => helpers.copyFixture('unpackaged-single'))
+
+ context('when asynchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base directory', () => {
+ it('should return promise for empty array', () => {
+ const unpackagedSingle = helpers.requireFromFixture('unpackaged-single', 'index.js')
+
+ return unpackagedSingle()
+ .then((packages) => {
+ expect(packages).to.be.empty
+ })
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for empty array', () => {
+ const unpackagedSingle = helpers.requireFromFixture('unpackaged-single', 'index.js')
+
+ return unpackagedSingle({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.be.empty
+ })
+ })
+ })
+ })
+
+ context('when synchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base directory', () => {
+ it('should return empty array', () => {
+ const unpackagedSingle = helpers.requireFromFixture('unpackaged-single', 'index.js')
+ const packages = unpackagedSingle.sync()
+
+ expect(packages).to.be.empty
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return empty array', () => {
+ const unpackagedSingle = helpers.requireFromFixture('unpackaged-single', 'index.js')
+ const packages = unpackagedSingle.sync({ includeParents: true })
+
+ expect(packages).to.be.empty
+ })
+ })
+ })
+ })
+})
diff --git a/test/pacscan.unpackaged.spec.js b/test/pacscan.unpackaged.spec.js
new file mode 100644
index 0000000..47da06b
--- /dev/null
+++ b/test/pacscan.unpackaged.spec.js
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2017 Alasdair Mercer, Skelp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+'use strict'
+
+const expect = require('chai').expect
+
+const helpers = require('./helpers')
+const pacscan = require('../src/pacscan')
+
+describe('pacscan:fixture:unpackaged', () => {
+ before(() => helpers.copyFixture('unpackaged'))
+
+ context('when asynchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base directory', () => {
+ it('should return promise for dependencies only', () => {
+ const unpackaged = helpers.requireFromFixture('unpackaged', 'index.js')
+
+ return unpackaged()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for dependencies only', () => {
+ const unpackaged = helpers.requireFromFixture('unpackaged', 'index.js')
+
+ return unpackaged({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within dependency package', () => {
+ it('should return promise for dependencies only', () => {
+ const foo = helpers.requireFromFixture('unpackaged', 'node_modules/foo/index.js')
+
+ return foo()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for dependencies only', () => {
+ const foo = helpers.requireFromFixture('unpackaged', 'node_modules/foo/index.js')
+
+ return foo({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+
+ context('and called from within nested dependency package', () => {
+ it('should return promise for nested dependency package only', () => {
+ const bar = helpers.requireFromFixture('unpackaged', 'node_modules/foo/node_modules/bar/index.js')
+
+ return bar()
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ })
+ ])
+ })
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return promise for dependencies only', () => {
+ const bar = helpers.requireFromFixture('unpackaged', 'node_modules/foo/node_modules/bar/index.js')
+
+ return bar({ includeParents: true })
+ .then((packages) => {
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+ })
+
+ context('when synchronous', () => {
+ before(() => pacscan.clearCache())
+
+ context('and called from within base directory', () => {
+ it('should return dependencies only', () => {
+ const unpackaged = helpers.requireFromFixture('unpackaged', 'index.js')
+ const packages = unpackaged.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return dependencies only', () => {
+ const unpackaged = helpers.requireFromFixture('unpackaged', 'index.js')
+ const packages = unpackaged.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within dependency package', () => {
+ it('should return dependencies only', () => {
+ const foo = helpers.requireFromFixture('unpackaged', 'node_modules/foo/index.js')
+ const packages = foo.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return dependencies only', () => {
+ const foo = helpers.requireFromFixture('unpackaged', 'node_modules/foo/index.js')
+ const packages = foo.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+
+ context('and called from within nested dependency package', () => {
+ it('should return nested dependency package only', () => {
+ const bar = helpers.requireFromFixture('unpackaged', 'node_modules/foo/node_modules/bar/index.js')
+ const packages = bar.sync()
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ })
+ ])
+ })
+
+ context('and "includeParents" is enabled', () => {
+ it('should return dependencies only', () => {
+ const bar = helpers.requireFromFixture('unpackaged', 'node_modules/foo/node_modules/bar/index.js')
+ const packages = bar.sync({ includeParents: true })
+
+ expect(packages).to.eql([
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo/node_modules/bar',
+ main: 'unpackaged/node_modules/foo/node_modules/bar/index',
+ name: 'bar',
+ version: '1.2.0'
+ }),
+ helpers.resolvePackageForFixture({
+ directory: 'unpackaged/node_modules/foo',
+ main: 'unpackaged/node_modules/foo/index.js',
+ name: 'foo',
+ version: '1.1.0'
+ })
+ ])
+ })
+ })
+ })
+ })
+})