initial cli api, some movement on tool selection
This commit is contained in:
30
util/asciiArt.ts
Normal file
30
util/asciiArt.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export async function getAsciiArt(art: string) {
|
||||
const artFilePath = Deno.env.get("BEARMETAL_ASCII_PATH") ||
|
||||
getBearmetalAsciiPath();
|
||||
if (!artFilePath) return art;
|
||||
let artFileText: string;
|
||||
if (artFilePath.startsWith("http")) {
|
||||
artFileText = await fetch(artFilePath).then((res) => res.text());
|
||||
} else {
|
||||
artFileText = await Deno.readTextFile(artFilePath);
|
||||
}
|
||||
const parserRX = /begin\s+(\w+)\s*\n([\s\S]*?)\s*end\s*/g;
|
||||
let result = parserRX.exec(artFileText);
|
||||
|
||||
while (result !== null) {
|
||||
const [_, name, artText] = result;
|
||||
if (name === art) return artText;
|
||||
result = parserRX.exec(artFileText);
|
||||
}
|
||||
return art;
|
||||
}
|
||||
|
||||
function getBearmetalAsciiPath() {
|
||||
const filenameRX = /asciiarts?\.txt$/;
|
||||
for (const filename of Deno.readDirSync(".")) {
|
||||
if (filename.isFile && filenameRX.test(filename.name)) {
|
||||
return filename.name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
55
util/call.ts
Normal file
55
util/call.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
type transformer = (arg: string) => any;
|
||||
interface IConfig {
|
||||
multiTransform?: boolean;
|
||||
args?: string[];
|
||||
}
|
||||
|
||||
export async function call<T extends unknown[]>(
|
||||
tool: ToolFunc<T>,
|
||||
transforms: transformer[],
|
||||
conf?: IConfig,
|
||||
) {
|
||||
const config: IConfig = {};
|
||||
|
||||
if (typeof conf === "object") {
|
||||
Object.assign(config, conf);
|
||||
}
|
||||
|
||||
const args = config.args || Deno.args;
|
||||
const shouldPair = transforms.length === args.length;
|
||||
const multiTransform = config.multiTransform ||
|
||||
!shouldPair && transforms.length > 1;
|
||||
|
||||
const transformedArgs = args.map((arg, i) => {
|
||||
if (shouldPair) return transforms[i](arg);
|
||||
if (multiTransform) return transforms.reduce((a, b) => b(a), arg);
|
||||
return transforms[0] ? transforms[0](arg) : arg;
|
||||
});
|
||||
|
||||
await tool(...transformedArgs as T);
|
||||
}
|
||||
|
||||
type prompt = [string, (v?: string) => boolean] | string;
|
||||
|
||||
export async function callWithArgPrompt<T extends unknown[]>(
|
||||
tool: ToolFunc<T>,
|
||||
prompts: prompt[],
|
||||
args?: string[],
|
||||
) {
|
||||
function buildPromptTransform(p: prompt): transformer {
|
||||
let validation = (v?: string) => !!v;
|
||||
let pText = p as string;
|
||||
|
||||
if (Array.isArray(p)) {
|
||||
[pText, validation] = p;
|
||||
}
|
||||
|
||||
return (a: string) => {
|
||||
while (!validation(a)) {
|
||||
a = prompt(pText) || "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await call(tool, prompts.map(buildPromptTransform), { args });
|
||||
}
|
128
util/caseManagement.ts
Normal file
128
util/caseManagement.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
function lowerToPascalCase(str: string) {
|
||||
return str.replace(/(?:^|\s)\w/g, (match) => match.toUpperCase()).replaceAll(
|
||||
" ",
|
||||
"",
|
||||
);
|
||||
}
|
||||
function lowerToTrainCase(str: string) {
|
||||
return str.replace(/(?:^|\s)\w/g, (match) => match.toUpperCase()).replaceAll(
|
||||
" ",
|
||||
"-",
|
||||
);
|
||||
}
|
||||
|
||||
function lowerToCamelCase(str: string) {
|
||||
return str.trim().replace(/(?:\s)\w/g, (match) => match.toUpperCase())
|
||||
.replaceAll(" ", "");
|
||||
}
|
||||
|
||||
function lowerToSnakeCase(str: string) {
|
||||
return str.replace(" ", "_");
|
||||
}
|
||||
|
||||
function lowerToKebabCase(str: string) {
|
||||
return str.replace(" ", "-");
|
||||
}
|
||||
|
||||
function lowerToMacroCase(str: string) {
|
||||
return str.replace(/\w\S*/g, (match) => match.toUpperCase()).replaceAll(
|
||||
" ",
|
||||
"_",
|
||||
);
|
||||
}
|
||||
|
||||
function lowerToTitleCase(str: string) {
|
||||
return str.replace(/(?:^|\s)\w/g, (match) => match.toUpperCase());
|
||||
}
|
||||
|
||||
type CaseType =
|
||||
| "pascal"
|
||||
| "camel"
|
||||
| "snake"
|
||||
| "kebab"
|
||||
| "macro"
|
||||
| "upper"
|
||||
| "lower"
|
||||
| "train"
|
||||
| "title"
|
||||
| "";
|
||||
|
||||
function parseCase(str: string) {
|
||||
const isCaseMap = new Map<CaseType, (str: string) => boolean>([
|
||||
["pascal", (str: string) => {
|
||||
return /^[A-Z][a-zA-Z]*$/.test(str);
|
||||
}],
|
||||
["camel", (str: string) => {
|
||||
return /^[a-z][a-zA-Z]*$/.test(str);
|
||||
}],
|
||||
["snake", (str: string) => {
|
||||
return /^[a-z][a-z0-9_]*$/.test(str);
|
||||
}],
|
||||
["kebab", (str: string) => {
|
||||
return /^[a-z][a-z0-9-]*$/.test(str);
|
||||
}],
|
||||
["macro", (str: string) => {
|
||||
return /^[A-Z]*$/.test(str);
|
||||
}],
|
||||
["upper", (str: string) => {
|
||||
return /^[A-Z]*$/.test(str);
|
||||
}],
|
||||
["lower", (str: string) => {
|
||||
return /^[a-z]*$/.test(str);
|
||||
}],
|
||||
["train", (str: string) => {
|
||||
return /([A-Z][a-z]*(?:-|$))+/.test(str);
|
||||
}],
|
||||
]);
|
||||
for (const [key, value] of isCaseMap) {
|
||||
if (value(str)) return key;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function coerceCaseToLower(str: string, caseType: CaseType) {
|
||||
switch (caseType) {
|
||||
case "pascal":
|
||||
case "camel":
|
||||
return str.replace(/[A-Z]/g, (match) => " " + match.toLowerCase().trim());
|
||||
case "macro":
|
||||
case "snake":
|
||||
case "upper":
|
||||
return str.replace("_", " ").toLowerCase();
|
||||
case "train":
|
||||
case "kebab":
|
||||
return str.replace("-", " ").toLowerCase();
|
||||
default:
|
||||
return str.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
export function toCase(str: string, toCase: CaseType) {
|
||||
const caseType = parseCase(str) || "";
|
||||
console.log(caseType);
|
||||
if (caseType === toCase) return str;
|
||||
const lowerStr = coerceCaseToLower(str, caseType);
|
||||
console.log(lowerStr);
|
||||
switch (toCase) {
|
||||
case "pascal":
|
||||
return lowerToPascalCase(lowerStr);
|
||||
case "camel":
|
||||
return lowerToCamelCase(lowerStr);
|
||||
case "snake":
|
||||
return lowerToSnakeCase(lowerStr);
|
||||
case "kebab":
|
||||
return lowerToKebabCase(lowerStr);
|
||||
case "macro":
|
||||
return lowerToMacroCase(lowerStr);
|
||||
case "upper":
|
||||
return lowerStr.toUpperCase();
|
||||
case "lower":
|
||||
return lowerStr.toLowerCase();
|
||||
case "train":
|
||||
return lowerToTrainCase(lowerStr);
|
||||
case "title":
|
||||
return lowerToTitleCase(lowerStr);
|
||||
default:
|
||||
return str;
|
||||
}
|
||||
}
|
19
util/saveLoadPdf.ts
Normal file
19
util/saveLoadPdf.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
|
||||
export async function loadPdfForm(path: string) {
|
||||
const pdfDoc = await loadPdf(path);
|
||||
const form = pdfDoc.getForm();
|
||||
return form;
|
||||
}
|
||||
|
||||
export async function loadPdf(path: string) {
|
||||
const pdfBytes = await Deno.readFile(path);
|
||||
const pdfDoc = await PDFDocument.load(pdfBytes);
|
||||
return pdfDoc;
|
||||
}
|
||||
|
||||
export async function savePdf(doc: PDFDocument, path: string) {
|
||||
const pdfBytes = await doc.save();
|
||||
if (Deno.env.get("DRYRUN") || path.includes("dryrun")) return;
|
||||
await Deno.writeFile(path, pdfBytes);
|
||||
}
|
Reference in New Issue
Block a user