all files / core/lib/ parse.js

100% Statements 51/51
100% Branches 8/8
100% Functions 3/3
100% Lines 47/47
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86        137×   137× 137× 137× 137× 137× 142×   137×         137× 142× 137× 132× 132× 132× 132×             159×     154×     152× 152×   152×           152× 151× 141× 140× 139× 138×     137× 137×   10×     147× 147×       147×     979×      
 
'use strict'
 
let debug = require('debug')('mako:parse')
let Promise = require('bluebird')
let Queue = require('./queue')
let utils = require('./utils')
 
module.exports = Promise.coroutine(function * (build) {
  debug('parse %j', build.entries)
 
  build.timeStart('parse')
  let runner = build.runner
  let parsed = build.parsed = new Set()
  let hooks = runner.hooks
  let tree = runner.tree
  let entries = build.entries.map(file => tree.findFile(file) || tree.addFile(file))
 
  let queue = new Queue({
    concurrency: runner.concurrency,
    factory: Promise.coroutine(parse)
  })
 
  yield runHooks('preparse', [ build ])
  entries.forEach(entry => queue.add(entry))
  yield queue.promise
  yield runHooks('postparse', [ build ])
  debug('parse finished (tree size: %s)', utils.treeSize(tree))
  build.timeStop('parse')
  return build
 
  /**
   * Helper for running analysis on a file.
   *
   * @param {File} file  The target file.
   */
  function * parse (file) {
    if (file.parsing) {
      debug('file %s already being parsed', utils.relative(file.path))
      return
    }
 
    if (parsed.has(file)) {
      debug('file %s already parsed for this build', utils.relative(file.path))
      return
    }
 
    debug('parsing %s', utils.relative(file.path))
    file.parsing = true
 
    try {
      // preread is always run, as it has the opportunity to mark a file as
      // "dirty" so it will be parsed. (such as when an mtime changes)
      // preread also always uses the original file type in case later
      // plugins change the type, allowing entries to be transpiled and
      // still picked up correctly.
      yield runHooks([ 'preread', file.initialType ], [ file, build ])
      if (!file.parsed) {
        yield runHooks([ 'read', file.type ], [ file, build ])
        yield runHooks([ 'postread', file.type ], [ file, build ])
        yield runHooks([ 'predependencies', file.type ], [ file, build ])
        yield runHooks([ 'dependencies', file.type ], [ file, build ])
        // the postdependencies hook runs at the outset of the build phase
 
        debug('parsed %s', utils.relative(file.path))
        file.parsed = true
      } else {
        debug('file %s already parsed by this runner', utils.relative(file.path))
      }
 
      file.parsing = false
      parsed.add(file)
    } catch (err) {
      debug('file %s hit error "%s" during parse', utils.relative(file.path), err.stack)
      file.parsing = false
      throw err
    }
 
    file.dependencies().forEach(dep => queue.add(dep))
  }
 
  function runHooks (key, args) {
    return hooks.run(key, args).then(stats => build.addTimings(stats))
  }
})