Update plugin shape
This commit is contained in:
parent
504c1e6f3c
commit
ae1b9e262e
12 changed files with 181 additions and 149 deletions
|
@ -1,14 +1,19 @@
|
||||||
export const name = "Announce Slam Dunks";
|
export const name = "Announce Slam Dunks";
|
||||||
export const description = "Get hype when a file has slam dunks";
|
export const description = "Get hype when a file has slam dunks";
|
||||||
|
|
||||||
export const process = (binding, { dunks }) => {
|
export const step = ({ entries, options, ...rest }) => {
|
||||||
|
const { dunks } = options;
|
||||||
const slamDunkKey = dunks?.key ?? "slamDunks";
|
const slamDunkKey = dunks?.key ?? "slamDunks";
|
||||||
|
|
||||||
for (const entry of binding.entries) {
|
for (const entry of entries) {
|
||||||
if (slamDunkKey in entry.data) {
|
if (slamDunkKey in entry.data) {
|
||||||
console.log(`Slam dunk!`);
|
console.log(`Slam dunk!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return binding;
|
return {
|
||||||
|
entries,
|
||||||
|
options,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
export const name = "Scream";
|
export function step(binding) {
|
||||||
|
|
||||||
export function process(binding) {
|
|
||||||
const modifiedEntries = binding.entries.map(entry => {
|
const modifiedEntries = binding.entries.map(entry => {
|
||||||
if (binding.markdownKey in entry.data) {
|
if (binding.markdownKey in entry.data) {
|
||||||
entry.data = {
|
entry.data = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { parseArgs } from "node:util";
|
import { parseArgs } from "node:util";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { type Binding, loadBinding } from "#core/binding";
|
import { loadBinding } from "#core/binding";
|
||||||
|
import type { MusePlugin } from "#core/plugins";
|
||||||
import { MuseError } from "#errors";
|
import { MuseError } from "#errors";
|
||||||
import { version } from "../../package.json";
|
import { version } from "../../package.json";
|
||||||
|
|
||||||
|
@ -68,50 +69,46 @@ function parseCLIArguments(argv: string[]): [string, CLIFlags] {
|
||||||
return [args[0] ?? "./", options];
|
return [args[0] ?? "./", options];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processBinding(
|
function getStepLogLine(plugin: MusePlugin): string {
|
||||||
inputFilePath: string,
|
const { name, description } = plugin;
|
||||||
flags: CLIFlags,
|
|
||||||
{ log, verbose }: Loggers,
|
|
||||||
) {
|
|
||||||
// Load the binding
|
|
||||||
const binding = await loadBinding(inputFilePath);
|
|
||||||
|
|
||||||
verbose(`Binding ${binding.bindingPath}`);
|
|
||||||
|
|
||||||
const stepWord = binding.processors.length === 1 ? "step" : "steps";
|
|
||||||
log(
|
|
||||||
`Processing ${binding.entries.length} entries with ${binding.processors.length} ${stepWord}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const processStart = performance.now();
|
|
||||||
|
|
||||||
// Run the data through all processors
|
|
||||||
const processedSteps: Binding[] = [binding];
|
|
||||||
for (const processor of binding.processors) {
|
|
||||||
const lastStep = processedSteps[processedSteps.length - 1];
|
|
||||||
|
|
||||||
const { process, name, description } = processor;
|
|
||||||
|
|
||||||
let processorLogLine = chalk.bold(`↪ ${name}`);
|
let processorLogLine = chalk.bold(`↪ ${name}`);
|
||||||
|
|
||||||
if (description && description.length > 0) {
|
if (description && description.length > 0) {
|
||||||
processorLogLine += chalk.dim(` (${description})`);
|
processorLogLine += chalk.dim(` (${description})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
log(processorLogLine);
|
return processorLogLine;
|
||||||
const thisStep = await process(lastStep, binding.options);
|
}
|
||||||
processedSteps.push(thisStep);
|
|
||||||
|
async function processBinding(
|
||||||
|
inputFilePath: string,
|
||||||
|
flags: CLIFlags,
|
||||||
|
{ log, verbose }: Loggers,
|
||||||
|
) {
|
||||||
|
// Load the binding
|
||||||
|
let binding = await loadBinding(inputFilePath);
|
||||||
|
verbose(`Binding ${binding.bindingPath}`);
|
||||||
|
|
||||||
|
const entryCount = binding.entries.length;
|
||||||
|
const stepCount = binding.plugins.length;
|
||||||
|
const stepWord = stepCount === 1 ? "step" : "steps";
|
||||||
|
log(`Processing ${entryCount} entries with ${stepCount} ${stepWord}`);
|
||||||
|
|
||||||
|
const processStart = performance.now();
|
||||||
|
|
||||||
|
// Run the data through relevant plugins
|
||||||
|
for (const plugin of binding.plugins) {
|
||||||
|
log(getStepLogLine(plugin));
|
||||||
|
const { step } = plugin;
|
||||||
|
binding = await step(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
const processEnd = performance.now();
|
const processEnd = performance.now();
|
||||||
const processTime = ((processEnd - processStart) / 1000).toFixed(2);
|
const processTime = ((processEnd - processStart) / 1000).toFixed(2);
|
||||||
verbose(`Processing completed in ${processTime}s`);
|
verbose(`Processing completed in ${processTime}s`);
|
||||||
|
|
||||||
const finalState = processedSteps[processedSteps.length - 1];
|
|
||||||
const serialized = JSON.stringify(finalState.entries, null, 2);
|
|
||||||
|
|
||||||
if (flags.stdout) {
|
if (flags.stdout) {
|
||||||
console.log(serialized);
|
console.log(JSON.stringify(binding, null, 2));
|
||||||
}
|
}
|
||||||
return ExitCode.Success;
|
return ExitCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ import path, { dirname } from "node:path";
|
||||||
import { Glob } from "bun";
|
import { Glob } from "bun";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { MuseError, MuseFileNotFoundError } from "#errors";
|
import { MuseError, MuseFileNotFoundError } from "#errors";
|
||||||
import type { UnknownRecord } from "#types";
|
|
||||||
import { resolveFilePath } from "#util";
|
import { resolveFilePath } from "#util";
|
||||||
import { type MuseEntry, parseMuseFile } from "./parse";
|
import { type MuseEntry, parseMuseFile } from "./parse";
|
||||||
import { type MuseProcessor, loadProcessor } from "./processor";
|
import { type MusePlugin, loadPlugin } from "./plugins";
|
||||||
|
import type { UnknownRecord } from "./types";
|
||||||
|
|
||||||
// Function to parse an unknown object into parts of a binding
|
// Function to parse an unknown object into parts of a binding
|
||||||
export const BindingSchema = z.object({
|
export const BindingSchema = z.object({
|
||||||
|
@ -37,7 +37,7 @@ export interface Binding<MetaShape = UnknownRecord> {
|
||||||
readonly entries: MuseEntry[];
|
readonly entries: MuseEntry[];
|
||||||
|
|
||||||
/** A list of processors to be applied to the entries */
|
/** A list of processors to be applied to the entries */
|
||||||
readonly processors: MuseProcessor[];
|
readonly plugins: MusePlugin[];
|
||||||
|
|
||||||
/** Arbitrary metadata for processors to use to cache project data */
|
/** Arbitrary metadata for processors to use to cache project data */
|
||||||
readonly meta: MetaShape;
|
readonly meta: MetaShape;
|
||||||
|
@ -75,20 +75,14 @@ async function resolveBindingPath(bindingPath: string): Promise<string> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new MuseFileNotFoundError(
|
throw new MuseFileNotFoundError(bindingPath);
|
||||||
bindingPath,
|
|
||||||
"Failed to find a binding file at the provided directory.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not a directory, check if its a file that exists
|
// If not a directory, check if its a file that exists
|
||||||
const exists = await inputLocation.exists();
|
const exists = await inputLocation.exists();
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
throw new MuseFileNotFoundError(
|
throw new MuseFileNotFoundError(bindingPath);
|
||||||
bindingPath,
|
|
||||||
"Provided binding path does not exist.",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is a file, return the path
|
// If it is a file, return the path
|
||||||
|
@ -133,9 +127,9 @@ export async function loadBinding(initialPath: string): Promise<Binding> {
|
||||||
)
|
)
|
||||||
).flat();
|
).flat();
|
||||||
|
|
||||||
// Load and check processors
|
// Load and check plugins
|
||||||
const processors: MuseProcessor[] = await Promise.all(
|
const plugins: MusePlugin[] = await Promise.all(
|
||||||
parsedBinding.processors.map(loadProcessor.bind(null, bindingDirname)),
|
parsedBinding.processors.map(loadPlugin.bind(null, bindingDirname)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -144,7 +138,7 @@ export async function loadBinding(initialPath: string): Promise<Binding> {
|
||||||
contentKey: parsedBinding.contentKey,
|
contentKey: parsedBinding.contentKey,
|
||||||
entries,
|
entries,
|
||||||
options: parsedBinding.options,
|
options: parsedBinding.options,
|
||||||
processors: processors,
|
plugins,
|
||||||
meta: {},
|
meta: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
32
src/core/files.ts
Normal file
32
src/core/files.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { basename, dirname, extname, normalize } from "node:path";
|
||||||
|
import { MuseFileNotFoundError } from "#errors";
|
||||||
|
|
||||||
|
export interface LoadedFile {
|
||||||
|
content: string;
|
||||||
|
filePath: string;
|
||||||
|
fileType: string;
|
||||||
|
dirname: string;
|
||||||
|
basename: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadFileContent(filePath: string): Promise<LoadedFile> {
|
||||||
|
const normalizedPath = normalize(filePath);
|
||||||
|
const file = Bun.file(normalizedPath);
|
||||||
|
|
||||||
|
const exists = await file.exists();
|
||||||
|
if (!exists) {
|
||||||
|
throw new MuseFileNotFoundError(normalizedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filecontent = await file.text();
|
||||||
|
|
||||||
|
const extension = extname(normalizedPath);
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: filecontent,
|
||||||
|
filePath: normalizedPath,
|
||||||
|
fileType: extension.slice(1),
|
||||||
|
dirname: dirname(normalizedPath),
|
||||||
|
basename: basename(normalizedPath, extension),
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import { extname, normalize } from "node:path";
|
|
||||||
import EMDY from "@endeavorance/emdy";
|
import EMDY from "@endeavorance/emdy";
|
||||||
import TOML from "smol-toml";
|
import TOML from "smol-toml";
|
||||||
import YAML from "yaml";
|
import YAML from "yaml";
|
||||||
import type { UnknownRecord } from "#types";
|
import { loadFileContent } from "./files";
|
||||||
import { MuseFileNotFoundError } from "#errors";
|
import type { UnknownRecord } from "./types";
|
||||||
|
|
||||||
export interface MuseEntry<MetaShape = UnknownRecord> {
|
export interface MuseEntry<MetaShape = UnknownRecord> {
|
||||||
_raw: string;
|
_raw: string;
|
||||||
|
@ -12,6 +11,20 @@ export interface MuseEntry<MetaShape = UnknownRecord> {
|
||||||
meta: MetaShape;
|
meta: MetaShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatEntries(val: unknown): UnknownRecord[] {
|
||||||
|
if (Array.isArray(val) && val.every((el) => typeof el === "object")) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof val === "object" && val !== null) {
|
||||||
|
return [val as UnknownRecord];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Invalid data format. Entry files must define an object or array of objects, but found "${val}"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function parseYAMLEntries(text: string): UnknownRecord[] {
|
function parseYAMLEntries(text: string): UnknownRecord[] {
|
||||||
const parsedDocs = YAML.parseAllDocuments(text);
|
const parsedDocs = YAML.parseAllDocuments(text);
|
||||||
|
|
||||||
|
@ -32,31 +45,15 @@ function parseYAMLEntries(text: string): UnknownRecord[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseJSONEntries(text: string): UnknownRecord[] {
|
function parseJSONEntries(text: string): UnknownRecord[] {
|
||||||
const parsed = JSON.parse(text);
|
return formatEntries(JSON.parse(text));
|
||||||
|
|
||||||
if (Array.isArray(parsed)) {
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof parsed === "object") {
|
|
||||||
return [parsed];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("JSON resource must be an object or an array of objects");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTOMLEntries(text: string): UnknownRecord[] {
|
function parseTOMLEntries(text: string): UnknownRecord[] {
|
||||||
const parsed = TOML.parse(text);
|
return formatEntries(TOML.parse(text));
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(parsed)) {
|
function parseMarkdownEntry(text: string, contentKey: string): UnknownRecord[] {
|
||||||
return parsed;
|
return formatEntries(EMDY.parse(text, contentKey));
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof parsed === "object") {
|
|
||||||
return [parsed];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error("TOML resource must be an object or an array of objects");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParseMuseFileOptions {
|
interface ParseMuseFileOptions {
|
||||||
|
@ -67,49 +64,37 @@ export async function parseMuseFile(
|
||||||
rawFilePath: string,
|
rawFilePath: string,
|
||||||
{ contentKey = "content" }: ParseMuseFileOptions = {},
|
{ contentKey = "content" }: ParseMuseFileOptions = {},
|
||||||
): Promise<MuseEntry[]> {
|
): Promise<MuseEntry[]> {
|
||||||
const filePath = normalize(rawFilePath);
|
const { content, filePath, fileType } = await loadFileContent(rawFilePath);
|
||||||
const file = Bun.file(filePath);
|
|
||||||
const fileType = extname(filePath).slice(1);
|
|
||||||
|
|
||||||
const fileExists = await file.exists();
|
|
||||||
if (!fileExists) {
|
|
||||||
throw new MuseFileNotFoundError(filePath, "Failed to load source file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawFileContent = await file.text();
|
|
||||||
|
|
||||||
const partial = {
|
const partial = {
|
||||||
_raw: rawFileContent,
|
_raw: content,
|
||||||
filePath,
|
filePath,
|
||||||
meta: {},
|
meta: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fileType === "md") {
|
if (fileType === "md") {
|
||||||
const parsed = EMDY.parse(rawFileContent, contentKey);
|
return parseMarkdownEntry(content, contentKey).map((data) => ({
|
||||||
return [
|
|
||||||
{
|
|
||||||
...partial,
|
...partial,
|
||||||
data: parsed,
|
data,
|
||||||
},
|
}));
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileType === "yaml") {
|
if (fileType === "yaml") {
|
||||||
return parseYAMLEntries(rawFileContent).map((data) => ({
|
return parseYAMLEntries(content).map((data) => ({
|
||||||
...partial,
|
...partial,
|
||||||
data,
|
data,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileType === "json") {
|
if (fileType === "json") {
|
||||||
return parseJSONEntries(rawFileContent).map((data) => ({
|
return parseJSONEntries(content).map((data) => ({
|
||||||
...partial,
|
...partial,
|
||||||
data,
|
data,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileType === "toml") {
|
if (fileType === "toml") {
|
||||||
return parseTOMLEntries(rawFileContent).map((data) => ({
|
return parseTOMLEntries(content).map((data) => ({
|
||||||
...partial,
|
...partial,
|
||||||
data,
|
data,
|
||||||
}));
|
}));
|
||||||
|
|
52
src/core/plugins.ts
Normal file
52
src/core/plugins.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import path from "node:path";
|
||||||
|
import { MuseError, MusePluginError } from "#errors";
|
||||||
|
import type { Binding } from "./binding";
|
||||||
|
|
||||||
|
export type MuseStepFn = (binding: Binding) => Promise<Binding>;
|
||||||
|
|
||||||
|
export interface MusePlugin {
|
||||||
|
readonly filePath: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly description: string;
|
||||||
|
readonly version: string;
|
||||||
|
readonly step: MuseStepFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadPlugin(
|
||||||
|
bindingDirname: string,
|
||||||
|
pluginPath: string,
|
||||||
|
): Promise<MusePlugin> {
|
||||||
|
// Resolve local paths, use URLs as-is
|
||||||
|
const resolvedProcessorPath = pluginPath.startsWith("http")
|
||||||
|
? pluginPath
|
||||||
|
: path.resolve(bindingDirname, pluginPath);
|
||||||
|
const { step, name, description, version } = await import(
|
||||||
|
resolvedProcessorPath
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!step || typeof step !== "function") {
|
||||||
|
throw new MuseError(
|
||||||
|
`Processor at ${pluginPath} does not export a step() function`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name && typeof name !== "string") {
|
||||||
|
throw new MusePluginError(pluginPath, "Plugin name is not a string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description && typeof description !== "string") {
|
||||||
|
throw new MusePluginError(pluginPath, "Plugin description is not a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version && typeof version !== "string") {
|
||||||
|
throw new MusePluginError(pluginPath, "Plugin version is not a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
filePath: resolvedProcessorPath,
|
||||||
|
step: step as MuseStepFn,
|
||||||
|
name: String(name ?? pluginPath),
|
||||||
|
description: String(description ?? ""),
|
||||||
|
version: String(version ?? "0.0.0"),
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
import path from "node:path";
|
|
||||||
import { MuseError } from "#errors";
|
|
||||||
import type { Binding } from "./binding";
|
|
||||||
|
|
||||||
export type MuseProcessorFn = (
|
|
||||||
binding: Binding,
|
|
||||||
opts: Record<string, unknown>,
|
|
||||||
) => Promise<Binding>;
|
|
||||||
|
|
||||||
export interface MuseProcessor {
|
|
||||||
readonly filePath: string;
|
|
||||||
readonly name: string;
|
|
||||||
readonly description: string;
|
|
||||||
readonly process: MuseProcessorFn;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadProcessor(
|
|
||||||
bindingDirname: string,
|
|
||||||
processorPath: string,
|
|
||||||
): Promise<MuseProcessor> {
|
|
||||||
// Resolve local paths, use URLs as-is
|
|
||||||
const resolvedProcessorPath = processorPath.startsWith("http")
|
|
||||||
? processorPath
|
|
||||||
: 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 ?? "");
|
|
||||||
|
|
||||||
return {
|
|
||||||
filePath: resolvedProcessorPath,
|
|
||||||
process: process as MuseProcessor["process"],
|
|
||||||
name: processorName,
|
|
||||||
description: processorDescription,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,3 +1 @@
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
export type UnknownRecord = Record<string, unknown>;
|
export type UnknownRecord = Record<string, unknown>;
|
|
@ -1,30 +1,40 @@
|
||||||
export class MuseError extends Error {
|
export class MuseError extends Error {
|
||||||
fmt(): string {
|
fmt(): string {
|
||||||
return this.message;
|
return `-- ERROR -- \nDetails: ${this.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MusePluginError extends MuseError {
|
||||||
|
plugin: string;
|
||||||
|
|
||||||
|
constructor(message: string, plugin: string) {
|
||||||
|
super(message);
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt(): string {
|
||||||
|
return `-- PLUGIN ERROR --\Plugin: ${this.plugin}\nDetails: ${this.message}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MuseFileError extends MuseError {
|
export class MuseFileError extends MuseError {
|
||||||
filePath: string;
|
filePath: string;
|
||||||
details?: string;
|
|
||||||
|
|
||||||
constructor(message: string, filePath: string, details?: string) {
|
constructor(message: string, filePath: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
this.details = details;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt(): string {
|
fmt(): string {
|
||||||
return `-- ${this.message} --\nFile Path: ${this.filePath}\nDetails: ${this.details}`;
|
return `-- FILE ERROR --\nFile Path: ${this.filePath}\nDetails: ${this.message}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MuseFileNotFoundError extends MuseFileError {
|
export class MuseFileNotFoundError extends MuseFileError {
|
||||||
constructor(filePath: string, details?: string) {
|
constructor(filePath: string) {
|
||||||
super("File not found", filePath);
|
super("File not found", filePath);
|
||||||
this.message = "File not found";
|
this.message = "File does not exist";
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
this.details = details ?? "No additional information.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
export type * from "#types";
|
// Content exports
|
||||||
export * from "#errors";
|
export * from "#errors";
|
||||||
|
|
||||||
|
// Constants
|
||||||
export const DEFAULT_CONTENT_KEY = "content";
|
export const DEFAULT_CONTENT_KEY = "content";
|
||||||
|
|
||||||
|
// Types
|
||||||
|
export type * from "#types";
|
||||||
|
export type { MusePlugin } from "#core/plugins";
|
||||||
|
|
|
@ -33,9 +33,6 @@
|
||||||
"#util": [
|
"#util": [
|
||||||
"./util.ts"
|
"./util.ts"
|
||||||
],
|
],
|
||||||
"#types": [
|
|
||||||
"./types.ts"
|
|
||||||
],
|
|
||||||
"#errors": [
|
"#errors": [
|
||||||
"./errors.ts"
|
"./errors.ts"
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue