unified engine to process multiple files, lettings users configure from the file system
npm install unified-engine[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
[unified][] engine to process multiple files, lettings users
[configure][config-files] from the file system.
* What is this?
* When should I use this?
* Install
* Use
* API
* engine(options, callback)
* Configuration
* Completer
* Callback
* ConfigResult
* ConfigTransform
* Context
* FileSet
* Options
* Preset
* ResolveFrom
* VFileReporter
* Config files
* Explicit configuration
* Implicit configuration
* Examples
* Ignore files
* Explicit ignoring
* Implicit ignoring
* Extra ignoring
* Ignoring
* Examples
* Plugins
* Examples
* options.alwaysStringify
* options.configTransform
* options.defaultConfig
* options.detectConfig
* options.detectIgnore
* options.extensions
* options.filePath
* options.files
* options.frail
* options.ignoreName
* options.ignorePath
* options.ignorePathResolveFrom
* options.ignorePatterns
* options.ignoreUnconfigured
* options.inspect
* options.out
* options.output
* options.packageField
* options.pluginPrefix
* options.plugins
* options.processor
* options.quiet
* options.rcName
* options.rcPath
* options.reporter and options.reporterOptions
* options.settings
* options.silent
* options.streamError
* options.streamIn
* options.streamOut
* options.tree
* options.treeIn
* options.treeOut
* Types
* Compatibility
* Security
* Contribute
* License
This package is the engine.
It’s what you use underneath when you use [remark-cli][remark-cli] or a
language server.
Compared to unified, this deals with multiple files, often from the file
system, and with [configuration files][config-files] and
[ignore files][ignore-files].
You typically use something that wraps this, such as:
* [unified-args][unified-args]
— create CLIs
* [unified-engine-gulp][unified-engine-gulp]
— create Gulp plugins
* [unified-language-server][unified-language-server]
— create language servers
You can use this to make such things.
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:
``sh`
npm install unified-engine
The following example processes all files in the current folder with a
markdown extension with [remark][], allows [configuration][config-files]
from .remarkrc and package.json files, ignoring files from .remarkignore
files, and more.
`js
/**
* @import {Callback} from 'unified-engine'
*/
import process from 'node:process'
import {remark} from 'remark'
import {engine} from 'unified-engine'
engine(
{
color: true,
extensions: ['md', 'markdown', 'mkd', 'mkdn', 'mkdown'],
files: ['.'],
ignoreName: '.remarkignore',
packageField: 'remarkConfig',
pluginPrefix: 'remark',
processor: remark,
rcName: '.remarkrc'
},
done
)
/* @type {Callback} /
function done(error, code) {
if (error) throw error
process.exitCode = code
}
`
This package exports the identifiers [Configuration][api-configuration] andengine
[][api-engine].
There is no default export.
Process.
###### Parameters
* options ([Options][api-options], required)callback
— configuration
* ([Callback][api-callback], required)
— configuration
###### Returns
Nothing (undefined).
Internal class to load configuration files.
Exposed to build more complex integrations.
###### Parameters
* options (subset of [Options][api-options], required)cwd
— configuration ( is required)
###### Fields
* load(string, (Error?[, ConfigResult?]): undefined): undefined
— get the config for a file
Completer (TypeScript type).
###### Type
`ts
type Completer = (CompleterCallback | CompleterRegular) & {
pluginId?: string | symbol | undefined
}
type CompleterCallback = (set: FileSet, next: CompleterCallbackNext) => undefined
type CompleterCallbackNext = (error?: Error | null | undefined) => undefined
type CompleterRegular = (set: FileSet) => Promise
`
Callback called when done (TypeScript type).
Called with a fatal error if things went horribly wrong (probably due to
incorrect configuration), or a status code and the processing context.
###### Parameters
* error (Error, optional)code
— error
* (0 or 1, optional)0
— exit code, if successful or 1 if unsuccessfulcontext
* ([Context][api-context], optional)
— processing context
###### Returns
Nothing (undefined).
Resolved configuration from [Configuration][api-configuration] (TypeScript
type).
###### Fields
* filePath (string)plugins
— file path of found configuration
* (Array from unified)settings
— resolved plugins
* ([Settings from unified][unified-settings])
— resolved settings
Transform arbitrary configs to our format (TypeScript type).
###### Parameters
* config (unknown)filePath
— arbitrary config
* (string)
— file path of config file
###### Returns
Our config format ([Preset][api-preset]).
Processing context (TypeScript type).
###### Fields
* fileSet ([FileSet][api-file-set])files
— internally used info
* ([Array][vfile])
— processed files
A FileSet is created to process multiple files through unified processors
(TypeScript type).
This set, containing all files, is exposed to plugins as the second parameter.
###### Parameters
None.
###### Fields
* valueOf(): Arrayuse(completer: Completer): this
— get files in a set
* Completer
— add middleware to be called when done (see: [][api-completer])add(file: VFile | string): this
* streamOut
— add a file; the given file is processed like other files with a few
differences: it’s ignored when their file path is already added, never
written to the file system or , and not included in the report
Configuration (TypeScript type).
> 👉 Note: options.processor is required.
###### Fields
* alwaysStringify (boolean, default: false)color
— whether to always serialize successfully processed files
* (boolean, default: false)configTransform
— whether to report with ANSI color sequences; given to the reporter
* ([ConfigTransform][api-config-transform], optional)cwd
— transform config files from a different schema
* (URL or string, default: process.cwd())defaultConfig
— folder to search files in, load plugins from, and more
* ([Preset][api-preset], optional)detectConfig
— default configuration to use if no config file is given or found
* (boolean, default: true if options.packageField oroptions.rcName
)detectIgnore
— whether to search for configuration files
* (boolean, default: true if options.ignoreName)extensions
— whether to search for ignore files
* (Array, optional)treeIn
— search for files with these extensions, when folders are passed;
generated files are also given the first extension if is on andoutput
is on or points to a folderfilePath
* (URL or string, optional)streamIn
— file path to process the given file on asfiles
* (Array, optional)frail
— paths or [globs][node-glob] to files and folder, or virtual files, to
process
* (boolean, default: false)1
— call back with an unsuccessful () code on warnings as well as errorsignoreName
* (string, optional)ignorePath
— name of ignore files to load
* (URL or string, optional)ignorePathResolveFrom
— filepath to an ignore file to load
* ([ResolveFrom][api-resolve-from], default:'dir'
)ignorePath
— resolve patterns in from the current working folder'cwd'
() or the ignore file’s folder ('dir')ignorePatterns
* (optional)ignoreUnconfigured
— patterns to ignore in addition to ignore files
* (boolean, default: false)rcName
— ignore files that do not have an associated detected configuration file;
either or packageField must be defined too; cannot be combinedrcPath
with or detectConfig: falseinspect
* (boolean, default: false)out
— whether to output a formatted syntax tree for debugging
* (boolean, default: false)streamOut
— whether to write the processed file to output
* (URL, boolean or string, default: false)true
— whether to write successfully processed files, and where to; when ,false
overwrites the given files, when , does not write to the file system;packageField
when pointing to an existing folder, files are written to that folder and
keep their original basenames; when the parent folder of the given path
exists and one file is processed, the file is written to the given path
* (string, optional)package.json
— field where configuration can be found in filespluginPrefix
* (string, optional)plugins
— prefix to use when searching for plugins
* ([Preset['plugins']][api-preset], optional)processor
— plugins to use
* ([Processor][unified-processor], required)quiet
— unified processor to transform files
* (boolean, default: false)rcName
— do not report successful files; given to the reporter
* (string, optional)rcPath
— name of configuration files to load
* (URL or string, optional)reporter
— filepath to a configuration file to load
* ([VFileReporter][api-vfile-reporter] or string, default:vfile-reporter
)string
— reporter to use; if a is passed, it’s loaded from cwd, and'vfile-reporter-'
can be omittedreporterOptions
* ([Options][vfile-reporter-options] fromvfile-reporter
, optional)settings
— config to pass to the used reporter
* ([Settings][unified-settings] from unified, optional)silent
— configuration for the parser and compiler of the processor
* (boolean, default: false)silentlyIgnore
— report only fatal errors; given to the reporter
* (boolean, default: false)streamError
— skip given files if they are ignored
* ([WritableStream][node-writable-stream] from Node.js,process.stderr
default: )streamIn
— stream to write the report (if any) to
* ([ReadableStream][node-readable-stream] from Node.js,process.stdin
default: )streamOut
— stream to read from if no files are found or given
* ([WritableStream][node-writable-stream] from Node.js,process.stdout
default: )out
— stream to write processed files to, nothing is streamed if either false
is , output is not false, multiple files are processed, or atree
fatal error occurred while processing a file
* (boolean, default: false)treeIn
— whether to treat both input and output as a syntax tree
* (boolean, default: options.tree)treeOut
— whether to treat input as a syntax tree
* (boolean, default: options.tree)verbose
— whether to output as a syntax tree
* (boolean, default: false)
— report extra info; given to the reporter
Sharable configuration, with support for specifiers (TypeScript type).
Specifiers should not be used in actual presets (because they can’t be
used by regular unified), but they can be used in config files locally,
as those are only for the engine.
They can contain plugins and settings.
###### Type
`ts
import type {
Plugin as UnifiedPlugin,
PluginTuple as UnifiedPluginTuple,
Preset as UnifiedPreset,
Settings
} from 'unified'
type Preset = {
plugins?: PluggableList | PluggableMap | undefined
settings?: Settings | undefined
}
type Pluggable = Plugin | PluginTuple | UnifiedPreset
type PluggableList = Array
type PluggableMap = Record
type Plugin = UnifiedPlugin | string
type PluginTupleSupportingSpecifiers =
| [plugin: string, ...parameters: Array
| UnifiedPluginTuple
`
How to resolve (TypeScript type).
###### Type
`ts`
type ResolveFrom = 'cwd' | 'dir';
Transform arbitrary configs to our format (TypeScript type).
This is essentially the interface of [vfile-reporter][vfile-reporter], with
added support for unknown fields in options and async support.
###### Parameters
* files ([Array][vfile])options
— files
* ([Options][vfile-reporter-options] from vfile-reporter,
optional)
— configuration
###### Returns
Report (Promise or string).
unified-engine accepts configuration through options and through
configuration files (rc files).
One configuration file can be given through options.rcPath, this is loadedoptions.detectConfig
regardless of and options.rcName.
Otherwise, configuration files are detected if options.detectConfig is turned
on, depending on the following options:
* if options.rcName is given, $rcName (JSON), $rcName.js (CommonJS ortype
ESM depending on the field of the closest package.json),$rcName.cjs
(CommonJS), $rcName.mjs (ESM), $rcName.yml (YAML),$rcName.yaml
and (YAML) are loadedoptions.packageField
* if is given, package.json (JSON) files are loaded$packageField
and the configuration at their field is used
The first file that is searched for in a folder is used as the configuration.
If no file is found, the parent folder is searched, and so on.
The schema (type) of rc files is [Preset][api-preset].
An example rc file could look as follows:
`json`
{
"plugins": [
"remark-inline-links",
"remark-lint-recommended"
],
"settings": {
"bullet": "*",
"ruleRepetition": 3,
"fences": true
}
}
Another example, rc.js, could look as follows:
`js
exports.plugins = [
'./script/natural-language.js',
'remark-lint-recommended',
'remark-license'
]
exports.settings = {bullet: '*'}
`
When using ESM (ECMAScript modules), rc.mjs could look as folows:
`js`
export default {
plugins: [
'./script/natural-language.js',
'remark-lint-recommended',
'remark-license'
],
settings: {bullet: '*'}
}
Another example, rc.yaml, could look as follows:
`js`
plugins:
- 'rehype-document'
- 'rehype-preset-minify'
settings:
preferUnquoted: true
quote: "'"
quoteSmart: true
verbose: true
unified-engine accepts patterns to ignore when searching for files to process
through ignore files.
One ignore file can be given through options.ignorePath, this is loadedoptions.detectIgnore
regardless of and options.ignoreName.
Otherwise, ignore files are detected if options.detectIgnore is turned on andoptions.ignoreName is given.
The first file named $ignoreName in the parent folder of a checked file is
used.
Or, if no file is found, the parent folder if searched, and so on.
In addition to explicit and implicit ignore files, other patterns can be given
with options.ignorePatterns.ignorePatterns
The format of each pattern in is the same as a line in an
ignore file.
Patterns and files are resolved based on the current working folder.
It is also possible to ignore files that do not have an associated detected
configuration file by turning on options.ignoreUnconfigured.
Ignoring is used when searching for files in folders.
If paths (including those expanded from [globs][node-glob]) are passed in that
are ignored, an error is thrown.
These files can be silently ignored by turning on options.silentlyIgnore.
Normally, files are ignored based on the path of the found ignore file and the
patterns inside it.
Patterns passed with options.ignorePatterns are resolved based on the current
working directory.
Patterns in an explicit ignore file passed in with options.ignorePath can beoptions.ignorePathResolveFrom
resolved from the current working directory instead, by setting to 'cwd' instead of 'dir' (default).
If paths or globs to folders are given to the engine, they will be searched
for matching files, but node_modules are normally not searched.node_modules
Pass paths (or globs) to the you want to include inoptions.files to search them.
The format for ignore files is the same as [.gitignore][gitignore], so it’s.gitignore
possible to pass a in as options.ignorePath.
[node-ignore][node-ignore] is used under the hood, see its documentation
for more information.
An example ignore file could look as follows:
`ini.githubIgnore files in
.
.github/
If we had an ignore file
folder/.remarkignore, with the value: index.txt,
and our file system looked as follows:`txt
folder/.remarkignore
folder/index.txt
index.txt
`Then
folder/index.txt would be ignored but index.txt would not be.Plugins
Normally, unified plugins receive a single
options argument upon attaching
(an Object users can provide to configure the plugin).If a plugin is attached by unified-engine, a second argument is given:
[
FileSet][api-file-set].Examples
unified-engine can be configured extensively by engine authors.$3
This example shows how you can use
options.alwaysStringify when you don’t
want the engine to write to the file system, but still want to get the compiled
results.
One example that does this is unified-engine-gulp.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'
import {VFile} from 'vfile'const file = new VFile({path: 'example.md', value: '_hi_'})
engine(
{alwaysStringify: true, files: [file], processor: remark},
function (error, code, context) {
if (error) throw error
console.log(context?.files.map((d) => String(d)))
}
)
`Yields:
`txt
example.md: no issues found
``js
[ 'hi\n' ]
`$3
To support custom rc files, that have a different format than what the engine
supports, pass as [
ConfigTransform][api-config-transform].This example processes
readme.md and loads options from custom (from a
package.json).
configTransform is called with those options and transforms it to
configuration unified-engine understands.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
configTransform,
files: ['readme.md'],
packageField: 'custom',
processor: remark()
},
function (error) {
if (error) throw error
}
)
function configTransform(config) {
return {settings: (config || {}).options}
}
`Where
package.json contains:`json
{
"name": "foo",
"private": true,
"custom": {
"options": {
"bullet": "+"
}
}
}
`$3
This example processes
readme.md.
If package.json exists, that config is used, otherwise the configuration at
defaultConfig is used.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
defaultConfig: {settings: {bullet: '+'}},
files: ['readme.md'],
packageField: 'remarkConfig',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`Where
package.json contains:`json
{
"name": "foo",
"private": true,
"remarkConfig": {
"settings": {
"bullet": "-"
}
}
}
`$3
This example processes
readme.md but does not allow configuration from
.remarkrc or package.json files, as detectConfig is false.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
detectConfig: false,
files: ['readme.md'],
processor: remark(),
packageField: 'remarkConfig',
rcName: '.remarkrc'
},
function (error) {
if (error) throw error
}
)
`$3
This example processes files in the current working directory with an
md
extension but does not ignore file paths from the closest .remarkignore
file, because detectIgnore is false.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
detectIgnore: false,
extensions: ['md'],
files: ['.'],
ignoreName: '.remarkignore',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example reformats all files with
md, markdown, and mkd
extensions in the current folder.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md', 'mkd', 'markdown'],
files: ['.'],
output: true,
processor: remark
},
function (error) {
if (error) throw error
}
)
`$3
This example shows that
streamIn is named as filePath:`js
import {PassThrough} from 'node:stream'
import {remark} from 'remark'
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
import {engine} from 'unified-engine'const streamIn = new PassThrough()
streamIn.write('doc')
setImmediate(function () {
streamIn.end('ument')
})
engine(
{
filePath: '~/alpha/bravo/charlie.md',
out: false,
plugins: [remarkPresetLintRecommended],
processor: remark(),
streamIn
},
function (error) {
if (error) throw error
}
)
`Yields:
`txt
~/alpha/bravo/charlie.md
1:1 warning Missing newline character at end of file final-newline remark-lint⚠ 1 warning
`$3
This example processes
LICENSE and all files with an md extension in doc.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['LICENSE', 'doc/'],
processor: remark
},
function (error) {
if (error) throw error
}
)
`$3
This example uses [
remark-lint][remark-lint] to lint readme.md and exits
with the given exit code.
Normally, only errors turn the code to 1, but in frail mode lint warnings
result in the same.`js
import process from 'node:process'
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
frail: true,
plugins: ['remark-preset-lint-recommended'],
processor: remark()
},
function (error, code) {
process.exitCode = error ? 1 : code
}
)
`$3
This example processes files in the current working directory with an
md
extension, and is configured to ignore file paths from the closest
.remarkignore file.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['.'],
ignoreName: '.remarkignore',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes files in the current working directory with an
md
extension and ignores file paths specified in .gitignore.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['.'],
ignorePath: '.gitignore',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes files in the current working directory with an
md
extension and takes a reusable configuration file from a dependency.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['.'],
ignorePath: 'node_modules/my-config/my-ignore',
ignorePathResolveFrom: 'cwd',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes files in the current working directory with an
md
extension, except for readme.md:`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['.'],
ignorePatterns: ['readme.md'],
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes files in the current working directory with an
md extension, but only if there is an explicit .remarkrc config file near
(upwards) to them:`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['.'],
ignoreUnconfigured: true,
processor: remark(),
rcName: '.remarkrc'
},
function (error) {
if (error) throw error
}
)
`$3
This example shows a module which reads and parses
doc.md, then
[remark-unlink][remark-unlink] transforms the syntax tree, the tree is
formatted with [unist-util-inspect][unist-util-inspect], and finally written
to stdout(4).`js
import {remark} from 'remark'
import remarkUnlink from 'remark-unlink'
import {engine} from 'unified-engine'engine(
{
files: ['doc.md'],
inspect: true,
plugins: [remarkUnlink],
processor: remark()
},
function (error) {
if (error) throw error
}
)
`Where
doc.md looks as follows:`markdown
foo
`Yields:
`txt
root[1] (1:1-2:1, 0-27)
└─ paragraph[1] (1:1-1:27, 0-26)
└─ text: "foo" (1:2-1:5, 1-4)
`$3
This example uses [
remark-lint][remark-lint] to lint readme.md, writes the
report, and ignores the serialized document.`js
import {remark} from 'remark'
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
out: false,
plugins: [remarkPresetLintRecommended],
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example writes all files in
src/ with an md extension compiled to
dest/.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
extensions: ['md'],
files: ['src/'],
output: 'dest/',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes
readme.md, and allows configuration from
remarkConfig fields in package.json files.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
packageField: 'remarkConfig',
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes
readme.md and loads the
preset-lint-recommended plugin.
Because pluginPrefix is given, this resolves to
[remark-preset-lint-recommended][remark-preset-lint-recommended] (from
node_modules/) if available.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
pluginPrefix: 'remark',
plugins: ['preset-lint-recommended'],
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example processes
readme.md and loads the
[remark-preset-lint-recommended][remark-preset-lint-recommended]
preset.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
plugins: ['remark-preset-lint-recommended'],
processor: remark()
},
function (error) {
if (error) throw error
}
)
`$3
This example reformats stdin(4) using [remark][], writes the report
to stderr(4), and formatted document to stdout(4).
`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine({processor: remark}, function (error) {
if (error) throw error
})
`$3
This example uses [
remark-lint][remark-lint] to lint readme.md.
Nothing is reported if the file processed successfully.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
plugins: ['remark-preset-lint-recommended'],
processor: remark(),
quiet: true
},
function (error) {
if (error) throw error
}
)
`$3
This example processes
readme.md and allows configuration from .remarkrc,
.remarkrc.json, .remarkrc.yml, .remarkrc.yaml, .remarkrc.js,
.remarkrc.cjs, and .remarkrc.mjs files.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{files: ['readme.md'], processor: remark(), rcName: '.remarkrc'},
function (error) {
if (error) throw error
}
)
`$3
This example processes
readme.md and loads configuration from config.json.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{files: ['readme.md'], processor: remark(), rcPath: 'config.json'},
function (error) {
if (error) throw error
}
)
`$3
This example processes all HTML files in the current folder with rehype,
configures the processor with
.rehyperc files, and prints a report in
JSON using [vfile-reporter-json][vfile-reporter-json] with
[reporter options][vfile-reporter-options].`js
import {rehype} from 'rehype'
import {engine} from 'unified-engine'engine(
{
extensions: ['html'],
files: ['.'],
processor: rehype(),
rcName: '.rehyperc',
reporter: 'json',
reporterOptions: {pretty: true}
},
function (error) {
if (error) throw error
}
)
`$3
This example processes
readme.md and configures the compiler
([remark-stringify][remark-stringify]) with bullet: '+'.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{files: ['readme.md'], processor: remark(), settings: {bullet: '+'}},
function (error) {
if (error) throw error
}
)
`$3
This example uses [
remark-lint][remark-lint] to lint readme.md but does not
report any warnings or success messages, only fatal errors, if they occur.`js
import {remark} from 'remark'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
plugins: ['remark-preset-lint-recommended'],
processor: remark(),
silent: true
},
function (error) {
if (error) throw error
}
)
`$3
This example uses [
remark-lint][remark-lint] to lint readme.md and writes
the report to report.txt.`js
import fs from 'node:fs'
import {remark} from 'remark'
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
import {engine} from 'unified-engine'engine(
{
files: ['readme.md'],
out: false,
plugins: [remarkPresetLintRecommended],
processor: remark(),
streamErr: fs.createWriteStream('report.txt')
},
function (error) {
if (error) throw error
}
)
`$3
This example uses [
remark-lint][remark-lint] to lint an incoming
stream.`js
import {PassThrough} from 'node:stream'
import {remark} from 'remark'
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
import {engine} from 'unified-engine'const streamIn = new PassThrough()
streamIn.write('doc')
setImmediate(function () {
streamIn.end('ument')
})
engine(
{
out: false,
plugins: [remarkPresetLintRecommended],
processor: remark(),
streamIn
},
function (error) {
if (error) throw error
}
)
`Yields:
`txt
1:1 warning Missing newline character at end of file final-newline remark-lint⚠ 1 warning
`$3
This example reads
readme.md and writes the serialized document to
readme-two.md.
This can also be achieved by passing output: 'readme-two.md' instead of
streamOut.`js
import fs from 'node:fs'
import {remark} from 'remark'
import {engine} from 'unified-engine'const streamOut = fs.createWriteStream('readme-two.md')
engine(
{files: ['readme.md'], processor: remark(), streamOut},
function (error) {
if (error) throw error
}
)
`$3
This example reads
tree.json, then [remark-unlink][remark-unlink]
transforms the syntax tree, and the transformed tree is written to
stdout(4).`js
import {remark} from 'remark'
import remarkUnlink from 'remark-unlink'
import {engine} from 'unified-engine'engine(
{
files: ['tree.json'],
plugins: [remarkUnlink],
processor: remark(),
tree: true
},
function (error) {
if (error) throw error
}
)
`Where
tree.json looks as follows:`json
{
"type": "paragraph",
"children": [{
"type": "link",
"url": "https://example.com",
"children": [{
"type": "text",
"value": "foo"
}]
}]
}
`Yields:
`json
{
"type": "paragraph",
"children": [{
"type": "text",
"value": "foo"
}]
}
`$3
This example reads
tree.json, then [remark-unlink][remark-unlink]
transforms the syntax tree, the tree is serialized, and the resulting document
is written to stdout(4).`js
import {remark} from 'remark'
import remarkUnlink from 'remark-unlink'
import {engine} from 'unified-engine'engine(
{
files: ['tree.json'],
plugins: [remarkUnlink],
processor: remark(),
treeIn: true
},
function (error) {
if (error) throw error
}
)
`Where
tree.json looks as follows:`json
{
"type": "paragraph",
"children": [{
"type": "link",
"url": "https://example.com",
"children": [{
"type": "text",
"value": "foo"
}]
}]
}
`Yields:
`markdown
foo
`$3
This example shows a module which reads and parses
doc.md, then
[remark-unlink][remark-unlink] transforms the syntax tree, and the tree is
written to stdout(4).`js
import {remark} from 'remark'
import remarkUnlink from 'remark-unlink'
import {engine} from 'unified-engine'engine(
{
files: ['doc.md'],
plugins: [remarkUnlink],
processor: remark(),
treeOut: true
},
function (error) {
if (error) throw error
}
)
`Where
doc.md looks as follows:`markdown
foo
`Yields:
`json
{
"type": "paragraph",
"children": [{
"type": "text",
"value": "foo"
}]
}
`Types
This package is fully typed with [TypeScript][].
It exports the additional types
[
Completer][api-completer],
[Callback][api-callback],
[ConfigResult][api-config-result],
[ConfigTransform][api-config-transform],
[Context][api-context],
[FileSet][api-file-set],
[Options][api-options],
[Preset][api-preset],
[ResolveFrom][api-resolve-from], and
[VFileReporter][api-vfile-reporter].Compatibility
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line,
unified-engine@^11,
compatible with Node.js 16.Security
unified-engine loads and evaluates configuration files, plugins, and presets
from the file system (often from node_modules/).
That means code that is on your file system runs.
Make sure you trust the workspace where you run unified-engine and be careful
with packages from npm and changes made by contributors.Contribute
See [
contributing.md][contributing] in [unifiedjs/.github][health] for ways
to get started.
See [support.md`][support] for ways to get help.This project has a [code of conduct][coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
[MIT][license] © [Titus Wormer][author]
[build-badge]: https://github.com/unifiedjs/unified-engine/workflows/main/badge.svg
[build]: https://github.com/unifiedjs/unified-engine/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/unifiedjs/unified-engine.svg
[coverage]: https://codecov.io/github/unifiedjs/unified-engine
[downloads-badge]: https://img.shields.io/npm/dm/unified-engine.svg
[downloads]: https://www.npmjs.com/package/unified-engine
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[collective]: https://opencollective.com/unified
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[chat]: https://github.com/unifiedjs/unified/discussions
[npm]: https://docs.npmjs.com/cli/install
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[typescript]: https://www.typescriptlang.org
[health]: https://github.com/unifiedjs/.github
[contributing]: https://github.com/unifiedjs/.github/blob/main/contributing.md
[support]: https://github.com/unifiedjs/.github/blob/main/support.md
[coc]: https://github.com/unifiedjs/.github/blob/main/code-of-conduct.md
[license]: license
[author]: https://wooorm.com
[gitignore]: https://git-scm.com/docs/gitignore
[node-glob]: https://github.com/isaacs/node-glob#glob-primer
[node-ignore]: https://github.com/kaelzhang/node-ignore
[remark]: https://github.com/remarkjs/remark
[remark-cli]: https://github.com/remarkjs/remark/tree/main/packages/remark-cli#readme
[remark-lint]: https://github.com/remarkjs/remark-lint
[remark-preset-lint-recommended]: https://github.com/remarkjs/remark-lint/tree/main/packages/remark-preset-lint-recommended
[remark-stringify]: https://github.com/remarkjs/remark/tree/main/packages/remark-stringify
[remark-unlink]: https://github.com/remarkjs/remark-unlink
[unified]: https://github.com/unifiedjs/unified
[unified-processor]: https://github.com/unifiedjs/unified#processor-1
[unified-args]: https://github.com/unifiedjs/unified-args
[unified-engine-gulp]: https://github.com/unifiedjs/unified-engine-gulp
[unified-language-server]: https://github.com/unifiedjs/unified-language-server
[unified-settings]: https://github.com/unifiedjs/unified#settings
[unist-util-inspect]: https://github.com/syntax-tree/unist-util-inspect
[vfile]: https://github.com/vfile/vfile
[vfile-reporter]: https://github.com/vfile/vfile-reporter
[vfile-reporter-json]: https://github.com/vfile/vfile-reporter-json
[vfile-reporter-options]: https://github.com/vfile/vfile-reporter#options
[node-readable-stream]: https://nodejs.org/api/stream.html#readable-streams
[node-writable-stream]: https://nodejs.org/api/stream.html#writable-streams
[config-files]: #config-files
[ignore-files]: #ignore-files
[api-configuration]: #configuration
[api-engine]: #engineoptions-callback
[api-completer]: #completer
[api-callback]: #callback
[api-config-result]: #configresult
[api-config-transform]: #configtransform
[api-context]: #context
[api-file-set]: #fileset
[api-options]: #options
[api-preset]: #preset
[api-resolve-from]: #resolvefrom
[api-vfile-reporter]: #vfilereporter