123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323 |
- import {bail} from 'bail'
- import extend from 'extend'
- import {ok as assert} from 'devlop'
- import isPlainObj from 'is-plain-obj'
- import {trough} from 'trough'
- import {VFile} from 'vfile'
- import {CallableInstance} from './callable-instance.js'
- const own = {}.hasOwnProperty
- export class Processor extends CallableInstance {
-
- constructor() {
-
- super('copy')
-
- this.Compiler = undefined
-
- this.Parser = undefined
-
-
-
-
-
- this.attachers = []
-
- this.compiler = undefined
-
- this.freezeIndex = -1
-
- this.frozen = undefined
-
- this.namespace = {}
-
- this.parser = undefined
-
- this.transformers = trough()
- }
-
- copy() {
-
- const destination =
- (
- new Processor()
- )
- let index = -1
- while (++index < this.attachers.length) {
- const attacher = this.attachers[index]
- destination.use(...attacher)
- }
- destination.data(extend(true, {}, this.namespace))
- return destination
- }
-
- data(key, value) {
- if (typeof key === 'string') {
-
- if (arguments.length === 2) {
- assertUnfrozen('data', this.frozen)
- this.namespace[key] = value
- return this
- }
-
- return (own.call(this.namespace, key) && this.namespace[key]) || undefined
- }
-
- if (key) {
- assertUnfrozen('data', this.frozen)
- this.namespace = key
- return this
- }
-
- return this.namespace
- }
-
- freeze() {
- if (this.frozen) {
- return this
- }
-
-
-
- const self = ( (this))
- while (++this.freezeIndex < this.attachers.length) {
- const [attacher, ...options] = this.attachers[this.freezeIndex]
- if (options[0] === false) {
- continue
- }
- if (options[0] === true) {
- options[0] = undefined
- }
- const transformer = attacher.call(self, ...options)
- if (typeof transformer === 'function') {
- this.transformers.use(transformer)
- }
- }
- this.frozen = true
- this.freezeIndex = Number.POSITIVE_INFINITY
- return this
- }
-
- parse(file) {
- this.freeze()
- const realFile = vfile(file)
- const parser = this.parser || this.Parser
- assertParser('parse', parser)
- return parser(String(realFile), realFile)
- }
-
- process(file, done) {
- const self = this
- this.freeze()
- assertParser('process', this.parser || this.Parser)
- assertCompiler('process', this.compiler || this.Compiler)
- return done ? executor(undefined, done) : new Promise(executor)
-
-
- function executor(resolve, reject) {
- const realFile = vfile(file)
-
-
- const parseTree =
- (
- (self.parse(realFile))
- )
- self.run(parseTree, realFile, function (error, tree, file) {
- if (error || !tree || !file) {
- return realDone(error)
- }
-
-
- const compileTree =
- (
- (tree)
- )
- const compileResult = self.stringify(compileTree, file)
- if (looksLikeAValue(compileResult)) {
- file.value = compileResult
- } else {
- file.result = compileResult
- }
- realDone(error, (file))
- })
-
- function realDone(error, file) {
- if (error || !file) {
- reject(error)
- } else if (resolve) {
- resolve(file)
- } else {
- assert(done, '`done` is defined if `resolve` is not')
- done(undefined, file)
- }
- }
- }
- }
-
- processSync(file) {
-
- let complete = false
-
- let result
- this.freeze()
- assertParser('processSync', this.parser || this.Parser)
- assertCompiler('processSync', this.compiler || this.Compiler)
- this.process(file, realDone)
- assertDone('processSync', 'process', complete)
- assert(result, 'we either bailed on an error or have a tree')
- return result
-
- function realDone(error, file) {
- complete = true
- bail(error)
- result = file
- }
- }
-
- run(tree, file, done) {
- assertNode(tree)
- this.freeze()
- const transformers = this.transformers
- if (!done && typeof file === 'function') {
- done = file
- file = undefined
- }
- return done ? executor(undefined, done) : new Promise(executor)
-
-
- function executor(resolve, reject) {
- assert(
- typeof file !== 'function',
- '`file` can’t be a `done` anymore, we checked'
- )
- const realFile = vfile(file)
- transformers.run(tree, realFile, realDone)
-
- function realDone(error, outputTree, file) {
- const resultingTree =
- (
- outputTree || tree
- )
- if (error) {
- reject(error)
- } else if (resolve) {
- resolve(resultingTree)
- } else {
- assert(done, '`done` is defined if `resolve` is not')
- done(undefined, resultingTree, file)
- }
- }
- }
- }
-
- runSync(tree, file) {
-
- let complete = false
-
- let result
- this.run(tree, file, realDone)
- assertDone('runSync', 'run', complete)
- assert(result, 'we either bailed on an error or have a tree')
- return result
-
- function realDone(error, tree) {
- bail(error)
- result = tree
- complete = true
- }
- }
-
- stringify(tree, file) {
- this.freeze()
- const realFile = vfile(file)
- const compiler = this.compiler || this.Compiler
- assertCompiler('stringify', compiler)
- assertNode(tree)
- return compiler(tree, realFile)
- }
-
- use(value, ...parameters) {
- const attachers = this.attachers
- const namespace = this.namespace
- assertUnfrozen('use', this.frozen)
- if (value === null || value === undefined) {
-
- } else if (typeof value === 'function') {
- addPlugin(value, parameters)
- } else if (typeof value === 'object') {
- if (Array.isArray(value)) {
- addList(value)
- } else {
- addPreset(value)
- }
- } else {
- throw new TypeError('Expected usable value, not `' + value + '`')
- }
- return this
-
- function add(value) {
- if (typeof value === 'function') {
- addPlugin(value, [])
- } else if (typeof value === 'object') {
- if (Array.isArray(value)) {
- const [plugin, ...parameters] =
- (value)
- addPlugin(plugin, parameters)
- } else {
- addPreset(value)
- }
- } else {
- throw new TypeError('Expected usable value, not `' + value + '`')
- }
- }
-
- function addPreset(result) {
- if (!('plugins' in result) && !('settings' in result)) {
- throw new Error(
- 'Expected usable value but received an empty preset, which is probably a mistake: presets typically come with `plugins` and sometimes with `settings`, but this has neither'
- )
- }
- addList(result.plugins)
- if (result.settings) {
- namespace.settings = extend(true, namespace.settings, result.settings)
- }
- }
-
- function addList(plugins) {
- let index = -1
- if (plugins === null || plugins === undefined) {
-
- } else if (Array.isArray(plugins)) {
- while (++index < plugins.length) {
- const thing = plugins[index]
- add(thing)
- }
- } else {
- throw new TypeError('Expected a list of plugins, not `' + plugins + '`')
- }
- }
-
- function addPlugin(plugin, parameters) {
- let index = -1
- let entryIndex = -1
- while (++index < attachers.length) {
- if (attachers[index][0] === plugin) {
- entryIndex = index
- break
- }
- }
- if (entryIndex === -1) {
- attachers.push([plugin, ...parameters])
- }
-
-
- else if (parameters.length > 0) {
- let [primary, ...rest] = parameters
- const currentPrimary = attachers[entryIndex][1]
- if (isPlainObj(currentPrimary) && isPlainObj(primary)) {
- primary = extend(true, currentPrimary, primary)
- }
- attachers[entryIndex] = [plugin, primary, ...rest]
- }
- }
- }
- }
- export const unified = new Processor().freeze()
- function assertParser(name, value) {
- if (typeof value !== 'function') {
- throw new TypeError('Cannot `' + name + '` without `parser`')
- }
- }
- function assertCompiler(name, value) {
- if (typeof value !== 'function') {
- throw new TypeError('Cannot `' + name + '` without `compiler`')
- }
- }
- function assertUnfrozen(name, frozen) {
- if (frozen) {
- throw new Error(
- 'Cannot call `' +
- name +
- '` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.'
- )
- }
- }
- function assertNode(node) {
-
-
- if (!isPlainObj(node) || typeof node.type !== 'string') {
- throw new TypeError('Expected node, got `' + node + '`')
-
- }
- }
- function assertDone(name, asyncName, complete) {
- if (!complete) {
- throw new Error(
- '`' + name + '` finished async. Use `' + asyncName + '` instead'
- )
- }
- }
- function vfile(value) {
- return looksLikeAVFile(value) ? value : new VFile(value)
- }
- function looksLikeAVFile(value) {
- return Boolean(
- value &&
- typeof value === 'object' &&
- 'message' in value &&
- 'messages' in value
- )
- }
- function looksLikeAValue(value) {
- return typeof value === 'string' || isUint8Array(value)
- }
- function isUint8Array(value) {
- return Boolean(
- value &&
- typeof value === 'object' &&
- 'byteLength' in value &&
- 'byteOffset' in value
- )
- }
|