From fbc528b690b4aa00095bc96fd68bacc447cbc0d9 Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Sun, 11 Sep 2022 23:42:38 -0500 Subject: [PATCH 1/5] refactor(plugins): switched from `require` to `await import()` when loading plugins to isolate the conversion ahead of #2543 --- lib/definitions/errors.js | 2 +- lib/plugins/index.js | 72 ++++++++++++++++++++-------------- lib/plugins/normalize.js | 6 ++- lib/plugins/utils.js | 4 +- test/plugins/normalize.test.js | 57 ++++++++++++++------------- test/plugins/plugins.test.js | 45 ++++++++++----------- test/plugins/utils.test.js | 8 ++-- 7 files changed, 105 insertions(+), 89 deletions(-) diff --git a/lib/definitions/errors.js b/lib/definitions/errors.js index c109f2afab..dad72ba4bc 100644 --- a/lib/definitions/errors.js +++ b/lib/definitions/errors.js @@ -68,7 +68,7 @@ Your configuration for the \`${type}\` plugin is \`${stringify(pluginConf)}\`.`, message: 'The `plugins` configuration is invalid.', details: `The [plugins](${linkify( 'docs/usage/configuration.md#plugins' - )}) option must be an array of plugin definions. A plugin definition is an npm module name, optionally wrapped in an array with an object. + )}) option must be an array of plugin definitions. A plugin definition is an npm module name, optionally wrapped in an array with an object. The invalid configuration is \`${stringify(plugin)}\`.`, }), diff --git a/lib/plugins/index.js b/lib/plugins/index.js index 7fd2286380..982ee9c20f 100644 --- a/lib/plugins/index.js +++ b/lib/plugins/index.js @@ -6,36 +6,41 @@ const {validatePlugin, validateStep, loadPlugin, parseConfig} = require('./utils const pipeline = require('./pipeline'); const normalize = require('./normalize'); -module.exports = (context, pluginsPath) => { +module.exports = async (context, pluginsPath) => { let {options, logger} = context; const errors = []; const plugins = options.plugins - ? castArray(options.plugins).reduce((plugins, plugin) => { - if (validatePlugin(plugin)) { - const [name, config] = parseConfig(plugin); - plugin = isString(name) ? loadPlugin(context, name, pluginsPath) : name; + ? await castArray(options.plugins).reduce(async (plugins, plugin) => { + const plugins2 = await plugins; + if (validatePlugin(plugin)) { + const [name, config] = parseConfig(plugin); + plugin = isString(name) ? await loadPlugin(context, name, pluginsPath) : name; - if (isPlainObject(plugin)) { - Object.entries(plugin).forEach(([type, func]) => { - if (PLUGINS_DEFINITIONS[type]) { - Reflect.defineProperty(func, 'pluginName', { - value: isPlainObject(name) ? 'Inline plugin' : name, - writable: false, - enumerable: true, - }); - plugins[type] = [...(plugins[type] || []), [func, config]]; - } - }); - } else { - errors.push(getError('EPLUGINSCONF', {plugin})); - } + console.log({plugins: options.plugins}) + console.dir(plugin, {depth: null}) + console.log(isPlainObject(plugin)) + if (isPlainObject(plugin)) { + Object.entries(plugin).forEach(([type, func]) => { + console.log({type, name}) + if (PLUGINS_DEFINITIONS[type]) { + Reflect.defineProperty(func, 'pluginName', { + value: isPlainObject(name) ? 'Inline plugin' : name, + writable: false, + enumerable: true, + }); + plugins2[type] = [...(plugins2[type] || []), [func, config]]; + } + }); } else { errors.push(getError('EPLUGINSCONF', {plugin})); } + } else { + errors.push(getError('EPLUGINSCONF', {plugin})); + } - return plugins; - }, {}) + return plugins2; + }, {}) : []; if (errors.length > 0) { @@ -44,9 +49,16 @@ module.exports = (context, pluginsPath) => { options = {...plugins, ...options}; - const pluginsConf = Object.entries(PLUGINS_DEFINITIONS).reduce( - (pluginsConf, [type, {required, default: def, pipelineConfig, postprocess = identity, preprocess = identity}]) => { + const pluginsConf = await Object.entries(PLUGINS_DEFINITIONS).reduce( + async (pluginsConf, [type, { + required, + default: def, + pipelineConfig, + postprocess = identity, + preprocess = identity + }]) => { let pluginOptions; + const pluginsConf2 = await pluginsConf; if (isNil(options[type]) && def) { pluginOptions = def; @@ -60,28 +72,28 @@ module.exports = (context, pluginsPath) => { if (!validateStep({required}, options[type])) { errors.push(getError('EPLUGINCONF', {type, required, pluginConf: options[type]})); - return pluginsConf; + return pluginsConf2; } pluginOptions = options[type]; } - const steps = castArray(pluginOptions).map((pluginOpt) => - normalize( + const steps = await Promise.all(castArray(pluginOptions).map(async (pluginOpt) => + await normalize( {...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), 'plugins')}, type, pluginOpt, pluginsPath ) - ); + )); - pluginsConf[type] = async (input) => + pluginsConf2[type] = async (input) => postprocess( - await pipeline(steps, pipelineConfig && pipelineConfig(pluginsConf, logger))(await preprocess(input)), + await pipeline(steps, pipelineConfig && pipelineConfig(pluginsConf2, logger))(await preprocess(input)), input ); - return pluginsConf; + return pluginsConf2; }, plugins ); diff --git a/lib/plugins/normalize.js b/lib/plugins/normalize.js index c9f2ab62cd..e01dbf4421 100644 --- a/lib/plugins/normalize.js +++ b/lib/plugins/normalize.js @@ -5,7 +5,7 @@ const {extractErrors} = require('../utils'); const PLUGINS_DEFINITIONS = require('../definitions/plugins'); const {loadPlugin, parseConfig} = require('./utils'); -module.exports = (context, type, pluginOpt, pluginsPath) => { +module.exports = async (context, type, pluginOpt, pluginsPath) => { const {stdout, stderr, options, logger} = context; if (!pluginOpt) { return noop; @@ -13,10 +13,12 @@ module.exports = (context, type, pluginOpt, pluginsPath) => { const [name, config] = parseConfig(pluginOpt); const pluginName = name.pluginName ? name.pluginName : isFunction(name) ? `[Function: ${name.name}]` : name; - const plugin = loadPlugin(context, name, pluginsPath); + const plugin = await loadPlugin(context, name, pluginsPath); debug(`options for ${pluginName}/${type}: %O`, config); + console.log({plugin}) + console.dir(plugin, {depth: null}) let func; if (isFunction(plugin)) { func = plugin.bind(null, cloneDeep({...options, ...config})); diff --git a/lib/plugins/utils.js b/lib/plugins/utils.js index 69bba2768b..4c7c38d44d 100644 --- a/lib/plugins/utils.js +++ b/lib/plugins/utils.js @@ -44,11 +44,11 @@ function validateStep({required}, conf) { return conf.length === 0 || validateSteps(conf); } -function loadPlugin({cwd}, name, pluginsPath) { +async function loadPlugin({cwd}, name, pluginsPath) { const basePath = pluginsPath[name] ? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name])) : __dirname; - return isFunction(name) ? name : require(resolveFrom.silent(basePath, name) || resolveFrom(cwd, name)); + return isFunction(name) ? name : (await import(resolveFrom.silent(basePath, name)) || resolveFrom(cwd, name)); } function parseConfig(plugin) { diff --git a/test/plugins/normalize.test.js b/test/plugins/normalize.test.js index 784714b010..725f48d36d 100644 --- a/test/plugins/normalize.test.js +++ b/test/plugins/normalize.test.js @@ -19,8 +19,8 @@ test.beforeEach((t) => { }; }); -test('Normalize and load plugin from string', (t) => { - const plugin = normalize( +test('Normalize and load plugin from string', async (t) => { + const plugin = await normalize( {cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './test/fixtures/plugin-noop', @@ -32,8 +32,8 @@ test('Normalize and load plugin from string', (t) => { t.deepEqual(t.context.success.args[0], ['Loaded plugin "verifyConditions" from "./test/fixtures/plugin-noop"']); }); -test('Normalize and load plugin from object', (t) => { - const plugin = normalize( +test('Normalize and load plugin from object', async (t) => { + const plugin = await normalize( {cwd, options: {}, logger: t.context.logger}, 'publish', {path: './test/fixtures/plugin-noop'}, @@ -45,8 +45,8 @@ test('Normalize and load plugin from object', (t) => { t.deepEqual(t.context.success.args[0], ['Loaded plugin "publish" from "./test/fixtures/plugin-noop"']); }); -test('Normalize and load plugin from a base file path', (t) => { - const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-noop', { +test('Normalize and load plugin from a base file path', async (t) => { + const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-noop', { './plugin-noop': './test/fixtures', }); @@ -58,7 +58,7 @@ test('Normalize and load plugin from a base file path', (t) => { }); test('Wrap plugin in a function that add the "pluginName" to the error"', async (t) => { - const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-error', { + const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-error', { './plugin-error': './test/fixtures', }); @@ -68,7 +68,7 @@ test('Wrap plugin in a function that add the "pluginName" to the error"', async }); test('Wrap plugin in a function that add the "pluginName" to multiple errors"', async (t) => { - const plugin = normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-errors', { + const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './plugin-errors', { './plugin-errors': './test/fixtures', }); @@ -78,16 +78,16 @@ test('Wrap plugin in a function that add the "pluginName" to multiple errors"', } }); -test('Normalize and load plugin from function', (t) => { +test('Normalize and load plugin from function', async (t) => { const pluginFunction = () => {}; - const plugin = normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {}); + const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {}); t.is(plugin.pluginName, '[Function: pluginFunction]'); t.is(typeof plugin, 'function'); }); -test('Normalize and load plugin that retuns multiple functions', (t) => { - const plugin = normalize( +test('Normalize and load plugin that retuns multiple functions', async (t) => { + const plugin = await normalize( {cwd, options: {}, logger: t.context.logger}, 'verifyConditions', './test/fixtures/multi-plugin', @@ -100,7 +100,7 @@ test('Normalize and load plugin that retuns multiple functions', (t) => { test('Wrap "analyzeCommits" plugin in a function that validate the output of the plugin', async (t) => { const analyzeCommits = stub().resolves(2); - const plugin = normalize( + const plugin = await normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'analyzeCommits', analyzeCommits, @@ -118,7 +118,7 @@ test('Wrap "analyzeCommits" plugin in a function that validate the output of the test('Wrap "generateNotes" plugin in a function that validate the output of the plugin', async (t) => { const generateNotes = stub().resolves(2); - const plugin = normalize( + const plugin = await normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'generateNotes', generateNotes, @@ -136,7 +136,7 @@ test('Wrap "generateNotes" plugin in a function that validate the output of the test('Wrap "publish" plugin in a function that validate the output of the plugin', async (t) => { const publish = stub().resolves(2); - const plugin = normalize( + const plugin = await normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'publish', publish, @@ -154,7 +154,7 @@ test('Wrap "publish" plugin in a function that validate the output of the plugin test('Wrap "addChannel" plugin in a function that validate the output of the plugin', async (t) => { const addChannel = stub().resolves(2); - const plugin = normalize( + const plugin = await normalize( {cwd, options: {}, stderr: t.context.stderr, logger: t.context.logger}, 'addChannel', addChannel, @@ -174,7 +174,7 @@ test('Plugin is called with "pluginConfig" (with object definition) and input', const pluginFunction = stub().resolves(); const pluginConf = {path: pluginFunction, conf: 'confValue'}; const options = {global: 'globalValue'}; - const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); + const plugin = await normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); await plugin({options: {}, param: 'param'}); t.true( @@ -189,7 +189,7 @@ test('Plugin is called with "pluginConfig" (with array definition) and input', a const pluginFunction = stub().resolves(); const pluginConf = [pluginFunction, {conf: 'confValue'}]; const options = {global: 'globalValue'}; - const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); + const plugin = await normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); await plugin({options: {}, param: 'param'}); t.true( @@ -206,7 +206,7 @@ test('Prevent plugins to modify "pluginConfig"', async (t) => { }); const pluginConf = {path: pluginFunction, conf: {subConf: 'originalConf'}}; const options = {globalConf: {globalSubConf: 'originalGlobalConf'}}; - const plugin = normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); + const plugin = await normalize({cwd, options, logger: t.context.logger}, '', pluginConf, {}); await plugin({options: {}}); t.is(pluginConf.conf.subConf, 'originalConf'); @@ -218,21 +218,21 @@ test('Prevent plugins to modify its input', async (t) => { options.param.subParam = 'otherParam'; }); const input = {param: {subParam: 'originalSubParam'}, options: {}}; - const plugin = normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {}); + const plugin = await normalize({cwd, options: {}, logger: t.context.logger}, '', pluginFunction, {}); await plugin(input); t.is(input.param.subParam, 'originalSubParam'); }); -test('Return noop if the plugin is not defined', (t) => { - const plugin = normalize({cwd, options: {}, logger: t.context.logger}); +test('Return noop if the plugin is not defined', async (t) => { + const plugin = await normalize({cwd, options: {}, logger: t.context.logger}); t.is(plugin, noop); }); test('Always pass a defined "pluginConfig" for plugin defined with string', async (t) => { // Call the normalize function with the path of a plugin that returns its config - const plugin = normalize( + const plugin = await normalize( {cwd, options: {}, logger: t.context.logger}, '', './test/fixtures/plugin-result-config', @@ -245,7 +245,7 @@ test('Always pass a defined "pluginConfig" for plugin defined with string', asyn test('Always pass a defined "pluginConfig" for plugin defined with path', async (t) => { // Call the normalize function with the path of a plugin that returns its config - const plugin = normalize( + const plugin = await normalize( {cwd, options: {}, logger: t.context.logger}, '', {path: './test/fixtures/plugin-result-config'}, @@ -256,8 +256,8 @@ test('Always pass a defined "pluginConfig" for plugin defined with path', async t.deepEqual(pluginResult.pluginConfig, {}); }); -test('Throws an error if the plugin return an object without the expected plugin function', (t) => { - const error = t.throws(() => +test('Throws an error if the plugin return an object without the expected plugin function', async (t) => { + const error = await t.throwsAsync(() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', './test/fixtures/multi-plugin', {}) ); @@ -267,8 +267,9 @@ test('Throws an error if the plugin return an object without the expected plugin t.truthy(error.details); }); -test('Throws an error if the plugin is not found', (t) => { - t.throws(() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}), { +test('Throws an error if the plugin is not found', async (t) => { + await t.throwsAsync(() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}), + { message: /Cannot find module 'non-existing-path'/, code: 'MODULE_NOT_FOUND', instanceOf: Error, diff --git a/test/plugins/plugins.test.js b/test/plugins/plugins.test.js index 417e7b0cbe..ccde05f714 100644 --- a/test/plugins/plugins.test.js +++ b/test/plugins/plugins.test.js @@ -15,8 +15,8 @@ test.beforeEach((t) => { t.context.logger = {log: t.context.log, success: t.context.success, scope: () => t.context.logger}; }); -test('Export default plugins', (t) => { - const plugins = getPlugins({cwd, options: {}, logger: t.context.logger}, {}); +test('Export default plugins', async (t) => { + const plugins = await getPlugins({cwd, options: {}, logger: t.context.logger}, {}); // Verify the module returns a function for each plugin t.is(typeof plugins.verifyConditions, 'function'); @@ -29,8 +29,8 @@ test('Export default plugins', (t) => { t.is(typeof plugins.fail, 'function'); }); -test('Export plugins based on steps config', (t) => { - const plugins = getPlugins( +test('Export plugins based on steps config', async (t) => { + const plugins = await getPlugins( { cwd, logger: t.context.logger, @@ -38,7 +38,8 @@ test('Export plugins based on steps config', (t) => { verifyConditions: ['./test/fixtures/plugin-noop', {path: './test/fixtures/plugin-noop'}], generateNotes: './test/fixtures/plugin-noop', analyzeCommits: {path: './test/fixtures/plugin-noop'}, - verifyRelease: () => {}, + verifyRelease: () => { + }, }, }, {} @@ -58,11 +59,11 @@ test('Export plugins based on steps config', (t) => { test('Export plugins based on "plugins" config (array)', async (t) => { const plugin1 = {verifyConditions: stub(), publish: stub()}; const plugin2 = {verifyConditions: stub(), verifyRelease: stub()}; - const plugins = getPlugins( + const plugins = await getPlugins( {cwd, logger: t.context.logger, options: {plugins: [plugin1, [plugin2, {}]], verifyRelease: () => {}}}, {} ); - +console.dir(plugins, {depth: null}) await plugins.verifyConditions({options: {}}); t.true(plugin1.verifyConditions.calledOnce); t.true(plugin2.verifyConditions.calledOnce); @@ -86,7 +87,7 @@ test('Export plugins based on "plugins" config (array)', async (t) => { test('Export plugins based on "plugins" config (single definition)', async (t) => { const plugin1 = {verifyConditions: stub(), publish: stub()}; - const plugins = getPlugins({cwd, logger: t.context.logger, options: {plugins: plugin1}}, {}); + const plugins = await getPlugins({cwd, logger: t.context.logger, options: {plugins: plugin1}}, {}); await plugins.verifyConditions({options: {}}); t.true(plugin1.verifyConditions.calledOnce); @@ -109,7 +110,7 @@ test('Merge global options, "plugins" options and step options', async (t) => { const plugin1 = [{verifyConditions: stub(), publish: stub()}, {pluginOpt1: 'plugin1'}]; const plugin2 = [{verifyConditions: stub()}, {pluginOpt2: 'plugin2'}]; const plugin3 = [stub(), {pluginOpt3: 'plugin3'}]; - const plugins = getPlugins( + const plugins = await getPlugins( { cwd, logger: t.context.logger, @@ -129,9 +130,9 @@ test('Merge global options, "plugins" options and step options', async (t) => { t.deepEqual(plugin3[0].args[0][0], {globalOpt: 'global', pluginOpt3: 'plugin3'}); }); -test('Unknown steps of plugins configured in "plugins" are ignored', (t) => { +test('Unknown steps of plugins configured in "plugins" are ignored', async (t) => { const plugin1 = {verifyConditions: () => {}, unknown: () => {}}; - const plugins = getPlugins({cwd, logger: t.context.logger, options: {plugins: [plugin1]}}, {}); + const plugins = await getPlugins({cwd, logger: t.context.logger, options: {plugins: [plugin1]}}, {}); t.is(typeof plugins.verifyConditions, 'function'); t.is(plugins.unknown, undefined); @@ -145,7 +146,7 @@ test('Export plugins loaded from the dependency of a shareable config module', a ); await outputFile(path.resolve(cwd, 'node_modules/shareable-config/index.js'), ''); - const plugins = getPlugins( + const plugins = await getPlugins( { cwd, logger: t.context.logger, @@ -175,7 +176,7 @@ test('Export plugins loaded from the dependency of a shareable config file', asy await copy('./test/fixtures/plugin-noop.js', path.resolve(cwd, 'plugin/plugin-noop.js')); await outputFile(path.resolve(cwd, 'shareable-config.js'), ''); - const plugins = getPlugins( + const plugins = await getPlugins( { cwd, logger: t.context.logger, @@ -200,14 +201,14 @@ test('Export plugins loaded from the dependency of a shareable config file', asy t.is(typeof plugins.fail, 'function'); }); -test('Use default when only options are passed for a single plugin', (t) => { +test('Use default when only options are passed for a single plugin', async (t) => { const analyzeCommits = {}; const generateNotes = {}; const publish = {}; const success = () => {}; const fail = [() => {}]; - const plugins = getPlugins( + const plugins = await getPlugins( { cwd, logger: t.context.logger, @@ -235,7 +236,7 @@ test('Use default when only options are passed for a single plugin', (t) => { }); test('Merge global options with plugin options', async (t) => { - const plugins = getPlugins( + const plugins = await getPlugins( { cwd, logger: t.context.logger, @@ -253,9 +254,9 @@ test('Merge global options with plugin options', async (t) => { t.deepEqual(result.pluginConfig, {localOpt: 'local', globalOpt: 'global', otherOpt: 'locally-defined'}); }); -test('Throw an error for each invalid plugin configuration', (t) => { +test('Throw an error for each invalid plugin configuration', async (t) => { const errors = [ - ...t.throws(() => + ...await t.throwsAsync(() => getPlugins( { cwd, @@ -283,9 +284,9 @@ test('Throw an error for each invalid plugin configuration', (t) => { t.is(errors[3].code, 'EPLUGINCONF'); }); -test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin definition (returns a function)', (t) => { +test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin definition (returns a function)', async (t) => { const errors = [ - ...t.throws(() => + ...await t.throwsAsync(() => getPlugins( { cwd, @@ -303,9 +304,9 @@ test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin de t.is(errors[1].code, 'EPLUGINSCONF'); }); -test('Throw EPLUGINSCONF error for each invalid definition if the "plugins" option', (t) => { +test('Throw EPLUGINSCONF error for each invalid definition if the "plugins" option', async (t) => { const errors = [ - ...t.throws(() => + ...await t.throwsAsync(() => getPlugins({cwd, logger: t.context.logger, options: {plugins: [1, {path: 1}, [() => {}, {}, {}]]}}, {}) ), ]; diff --git a/test/plugins/utils.test.js b/test/plugins/utils.test.js index 99fa42d93b..e9f14dc765 100644 --- a/test/plugins/utils.test.js +++ b/test/plugins/utils.test.js @@ -189,17 +189,17 @@ test('validateStep: required plugin configuration', (t) => { ); }); -test('loadPlugin', (t) => { +test('loadPlugin', async (t) => { const cwd = process.cwd(); const func = () => {}; - t.is(require('../fixtures/plugin-noop'), loadPlugin({cwd: './test/fixtures'}, './plugin-noop', {}), 'From cwd'); + t.is(require('../fixtures/plugin-noop'), await loadPlugin({cwd: './test/fixtures'}, './plugin-noop', {}), 'From cwd'); t.is( require('../fixtures/plugin-noop'), - loadPlugin({cwd}, './plugin-noop', {'./plugin-noop': './test/fixtures'}), + await loadPlugin({cwd}, './plugin-noop', {'./plugin-noop': './test/fixtures'}), 'From a shareable config context' ); - t.is(func, loadPlugin({cwd}, func, {}), 'Defined as a function'); + t.is(func, await loadPlugin({cwd}, func, {}), 'Defined as a function'); }); test('parseConfig', (t) => { From 476e0bb453ef49507685ccaa5f2ab675dc107bfb Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Fri, 16 Sep 2022 16:58:30 -0500 Subject: [PATCH 2/5] fix(plugins): referenced the default of the imported plugin and fixed paren grouping --- lib/plugins/utils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/plugins/utils.js b/lib/plugins/utils.js index 4c7c38d44d..b9fa87d0ca 100644 --- a/lib/plugins/utils.js +++ b/lib/plugins/utils.js @@ -48,7 +48,10 @@ async function loadPlugin({cwd}, name, pluginsPath) { const basePath = pluginsPath[name] ? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name])) : __dirname; - return isFunction(name) ? name : (await import(resolveFrom.silent(basePath, name)) || resolveFrom(cwd, name)); + + return isFunction(name) + ? name + : (await import(resolveFrom.silent(basePath, name) || resolveFrom(cwd, name))).default; } function parseConfig(plugin) { From 4fb3cd211c65feb701362644c039944dc6a4eec9 Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Fri, 16 Sep 2022 17:15:31 -0500 Subject: [PATCH 3/5] refactor(plugins): improved variable names within reduce loops --- lib/plugins/index.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/plugins/index.js b/lib/plugins/index.js index 982ee9c20f..569b1b216c 100644 --- a/lib/plugins/index.js +++ b/lib/plugins/index.js @@ -11,15 +11,12 @@ module.exports = async (context, pluginsPath) => { const errors = []; const plugins = options.plugins - ? await castArray(options.plugins).reduce(async (plugins, plugin) => { - const plugins2 = await plugins; + ? await castArray(options.plugins).reduce(async (eventualPluginsList, plugin) => { + const pluginsList = await eventualPluginsList; if (validatePlugin(plugin)) { const [name, config] = parseConfig(plugin); plugin = isString(name) ? await loadPlugin(context, name, pluginsPath) : name; - console.log({plugins: options.plugins}) - console.dir(plugin, {depth: null}) - console.log(isPlainObject(plugin)) if (isPlainObject(plugin)) { Object.entries(plugin).forEach(([type, func]) => { console.log({type, name}) @@ -29,7 +26,7 @@ module.exports = async (context, pluginsPath) => { writable: false, enumerable: true, }); - plugins2[type] = [...(plugins2[type] || []), [func, config]]; + pluginsList[type] = [...(pluginsList[type] || []), [func, config]]; } }); } else { @@ -39,7 +36,7 @@ module.exports = async (context, pluginsPath) => { errors.push(getError('EPLUGINSCONF', {plugin})); } - return plugins2; + return pluginsList; }, {}) : []; @@ -49,8 +46,8 @@ module.exports = async (context, pluginsPath) => { options = {...plugins, ...options}; - const pluginsConf = await Object.entries(PLUGINS_DEFINITIONS).reduce( - async (pluginsConf, [type, { + const pluginsConfig = await Object.entries(PLUGINS_DEFINITIONS).reduce( + async (eventualPluginsConfigAccumulator, [type, { required, default: def, pipelineConfig, @@ -58,7 +55,7 @@ module.exports = async (context, pluginsPath) => { preprocess = identity }]) => { let pluginOptions; - const pluginsConf2 = await pluginsConf; + const pluginsConfigAccumulator = await eventualPluginsConfigAccumulator; if (isNil(options[type]) && def) { pluginOptions = def; @@ -72,28 +69,31 @@ module.exports = async (context, pluginsPath) => { if (!validateStep({required}, options[type])) { errors.push(getError('EPLUGINCONF', {type, required, pluginConf: options[type]})); - return pluginsConf2; + return pluginsConfigAccumulator; } pluginOptions = options[type]; } - const steps = await Promise.all(castArray(pluginOptions).map(async (pluginOpt) => - await normalize( + const steps = await Promise.all(castArray(pluginOptions).map(async (pluginOpt) => { + const newVar = await normalize( {...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), 'plugins')}, type, pluginOpt, pluginsPath - ) + ); + console.log({newVar, type, pluginsPath}) + return newVar; + } )); - pluginsConf2[type] = async (input) => + pluginsConfigAccumulator[type] = async (input) => postprocess( - await pipeline(steps, pipelineConfig && pipelineConfig(pluginsConf2, logger))(await preprocess(input)), + await pipeline(steps, pipelineConfig && pipelineConfig(pluginsConfigAccumulator, logger))(await preprocess(input)), input ); - return pluginsConf2; + return pluginsConfigAccumulator; }, plugins ); @@ -101,5 +101,5 @@ module.exports = async (context, pluginsPath) => { throw new AggregateError(errors); } - return pluginsConf; + return pluginsConfig; }; From 47ca65c2f65bc9c83575fc003808ead0c952a3e0 Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Fri, 16 Sep 2022 17:16:20 -0500 Subject: [PATCH 4/5] refactor(plugins): removed console.logs and resolved lint issues --- lib/plugins/index.js | 78 +++++++++++++++++----------------- lib/plugins/normalize.js | 2 - lib/plugins/utils.js | 4 +- test/plugins/normalize.test.js | 12 +++--- test/plugins/plugins.test.js | 16 +++---- 5 files changed, 53 insertions(+), 59 deletions(-) diff --git a/lib/plugins/index.js b/lib/plugins/index.js index 569b1b216c..47ff577a30 100644 --- a/lib/plugins/index.js +++ b/lib/plugins/index.js @@ -12,32 +12,31 @@ module.exports = async (context, pluginsPath) => { const plugins = options.plugins ? await castArray(options.plugins).reduce(async (eventualPluginsList, plugin) => { - const pluginsList = await eventualPluginsList; - if (validatePlugin(plugin)) { - const [name, config] = parseConfig(plugin); - plugin = isString(name) ? await loadPlugin(context, name, pluginsPath) : name; + const pluginsList = await eventualPluginsList; + if (validatePlugin(plugin)) { + const [name, config] = parseConfig(plugin); + plugin = isString(name) ? await loadPlugin(context, name, pluginsPath) : name; - if (isPlainObject(plugin)) { - Object.entries(plugin).forEach(([type, func]) => { - console.log({type, name}) - if (PLUGINS_DEFINITIONS[type]) { - Reflect.defineProperty(func, 'pluginName', { - value: isPlainObject(name) ? 'Inline plugin' : name, - writable: false, - enumerable: true, - }); - pluginsList[type] = [...(pluginsList[type] || []), [func, config]]; - } - }); + if (isPlainObject(plugin)) { + Object.entries(plugin).forEach(([type, func]) => { + if (PLUGINS_DEFINITIONS[type]) { + Reflect.defineProperty(func, 'pluginName', { + value: isPlainObject(name) ? 'Inline plugin' : name, + writable: false, + enumerable: true, + }); + pluginsList[type] = [...(pluginsList[type] || []), [func, config]]; + } + }); + } else { + errors.push(getError('EPLUGINSCONF', {plugin})); + } } else { errors.push(getError('EPLUGINSCONF', {plugin})); } - } else { - errors.push(getError('EPLUGINSCONF', {plugin})); - } - return pluginsList; - }, {}) + return pluginsList; + }, {}) : []; if (errors.length > 0) { @@ -47,13 +46,10 @@ module.exports = async (context, pluginsPath) => { options = {...plugins, ...options}; const pluginsConfig = await Object.entries(PLUGINS_DEFINITIONS).reduce( - async (eventualPluginsConfigAccumulator, [type, { - required, - default: def, - pipelineConfig, - postprocess = identity, - preprocess = identity - }]) => { + async ( + eventualPluginsConfigAccumulator, + [type, {required, default: def, pipelineConfig, postprocess = identity, preprocess = identity}] + ) => { let pluginOptions; const pluginsConfigAccumulator = await eventualPluginsConfigAccumulator; @@ -75,21 +71,23 @@ module.exports = async (context, pluginsPath) => { pluginOptions = options[type]; } - const steps = await Promise.all(castArray(pluginOptions).map(async (pluginOpt) => { - const newVar = await normalize( - {...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), 'plugins')}, - type, - pluginOpt, - pluginsPath - ); - console.log({newVar, type, pluginsPath}) - return newVar; - } - )); + const steps = await Promise.all( + castArray(pluginOptions).map(async (pluginOpt) => + normalize( + {...context, options: omit(options, Object.keys(PLUGINS_DEFINITIONS), 'plugins')}, + type, + pluginOpt, + pluginsPath + ) + ) + ); pluginsConfigAccumulator[type] = async (input) => postprocess( - await pipeline(steps, pipelineConfig && pipelineConfig(pluginsConfigAccumulator, logger))(await preprocess(input)), + await pipeline( + steps, + pipelineConfig && pipelineConfig(pluginsConfigAccumulator, logger) + )(await preprocess(input)), input ); diff --git a/lib/plugins/normalize.js b/lib/plugins/normalize.js index e01dbf4421..d44400d24c 100644 --- a/lib/plugins/normalize.js +++ b/lib/plugins/normalize.js @@ -17,8 +17,6 @@ module.exports = async (context, type, pluginOpt, pluginsPath) => { debug(`options for ${pluginName}/${type}: %O`, config); - console.log({plugin}) - console.dir(plugin, {depth: null}) let func; if (isFunction(plugin)) { func = plugin.bind(null, cloneDeep({...options, ...config})); diff --git a/lib/plugins/utils.js b/lib/plugins/utils.js index b9fa87d0ca..c16fd47fe1 100644 --- a/lib/plugins/utils.js +++ b/lib/plugins/utils.js @@ -49,9 +49,7 @@ async function loadPlugin({cwd}, name, pluginsPath) { ? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name])) : __dirname; - return isFunction(name) - ? name - : (await import(resolveFrom.silent(basePath, name) || resolveFrom(cwd, name))).default; + return isFunction(name) ? name : (await import(resolveFrom.silent(basePath, name) || resolveFrom(cwd, name))).default; } function parseConfig(plugin) { diff --git a/test/plugins/normalize.test.js b/test/plugins/normalize.test.js index 725f48d36d..65a7350b20 100644 --- a/test/plugins/normalize.test.js +++ b/test/plugins/normalize.test.js @@ -268,10 +268,12 @@ test('Throws an error if the plugin return an object without the expected plugin }); test('Throws an error if the plugin is not found', async (t) => { - await t.throwsAsync(() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}), + await t.throwsAsync( + () => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}), { - message: /Cannot find module 'non-existing-path'/, - code: 'MODULE_NOT_FOUND', - instanceOf: Error, - }); + message: /Cannot find module 'non-existing-path'/, + code: 'MODULE_NOT_FOUND', + instanceOf: Error, + } + ); }); diff --git a/test/plugins/plugins.test.js b/test/plugins/plugins.test.js index ccde05f714..435459a267 100644 --- a/test/plugins/plugins.test.js +++ b/test/plugins/plugins.test.js @@ -38,8 +38,7 @@ test('Export plugins based on steps config', async (t) => { verifyConditions: ['./test/fixtures/plugin-noop', {path: './test/fixtures/plugin-noop'}], generateNotes: './test/fixtures/plugin-noop', analyzeCommits: {path: './test/fixtures/plugin-noop'}, - verifyRelease: () => { - }, + verifyRelease: () => {}, }, }, {} @@ -63,7 +62,6 @@ test('Export plugins based on "plugins" config (array)', async (t) => { {cwd, logger: t.context.logger, options: {plugins: [plugin1, [plugin2, {}]], verifyRelease: () => {}}}, {} ); -console.dir(plugins, {depth: null}) await plugins.verifyConditions({options: {}}); t.true(plugin1.verifyConditions.calledOnce); t.true(plugin2.verifyConditions.calledOnce); @@ -256,7 +254,7 @@ test('Merge global options with plugin options', async (t) => { test('Throw an error for each invalid plugin configuration', async (t) => { const errors = [ - ...await t.throwsAsync(() => + ...(await t.throwsAsync(() => getPlugins( { cwd, @@ -271,7 +269,7 @@ test('Throw an error for each invalid plugin configuration', async (t) => { }, {} ) - ), + )), ]; t.is(errors[0].name, 'SemanticReleaseError'); @@ -286,7 +284,7 @@ test('Throw an error for each invalid plugin configuration', async (t) => { test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin definition (returns a function)', async (t) => { const errors = [ - ...await t.throwsAsync(() => + ...(await t.throwsAsync(() => getPlugins( { cwd, @@ -295,7 +293,7 @@ test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin de }, {} ) - ), + )), ]; t.is(errors[0].name, 'SemanticReleaseError'); @@ -306,9 +304,9 @@ test('Throw EPLUGINSCONF error if the "plugins" option contains an old plugin de test('Throw EPLUGINSCONF error for each invalid definition if the "plugins" option', async (t) => { const errors = [ - ...await t.throwsAsync(() => + ...(await t.throwsAsync(() => getPlugins({cwd, logger: t.context.logger, options: {plugins: [1, {path: 1}, [() => {}, {}, {}]]}}, {}) - ), + )), ]; t.is(errors[0].name, 'SemanticReleaseError'); From eeae4d36adda2527016c007bc91282afde58771b Mon Sep 17 00:00:00 2001 From: Matt Travi Date: Fri, 16 Sep 2022 23:03:46 -0500 Subject: [PATCH 5/5] test(lint): disabled the check for `node/no-unsupported-features/es-syntax` when loading plugins based on https://github.com/mysticatea/eslint-plugin-node/issues/250 --- lib/plugins/utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/plugins/utils.js b/lib/plugins/utils.js index c16fd47fe1..2b69da41a5 100644 --- a/lib/plugins/utils.js +++ b/lib/plugins/utils.js @@ -49,6 +49,8 @@ async function loadPlugin({cwd}, name, pluginsPath) { ? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name])) : __dirname; + // See https://github.com/mysticatea/eslint-plugin-node/issues/250 + // eslint-disable-next-line node/no-unsupported-features/es-syntax return isFunction(name) ? name : (await import(resolveFrom.silent(basePath, name) || resolveFrom(cwd, name))).default; }