aMarCruz/jscc

View on GitHub
src/parse-chunks.ts

Summary

Maintainability
A
0 mins
Test Coverage
// typings
import ParseHelper = require('./parse-helper')
import Parser = require('./parser')

/**
 * Handles possible error with a BOM mark in the source by replacing it with
 * an EOL (it allows the parser regex identify the start of the first line).
 *
 * The mark is preserved because, if there are replacements, the edited buffer
 * will be obtained from magicStr, which will not touch the mark, and if there
 * are not, the caller will use the original source.
 *
 * @param source The original source
 */
const withoutBOMmark = (source: string) => {
  return source.charCodeAt(0) === 0xFEFF ? '\n' + source.slice(1) : source
}

/**
 * This routine searches for the start of jscc directives through a buffer.
 * For each match found, calls the parser with the result of the regex and
 * the parser returns the next position from which to continue the search.
 *
 * @param parser jscc parser instance
 * @param source The original source
 * @param helper Functions to flush and remove chuncks
 */
const parseChunks = function _parseChunks (parser: Parser, source: string, helper: ParseHelper) {

  // Get a regex from the jscc parser to match line containing directives.
  // This regex depends on the prefixes in use and its match is handled by
  // the jscc parser, here we only care about the position of the matched line.
  const re = parser.getRegex()

  let match = re.exec(withoutBOMmark(source))

  // With `re`, there's no way for a line other than a directive to be
  // matched, so we can set a flag here to avoid a non-necessary sourcemap.
  const changes = !!match

  while (match) {

    // The parser could change the jscc varnames, so it's necessary
    // to replace any pending chunks before parsing the line.
    helper.flushPrev(match.index)

    // Parse the line and update buffers and searching position.
    // `parser.parse` returns the new output state.
    re.lastIndex = helper.flushLine(
      match.index,
      re.lastIndex,
      parser.parse(match)
    )

    // With lastIndex already updated, search the next directive.
    match = re.exec(source)
  }

  // This will throw if the buffer has unbalanced blocks
  parser.close()

  // This final flush is necessary because the source can have replacements
  // even if it does not contain directives.
  return helper.flush() || changes
}

export = parseChunks