UNPKG

@gram-data/gram-parse

Version:
1,814 lines (1,495 loc) 111 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory((global.gram = global.gram || {}, global.gram.parse = {}))); }(this, (function (exports) { 'use strict'; var bail_1 = bail; function bail(err) { if (err) { throw err } } /*! * Determine if an object is a Buffer * * @author Feross Aboukhadijeh <https://feross.org> * @license MIT */ var isBuffer = function isBuffer (obj) { return obj != null && obj.constructor != null && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) }; var hasOwn = Object.prototype.hasOwnProperty; var toStr = Object.prototype.toString; var defineProperty = Object.defineProperty; var gOPD = Object.getOwnPropertyDescriptor; var isArray = function isArray(arr) { if (typeof Array.isArray === 'function') { return Array.isArray(arr); } return toStr.call(arr) === '[object Array]'; }; var isPlainObject = function isPlainObject(obj) { if (!obj || toStr.call(obj) !== '[object Object]') { return false; } var hasOwnConstructor = hasOwn.call(obj, 'constructor'); var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); // Not own constructor property must be Object if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) { return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for (key in obj) { /**/ } return typeof key === 'undefined' || hasOwn.call(obj, key); }; // If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target var setProperty = function setProperty(target, options) { if (defineProperty && options.name === '__proto__') { defineProperty(target, options.name, { enumerable: true, configurable: true, value: options.newValue, writable: true }); } else { target[options.name] = options.newValue; } }; // Return undefined instead of __proto__ if '__proto__' is not an own property var getProperty = function getProperty(obj, name) { if (name === '__proto__') { if (!hasOwn.call(obj, name)) { return void 0; } else if (gOPD) { // In early versions of node, obj['__proto__'] is buggy when obj has // __proto__ as an own property. Object.getOwnPropertyDescriptor() works. return gOPD(obj, name).value; } } return obj[name]; }; var extend = function extend() { var options, name, src, copy, copyIsArray, clone; var target = arguments[0]; var i = 1; var length = arguments.length; var deep = false; // Handle a deep copy situation if (typeof target === 'boolean') { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } if (target == null || (typeof target !== 'object' && typeof target !== 'function')) { target = {}; } for (; i < length; ++i) { options = arguments[i]; // Only deal with non-null/undefined values if (options != null) { // Extend the base object for (name in options) { src = getProperty(target, name); copy = getProperty(options, name); // Prevent never-ending loop if (target !== copy) { // Recurse if we're merging plain objects or arrays if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { if (copyIsArray) { copyIsArray = false; clone = src && isArray(src) ? src : []; } else { clone = src && isPlainObject(src) ? src : {}; } // Never move original objects, clone them setProperty(target, { name: name, newValue: extend(deep, clone, copy) }); // Don't bring in undefined values } else if (typeof copy !== 'undefined') { setProperty(target, { name: name, newValue: copy }); } } } } } // Return the modified object return target; }; var isPlainObj = value => { if (Object.prototype.toString.call(value) !== '[object Object]') { return false; } const prototype = Object.getPrototypeOf(value); return prototype === null || prototype === Object.prototype; }; var slice = [].slice; var wrap_1 = wrap; // Wrap `fn`. // Can be sync or async; return a promise, receive a completion handler, return // new values and errors. function wrap(fn, callback) { var invoked; return wrapped function wrapped() { var params = slice.call(arguments, 0); var callback = fn.length > params.length; var result; if (callback) { params.push(done); } try { result = fn.apply(null, params); } catch (error) { // Well, this is quite the pickle. // `fn` received a callback and invoked it (thus continuing the pipeline), // but later also threw an error. // We’re not about to restart the pipeline again, so the only thing left // to do is to throw the thing instead. if (callback && invoked) { throw error } return done(error) } if (!callback) { if (result && typeof result.then === 'function') { result.then(then, done); } else if (result instanceof Error) { done(result); } else { then(result); } } } // Invoke `next`, only once. function done() { if (!invoked) { invoked = true; callback.apply(null, arguments); } } // Invoke `done` with one value. // Tracks if an error is passed, too. function then(value) { done(null, value); } } var trough_1 = trough; trough.wrap = wrap_1; var slice$1 = [].slice; // Create new middleware. function trough() { var fns = []; var middleware = {}; middleware.run = run; middleware.use = use; return middleware // Run `fns`. Last argument must be a completion handler. function run() { var index = -1; var input = slice$1.call(arguments, 0, -1); var done = arguments[arguments.length - 1]; if (typeof done !== 'function') { throw new Error('Expected function as last argument, not ' + done) } next.apply(null, [null].concat(input)); // Run the next `fn`, if any. function next(err) { var fn = fns[++index]; var params = slice$1.call(arguments, 0); var values = params.slice(1); var length = input.length; var pos = -1; if (err) { done(err); return } // Copy non-nully input into values. while (++pos < length) { if (values[pos] === null || values[pos] === undefined) { values[pos] = input[pos]; } } input = values; // Next or done. if (fn) { wrap_1(fn, next).apply(null, input); } else { done.apply(null, [null].concat(input)); } } } // Add `fn` to the list. function use(fn) { if (typeof fn !== 'function') { throw new Error('Expected `fn` to be a function, not ' + fn) } fns.push(fn); return middleware } } var own = {}.hasOwnProperty; var unistUtilStringifyPosition = stringify; function stringify(value) { // Nothing. if (!value || typeof value !== 'object') { return '' } // Node. if (own.call(value, 'position') || own.call(value, 'type')) { return position(value.position) } // Position. if (own.call(value, 'start') || own.call(value, 'end')) { return position(value) } // Point. if (own.call(value, 'line') || own.call(value, 'column')) { return point(value) } // ? return '' } function point(point) { if (!point || typeof point !== 'object') { point = {}; } return index(point.line) + ':' + index(point.column) } function position(pos) { if (!pos || typeof pos !== 'object') { pos = {}; } return point(pos.start) + '-' + point(pos.end) } function index(value) { return value && typeof value === 'number' ? value : 1 } var vfileMessage = VMessage; // Inherit from `Error#`. function VMessagePrototype() {} VMessagePrototype.prototype = Error.prototype; VMessage.prototype = new VMessagePrototype(); // Message properties. var proto = VMessage.prototype; proto.file = ''; proto.name = ''; proto.reason = ''; proto.message = ''; proto.stack = ''; proto.fatal = null; proto.column = null; proto.line = null; // Construct a new VMessage. // // Note: We cannot invoke `Error` on the created context, as that adds readonly // `line` and `column` attributes on Safari 9, thus throwing and failing the // data. function VMessage(reason, position, origin) { var parts; var range; var location; if (typeof position === 'string') { origin = position; position = null; } parts = parseOrigin(origin); range = unistUtilStringifyPosition(position) || '1:1'; location = { start: {line: null, column: null}, end: {line: null, column: null} }; // Node. if (position && position.position) { position = position.position; } if (position) { // Position. if (position.start) { location = position; position = position.start; } else { // Point. location.start = position; } } if (reason.stack) { this.stack = reason.stack; reason = reason.message; } this.message = reason; this.name = range; this.reason = reason; this.line = position ? position.line : null; this.column = position ? position.column : null; this.location = location; this.source = parts[0]; this.ruleId = parts[1]; } function parseOrigin(origin) { var result = [null, null]; var index; if (typeof origin === 'string') { index = origin.indexOf(':'); if (index === -1) { result[1] = origin; } else { result[0] = origin.slice(0, index); result[1] = origin.slice(index + 1); } } return result } // A derivative work based on: // <https://github.com/browserify/path-browserify>. // Which is licensed: // // MIT License // // Copyright (c) 2013 James Halliday // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // A derivative work based on: // // Parts of that are extracted from Node’s internal `path` module: // <https://github.com/nodejs/node/blob/master/lib/path.js>. // Which is licensed: // // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. var basename_1 = basename; var dirname_1 = dirname; var extname_1 = extname; var join_1 = join; var sep = '/'; function basename(path, ext) { var start = 0; var end = -1; var index; var firstNonSlashEnd; var seenNonSlash; var extIndex; if (ext !== undefined && typeof ext !== 'string') { throw new TypeError('"ext" argument must be a string') } assertPath(path); index = path.length; if (ext === undefined || !ext.length || ext.length > path.length) { while (index--) { if (path.charCodeAt(index) === 47 /* `/` */) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now. if (seenNonSlash) { start = index + 1; break } } else if (end < 0) { // We saw the first non-path separator, mark this as the end of our // path component. seenNonSlash = true; end = index + 1; } } return end < 0 ? '' : path.slice(start, end) } if (ext === path) { return '' } firstNonSlashEnd = -1; extIndex = ext.length - 1; while (index--) { if (path.charCodeAt(index) === 47 /* `/` */) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now. if (seenNonSlash) { start = index + 1; break } } else { if (firstNonSlashEnd < 0) { // We saw the first non-path separator, remember this index in case // we need it if the extension ends up not matching. seenNonSlash = true; firstNonSlashEnd = index + 1; } if (extIndex > -1) { // Try to match the explicit extension. if (path.charCodeAt(index) === ext.charCodeAt(extIndex--)) { if (extIndex < 0) { // We matched the extension, so mark this as the end of our path // component end = index; } } else { // Extension does not match, so our result is the entire path // component extIndex = -1; end = firstNonSlashEnd; } } } } if (start === end) { end = firstNonSlashEnd; } else if (end < 0) { end = path.length; } return path.slice(start, end) } function dirname(path) { var end; var unmatchedSlash; var index; assertPath(path); if (!path.length) { return '.' } end = -1; index = path.length; // Prefix `--` is important to not run on `0`. while (--index) { if (path.charCodeAt(index) === 47 /* `/` */) { if (unmatchedSlash) { end = index; break } } else if (!unmatchedSlash) { // We saw the first non-path separator unmatchedSlash = true; } } return end < 0 ? path.charCodeAt(0) === 47 /* `/` */ ? '/' : '.' : end === 1 && path.charCodeAt(0) === 47 /* `/` */ ? '//' : path.slice(0, end) } function extname(path) { var startDot = -1; var startPart = 0; var end = -1; // Track the state of characters (if any) we see before our first dot and // after any path separator we find. var preDotState = 0; var unmatchedSlash; var code; var index; assertPath(path); index = path.length; while (index--) { code = path.charCodeAt(index); if (code === 47 /* `/` */) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now. if (unmatchedSlash) { startPart = index + 1; break } continue } if (end < 0) { // We saw the first non-path separator, mark this as the end of our // extension. unmatchedSlash = true; end = index + 1; } if (code === 46 /* `.` */) { // If this is our first dot, mark it as the start of our extension. if (startDot < 0) { startDot = index; } else if (preDotState !== 1) { preDotState = 1; } } else if (startDot > -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension. preDotState = -1; } } if ( startDot < 0 || end < 0 || // We saw a non-dot character immediately before the dot. preDotState === 0 || // The (right-most) trimmed path component is exactly `..`. (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) ) { return '' } return path.slice(startDot, end) } function join() { var index = -1; var joined; while (++index < arguments.length) { assertPath(arguments[index]); if (arguments[index]) { joined = joined === undefined ? arguments[index] : joined + '/' + arguments[index]; } } return joined === undefined ? '.' : normalize(joined) } // Note: `normalize` is not exposed as `path.normalize`, so some code is // manually removed from it. function normalize(path) { var absolute; var value; assertPath(path); absolute = path.charCodeAt(0) === 47; /* `/` */ // Normalize the path according to POSIX rules. value = normalizeString(path, !absolute); if (!value.length && !absolute) { value = '.'; } if (value.length && path.charCodeAt(path.length - 1) === 47 /* / */) { value += '/'; } return absolute ? '/' + value : value } // Resolve `.` and `..` elements in a path with directory names. function normalizeString(path, allowAboveRoot) { var result = ''; var lastSegmentLength = 0; var lastSlash = -1; var dots = 0; var index = -1; var code; var lastSlashIndex; while (++index <= path.length) { if (index < path.length) { code = path.charCodeAt(index); } else if (code === 47 /* `/` */) { break } else { code = 47; /* `/` */ } if (code === 47 /* `/` */) { if (lastSlash === index - 1 || dots === 1) ; else if (lastSlash !== index - 1 && dots === 2) { if ( result.length < 2 || lastSegmentLength !== 2 || result.charCodeAt(result.length - 1) !== 46 /* `.` */ || result.charCodeAt(result.length - 2) !== 46 /* `.` */ ) { if (result.length > 2) { lastSlashIndex = result.lastIndexOf('/'); /* istanbul ignore else - No clue how to cover it. */ if (lastSlashIndex !== result.length - 1) { if (lastSlashIndex < 0) { result = ''; lastSegmentLength = 0; } else { result = result.slice(0, lastSlashIndex); lastSegmentLength = result.length - 1 - result.lastIndexOf('/'); } lastSlash = index; dots = 0; continue } } else if (result.length) { result = ''; lastSegmentLength = 0; lastSlash = index; dots = 0; continue } } if (allowAboveRoot) { result = result.length ? result + '/..' : '..'; lastSegmentLength = 2; } } else { if (result.length) { result += '/' + path.slice(lastSlash + 1, index); } else { result = path.slice(lastSlash + 1, index); } lastSegmentLength = index - lastSlash - 1; } lastSlash = index; dots = 0; } else if (code === 46 /* `.` */ && dots > -1) { dots++; } else { dots = -1; } } return result } function assertPath(path) { if (typeof path !== 'string') { throw new TypeError( 'Path must be a string. Received ' + JSON.stringify(path) ) } } var minpath_browser = { basename: basename_1, dirname: dirname_1, extname: extname_1, join: join_1, sep: sep }; // Somewhat based on: // <https://github.com/defunctzombie/node-process/blob/master/browser.js>. // But I don’t think one tiny line of code can be copyrighted. 😅 var cwd_1 = cwd; function cwd() { return '/' } var minproc_browser = { cwd: cwd_1 }; var core = VFile; var own$1 = {}.hasOwnProperty; // Order of setting (least specific to most), we need this because otherwise // `{stem: 'a', path: '~/b.js'}` would throw, as a path is needed before a // stem can be set. var order = ['history', 'path', 'basename', 'stem', 'extname', 'dirname']; VFile.prototype.toString = toString; // Access full path (`~/index.min.js`). Object.defineProperty(VFile.prototype, 'path', {get: getPath, set: setPath}); // Access parent path (`~`). Object.defineProperty(VFile.prototype, 'dirname', { get: getDirname, set: setDirname }); // Access basename (`index.min.js`). Object.defineProperty(VFile.prototype, 'basename', { get: getBasename, set: setBasename }); // Access extname (`.js`). Object.defineProperty(VFile.prototype, 'extname', { get: getExtname, set: setExtname }); // Access stem (`index.min`). Object.defineProperty(VFile.prototype, 'stem', {get: getStem, set: setStem}); // Construct a new file. function VFile(options) { var prop; var index; if (!options) { options = {}; } else if (typeof options === 'string' || isBuffer(options)) { options = {contents: options}; } else if ('message' in options && 'messages' in options) { return options } if (!(this instanceof VFile)) { return new VFile(options) } this.data = {}; this.messages = []; this.history = []; this.cwd = minproc_browser.cwd(); // Set path related properties in the correct order. index = -1; while (++index < order.length) { prop = order[index]; if (own$1.call(options, prop)) { this[prop] = options[prop]; } } // Set non-path related properties. for (prop in options) { if (order.indexOf(prop) < 0) { this[prop] = options[prop]; } } } function getPath() { return this.history[this.history.length - 1] } function setPath(path) { assertNonEmpty(path, 'path'); if (this.path !== path) { this.history.push(path); } } function getDirname() { return typeof this.path === 'string' ? minpath_browser.dirname(this.path) : undefined } function setDirname(dirname) { assertPath$1(this.path, 'dirname'); this.path = minpath_browser.join(dirname || '', this.basename); } function getBasename() { return typeof this.path === 'string' ? minpath_browser.basename(this.path) : undefined } function setBasename(basename) { assertNonEmpty(basename, 'basename'); assertPart(basename, 'basename'); this.path = minpath_browser.join(this.dirname || '', basename); } function getExtname() { return typeof this.path === 'string' ? minpath_browser.extname(this.path) : undefined } function setExtname(extname) { assertPart(extname, 'extname'); assertPath$1(this.path, 'extname'); if (extname) { if (extname.charCodeAt(0) !== 46 /* `.` */) { throw new Error('`extname` must start with `.`') } if (extname.indexOf('.', 1) > -1) { throw new Error('`extname` cannot contain multiple dots') } } this.path = minpath_browser.join(this.dirname, this.stem + (extname || '')); } function getStem() { return typeof this.path === 'string' ? minpath_browser.basename(this.path, this.extname) : undefined } function setStem(stem) { assertNonEmpty(stem, 'stem'); assertPart(stem, 'stem'); this.path = minpath_browser.join(this.dirname || '', stem + (this.extname || '')); } // Get the value of the file. function toString(encoding) { return (this.contents || '').toString(encoding) } // Assert that `part` is not a path (i.e., does not contain `p.sep`). function assertPart(part, name) { if (part && part.indexOf(minpath_browser.sep) > -1) { throw new Error( '`' + name + '` cannot be a path: did not expect `' + minpath_browser.sep + '`' ) } } // Assert that `part` is not empty. function assertNonEmpty(part, name) { if (!part) { throw new Error('`' + name + '` cannot be empty') } } // Assert `path` exists. function assertPath$1(path, name) { if (!path) { throw new Error('Setting `' + name + '` requires `path` to be set too') } } var lib = core; core.prototype.message = message; core.prototype.info = info; core.prototype.fail = fail; // Create a message with `reason` at `position`. // When an error is passed in as `reason`, copies the stack. function message(reason, position, origin) { var message = new vfileMessage(reason, position, origin); if (this.path) { message.name = this.path + ':' + message.name; message.file = this.path; } message.fatal = false; this.messages.push(message); return message } // Fail: creates a vmessage, associates it with the file, and throws it. function fail() { var message = this.message.apply(this, arguments); message.fatal = true; throw message } // Info: creates a vmessage, associates it with the file, and marks the fatality // as null. function info() { var message = this.message.apply(this, arguments); message.fatal = null; return message } var vfile = lib; // Expose a frozen processor. var unified_1 = unified().freeze(); var slice$2 = [].slice; var own$2 = {}.hasOwnProperty; // Process pipeline. var pipeline = trough_1() .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) ; else if (typeof result === 'string' || isBuffer(result)) { file.contents = result; } else { file.result = result; } } // Function to create the first processor. function unified() { var attachers = []; var transformers = trough_1(); 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: it’s 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$2.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) ; 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) ; 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 (isPlainObj(entry[1]) && isPlainObj(value)) { value = extend(entry[1], value); } entry[1] = value; } else { attachers.push(slice$2.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_1(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_1(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' ) } } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var nearley = createCommonjsModule(function (module) { (function(root, factory) { if ( module.exports) { module.exports = factory(); } else { root.nearley = factory(); } }(commonjsGlobal, function() { function Rule(name, symbols, postprocess) { this.id = ++Rule.highestId; this.name = name; this.symbols = symbols; // a list of literal | regex class | nonterminal this.postprocess = postprocess; return this; } Rule.highestId = 0; Rule.prototype.toString = function(withCursorAt) { var symbolSequence = (typeof withCursorAt === "undefined") ? this.symbols.map(getSymbolShortDisplay).join(' ') : ( this.symbols.slice(0, withCursorAt).map(getSymbolShortDisplay).join(' ') + " ● " + this.symbols.slice(withCursorAt).map(getSymbolShortDisplay).join(' ') ); return this.name + " → " + symbolSequence; }; // a State is a rule at a position from a given starting point in the input stream (reference) function State(rule, dot, reference, wantedBy) { this.rule = rule; this.dot = dot; this.reference = reference; this.data = []; this.wantedBy = wantedBy; this.isComplete = this.dot === rule.symbols.length; } State.prototype.toString = function() { return "{" + this.rule.toString(this.dot) + "}, from: " + (this.reference || 0); }; State.prototype.nextState = function(child) { var state = new State(this.rule, this.dot + 1, this.reference, this.wantedBy); state.left = this; state.right = child; if (state.isComplete) { state.data = state.build(); // Having right set here will prevent the right state and its children // form being garbage collected state.right = undefined; } return state; }; State.prototype.build = function() { var children = []; var node = this; do { children.push(node.right.data); node = node.left; } while (node.left); children.reverse(); return children; }; State.prototype.finish = function() { if (this.rule.postprocess) { this.data = this.rule.postprocess(this.data, this.reference, Parser.fail); } }; function Column(grammar, index) { this.grammar = grammar; this.index = index; this.states = []; this.wants = {}; // states indexed by the non-terminal they expect this.scannable = []; // list of states that expect a token this.completed = {}; // states that are nullable } Column.prototype.process = function(nextColumn) { var states = this.states; var wants = this.wants; var completed = this.completed; for (var w = 0; w < states.length; w++) { // nb. we push() during iteration var state = states[w]; if (state.isComplete) { state.finish(); if (state.data !== Parser.fail) { // complete var wantedBy = state.wantedBy; for (var i = wantedBy.length; i--; ) { // this line is hot var left = wantedBy[i]; this.complete(left, state); } // special-case nullables if (state.reference === this.index) { // make sure future predictors of this rule get completed. var exp = state.rule.name; (this.completed[exp] = this.completed[exp] || []).push(state); } } } else { // queue scannable states var exp = state.rule.symbols[state.dot]; if (typeof exp !== 'string') { this.scannable.push(state); continue; } // predict if (wants[exp]) { wants[exp].push(state); if (completed.hasOwnProperty(exp)) { var nulls = completed[exp]; for (var i = 0; i < nulls.length; i++) { var right = nulls[i]; this.complete(state, right); } } } else { wants[exp] = [state]; this.predict(exp); } } } }; Column.prototype.predict = function(exp) { var rules = this.grammar.byName[exp] || []; for (var i = 0; i < rules.length; i++) { var r = rules[i]; var wantedBy = this.wants[exp]; var s = new State(r, 0, this.index, wantedBy); this.states.push(s); } }; Column.prototype.complete = function(left, right) { var copy = left.nextState(right); this.states.push(copy); }; function Grammar(rules, start) { this.rules = rules; this.start = start || this.rules[0].name; var byName = this.byName = {}; this.rules.forEach(function(rule) { if (!byName.hasOwnProperty(rule.name)) { byName[rule.name] = []; } byName[rule.name].push(rule); }); } // So we can allow passing (rules, start) directly to Parser for backwards compatibility Grammar.fromCompiled = function(rules, start) { var lexer = rules.Lexer; if (rules.ParserStart) { start = rules.ParserStart; rules = rules.ParserRules; } var rules = rules.map(function (r) { return (new Rule(r.name, r.symbols, r.postprocess)); }); var g = new Grammar(rules, start); g.lexer = lexer; // nb. storing lexer on Grammar is iffy, but unavoidable return g; }; function StreamLexer() { this.reset(""); } StreamLexer.prototype.reset = function(data, state) { this.buffer = data; this.index = 0; this.line = state ? state.line : 1; this.lastLineBreak = state ? -state.col : 0; }; StreamLexer.prototype.next = function() { if (this.index < this.buffer.length) { var ch = this.buffer[this.index++]; if (ch === '\n') { this.line += 1; this.lastLineBreak = this.index; } return {value: ch}; } }; StreamLexer.prototype.save = function() { return { line: this.line, col: this.index - this.lastLineBreak, } }; StreamLexer.prototype.formatError = function(token, message) { // nb. this gets called after consuming the offending token, // so the culprit is index-1 var buffer = this.buffer; if (typeof buffer === 'string') { var lines = buffer .split("\n") .slice( Math.max(0, this.line - 5), this.line ); var nextLineBreak = buffer.indexOf('\n', this.index); if (nextLineBreak === -1) nextLineBreak = buffer.length; var col = this.index - this.lastLineBreak; var lastLineDigits = String(this.line).length; message += " at line " + this.line + " col " + col + ":\n\n"; message += lines .map(function(line, i) { return pad(this.line - lines.length + i + 1, lastLineDigits) + " " + line; }, this) .join("\n"); message += "\n" + pad("", lastLineDigits + col) + "^\n"; return message; } else { return message + " at index " + (this.index - 1); } function pad(n, length) { var s = String(n); return Array(length - s.length + 1).join(" ") + s; } }; function Parser(rules, start, options) { if (rules instanceof Grammar) { var grammar = rules; var options = start; } else { var grammar = Grammar.fromCompiled(rules, start); } this.grammar = grammar; // Read options this.options = { keepHistory: false, lexer: grammar.lexer || new StreamLexer, }; for (var key in (options || {})) { this.options[key] = options[key]; } // Setup lexer this.lexer = this.options.lexer; this.lexerState = undefined; // Setup a table var column = new Column(grammar, 0); var table = this.table = [column]; // I could be expecting anything. column.wants[grammar.start] = []; column.predict(grammar.start); // TODO what if start rule is nullable? column.process(); this.current = 0; // token index } // create a reserved token for indicating a parse fail Parser.fail = {}; Parser.prototype.feed = function(chunk) { var lexer = this.lexer; lexer.reset(chunk, this.lexerState); var token; while (true) { try { token = lexer.next(); if (!token) { break; } } catch (e) { // Create the next column so that the error reporter // can display the correctly predicted states. var nextColumn = new Column(this.grammar, this.current + 1); this.table.push(nextColumn); var err = new Error(this.reportLexerError(e)); err.offset = this.current; err.token = e.token; throw err; } // We add new states to table[current+1] var column = this.table[this.current]; // GC unused states if (!this.options.keepHistory) { delete this.table[this.current - 1]; } var n = this.current + 1; var nextColumn = new Column(this.grammar, n); this.table.push(nextColumn); // Advance all tokens that expect the symbol var literal = token.text !== undefined ? token.text : token.value; var value = lexer.constructor === StreamLexer ? token.value : token; var scannable = column.scannable; for (var w = scannable.length; w--; ) { var state = scannable[w]; var expect = state.rule.symbols[state.dot];