diff --git a/README.md b/README.md index a1543bf..b985fbb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,20 @@ -# Playbill Builder CLI +# Muse -This is a CLI tool for compiling Markdown and YAML files into a validated Playbill for [Proscenium](https://proscenium.game) +A CLI for wrangling directories of source files. + +Like a static generator, but for whatever. + +## Overview + +**Muse** is a CLI and toolchain for operating on directories of +json, yaml, toml, and markdown files. Each file can specify any shape +of data. Muse scans included files, parses them into data, and streams +the loaded data through processors and plugins. + +Each processor can modify the data at compile time, as well as enact +side effects such as writing files to disk. + +Muse does not edit source files, it only reads them in. ## Usage @@ -9,209 +23,24 @@ Usage: muse [/path/to/binding.yaml] Options: - --check Only load and check the current binding and resources, but do not compile - --outfile, -o Specify the output file path. If not specified, output to stdout - --watch, -w Watch the directory for changes and recompile - --renderer, -r Specify the output renderer. Options: json, html + --stdout -s Output final data to stdout + --verbose, -v Enable verbose logging --help, -h Show this help message ``` ## Binding File -Each Muse project should specify a `binding.yaml` file with the following shape: +Each Muse project should specify a `binding` file with the following shape: ```yaml -name: My Playbill # Required -author: My Name # Required -version: 0.0.1 # Required -extend: ../another-playbill # Optional +include: + - ../another-project # Optional files: # Optional - "**/*.yaml" -styles: # Optional - - stylesheet.css -terms: # Optional - Some Term: Some Definition - Another Term: Another Definition +contentKey: "content" # Optional +options: # Optional + someOption: someValue +processors: + - first-processor + - second-processor ``` -The **Binding** file is used to specify the metadata for the Playbill, as well as the files to be compiled. It is also the entry point for a project. - -When using the `muse` CLI, you must provide either a path to a `binding.yaml` file or a directory which contains a `binding.yaml` file. - -## Common Types - -Many Playbill components share common properties that expect a value -from a predefined list. These are the common types used in the Playbill. - -### `Roll` Options - -- `none` -- `attack` -- `fate` -- `muscle` -- `focus` -- `knowledge` -- `charm` -- `cunning` -- `spark` - -### `Damage Type` Options - -- `phy` (denotes "physical damage") -- `arc` (denotes "arcane damage") - -### `Prowess` Options - -- `novice` -- `adept` -- `master` - -### `Challenge` Options - -- `novice` -- `adept` -- `master` -- `theatrical` - -### `Ability Type` Options - -- `action` -- `cue` -- `trait` - -## Definition Shapes - -These YAML representations of definitions show the properties available for each Playbill component. - -Note that every Playbill component definition can define the following properties: - -```yaml -id: an-id # defaults to a slugified version of the file name -name: Component Name # defaults to the file name -description: Markdown description # defaults to a placeholder -categories: # defaults to no categories - - list - - of - - categories -``` - -### Ability Definition - -```yaml -$define: ability -type: # Defaults to action -ap: 0 # AP cost to use this ability (default 0) -hp: 0 # HP cost to use this ability (default 0) -ep: 0 # EP cost to use this ability (default 0) -xp: 0 # XP cost to learn this ability (default 1) -damage: 0 # Damage dealt by this ability (default 0) -damageType: # Type of damage dealt by this ability (default phy) -roll: # Roll type for this ability (default none) -``` - -### Blueprint Definition - -```yaml -$define: blueprint -species: species-id # ID of the species this blueprint is for -items: # List of item IDs (default empty) - - item-id -abilities: # List of ability IDs (default empty) - - ability-id -ap: 0 # Starting AP (default 4) -hp: 0 # Starting HP (default 5) -ep: 0 # Starting EP (default 1) -xp: 0 # Starting XP (default 0) -muscle: # Starting muscle prowess (default novice) -focus: # Starting focus prowess (default novice) -knowledge: # Starting knowledge prowess (default novice) -charm: # Starting charm prowess (default novice) -cunning: # Starting cunning prowess (default novice) -spark: # Starting spark prowess (default novice) -``` - -### Item Definition - -```yaml -$define: item -type: # Defaults to wielded -rarity: # Defaults to common -affinity: # Defaults to none -damage: 0 # Defaults to 0 -damageType: # Defaults to phy -hands: 1 | 2 # Only for wielded items -slot: # Only for worn items -``` - -#### `Item Type` Options - -- `wielded` -- `worn` -- `trinket` - -#### `Rarity` Options - -- `common` -- `uncommon` -- `rare` -- `legendary` - -#### `Item Slot` Options - -- `headgear` -- `outfit` -- `gloves` -- `boots` -- `adornment` - -### Method Definition - -```yaml -$define: method -curator: Someone # The name of the curator -abilities: # A 2-d array of ability IDs - - [rank-1-ability-id-one, rank-1-ability-id-two] - - [rank-2-ability-id-one] -``` - -### Resource Definition - -```yaml -$define: resource -type: # Defaults to text -url: https://url.com/image.jpeg # Only for image resources -data: # Only for table resources -``` - -#### `Resource Type` Options - -- `text` -- `image` -- `table` - -### Rule Definition - -```yaml -$define: rule -overrule: another-rule-id # Optional -order: 0 # Optional -``` - -### Species Definition - -```yaml -$define: species -hands: 2 # Defaults to 2 -abilities: # A list of innate ability IDs - - some-ability-id - - another-ability-id -ap: 0 # Starting AP modifier -hp: 0 # Starting HP modifier -ep: 0 # Starting EP modifier -xp: 0 # Starting XP modifier -muscle: # Defaults to novice -focus: # Defaults to novice -knowledge: # Defaults to novice -charm: # Defaults to novice -cunning: # Defaults to novice -spark: # Defaults to novice -``` diff --git a/demo/main/binding.md b/demo/main/binding.md new file mode 100644 index 0000000..b660a51 --- /dev/null +++ b/demo/main/binding.md @@ -0,0 +1,11 @@ +--- +markdownKey: description +options: + dunks: + key: dunkaroos +processors: + - ./processors/scream.js + - ./processors/announce-slam-dunks.js +--- + +A markdown-powered binding file! diff --git a/demo/main/binding.yaml b/demo/main/binding.yaml deleted file mode 100644 index 9f9e12c..0000000 --- a/demo/main/binding.yaml +++ /dev/null @@ -1,3 +0,0 @@ -markdownKey: description -processors: - - ./processors/scream.js diff --git a/demo/main/processors/announce-slam-dunks.js b/demo/main/processors/announce-slam-dunks.js new file mode 100644 index 0000000..24cdb96 --- /dev/null +++ b/demo/main/processors/announce-slam-dunks.js @@ -0,0 +1,13 @@ +export const name = "Announce Slam Dunks"; + +export const process = (binding, { dunks }) => { + const slamDunkKey = dunks?.key ?? "slamDunks"; + + for (const entry of binding.entries) { + if (slamDunkKey in entry.data) { + console.log(`Slam dunk!`); + } + } + + return binding; +}; diff --git a/demo/main/processors/scream.js b/demo/main/processors/scream.js index 9b5132d..11f177d 100644 --- a/demo/main/processors/scream.js +++ b/demo/main/processors/scream.js @@ -1,5 +1,5 @@ export const name = "Scream"; -export function process(binding, opts) { +export function process(binding) { const modifiedEntries = binding.entries.map(entry => { if (binding.markdownKey in entry.data) { entry.data = { diff --git a/demo/main/stats/statistics.toml b/demo/main/stats/statistics.toml index 8355b1e..d28b28b 100644 --- a/demo/main/stats/statistics.toml +++ b/demo/main/stats/statistics.toml @@ -1 +1,2 @@ -slamDunks = 100 +player = "Flynn" +dunkaroos = 100 diff --git a/package.json b/package.json index 0a9db1a..e9fae55 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,17 @@ { "name": "@proscenium/muse", - "version": "0.0.1", - "module": "index.ts", + "version": "0.1.0", + "module": "dist/index.js", + "exports": { + ".": { + "import": "./dist/muse.js", + "types": "./dist/muse.d.ts" + } + }, "type": "module", + "files": [ + "dist" + ], "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/bun": "latest", @@ -20,9 +29,11 @@ }, "scripts": { "fmt": "bunx --bun biome check --fix", - "build": "bun build ./src/index.ts --outfile muse --compile", - "demo": "bun run ./src/index.ts -- ./demo-data/great-spires/binding.yaml", + "clean": "rm -rf dist", + "types": "dts-bundle-generator -o dist/muse.d.ts --project ./tsconfig.json ./src/exports.ts", + "compile": "bun build ./src/cli.ts --outfile ./dist/muse --compile", + "build": "bun run clean && bun run compile && bun run types", "build:install": "bun run build && mv muse ~/.local/bin/muse", - "types": "dts-bundle-generator -o types/muse.d.ts --project ./tsconfig.json ./src/types.ts" + "demo": "bun run ./src/cli.ts -- ./demo/main" } } diff --git a/src/args.ts b/src/args.ts deleted file mode 100644 index 09fe7a8..0000000 --- a/src/args.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { parseArgs } from "node:util"; -import chalk from "chalk"; -import { version } from "../package.json" with { type: "json" }; - -export const USAGE = ` -${chalk.bold("muse")} - Compile and process troves of data -${chalk.dim(`v${version}`)} - -Usage: - muse [/path/to/binding.yaml] - -Options: - --stdout -s Output final data to stdout - --verbose, -v Enable verbose logging - --help, -h Show this help message -`.trim(); - -/** - * A shape representing the arguments passed to the CLI - */ -export interface CLIArguments { - inputFilePath: string; - - options: { - help: boolean; - verbose: boolean; - stdout: boolean; - }; -} - -/** - * 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 { - const { values: options, positionals: args } = parseArgs({ - args: argv, - options: { - help: { - short: "h", - default: false, - type: "boolean", - }, - verbose: { - short: "v", - default: false, - type: "boolean", - }, - stdout: { - short: "s", - default: false, - type: "boolean", - }, - }, - strict: true, - allowPositionals: true, - }); - - return { - inputFilePath: args[0] ?? "./binding.yaml", - - options: { - help: options.help, - verbose: options.verbose, - stdout: options.stdout, - }, - }; -} diff --git a/src/binding.ts b/src/binding.ts index fd57739..9499757 100644 --- a/src/binding.ts +++ b/src/binding.ts @@ -1,26 +1,42 @@ import path, { dirname } from "node:path"; import { Glob } from "bun"; -import z from "zod"; import { FileNotFoundError, MuseError } from "./errors"; -import { parseMuseFile, type MuseEntry } from "./muse-file"; +import { parseMuseFile } from "./parse"; +import { + type Binding, + BindingSchema, + type MuseEntry, + type MuseProcessor, +} from "./types"; +import { resolveFilePath } from "./util"; -// binding.yaml file schema -const BindingSchema = z.object({ - include: z.array(z.string()).default([]), - markdownKey: z.string().default("content"), - files: z - .array(z.string()) - .default(["**/*.yaml", "**/*.md", "**/*.toml", "**/*.json"]), - options: z.record(z.string(), z.any()).default({}), - processors: z.array(z.string()).default([]), -}); +async function loadProcessor( + bindingDirname: string, + processorPath: string, +): Promise { + const resolvedProcessorPath = path.resolve(bindingDirname, processorPath); + const { process, name, description } = await import(resolvedProcessorPath); -type ParsedBinding = z.infer; + if (!process || typeof process !== "function") { + throw new MuseError( + `Processor at ${processorPath} does not export a process() function`, + ); + } + const processorName = String(name ?? "Unnamed Processor"); + const processorDescription = String(description ?? "No description provided"); + + return { + filePath: resolvedProcessorPath, + process: process as MuseProcessor["process"], + name: processorName, + description: processorDescription, + }; +} /** - * Given a path, find the binding.yaml file - * If the path is to a directory, check for a binding.yaml inside - * If the path is to a file, check if it exists and is a binding.yaml + * Given a path, find the binding file + * If the path is to a directory, check for a binding inside + * Check order: binding.json, binding.yaml, binding.toml, binding.md * Otherwise throw an error * * @param bindingPath - The path to the binding file @@ -30,45 +46,50 @@ export async function resolveBindingPath(bindingPath: string): Promise { // If the path does not specify a filename, use binding.yaml const inputLocation = Bun.file(bindingPath); - // If it is a directory, try again seeking a binding.yaml inside + // If it is a directory, try for the four main supported types const stat = await inputLocation.stat(); if (stat.isDirectory()) { - return resolveBindingPath(path.resolve(bindingPath, "binding.yaml")); - } + const jsonPath = await resolveFilePath( + path.resolve(bindingPath, "binding.json"), + ); + if (jsonPath) { + return jsonPath; + } + + const yamlPath = await resolveFilePath( + path.resolve(bindingPath, "binding.yaml"), + ); + if (yamlPath) { + return yamlPath; + } + + const tomlPath = await resolveFilePath( + path.resolve(bindingPath, "binding.toml"), + ); + if (tomlPath) { + return tomlPath; + } + + const mdPath = await resolveFilePath( + path.resolve(bindingPath, "binding.md"), + ); + if (mdPath) { + return mdPath; + } - // If it doesnt exist, bail - if (!(await inputLocation.exists())) { throw new FileNotFoundError(bindingPath); } - // Resolve the path + const exists = await inputLocation.exists(); + + if (!exists) { + throw new FileNotFoundError(bindingPath); + } + + // If it is a file, return the path return path.resolve(bindingPath); } -export type MuseProcessorFn = ( - binding: Binding, - opts: Record, -) => Promise; - -export interface MuseProcessor { - readonly filePath: string; - readonly name: string; - readonly description: string; - readonly process: MuseProcessorFn; -} - -export interface Binding { - readonly _raw: ParsedBinding; - readonly bindingPath: string; - readonly markdownKey: string; - readonly includedFiles: string[]; - readonly entries: MuseEntry[]; - readonly meta: Record; - readonly options: Record; - readonly processors: MuseProcessor[]; - readonly imports: Binding[]; -} - export async function loadBinding(initialPath: string): Promise { // Resolve the file location if possible const bindingPath = await resolveBindingPath(initialPath); @@ -95,68 +116,41 @@ export async function loadBinding(initialPath: string): Promise { entries.push(...loadedBinding.entries); } - // Collect file manifest from globs - const allFilePaths: string[] = []; - for (const thisGlob of parsedBinding.files) { - const glob = new Glob(thisGlob); + // Aggregate file paths to import + const includedFilePaths = parsedBinding.files + .flatMap((thisGlob) => { + return Array.from( + new Glob(thisGlob).scanSync({ + cwd: bindingDirname, + absolute: true, + followSymlinks: true, + onlyFiles: true, + }), + ); + }) + .filter((filePath) => filePath !== bindingPath); - const results = glob.scanSync({ - cwd: bindingDirname, - absolute: true, - followSymlinks: true, - onlyFiles: true, - }); + // Load files + const loadedEntries = await Promise.all( + includedFilePaths.map((filePath) => { + return parseMuseFile(filePath, { + contentKey: parsedBinding.contentKey, + }); + }), + ); - allFilePaths.push(...results); - } - - // Exclude the binding.yaml file - const includedFilePaths = allFilePaths.filter((filePath) => { - return filePath !== bindingPath; - }); - - const fileLoadPromises: Promise[] = []; - for (const filePath of includedFilePaths) { - fileLoadPromises.push( - parseMuseFile(filePath, { - markdownKey: parsedBinding.markdownKey, - }), - ); - } - - const mainEntries = await Promise.all(fileLoadPromises); - entries.push(...mainEntries.flat()); + // Add loaded entries to main list + entries.push(...loadedEntries.flat()); // Load and check processors - const processors: MuseProcessor[] = []; - for (const processorPath of parsedBinding.processors) { - const resolvedProcessorPath = path.resolve(bindingDirname, processorPath); - const { process, name, description } = await import(resolvedProcessorPath); - - if (!process || typeof process !== "function") { - throw new MuseError( - `Processor at ${processorPath} does not export a process() function`, - ); - } - - const processorName = String(name ?? "Unnamed Processor"); - const processorDescription = String( - description ?? "No description provided", - ); - - processors.push({ - filePath: resolvedProcessorPath, - process: process as MuseProcessor["process"], - name: processorName, - description: processorDescription, - }); - } + const processors: MuseProcessor[] = await Promise.all( + parsedBinding.processors.map(loadProcessor.bind(null, bindingDirname)), + ); return { _raw: parsedBinding, bindingPath, - markdownKey: parsedBinding.markdownKey, - includedFiles: includedFilePaths, + contentKey: parsedBinding.contentKey, entries, options: parsedBinding.options, processors: processors, diff --git a/src/index.ts b/src/cli.ts similarity index 54% rename from src/index.ts rename to src/cli.ts index 8b1c510..762d30e 100644 --- a/src/index.ts +++ b/src/cli.ts @@ -1,7 +1,9 @@ +import { parseArgs } from "node:util"; import chalk from "chalk"; -import { MuseError } from "./errors.ts"; -import { loadBinding, type Binding } from "./binding"; -import { type CLIArguments, parseCLIArguments, USAGE } from "./args"; +import { MuseError } from "./errors"; +import { loadBinding } from "./binding"; +import { version } from "../package.json"; +import type { Binding, CLIArguments } from "./types"; interface Loggers { log: (msg: string) => void; @@ -13,8 +15,62 @@ enum ExitCode { Error = 1, } +export const USAGE = ` +${chalk.bold("muse")} - Compile and process troves of data +${chalk.dim(`v${version}`)} + +Usage: + muse [/path/to/binding.yaml] + +Options: + --stdout -s Output final data to stdout + --verbose, -v Enable verbose logging + --help, -h Show this help message +`.trim(); + +/** + * 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 { + const { values: options, positionals: args } = parseArgs({ + args: argv, + options: { + help: { + short: "h", + default: false, + type: "boolean", + }, + verbose: { + short: "v", + default: false, + type: "boolean", + }, + stdout: { + short: "s", + default: false, + type: "boolean", + }, + }, + strict: true, + allowPositionals: true, + }); + + return { + inputFilePath: args[0] ?? "./binding.yaml", + flags: { + help: options.help, + verbose: options.verbose, + stdout: options.stdout, + }, + }; +} async function processBinding( - { inputFilePath, options }: CLIArguments, + { inputFilePath, flags }: CLIArguments, { log, verbose }: Loggers, ) { // Load the binding @@ -37,7 +93,7 @@ async function processBinding( const { process, name } = processor; log(chalk.bold(`↪ ${name}`) + chalk.dim(` (${processor.description})`)); - const thisStep = await process(lastStep, binding.options); + const thisStep = await process(lastStep, binding.options, flags); processedSteps.push(thisStep); } @@ -48,7 +104,7 @@ async function processBinding( const finalState = processedSteps[processedSteps.length - 1]; const serialized = JSON.stringify(finalState.entries, null, 2); - if (options.stdout) { + if (flags.stdout) { console.log(serialized); } return ExitCode.Success; @@ -56,16 +112,16 @@ async function processBinding( async function main(): Promise { const cliArguments = parseCLIArguments(Bun.argv.slice(2)); - const { options } = cliArguments; + const { flags } = cliArguments; // If --help is specified, print usage and exit - if (options.help) { + if (flags.help) { console.log(USAGE); return ExitCode.Success; } - const logFn = !options.stdout ? console.log : () => {}; - const verboseFn = options.verbose + const logFn = !flags.stdout ? console.log : () => {}; + const verboseFn = flags.verbose ? (msg: string) => { console.log(chalk.dim(msg)); } diff --git a/src/errors.ts b/src/errors.ts index b92c44c..7c8c014 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -19,8 +19,6 @@ export class FileError extends MuseError { } } -export class MalformedResourceFileError extends FileError {} - export class FileNotFoundError extends FileError { constructor(filePath: string) { super("File not found", filePath); diff --git a/src/exports.ts b/src/exports.ts new file mode 100644 index 0000000..8a07b08 --- /dev/null +++ b/src/exports.ts @@ -0,0 +1,2 @@ +export type * from "./types"; +export const DEFAULT_CONTENT_KEY = "content"; diff --git a/src/muse-file.ts b/src/parse.ts similarity index 74% rename from src/muse-file.ts rename to src/parse.ts index 3243c5d..842f6d2 100644 --- a/src/muse-file.ts +++ b/src/parse.ts @@ -2,30 +2,7 @@ import { normalize, extname } from "node:path"; import YAML from "yaml"; import TOML from "smol-toml"; import EMDY from "@endeavorance/emdy"; - -type UnknownRecord = Record; -export type MuseFileType = "md" | "yaml" | "json" | "toml"; -export interface MuseEntry { - _raw: string; - filePath: string; - data: Record; - meta: Record; -} - -function parseFileType(ext: string): MuseFileType { - switch (ext) { - case "md": - return "md"; - case "yaml": - return "yaml"; - case "json": - return "json"; - case "toml": - return "toml"; - default: - throw new Error(`Unsupported file format: ${ext}`); - } -} +import type { MuseEntry, UnknownRecord } from "./types"; function parseYAMLEntries(text: string): UnknownRecord[] { const parsedDocs = YAML.parseAllDocuments(text); @@ -75,16 +52,16 @@ function parseTOMLEntries(text: string): UnknownRecord[] { } interface ParseMuseFileOptions { - markdownKey?: string; + contentKey?: string; } export async function parseMuseFile( rawFilePath: string, - { markdownKey = "content" }: ParseMuseFileOptions = {}, + { contentKey = "content" }: ParseMuseFileOptions = {}, ): Promise { const filePath = normalize(rawFilePath); const file = Bun.file(filePath); - const fileType = parseFileType(extname(filePath).slice(1)); + const fileType = extname(filePath).slice(1); const rawFileContent = await file.text(); const partial = { @@ -94,7 +71,7 @@ export async function parseMuseFile( }; if (fileType === "md") { - const parsed = EMDY.parse(rawFileContent, markdownKey); + const parsed = EMDY.parse(rawFileContent, contentKey); return [ { ...partial, diff --git a/src/types.ts b/src/types.ts index 21dce91..f9faa6c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,55 @@ -import type { Binding, MuseProcessorFn } from "./binding"; -import type { MuseEntry } from "./muse-file"; -export type { Binding, MuseProcessorFn, MuseEntry }; +import { z } from "zod"; + +export interface CLIFlags { + help: boolean; + verbose: boolean; + stdout: boolean; +} + +export interface CLIArguments { + inputFilePath: string; + flags: CLIFlags; +} + +export const BindingSchema = z.object({ + include: z.array(z.string()).default([]), + contentKey: z.string().default("content"), + files: z + .array(z.string()) + .default(["**/*.yaml", "**/*.md", "**/*.toml", "**/*.json"]), + options: z.record(z.string(), z.any()).default({}), + processors: z.array(z.string()).default([]), +}); + +export interface Binding { + readonly _raw: z.infer; + readonly bindingPath: string; + readonly contentKey: string; + readonly entries: MuseEntry[]; + readonly meta: Record; + readonly options: Record; + readonly processors: MuseProcessor[]; + readonly imports: Binding[]; +} + +export type MuseProcessorFn = ( + binding: Binding, + opts: Record, + flags: CLIFlags, +) => Promise; + +export interface MuseProcessor { + readonly filePath: string; + readonly name: string; + readonly description: string; + readonly process: MuseProcessorFn; +} + +export interface MuseEntry { + _raw: string; + filePath: string; + data: Record; + meta: Record; +} + +export type UnknownRecord = Record; diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..0c84a67 --- /dev/null +++ b/src/util.ts @@ -0,0 +1,27 @@ +import { normalize } from "node:path"; + +/** + * Given a file path, ensure it is a file that exists + * Otherwise, return null + * + * @param filePath - The path to the file + * @returns A promise which resolves to the resolved file path or null + */ +export async function resolveFilePath( + filePath: string, +): Promise { + const normalized = normalize(filePath); + const file = Bun.file(normalized); + const exists = await file.exists(); + + if (!exists) { + return null; + } + + const stat = await file.stat(); + if (stat.isDirectory()) { + return null; + } + + return normalized; +} diff --git a/tsconfig.json b/tsconfig.json index 0d2aab2..f2b0046 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,7 @@ "noPropertyAccessFromIndexSignature": false, "baseUrl": "./src", "paths": {}, - "outDir": "./types", + "outDir": "./dist", }, "include": [ "src/**/*.ts", diff --git a/types/muse.d.ts b/types/muse.d.ts deleted file mode 100644 index 88fdc98..0000000 --- a/types/muse.d.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Generated by dts-bundle-generator v9.5.1 - -import z from 'zod'; - -export type MuseFileType = "md" | "yaml" | "json" | "toml"; -export interface MuseFileContent { - type: MuseFileType; - text: string; - data: Record; -} -declare const BindingSchema: z.ZodObject<{ - include: z.ZodDefault>; - name: z.ZodDefault; - author: z.ZodDefault; - description: z.ZodDefault; - version: z.ZodDefault; - files: z.ZodDefault>; - options: z.ZodDefault>; - processors: z.ZodDefault>; -}, "strip", z.ZodTypeAny, { - options: Record; - include: string[]; - name: string; - author: string; - description: string; - version: string; - files: string[]; - processors: string[]; -}, { - options?: Record | undefined; - include?: string[] | undefined; - name?: string | undefined; - author?: string | undefined; - description?: string | undefined; - version?: string | undefined; - files?: string[] | undefined; - processors?: string[] | undefined; -}>; -export type ParsedBinding = z.infer; -export interface BindingMetadata { - name: string; - author: string; - description: string; - version: string; -} -export type MuseProcessorFn = (binding: Binding) => Promise; -export interface MuseProcessor { - readonly filePath: string; - readonly process: MuseProcessorFn; -} -export interface Binding { - readonly _raw: ParsedBinding; - readonly bindingPath: string; - readonly includedFiles: string[]; - readonly entries: MuseFileContent[]; - readonly metadata: BindingMetadata; - readonly options: Record; - readonly processors: MuseProcessor[]; - readonly imports: Binding[]; -} - -export {};