Cleanup, commenting
This commit is contained in:
parent
d39e7f5154
commit
515217e347
1 changed files with 82 additions and 27 deletions
109
src/index.ts
109
src/index.ts
|
@ -1,19 +1,26 @@
|
||||||
import Path from "node:path";
|
import Path from "node:path";
|
||||||
import { parseArgs } from "node:util";
|
import { parseArgs } from "node:util";
|
||||||
import EMDY from "@endeavorance/emdy";
|
import EMDY from "@endeavorance/emdy";
|
||||||
import defaultStylesheet from "./defaults/default-style.css" with {
|
import type { BunFile } from "bun";
|
||||||
|
import DEFAULT_STYLESHEET from "./defaults/default-style.css" with {
|
||||||
type: "text",
|
type: "text",
|
||||||
};
|
};
|
||||||
import defaultTemplate from "./defaults/default-template.html" with {
|
import DEFAULT_TEMPLATE from "./defaults/default-template.html" with {
|
||||||
type: "text",
|
type: "text",
|
||||||
};
|
};
|
||||||
import { CLIError } from "./error";
|
import { CLIError } from "./error";
|
||||||
import type { BunFile } from "bun";
|
|
||||||
import { parseMarkdown } from "./markdown";
|
import { parseMarkdown } from "./markdown";
|
||||||
|
|
||||||
const DEFAULT_TEMPLATE_FILE = "_template.html";
|
const DEFAULT_TEMPLATE_FILE = "_template.html";
|
||||||
const DEFAULT_STYLESHEET_FILE = "_style.css";
|
const DEFAULT_STYLESHEET_FILE = "_style.css";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a file path, attempt to read the text of the file
|
||||||
|
* @param filePath - The path to the file to read
|
||||||
|
* @returns The text content of the file
|
||||||
|
*
|
||||||
|
* @throws CLIError if the file does not exist
|
||||||
|
*/
|
||||||
async function readFile(filePath: string): Promise<string> {
|
async function readFile(filePath: string): Promise<string> {
|
||||||
const file = Bun.file(filePath);
|
const file = Bun.file(filePath);
|
||||||
const exists = await file.exists();
|
const exists = await file.exists();
|
||||||
|
@ -23,7 +30,13 @@ async function readFile(filePath: string): Promise<string> {
|
||||||
return file.text();
|
return file.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
function replacePlaceholders(
|
/**
|
||||||
|
* Renders the provided template with the given data.
|
||||||
|
* @param template - The template string containing placeholders like %key%
|
||||||
|
* @param data - An object containing key-value pairs to replace in the template
|
||||||
|
* @returns The rendered string with all placeholders replaced by their corresponding values
|
||||||
|
*/
|
||||||
|
function renderTemplate(
|
||||||
template: string,
|
template: string,
|
||||||
data: Record<string, unknown>,
|
data: Record<string, unknown>,
|
||||||
): string {
|
): string {
|
||||||
|
@ -34,17 +47,39 @@ function replacePlaceholders(
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of options parsed from the command line arguments.
|
||||||
|
*/
|
||||||
interface CLIOptions {
|
interface CLIOptions {
|
||||||
|
/** A path to the output file */
|
||||||
outfile: string | null;
|
outfile: string | null;
|
||||||
|
|
||||||
|
/** A path to the output directory */
|
||||||
outdir: string | null;
|
outdir: string | null;
|
||||||
|
|
||||||
|
/** If true, force output to stdout */
|
||||||
stdout: boolean;
|
stdout: boolean;
|
||||||
|
|
||||||
|
/** The path to the template file */
|
||||||
templateFilePath: string | null;
|
templateFilePath: string | null;
|
||||||
|
|
||||||
|
/** The path to the stylesheet file */
|
||||||
stylesheetFilePath: string | null;
|
stylesheetFilePath: string | null;
|
||||||
|
|
||||||
|
/** If true, show help message */
|
||||||
help: boolean;
|
help: boolean;
|
||||||
|
|
||||||
|
/** If provided, overrides the document title */
|
||||||
title: string | null;
|
title: string | null;
|
||||||
|
|
||||||
|
/** If provided, overrides the current working directory (default: .) */
|
||||||
cwd: string;
|
cwd: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the command line arguments and return the options and positional arguments.
|
||||||
|
* @returns An object containing the parsed options and positional arguments
|
||||||
|
*/
|
||||||
function parseCLIArgs(): { options: CLIOptions; args: string[] } {
|
function parseCLIArgs(): { options: CLIOptions; args: string[] } {
|
||||||
const { values: flags, positionals } = parseArgs({
|
const { values: flags, positionals } = parseArgs({
|
||||||
args: Bun.argv.slice(2),
|
args: Bun.argv.slice(2),
|
||||||
|
@ -109,57 +144,69 @@ function parseCLIArgs(): { options: CLIOptions; args: string[] } {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to load a custom template, falling back to a default
|
||||||
|
* @param options - The CLI options containing the template file path
|
||||||
|
* @returns The template string
|
||||||
|
*/
|
||||||
async function loadTemplate(options: CLIOptions): Promise<string> {
|
async function loadTemplate(options: CLIOptions): Promise<string> {
|
||||||
if (options.templateFilePath) {
|
if (options.templateFilePath) {
|
||||||
return readFile(options.templateFilePath);
|
return readFile(options.templateFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultTemplateFilePath = Path.join(options.cwd, DEFAULT_TEMPLATE_FILE);
|
const checkTemplateFile = Bun.file(
|
||||||
const defaultTemplateFile = Bun.file(defaultTemplateFilePath);
|
Path.join(options.cwd, DEFAULT_TEMPLATE_FILE),
|
||||||
|
);
|
||||||
|
|
||||||
if (await defaultTemplateFile.exists()) {
|
if (await checkTemplateFile.exists()) {
|
||||||
return defaultTemplateFile.text();
|
return checkTemplateFile.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultTemplate;
|
return DEFAULT_TEMPLATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to load a custom stylesheet, falling back to a default
|
||||||
|
* @param options - The CLI options containing the stylesheet file path
|
||||||
|
* @returns The stylesheet string
|
||||||
|
*/
|
||||||
async function loadStylesheet(options: CLIOptions): Promise<string> {
|
async function loadStylesheet(options: CLIOptions): Promise<string> {
|
||||||
if (options.stylesheetFilePath) {
|
if (options.stylesheetFilePath) {
|
||||||
return readFile(options.stylesheetFilePath);
|
return readFile(options.stylesheetFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultStylesheetFilePath = Path.join(
|
const checkStylesheetFile = Bun.file(
|
||||||
options.cwd,
|
Path.join(options.cwd, DEFAULT_STYLESHEET_FILE),
|
||||||
DEFAULT_STYLESHEET_FILE,
|
|
||||||
);
|
);
|
||||||
const defaultStylesheetFile = Bun.file(defaultStylesheetFilePath);
|
|
||||||
|
|
||||||
if (await defaultStylesheetFile.exists()) {
|
if (await checkStylesheetFile.exists()) {
|
||||||
return defaultStylesheetFile.text();
|
return checkStylesheetFile.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultStylesheet;
|
return DEFAULT_STYLESHEET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build and write a file
|
||||||
|
* @param infile - The input file to read from
|
||||||
|
* @param outfile - The output file to write to
|
||||||
|
* @param options - The CLI options containing template and stylesheet paths
|
||||||
|
*/
|
||||||
async function buildFile(
|
async function buildFile(
|
||||||
infile: BunFile,
|
infile: BunFile,
|
||||||
outfile: BunFile,
|
outfile: BunFile,
|
||||||
options: CLIOptions,
|
options: CLIOptions,
|
||||||
): Promise<string> {
|
): Promise<void> {
|
||||||
const input = await infile.text();
|
const input = await infile.text();
|
||||||
const template = await loadTemplate(options);
|
const template = await loadTemplate(options);
|
||||||
const stylesheet = await loadStylesheet(options);
|
const stylesheet = await loadStylesheet(options);
|
||||||
|
|
||||||
const { content, ...props } = EMDY.parse(input) as Record<string, unknown> & {
|
const { content, ...props } = EMDY.parse(input) as Record<string, unknown> & {
|
||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = await parseMarkdown(content);
|
const html = await parseMarkdown(content);
|
||||||
|
const title = options.title ?? props.title ?? "Untitled";
|
||||||
const title = [options.title, props.title].find((t) => t) || "Untitled";
|
const templateData = {
|
||||||
|
|
||||||
const replacers = {
|
|
||||||
content: html,
|
content: html,
|
||||||
title,
|
title,
|
||||||
stylesheet: stylesheet,
|
stylesheet: stylesheet,
|
||||||
|
@ -168,13 +215,15 @@ async function buildFile(
|
||||||
...props,
|
...props,
|
||||||
};
|
};
|
||||||
|
|
||||||
const output = replacePlaceholders(template, replacers);
|
await Bun.write(outfile, renderTemplate(template, templateData));
|
||||||
|
|
||||||
Bun.write(outfile, output);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the output path based on the input path and options
|
||||||
|
* @param inputPath - The path of the input file
|
||||||
|
* @param options - The CLI options containing output directory
|
||||||
|
* @returns The resolved output path
|
||||||
|
*/
|
||||||
async function getOutputPath(inputPath: string, options: CLIOptions) {
|
async function getOutputPath(inputPath: string, options: CLIOptions) {
|
||||||
const inputDirname = Path.dirname(inputPath);
|
const inputDirname = Path.dirname(inputPath);
|
||||||
const inputBasename = Path.basename(inputPath);
|
const inputBasename = Path.basename(inputPath);
|
||||||
|
@ -189,6 +238,12 @@ async function getOutputPath(inputPath: string, options: CLIOptions) {
|
||||||
return Path.join(inputDirname, outputBasename);
|
return Path.join(inputDirname, outputBasename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the output file based on the input path and options
|
||||||
|
* @param inputPath - The path of the input file
|
||||||
|
* @param options - The CLI options containing output file and directory
|
||||||
|
* @returns The BunFile object representing the output file
|
||||||
|
*/
|
||||||
async function getOutputFile(
|
async function getOutputFile(
|
||||||
inputPath: string,
|
inputPath: string,
|
||||||
options: CLIOptions,
|
options: CLIOptions,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue