Organize into folders
This commit is contained in:
parent
84b8f1c9d6
commit
2e0d4b45ea
12 changed files with 121 additions and 64 deletions
|
@ -7,7 +7,8 @@
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"ignoreUnknown": false,
|
"ignoreUnknown": false,
|
||||||
"ignore": ["*.d.ts", "*.json"]
|
"ignore": ["*.d.ts", "*.json"],
|
||||||
|
"include": ["./src/**/*.ts"]
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|
42
src/index.ts
42
src/index.ts
|
@ -1,15 +1,32 @@
|
||||||
|
import { watch } from "node:fs/promises";
|
||||||
import {
|
import {
|
||||||
serializePlaybill,
|
|
||||||
ValidatedPlaybillSchema,
|
ValidatedPlaybillSchema,
|
||||||
|
serializePlaybill,
|
||||||
} from "@proscenium/playbill";
|
} from "@proscenium/playbill";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { watch } from "node:fs/promises";
|
import { loadFromBinding, resolveBindingPath } from "#filetypes/binding";
|
||||||
import { loadFromBinding, resolveBindingPath } from "./filetypes/binding";
|
import { CLIError, MuseError } from "#lib/errors";
|
||||||
import { usage } from "./usage";
|
import { renderAsHTML } from "#renderers/html";
|
||||||
import { CLIError, MuseError } from "./errors";
|
import { type CLIArguments, parseCLIArguments } from "#util/args";
|
||||||
import { renderAsHTML } from "./renderers/html";
|
import { getAbsoluteDirname } from "#util/files";
|
||||||
import { parseCLIArguments, type CLIArguments } from "./args";
|
import { version } from "../package.json" with { type: "json" };
|
||||||
import { fullDirname } from "./util/files";
|
|
||||||
|
const usage = `
|
||||||
|
${chalk.bold("muse")} - Compile and validate Playbills for Proscenium
|
||||||
|
${chalk.dim(`v${version}`)}
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
muse [/path/to/binding.yaml] <options>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--check Only load and check the current binding and resources, but do not compile
|
||||||
|
--write Write the output to a file. If not specified, outputs to stdout
|
||||||
|
--outfile Specify the output file path [default: playbill.json]
|
||||||
|
--verbose, -v Verbose output
|
||||||
|
--minify, -m Minify the output JSON
|
||||||
|
--watch Watch the directory for changes and recompile
|
||||||
|
--help, -h Show this help message
|
||||||
|
`.trim();
|
||||||
|
|
||||||
enum ExitCode {
|
enum ExitCode {
|
||||||
Success = 0,
|
Success = 0,
|
||||||
|
@ -71,17 +88,14 @@ async function main(): Promise<number> {
|
||||||
return ExitCode.Success;
|
return ExitCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- ARG VALIDATION -- //
|
|
||||||
if (options.check && options.write) {
|
|
||||||
throw new CLIError("Cannot use --check and --write together");
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Processing ${cliArguments.inputFilePath}`);
|
console.log(`Processing ${cliArguments.inputFilePath}`);
|
||||||
let lastProcessResult = await processBinding(cliArguments);
|
let lastProcessResult = await processBinding(cliArguments);
|
||||||
|
|
||||||
if (options.watch) {
|
if (options.watch) {
|
||||||
const watchDir = fullDirname(cliArguments.inputFilePath);
|
const watchDir = getAbsoluteDirname(cliArguments.inputFilePath);
|
||||||
|
|
||||||
console.log(`Watching ${watchDir} for changes`);
|
console.log(`Watching ${watchDir} for changes`);
|
||||||
|
|
||||||
const watcher = watch(watchDir, {
|
const watcher = watch(watchDir, {
|
||||||
recursive: true,
|
recursive: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import {
|
||||||
|
type Playbill,
|
||||||
|
type UnknownResource,
|
||||||
|
getEmptyPlaybill,
|
||||||
|
} from "@proscenium/playbill";
|
||||||
import { Glob } from "bun";
|
import { Glob } from "bun";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
import {
|
import { FileNotFoundError } from "#lib/errors";
|
||||||
getEmptyPlaybill,
|
import { loadYAMLFileOrFail } from "#util/files";
|
||||||
type UnknownResource,
|
|
||||||
type Playbill,
|
|
||||||
} from "@proscenium/playbill";
|
|
||||||
import { loadYAMLFileOrFail } from "../util/files";
|
|
||||||
import { loadResourceFile } from "./resource";
|
import { loadResourceFile } from "./resource";
|
||||||
import { FileNotFoundError } from "../errors";
|
|
||||||
|
|
||||||
const HTMLRenderOptionsSchema = z.object({
|
const HTMLRenderOptionsSchema = z.object({
|
||||||
styles: z.array(z.string()).optional(),
|
styles: z.array(z.string()).optional(),
|
|
@ -19,7 +19,7 @@ export class FileError extends MuseError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MalformedResourceFileError extends FileError { }
|
export class MalformedResourceFileError extends FileError {}
|
||||||
|
|
||||||
export class FileNotFoundError extends FileError {
|
export class FileNotFoundError extends FileError {
|
||||||
constructor(filePath: string) {
|
constructor(filePath: string) {
|
||||||
|
@ -29,4 +29,4 @@ export class FileNotFoundError extends FileError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CLIError extends MuseError { }
|
export class CLIError extends MuseError {}
|
|
@ -27,6 +27,11 @@ export function extractFrontmatter(content: string) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a string of a markdown document, extract the markdown content
|
||||||
|
* @param content The raw markdown content
|
||||||
|
* @returns The markdown content without frontmatter
|
||||||
|
*/
|
||||||
export function extractMarkdown(content: string): string {
|
export function extractMarkdown(content: string): string {
|
||||||
if (content.trim().indexOf("---") !== 0) {
|
if (content.trim().indexOf("---") !== 0) {
|
||||||
return content;
|
return content;
|
||||||
|
@ -54,6 +59,12 @@ ${markdown.trim()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a string of markdown, convert it to HTML
|
||||||
|
*
|
||||||
|
* @param markdown The markdown to convert
|
||||||
|
* @returns A promise resolving to the HTML representation of the markdown
|
||||||
|
*/
|
||||||
export async function markdownToHtml(markdown: string): Promise<string> {
|
export async function markdownToHtml(markdown: string): Promise<string> {
|
||||||
const rendered = await unified()
|
const rendered = await unified()
|
||||||
.use(remarkParse)
|
.use(remarkParse)
|
|
@ -1,13 +1,13 @@
|
||||||
import {
|
import {
|
||||||
|
ResourceMap,
|
||||||
type UnknownResource,
|
type UnknownResource,
|
||||||
UnknownResourceSchema,
|
UnknownResourceSchema,
|
||||||
ResourceMap,
|
|
||||||
} from "@proscenium/playbill";
|
} from "@proscenium/playbill";
|
||||||
import YAML, { YAMLParseError } from "yaml";
|
import YAML, { YAMLParseError } from "yaml";
|
||||||
import { ZodError } from "zod";
|
import { ZodError } from "zod";
|
||||||
import { MalformedResourceFileError } from "../errors";
|
import { MalformedResourceFileError } from "#lib/errors";
|
||||||
|
import { loadFileOrFail } from "#util/files";
|
||||||
import { extractFrontmatter, extractMarkdown } from "./markdown";
|
import { extractFrontmatter, extractMarkdown } from "./markdown";
|
||||||
import { loadFileOrFail } from "../util/files";
|
|
||||||
|
|
||||||
type FileFormat = "yaml" | "markdown";
|
type FileFormat = "yaml" | "markdown";
|
||||||
|
|
|
@ -6,14 +6,14 @@ import type {
|
||||||
Rule,
|
Rule,
|
||||||
ValidatedPlaybill,
|
ValidatedPlaybill,
|
||||||
} from "@proscenium/playbill";
|
} from "@proscenium/playbill";
|
||||||
import { markdownToHtml } from "../filetypes/markdown";
|
import type { PlaybillBinding } from "lib/binding";
|
||||||
import type { PlaybillBinding } from "../filetypes/binding";
|
import { markdownToHtml } from "lib/markdown";
|
||||||
import rehypeParse from "rehype-parse";
|
|
||||||
import { unified } from "unified";
|
|
||||||
import rehypeFormat from "rehype-format";
|
|
||||||
import rehypeStringify from "rehype-stringify";
|
|
||||||
import capitalize from "lodash-es/capitalize";
|
import capitalize from "lodash-es/capitalize";
|
||||||
import { FileNotFoundError } from "../errors";
|
import rehypeFormat from "rehype-format";
|
||||||
|
import rehypeParse from "rehype-parse";
|
||||||
|
import rehypeStringify from "rehype-stringify";
|
||||||
|
import { unified } from "unified";
|
||||||
|
import { FileNotFoundError } from "#lib/errors";
|
||||||
|
|
||||||
async function renderGuide(guide: Guide): Promise<string> {
|
async function renderGuide(guide: Guide): Promise<string> {
|
||||||
const html = await markdownToHtml(guide.description);
|
const html = await markdownToHtml(guide.description);
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
const Renderers = ["json", "html"] as const;
|
|
||||||
export const RendererSchema = z.enum(Renderers);
|
|
||||||
export type Renderer = "json" | "html";
|
|
18
src/usage.ts
18
src/usage.ts
|
@ -1,18 +0,0 @@
|
||||||
import chalk from "chalk";
|
|
||||||
import { version } from "../package.json" with { type: "json" };
|
|
||||||
|
|
||||||
export const usage = `
|
|
||||||
${chalk.bold("muse")} - Compile and validate Playbills for Proscenium
|
|
||||||
${chalk.dim(`v${version}`)}
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
muse [/path/to/binding.yaml] <options>
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--check Only load and check the current binding and resources, but do not compile
|
|
||||||
--write Write the output to a file. If not specified, outputs to stdout
|
|
||||||
--outfile Specify the output file path [default: playbill.json]
|
|
||||||
--verbose, -v Verbose output
|
|
||||||
--minify, -m Minify the output JSON
|
|
||||||
--help, -h Show this help message
|
|
||||||
`.trim();
|
|
|
@ -1,7 +1,14 @@
|
||||||
import { parseArgs } from "node:util";
|
import { parseArgs } from "node:util";
|
||||||
import { RendererSchema, type Renderer } from "./types";
|
import { z } from "zod";
|
||||||
import { MuseError } from "./errors";
|
import { CLIError, MuseError } from "#lib/errors";
|
||||||
|
|
||||||
|
const Renderers = ["json", "html"] as const;
|
||||||
|
const RendererSchema = z.enum(Renderers);
|
||||||
|
type Renderer = z.infer<typeof RendererSchema>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shape representing the arguments passed to the CLI
|
||||||
|
*/
|
||||||
export interface CLIArguments {
|
export interface CLIArguments {
|
||||||
inputFilePath: string;
|
inputFilePath: string;
|
||||||
|
|
||||||
|
@ -16,6 +23,14 @@ export interface CLIArguments {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an array of CLI arguments, parse them into a structured object
|
||||||
|
*
|
||||||
|
* @param argv The arguments to parse
|
||||||
|
* @returns The parsed CLI arguments
|
||||||
|
*
|
||||||
|
* @throws {CLIError} if the arguments are invalid
|
||||||
|
*/
|
||||||
export function parseCLIArguments(argv: string[]): CLIArguments {
|
export function parseCLIArguments(argv: string[]): CLIArguments {
|
||||||
const { values: options, positionals: args } = parseArgs({
|
const { values: options, positionals: args } = parseArgs({
|
||||||
args: argv,
|
args: argv,
|
||||||
|
@ -59,6 +74,11 @@ export function parseCLIArguments(argv: string[]): CLIArguments {
|
||||||
allowPositionals: true,
|
allowPositionals: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// -- ARG VALIDATION -- //
|
||||||
|
if (options.check && options.write) {
|
||||||
|
throw new CLIError("Cannot use --check and --write together");
|
||||||
|
}
|
||||||
|
|
||||||
const parsedRenderer = RendererSchema.safeParse(options.renderer);
|
const parsedRenderer = RendererSchema.safeParse(options.renderer);
|
||||||
|
|
||||||
if (!parsedRenderer.success) {
|
if (!parsedRenderer.success) {
|
|
@ -1,7 +1,14 @@
|
||||||
import YAML from "yaml";
|
|
||||||
import { FileError, FileNotFoundError } from "../errors";
|
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import YAML from "yaml";
|
||||||
|
import { FileError, FileNotFoundError } from "../lib/errors";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a file from the filesystem or throw an error if it does not exist.
|
||||||
|
* @param filePath The path to the file to load
|
||||||
|
* @returns The contents of the file as a string
|
||||||
|
*
|
||||||
|
* @throws {FileNotFoundError} if the file does not exist
|
||||||
|
*/
|
||||||
export async function loadFileOrFail(filePath: string): Promise<string> {
|
export async function loadFileOrFail(filePath: string): Promise<string> {
|
||||||
const fileToLoad = Bun.file(filePath);
|
const fileToLoad = Bun.file(filePath);
|
||||||
const fileExists = await fileToLoad.exists();
|
const fileExists = await fileToLoad.exists();
|
||||||
|
@ -13,6 +20,15 @@ export async function loadFileOrFail(filePath: string): Promise<string> {
|
||||||
return await fileToLoad.text();
|
return await fileToLoad.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and parse a YAML file or throw an error if the file doesnt exist
|
||||||
|
* or the yaml fails to parse
|
||||||
|
* @param filePath The path to the file to load
|
||||||
|
* @returns The parsed contents of the file
|
||||||
|
*
|
||||||
|
* @throws {FileNotFoundError} if the file does not exist
|
||||||
|
* @throws {FileError} if the file is not valid YAML
|
||||||
|
*/
|
||||||
export async function loadYAMLFileOrFail(filePath: string): Promise<unknown> {
|
export async function loadYAMLFileOrFail(filePath: string): Promise<unknown> {
|
||||||
try {
|
try {
|
||||||
return YAML.parse(await loadFileOrFail(filePath));
|
return YAML.parse(await loadFileOrFail(filePath));
|
||||||
|
@ -21,6 +37,12 @@ export async function loadYAMLFileOrFail(filePath: string): Promise<unknown> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fullDirname(inputPath: string): string {
|
/**
|
||||||
return path.resolve(path.dirname(inputPath));
|
* Returns the absolute path of the directory containing the given file
|
||||||
|
*
|
||||||
|
* @param filePath The path to the file
|
||||||
|
* @returns The absolute path of the directory containing the file
|
||||||
|
*/
|
||||||
|
export function getAbsoluteDirname(filePath: string): string {
|
||||||
|
return path.resolve(path.dirname(filePath));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,18 @@
|
||||||
// Some stricter flags (disabled by default)
|
// Some stricter flags (disabled by default)
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": false,
|
"noUnusedParameters": false,
|
||||||
"noPropertyAccessFromIndexSignature": false
|
"noPropertyAccessFromIndexSignature": false,
|
||||||
|
"baseUrl": "./src",
|
||||||
|
"paths": {
|
||||||
|
"#lib/*": [
|
||||||
|
"./lib/*"
|
||||||
|
],
|
||||||
|
"#renderers/*": [
|
||||||
|
"./renderers/*"
|
||||||
|
],
|
||||||
|
"#util/*": [
|
||||||
|
"./util/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue