{Lexer}       = require './lexer'
{parser}      = require './parser'
helpers       = require './helpers'
SourceMap     = require './sourcemap'CoffeeScriptは、Node.js/V8ベースのコマンドラインコンパイラとしてサーバー上で使用することも、ブラウザで直接CoffeeScriptを実行することもできます。このモジュールには、CoffeeScriptソースをトークン化、解析、およびJavaScriptにコンパイルするための主要なエントリ関数が含まれています。
{Lexer}       = require './lexer'
{parser}      = require './parser'
helpers       = require './helpers'
SourceMap     = require './sourcemap'このファイルはlib/coffeescriptから評価されるため、このファイルの2つ上のレベルにあるpackage.jsonをrequireします。
packageJson   = require '../../package.json'現在のCoffeeScriptのバージョン番号。
exports.VERSION = packageJson.version
exports.FILE_EXTENSIONS = FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']テスト用のヘルパーを公開します。
exports.helpers = helpers
{getSourceMap, registerCompiled} = SourceMapこれは、外部モジュールがソースマップのキャッシュを実装できるようにするために公開されています。これは、キャッシュされたソースマップを持つファイルのスタックトレースを調整するためにpatchStackTraceが呼び出された場合にのみ使用されます。
exports.registerCompiled = registerCompilednodejsとブラウザの両方でbtoaを許可する関数。
base64encode = (src) -> switch
  when typeof Buffer is 'function'
    Buffer.from(src).toString('base64')
  when typeof btoa is 'function'<script>ブロックの内容はUTF-16でエンコードされているため、ブロック内で拡張文字が使用されている場合、btoaはUTF-8で最大になるため失敗します。詳細とここで実装されている解決策については、https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problemを参照してください。
    btoa encodeURIComponent(src).replace /%([0-9A-F]{2})/g, (match, p1) ->
      String.fromCharCode '0x' + p1
  else
    throw new Error('Unable to base64 encode inline sourcemap.')字句解析器/パーサー/コンパイラーによってスローされたSyntaxErrorにソースファイル情報を追加するための関数ラッパー。
withPrettyErrors = (fn) ->
  (code, options = {}) ->
    try
      fn.call @, code, options
    catch err
      throw err if typeof code isnt 'string' # Support `CoffeeScript.nodes(tokens)`.
      throw helpers.updateSyntaxError err, code, options.filenameCoffee/Jisonコンパイラーを使用して、CoffeeScriptコードをJavaScriptにコンパイルします。
options.sourceMapが指定されている場合は、options.filenameも指定する必要があります。SourceMap#generateに渡すことができるすべてのオプションもここに渡すことができます。
これは、options.sourceMapが渡されない限り、javascript文字列を返します。渡された場合は、{js, v3SourceMap, sourceMap}オブジェクトを返します。ここで、sourceMapは、プログラムによるルックアップに便利なsourcemap.coffee#SourceMapオブジェクトです。
exports.compile = compile = withPrettyErrors (code, options = {}) ->渡されたoptionsオブジェクトをミューテートしないように、optionsを複製します。
  options = Object.assign {}, options
  generateSourceMap = options.sourceMap or options.inlineMap or not options.filename?
  filename = options.filename or helpers.anonymousFileName()
  checkShebangLine filename, code
  map = new SourceMap if generateSourceMap
  tokens = lexer.tokenize code, options生成された変数が同じ名前にならないように、参照された変数のリストを渡します。
  options.referencedVars = (
    token[1] for token in tokens when token[0] is 'IDENTIFIER'
  )インポートまたはエクスポートを確認します。見つかった場合は、強制的にベアモードにします。
  unless options.bare? and options.bare is yes
    for token in tokens
      if token[0] in ['IMPORT', 'EXPORT']
        options.bare = yes
        break
  nodes = parser.parse tokens要求されたのがノードのPOJO表現、例えば抽象構文木(AST)のみである場合は、ここで停止してそれを返すことができます(lexerのclean関数によって元のソースからずれている可能性がある、ルート/File»Programノードの位置データを修正した後)。
  if options.ast
    nodes.allCommentTokens = helpers.extractAllCommentTokens tokens
    sourceCodeNumberOfLines = (code.match(/\r?\n/g) or '').length + 1
    sourceCodeLastLine = /.*$/.exec(code)[0] # `.*` matches all but line break characters.
    ast = nodes.ast options
    range = [0, code.length]
    ast.start = ast.program.start = range[0]
    ast.end = ast.program.end = range[1]
    ast.range = ast.program.range = range
    ast.loc.start = ast.program.loc.start = {line: 1, column: 0}
    ast.loc.end.line = ast.program.loc.end.line = sourceCodeNumberOfLines
    ast.loc.end.column = ast.program.loc.end.column = sourceCodeLastLine.length
    ast.tokens = tokens
    return ast
  fragments = nodes.compileToFragments options
  currentLine = 0
  currentLine += 1 if options.header
  currentLine += 1 if options.shiftLine
  currentColumn = 0
  js = ""
  for fragment in fragments各フラグメントからのデータでソースマップを更新します。
    if generateSourceMap空、空白、またはセミコロンのみのフラグメントを含めないでください。
      if fragment.locationData and not /^[;\s]*$/.test fragment.code
        map.add(
          [fragment.locationData.first_line, fragment.locationData.first_column]
          [currentLine, currentColumn]
          {noReplace: true})
      newLines = helpers.count fragment.code, "\n"
      currentLine += newLines
      if newLines
        currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1)
      else
        currentColumn += fragment.code.length各フラグメントから最終的なJavaScriptにコードをコピーします。
    js += fragment.code
  if options.header
    header = "Generated by CoffeeScript #{@VERSION}"
    js = "// #{header}\n#{js}"
  if generateSourceMap
    v3SourceMap = map.generate options, code
  if options.transpile
    if typeof options.transpile isnt 'object'これは、Node APIを介して実行され、transpileがオブジェクト以外のものに設定されている場合にのみ発生します。
      throw new Error 'The transpile option must be given an object with options to pass to Babel'このコンパイラがCLIまたはNode APIを介して実行されている場合に渡されたBabelへの参照を取得します。
    transpiler = options.transpile.transpile
    delete options.transpile.transpile
    transpilerOptions = Object.assign {}, options.transpilehttps://github.com/babel/babel/issues/827#issuecomment-77573107を参照してください。Babelは、inputSourceMapでv3ソースマップオブジェクトを入力として受け取り、その出力で更新されたv3ソースマップオブジェクトを返します。
    if v3SourceMap and not transpilerOptions.inputSourceMap?
      transpilerOptions.inputSourceMap = v3SourceMap
    transpilerOutput = transpiler js, transpilerOptions
    js = transpilerOutput.code
    if v3SourceMap and transpilerOutput.map
      v3SourceMap = transpilerOutput.map
  if options.inlineMap
    encoded = base64encode JSON.stringify v3SourceMap
    sourceMapDataURI = "//# sourceMappingURL=data:application/json;base64,#{encoded}"
    sourceURL = "//# sourceURL=#{filename}"
    js = "#{js}\n#{sourceMapDataURI}\n#{sourceURL}"
  registerCompiled filename, code, map
  if options.sourceMap
    {
      js
      sourceMap: map
      v3SourceMap: JSON.stringify v3SourceMap, null, 2
    }
  else
    jsCoffeeScriptコードの文字列をトークン化し、トークンの配列を返します。
exports.tokens = withPrettyErrors (code, options) ->
  lexer.tokenize code, optionsCoffeeScriptコードの文字列または字句解析されたトークンの配列を解析し、ASTを返します。その後、ルートで.compile()を呼び出してコンパイルするか、コールバックを使用して.traverseChildren()を使用することでトラバースできます。
exports.nodes = withPrettyErrors (source, options) ->
  source = lexer.tokenize source, options if typeof source is 'string'
  parser.parse sourceこのファイルは以前これらのメソッドをエクスポートしていました。代わりに警告をスローするスタブを残します。これらのメソッドは、Nodeと非Node環境で別々のエントリポイントを提供するためにindex.coffeeに移動されたため、静的解析ツールが非Node環境用にコンパイルするときにNodeパッケージを詰まらせないようにします。
exports.run = exports.eval = exports.register = ->
  throw new Error 'require index.coffee, not this file'ここで使用するためにLexerをインスタンス化します。
lexer = new Lexer実際のLexerは、トークンの一般的なストリームを生成します。このオブジェクトは、Jison APIと互換性のある、その上に薄いラッパーを提供します。その後、それを「Jisonレクサー」として直接渡すことができます。
parser.lexer =
  yylloc:
    range: []
  options:
    ranges: yes
  lex: ->
    token = parser.tokens[@pos++]
    if token
      [tag, @yytext, @yylloc] = token
      parser.errorToken = token.origin or token
      @yylineno = @yylloc.first_line
    else
      tag = ''
    tag
  setInput: (tokens) ->
    parser.tokens = tokens
    @pos = 0
  upcomingInput: -> ''すべてのASTノードをパーサーに表示します。
parser.yy = require './nodes'Jisonのデフォルトのエラー処理関数をオーバーライドします。
parser.yy.parseError = (message, {token}) ->Jisonのメッセージを無視します。冗長な行番号情報が含まれています。トークンを無視します。エラーが、その起源を参照する可能性のある生成されたトークンによって引き起こされた場合に備えて、レクサーから直接値を取得します。
  {errorToken, tokens} = parser
  [errorTag, errorText, errorLoc] = errorToken
  errorText = switch
    when errorToken is tokens[tokens.length - 1]
      'end of input'
    when errorTag in ['INDENT', 'OUTDENT']
      'indentation'
    when errorTag in ['IDENTIFIER', 'NUMBER', 'INFINITY', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START']
      errorTag.replace(/_START$/, '').toLowerCase()
    else
      helpers.nameWhitespaceCharacter errorText2番目の引数にはlocプロパティがあり、このトークンの位置データが含まれている必要があります。残念ながら、Jisonは古いloc(前のトークンからの)を送信しているように見えるため、レクサーから直接位置情報を取得します。
  helpers.throwSyntaxError "unexpected #{errorText}", errorLoc
exports.patchStackTrace = ->http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.jsに基づいています。sourceMapを処理するように変更されました
  formatSourcePosition = (frame, getSourceMapping) ->
    filename = undefined
    fileLocation = ''
    if frame.isNative()
      fileLocation = "native"
    else
      if frame.isEval()
        filename = frame.getScriptNameOrSourceURL()
        fileLocation = "#{frame.getEvalOrigin()}, " unless filename
      else
        filename = frame.getFileName()
      filename or= "<anonymous>"
      line = frame.getLineNumber()
      column = frame.getColumnNumber()sourceMapの位置を確認します
      source = getSourceMapping filename, line, column
      fileLocation =
        if source
          "#{filename}:#{source[0]}:#{source[1]}"
        else
          "#{filename}:#{line}:#{column}"
    functionName = frame.getFunctionName()
    isConstructor = frame.isConstructor()
    isMethodCall = not (frame.isToplevel() or isConstructor)
    if isMethodCall
      methodName = frame.getMethodName()
      typeName = frame.getTypeName()
      if functionName
        tp = as = ''
        if typeName and functionName.indexOf typeName
          tp = "#{typeName}."
        if methodName and functionName.indexOf(".#{methodName}") isnt functionName.length - methodName.length - 1
          as = " [as #{methodName}]"
        "#{tp}#{functionName}#{as} (#{fileLocation})"
      else
        "#{typeName}.#{methodName or '<anonymous>'} (#{fileLocation})"
    else if isConstructor
      "new #{functionName or '<anonymous>'} (#{fileLocation})"
    else if functionName
      "#{functionName} (#{fileLocation})"
    else
      fileLocation
  getSourceMapping = (filename, line, column) ->
    sourceMap = getSourceMap filename, line, column
    answer = sourceMap.sourceLocation [line - 1, column - 1] if sourceMap?
    if answer? then [answer[0] + 1, answer[1] + 1] else nullmichaelficarra/CoffeeScriptReduxに基づいています。NodeJS / V8は、sourceMapを使用してスタックトレース内の位置を変換することをサポートしていないため、ErrorをモンキーパッチしてCoffeeScriptソースの位置を表示する必要があります。
  Error.prepareStackTrace = (err, stack) ->
    frames = for frame in stackCoffeeScript.runよりも深いスタックフレームを表示しないでください。
      break if frame.getFunction() is exports.run
      "    at #{formatSourcePosition frame, getSourceMapping}"
    "#{err.toString()}\n#{frames.join '\n'}\n"
checkShebangLine = (file, input) ->
  firstLine = input.split(/$/m, 1)[0]
  rest = firstLine?.match(/^#!\s*([^\s]+\s*)(.*)/)
  args = rest?[2]?.split(/\s/).filter (s) -> s isnt ''
  if args?.length > 1
    console.error '''
      The script to be run begins with a shebang line with more than one
      argument. This script will fail on platforms such as Linux which only
      allow a single argument.
    '''
    console.error "The shebang line was: '#{firstLine}' in file '#{file}'"
    console.error "The arguments were: #{JSON.stringify args}"