CoolFace
Apppublic

AK-21/Graphite-Industrial-Intelligence

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
parse.js332 linesDownload Raw Back to lib
1'use strict';2 3const stringify = require('./stringify');4 5/**6 * Constants7 */8 9const {10  MAX_LENGTH,11  CHAR_BACKSLASH, /* \ */12  CHAR_BACKTICK, /* ` */13  CHAR_COMMA, /* , */14  CHAR_DOT, /* . */15  CHAR_LEFT_PARENTHESES, /* ( */16  CHAR_RIGHT_PARENTHESES, /* ) */17  CHAR_LEFT_CURLY_BRACE, /* { */18  CHAR_RIGHT_CURLY_BRACE, /* } */19  CHAR_LEFT_SQUARE_BRACKET, /* [ */20  CHAR_RIGHT_SQUARE_BRACKET, /* ] */21  CHAR_DOUBLE_QUOTE, /* " */22  CHAR_SINGLE_QUOTE, /* ' */23  CHAR_NO_BREAK_SPACE,24  CHAR_ZERO_WIDTH_NOBREAK_SPACE25} = require('./constants');26 27/**28 * parse29 */30 31const parse = (input, options = {}) => {32  if (typeof input !== 'string') {33    throw new TypeError('Expected a string');34  }35 36  const opts = options || {};37  const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;38  if (input.length > max) {39    throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`);40  }41 42  const ast = { type: 'root', input, nodes: [] };43  const stack = [ast];44  let block = ast;45  let prev = ast;46  let brackets = 0;47  const length = input.length;48  let index = 0;49  let depth = 0;50  let value;51 52  /**53   * Helpers54   */55 56  const advance = () => input[index++];57  const push = node => {58    if (node.type === 'text' && prev.type === 'dot') {59      prev.type = 'text';60    }61 62    if (prev && prev.type === 'text' && node.type === 'text') {63      prev.value += node.value;64      return;65    }66 67    block.nodes.push(node);68    node.parent = block;69    node.prev = prev;70    prev = node;71    return node;72  };73 74  push({ type: 'bos' });75 76  while (index < length) {77    block = stack[stack.length - 1];78    value = advance();79 80    /**81     * Invalid chars82     */83 84    if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) {85      continue;86    }87 88    /**89     * Escaped chars90     */91 92    if (value === CHAR_BACKSLASH) {93      push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() });94      continue;95    }96 97    /**98     * Right square bracket (literal): ']'99     */100 101    if (value === CHAR_RIGHT_SQUARE_BRACKET) {102      push({ type: 'text', value: '\\' + value });103      continue;104    }105 106    /**107     * Left square bracket: '['108     */109 110    if (value === CHAR_LEFT_SQUARE_BRACKET) {111      brackets++;112 113      let next;114 115      while (index < length && (next = advance())) {116        value += next;117 118        if (next === CHAR_LEFT_SQUARE_BRACKET) {119          brackets++;120          continue;121        }122 123        if (next === CHAR_BACKSLASH) {124          value += advance();125          continue;126        }127 128        if (next === CHAR_RIGHT_SQUARE_BRACKET) {129          brackets--;130 131          if (brackets === 0) {132            break;133          }134        }135      }136 137      push({ type: 'text', value });138      continue;139    }140 141    /**142     * Parentheses143     */144 145    if (value === CHAR_LEFT_PARENTHESES) {146      block = push({ type: 'paren', nodes: [] });147      stack.push(block);148      push({ type: 'text', value });149      continue;150    }151 152    if (value === CHAR_RIGHT_PARENTHESES) {153      if (block.type !== 'paren') {154        push({ type: 'text', value });155        continue;156      }157      block = stack.pop();158      push({ type: 'text', value });159      block = stack[stack.length - 1];160      continue;161    }162 163    /**164     * Quotes: '|"|`165     */166 167    if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) {168      const open = value;169      let next;170 171      if (options.keepQuotes !== true) {172        value = '';173      }174 175      while (index < length && (next = advance())) {176        if (next === CHAR_BACKSLASH) {177          value += next + advance();178          continue;179        }180 181        if (next === open) {182          if (options.keepQuotes === true) value += next;183          break;184        }185 186        value += next;187      }188 189      push({ type: 'text', value });190      continue;191    }192 193    /**194     * Left curly brace: '{'195     */196 197    if (value === CHAR_LEFT_CURLY_BRACE) {198      depth++;199 200      const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true;201      const brace = {202        type: 'brace',203        open: true,204        close: false,205        dollar,206        depth,207        commas: 0,208        ranges: 0,209        nodes: []210      };211 212      block = push(brace);213      stack.push(block);214      push({ type: 'open', value });215      continue;216    }217 218    /**219     * Right curly brace: '}'220     */221 222    if (value === CHAR_RIGHT_CURLY_BRACE) {223      if (block.type !== 'brace') {224        push({ type: 'text', value });225        continue;226      }227 228      const type = 'close';229      block = stack.pop();230      block.close = true;231 232      push({ type, value });233      depth--;234 235      block = stack[stack.length - 1];236      continue;237    }238 239    /**240     * Comma: ','241     */242 243    if (value === CHAR_COMMA && depth > 0) {244      if (block.ranges > 0) {245        block.ranges = 0;246        const open = block.nodes.shift();247        block.nodes = [open, { type: 'text', value: stringify(block) }];248      }249 250      push({ type: 'comma', value });251      block.commas++;252      continue;253    }254 255    /**256     * Dot: '.'257     */258 259    if (value === CHAR_DOT && depth > 0 && block.commas === 0) {260      const siblings = block.nodes;261 262      if (depth === 0 || siblings.length === 0) {263        push({ type: 'text', value });264        continue;265      }266 267      if (prev.type === 'dot') {268        block.range = [];269        prev.value += value;270        prev.type = 'range';271 272        if (block.nodes.length !== 3 && block.nodes.length !== 5) {273          block.invalid = true;274          block.ranges = 0;275          prev.type = 'text';276          continue;277        }278 279        block.ranges++;280        block.args = [];281        continue;282      }283 284      if (prev.type === 'range') {285        siblings.pop();286 287        const before = siblings[siblings.length - 1];288        before.value += prev.value + value;289        prev = before;290        block.ranges--;291        continue;292      }293 294      push({ type: 'dot', value });295      continue;296    }297 298    /**299     * Text300     */301 302    push({ type: 'text', value });303  }304 305  // Mark imbalanced braces and brackets as invalid306  do {307    block = stack.pop();308 309    if (block.type !== 'root') {310      block.nodes.forEach(node => {311        if (!node.nodes) {312          if (node.type === 'open') node.isOpen = true;313          if (node.type === 'close') node.isClose = true;314          if (!node.nodes) node.type = 'text';315          node.invalid = true;316        }317      });318 319      // get the location of the block on parent.nodes (block's siblings)320      const parent = stack[stack.length - 1];321      const index = parent.nodes.indexOf(block);322      // replace the (invalid) block with it's nodes323      parent.nodes.splice(index, 1, ...block.nodes);324    }325  } while (stack.length > 0);326 327  push({ type: 'eos' });328  return ast;329};330 331module.exports = parse;332