Update plugin shape again

This commit is contained in:
Endeavorance 2025-04-04 16:14:17 -04:00
parent dfc65dacfa
commit 2d3ba356b5
5 changed files with 52 additions and 46 deletions

View file

@ -1,20 +1,17 @@
# Muse # Muse
A CLI for wrangling directories of source files. _Bind data into anything_
Like a static generator, but for whatever.
## Overview ## Overview
**Muse** is a CLI and toolchain for operating on directories of **Muse** is a CLI and toolchain for operating on data collected from
json, yaml, toml, and markdown files. Each file can specify any shape json, yaml, toml, and markdown files.
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 Muse scans included files, parses them into data, and streams
side effects such as writing files to disk. the loaded data through plugins.
Muse does not edit source files, it only reads them in. Each plugin can modify the data as well as enact side effects
such as writing files to disk.
## Usage ## Usage
@ -32,10 +29,9 @@ Options:
Each Muse project should specify a `binding` file with the following shape: Each Muse project should specify a `binding` file with the following shape:
```yaml ```yaml
include: sources: # Optional
- ../another-project # Optional - file: "**/*.yaml"
files: # Optional - web: "https://example.com/data.json"
- "**/*.yaml"
contentKey: "content" # Optional contentKey: "content" # Optional
options: # Optional options: # Optional
someOption: someValue someOption: someValue
@ -44,9 +40,9 @@ processors:
- second-processor - second-processor
``` ```
The `binding` file can be any of the supported file types for Muse. If The `binding` file can be any of the supported file types for Muse and can
the CLI is invoked with a directory instead of a file, Muse will look be named anything. If the CLI is invoked with a directory instead of a file,
for a binding file in the directory with the following order: Muse will look for a binding file in the directory with the following order:
1. `binding.json` 1. `binding.json`
2. `binding.yaml` 2. `binding.yaml`
@ -68,3 +64,34 @@ Your markdown content here
When loading markdown files, Muse will load the content of the file When loading markdown files, Muse will load the content of the file
into a key called `content` by default. This can be changed in the binding into a key called `content` by default. This can be changed in the binding
configuration by setting a `contentKey` value as an override. configuration by setting a `contentKey` value as an override.
## Plugin API
Muse plugins are written in TypeScript/JavaScript and expose information
describing the plugin, as well as the functions to operate with:
```typescript
export const name = "Plugin Name";
export const description = "Plugin Description";
export async function step(binding: Binding): Promise<Binding> {}
```
The main function of a plugin is `step`, which takes a `Binding` object
and returns a modified `Binding` object.
When returning a new Binding object, it is best practice to make immutable
changes:
```typescript
export async function step(binding: Binding): Promise<Binding> {
const newBinding = { ...binding };
newBinding.options.someOption = "newValue";
return {
...binding,
meta: {
...binding.meta,
customValue: true,
}
};
}
```

View file

@ -1,6 +1,6 @@
{ {
"name": "@endeavorance/muse", "name": "@endeavorance/muse",
"version": "0.2.0", "version": "0.3.0",
"module": "dist/index.js", "module": "dist/index.js",
"exports": { "exports": {
".": { ".": {

View file

@ -22,7 +22,7 @@ const BindingSchema = z.object({
}, },
]), ]),
options: z.record(z.string(), z.any()).default({}), options: z.record(z.string(), z.any()).default({}),
processors: z.array(z.string()).default([]), plugins: z.array(z.string()).default([]),
}); });
/** /**
@ -31,9 +31,6 @@ const BindingSchema = z.object({
* the project, and a list of entries to be processed * the project, and a list of entries to be processed
*/ */
export interface Binding<MetaShape = UnknownRecord> { export interface Binding<MetaShape = UnknownRecord> {
/** The raw data read from the binding file */
readonly _raw: z.infer<typeof BindingSchema>;
/** Information about the sources used to load entries */ /** Information about the sources used to load entries */
readonly sources: MuseSource[]; readonly sources: MuseSource[];
@ -133,11 +130,10 @@ export async function loadBinding(initialPath: string): Promise<Binding> {
// Load and check plugins // Load and check plugins
const plugins: MusePlugin[] = await Promise.all( const plugins: MusePlugin[] = await Promise.all(
parsedBinding.processors.map(loadPlugin.bind(null, bindingDirname)), parsedBinding.plugins.map(loadPlugin.bind(null, bindingDirname)),
); );
return { return {
_raw: parsedBinding,
sources, sources,
bindingPath, bindingPath,
contentKey: parsedBinding.contentKey, contentKey: parsedBinding.contentKey,

View file

@ -5,5 +5,8 @@ export * from "#errors";
export const DEFAULT_CONTENT_KEY = "content"; export const DEFAULT_CONTENT_KEY = "content";
// Types // Types
export type * from "#types"; export type * from "#core/binding";
export type { MusePlugin } from "#core/plugins"; export type * from "#core/plugins";
export type * from "#core/sources";
export type * from "#core/records";
export type * from "#core/files";

View file

@ -1,20 +0,0 @@
import type { Binding } from "#core/binding";
export class Muse {
bindingLoaded = false;
preliminaryBinding: Partial<Binding> = {};
additionalSources: string[] = [];
additionalPluginPaths: string[] = [];
constructor(bindingConfig: Partial<Binding>) {
this.preliminaryBinding = bindingConfig;
}
source(newSource: string) {
this.additionalSources.push(newSource);
}
plugin(pluginPath: string) {
this.additionalPluginPaths.push(pluginPath);
}
}