Add documentation to the commands for the CLI

This commit is contained in:
2026-05-04 12:14:40 +00:00
parent 8d7856f32e
commit 3c47ee8a4c
11 changed files with 480 additions and 55 deletions

View File

@@ -37,22 +37,33 @@ export const handleTemplateListCommand = async (
deps: CommandDependencies,
args: string[],
): Promise<{ count?: number }> => {
// Get the template category from the arguments - This could be "action", "transaction", "output", "lockingscript", or "variable"
const templateCategory = args[0];
deps.io.verbose(`Template list category: ${templateCategory}`);
// If no template category is provided, list all the imported templates
if (!templateCategory) {
// List all the imported templates
const templates = await deps.app.engine.listImportedTemplates();
// Format the templates into a list of strings that we can display to the user
const formattedTemplates = templates.map(
(template: XOTemplate) =>
`${bold(generateTemplateIdentifier(template))} - ${dim(template.name)} ${dim(template.description)}`,
);
// Display the templates to the user
deps.io.out(formattedTemplates.join("\n"));
// Return the number of templates
return { count: templates.length };
}
// Get the template identifier from the arguments
const templateIdentifier = args[1];
deps.io.verbose(`Template identifier: ${templateIdentifier}`);
// If no template identifier is provided, print a message and throw an error
if (!templateIdentifier) {
deps.io.err("No template identifier provided");
throw new CommandError(
@@ -61,7 +72,10 @@ export const handleTemplateListCommand = async (
);
}
// Get the raw template from the engine
const rawTemplate = await deps.app.engine.getTemplate(templateIdentifier);
// If the raw template is not found, print a message and throw an error
if (!rawTemplate) {
deps.io.err(`No template found: ${templateIdentifier}`);
throw new CommandError(
@@ -70,53 +84,91 @@ export const handleTemplateListCommand = async (
);
}
// Resolve the template deeply - Deeply nested objects instead of shallow objects referencing keys at the top level.
// Reduces the load of having to call multiple lookups just to get some resolved value like the outputIdentifer that comes from calling an action.
const template = await resolveTemplateReferences(rawTemplate);
deps.io.verbose(`Template: ${formatObject(template)}`);
// Handle the template category
switch (templateCategory) {
case "action": {
// Get the actions from the template
const actions = template.actions;
// Format the actions into a list of strings that we can display to the user
const formattedActions = Object.entries(actions).map(
([actionIdentifier, action]) =>
`${bold(actionIdentifier)} ${dim(action.name)} ${dim(action.description)}`,
);
// Display the actions to the user
deps.io.out(formattedActions.join("\n"));
// Return the number of actions
return {};
}
case "transaction": {
// Get the transactions from the template
const transactions = template.transactions;
// Format the transactions into a list of strings that we can display to the user
const formattedTransactions = Object.entries(transactions).map(
([transactionIdentifier, transaction]) =>
`${bold(transactionIdentifier)} ${dim(transaction.name)} ${dim(transaction.description)}`,
);
// Display the transactions to the user
deps.io.out(formattedTransactions.join("\n"));
// Return the number of transactions
return {};
}
case "output": {
// Get the outputs from the template
const outputs = template.outputs;
// Format the outputs into a list of strings that we can display to the user
const formattedOutputs = Object.entries(outputs).map(
([outputIdentifier, output]) =>
`${bold(outputIdentifier)} ${dim(output.name)} ${dim(output.description)}`,
);
// Display the outputs to the user
deps.io.out(formattedOutputs.join("\n"));
// Return the number of outputs
return {};
}
case "lockingscript": {
// Get the lockingscripts from the template
const lockingscripts = template.lockingScripts;
// Format the lockingscripts into a list of strings that we can display to the user
const formattedLockingscripts = Object.entries(lockingscripts).map(
([lockingScriptIdentifier, lockingScript]) =>
`${bold(lockingScriptIdentifier)} ${dim(lockingScript.name)} ${dim(lockingScript.description)}`,
);
// Display the lockingscripts to the user
deps.io.out(formattedLockingscripts.join("\n"));
// Return the number of lockingscripts
return {};
}
case "variable": {
// Get the variables from the template
const variables = template.variables || {};
// Format the variables into a list of strings that we can display to the user
const formattedVariables = Object.entries(variables).map(
([variableIdentifier, variable]) =>
`${bold(variableIdentifier)} ${dim(variable.name)} ${dim(variable.description)}`,
);
// Display the variables to the user
deps.io.out(formattedVariables.join("\n"));
// Return the number of variables
return {};
}
default: {
@@ -162,6 +214,7 @@ export const handleTemplateInspectCommand = async (
deps: CommandDependencies,
args: string[],
): Promise<Record<string, never>> => {
// Get the template category, identifier, and field from the arguments
const templateCategory = args[0];
const templateQuery = args[1];
const templateField = args[2];
@@ -170,6 +223,7 @@ export const handleTemplateInspectCommand = async (
`Template inspect args - category: ${templateCategory}, identifier: ${templateQuery}, field: ${templateField}`,
);
// If no template category, identifier, or field is provided, print a message and throw an error
if (!templateCategory || !templateQuery || !templateField) {
deps.io.err("No template category, identifier, or field provided");
printTemplateInspectHelp(deps.io);
@@ -179,15 +233,21 @@ export const handleTemplateInspectCommand = async (
);
}
// Resolve the template
const originalTemplate = await resolveTemplate(deps, templateQuery);
deps.io.verbose(`Original Template: ${formatObject(originalTemplate)}`);
// Resolve the template references
const template = await resolveTemplateReferences(originalTemplate);
deps.io.verbose(`Extended Template: ${formatObject(template)}`);
// Handle the template category
switch (templateCategory) {
case "action": {
// Get the action from the template
const action = template.actions[templateField];
// If the action is not found, print a message and throw an error
if (!action) {
deps.io.err(`No action found: ${templateField}`);
throw new CommandError(
@@ -195,11 +255,16 @@ export const handleTemplateInspectCommand = async (
`No action found: ${templateField}`,
);
}
// Display the action to the user
deps.io.out(formatObject(action));
return {};
}
case "transaction": {
// Get the transaction from the template
const transaction = template.transactions?.[templateField];
// If the transaction is not found, print a message and throw an error
if (!transaction) {
deps.io.err(`No transaction found: ${templateField}`);
throw new CommandError(
@@ -207,11 +272,16 @@ export const handleTemplateInspectCommand = async (
`No transaction found: ${templateField}`,
);
}
// Display the transaction to the user
deps.io.out(formatObject(transaction));
return {};
}
case "output": {
// Get the output from the template
const output = template.outputs[templateField];
// If the output is not found, print a message and throw an error
if (!output) {
deps.io.err(`No output found: ${templateField}`);
throw new CommandError(
@@ -219,11 +289,16 @@ export const handleTemplateInspectCommand = async (
`No output found: ${templateField}`,
);
}
// Display the output to the user
deps.io.out(formatObject(output));
return {};
}
case "lockingscript": {
// Get the lockingscript from the template
const lockingscript = template.lockingScripts[templateField];
// If the lockingscript is not found, print a message and throw an error
if (!lockingscript) {
deps.io.err(`No lockingscript found: ${templateField}`);
throw new CommandError(
@@ -231,11 +306,16 @@ export const handleTemplateInspectCommand = async (
`No lockingscript found: ${templateField}`,
);
}
// Display the lockingscript to the user
deps.io.out(formatObject(lockingscript));
return {};
}
case "variable": {
// Get the variable from the template
const variable = template.variables?.[templateField];
// If the variable is not found, print a message and throw an error
if (!variable) {
deps.io.err(`No variable found: ${templateField}`);
throw new CommandError(
@@ -243,6 +323,8 @@ export const handleTemplateInspectCommand = async (
`No variable found: ${templateField}`,
);
}
// Display the variable to the user
deps.io.out(formatObject(variable));
return {};
}
@@ -268,8 +350,10 @@ export const handleTemplateCommand = async (
args: string[],
_options: Record<string, string>,
): Promise<{ templateFile?: string; count?: number }> => {
// Get the sub-command from the arguments
const subCommand = args[0];
// If no sub-command is provided, print a message and throw an error
if (!subCommand) {
deps.io.verbose("No sub-command provided");
printTemplateHelp(deps.io);
@@ -279,9 +363,13 @@ export const handleTemplateCommand = async (
);
}
// Handle the sub-command
switch (subCommand) {
case "import": {
// Get the template file from the arguments
const templateFile = args[1];
// If no template file is provided, print a message and throw an error
deps.io.verbose(`Template file: ${templateFile}`);
if (!templateFile) {
@@ -293,9 +381,11 @@ export const handleTemplateCommand = async (
);
}
// Resolve the template path
const templatePath = path.resolve(`${process.cwd()}/${templateFile}`);
deps.io.verbose(`Template path: ${templatePath}`);
// If the template file does not exist, print a message and throw an error
if (!existsSync(templatePath)) {
deps.io.err(`Template file does not exist: ${templatePath}`);
printTemplateHelp(deps.io);
@@ -305,23 +395,32 @@ export const handleTemplateCommand = async (
);
}
// Read the template file
const template = await readFileSync(templatePath, "utf8");
deps.io.verbose(`Importing template: ${templateFile}`);
// Import the template
await deps.app.engine.importTemplate(template);
deps.io.verbose(`Template imported: ${templateFile}`);
// Return the template file
return { templateFile };
}
case "list": {
// Handle the template list command, We offload here as it has lots of arguments and is quite long
return handleTemplateListCommand(deps, args.slice(1));
}
case "inspect": {
// Handle the template inspect command, We offload here as it has lots of arguments and is quite long
return handleTemplateInspectCommand(deps, args.slice(1));
}
case "set-default": {
// Get the template file, output identifier, and role identifier from the arguments
const templateFile = args[1];
const outputIdentifier = args[2];
const roleIdentifier = args[3];
// If no template file, output identifier, or role identifier is provided, print a message and throw an error
if (!templateFile || !outputIdentifier || !roleIdentifier) {
deps.io.verbose(
"No template file, output identifier, or role identifier provided",
@@ -332,17 +431,24 @@ export const handleTemplateCommand = async (
"No template file, output identifier, or role identifier provided",
);
}
// Set the default locking parameters
deps.io.verbose(
`Template file: ${templateFile}, output identifier: ${outputIdentifier}, role identifier: ${roleIdentifier}`,
);
// Set the default locking parameters
await deps.app.engine.setDefaultLockingParameters(
templateFile,
outputIdentifier,
roleIdentifier,
);
// Return an empty object
return {};
}
default:
// If the sub-command is not found, print a message and throw an error
deps.io.verbose(`Unknown template sub-command: ${subCommand}`);
printTemplateHelp(deps.io);
throw new CommandError(