<commit_before>_ = window?._ ? self?._ ? global?._ ? require 'lodash'  # rely on lodash existing, since it busts CodeCombat to browserify it--TODO
traceur = window?.traceur ? self?.traceur ? global?.traceur ? require 'traceur'  # rely on traceur existing, since it busts CodeCombat to browserify it--TODO

esprima = require 'esprima'  # getting our Esprima Harmony
normalizer = require 'JS_WALA/normalizer/lib/normalizer'
escodegen = require 'escodegen'

defaults = require './defaults'
problems = require './problems'
execution = require './execution'
traversal = require './traversal'
transforms = require './transforms'
protectAPI = require './protectAPI'
protectBuiltins = require './protectBuiltins'
instrumentation = require './instrumentation'
optionsValidator = require './validators/options'
languages = require './languages/languages'

module.exports = class Aether
  @execution: execution
  @addGlobal: protectBuiltins.addGlobal  # Use before instantiating Aether instances
  @replaceBuiltin: protectBuiltins.replaceBuiltin
  @globals: protectBuiltins.addedGlobals

  # Current call depth
  depth: 0

  constructor: (options) ->
    options ?= {}
    validationResults = optionsValidator options
    unless validationResults.valid
      throw new Error "Aether options are invalid: " + JSON.stringify(validationResults.errors, null, 4)

    # Save our original options for recreating this Aether later.
    @originalOptions = _.cloneDeep options  # TODO: slow

    # Merge the given options with the defaults.
    defaultsCopy = _.cloneDeep defaults
    @options = _.merge defaultsCopy, options

    @setLanguage @options.language, @options.languageVersion
    @allGlobals = @options.globals.concat protectBuiltins.builtinNames, Object.keys @language.runtimeGlobals  # After setLanguage, which can add globals.

    ## For mapping API clones and values to each other
    @protectAPIClonesToValues = {}
    @protectAPIValuesToClones = {}

  # Language can be changed after construction. (It will reset Aether's state.)
  setLanguage: (language, languageVersion) ->
    return if @language and @language.id is language and @language.version is languageVersion
    validationResults = optionsValidator language: language, languageVersion: languageVersion
    unless validationResults.valid
      throw new Error "New language is invalid: " + JSON.stringify(validationResults.errors, null, 4)
    @originalOptions.language = @options.language = language
    @originalOptions.languageVersion = @options.languageVersion = languageVersion
    @language = new languages[language] languageVersion
    @languageJS ?= if language is 'javascript' then @language else new languages.javascript 'ES5'
    Aether.addGlobal name, global for name, global of @language.runtimeGlobals
    @reset()
    return language

  # Resets the state of Aether, readying it for a fresh transpile.
  reset: ->
    @problems = errors: [], warnings: [], infos: []
    @style = {}
    @flow = {}
    @metrics = {}
    @pure = null

  # Convert to JSON so we can pass it across web workers and HTTP requests and store it in databases and such.
  serialize: ->
    _.pick @, ['originalOptions', 'raw', 'pure', 'problems', 'flow', 'metrics', 'style']

  # Convert a serialized Aether instance back from JSON.
  @deserialize: (serialized) ->
    aether = new Aether serialized.originalOptions
    aether[prop] = val for prop, val of serialized when prop isnt "originalOptions"
    aether

  # Performs quick heuristics to determine whether the code will run or produce compilation errors.
  # If thorough, it will perform detailed linting and return false if there are any lint errors.
  canTranspile: (rawCode, thorough=false) ->
    return true if not rawCode # blank code should compile, but bypass the other steps
    return false if @language.obviouslyCannotTranspile rawCode
    return true unless thorough
    @lint(rawCode, @).errors.length is 0

  # Determine whether two strings of code are significantly different.
  # If careAboutLineNumbers, we strip trailing comments and whitespace and compare line count.
  # If careAboutLint, we also lint and make sure lint problems are the same.
  hasChangedSignificantly: (a, b, careAboutLineNumbers=false, careAboutLint=false) ->
    return true unless a? and b?
    return false if a is b
    return true if careAboutLineNumbers and @language.hasChangedLineNumbers a, b
    return true if careAboutLint and @hasChangedLintProblems a, b
    # If the simple tests fail, we compare abstract syntax trees for equality.
    result = @language.hasChangedASTs a, b
    if result
      console.log 'Aether hasChangedSignificantly', result
    result

  # Determine whether two strings of code produce different lint problems.
  hasChangedLintProblems: (a, b) ->
    aLintProblems = [p.id, p.message, p.hint] for p in @getAllProblems @lint a
    bLintProblems = [p.id, p.message, p.hint] for p in @getAllProblems @lint b
    return not _.isEqual aLintProblems, bLintProblems
<commit_msg>Removing extra debug log<commit_after>_ = window?._ ? self?._ ? global?._ ? require 'lodash'  # rely on lodash existing, since it busts CodeCombat to browserify it--TODO
traceur = window?.traceur ? self?.traceur ? global?.traceur ? require 'traceur'  # rely on traceur existing, since it busts CodeCombat to browserify it--TODO

esprima = require 'esprima'  # getting our Esprima Harmony
normalizer = require 'JS_WALA/normalizer/lib/normalizer'
escodegen = require 'escodegen'

defaults = require './defaults'
problems = require './problems'
execution = require './execution'
traversal = require './traversal'
transforms = require './transforms'
protectAPI = require './protectAPI'
protectBuiltins = require './protectBuiltins'
instrumentation = require './instrumentation'
optionsValidator = require './validators/options'
languages = require './languages/languages'

module.exports = class Aether
  @execution: execution
  @addGlobal: protectBuiltins.addGlobal  # Use before instantiating Aether instances
  @replaceBuiltin: protectBuiltins.replaceBuiltin
  @globals: protectBuiltins.addedGlobals

  # Current call depth
  depth: 0

  constructor: (options) ->
    options ?= {}
    validationResults = optionsValidator options
    unless validationResults.valid
      throw new Error "Aether options are invalid: " + JSON.stringify(validationResults.errors, null, 4)

    # Save our original options for recreating this Aether later.
    @originalOptions = _.cloneDeep options  # TODO: slow

    # Merge the given options with the defaults.
    defaultsCopy = _.cloneDeep defaults
    @options = _.merge defaultsCopy, options

    @setLanguage @options.language, @options.languageVersion
    @allGlobals = @options.globals.concat protectBuiltins.builtinNames, Object.keys @language.runtimeGlobals  # After setLanguage, which can add globals.

    ## For mapping API clones and values to each other
    @protectAPIClonesToValues = {}
    @protectAPIValuesToClones = {}

  # Language can be changed after construction. (It will reset Aether's state.)
  setLanguage: (language, languageVersion) ->
    return if @language and @language.id is language and @language.version is languageVersion
    validationResults = optionsValidator language: language, languageVersion: languageVersion
    unless validationResults.valid
      throw new Error "New language is invalid: " + JSON.stringify(validationResults.errors, null, 4)
    @originalOptions.language = @options.language = language
    @originalOptions.languageVersion = @options.languageVersion = languageVersion
    @language = new languages[language] languageVersion
    @languageJS ?= if language is 'javascript' then @language else new languages.javascript 'ES5'
    Aether.addGlobal name, global for name, global of @language.runtimeGlobals
    @reset()
    return language

  # Resets the state of Aether, readying it for a fresh transpile.
  reset: ->
    @problems = errors: [], warnings: [], infos: []
    @style = {}
    @flow = {}
    @metrics = {}
    @pure = null

  # Convert to JSON so we can pass it across web workers and HTTP requests and store it in databases and such.
  serialize: ->
    _.pick @, ['originalOptions', 'raw', 'pure', 'problems', 'flow', 'metrics', 'style']

  # Convert a serialized Aether instance back from JSON.
  @deserialize: (serialized) ->
    aether = new Aether serialized.originalOptions
    aether[prop] = val for prop, val of serialized when prop isnt "originalOptions"
    aether

  # Performs quick heuristics to determine whether the code will run or produce compilation errors.
  # If thorough, it will perform detailed linting and return false if there are any lint errors.
  canTranspile: (rawCode, thorough=false) ->
    return true if not rawCode # blank code should compile, but bypass the other steps
    return false if @language.obviouslyCannotTranspile rawCode
    return true unless thorough
    @lint(rawCode, @).errors.length is 0

  # Determine whether two strings of code are significantly different.
  # If careAboutLineNumbers, we strip trailing comments and whitespace and compare line count.
  # If careAboutLint, we also lint and make sure lint problems are the same.
  hasChangedSignificantly: (a, b, careAboutLineNumbers=false, careAboutLint=false) ->
    return true unless a? and b?
    return false if a is b
    return true if careAboutLineNumbers and @language.hasChangedLineNumbers a, b
    return true if careAboutLint and @hasChangedLintProblems a, b
    # If the simple tests fail, we compare abstract syntax trees for equality.
    @language.hasChangedASTs a, b

  # Determine whether two strings of code produce different lint problems.
  hasChangedLintProblems: (a, b) ->
    aLintProblems = [p.id, p.message, p.hint] for p in @getAllProblems @lint a
    bLintProblems = [p.id, p.message, p.hint] for p in @getAllProblems @lint b
    return not _.isEqual aLintProblems, bLintProblems

{'fraction_non_alphanumeric': 0.08289685737308622, 'fraction_numerical': 0.001007252215954875, 'mean_word_length': 4.128615702479339, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5241257', 'n_tokens_mistral': 2773, 'n_tokens_neox': 2663, 'n_words': 1013}