mu-format
Version:
A tool for formatting MUSHCode into something you can quote into your client.
243 lines (198 loc) • 8.1 kB
Markdown
# Mu-Format
A Program that turns pretty formatted MUSHCode into something you can quote to your client, mixed with a few extras to speed up your coding flow.
## Installation
```
npm i mu-format
```
## Usage
There are just a few steps in setting up the formatter.
```js
// Create your app
const Formatter = require('mu-formatter');
const app = new Formatter({
plugins: [
'./extras/plugins/plugin1',
'./another/place/plugin2'
]
});
// Setup some event listeners
app.on('log', log => console.log(log));
app.on('error', error => app.logger(error.stack));
app.on('done', results => console.log(results[0].contents));
// Now run the formatter! If you run a file from the directory
// level, or from a github repo, it will look for a file called
// `installer.mu`.
app.format('./code/codefile.mu'); // or
app.format('./code/'); // or
app.format('github:user/repo');
```
## The Queue and Jobs
At it's heart, Mu-Format is a middleware driven program that runs lists, or queues of functions, or jobs. The majority of the work happens in in the render (or pre-render) and compress (or pre-compress) queues.
#### The Data Object
Each job is passed a `data` object, containing information about the document currently, as well as a few helper functions to trigger formatter events.
```js
//Some functionality removed for simplification.
const data = {
path: './code/installer.mu',
baseDir: './code/',
// The working text of the format file.
// All of the #includes are combined into this
// attribute, and modify it through out the format
// process.
txt: '...',
// A copy of the composited document before rendering
// and compressing.
raw: '...',
// vars is a unified place to save working data.
vars: {
headers: [
{
name: 'Foo',
value: 'bar'
},
{
name: 'Something',
value: 'important'
}
]
},
// The options passed to mu-format at instantiation
options: {
plugins: [
'plugin1',
'/path/to/plugin2'
]
}
}
```
#### Helper Functions
**data.emit('Event',[data])** Trigger a custom event on the formatter object.
**data.log(message)** Trigger a 'log' event on the formatter object, and also save the message in the result object log.
**data.error(error)** Trigger an 'error' event on theformatter object. Error must be an error object.
### Defining Queues and Jobs
```js
module.exports = app => {
// First, create a queue. When you call the queue command,
// it will either create the queue if it doesn't exist - or
// load an existing queue object. We can link our methods
// through chaining. The job function is passed a single
// parameter, data.
app.queue('render')
.addJob('someJob', data => {
// actions on the data object. Normally you'll be working
// on data.txt where the document contents are stored
// - but there are other things the data object can do.
data.log('Log message!')
})
}
```
```js
// to run a single job from a queue:
app.queue('name').job('jobName')(data)
```
## Creating plugins
Creating a plugin for the system is pretty straight forward. Make a module that exports a function.
```js
/* .plugins/plugin.js */
module.exports = app => {
app.queue('pre-render')
.addJob('custom-job' data => {
// Do whatever processing you need to do on the current
// document (data.txt).
})
}
/* index.js */
// after your app is declared.
app.plugins(['./plugins/plugin.js'])
// Or you can declare plugins at runtime.
app.format('github:user/repo',{
plugins:['./plugins/plugin.js']
})
// You can even just require the file:
require('./plugins/plugin.js')(app)
```
## Formatting Rules
The rules for formatting .mu documents is pretty simple! First, You can format your code however you'd like. I suggest adopting an easy to read style using indentations and spacing to make your code digestable. MU-Format looks for ```[&+@-]``` in the first position of the current line to designate the start of a new command, attribute, or spacer. You can add comments in your code in either ```/* ... */``` block style or ```//``` inline style comments.
A spacer, or dash ```-``` is a purely cosmetic mark for formatting the program output. During the compression phase blank lines are removed. Dashes become newlines making the processed code a little easier to process through.
```
/*
------------------------------------------
--- Commands: +things & +stuff -----------
*/
@@ A comment for someone reading your minified code.
-
&cmd.mycommand me = $+Stuff *:
%#=You entered things and %0.
// Another command that does things
&cmd.mycommandtwo me = $+things *=*:
// Sets an attribute on myself!
&_things me=%0-%1;
think Things %0 %1! // Wut?
```
When we format this block of code, it turns into:
```
@@ A comment for someone reading your minified code.
&cmd_mycommand me = $+Stuff *: %#=You entered things and %0.
&cmd_mycommandtwo me = $+things *=*: &_things me=%0-%1; think Things %0 %1!
```
**Simple!**
The real power of Mu-Format comes in it's #meta tag system. #metas are, when the code is processed, translated into MU friendly output. They are honestly a good way to save a few keystrokes and even organize your code projects. Lets take a look at the few that exist right now:
### #include /path/to/file.mu
this #meta allows you to import a file (or entire Github repository) into the current file. #include accepts three kinds of files right now:
- **Local File**
You can designate a local file to include, entering the ```./path/to/file.mu``` format.
- **Local Directory**
If you list a directory, Mu-Format will look for a file called ```installer.mu``` and kick off the #include from there.
- **Github Archive**
This is the same as installing from a local directory, instead you'll you'll enter ```github:user/repo```. If you start hitting errors while compiling from Github, try adding Github authorization when you create a new Formatter object.
```js
app = new Formatter({
gitUser: 'user',
gitPass: '123Secret!'
})
```
**Example**
```
&cmd.command #123 = $foo *:
think me Foo %0.
// Include the rest of the library.
#include ./path/to/file2.mu
```
### #esc|#file [file[|string]]
Honestly #esc (or #file) works list like #include, except it escapes each line of text with a MUSH null string ```@@``` so they don't get quoted to the Game. This is great for things like license files, and other custom comments text.
```
@@ Legal Stuff
@@ Bla bla, yadda
@@
@@ Instructions
@@ ----------------
@@ 1. Things and
@@ 2. Stuff
```
### #header or #footer key=value
Add key/value information to be listed at the very top or bottom of the resulting file.
```#header version=1.0.0``` escapes into: ```@@ version 1.0.0``` at the top of the resulting document.
### #def string|regex
Roll your own edits! I wanted to keep the system as open to modification as I could. ```#def``` #metas are are a way to replace tags with code at processing time. I find them really useful for code snippets that I'm going to use more than once or twice. Remember! a ```@&-+``` at the beginning of a line results in a new command or attribute being defined.
```
#def #check-wiz
hasflag(%#,Wizard) = { %#=Permission denied.}
#enddef
```
Then later in your code:
```
&cmd.wizcode #1234=$+cmd foobar:
#wiz-check
// Rest of your code ...
```
You can also make a ```#def``` that uses a regular expression string (you don't need to provide the beginning and end of the search ```//```). Any group matches can represented in your code in the variables ```$0 - $9``` Remember! ```$0``` is the entire match.
```
#def #create\s+(.*)\s*=\s*(.*)
[locate(me,$1,*)] = {
$1;
&$2 me = [locate(me,$1,*)];
},{
&$2 me = [locate(me,$1,*)];
}
#enddef
```