@commercelayer/cli
Version:
223 lines (219 loc) • 8.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const cli_core_1 = require("@commercelayer/cli-core");
const core_1 = require("@oclif/core");
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const prettier_1 = require("prettier");
const node_os_1 = require("node:os");
const FIG_SPECS_DIR = `${(0, node_os_1.homedir)()}/Documents/GitHub/fig-autocomplete/src`;
const SPEC_NAME = 'commercelayer';
const processedCommands = [];
function getFigArgs(args) {
const figArgs = [];
for (const arg of args) {
if (arg.hidden)
continue;
const figArg = {
name: arg.name,
...(arg.description && { description: description(arg.description) }),
...(arg.default && { default: `${arg.default}` }),
...(arg.options?.length && { suggestions: arg.options }),
...(arg.required === false && { isOptional: true })
};
figArgs.push(figArg);
}
return figArgs;
}
function getFigOptions(options) {
const figOptions = [];
for (const flag of options) {
const figOption = {
name: flag.char ? [`-${flag.char}`, `--${flag.name}`] : `--${flag.name}`,
...(flag.description && { description: description(flag.description) }),
...(flag.type === "option" && {
args: {
description: description(flag.helpValue),
...(flag.options?.length && { suggestions: flag.options }),
...(flag.default && { default: `${flag.default}` }),
},
}),
...(flag.required === true && { isRequired: true }),
...(flag.type === "boolean" && flag.allowNo && { exclusiveOn: [`--no-${flag.name}`] }),
hidden: flag.hidden
};
figOptions.push(figOption);
if (flag.type === "boolean" && flag.allowNo) {
figOptions.push({
name: `--no-${flag.name}`
});
}
}
return figOptions;
}
function description(desc) {
if (!desc)
return desc;
let d = desc;
if (Array.isArray(d)) {
if (d.length > 0)
d = d[0];
else
d = '';
}
if (d) {
if (d.length > 80) {
d = d.substring(0, d.indexOf('.') + 1);
if (d.length > 80)
d = d.substring(0, 80);
}
if (d.endsWith('...') && (d.charAt(d.indexOf('...') - 1) === '|'))
d = d.replace('...', 'etc');
d = cli_core_1.clText.capitalize(d) || '';
if (d.endsWith('.'))
d = d.substring(0, d.length - 1);
d = d.trim();
}
return d;
}
function getFigSubcommands(commands, hidden = false) {
const subcommands = [];
for (const command of commands) {
// skip...
if (['fig', 'cli:fig'].includes(command.id) // this command
|| processedCommands.includes(command.id) // command aliases
|| (command.hidden && !hidden))
continue; // hidden commands if no explicitely requested
const options = getFigOptions(Object.values(command.flags));
const args = getFigArgs(Object.values(command.args));
const commandNames = [command.id];
if (command.aliases)
command.aliases.forEach(a => { if (!commandNames.includes(a))
commandNames.push(a); });
const subCommand = {
name: (commandNames.length === 1) ? commandNames[0] : commandNames,
...(command.description && { description: description(command.description) }),
...(options.length && { options }),
...(args.length && { args: (args.length === 1) ? args[0] : args }),
hidden: command.hidden
};
subcommands.push(subCommand);
processedCommands.push(...commandNames); // mark command and its aliases as processed
}
return subcommands;
}
const buildSpec = (spec) => {
return `/**
* Autogenerated by @commercelayer/cli cli:fig command
**/
const completionSpec: Fig.Spec = ${JSON.stringify(spec, null, 2)}
export default completionSpec
`;
};
async function classifyResources(resUrl) {
const resources = (await (await fetch(resUrl)).json()).data;
const classes = {
listable: [],
retrievable: [],
updatable: [],
creatable: [],
deletable: []
};
resources.filter(res => res.type === 'resources').forEach(res => {
if (res.attributes?.actions) {
const r = res.id;
const actions = res.attributes.actions;
if (actions.includes('list'))
classes.listable.push(r);
if (actions.includes('retrieve'))
classes.retrievable.push(r);
if (actions.includes('update'))
classes.updatable.push(r);
if (actions.includes('create'))
classes.creatable.push(r);
if (actions.includes('delete'))
classes.deletable.push(r);
}
});
return classes;
}
function setCmdArgSuggestions(spec, cmd, res, suggestions) {
const args = spec.subcommands?.find(res => res.name.includes(cmd))?.args;
if (args) {
const arg = Array.isArray(args) ? args.find(a => a.name === res) : args;
if (arg)
arg.suggestions = suggestions;
}
return spec;
}
async function enhanceSpec(spec) {
let classes;
// CORE
classes = await classifyResources('https://core.commercelayer.io/api/public/resources');
setCmdArgSuggestions(spec, 'resources:list', 'resource', classes.listable.map(r => cli_core_1.clText.pluralize(r)));
setCmdArgSuggestions(spec, 'resources:retrieve', 'resource', classes.retrievable);
setCmdArgSuggestions(spec, 'resources:update', 'resource', classes.updatable);
setCmdArgSuggestions(spec, 'resources:create', 'resource', classes.creatable);
setCmdArgSuggestions(spec, 'resources:delete', 'resource', classes.deletable);
// PROVISIONING
classes = await classifyResources('https://provisioning.commercelayer.co/api/public/resources');
setCmdArgSuggestions(spec, 'provisioning:list', 'resource', classes.listable.map(r => cli_core_1.clText.pluralize(r)));
setCmdArgSuggestions(spec, 'provisioning:retrieve', 'resource', classes.retrievable);
setCmdArgSuggestions(spec, 'provisioning:update', 'resource', classes.updatable);
setCmdArgSuggestions(spec, 'provisioning:create', 'resource', classes.creatable);
setCmdArgSuggestions(spec, 'provisioning:delete', 'resource', classes.deletable);
return spec;
}
class CliFig extends core_1.Command {
static description = 'generate a Fig completion spec for Commerce Layer CLI';
static hidden = true;
static flags = {
dir: core_1.Flags.directory({
char: 'd',
description: 'directory where to save the output spec file',
exclusive: ['install']
}),
hidden: core_1.Flags.boolean({
char: 'h',
description: 'include hidden commands'
}),
install: core_1.Flags.boolean({
char: 'i',
description: 'copy into Fig specs directory',
exclusive: ['dir'],
hidden: true
}),
blind: core_1.Flags.boolean({
char: 'b',
description: 'execute in blind mode without terminal output',
hidden: true,
exclusive: ['install']
})
};
async run() {
const { flags } = await this.parse(CliFig);
const spec = {
name: this.config.name,
subcommands: getFigSubcommands(this.config.commands)
};
await enhanceSpec(spec);
const template = await (0, prettier_1.format)(buildSpec(spec), { parser: 'typescript', printWidth: 80 });
if (flags.dir || flags.install) {
const fileName = `${SPEC_NAME}.ts`;
let fileDir = '.';
if (flags.dir)
fileDir = cli_core_1.clUtil.specialFolder(flags.dir);
else if (flags.install)
fileDir = FIG_SPECS_DIR;
if (!(0, node_fs_1.existsSync)(fileDir))
this.error(`Folder does not exists: ${cli_core_1.clColor.msg.error(fileDir)}`);
const filePath = (0, node_path_1.join)(fileDir, fileName);
core_1.ux.action.start(`Generating spec file ${filePath}`);
(0, node_fs_1.writeFileSync)(filePath, template, { encoding: 'utf8', flag: 'w' });
core_1.ux.action.stop();
}
else if (!flags.blind)
this.log(template);
}
}
exports.default = CliFig;