@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
171 lines • 6.44 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const error_1 = __importDefault(require("@sprucelabs/error"));
const schema_1 = __importDefault(require("@sprucelabs/schema"));
const lodash_1 = require("lodash");
const SpruceError_1 = __importDefault(require("../errors/SpruceError"));
const graphicsInterface_types_1 = require("../types/graphicsInterface.types");
var FormBuilderActionType;
(function (FormBuilderActionType) {
FormBuilderActionType["Done"] = "done";
FormBuilderActionType["Cancel"] = "cancel";
FormBuilderActionType["EditField"] = "edit_field";
})(FormBuilderActionType || (FormBuilderActionType = {}));
class FormComponent extends schema_1.default {
ui;
handlers = {};
constructor(options) {
// Setup schema
super(options.schema, options.initialValues);
const { ui } = options;
// Save ui for writing, saving
this.ui = ui;
// Handlers
const { onWillAskQuestion } = options;
this.handlers.onWillAskQuestion = onWillAskQuestion;
}
/** Pass me a schema and i'll give you back an object that conforms to it based on user input */
async present(options = {}) {
const { ui } = this;
const { headline, showOverview, fields = this.getNamedFields().map((nf) => nf.name), } = options;
let done = false;
let valid = false;
do {
if (headline) {
ui.renderHeadline(headline, [graphicsInterface_types_1.GraphicsTextEffect.SpruceHeader]);
ui.renderLine('');
}
if (showOverview) {
// Overview mode
const action = await this.renderOverview({ fields });
switch (action.type) {
case FormBuilderActionType.EditField: {
// Editing a field
const fieldName = action.fieldName;
const answer = await this.askQuestion(fieldName);
// Set the new value
this.set(fieldName, answer);
break;
}
case FormBuilderActionType.Done: {
done = true;
}
}
}
else {
// Asking one question at a time
const namedFields = this.getNamedFields({ fields });
for (const namedField of namedFields) {
const { name } = namedField;
const answer = await this.askQuestion(name);
this.set(name, answer);
}
done = true;
}
if (done) {
try {
this.validate({ fields });
valid = true;
}
catch (err) {
this.renderError(err);
await this.ui.waitForEnter();
}
}
} while (!done || !valid);
const values = this.getValues({
fields,
shouldCreateEntityInstances: false,
});
const cleanValues = (0, lodash_1.pick)(values, fields);
return cleanValues;
}
/** Ask a question based on a field */
askQuestion(fieldName) {
const field = this.getNamedFields().find((nf) => nf.name === fieldName)?.field;
if (!field) {
throw new Error(`No field named ${fieldName} on form ${this.schemaId}`);
}
let definition = { ...field.definition };
const value = this.get(fieldName, {
shouldValidate: false,
shouldCreateEntityInstances: false,
});
if (definition.isArray) {
throw new SpruceError_1.default({
code: 'NOT_IMPLEMENTED',
friendlyMessage: 'Form builder does not support isArray yet',
});
}
if (value) {
definition.defaultValue = value;
}
if (this.handlers.onWillAskQuestion) {
definition = this.handlers.onWillAskQuestion(fieldName,
//@ts-ignore
definition, this.getValues({
shouldValidate: false,
shouldCreateEntityInstances: false,
}));
}
return this.ui.prompt(definition);
}
renderError(error) {
this.ui.renderDivider();
this.ui.renderHeadline('Please fix the following...', [
graphicsInterface_types_1.GraphicsTextEffect.Red,
graphicsInterface_types_1.GraphicsTextEffect.Bold,
]);
this.ui.renderLine('');
if (error instanceof error_1.default) {
this.ui.renderWarning(error.friendlyMessage());
}
else {
this.ui.renderWarning(`Unexpected error ${error.message}`);
}
this.ui.renderLine('');
}
async renderOverview(options = {}) {
const { ui } = this;
const { fields = this.getNamedFields().map((nf) => nf.name) } = options;
const actionMap = {};
const choices = this.getNamedFields()
.filter((namedField) => fields.indexOf(namedField.name) > -1)
.map((namedField) => {
const { field, name } = namedField;
const actionKey = `field:${name}`;
const action = {
type: FormBuilderActionType.EditField,
fieldName: name,
};
actionMap[actionKey] = action;
const value = this.get(name, { shouldValidate: false });
return {
value: actionKey,
label: `${field.label}: ${value ? value : '***missing***'}`,
};
});
actionMap['done'] = {
type: FormBuilderActionType.Done,
};
choices.push({
value: 'done',
label: 'Done',
});
const response = await ui.prompt({
type: 'select',
isRequired: true,
label: 'Select any field to edit',
options: {
choices,
},
});
const action = actionMap[response];
return action;
}
}
exports.default = FormComponent;
//# sourceMappingURL=FormComponent.js.map