serverless/lib/cli/resolve-input-final.js
2024-05-29 11:51:04 -04:00

105 lines
4.2 KiB
JavaScript

import _ from 'lodash'
import commandSchema from './commands-schema.js'
import serviceOptions from './commands-options-schema.js'
import logDeprecation from '../utils/log-deprecation.js'
/**
* This module exports a function that processes loaded plugins and their
* configurations, mapping out their commands and options into a commands Map.
* It imports AWS service commands and common options, and merges them with
* the commands and options from the loaded plugins. It also handles missing
* option types by logging a deprecation warning.
*
* @param {Array} loadedPlugins - An array of loaded plugin objects.
* @param {Object} configuration - The configuration object for the plugins.
* @returns {Map} A Map object of commands and their options.
*/
export default (loadedPlugins, { configuration }) => {
const commands = new Map(commandSchema)
const missingOptionTypes = new Map()
const commonOptions = serviceOptions
commands.commonOptions = commonOptions
/**
* Recursively processes a configuration object for a plugin, mapping out its
* commands and their options. It skips commands of type 'entrypoint', and for
* other commands, it creates or updates a schema with details like usage,
* lifecycle events, and options. If an option is missing the 'type' property,
* it is added to the `missingOptionTypes` set for later processing.
*
* @param {Object} loadedPlugin - The loaded plugin object.
* @param {Object} config - The configuration object for the plugin.
* @param {string} commandPrefix - The prefix for the command (default is '').
*/
const resolveCommands = (loadedPlugin, config, commandPrefix = '') => {
if (!config.commands) return
for (const [commandName, commandConfig] of Object.entries(
config.commands,
)) {
if (commandConfig.type === 'entrypoint') continue
const fullCommandName = `${commandPrefix}${commandName}`
if (commandConfig.type !== 'container') {
const schema = commands.has(fullCommandName)
? _.merge({}, commands.get(fullCommandName))
: {
usage: commandConfig.usage,
serviceDependencyMode: 'required',
isExtension: true,
sourcePlugin: loadedPlugin,
isHidden: commandConfig.isHidden,
noSupportNotice: commandConfig.noSupportNotice,
options: {},
}
if (commandConfig.lifecycleEvents)
schema.lifecycleEvents = commandConfig.lifecycleEvents
if (commandConfig.options) {
for (const [optionName, optionConfig] of Object.entries(
commandConfig.options,
)) {
if (!schema.options[optionName]) {
schema.options[optionName] = optionConfig
if (!optionConfig.type) {
if (!missingOptionTypes.has(loadedPlugin)) {
missingOptionTypes.set(loadedPlugin, new Set())
}
missingOptionTypes.get(loadedPlugin).add(optionName)
}
}
}
}
// Put common options to end of index
for (const optionName of Object.keys(commonOptions))
delete schema.options[optionName]
Object.assign(schema.options, commonOptions)
commands.set(fullCommandName, schema)
}
resolveCommands(loadedPlugin, commandConfig, `${fullCommandName} `)
}
}
for (const loadedPlugin of loadedPlugins)
resolveCommands(loadedPlugin, loadedPlugin)
if (missingOptionTypes.size) {
logDeprecation(
'CLI_OPTIONS_SCHEMA_V3',
'CLI options definitions were upgraded with "type" property (which could be one of "string", "boolean", "multiple"). ' +
'Below listed plugins do not predefine type for introduced options:\n' +
` - ${Array.from(
missingOptionTypes,
([plugin, optionNames]) =>
`${plugin.constructor.name} for "${Array.from(optionNames).join(
'", "',
)}"`,
).join('\n - ')}\n` +
'Please report this issue in plugin issue tracker.\n' +
'Starting with next major release, this will be communicated with a thrown error.',
{ serviceConfig: configuration },
)
}
return commands
}