Pending changes to add API example

This commit is contained in:
Kevin FEDYNA
2025-01-20 16:44:52 +01:00
parent 282f618386
commit 9fee9ea0e8
7 changed files with 210 additions and 24 deletions
+65 -21
View File
@@ -1,8 +1,11 @@
import { parseArgs, type ParseOptions } from "@std/cli/parse-args";
import { createModule } from "$root/toolbox/module.ts";
import { createModule } from "$root/toolbox/module/create.ts";
import { listModules } from "$root/toolbox/module/list.ts";
type CLICommand = (...args: Array<string>) => void;
type CLIAsyncCommand = (...args: Array<string>) => Promise<void>;
interface CLI {
[command: string]: CLI | (() => void) | (() => Promise<void>);
[command: string]: CLI | CLICommand | CLIAsyncCommand;
}
const argSpec: ParseOptions = {};
@@ -10,51 +13,92 @@ const argSpec: ParseOptions = {};
const cli: CLI = {
help: () => displayHelp(cli),
module: {
create: createModule,
list: () => listModules(),
create: (name: string) => createModule(name),
},
};
function displayHelp(cli: CLI, errorMessage?: string): never {
function displayHelp(
cli: CLI | CLICommand | CLIAsyncCommand,
errorMessage?: string,
): never {
const loggingFunction = errorMessage ? console.error : console.log;
if (errorMessage) {
console.error(errorMessage);
}
loggingFunction("Commands:");
if (typeof cli == "function") {
loggingFunction("Usage:");
displayFunctionHelp(cli, loggingFunction);
} else {
loggingFunction("Commands:");
displayObjectHelp(cli, loggingFunction);
}
Deno.exit(errorMessage ? 1 : 0);
}
function runCommand(commands: Array<string | number>, cli: CLI): never | void | Promise<void> {
function displayObjectHelp(
cli: CLI,
loggingFunction: typeof console.log,
level: number = 1,
) {
for (const [key, value] of Object.entries(cli)) {
if (typeof value == "function") {
displayFunctionHelp(value, loggingFunction, level);
} else {
loggingFunction(`${" ".repeat(level * 2)}${key}`);
displayObjectHelp(value, loggingFunction, level + 1);
}
}
}
function displayFunctionHelp(
cli: CLICommand | CLIAsyncCommand,
loggingFunction: typeof console.log,
level: number = 1,
) {
const command = cli.name;
const matched = cli.toString().match(/(?<=^\()[^\)]+(?=\))/);
const args = matched?.[0].split(",").map((arg) => `<${arg.trim()}>`);
loggingFunction(
`${" ".repeat(level * 2)}${command} ${args?.join(" ") ?? ""}`,
);
}
function runCommand(
commands: Array<string | number>,
cli: CLI,
): never | {
command: CLICommand | CLIAsyncCommand;
args: Array<string | number>;
} {
if (commands.length == 0) {
console.error(
`No command provided. Available commands are ${
JSON.stringify(Object.keys(cli))
}.`,
);
Deno.exit(1);
displayHelp(cli, `No command provided.`);
}
const command = commands.shift()!.toString();
if (cli[command] == undefined) {
console.error(
`Command "${command}" doesn't exist. Available commands are ${
JSON.stringify(Object.keys(cli))
}.`,
);
Deno.exit(1);
displayHelp(cli, `Command "${command}" doesn't exist.`);
}
if (typeof cli[command] == "object") {
return runCommand(commands, cli[command]);
}
return cli[command]();
if (cli[command].length != commands.length) {
displayHelp(cli[command], `Wrong usage of command "${command}".`);
}
return { command: cli[command], args: commands };
}
function main() {
const args = parseArgs(Deno.args, argSpec);
runCommand(args._, cli);
const argv = parseArgs(Deno.args, argSpec);
const { command, args } = runCommand(argv._, cli);
command(...args.map((element) => element.toString()));
}
main();
-3
View File
@@ -1,3 +0,0 @@
export async function createModule() {
}
+125
View File
@@ -0,0 +1,125 @@
export async function createModule(name: string): Promise<void> {
console.log(`Checking for module ${name}...`);
try {
await Deno.mkdir(`routes/(apps)/${name}`);
} catch (error) {
if (!(error instanceof Deno.errors.AlreadyExists)) {
throw error;
}
console.error(`Some module is already named ${name}, aborting.`);
Deno.exit(1);
}
const capitalizedName = `${name[0].toUpperCase()}${
name.substring(1).toLowerCase()
}`;
Promise.allSettled([
createDir(`routes/(apps)/${name}/(_props)`),
createDir(`routes/(apps)/${name}/partials`),
createDir(`routes/(apps)/${name}/(_islands)`),
createDir(`routes/(apps)/${name}/(_components)`),
createDir(`routes/(apps)/${name}/api`),
]);
Promise.allSettled([
createFile(
`routes/(apps)/${name}/index.tsx`,
getIndexContent(capitalizedName),
),
createFile(
`routes/(apps)/${name}/(_props)/props.ts`,
getPropsContent(capitalizedName),
),
createFile(
`routes/(apps)/${name}/partials/index.tsx`,
getPartialIndexContent(capitalizedName),
),
createFile(
`routes/(apps)/${name}/api/example.ts`,
getApiExampleContent(capitalizedName),
),
]);
const formatter = new Deno.Command(Deno.execPath(), {
args: [
"fmt",
`routes/(apps)/${name}`,
],
});
formatter.output();
}
function createFile(path: string, content: string): Promise<void> {
console.log(`Creating file ${path}...`);
return Deno.writeTextFile(path, content);
}
function createDir(path: string): Promise<void> {
console.log(`Creating directory ${path}...`);
return Deno.mkdir(path);
}
function getIndexContent(_name: string) {
return `
import makeIndex from "$root/defaults/makeIndex.ts";
export default makeIndex(import.meta.dirname!);
`;
}
function getPartialIndexContent(name: string) {
return `
import { EmptyObject } from "$root/defaults/interfaces.ts";
import {
getPartialsConfig,
makePartials,
} from "$root/defaults/makePartials.tsx";
type ${name}IndexProps = EmptyObject;
export function Index(_props: ${name}IndexProps) {
return <h2>Welcome to ${name}.</h2>;
}
export const config = getPartialsConfig();
export default makePartials(Index);
`;
}
function getPropsContent(name: string) {
return `
import { AppProperties } from "$root/defaults/interfaces.ts";
const properties: AppProperties = {
name: "${name}",
icon: "school",
pages: {
index: "Homepage",
},
adminOnly: [],
hint: "PolyMPR module",
};
export default properties;
`;
}
function getApiExampleContent(name: string) {
return `
import { AppProperties } from "$root/defaults/interfaces.ts";
const properties: AppProperties = {
name: "${name}",
icon: "school",
pages: {
index: "Homepage",
},
adminOnly: [],
hint: "PolyMPR module",
};
export default properties;
`;
}
+7
View File
@@ -0,0 +1,7 @@
export async function listModules(): Promise<void> {
for await (const path of Deno.readDir("routes/(apps)")) {
if (path.isDirectory) {
console.log(path.name);
}
}
}