mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
chore(loader): fix types for plugin options (#4970)
* chore(loader): fix types for plugin options * debug
This commit is contained in:
parent
6e344d0f48
commit
ba71932523
7 changed files with 58 additions and 41 deletions
6
.changeset/cool-seals-watch.md
Normal file
6
.changeset/cool-seals-watch.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@verdaccio/loaders': patch
|
||||
'@verdaccio/config': patch
|
||||
---
|
||||
|
||||
chore(loader): fix types for plugin options
|
|
@ -52,6 +52,7 @@ class Config implements AppConfig {
|
|||
public packages: PackageList;
|
||||
public users: any;
|
||||
public auth: AuthConf;
|
||||
public store: any;
|
||||
public server_id: string;
|
||||
public configPath: string;
|
||||
/**
|
||||
|
|
|
@ -3,7 +3,6 @@ import fs from 'fs';
|
|||
import { dirname, isAbsolute, join, resolve } from 'path';
|
||||
|
||||
import { pluginUtils } from '@verdaccio/core';
|
||||
import { Config, Logger } from '@verdaccio/types';
|
||||
|
||||
import { PluginType, isES6, isValid, tryLoad } from './utils';
|
||||
|
||||
|
@ -16,8 +15,6 @@ async function isDirectory(pathFolder: string) {
|
|||
return stat.isDirectory();
|
||||
}
|
||||
|
||||
export type Params = { config: Config; logger: Logger };
|
||||
|
||||
// type Plugins<T> =
|
||||
// | pluginUtils.Auth<T>
|
||||
// | pluginUtils.Storage<T>
|
||||
|
@ -40,24 +37,25 @@ export type Params = { config: Config; logger: Logger };
|
|||
* The `params` is an object that contains the global configuration and the logger.
|
||||
*
|
||||
* @param {*} pluginConfigs the custom plugin section
|
||||
* @param {*} params a set of params to initialize the plugin
|
||||
* @param {*} pluginOptions a set of options to initialize the plugin
|
||||
* @param {*} sanityCheck callback that check the shape that should fulfill the plugin
|
||||
* @param {*} prefix by default is verdaccio but can be override with config.server.pluginPrefix
|
||||
* @param {*} pluginCategory the category of the plugin, eg: auth, storage, middleware
|
||||
* @return {Array} list of plugins
|
||||
*/
|
||||
export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
|
||||
pluginConfigs: any = {},
|
||||
params: Params,
|
||||
pluginOptions: pluginUtils.PluginOptions,
|
||||
sanityCheck: (plugin: PluginType<T>) => boolean,
|
||||
prefix: string = 'verdaccio',
|
||||
pluginCategory: string = ''
|
||||
): Promise<PluginType<T>[]> {
|
||||
const logger = params?.logger;
|
||||
const logger = pluginOptions?.logger;
|
||||
const pluginsIds = Object.keys(pluginConfigs);
|
||||
const { config } = params;
|
||||
const { config } = pluginOptions;
|
||||
let plugins: PluginType<T>[] = [];
|
||||
for (let pluginId of pluginsIds) {
|
||||
debug('plugin %s', pluginId);
|
||||
debug('looking for plugin %o', pluginId);
|
||||
if (typeof config.plugins === 'string') {
|
||||
let pluginsPath = config.plugins;
|
||||
debug('plugin path %s', pluginsPath);
|
||||
|
@ -84,7 +82,7 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
|
|||
logger.error(a, b);
|
||||
});
|
||||
if (plugin && isValid(plugin)) {
|
||||
plugin = executePlugin(plugin, pluginConfigs[pluginId], params);
|
||||
plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
|
||||
if (!sanityCheck(plugin)) {
|
||||
logger.error(
|
||||
{ content: externalFilePlugin },
|
||||
|
@ -109,14 +107,14 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
|
|||
|
||||
if (typeof pluginId === 'string') {
|
||||
const isScoped: boolean = pluginId.startsWith('@') && pluginId.includes('/');
|
||||
debug('is scoped plugin %s', isScoped);
|
||||
debug('is scoped plugin: %s', isScoped);
|
||||
const pluginName = isScoped ? pluginId : `${prefix}-${pluginId}`;
|
||||
debug('plugin pkg name %s', pluginName);
|
||||
debug('plugin package name %s', pluginName);
|
||||
let plugin = tryLoad<T>(pluginName, (a: any, b: any) => {
|
||||
logger.error(a, b);
|
||||
});
|
||||
if (plugin && isValid(plugin)) {
|
||||
plugin = executePlugin(plugin, pluginConfigs[pluginId], params);
|
||||
plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
|
||||
if (!sanityCheck(plugin)) {
|
||||
logger.error({ content: pluginName }, "@{content} doesn't look like a valid plugin");
|
||||
continue;
|
||||
|
@ -136,23 +134,23 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
|
|||
}
|
||||
}
|
||||
}
|
||||
debug('plugin found %s', plugins.length);
|
||||
debug('%s plugins found: %s', pluginCategory, plugins.length);
|
||||
return plugins;
|
||||
}
|
||||
|
||||
export function executePlugin<T>(
|
||||
plugin: PluginType<T>,
|
||||
pluginConfig: unknown,
|
||||
params: Params
|
||||
pluginOptions: pluginUtils.PluginOptions
|
||||
): PluginType<T> {
|
||||
if (isES6(plugin)) {
|
||||
debug('plugin is ES6');
|
||||
// @ts-expect-error no relevant for the code
|
||||
// eslint-disable-next-line new-cap
|
||||
return new plugin.default(pluginConfig, params) as Plugin;
|
||||
return new plugin.default(pluginConfig, pluginOptions) as Plugin;
|
||||
} else {
|
||||
debug('plugin is commonJS');
|
||||
// @ts-expect-error improve this type
|
||||
return plugin(pluginConfig, params) as PluginType<T>;
|
||||
return plugin(pluginConfig, pluginOptions) as PluginType<T>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
store:
|
||||
plugin-store:
|
||||
enabled: true
|
|
@ -0,0 +1,7 @@
|
|||
function ValidVerdaccioPlugin() {
|
||||
return {
|
||||
getPackageStorage: function () {},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = ValidVerdaccioPlugin;
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "verdaccio-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
|
@ -15,6 +15,9 @@ function getConfig(file: string) {
|
|||
const authSanitize = function (plugin) {
|
||||
return plugin.authenticate || plugin.allow_access || plugin.allow_publish;
|
||||
};
|
||||
const storeSanitize = function (plugin) {
|
||||
return typeof plugin.getPackageStorage !== 'undefined';
|
||||
};
|
||||
|
||||
const pluginsPartialsFolder = path.join(__dirname, './partials/test-plugin-storage');
|
||||
|
||||
|
@ -31,13 +34,17 @@ describe('plugin loader', () => {
|
|||
expect(plugins).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('testing storage valid plugin loader', async () => {
|
||||
const config = getConfig('valid-plugin-store.yaml');
|
||||
config.plugins = pluginsPartialsFolder;
|
||||
const plugins = await asyncLoadPlugin(config.store, { config, logger }, storeSanitize);
|
||||
|
||||
expect(plugins).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should handle does not exist plugin folder', async () => {
|
||||
const config = getConfig('plugins-folder-fake.yaml');
|
||||
const plugins = await asyncLoadPlugin(
|
||||
config.auth,
|
||||
{ logger: logger, config: config },
|
||||
authSanitize
|
||||
);
|
||||
const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
|
||||
|
||||
expect(plugins).toHaveLength(0);
|
||||
});
|
||||
|
@ -59,11 +66,7 @@ describe('plugin loader', () => {
|
|||
const config = getConfig('plugins-folder-fake.yaml');
|
||||
// force file instead a folder.
|
||||
config.plugins = path.join(__dirname, 'just-a-file.js');
|
||||
const plugins = await asyncLoadPlugin(
|
||||
config.auth,
|
||||
{ logger: logger, config: config },
|
||||
authSanitize
|
||||
);
|
||||
const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
|
||||
|
||||
expect(plugins).toHaveLength(0);
|
||||
});
|
||||
|
@ -72,11 +75,7 @@ describe('plugin loader', () => {
|
|||
test('should resolve plugin based on relative path', async () => {
|
||||
const config = getConfig('relative-plugins.yaml');
|
||||
// force file instead a folder.
|
||||
const plugins = await asyncLoadPlugin(
|
||||
config.auth,
|
||||
{ logger: logger, config: config },
|
||||
authSanitize
|
||||
);
|
||||
const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
|
||||
|
||||
expect(plugins).toHaveLength(1);
|
||||
});
|
||||
|
@ -88,11 +87,7 @@ describe('plugin loader', () => {
|
|||
// @ts-expect-error
|
||||
config.config_path = undefined;
|
||||
// force file instead a folder.
|
||||
const plugins = await asyncLoadPlugin(
|
||||
config.auth,
|
||||
{ logger: logger, config: config },
|
||||
authSanitize
|
||||
);
|
||||
const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
|
||||
|
||||
expect(plugins).toHaveLength(0);
|
||||
});
|
||||
|
@ -103,11 +98,7 @@ describe('plugin loader', () => {
|
|||
// @ts-expect-error
|
||||
config.configPath = undefined;
|
||||
// force file instead a folder.
|
||||
const plugins = await asyncLoadPlugin(
|
||||
config.auth,
|
||||
{ logger: logger, config: config },
|
||||
authSanitize
|
||||
);
|
||||
const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize);
|
||||
|
||||
expect(plugins).toHaveLength(0);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue