-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #487 from chris48s/plugins-part2
load user supplied plugins
- Loading branch information
Showing
35 changed files
with
4,254 additions
and
381 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
plugins: | ||
- "./node_modules/prettier-plugin-jsdoc/dist/index.js" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { execSync } from "child_process"; | ||
|
||
function ensureDirExists(dirPath) { | ||
if (!fs.existsSync(dirPath)) { | ||
fs.mkdirSync(dirPath, { recursive: true }); | ||
} | ||
} | ||
|
||
const tempDocsDir = "./.tempdocs"; | ||
const referenceFile = "./docs/plugins/reference.mdx"; | ||
const tempFiles = [ | ||
{ filename: path.join(tempDocsDir, "BasePlugin.mdx"), title: "BasePlugin" }, | ||
{ filename: path.join(tempDocsDir, "Document.mdx"), title: "Document" }, | ||
{ | ||
filename: path.join(tempDocsDir, "ValidationResult.mdx"), | ||
title: "ValidationResult", | ||
}, | ||
]; | ||
|
||
// clear files if they already exist | ||
if (fs.existsSync(tempDocsDir)) { | ||
fs.rmSync(tempDocsDir, { recursive: true, force: true }); | ||
} | ||
ensureDirExists(tempDocsDir); | ||
if (fs.existsSync(referenceFile)) { | ||
fs.unlinkSync(referenceFile); | ||
} | ||
|
||
// generate from JSDoc | ||
execSync("npx jsdoc-to-mdx -o ./.tempdocs -j jsdoc.json"); | ||
|
||
// post-processing | ||
let combinedContent = `--- | ||
sidebar_position: 3 | ||
custom_edit_url: null | ||
--- | ||
# Plugin API Reference | ||
v8r exports two classes: [BasePlugin](#BasePlugin) and [Document](#Document). | ||
v8r plugins extend the [BasePlugin](#BasePlugin) class. | ||
Parsing a file should return a [Document](#Document) object. | ||
Additionally, validating a document yields a [ValidationResult](#ValidationResult) object. | ||
`; | ||
tempFiles.forEach((file) => { | ||
if (fs.existsSync(file.filename)) { | ||
let content = fs.readFileSync(file.filename, "utf8"); | ||
content = content | ||
.replace(/##/g, "###") | ||
.replace( | ||
/---\ncustom_edit_url: null\n---/g, | ||
`## ${file.title} {#${file.title}}`, | ||
) | ||
.replace(/<br \/>/g, " ") | ||
.replace(/:---:/g, "---") | ||
.replace( | ||
/\[ValidationResult\]\(ValidationResult\)/g, | ||
"[ValidationResult](#ValidationResult)", | ||
) | ||
.replace(/\[Document\]\(Document\)/g, "[Document](#Document)"); | ||
combinedContent += content; | ||
} | ||
}); | ||
|
||
// write out result | ||
ensureDirExists(path.dirname(tempDocsDir)); | ||
fs.writeFileSync(referenceFile, combinedContent); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
--- | ||
sidebar_position: 7 | ||
sidebar_position: 8 | ||
--- | ||
|
||
# FAQ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"label": "Plugins", | ||
"position": 6, | ||
"link": { | ||
"type": "generated-index" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Using Plugins | ||
|
||
It is possible to extend the functionality of v8r by installing plugins. | ||
|
||
Plugins can be packages installed from a registry like [npm](https://www.npmjs.com/) or [jsr](https://jsr.io/) or local files in your repo. | ||
|
||
Plugins must be specified in a [config file](../configuration.md). They can't be loaded using command line arguments. | ||
|
||
```yaml title=".v8rrc.yml" | ||
plugins: | ||
# Plugins installed from NPM (or JSR) must be prefixed by "package:" | ||
- "package:v8r-plugin-emoji-output" | ||
# Plugins in the project dir must be prefixed by "file:" | ||
- "file:./subdir/my-local-plugin.mjs" | ||
``` | ||
Plugins are invoked one at a time in the order they are specified in your config file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
--- | ||
sidebar_position: 2 | ||
--- | ||
|
||
# Writing Plugins | ||
|
||
We can extend the functionality of v8r by writing a plugin. A plugin can be a local file contained within your project or package published to a registry like [npm](https://www.npmjs.com/) or [jsr](https://jsr.io/). | ||
|
||
Plugins extend the [BasePlugin](../reference) class which exposes hooks that allow us customise the parsing of files and output of results. Internally, v8r's [core parsers and output formats](https://github.com/chris48s/v8r/tree/main/src/plugins) are implemented as plugins. You can use these as a reference. | ||
|
||
## Plugin Execution | ||
|
||
Plugins are invoked in the following sequence: | ||
|
||
Plugins that the user has specified in the config file are run first. These are executed in the order they are specified in the config file. | ||
|
||
v8r's core plugins run second. The order of execution for core plugins is non-configurable. | ||
|
||
## Hook Types | ||
|
||
There are two patterns used by v8r plugin hooks. | ||
|
||
### Register Hooks | ||
|
||
- `registerInputFileParsers` | ||
- `registerOutputFormats` | ||
|
||
These hooks return an array of strings. Any values returned by these hooks are added to the list of formats v8r can work with. | ||
|
||
### Early Return Hooks | ||
|
||
- `parseInputFile` | ||
- `getSingleResultLogMessage` | ||
- `getAllResultsLogMessage` | ||
|
||
These hooks may optionally return or not return a value. Each plugin is run in sequence. The first plugin that returns a value "wins". That value will be used and no further plugins will be invoked. If a hook doesn't return anything, v8r will move on to the next plugin in the stack. | ||
|
||
## Worked Example | ||
|
||
Lets build a simple example plugin. Our plugin is going to register an output format called "emoji". If the user passes `--format emoji` (or sets `format: emoji` in their config file) the plugin will output a 👍 when the file is valid and a 👎 when the file is invalid instead of the default text log message. | ||
|
||
```js title="./plugins/v8r-plugin-emoji-output.js" | ||
// Our plugin extends the BasePlugin class | ||
import { BasePlugin } from "v8r"; | ||
|
||
class EmojiOutput extends BasePlugin { | ||
|
||
// v8r plugins must declare a name starting with "v8r-plugin-" | ||
static name = "v8r-plugin-emoji-output"; | ||
|
||
registerOutputFormats() { | ||
/* | ||
Registering "emoji" as an output format here adds "emoji" to the list | ||
of values the user may pass to the --format argument. | ||
We could register multiple output formats here if we want, | ||
but we're just going to register one. | ||
*/ | ||
return ["emoji"]; | ||
} | ||
|
||
/* | ||
We're going to implement the getSingleResultLogMessage hook here. This | ||
allows us to optionally return a log message to be written to stdout | ||
after each file is validated. | ||
*/ | ||
getSingleResultLogMessage(result, filename, format) { | ||
/* | ||
Check if the user has requested "emoji" output. | ||
If the user hasn't requested emoji output, we don't want to return a value. | ||
That will allow v8r to hand over to the next plugin in the sequence | ||
to check for other output formats. | ||
*/ | ||
if (format === "emoji") { | ||
// Implement our plugin logic | ||
if (result.valid === true) { | ||
return "👍"; | ||
} | ||
return "👎"; | ||
} | ||
} | ||
} | ||
|
||
// Our plugin must be an ESM module | ||
// and the plugin class must be the default export | ||
export default EmojiOutput; | ||
``` | ||
|
||
We can now register the plugin in our config file: | ||
|
||
```yaml title=".v8rrc.yml" | ||
plugins: | ||
- "file:./plugins/v8r-plugin-emoji-output.js" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"source": { | ||
"include": ["../src/plugins.js"] | ||
} | ||
} |
Oops, something went wrong.