Mari's guided journal software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

77 lines
3.1 KiB

import {AnySchemaDataFor} from "./SchemaData";
import {dump, load} from "js-yaml";
import {InquireFunction, ShowFunction} from "../prompts/Inquire";
import {EditorQuestion, ExpandQuestion} from "inquirer";
const RETRY = "Retry"
const ABORT = "Abort"
export interface YamlPromptOptions<ObjectT> {
schema: AnySchemaDataFor<ObjectT>
currentValue: ObjectT|undefined
name: string
}
export interface YamlPromptSetOptions<ObjectT> extends YamlPromptOptions<ObjectT> {
currentValue: ObjectT
}
export interface YamlPromptDependencies {
inquire: InquireFunction<EditorQuestion, string> & InquireFunction<ExpandQuestion, typeof RETRY|typeof ABORT>
showError: ShowFunction
}
export type YamlPromptFunction = (<ObjectT>(opts: YamlPromptSetOptions<ObjectT>) => Promise<ObjectT>) & (<ObjectT>(opts: YamlPromptOptions<ObjectT>) => Promise<ObjectT|undefined>)
export function yamlPrompt(deps: YamlPromptDependencies): YamlPromptFunction {
function injectedYamlPrompt<ObjectT>(opts: YamlPromptSetOptions<ObjectT>): Promise<ObjectT>
function injectedYamlPrompt<ObjectT>(opts: YamlPromptOptions<ObjectT>): Promise<ObjectT|undefined>
function injectedYamlPrompt<ObjectT>(opts: YamlPromptOptions<ObjectT>): Promise<ObjectT|undefined> {
return promptForYaml<ObjectT>(opts, deps)
}
return injectedYamlPrompt
}
export async function promptForYaml<ObjectT>({schema, currentValue, name}: YamlPromptSetOptions<ObjectT>, {inquire, showError}: YamlPromptDependencies): Promise<ObjectT>
export async function promptForYaml<ObjectT>({schema, currentValue, name}: YamlPromptOptions<ObjectT>, {inquire, showError}: YamlPromptDependencies): Promise<ObjectT|undefined>
export async function promptForYaml<ObjectT>({schema, currentValue, name}: YamlPromptOptions<ObjectT>, {inquire, showError}: YamlPromptDependencies): Promise<ObjectT|undefined> {
const original = dump(currentValue)
let text = original
while (true) {
const modified = await inquire({
type: "editor",
message: `View and edit ${name}:`,
default: text,
})
if (original !== modified) {
try {
const result = load(modified)
if (schema.validate(result)) {
return result
} else {
await showError(schema.validate.errors?.map((e) => e.toString()).join("; ") || "Failed validation")
}
} catch (e) {
await showError(e.toString())
}
const option = await inquire({
type: "expand",
message: "Choose how to proceed:",
choices: [
{key: "r", name: "Retry edits with current text", value: RETRY},
{key: "a", name: "Abort editing and keep original state", value: ABORT}
],
})
switch (option) {
default:
case RETRY:
text = modified
break
case ABORT:
return currentValue
}
} else {
return currentValue
}
}
}