• Jump To … +
    browser.coffee cake.coffee coffee-script.coffee command.coffee grammar.coffee helpers.coffee index.coffee lexer.coffee nodes.coffee optparse.coffee repl.coffee rewriter.coffee scope.litcoffee sourcemap.litcoffee
  • helpers.coffee

  • ¶

    This file contains the common helper functions that we'd like to share among the Lexer, Rewriter, and the Nodes. Merge objects, flatten arrays, count characters, that sort of thing.

  • ¶

    Peek at the beginning of a given string to see if it matches a sequence.

    exports.starts = (string, literal, start) ->
      literal is string.substr start, literal.length
  • ¶

    Peek at the end of a given string to see if it matches a sequence.

    exports.ends = (string, literal, back) ->
      len = literal.length
      literal is string.substr string.length - len - (back or 0), len
  • ¶

    Repeat a string n times.

    exports.repeat = repeat = (str, n) ->
  • ¶

    Use clever algorithm to have O(log(n)) string concatenation operations.

      res = ''
      while n > 0
        res += str if n & 1
        n >>>= 1
        str += str
      res
  • ¶

    Trim out all falsy values from an array.

    exports.compact = (array) ->
      item for item in array when item
  • ¶

    Count the number of occurrences of a string in a string.

    exports.count = (string, substr) ->
      num = pos = 0
      return 1/0 unless substr.length
      num++ while pos = 1 + string.indexOf substr, pos
      num
  • ¶

    Merge objects, returning a fresh copy with attributes from both sides. Used every time Base#compile is called, to allow properties in the options hash to propagate down the tree without polluting other branches.

    exports.merge = (options, overrides) ->
      extend (extend {}, options), overrides
  • ¶

    Extend a source object with the properties of another object (shallow copy).

    extend = exports.extend = (object, properties) ->
      for key, val of properties
        object[key] = val
      object
  • ¶

    Return a flattened version of an array. Handy for getting a list of children from the nodes.

    exports.flatten = flatten = (array) ->
      flattened = []
      for element in array
        if element instanceof Array
          flattened = flattened.concat flatten element
        else
          flattened.push element
      flattened
  • ¶

    Delete a key from an object, returning the value. Useful when a node is looking for a particular method in an options hash.

    exports.del = (obj, key) ->
      val =  obj[key]
      delete obj[key]
      val
  • ¶

    Gets the last item of an array(-like) object.

    exports.last = last = (array, back) -> array[array.length - (back or 0) - 1]
  • ¶

    Typical Array::some

    exports.some = Array::some ? (fn) ->
      return true for e in this when fn e
      false
  • ¶

    Simple function for inverting Literate CoffeeScript code by putting the documentation in comments, producing a string of CoffeeScript code that can be compiled "normally".

    exports.invertLiterate = (code) ->
      maybe_code = true
      lines = for line in code.split('\n')
        if maybe_code and /^([ ]{4}|[ ]{0,3}\t)/.test line
          line
        else if maybe_code = /^\s*$/.test line
          line
        else
          '# ' + line
      lines.join '\n'
  • ¶

    Merge two jison-style location data objects together. If last is not provided, this will simply return first.

    buildLocationData = (first, last) ->
      if not last
        first
      else
        first_line: first.first_line
        first_column: first.first_column
        last_line: last.last_line
        last_column: last.last_column
  • ¶

    This returns a function which takes an object as a parameter, and if that object is an AST node, updates that object's locationData. The object is returned either way.

    exports.addLocationDataFn = (first, last) ->
        (obj) ->
          if ((typeof obj) is 'object') and (!!obj['updateLocationDataIfMissing'])
            obj.updateLocationDataIfMissing buildLocationData(first, last)
    
          return obj
  • ¶

    Convert jison location data to a string. obj can be a token, or a locationData.

    exports.locationDataToString = (obj) ->
        if ("2" of obj) and ("first_line" of obj[2]) then locationData = obj[2]
        else if "first_line" of obj then locationData = obj
    
        if locationData
          "#{locationData.first_line + 1}:#{locationData.first_column + 1}-" +
          "#{locationData.last_line + 1}:#{locationData.last_column + 1}"
        else
          "No location data"
  • ¶

    A .coffee.md compatible version of basename, that returns the file sans-extension.

    exports.baseFileName = (file, stripExt = no, useWinPathSep = no) ->
      pathSep = if useWinPathSep then /\\|\// else /\//
      parts = file.split(pathSep)
      file = parts[parts.length - 1]
      return file unless stripExt
      parts = file.split('.')
      parts.pop()
      parts.pop() if parts[parts.length - 1] is 'coffee' and parts.length > 1
      parts.join('.')
  • ¶

    Determine if a filename represents a CoffeeScript file.

    exports.isCoffee = (file) -> /\.((lit)?coffee|coffee\.md)$/.test file
  • ¶

    Determine if a filename represents a Literate CoffeeScript file.

    exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file
  • ¶

    Throws a SyntaxError with a source file location data attached to it in a property called location.

    exports.throwSyntaxError = (message, location) ->
      location.last_line ?= location.first_line
      location.last_column ?= location.first_column
      error = new SyntaxError message
      error.location = location
      throw error
  • ¶

    Creates a nice error message like, following the "standard" format

    ::: plus the line with the error and a marker showing where the error is.

    exports.prettyErrorMessage = (error, fileName, code, useColors) ->
      return error.stack or "#{error}" unless error.location
    
      {first_line, first_column, last_line, last_column} = error.location
      codeLine = code.split('\n')[first_line]
      start    = first_column
  • ¶

    Show only the first line on multi-line errors.

      end      = if first_line is last_line then last_column + 1 else codeLine.length
      marker   = repeat(' ', start) + repeat('^', end - start)
    
      if useColors
        colorize  = (str) -> "\x1B[1;31m#{str}\x1B[0m"
        codeLine = codeLine[...start] + colorize(codeLine[start...end]) + codeLine[end..]
        marker    = colorize marker
    
      message = """
      #{fileName}:#{first_line + 1}:#{first_column + 1}: error: #{error.message}
      #{codeLine}
      #{marker}
                """
  • ¶

    Uncomment to add stacktrace. message += "\n#{error.stack}"

      message