This repository has been archived on 2020-11-02. You can view files and clone it, but cannot push or open issues or pull requests.
TripSit_Suite/node_modules/unified/index.js
2020-11-01 22:46:04 +00:00

474 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict'
var bail = require('bail')
var buffer = require('is-buffer')
var extend = require('extend')
var plain = require('is-plain-obj')
var trough = require('trough')
var vfile = require('vfile')
// Expose a frozen processor.
module.exports = unified().freeze()
var slice = [].slice
var own = {}.hasOwnProperty
// Process pipeline.
var pipeline = trough()
.use(pipelineParse)
.use(pipelineRun)
.use(pipelineStringify)
function pipelineParse(p, ctx) {
ctx.tree = p.parse(ctx.file)
}
function pipelineRun(p, ctx, next) {
p.run(ctx.tree, ctx.file, done)
function done(err, tree, file) {
if (err) {
next(err)
} else {
ctx.tree = tree
ctx.file = file
next()
}
}
}
function pipelineStringify(p, ctx) {
var result = p.stringify(ctx.tree, ctx.file)
var file = ctx.file
if (result === undefined || result === null) {
// Empty.
} else if (typeof result === 'string' || buffer(result)) {
file.contents = result
} else {
file.result = result
}
}
// Function to create the first processor.
function unified() {
var attachers = []
var transformers = trough()
var namespace = {}
var frozen = false
var freezeIndex = -1
// Data management.
processor.data = data
// Lock.
processor.freeze = freeze
// Plugins.
processor.attachers = attachers
processor.use = use
// API.
processor.parse = parse
processor.stringify = stringify
processor.run = run
processor.runSync = runSync
processor.process = process
processor.processSync = processSync
// Expose.
return processor
// Create a new processor based on the processor in the current scope.
function processor() {
var destination = unified()
var length = attachers.length
var index = -1
while (++index < length) {
destination.use.apply(null, attachers[index])
}
destination.data(extend(true, {}, namespace))
return destination
}
// Freeze: used to signal a processor that has finished configuration.
//
// For example, take unified itself: its frozen.
// Plugins should not be added to it.
// Rather, it should be extended, by invoking it, before modifying it.
//
// In essence, always invoke this when exporting a processor.
function freeze() {
var values
var plugin
var options
var transformer
if (frozen) {
return processor
}
while (++freezeIndex < attachers.length) {
values = attachers[freezeIndex]
plugin = values[0]
options = values[1]
transformer = null
if (options === false) {
continue
}
if (options === true) {
values[1] = undefined
}
transformer = plugin.apply(processor, values.slice(1))
if (typeof transformer === 'function') {
transformers.use(transformer)
}
}
frozen = true
freezeIndex = Infinity
return processor
}
// Data management.
// Getter / setter for processor-specific informtion.
function data(key, value) {
if (typeof key === 'string') {
// Set `key`.
if (arguments.length === 2) {
assertUnfrozen('data', frozen)
namespace[key] = value
return processor
}
// Get `key`.
return (own.call(namespace, key) && namespace[key]) || null
}
// Set space.
if (key) {
assertUnfrozen('data', frozen)
namespace = key
return processor
}
// Get space.
return namespace
}
// Plugin management.
//
// Pass it:
// * an attacher and options,
// * a preset,
// * a list of presets, attachers, and arguments (list of attachers and
// options).
function use(value) {
var settings
assertUnfrozen('use', frozen)
if (value === null || value === undefined) {
// Empty.
} else if (typeof value === 'function') {
addPlugin.apply(null, arguments)
} else if (typeof value === 'object') {
if ('length' in value) {
addList(value)
} else {
addPreset(value)
}
} else {
throw new Error('Expected usable value, not `' + value + '`')
}
if (settings) {
namespace.settings = extend(namespace.settings || {}, settings)
}
return processor
function addPreset(result) {
addList(result.plugins)
if (result.settings) {
settings = extend(settings || {}, result.settings)
}
}
function add(value) {
if (typeof value === 'function') {
addPlugin(value)
} else if (typeof value === 'object') {
if ('length' in value) {
addPlugin.apply(null, value)
} else {
addPreset(value)
}
} else {
throw new Error('Expected usable value, not `' + value + '`')
}
}
function addList(plugins) {
var length
var index
if (plugins === null || plugins === undefined) {
// Empty.
} else if (typeof plugins === 'object' && 'length' in plugins) {
length = plugins.length
index = -1
while (++index < length) {
add(plugins[index])
}
} else {
throw new Error('Expected a list of plugins, not `' + plugins + '`')
}
}
function addPlugin(plugin, value) {
var entry = find(plugin)
if (entry) {
if (plain(entry[1]) && plain(value)) {
value = extend(entry[1], value)
}
entry[1] = value
} else {
attachers.push(slice.call(arguments))
}
}
}
function find(plugin) {
var length = attachers.length
var index = -1
var entry
while (++index < length) {
entry = attachers[index]
if (entry[0] === plugin) {
return entry
}
}
}
// Parse a file (in string or vfile representation) into a unist node using
// the `Parser` on the processor.
function parse(doc) {
var file = vfile(doc)
var Parser
freeze()
Parser = processor.Parser
assertParser('parse', Parser)
if (newable(Parser, 'parse')) {
return new Parser(String(file), file).parse()
}
return Parser(String(file), file) // eslint-disable-line new-cap
}
// Run transforms on a unist node representation of a file (in string or
// vfile representation), async.
function run(node, file, cb) {
assertNode(node)
freeze()
if (!cb && typeof file === 'function') {
cb = file
file = null
}
if (!cb) {
return new Promise(executor)
}
executor(null, cb)
function executor(resolve, reject) {
transformers.run(node, vfile(file), done)
function done(err, tree, file) {
tree = tree || node
if (err) {
reject(err)
} else if (resolve) {
resolve(tree)
} else {
cb(null, tree, file)
}
}
}
}
// Run transforms on a unist node representation of a file (in string or
// vfile representation), sync.
function runSync(node, file) {
var complete = false
var result
run(node, file, done)
assertDone('runSync', 'run', complete)
return result
function done(err, tree) {
complete = true
bail(err)
result = tree
}
}
// Stringify a unist node representation of a file (in string or vfile
// representation) into a string using the `Compiler` on the processor.
function stringify(node, doc) {
var file = vfile(doc)
var Compiler
freeze()
Compiler = processor.Compiler
assertCompiler('stringify', Compiler)
assertNode(node)
if (newable(Compiler, 'compile')) {
return new Compiler(node, file).compile()
}
return Compiler(node, file) // eslint-disable-line new-cap
}
// Parse a file (in string or vfile representation) into a unist node using
// the `Parser` on the processor, then run transforms on that node, and
// compile the resulting node using the `Compiler` on the processor, and
// store that result on the vfile.
function process(doc, cb) {
freeze()
assertParser('process', processor.Parser)
assertCompiler('process', processor.Compiler)
if (!cb) {
return new Promise(executor)
}
executor(null, cb)
function executor(resolve, reject) {
var file = vfile(doc)
pipeline.run(processor, {file: file}, done)
function done(err) {
if (err) {
reject(err)
} else if (resolve) {
resolve(file)
} else {
cb(null, file)
}
}
}
}
// Process the given document (in string or vfile representation), sync.
function processSync(doc) {
var complete = false
var file
freeze()
assertParser('processSync', processor.Parser)
assertCompiler('processSync', processor.Compiler)
file = vfile(doc)
process(file, done)
assertDone('processSync', 'process', complete)
return file
function done(err) {
complete = true
bail(err)
}
}
}
// Check if `value` is a constructor.
function newable(value, name) {
return (
typeof value === 'function' &&
value.prototype &&
// A function with keys in its prototype is probably a constructor.
// Classes prototype methods are not enumerable, so we check if some value
// exists in the prototype.
(keys(value.prototype) || name in value.prototype)
)
}
// Check if `value` is an object with keys.
function keys(value) {
var key
for (key in value) {
return true
}
return false
}
// Assert a parser is available.
function assertParser(name, Parser) {
if (typeof Parser !== 'function') {
throw new Error('Cannot `' + name + '` without `Parser`')
}
}
// Assert a compiler is available.
function assertCompiler(name, Compiler) {
if (typeof Compiler !== 'function') {
throw new Error('Cannot `' + name + '` without `Compiler`')
}
}
// Assert the processor is not frozen.
function assertUnfrozen(name, frozen) {
if (frozen) {
throw new Error(
'Cannot invoke `' +
name +
'` on a frozen processor.\nCreate a new processor first, by invoking it: use `processor()` instead of `processor`.'
)
}
}
// Assert `node` is a unist node.
function assertNode(node) {
if (!node || typeof node.type !== 'string') {
throw new Error('Expected node, got `' + node + '`')
}
}
// Assert that `complete` is `true`.
function assertDone(name, asyncName, complete) {
if (!complete) {
throw new Error(
'`' + name + '` finished async. Use `' + asyncName + '` instead'
)
}
}