diff --git a/.eslintrc.json b/.eslintrc.json index e11a5ba..8bced1d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,9 +1,13 @@ { - "extends": "skelp/v3/es6", + "extends": "notninja/es6", "env": { "node": true }, "rules": { + "func-names": [ + "error", + "always" + ], "global-require": "off", "max-params": [ "error", diff --git a/.travis.yml b/.travis.yml index 3694d3a..e815da8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,11 @@ node_js: - "6" - "7" script: - - npm test + - npm run ci after_script: - npm run report-coverage +notifications: + slack: + rooms: + - secure: aWIR/s68NNaoxHs5NKWrC7e9jDP89uEIrtpKjKhi/Q7ZXIc1l/e5RPjyvJtCs1V8JJsvHOMebQn1eCJbAldlTp3aqzEYIyMVreyCus04ZkCGdnHI1q7v3EmVeEfwXSnxXZrLar82j8DeegriHCMJofpRyCvUNFJ2jZBw9KrWO3TaYf7bT6spjhQJDPWteKFMfgt3HMaNbv8OdbQVoGzM3PpWxWMZvELSslKOeDC8Esd1IfiHjPBsdx/Hc80E5JXEhsj61+ggWdQYfso1ex+FgZqyxwjSrD+4TDdAFoN8G5lYPObBBa4zN2IsGvWMKZkiIVaJce/H5NoiBhYItSDAczm+edZ+LJki954Hm0gLE2NyD8N6RfGiGxYBcZBryzcgEIpvE1QY0M+3TRC2RklPEK0jXutGSrmYuW1TC3QmuZP5W7Rcr33uRdLdUa3gkLH05jQwxNwX06z88jAVfVNqpqJuscX1A52qBMOm4lm5P0PRmz6/DA/lntGbDzhbJVvPtEE/Um5QZYrnw5aA4zAz4cZx6Pm+hr2BSKD/3PObFO6l0nXAomy6QT+h/M3Ycj0BC3U++mY0UhmOWwJuFeKbeHx4E5qdRPjX5CEFCcDSRprlj6iQdoxhm+jjl9Ui7Fs5ndRLDeqM8kxHYe0bFoi2EfasglqnibKotfTgMSHnwRA= + on_success: change diff --git a/AUTHORS.md b/AUTHORS.md index 62f2a88..3849918 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,3 +1,3 @@ # Authors ordered by first contribution -* Alasdair Mercer +* Alasdair Mercer diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd753e5..1d95bfe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,10 @@ # Contributing -If you have any questions about [ServiceLoader](https://github.com/Skelp/node-service-loader) please feel free to -[raise an issue](https://github.com/Skelp/node-service-loader/issues/new). +If you have any questions about [ServiceLoader](https://github.com/NotNinja/node-service-loader) please feel free to +[raise an issue](https://github.com/NotNinja/node-service-loader/issues/new). -Please [search existing issues](https://github.com/Skelp/node-service-loader/issues) for the same feature and/or issue -before raising a new issue. Commenting on an existing issue is usually preferred over raising duplicate issues. +Please [search existing issues](https://github.com/NotNinja/node-service-loader/issues) for the same feature and/or +issue before raising a new issue. Commenting on an existing issue is usually preferred over raising duplicate issues. Please ensure that all files conform to the coding standards, using the same coding style as the rest of the code base. All unit tests should be updated and passing as well. All of this can easily be checked via command-line: @@ -21,5 +21,5 @@ You must have at least [Node.js](https://nodejs.org) 4 or newer. All pull requests should be made to the `develop` branch. Don't forget to add your details to the list of -[AUTHORS.md](https://github.com/Skelp/node-service-loader/blob/master/AUTHORS.md) if you want your contribution to be +[AUTHORS.md](https://github.com/NotNinja/node-service-loader/blob/master/AUTHORS.md) if you want your contribution to be recognized by others. diff --git a/LICENSE.md b/LICENSE.md index c1f46b7..6cc536a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (C) 2017 Alasdair Mercer, Skelp +Copyright (C) 2017 Alasdair Mercer, !ninja Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3f3e1eb..206d4c7 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,25 @@ - .d8888b. d8b 888 888 - d88P Y88b Y8P 888 888 - Y88b. 888 888 - "Y888b. .d88b. 888d888 888 888 888 .d8888b .d88b. 888 .d88b. 8888b. .d88888 .d88b. 888d888 - "Y88b. d8P Y8b 888P" 888 888 888 d88P" d8P Y8b 888 d88""88b "88b d88" 888 d8P Y8b 888P" - "888 88888888 888 Y88 88P 888 888 88888888 888 888 888 .d888888 888 888 88888888 888 - Y88b d88P Y8b. 888 Y8bd8P 888 Y88b. Y8b. 888 Y88..88P 888 888 Y88b 888 Y8b. 888 - "Y8888P" "Y8888 888 Y88P 888 "Y8888P "Y8888 88888888 "Y88P" "Y888888 "Y88888 "Y8888 888 - -[ServiceLoader](https://github.com/Skelp/node-service-loader) is a service provider loader. - -[![Build](https://img.shields.io/travis/Skelp/node-service-loader/develop.svg?style=flat-square)](https://travis-ci.org/Skelp/node-service-loader) -[![Coverage](https://img.shields.io/coveralls/Skelp/node-service-loader/develop.svg?style=flat-square)](https://coveralls.io/github/Skelp/node-service-loader) -[![Dependencies](https://img.shields.io/david/Skelp/node-service-loader.svg?style=flat-square)](https://david-dm.org/Skelp/node-service-loader) -[![Dev Dependencies](https://img.shields.io/david/dev/Skelp/node-service-loader.svg?style=flat-square)](https://david-dm.org/Skelp/node-service-loader#info=devDependencies) -[![License](https://img.shields.io/npm/l/service-loader.svg?style=flat-square)](https://github.com/Skelp/node-service-loader/blob/master/LICENSE.md) + d8b + Y8P + + .d8888b .d88b. 888d888 888 888 888 .d8888b .d88b. + 88K d8P Y8b 888P" 888 888 888 d88P" d8P Y8b + "Y8888b. 88888888 888 Y88 88P 888 888 88888888 + X88 Y8b. 888 Y8bd8P 888 Y88b. Y8b. 888 + 88888P' "Y8888 888 Y88P 888 "Y8888P "Y8888 888 + 888 888 + 888 .d88b. 8888b. .d88888 .d88b. 888d888 + 888 d88""88b "88b d88" 888 d8P Y8b 888P" + 888 888 888 .d888888 888 888 88888888 888 + 888 Y88..88P 888 888 Y88b 888 Y8b. 888 + 888 "Y88P" "Y888888 "Y88888 "Y8888 888 + +[ServiceLoader](https://github.com/NotNinja/node-service-loader) is a service provider loader. + +[![Build](https://img.shields.io/travis/NotNinja/node-service-loader/develop.svg?style=flat-square)](https://travis-ci.org/NotNinja/node-service-loader) +[![Coverage](https://img.shields.io/codecov/c/github/NotNinja/node-service-loader/develop.svg?style=flat-square)](https://codecov.io/gh/NotNinja/node-service-loader) +[![Dependencies](https://img.shields.io/david/NotNinja/node-service-loader.svg?style=flat-square)](https://david-dm.org/NotNinja/node-service-loader) +[![Dev Dependencies](https://img.shields.io/david/dev/NotNinja/node-service-loader.svg?style=flat-square)](https://david-dm.org/NotNinja/node-service-loader?type=dev) +[![License](https://img.shields.io/npm/l/service-loader.svg?style=flat-square)](https://github.com/NotNinja/node-service-loader/blob/master/LICENSE.md) [![Release](https://img.shields.io/npm/v/service-loader.svg?style=flat-square)](https://www.npmjs.com/package/service-loader) * [Install](#install) @@ -32,9 +38,10 @@ You'll need to have at least [Node.js](https://nodejs.org) 4 or newer. ## API -### `load(service[, packageName])` +### `load(serviceName[, packageName][, options])` TODO: Document + TODO: Example(s) ### `version` @@ -42,30 +49,29 @@ TODO: Example(s) The current version of ServiceLoader. ``` javascript -const ServiceLoader = require('service-loader') +const ServiceLoader = require('service-loader'); -ServiceLoader.version -=> "0.1.0alpha" +ServiceLoader.version; +=> "0.1.0" ``` ## Bugs If you have any problems with ServiceLoader or would like to see changes currently in development you can do so -[here](https://github.com/Skelp/node-service-loader/issues). +[here](https://github.com/NotNinja/node-service-loader/issues). ## Contributors If you want to contribute, you're a legend! Information on how you can do so can be found in -[CONTRIBUTING.md](https://github.com/Skelp/node-service-loader/blob/master/CONTRIBUTING.md). We want your suggestions +[CONTRIBUTING.md](https://github.com/NotNinja/node-service-loader/blob/master/CONTRIBUTING.md). We want your suggestions and pull requests! A list of ServiceLoader contributors can be found in -[AUTHORS.md](https://github.com/Skelp/node-service-loader/blob/master/AUTHORS.md). +[AUTHORS.md](https://github.com/NotNinja/node-service-loader/blob/master/AUTHORS.md). ## License -See [LICENSE.md](https://github.com/Skelp/node-service-loader/raw/master/LICENSE.md) for more information on our MIT +See [LICENSE.md](https://github.com/NotNinja/node-service-loader/raw/master/LICENSE.md) for more information on our MIT license. -© 2017 [Skelp](https://skelp.io) - +[![Copyright !ninja](https://cdn.rawgit.com/NotNinja/branding/master/assets/copyright/base/not-ninja-copyright-186x25.png)](https://not.ninja) diff --git a/package.json b/package.json index f31cf1b..a23872b 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "service-loader", - "version": "0.1.0alpha", + "version": "0.1.0", "description": "A service provider loader", - "homepage": "https://github.com/Skelp/node-service-loader", + "homepage": "https://github.com/NotNinja/node-service-loader", "bugs": { - "url": "https://github.com/Skelp/node-service-loader/issues" + "url": "https://github.com/NotNinja/node-service-loader/issues" }, "author": { "name": "Alasdair Mercer", - "email": "alasdair@skelp.io", - "url": "https://skelp.io" + "email": "mercer.alasdair@gmail.com", + "url": "https://not.ninja" }, "license": "MIT", "keywords": [ @@ -20,27 +20,31 @@ ], "repository": { "type": "git", - "url": "https://github.com/Skelp/node-service-loader.git" + "url": "https://github.com/NotNinja/node-service-loader.git" }, "dependencies": { - "debug": "^2.6.1", - "knockknock": "^0.2.0", + "debug": "*", + "knockknock": "^0.3.0", "lodash.forown": "^4.4.0", - "pacscan": "^0.1.0" + "pacscan": "^0.2.0" }, "devDependencies": { "chai": "^3.5.0", - "coveralls": "^2.11.16", - "eslint": "^3.15.0", - "eslint-config-skelp": "^0.1.5", + "codecov": "^2.2.0", + "eslint": "^3.19.0", + "eslint-config-notninja": "^0.1.1", "istanbul": "^0.4.5", - "mocha": "^3.2.0" + "mkdirp": "^0.5.1", + "mocha": "^3.4.1", + "ncp": "^2.0.0", + "tmp": "0.0.31" }, "main": "src/service-loader.js", "scripts": { - "report-coverage": "istanbul cover _mocha --report lcovonly -- -R spec \"test/**/*.spec.js\" && coveralls < coverage/lcov.info", + "ci": "npm run test", + "report-coverage": "istanbul cover _mocha --report lcovonly -- -R list \"test/**/*.spec.js\" && codecov", "pretest": "eslint \"src/**/*.js\" \"test/**/*.js\"", - "test": "istanbul cover _mocha -- -R spec \"test/**/*.spec.js\"", + "test": "istanbul cover _mocha -- -R list \"test/**/*.spec.js\"", "posttest": "istanbul check-coverage" }, "engines": { diff --git a/src/service-loader.js b/src/service-loader.js index ebfb98a..179da8f 100644 --- a/src/service-loader.js +++ b/src/service-loader.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,15 +20,15 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const debug = require('debug')('service-loader') -const forOwn = require('lodash.forown') -const pacscan = require('pacscan') -const path = require('path') -const whoIsThere = require('knockknock') +const debug = require('debug')('service-loader'); +const forOwn = require('lodash.forown'); +const pacscan = require('pacscan'); +const path = require('path'); +const whoIsThere = require('knockknock'); -const version = require('../package.json').version +const version = require('../package.json').version; /** * The regular expression used to check whether the string representation of a function indicates that it is in fact an @@ -37,7 +37,7 @@ const version = require('../package.json').version * @private * @type {RegExp} */ -const rClass = /^class\s+/ +const rClass = /^class\s+/; /** * TODO: Document @@ -49,27 +49,27 @@ const rClass = /^class\s+/ class ServiceLoader { /** - * Creates an instance of {@link ServiceLoader} for the specified service using the options - * provided. + * Creates an instance of {@link ServiceLoader} for the service with the specified name belonging to the named package + * and using the options provided. * - * If service is a function, then the name of that function will be used to lookup service providers. If - * no packageName option is specified, then the name of the package that called this method will be used - * instead. + * If packageName is not specified or is null, then the name of the package that called this + * method will be used instead. * * Consumers can control what modules/packages are considered during the search for the calling package via the * knockknock option, however, the limit will always be overridden to 1. * - * @param {string|Function} service - the name of the service (or the service function, only if not anonymous) whose - * providers are to be loaded + * @param {string} serviceName - the name of the service whose providers are to be loaded + * @param {string} [packageName] - the name of the package for which the services are loaded (may be + * null) * @param {ServiceLoader~Options} [options] - the options to be used (may be null) - * @return {ServiceLoader} The {@link ServiceLoader} to be used to load providers for service. - * @throws {Error} If service is not provided or the package name could not be resolved from the caller - * and the packageName option was not specified. + * @return {ServiceLoader} The {@link ServiceLoader} to be used to load providers for the named service. + * @throws {Error} If service is not provided or if packageName is not provided and the + * package name could not be resolved from the caller. * @public * @static */ - static load(service, options) { - return new ServiceLoader(service, options) + static load(serviceName, packageName, options) { + return new ServiceLoader(serviceName, packageName, options); } /** @@ -80,7 +80,7 @@ class ServiceLoader { * @type {string} */ static get version() { - return version + return version; } /** @@ -94,13 +94,13 @@ class ServiceLoader { * @static */ static _findCaller(options) { - options = Object.assign({}, options, { limit: 1 }) + options = Object.assign({}, options, { limit: 1 }); - const excludes = [ 'service-loader' ] + const excludes = [ 'service-loader' ]; - options.excludes = options.excludes ? excludes.concat(options.excludes) : excludes + options.excludes = options.excludes ? excludes.concat(options.excludes) : excludes; - return whoIsThere.sync(options)[0] + return whoIsThere.sync(options)[0]; } /** @@ -112,7 +112,7 @@ class ServiceLoader { * @static */ static _isClass(obj) { - return typeof obj === 'function' && rClass.test(obj.toString()) + return typeof obj === 'function' && rClass.test(obj.toString()); } /** @@ -127,59 +127,57 @@ class ServiceLoader { */ static _parseOptions(options) { if (!options) { - options = {} + options = {}; } - let packageName = options.packageName - if (!packageName) { - const caller = ServiceLoader._findCaller(options.knockknock) - packageName = caller != null && caller.pkg != null ? caller.pkg.name : null - } - - return { - knockknock: options.knockknock, - packageName - } + return { knockknock: options.knockknock }; } /** - * Creates an instance of {@link ServiceLoader} for the specified service using the options - * provided. + * Creates an instance of {@link ServiceLoader} for the service with the specified name belonging to the named package + * and using the options provided. * - * If service is a function, then the name of that function will be used to lookup service providers. If - * no packageName option is specified, then the name of the package that called this constructor will be - * used instead. + * If packageName is not specified or is null, then the name of the package that called this + * constructor will be used instead. * * Consumers can control what modules/packages are considered during the search for the calling package via the * knockknock option, however, the limit will always be overridden to 1. * - * @param {string|Function} service - the name of the service (or the service function, only if not anonymous) whose - * providers are to be loaded + * @param {string} serviceName - the name of the service whose providers are to be loaded + * @param {string} [packageName] - the name of the package for which the services are loaded (may be + * null) * @param {ServiceLoader~Options} [options] - the options to be used (may be null) - * @throws {Error} If service is not provided or the package name could not be resolved from the caller - * and the packageName option was not specified. + * @throws {Error} If service is not provided or if packageName is not provided and the + * package name could not be resolved from the caller. * @public */ - constructor(service, options) { - options = ServiceLoader._parseOptions(options) + constructor(serviceName, packageName, options) { + if (!options && typeof packageName === 'object') { + options = packageName; + packageName = null; + } - const serviceName = typeof service === 'function' ? service.name : service - const packageName = options.packageName + options = ServiceLoader._parseOptions(options); + + if (!packageName) { + const caller = ServiceLoader._findCaller(options.knockknock); + packageName = caller != null && caller.pkg != null ? caller.pkg.name : null; + } if (!serviceName) { - throw new Error('service must be provided') + throw new Error('serviceName must be specified'); } if (!packageName) { - throw new Error('packageName option must be provided as cannot resolve calling package') + throw new Error('packageName must be specified as cannot resolve calling package'); } /** - * The parsed options for this {@link ServiceLoader}. + * The name of the service whose providers are to be loaded by this {@link ServiceLoader}. * * @private - * @type {ServiceLoader~Options} + * @type {string} */ - this._options = options + this._serviceName = serviceName; /** * The name of the package whose named service the providers are to be loaded by this {@link ServiceLoader}. @@ -187,7 +185,15 @@ class ServiceLoader { * @private * @type {string} */ - this._packageName = packageName + this._packageName = packageName; + + /** + * The parsed options for this {@link ServiceLoader}. + * + * @private + * @type {ServiceLoader~Options} + */ + this._options = options; /** * The file paths of loaded providers mapped to their corresponding loaded provider. @@ -201,17 +207,9 @@ class ServiceLoader { * @private * @type {?Map.} */ - this._providers = null - - /** - * The name of the service whose providers are to be loaded by this {@link ServiceLoader}. - * - * @private - * @type {string} - */ - this._serviceName = serviceName + this._providers = null; - debug('Loaded ServiceLoader for "%s" service in "%s" package', serviceName, packageName) + debug('Loaded ServiceLoader for "%s" service in "%s" package', serviceName, packageName); } /** @@ -221,16 +219,17 @@ class ServiceLoader { if (!this._providers) { const packages = pacscan.sync({ includeParents: true, + knockknock: this._options.knockknock, path: __filename - }) - const providers = new Map() + }); + const providers = new Map(); - packages.forEach((pkg) => this._loadPackage(pkg, providers)) + packages.forEach((pkg) => this._loadPackage(pkg, providers)); - this._providers = providers + this._providers = providers; } - yield* this._providers.values() + yield* this._providers.values(); } /** @@ -240,14 +239,14 @@ class ServiceLoader { * @public */ reload() { - this._providers = null + this._providers = null; } /** * @override */ toString() { - return `ServiceLoader[${this._serviceName}]` + return `ServiceLoader[${this._serviceName}]`; } /** @@ -263,15 +262,15 @@ class ServiceLoader { * @private */ _loadPackage(pkg, providers) { - debug('Attempting to load package "%s"', pkg.name) + debug('Attempting to load package "%s"', pkg.name); - const packageJson = require(path.join(pkg.directory, 'package.json')) + const packageJson = require(path.join(pkg.directory, 'package.json')); forOwn(packageJson.services, (services, servicePackageName) => { if (servicePackageName === this._packageName) { - this._loadServiceProviders(pkg, services, providers) + this._loadServiceProviders(pkg, services, providers); } - }) + }); } /** @@ -286,15 +285,15 @@ class ServiceLoader { * @private */ _loadProvider(filePath) { - debug('Loading "%s" provider for "%s" service in "%s" package', filePath, this._serviceName, this._packageName) + debug('Loading "%s" provider for "%s" service in "%s" package', filePath, this._serviceName, this._packageName); - const provider = require(filePath) + const provider = require(filePath); if (ServiceLoader._isClass(provider)) { - const ProviderConstructor = provider - return new ProviderConstructor() + const ProviderConstructor = provider; + return new ProviderConstructor(); } - return provider + return provider; } /** @@ -315,21 +314,21 @@ class ServiceLoader { */ _loadServiceProviders(pkg, services, providers) { forOwn(services, (service, serviceName) => { - service = typeof service === 'string' ? { path: service } : service + service = typeof service === 'string' ? { path: service } : service; if (serviceName === this._serviceName && service && service.path) { - const providerPath = path.resolve(pkg.directory, service.path) + const providerPath = path.resolve(pkg.directory, service.path); if (!providers.has(providerPath)) { - providers.set(providerPath, this._loadProvider(providerPath)) + providers.set(providerPath, this._loadProvider(providerPath)); } } - }) + }); } } -module.exports = ServiceLoader +module.exports = ServiceLoader; /** * The options to be used to load service providers. @@ -337,7 +336,6 @@ module.exports = ServiceLoader * @typedef {Object} ServiceLoader~Options * @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} [packageName] - The name of the package for which the services are loaded. */ /** diff --git a/test/.eslintrc.json b/test/.eslintrc.json index ba3ed6c..96e76ad 100644 --- a/test/.eslintrc.json +++ b/test/.eslintrc.json @@ -2,5 +2,9 @@ "extends": "../.eslintrc.json", "env": { "mocha": true + }, + "rules": { + "func-name-matching": "off", + "no-unused-expressions": "off" } } diff --git a/test/fixtures/node_modules/mod-c/src/index.js b/test/fixtures/dependencies/node_modules/@scope/buzz/index.js similarity index 77% rename from test/fixtures/node_modules/mod-c/src/index.js rename to test/fixtures/dependencies/node_modules/@scope/buzz/index.js index 0546da4..f05a468 100644 --- a/test/fixtures/node_modules/mod-c/src/index.js +++ b/test/fixtures/dependencies/node_modules/@scope/buzz/index.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const debug = require('debug')('service-loader') - -const ServiceLoader = require('../../../../../src/service-loader') - -const services = ServiceLoader.load('foo', { packageName: 'service-loader-example' }) - -debug(Array.from(services)) - -module.exports = services +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/dependencies/node_modules/@scope/buzz/package.json b/test/fixtures/dependencies/node_modules/@scope/buzz/package.json new file mode 100644 index 0000000..97ad959 --- /dev/null +++ b/test/fixtures/dependencies/node_modules/@scope/buzz/package.json @@ -0,0 +1,6 @@ +{ + "name": "@fu/buzz", + "version": "1.3.2", + "main": "index.js", + "private": true +} diff --git a/test/fixtures/node_modules/mod-b/src/index.js b/test/fixtures/dependencies/node_modules/@scope/fizz/index.js similarity index 77% rename from test/fixtures/node_modules/mod-b/src/index.js rename to test/fixtures/dependencies/node_modules/@scope/fizz/index.js index 0546da4..67eb692 100644 --- a/test/fixtures/node_modules/mod-b/src/index.js +++ b/test/fixtures/dependencies/node_modules/@scope/fizz/index.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const debug = require('debug')('service-loader') - -const ServiceLoader = require('../../../../../src/service-loader') - -const services = ServiceLoader.load('foo', { packageName: 'service-loader-example' }) - -debug(Array.from(services)) - -module.exports = services +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/dependencies/node_modules/@scope/fizz/package.json b/test/fixtures/dependencies/node_modules/@scope/fizz/package.json new file mode 100644 index 0000000..06461db --- /dev/null +++ b/test/fixtures/dependencies/node_modules/@scope/fizz/package.json @@ -0,0 +1,6 @@ +{ + "name": "@fu/fizz", + "version": "1.3.1", + "main": "index.js", + "private": true +} diff --git a/test/fixtures/node_modules/mod-a/src/index.js b/test/fixtures/dependencies/node_modules/bar/index.js similarity index 77% rename from test/fixtures/node_modules/mod-a/src/index.js rename to test/fixtures/dependencies/node_modules/bar/index.js index 0546da4..ea8100a 100644 --- a/test/fixtures/node_modules/mod-a/src/index.js +++ b/test/fixtures/dependencies/node_modules/bar/index.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const debug = require('debug')('service-loader') - -const ServiceLoader = require('../../../../../src/service-loader') - -const services = ServiceLoader.load('foo', { packageName: 'service-loader-example' }) - -debug(Array.from(services)) - -module.exports = services +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/node_modules/mod-c/package.json b/test/fixtures/dependencies/node_modules/bar/package.json similarity index 53% rename from test/fixtures/node_modules/mod-c/package.json rename to test/fixtures/dependencies/node_modules/bar/package.json index 6c6b38a..041b9ce 100644 --- a/test/fixtures/node_modules/mod-c/package.json +++ b/test/fixtures/dependencies/node_modules/bar/package.json @@ -1,6 +1,6 @@ { - "name": "mod-c", + "name": "bar", "version": "1.2.0", - "services": {}, + "main": "./index", "private": true } diff --git a/test/fixtures/node_modules/mod-a/node_modules/mod-a2/src/index.js b/test/fixtures/dependencies/node_modules/foo/index.js similarity index 77% rename from test/fixtures/node_modules/mod-a/node_modules/mod-a2/src/index.js rename to test/fixtures/dependencies/node_modules/foo/index.js index aad4c85..ad64d5c 100644 --- a/test/fixtures/node_modules/mod-a/node_modules/mod-a2/src/index.js +++ b/test/fixtures/dependencies/node_modules/foo/index.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const debug = require('debug')('service-loader') - -const ServiceLoader = require('../../../../../../src/service-loader') - -const services = ServiceLoader.load('foo', { packageName: 'service-loader-example' }) - -debug(Array.from(services)) - -module.exports = services +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/node_modules/mod-b/package.json b/test/fixtures/dependencies/node_modules/foo/package.json similarity index 53% rename from test/fixtures/node_modules/mod-b/package.json rename to test/fixtures/dependencies/node_modules/foo/package.json index 0d5be2e..63620cc 100644 --- a/test/fixtures/node_modules/mod-b/package.json +++ b/test/fixtures/dependencies/node_modules/foo/package.json @@ -1,6 +1,6 @@ { - "name": "mod-b", + "name": "foo", "version": "1.1.0", - "services": {}, + "main": "index.js", "private": true } diff --git a/test/fixtures/dependencies/package.json b/test/fixtures/dependencies/package.json new file mode 100644 index 0000000..d563f30 --- /dev/null +++ b/test/fixtures/dependencies/package.json @@ -0,0 +1,6 @@ +{ + "name": "flat", + "version": "1.0.0", + "main": "src/index.js", + "private": true +} diff --git a/test/fixtures/dependencies/src/index.js b/test/fixtures/dependencies/src/index.js new file mode 100644 index 0000000..39057a9 --- /dev/null +++ b/test/fixtures/dependencies/src/index.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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 dependenciesFunction(serviceLoaderPath, serviceName, packageName, options) { + return require(serviceLoaderPath).load(serviceName, packageName, options); +}; diff --git a/test/fixtures/node_modules/@scope/mod-d/package.json b/test/fixtures/node_modules/@scope/mod-d/package.json deleted file mode 100644 index 75f0ae0..0000000 --- a/test/fixtures/node_modules/@scope/mod-d/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "@scope/mod-d", - "version": "1.3.0", - "services": {}, - "private": true -} diff --git a/test/fixtures/node_modules/mod-a/node_modules/mod-a2/package.json b/test/fixtures/node_modules/mod-a/node_modules/mod-a2/package.json deleted file mode 100644 index b6c55e6..0000000 --- a/test/fixtures/node_modules/mod-a/node_modules/mod-a2/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "mod-a2", - "version": "2.0.0", - "services": {}, - "private": true -} diff --git a/test/fixtures/node_modules/mod-a/node_modules/mod-b/package.json b/test/fixtures/node_modules/mod-a/node_modules/mod-b/package.json deleted file mode 100644 index f79562a..0000000 --- a/test/fixtures/node_modules/mod-a/node_modules/mod-b/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "mod-b", - "version": "2.1.0", - "services": {}, - "private": true -} diff --git a/test/fixtures/node_modules/mod-a/node_modules/mod-b/src/index.js b/test/fixtures/node_modules/mod-a/node_modules/mod-b/src/index.js deleted file mode 100644 index aad4c85..0000000 --- a/test/fixtures/node_modules/mod-a/node_modules/mod-b/src/index.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 debug = require('debug')('service-loader') - -const ServiceLoader = require('../../../../../../src/service-loader') - -const services = ServiceLoader.load('foo', { packageName: 'service-loader-example' }) - -debug(Array.from(services)) - -module.exports = services diff --git a/test/fixtures/node_modules/mod-a/package.json b/test/fixtures/node_modules/mod-a/package.json deleted file mode 100644 index 5187f2c..0000000 --- a/test/fixtures/node_modules/mod-a/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "mod-a", - "version": "1.0.0", - "dependencies": { - "mod-a2": "2.0.0", - "mod-b": "2.1.0" - }, - "services": {}, - "private": true -} diff --git a/test/fixtures/package.json b/test/fixtures/package.json deleted file mode 100644 index 827bd3b..0000000 --- a/test/fixtures/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "service-loader-fixtures", - "version": "1.2.3", - "dependencies": { - "mod-a": "1.0.0", - "mod-b": "1.1.0", - "mod-c": "1.2.0" - }, - "services": {}, - "private": true -} diff --git a/test/fixtures/services-none/package.json b/test/fixtures/services-none/package.json new file mode 100644 index 0000000..4fff424 --- /dev/null +++ b/test/fixtures/services-none/package.json @@ -0,0 +1,6 @@ +{ + "name": "services-none", + "version": "1.0.0", + "main": "src/index.js", + "private": true +} diff --git a/test/fixtures/services-none/src/index.js b/test/fixtures/services-none/src/index.js new file mode 100644 index 0000000..d03aaf2 --- /dev/null +++ b/test/fixtures/services-none/src/index.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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 servicesNoneFunction(serviceLoaderPath, serviceName, packageName, options) { + return require(serviceLoaderPath).load(serviceName, packageName, options); +}; diff --git a/test/fixtures/unpackaged-single/index.js b/test/fixtures/unpackaged-single/index.js new file mode 100644 index 0000000..34afceb --- /dev/null +++ b/test/fixtures/unpackaged-single/index.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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(serviceLoaderPath, serviceName, packageName, options) { + return require(serviceLoaderPath).load(serviceName, packageName, options); +}; diff --git a/test/fixtures/unpackaged/index.js b/test/fixtures/unpackaged/index.js new file mode 100644 index 0000000..06f5fbe --- /dev/null +++ b/test/fixtures/unpackaged/index.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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(serviceLoaderPath, serviceName, packageName, options) { + return require(serviceLoaderPath).load(serviceName, packageName, options); +}; diff --git a/test/fixtures/unpackaged/node_modules/bar/package.json b/test/fixtures/unpackaged/node_modules/bar/package.json new file mode 100644 index 0000000..dea6c89 --- /dev/null +++ b/test/fixtures/unpackaged/node_modules/bar/package.json @@ -0,0 +1,6 @@ +{ + "name": "bar", + "version": "1.2.0", + "main": "src/index.js", + "private": true +} diff --git a/test/fixtures/unpackaged/node_modules/bar/src/index.js b/test/fixtures/unpackaged/node_modules/bar/src/index.js new file mode 100644 index 0000000..b36638d --- /dev/null +++ b/test/fixtures/unpackaged/node_modules/bar/src/index.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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(serviceLoaderPath, serviceName, packageName, options) { + return require(serviceLoaderPath).load(serviceName, packageName, options); +}; 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..51d4621 --- /dev/null +++ b/test/fixtures/unpackaged/node_modules/foo/package.json @@ -0,0 +1,6 @@ +{ + "name": "foo", + "version": "1.1.0", + "main": "src/index.js", + "private": true +} diff --git a/test/fixtures/unpackaged/node_modules/foo/src/index.js b/test/fixtures/unpackaged/node_modules/foo/src/index.js new file mode 100644 index 0000000..da57f1b --- /dev/null +++ b/test/fixtures/unpackaged/node_modules/foo/src/index.js @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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(serviceLoaderPath, serviceName, packageName, options) { + return require(serviceLoaderPath).load(serviceName, packageName, options); +}; diff --git a/test/helpers.js b/test/helpers.js new file mode 100644 index 0000000..49e4699 --- /dev/null +++ b/test/helpers.js @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2017 Alasdair Mercer, !ninja + * + * 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 {ServiceLoader~Options} [options] - the options to be used (may be null) + * @return {ServiceLoader~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 ServiceLoader by themselves. For this reason, this method returns a proxy to these fixtures + * so that it can pass the absolute path to require ServiceLoader within the fixture while also ensuring that the + * options 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. + * @public + * @static + */ +exports.requireFromFixture = function requireFromFixture(name, filePath) { + const fixture = require(exports.resolveFixtureFile(name, filePath)); + const serviceLoaderPath = path.resolve(__dirname, '../src/service-loader'); + + return function proxy(serviceName, packageName, options) { + if (!options && typeof packageName === 'object') { + options = packageName; + packageName = null; + } + + return fixture(serviceLoaderPath, serviceName, packageName, exports.createOptions(options)); + }; +}; + +/** + * 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); +}; diff --git a/test/service-loader.spec.js b/test/service-loader.spec.js index af6c0a9..c5c6c66 100644 --- a/test/service-loader.spec.js +++ b/test/service-loader.spec.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,19 +20,19 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const expect = require('chai').expect +const expect = require('chai').expect; -const ServiceLoader = require('../src/service-loader') -const version = require('../package.json').version +const ServiceLoader = require('../src/service-loader'); +const version = require('../package.json').version; describe('ServiceLoader', () => { // TODO: Complete describe('.version', () => { it('should match package version', () => { - expect(ServiceLoader.version).to.equal(version) - }) - }) -}) + expect(ServiceLoader.version).to.equal(version); + }); + }); +}); diff --git a/test/fixtures/node_modules/@scope/mod-d/src/index.js b/test/service-loader.unpackage-single.spec.js similarity index 54% rename from test/fixtures/node_modules/@scope/mod-d/src/index.js rename to test/service-loader.unpackage-single.spec.js index 458d52b..4332283 100644 --- a/test/fixtures/node_modules/@scope/mod-d/src/index.js +++ b/test/service-loader.unpackage-single.spec.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Alasdair Mercer, Skelp + * Copyright (C) 2017 Alasdair Mercer, !ninja * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,15 +20,31 @@ * SOFTWARE. */ -'use strict' +'use strict'; -const debug = require('debug')('service-loader') +const expect = require('chai').expect; -const ServiceLoader = require('../../../../../../src/service-loader') +const helpers = require('./helpers'); -const services = ServiceLoader.load('foo', { packageName: 'service-loader-example' }) +describe('service-loader:fixture:unpackaged-single', () => { + before(() => helpers.copyFixture('unpackaged-single')); -debug(Array.from(services)) + context('when called with package name', () => { + it('should be empty', () => { + const unpackagedSingle = helpers.requireFromFixture('unpackaged-single', 'index.js'); + const providers = Array.from(unpackagedSingle('foo', 'bar')); -module.exports = services + expect(providers).to.be.empty; + }); + }); + context('when called without package name', () => { + it('should throw an error', () => { + const unpackagedSingle = helpers.requireFromFixture('unpackaged-single', 'index.js'); + + expect(() => { + unpackagedSingle('foo'); + }).to.throw(Error, /packageName must be specified as cannot resolve calling package/); + }); + }); +});