mirror of
https://github.com/atom/atom.git
synced 2026-01-23 13:58:08 -05:00
Merge pull request #8433 from atom/mb-bundle-line-ending-selector
Support bundling babel packages and bundle the line-ending-selector package
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
os = require 'os'
|
||||
glob = require 'glob'
|
||||
usesBabel = require './lib/uses-babel'
|
||||
babelOptions = require '../static/babelrc'
|
||||
|
||||
# Add support for obselete APIs of vm module so we can make some third-party
|
||||
# modules work under node v0.11.x.
|
||||
@@ -10,13 +13,11 @@ _ = require 'underscore-plus'
|
||||
|
||||
packageJson = require '../package.json'
|
||||
|
||||
# Shim harmony collections in case grunt was invoked without harmony
|
||||
# collections enabled
|
||||
_.extend(global, require('harmony-collections')) unless global.WeakMap?
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.loadNpmTasks('grunt-babel')
|
||||
grunt.loadNpmTasks('grunt-coffeelint')
|
||||
grunt.loadNpmTasks('grunt-lesslint')
|
||||
grunt.loadNpmTasks('grunt-standard')
|
||||
grunt.loadNpmTasks('grunt-cson')
|
||||
grunt.loadNpmTasks('grunt-contrib-csslint')
|
||||
grunt.loadNpmTasks('grunt-contrib-coffee')
|
||||
@@ -77,6 +78,11 @@ module.exports = (grunt) ->
|
||||
dest: appDir
|
||||
ext: '.js'
|
||||
|
||||
babelConfig =
|
||||
options: babelOptions
|
||||
dist:
|
||||
files: []
|
||||
|
||||
lessConfig =
|
||||
options:
|
||||
paths: [
|
||||
@@ -141,6 +147,13 @@ module.exports = (grunt) ->
|
||||
|
||||
pegConfig.glob_to_multiple.src.push("#{directory}/lib/*.pegjs")
|
||||
|
||||
for jsFile in glob.sync("#{directory}/lib/**/*.js")
|
||||
if usesBabel(jsFile)
|
||||
babelConfig.dist.files.push({
|
||||
src: [jsFile]
|
||||
dest: path.join(appDir, jsFile)
|
||||
})
|
||||
|
||||
grunt.initConfig
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
|
||||
@@ -148,6 +161,8 @@ module.exports = (grunt) ->
|
||||
|
||||
docsOutputDir: 'docs/output'
|
||||
|
||||
babel: babelConfig
|
||||
|
||||
coffee: coffeeConfig
|
||||
|
||||
less: lessConfig
|
||||
@@ -174,6 +189,12 @@ module.exports = (grunt) ->
|
||||
'spec/*.coffee'
|
||||
]
|
||||
|
||||
standard:
|
||||
src: [
|
||||
'src/**/*.js'
|
||||
'static/*.js'
|
||||
]
|
||||
|
||||
csslint:
|
||||
options:
|
||||
'adjoining-classes': false
|
||||
@@ -229,8 +250,8 @@ module.exports = (grunt) ->
|
||||
stderr: false
|
||||
failOnError: false
|
||||
|
||||
grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson', 'peg'])
|
||||
grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
|
||||
grunt.registerTask('compile', ['babel', 'coffee', 'prebuild-less', 'cson', 'peg'])
|
||||
grunt.registerTask('lint', ['standard', 'coffeelint', 'csslint', 'lesslint'])
|
||||
grunt.registerTask('test', ['shell:kill-atom', 'run-specs'])
|
||||
|
||||
ciTasks = ['output-disk-space', 'download-atom-shell', 'download-atom-shell-chromedriver', 'build']
|
||||
|
||||
18
build/lib/uses-babel.coffee
Normal file
18
build/lib/uses-babel.coffee
Normal file
@@ -0,0 +1,18 @@
|
||||
fs = require 'fs'
|
||||
|
||||
BABEL_PREFIXES = [
|
||||
"'use babel'"
|
||||
'"use babel"'
|
||||
'/** @babel */'
|
||||
]
|
||||
|
||||
PREFIX_LENGTH = Math.max(BABEL_PREFIXES.map((prefix) -> prefix.length)...)
|
||||
|
||||
buffer = Buffer(PREFIX_LENGTH)
|
||||
|
||||
module.exports = (filename) ->
|
||||
file = fs.openSync(filename, 'r')
|
||||
fs.readSync(file, buffer, 0, PREFIX_LENGTH)
|
||||
fs.closeSync(file)
|
||||
BABEL_PREFIXES.some (prefix) ->
|
||||
prefix is buffer.toString('utf8', 0, prefix.length)
|
||||
@@ -12,8 +12,9 @@
|
||||
"formidable": "~1.0.14",
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.2.0",
|
||||
"glob": "^5.0.14",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-electron-installer": "^0.37.0",
|
||||
"grunt-babel": "^5.0.1",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe",
|
||||
"grunt-contrib-coffee": "~0.12.0",
|
||||
@@ -21,10 +22,11 @@
|
||||
"grunt-contrib-less": "~0.8.0",
|
||||
"grunt-cson": "0.14.0",
|
||||
"grunt-download-atom-shell": "~0.14.0",
|
||||
"grunt-electron-installer": "^0.37.0",
|
||||
"grunt-lesslint": "0.17.0",
|
||||
"grunt-peg": "~1.1.0",
|
||||
"grunt-shell": "~0.3.1",
|
||||
"harmony-collections": "~0.3.8",
|
||||
"grunt-standard": "^1.0.2",
|
||||
"legal-eagle": "~0.10.0",
|
||||
"minidump": "~0.9",
|
||||
"npm": "2.13.3",
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
"babel-core": "^5.8.21",
|
||||
"bootstrap": "^3.3.4",
|
||||
"clear-cut": "^2.0.1",
|
||||
"coffee-cash": "0.8.0",
|
||||
"coffee-script": "1.8.0",
|
||||
"coffeestack": "^1.1.2",
|
||||
"color": "^0.7.3",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.3.3",
|
||||
@@ -32,7 +30,7 @@
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^2.1",
|
||||
"git-utils": "^3.0.0",
|
||||
"grim": "1.4.1",
|
||||
"grim": "1.4.2",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-tagged": "^1.1.4",
|
||||
"jquery": "^2.1.1",
|
||||
@@ -54,6 +52,7 @@
|
||||
"semver": "^4.3.3",
|
||||
"serializable": "^1",
|
||||
"service-hub": "^0.6.2",
|
||||
"source-map-support": "^0.3.2",
|
||||
"space-pen": "3.8.2",
|
||||
"stacktrace-parser": "0.1.1",
|
||||
"temp": "0.8.1",
|
||||
@@ -101,6 +100,7 @@
|
||||
"image-view": "0.54.0",
|
||||
"incompatible-packages": "0.24.1",
|
||||
"keybinding-resolver": "0.33.0",
|
||||
"line-ending-selector": "0.0.3",
|
||||
"link": "0.30.0",
|
||||
"markdown-preview": "0.150.0",
|
||||
"metrics": "0.51.0",
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
{convertStackTrace} = require 'coffeestack'
|
||||
{View, $, $$} = require '../src/space-pen-extensions'
|
||||
grim = require 'grim'
|
||||
marked = require 'marked'
|
||||
|
||||
sourceMaps = {}
|
||||
formatStackTrace = (spec, message='', stackTrace) ->
|
||||
return stackTrace unless stackTrace
|
||||
|
||||
jasminePattern = /^\s*at\s+.*\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
firstJasmineLinePattern = /^\s*at [/\\].*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/
|
||||
convertedLines = []
|
||||
lines = []
|
||||
for line in stackTrace.split('\n')
|
||||
convertedLines.push(line) unless jasminePattern.test(line)
|
||||
lines.push(line) unless jasminePattern.test(line)
|
||||
break if firstJasmineLinePattern.test(line)
|
||||
|
||||
stackTrace = convertStackTrace(convertedLines.join('\n'), sourceMaps)
|
||||
lines = stackTrace.split('\n')
|
||||
|
||||
# Remove first line of stack when it is the same as the error message
|
||||
errorMatch = lines[0]?.match(/^Error: (.*)/)
|
||||
lines.shift() if message.trim() is errorMatch?[1]?.trim()
|
||||
|
||||
@@ -1,64 +1,19 @@
|
||||
babel = require '../src/babel'
|
||||
crypto = require 'crypto'
|
||||
grim = require 'grim'
|
||||
|
||||
describe "Babel transpiler support", ->
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
describe "::createBabelVersionAndOptionsDigest", ->
|
||||
it "returns a digest for the library version and specified options", ->
|
||||
defaultOptions =
|
||||
blacklist: [
|
||||
'useStrict'
|
||||
]
|
||||
experimental: true
|
||||
optional: [
|
||||
'asyncToGenerator'
|
||||
]
|
||||
reactCompat: true
|
||||
sourceMap: 'inline'
|
||||
version = '3.0.14'
|
||||
shasum = crypto.createHash('sha1')
|
||||
shasum.update('babel-core', 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(version, 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update('{"blacklist": ["useStrict",],"experimental": true,"optional": ["asyncToGenerator",],"reactCompat": true,"sourceMap": "inline",}')
|
||||
expectedDigest = shasum.digest('hex')
|
||||
|
||||
observedDigest = babel.createBabelVersionAndOptionsDigest(version, defaultOptions)
|
||||
expect(observedDigest).toEqual expectedDigest
|
||||
describe 'when a .js file starts with /** @babel */;', ->
|
||||
it "transpiles it using babel", ->
|
||||
transpiled = require('./fixtures/babel/babel-comment.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
|
||||
describe "when a .js file starts with 'use babel';", ->
|
||||
it "transpiles it using babel", ->
|
||||
transpiled = require('./fixtures/babel/babel-single-quotes.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
expect(grim.getDeprecationsLength()).toBe 0
|
||||
|
||||
describe "when a .js file starts with 'use 6to5';", ->
|
||||
it "transpiles it using babel and adds a pragma deprecation", ->
|
||||
expect(grim.getDeprecationsLength()).toBe 0
|
||||
transpiled = require('./fixtures/babel/6to5-single-quotes.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
expect(grim.getDeprecationsLength()).toBe 1
|
||||
|
||||
describe 'when a .js file starts with "use babel";', ->
|
||||
it "transpiles it using babel", ->
|
||||
transpiled = require('./fixtures/babel/babel-double-quotes.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
expect(grim.getDeprecationsLength()).toBe 0
|
||||
|
||||
describe 'when a .js file starts with "use 6to5";', ->
|
||||
it "transpiles it using babel and adds a pragma deprecation", ->
|
||||
expect(grim.getDeprecationsLength()).toBe 0
|
||||
transpiled = require('./fixtures/babel/6to5-double-quotes.js')
|
||||
expect(transpiled(3)).toBe 4
|
||||
expect(grim.getDeprecationsLength()).toBe 1
|
||||
|
||||
describe "when a .js file does not start with 'use 6to6';", ->
|
||||
describe "when a .js file does not start with 'use babel';", ->
|
||||
it "does not transpile it using babel", ->
|
||||
expect(-> require('./fixtures/babel/invalid.js')).toThrow()
|
||||
|
||||
@@ -1,39 +1,71 @@
|
||||
path = require 'path'
|
||||
temp = require('temp').track()
|
||||
Babel = require 'babel-core'
|
||||
CoffeeScript = require 'coffee-script'
|
||||
{TypeScriptSimple} = require 'typescript-simple'
|
||||
CSON = require 'season'
|
||||
CoffeeCache = require 'coffee-cash'
|
||||
|
||||
babel = require '../src/babel'
|
||||
typescript = require '../src/typescript'
|
||||
CSONParser = require 'season/node_modules/cson-parser'
|
||||
CompileCache = require '../src/compile-cache'
|
||||
|
||||
describe "Compile Cache", ->
|
||||
describe ".addPathToCache(filePath)", ->
|
||||
it "adds the path to the correct CSON, CoffeeScript, babel or typescript cache", ->
|
||||
spyOn(CSON, 'readFileSync').andCallThrough()
|
||||
spyOn(CoffeeCache, 'addPathToCache').andCallThrough()
|
||||
spyOn(babel, 'addPathToCache').andCallThrough()
|
||||
spyOn(typescript, 'addPathToCache').andCallThrough()
|
||||
describe 'CompileCache', ->
|
||||
[atomHome, fixtures] = []
|
||||
|
||||
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'cson.cson'))
|
||||
expect(CSON.readFileSync.callCount).toBe 1
|
||||
expect(CoffeeCache.addPathToCache.callCount).toBe 0
|
||||
expect(babel.addPathToCache.callCount).toBe 0
|
||||
expect(typescript.addPathToCache.callCount).toBe 0
|
||||
beforeEach ->
|
||||
fixtures = atom.project.getPaths()[0]
|
||||
atomHome = temp.mkdirSync('fake-atom-home')
|
||||
|
||||
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'coffee.coffee'))
|
||||
expect(CSON.readFileSync.callCount).toBe 1
|
||||
expect(CoffeeCache.addPathToCache.callCount).toBe 1
|
||||
expect(babel.addPathToCache.callCount).toBe 0
|
||||
expect(typescript.addPathToCache.callCount).toBe 0
|
||||
CSON.setCacheDir(null)
|
||||
CompileCache.resetCacheStats()
|
||||
|
||||
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'babel', 'babel-double-quotes.js'))
|
||||
expect(CSON.readFileSync.callCount).toBe 1
|
||||
expect(CoffeeCache.addPathToCache.callCount).toBe 1
|
||||
expect(babel.addPathToCache.callCount).toBe 1
|
||||
expect(typescript.addPathToCache.callCount).toBe 0
|
||||
spyOn(Babel, 'transform').andReturn {code: 'the-babel-code'}
|
||||
spyOn(CoffeeScript, 'compile').andReturn {js: 'the-coffee-code', v3SourceMap: {}}
|
||||
spyOn(TypeScriptSimple::, 'compile').andReturn 'the-typescript-code'
|
||||
spyOn(CSONParser, 'parse').andReturn {the: 'cson-data'}
|
||||
|
||||
CompileCache.addPathToCache(path.join(__dirname, 'fixtures', 'typescript', 'valid.ts'))
|
||||
expect(CSON.readFileSync.callCount).toBe 1
|
||||
expect(CoffeeCache.addPathToCache.callCount).toBe 1
|
||||
expect(babel.addPathToCache.callCount).toBe 1
|
||||
expect(typescript.addPathToCache.callCount).toBe 1
|
||||
afterEach ->
|
||||
CSON.setCacheDir(CompileCache.getCacheDirectory())
|
||||
CompileCache.setAtomHomeDirectory(process.env.ATOM_HOME)
|
||||
|
||||
describe 'addPathToCache(filePath, atomHome)', ->
|
||||
describe 'when the given file is plain javascript', ->
|
||||
it 'does not compile or cache the file', ->
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'sample.js'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.js']).toEqual {hits: 0, misses: 0}
|
||||
|
||||
describe 'when the given file uses babel', ->
|
||||
it 'compiles the file with babel and caches it', ->
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'babel', 'babel-comment.js'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.js']).toEqual {hits: 0, misses: 1}
|
||||
expect(Babel.transform.callCount).toBe 1
|
||||
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'babel', 'babel-comment.js'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.js']).toEqual {hits: 1, misses: 1}
|
||||
expect(Babel.transform.callCount).toBe 1
|
||||
|
||||
describe 'when the given file is coffee-script', ->
|
||||
it 'compiles the file with coffee-script and caches it', ->
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'coffee.coffee'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.coffee']).toEqual {hits: 0, misses: 1}
|
||||
expect(CoffeeScript.compile.callCount).toBe 1
|
||||
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'coffee.coffee'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.coffee']).toEqual {hits: 1, misses: 1}
|
||||
expect(CoffeeScript.compile.callCount).toBe 1
|
||||
|
||||
describe 'when the given file is typescript', ->
|
||||
it 'compiles the file with typescript and caches it', ->
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'typescript', 'valid.ts'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.ts']).toEqual {hits: 0, misses: 1}
|
||||
expect(TypeScriptSimple::compile.callCount).toBe 1
|
||||
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'typescript', 'valid.ts'), atomHome)
|
||||
expect(CompileCache.getCacheStats()['.ts']).toEqual {hits: 1, misses: 1}
|
||||
expect(TypeScriptSimple::compile.callCount).toBe 1
|
||||
|
||||
describe 'when the given file is CSON', ->
|
||||
it 'compiles the file to JSON and caches it', ->
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'cson.cson'), atomHome)
|
||||
expect(CSONParser.parse.callCount).toBe 1
|
||||
|
||||
CompileCache.addPathToCache(path.join(fixtures, 'cson.cson'), atomHome)
|
||||
expect(CSONParser.parse.callCount).toBe 1
|
||||
|
||||
3
spec/fixtures/babel/6to5-single-quotes.js
vendored
3
spec/fixtures/babel/6to5-single-quotes.js
vendored
@@ -1,3 +0,0 @@
|
||||
'use 6to5';
|
||||
|
||||
module.exports = v => v + 1
|
||||
@@ -1,3 +1,3 @@
|
||||
"use 6to5";
|
||||
/** @babel */
|
||||
|
||||
module.exports = v => v + 1
|
||||
@@ -1,25 +1,4 @@
|
||||
typescript = require '../src/typescript'
|
||||
crypto = require 'crypto'
|
||||
|
||||
describe "TypeScript transpiler support", ->
|
||||
describe "::createTypeScriptVersionAndOptionsDigest", ->
|
||||
it "returns a digest for the library version and specified options", ->
|
||||
defaultOptions =
|
||||
target: 1 # ES5
|
||||
module: 'commonjs'
|
||||
sourceMap: true
|
||||
version = '1.4.1'
|
||||
shasum = crypto.createHash('sha1')
|
||||
shasum.update('typescript', 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(version, 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(JSON.stringify(defaultOptions))
|
||||
expectedDigest = shasum.digest('hex')
|
||||
|
||||
observedDigest = typescript.createTypeScriptVersionAndOptionsDigest(version, defaultOptions)
|
||||
expect(observedDigest).toEqual expectedDigest
|
||||
|
||||
describe "when there is a .ts file", ->
|
||||
it "transpiles it using typescript", ->
|
||||
transpiled = require('./fixtures/typescript/valid.ts')
|
||||
|
||||
@@ -9,7 +9,7 @@ _ = require 'underscore-plus'
|
||||
{deprecate, includeDeprecatedAPIs} = require 'grim'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
fs = require 'fs-plus'
|
||||
{convertStackTrace, convertLine} = require 'coffeestack'
|
||||
{mapSourcePosition} = require 'source-map-support'
|
||||
Model = require './model'
|
||||
{$} = require './space-pen-extensions'
|
||||
WindowEventHandler = require './window-event-handler'
|
||||
@@ -196,15 +196,11 @@ class Atom extends Model
|
||||
#
|
||||
# Call after this instance has been assigned to the `atom` global.
|
||||
initialize: ->
|
||||
sourceMapCache = {}
|
||||
|
||||
window.onerror = =>
|
||||
@lastUncaughtError = Array::slice.call(arguments)
|
||||
[message, url, line, column, originalError] = @lastUncaughtError
|
||||
|
||||
convertedLine = convertLine(url, line, column, sourceMapCache)
|
||||
{line, column} = convertedLine if convertedLine?
|
||||
originalError.stack = convertStackTrace(originalError.stack, sourceMapCache) if originalError
|
||||
{line, column} = mapSourcePosition({source: url, line, column})
|
||||
|
||||
eventObject = {message, url, line, column, originalError}
|
||||
|
||||
|
||||
200
src/babel.coffee
200
src/babel.coffee
@@ -1,200 +0,0 @@
|
||||
###
|
||||
Cache for source code transpiled by Babel.
|
||||
|
||||
Inspired by https://github.com/atom/atom/blob/6b963a562f8d495fbebe6abdbafbc7caf705f2c3/src/coffee-cache.coffee.
|
||||
###
|
||||
|
||||
crypto = require 'crypto'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
babel = null # Defer until used
|
||||
Grim = null # Defer until used
|
||||
|
||||
stats =
|
||||
hits: 0
|
||||
misses: 0
|
||||
|
||||
defaultOptions =
|
||||
# Currently, the cache key is a function of:
|
||||
# * The version of Babel used to transpile the .js file.
|
||||
# * The contents of this defaultOptions object.
|
||||
# * The contents of the .js file.
|
||||
# That means that we cannot allow information from an unknown source
|
||||
# to affect the cache key for the output of transpilation, which means
|
||||
# we cannot allow users to override these default options via a .babelrc
|
||||
# file, because the contents of that .babelrc file will not make it into
|
||||
# the cache key. It would be great to support .babelrc files once we
|
||||
# have a way to do so that is safe with respect to caching.
|
||||
breakConfig: true
|
||||
|
||||
# The Chrome dev tools will show the original version of the file
|
||||
# when the source map is inlined.
|
||||
sourceMap: 'inline'
|
||||
|
||||
# Blacklisted features do not get transpiled. Features that are
|
||||
# natively supported in the target environment should be listed
|
||||
# here. Because Atom uses a bleeding edge version of Node/io.js,
|
||||
# I think this can include es6.arrowFunctions, es6.classes, and
|
||||
# possibly others, but I want to be conservative.
|
||||
blacklist: [
|
||||
'es6.forOf'
|
||||
'useStrict'
|
||||
]
|
||||
|
||||
optional: [
|
||||
# Target a version of the regenerator runtime that
|
||||
# supports yield so the transpiled code is cleaner/smaller.
|
||||
'asyncToGenerator'
|
||||
]
|
||||
|
||||
# Includes support for es7 features listed at:
|
||||
# http://babeljs.io/docs/usage/experimental/.
|
||||
stage: 0
|
||||
|
||||
|
||||
###
|
||||
shasum - Hash with an update() method.
|
||||
value - Must be a value that could be returned by JSON.parse().
|
||||
###
|
||||
updateDigestForJsonValue = (shasum, value) ->
|
||||
# Implmentation is similar to that of pretty-printing a JSON object, except:
|
||||
# * Strings are not escaped.
|
||||
# * No effort is made to avoid trailing commas.
|
||||
# These shortcuts should not affect the correctness of this function.
|
||||
type = typeof value
|
||||
if type is 'string'
|
||||
shasum.update('"', 'utf8')
|
||||
shasum.update(value, 'utf8')
|
||||
shasum.update('"', 'utf8')
|
||||
else if type in ['boolean', 'number']
|
||||
shasum.update(value.toString(), 'utf8')
|
||||
else if value is null
|
||||
shasum.update('null', 'utf8')
|
||||
else if Array.isArray value
|
||||
shasum.update('[', 'utf8')
|
||||
for item in value
|
||||
updateDigestForJsonValue(shasum, item)
|
||||
shasum.update(',', 'utf8')
|
||||
shasum.update(']', 'utf8')
|
||||
else
|
||||
# value must be an object: be sure to sort the keys.
|
||||
keys = Object.keys value
|
||||
keys.sort()
|
||||
|
||||
shasum.update('{', 'utf8')
|
||||
for key in keys
|
||||
updateDigestForJsonValue(shasum, key)
|
||||
shasum.update(': ', 'utf8')
|
||||
updateDigestForJsonValue(shasum, value[key])
|
||||
shasum.update(',', 'utf8')
|
||||
shasum.update('}', 'utf8')
|
||||
|
||||
createBabelVersionAndOptionsDigest = (version, options) ->
|
||||
shasum = crypto.createHash('sha1')
|
||||
# Include the version of babel in the hash.
|
||||
shasum.update('babel-core', 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(version, 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
updateDigestForJsonValue(shasum, options)
|
||||
shasum.digest('hex')
|
||||
|
||||
cacheDir = null
|
||||
jsCacheDir = null
|
||||
|
||||
getCachePath = (sourceCode) ->
|
||||
digest = crypto.createHash('sha1').update(sourceCode, 'utf8').digest('hex')
|
||||
|
||||
unless jsCacheDir?
|
||||
to5Version = require('babel-core/package.json').version
|
||||
jsCacheDir = path.join(cacheDir, createBabelVersionAndOptionsDigest(to5Version, defaultOptions))
|
||||
|
||||
path.join(jsCacheDir, "#{digest}.js")
|
||||
|
||||
getCachedJavaScript = (cachePath) ->
|
||||
if fs.isFileSync(cachePath)
|
||||
try
|
||||
cachedJavaScript = fs.readFileSync(cachePath, 'utf8')
|
||||
stats.hits++
|
||||
return cachedJavaScript
|
||||
null
|
||||
|
||||
# Returns the babel options that should be used to transpile filePath.
|
||||
createOptions = (filePath) ->
|
||||
options = filename: filePath
|
||||
for key, value of defaultOptions
|
||||
options[key] = value
|
||||
options
|
||||
|
||||
transpile = (sourceCode, filePath, cachePath) ->
|
||||
options = createOptions(filePath)
|
||||
babel ?= require 'babel-core'
|
||||
js = babel.transform(sourceCode, options).code
|
||||
stats.misses++
|
||||
|
||||
try
|
||||
fs.writeFileSync(cachePath, js)
|
||||
|
||||
js
|
||||
|
||||
# Function that obeys the contract of an entry in the require.extensions map.
|
||||
# Returns the transpiled version of the JavaScript code at filePath, which is
|
||||
# either generated on the fly or pulled from cache.
|
||||
loadFile = (module, filePath) ->
|
||||
sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
if sourceCode.startsWith('"use babel"') or sourceCode.startsWith("'use babel'")
|
||||
# Continue.
|
||||
else if sourceCode.startsWith('"use 6to5"') or sourceCode.startsWith("'use 6to5'")
|
||||
# Create a manual deprecation since the stack is too deep to use Grim
|
||||
# which limits the depth to 3
|
||||
Grim ?= require 'grim'
|
||||
stack = [
|
||||
{
|
||||
fileName: __filename
|
||||
functionName: 'loadFile'
|
||||
location: "#{__filename}:161:5"
|
||||
}
|
||||
{
|
||||
fileName: filePath
|
||||
functionName: '<unknown>'
|
||||
location: "#{filePath}:1:1"
|
||||
}
|
||||
]
|
||||
deprecation =
|
||||
message: "Use the 'use babel' pragma instead of 'use 6to5'"
|
||||
stacks: [stack]
|
||||
Grim.addSerializedDeprecation(deprecation)
|
||||
else
|
||||
return module._compile(sourceCode, filePath)
|
||||
|
||||
cachePath = getCachePath(sourceCode)
|
||||
js = getCachedJavaScript(cachePath) ? transpile(sourceCode, filePath, cachePath)
|
||||
module._compile(js, filePath)
|
||||
|
||||
register = ->
|
||||
Object.defineProperty(require.extensions, '.js', {
|
||||
enumerable: true
|
||||
writable: false
|
||||
value: loadFile
|
||||
})
|
||||
|
||||
setCacheDirectory = (newCacheDir) ->
|
||||
if cacheDir isnt newCacheDir
|
||||
cacheDir = newCacheDir
|
||||
jsCacheDir = null
|
||||
|
||||
module.exports =
|
||||
register: register
|
||||
setCacheDirectory: setCacheDirectory
|
||||
getCacheMisses: -> stats.misses
|
||||
getCacheHits: -> stats.hits
|
||||
|
||||
# Visible for testing.
|
||||
createBabelVersionAndOptionsDigest: createBabelVersionAndOptionsDigest
|
||||
|
||||
addPathToCache: (filePath) ->
|
||||
return if path.extname(filePath) isnt '.js'
|
||||
|
||||
sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
cachePath = getCachePath(sourceCode)
|
||||
transpile(sourceCode, filePath, cachePath)
|
||||
63
src/babel.js
Normal file
63
src/babel.js
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
var crypto = require('crypto')
|
||||
var path = require('path')
|
||||
var defaultOptions = require('../static/babelrc.json')
|
||||
|
||||
var babel = null
|
||||
var babelVersionDirectory = null
|
||||
|
||||
var PREFIXES = [
|
||||
'/** @babel */',
|
||||
'"use babel"',
|
||||
'\'use babel\''
|
||||
]
|
||||
|
||||
var PREFIX_LENGTH = Math.max.apply(Math, PREFIXES.map(function (prefix) {
|
||||
return prefix.length
|
||||
}))
|
||||
|
||||
exports.shouldCompile = function (sourceCode) {
|
||||
var start = sourceCode.substr(0, PREFIX_LENGTH)
|
||||
return PREFIXES.some(function (prefix) {
|
||||
return start.indexOf(prefix) === 0
|
||||
})
|
||||
}
|
||||
|
||||
exports.getCachePath = function (sourceCode) {
|
||||
if (babelVersionDirectory == null) {
|
||||
var babelVersion = require('babel-core/package.json').version
|
||||
babelVersionDirectory = path.join('js', 'babel', createVersionAndOptionsDigest(babelVersion, defaultOptions))
|
||||
}
|
||||
|
||||
return path.join(
|
||||
babelVersionDirectory,
|
||||
crypto
|
||||
.createHash('sha1')
|
||||
.update(sourceCode, 'utf8')
|
||||
.digest('hex') + '.js'
|
||||
)
|
||||
}
|
||||
|
||||
exports.compile = function (sourceCode, filePath) {
|
||||
if (!babel) {
|
||||
babel = require('babel-core')
|
||||
}
|
||||
|
||||
var options = {filename: filePath}
|
||||
for (var key in defaultOptions) {
|
||||
options[key] = defaultOptions[key]
|
||||
}
|
||||
return babel.transform(sourceCode, options).code
|
||||
}
|
||||
|
||||
function createVersionAndOptionsDigest (version, options) {
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update('babel-core', 'utf8')
|
||||
.update('\0', 'utf8')
|
||||
.update(version, 'utf8')
|
||||
.update('\0', 'utf8')
|
||||
.update(JSON.stringify(options), 'utf8')
|
||||
.digest('hex')
|
||||
}
|
||||
@@ -16,7 +16,7 @@ process.on 'uncaughtException', (error={}) ->
|
||||
|
||||
start = ->
|
||||
setupAtomHome()
|
||||
setupCoffeeCache()
|
||||
setupCompileCache()
|
||||
|
||||
if process.platform is 'win32'
|
||||
SquirrelUpdate = require './squirrel-update'
|
||||
@@ -77,14 +77,9 @@ setupAtomHome = ->
|
||||
atomHome = fs.realpathSync(atomHome)
|
||||
process.env.ATOM_HOME = atomHome
|
||||
|
||||
setupCoffeeCache = ->
|
||||
CoffeeCache = require 'coffee-cash'
|
||||
cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache')
|
||||
# Use separate compile cache when sudo'ing as root to avoid permission issues
|
||||
if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER
|
||||
cacheDir = path.join(cacheDir, 'root')
|
||||
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'))
|
||||
CoffeeCache.register()
|
||||
setupCompileCache = ->
|
||||
compileCache = require('../compile-cache')
|
||||
compileCache.setAtomHomeDirectory(process.env.ATOM_HOME)
|
||||
|
||||
parseCommandLine = ->
|
||||
version = app.getVersion()
|
||||
|
||||
44
src/coffee-script.js
Normal file
44
src/coffee-script.js
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict'
|
||||
|
||||
var crypto = require('crypto')
|
||||
var path = require('path')
|
||||
var CoffeeScript = null
|
||||
|
||||
exports.shouldCompile = function () {
|
||||
return true
|
||||
}
|
||||
|
||||
exports.getCachePath = function (sourceCode) {
|
||||
return path.join(
|
||||
'coffee',
|
||||
crypto
|
||||
.createHash('sha1')
|
||||
.update(sourceCode, 'utf8')
|
||||
.digest('hex') + '.js'
|
||||
)
|
||||
}
|
||||
|
||||
exports.compile = function (sourceCode, filePath) {
|
||||
if (!CoffeeScript) {
|
||||
var previousPrepareStackTrace = Error.prepareStackTrace
|
||||
CoffeeScript = require('coffee-script')
|
||||
|
||||
// When it loads, coffee-script reassigns Error.prepareStackTrace. We have
|
||||
// already reassigned it via the 'source-map-support' module, so we need
|
||||
// to set it back.
|
||||
Error.prepareStackTrace = previousPrepareStackTrace
|
||||
}
|
||||
|
||||
var output = CoffeeScript.compile(sourceCode, {
|
||||
filename: filePath,
|
||||
sourceFiles: [filePath],
|
||||
sourceMap: true
|
||||
})
|
||||
|
||||
var js = output.js
|
||||
js += '\n'
|
||||
js += '//# sourceMappingURL=data:application/json;base64,'
|
||||
js += new Buffer(output.v3SourceMap).toString('base64')
|
||||
js += '\n'
|
||||
return js
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
path = require 'path'
|
||||
CSON = require 'season'
|
||||
CoffeeCache = require 'coffee-cash'
|
||||
babel = require './babel'
|
||||
typescript = require './typescript'
|
||||
|
||||
# This file is required directly by apm so that files can be cached during
|
||||
# package install so that the first package load in Atom doesn't have to
|
||||
# compile anything.
|
||||
exports.addPathToCache = (filePath, atomHome) ->
|
||||
atomHome ?= process.env.ATOM_HOME
|
||||
cacheDir = path.join(atomHome, 'compile-cache')
|
||||
# Use separate compile cache when sudo'ing as root to avoid permission issues
|
||||
if process.env.USER is 'root' and process.env.SUDO_USER and process.env.SUDO_USER isnt process.env.USER
|
||||
cacheDir = path.join(cacheDir, 'root')
|
||||
|
||||
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'))
|
||||
CSON.setCacheDir(path.join(cacheDir, 'cson'))
|
||||
babel.setCacheDirectory(path.join(cacheDir, 'js', 'babel'))
|
||||
typescript.setCacheDirectory(path.join(cacheDir, 'ts'))
|
||||
|
||||
switch path.extname(filePath)
|
||||
when '.coffee'
|
||||
CoffeeCache.addPathToCache(filePath)
|
||||
when '.cson'
|
||||
CSON.readFileSync(filePath)
|
||||
when '.js'
|
||||
babel.addPathToCache(filePath)
|
||||
when '.ts'
|
||||
typescript.addPathToCache(filePath)
|
||||
174
src/compile-cache.js
Normal file
174
src/compile-cache.js
Normal file
@@ -0,0 +1,174 @@
|
||||
'use strict'
|
||||
|
||||
var path = require('path')
|
||||
var fs = require('fs-plus')
|
||||
var CSON = null
|
||||
|
||||
var COMPILERS = {
|
||||
'.js': require('./babel'),
|
||||
'.ts': require('./typescript'),
|
||||
'.coffee': require('./coffee-script')
|
||||
}
|
||||
|
||||
var cacheStats = {}
|
||||
var cacheDirectory = null
|
||||
|
||||
exports.setAtomHomeDirectory = function (atomHome) {
|
||||
var cacheDir = path.join(atomHome, 'compile-cache')
|
||||
if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) {
|
||||
cacheDir = path.join(cacheDirectory, 'root')
|
||||
}
|
||||
this.setCacheDirectory(cacheDir)
|
||||
}
|
||||
|
||||
exports.setCacheDirectory = function (directory) {
|
||||
cacheDirectory = directory
|
||||
}
|
||||
|
||||
exports.getCacheDirectory = function () {
|
||||
return cacheDirectory
|
||||
}
|
||||
|
||||
exports.addPathToCache = function (filePath, atomHome) {
|
||||
this.setAtomHomeDirectory(atomHome)
|
||||
var extension = path.extname(filePath)
|
||||
|
||||
if (extension === '.cson') {
|
||||
if (!CSON) {
|
||||
CSON = require('season')
|
||||
CSON.setCacheDir(this.getCacheDirectory())
|
||||
}
|
||||
CSON.readFileSync(filePath)
|
||||
} else {
|
||||
var compiler = COMPILERS[extension]
|
||||
if (compiler) {
|
||||
compileFileAtPath(compiler, filePath, extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.getCacheStats = function () {
|
||||
return cacheStats
|
||||
}
|
||||
|
||||
exports.resetCacheStats = function () {
|
||||
Object.keys(COMPILERS).forEach(function (extension) {
|
||||
cacheStats[extension] = {
|
||||
hits: 0,
|
||||
misses: 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function compileFileAtPath (compiler, filePath, extension) {
|
||||
var sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
if (compiler.shouldCompile(sourceCode, filePath)) {
|
||||
var cachePath = compiler.getCachePath(sourceCode, filePath)
|
||||
var compiledCode = readCachedJavascript(cachePath)
|
||||
if (compiledCode != null) {
|
||||
cacheStats[extension].hits++
|
||||
} else {
|
||||
cacheStats[extension].misses++
|
||||
compiledCode = addSourceURL(compiler.compile(sourceCode, filePath), filePath)
|
||||
writeCachedJavascript(cachePath, compiledCode)
|
||||
}
|
||||
return compiledCode
|
||||
}
|
||||
return sourceCode
|
||||
}
|
||||
|
||||
function readCachedJavascript (relativeCachePath) {
|
||||
var cachePath = path.join(cacheDirectory, relativeCachePath)
|
||||
if (fs.isFileSync(cachePath)) {
|
||||
try {
|
||||
return fs.readFileSync(cachePath, 'utf8')
|
||||
} catch (error) {}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function writeCachedJavascript (relativeCachePath, code) {
|
||||
var cachePath = path.join(cacheDirectory, relativeCachePath)
|
||||
fs.writeFileSync(cachePath, code, 'utf8')
|
||||
}
|
||||
|
||||
function addSourceURL (jsCode, filePath) {
|
||||
if (process.platform === 'win32') {
|
||||
filePath = '/' + path.resolve(filePath).replace(/\\/g, '/')
|
||||
}
|
||||
return jsCode + '\n' + '//# sourceURL=' + encodeURI(filePath) + '\n'
|
||||
}
|
||||
|
||||
var INLINE_SOURCE_MAP_REGEXP = /\/\/[#@]\s*sourceMappingURL=([^'"\n]+)\s*$/mg
|
||||
|
||||
require('source-map-support').install({
|
||||
handleUncaughtExceptions: false,
|
||||
|
||||
// Most of this logic is the same as the default implementation in the
|
||||
// source-map-support module, but we've overridden it to read the javascript
|
||||
// code from our cache directory.
|
||||
retrieveSourceMap: function (filePath) {
|
||||
if (!fs.isFileSync(filePath)) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
var sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
} catch (error) {
|
||||
console.warn('Error reading source file', error.stack)
|
||||
return null
|
||||
}
|
||||
|
||||
var compiler = COMPILERS[path.extname(filePath)]
|
||||
|
||||
try {
|
||||
var fileData = readCachedJavascript(compiler.getCachePath(sourceCode, filePath))
|
||||
} catch (error) {
|
||||
console.warn('Error reading compiled file', error.stack)
|
||||
return null
|
||||
}
|
||||
|
||||
if (fileData == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
var match, lastMatch
|
||||
INLINE_SOURCE_MAP_REGEXP.lastIndex = 0
|
||||
while ((match = INLINE_SOURCE_MAP_REGEXP.exec(fileData))) {
|
||||
lastMatch = match
|
||||
}
|
||||
if (lastMatch == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
var sourceMappingURL = lastMatch[1]
|
||||
var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1)
|
||||
|
||||
try {
|
||||
var sourceMap = JSON.parse(new Buffer(rawData, 'base64'))
|
||||
} catch (error) {
|
||||
console.warn('Error parsing source map', error.stack)
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
map: sourceMap,
|
||||
url: null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Object.keys(COMPILERS).forEach(function (extension) {
|
||||
var compiler = COMPILERS[extension]
|
||||
|
||||
Object.defineProperty(require.extensions, extension, {
|
||||
enumerable: true,
|
||||
writable: false,
|
||||
value: function (module, filePath) {
|
||||
var code = compileFileAtPath(compiler, filePath, extension)
|
||||
return module._compile(code, filePath)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
exports.resetCacheStats()
|
||||
@@ -66,15 +66,11 @@ class Task
|
||||
# * `taskPath` The {String} path to the CoffeeScript/JavaScript file that
|
||||
# exports a single {Function} to execute.
|
||||
constructor: (taskPath) ->
|
||||
coffeeCacheRequire = "require('#{require.resolve('coffee-cash')}')"
|
||||
coffeeCachePath = require('coffee-cash').getCacheDirectory()
|
||||
coffeeStackRequire = "require('#{require.resolve('coffeestack')}')"
|
||||
stackCachePath = require('coffeestack').getCacheDirectory()
|
||||
compileCacheRequire = "require('#{require.resolve('./compile-cache')}')"
|
||||
compileCachePath = require('./compile-cache').getCacheDirectory()
|
||||
taskBootstrapRequire = "require('#{require.resolve('./task-bootstrap')}');"
|
||||
bootstrap = """
|
||||
#{coffeeCacheRequire}.setCacheDirectory('#{coffeeCachePath}');
|
||||
#{coffeeCacheRequire}.register();
|
||||
#{coffeeStackRequire}.setCacheDirectory('#{stackCachePath}');
|
||||
#{compileCacheRequire}.setCacheDirectory('#{compileCachePath}');
|
||||
#{taskBootstrapRequire}
|
||||
"""
|
||||
bootstrap = bootstrap.replace(/\\/g, "\\\\")
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
###
|
||||
Cache for source code transpiled by TypeScript.
|
||||
|
||||
Inspired by https://github.com/atom/atom/blob/7a719d585db96ff7d2977db9067e1d9d4d0adf1a/src/babel.coffee
|
||||
###
|
||||
|
||||
crypto = require 'crypto'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
tss = null # Defer until used
|
||||
|
||||
stats =
|
||||
hits: 0
|
||||
misses: 0
|
||||
|
||||
defaultOptions =
|
||||
target: 1 # ES5
|
||||
module: 'commonjs'
|
||||
sourceMap: true
|
||||
|
||||
createTypeScriptVersionAndOptionsDigest = (version, options) ->
|
||||
shasum = crypto.createHash('sha1')
|
||||
# Include the version of typescript in the hash.
|
||||
shasum.update('typescript', 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(version, 'utf8')
|
||||
shasum.update('\0', 'utf8')
|
||||
shasum.update(JSON.stringify(options))
|
||||
shasum.digest('hex')
|
||||
|
||||
cacheDir = null
|
||||
jsCacheDir = null
|
||||
|
||||
getCachePath = (sourceCode) ->
|
||||
digest = crypto.createHash('sha1').update(sourceCode, 'utf8').digest('hex')
|
||||
|
||||
unless jsCacheDir?
|
||||
tssVersion = require('typescript-simple/package.json').version
|
||||
jsCacheDir = path.join(cacheDir, createTypeScriptVersionAndOptionsDigest(tssVersion, defaultOptions))
|
||||
|
||||
path.join(jsCacheDir, "#{digest}.js")
|
||||
|
||||
getCachedJavaScript = (cachePath) ->
|
||||
if fs.isFileSync(cachePath)
|
||||
try
|
||||
cachedJavaScript = fs.readFileSync(cachePath, 'utf8')
|
||||
stats.hits++
|
||||
return cachedJavaScript
|
||||
null
|
||||
|
||||
# Returns the TypeScript options that should be used to transpile filePath.
|
||||
createOptions = (filePath) ->
|
||||
options = filename: filePath
|
||||
for key, value of defaultOptions
|
||||
options[key] = value
|
||||
options
|
||||
|
||||
transpile = (sourceCode, filePath, cachePath) ->
|
||||
options = createOptions(filePath)
|
||||
unless tss?
|
||||
{TypeScriptSimple} = require 'typescript-simple'
|
||||
tss = new TypeScriptSimple(options, false)
|
||||
js = tss.compile(sourceCode, filePath)
|
||||
stats.misses++
|
||||
|
||||
try
|
||||
fs.writeFileSync(cachePath, js)
|
||||
|
||||
js
|
||||
|
||||
# Function that obeys the contract of an entry in the require.extensions map.
|
||||
# Returns the transpiled version of the JavaScript code at filePath, which is
|
||||
# either generated on the fly or pulled from cache.
|
||||
loadFile = (module, filePath) ->
|
||||
sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
cachePath = getCachePath(sourceCode)
|
||||
js = getCachedJavaScript(cachePath) ? transpile(sourceCode, filePath, cachePath)
|
||||
module._compile(js, filePath)
|
||||
|
||||
register = ->
|
||||
Object.defineProperty(require.extensions, '.ts', {
|
||||
enumerable: true
|
||||
writable: false
|
||||
value: loadFile
|
||||
})
|
||||
|
||||
setCacheDirectory = (newCacheDir) ->
|
||||
if cacheDir isnt newCacheDir
|
||||
cacheDir = newCacheDir
|
||||
jsCacheDir = null
|
||||
|
||||
module.exports =
|
||||
register: register
|
||||
setCacheDirectory: setCacheDirectory
|
||||
getCacheMisses: -> stats.misses
|
||||
getCacheHits: -> stats.hits
|
||||
|
||||
# Visible for testing.
|
||||
createTypeScriptVersionAndOptionsDigest: createTypeScriptVersionAndOptionsDigest
|
||||
|
||||
addPathToCache: (filePath) ->
|
||||
return if path.extname(filePath) isnt '.ts'
|
||||
|
||||
sourceCode = fs.readFileSync(filePath, 'utf8')
|
||||
cachePath = getCachePath(sourceCode)
|
||||
transpile(sourceCode, filePath, cachePath)
|
||||
53
src/typescript.js
Normal file
53
src/typescript.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
|
||||
var _ = require('underscore-plus')
|
||||
var crypto = require('crypto')
|
||||
var path = require('path')
|
||||
|
||||
var defaultOptions = {
|
||||
target: 1,
|
||||
module: 'commonjs',
|
||||
sourceMap: true
|
||||
}
|
||||
|
||||
var TypeScriptSimple = null
|
||||
var typescriptVersionDir = null
|
||||
|
||||
exports.shouldCompile = function () {
|
||||
return true
|
||||
}
|
||||
|
||||
exports.getCachePath = function (sourceCode) {
|
||||
if (typescriptVersionDir == null) {
|
||||
var version = require('typescript-simple/package.json').version
|
||||
typescriptVersionDir = path.join('ts', createVersionAndOptionsDigest(version, defaultOptions))
|
||||
}
|
||||
|
||||
return path.join(
|
||||
typescriptVersionDir,
|
||||
crypto
|
||||
.createHash('sha1')
|
||||
.update(sourceCode, 'utf8')
|
||||
.digest('hex') + '.js'
|
||||
)
|
||||
}
|
||||
|
||||
exports.compile = function (sourceCode, filePath) {
|
||||
if (!TypeScriptSimple) {
|
||||
TypeScriptSimple = require('typescript-simple').TypeScriptSimple
|
||||
}
|
||||
|
||||
var options = _.defaults({filename: filePath}, defaultOptions)
|
||||
return new TypeScriptSimple(options, false).compile(sourceCode, filePath)
|
||||
}
|
||||
|
||||
function createVersionAndOptionsDigest (version, options) {
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update('typescript', 'utf8')
|
||||
.update('\0', 'utf8')
|
||||
.update(version, 'utf8')
|
||||
.update('\0', 'utf8')
|
||||
.update(JSON.stringify(options), 'utf8')
|
||||
.digest('hex')
|
||||
}
|
||||
7
static/babelrc.json
Normal file
7
static/babelrc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"breakConfig": true,
|
||||
"sourceMap": "inline",
|
||||
"blacklist": ["es6.forOf", "useStrict"],
|
||||
"optional": ["asyncToGenerator"],
|
||||
"stage": 0
|
||||
}
|
||||
403
static/index.js
403
static/index.js
@@ -1,234 +1,197 @@
|
||||
(function() {
|
||||
(function () {
|
||||
var fs = require('fs')
|
||||
var path = require('path')
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var loadSettings = null
|
||||
var loadSettingsError = null
|
||||
|
||||
var loadSettings = null;
|
||||
var loadSettingsError = null;
|
||||
|
||||
window.onload = function() {
|
||||
try {
|
||||
var startTime = Date.now();
|
||||
|
||||
process.on('unhandledRejection', function(error, promise) {
|
||||
console.error('Unhandled promise rejection %o with error: %o', promise, error);
|
||||
});
|
||||
|
||||
// Ensure ATOM_HOME is always set before anything else is required
|
||||
setupAtomHome();
|
||||
|
||||
// Normalize to make sure drive letter case is consistent on Windows
|
||||
process.resourcesPath = path.normalize(process.resourcesPath);
|
||||
|
||||
if (loadSettingsError) {
|
||||
throw loadSettingsError;
|
||||
}
|
||||
|
||||
var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep);
|
||||
|
||||
if (devMode) {
|
||||
setupDeprecatedPackages();
|
||||
}
|
||||
|
||||
if (loadSettings.profileStartup) {
|
||||
profileStartup(loadSettings, Date.now() - startTime);
|
||||
} else {
|
||||
setupWindow(loadSettings);
|
||||
setLoadTime(Date.now() - startTime);
|
||||
}
|
||||
} catch (error) {
|
||||
handleSetupError(error);
|
||||
}
|
||||
}
|
||||
|
||||
var getCacheDirectory = function() {
|
||||
var cacheDir = path.join(process.env.ATOM_HOME, 'compile-cache');
|
||||
// Use separate compile cache when sudo'ing as root to avoid permission issues
|
||||
if (process.env.USER === 'root' && process.env.SUDO_USER && process.env.SUDO_USER !== process.env.USER) {
|
||||
cacheDir = path.join(cacheDir, 'root');
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
|
||||
var setLoadTime = function(loadTime) {
|
||||
if (global.atom) {
|
||||
global.atom.loadTime = loadTime;
|
||||
console.log('Window load time: ' + global.atom.getWindowLoadTime() + 'ms');
|
||||
}
|
||||
}
|
||||
|
||||
var handleSetupError = function(error) {
|
||||
var currentWindow = require('remote').getCurrentWindow();
|
||||
currentWindow.setSize(800, 600);
|
||||
currentWindow.center();
|
||||
currentWindow.show();
|
||||
currentWindow.openDevTools();
|
||||
console.error(error.stack || error);
|
||||
}
|
||||
|
||||
var setupWindow = function(loadSettings) {
|
||||
var cacheDir = getCacheDirectory();
|
||||
|
||||
setupCoffeeCache(cacheDir);
|
||||
|
||||
ModuleCache = require('../src/module-cache');
|
||||
ModuleCache.register(loadSettings);
|
||||
ModuleCache.add(loadSettings.resourcePath);
|
||||
|
||||
// Only include deprecated APIs when running core spec
|
||||
require('grim').includeDeprecatedAPIs = isRunningCoreSpecs(loadSettings);
|
||||
|
||||
// Start the crash reporter before anything else.
|
||||
require('crash-reporter').start({
|
||||
productName: 'Atom',
|
||||
companyName: 'GitHub',
|
||||
// By explicitly passing the app version here, we could save the call
|
||||
// of "require('remote').require('app').getVersion()".
|
||||
extra: {_version: loadSettings.appVersion}
|
||||
});
|
||||
|
||||
setupVmCompatibility();
|
||||
setupCsonCache(cacheDir);
|
||||
setupSourceMapCache(cacheDir);
|
||||
setupBabel(cacheDir);
|
||||
setupTypeScript(cacheDir);
|
||||
|
||||
require(loadSettings.bootstrapScript);
|
||||
require('ipc').sendChannel('window-command', 'window:loaded');
|
||||
}
|
||||
|
||||
var setupCoffeeCache = function(cacheDir) {
|
||||
var CoffeeCache = require('coffee-cash');
|
||||
CoffeeCache.setCacheDirectory(path.join(cacheDir, 'coffee'));
|
||||
CoffeeCache.register();
|
||||
}
|
||||
|
||||
var setupAtomHome = function() {
|
||||
if (!process.env.ATOM_HOME) {
|
||||
var home;
|
||||
if (process.platform === 'win32') {
|
||||
home = process.env.USERPROFILE;
|
||||
} else {
|
||||
home = process.env.HOME;
|
||||
}
|
||||
var atomHome = path.join(home, '.atom');
|
||||
try {
|
||||
atomHome = fs.realpathSync(atomHome);
|
||||
} catch (error) {
|
||||
// Ignore since the path might just not exist yet.
|
||||
}
|
||||
process.env.ATOM_HOME = atomHome;
|
||||
}
|
||||
}
|
||||
|
||||
var setupBabel = function(cacheDir) {
|
||||
var babel = require('../src/babel');
|
||||
babel.setCacheDirectory(path.join(cacheDir, 'js', 'babel'));
|
||||
babel.register();
|
||||
}
|
||||
|
||||
var setupTypeScript = function(cacheDir) {
|
||||
var typescript = require('../src/typescript');
|
||||
typescript.setCacheDirectory(path.join(cacheDir, 'typescript'));
|
||||
typescript.register();
|
||||
}
|
||||
|
||||
var setupCsonCache = function(cacheDir) {
|
||||
require('season').setCacheDir(path.join(cacheDir, 'cson'));
|
||||
}
|
||||
|
||||
var setupSourceMapCache = function(cacheDir) {
|
||||
require('coffeestack').setCacheDirectory(path.join(cacheDir, 'coffee', 'source-maps'));
|
||||
}
|
||||
|
||||
var setupVmCompatibility = function() {
|
||||
var vm = require('vm');
|
||||
if (!vm.Script.createContext) {
|
||||
vm.Script.createContext = vm.createContext;
|
||||
}
|
||||
}
|
||||
|
||||
var setupDeprecatedPackages = function() {
|
||||
var metadata = require('../package.json');
|
||||
if (!metadata._deprecatedPackages) {
|
||||
try {
|
||||
metadata._deprecatedPackages = require('../build/deprecated-packages.json');
|
||||
} catch(requireError) {
|
||||
console.error('Failed to setup deprecated packages list', requireError.stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var profileStartup = function(loadSettings, initialTime) {
|
||||
var profile = function() {
|
||||
console.profile('startup');
|
||||
window.onload = function () {
|
||||
try {
|
||||
var startTime = Date.now()
|
||||
setupWindow(loadSettings);
|
||||
setLoadTime(Date.now() - startTime + initialTime);
|
||||
|
||||
process.on('unhandledRejection', function (error, promise) {
|
||||
console.error('Unhandled promise rejection %o with error: %o', promise, error)
|
||||
})
|
||||
|
||||
// Ensure ATOM_HOME is always set before anything else is required
|
||||
setupAtomHome()
|
||||
|
||||
// Normalize to make sure drive letter case is consistent on Windows
|
||||
process.resourcesPath = path.normalize(process.resourcesPath)
|
||||
|
||||
if (loadSettingsError) {
|
||||
throw loadSettingsError
|
||||
}
|
||||
|
||||
var devMode = loadSettings.devMode || !loadSettings.resourcePath.startsWith(process.resourcesPath + path.sep)
|
||||
|
||||
if (devMode) {
|
||||
setupDeprecatedPackages()
|
||||
}
|
||||
|
||||
if (loadSettings.profileStartup) {
|
||||
profileStartup(loadSettings, Date.now() - startTime)
|
||||
} else {
|
||||
setupWindow(loadSettings)
|
||||
setLoadTime(Date.now() - startTime)
|
||||
}
|
||||
} catch (error) {
|
||||
handleSetupError(error);
|
||||
} finally {
|
||||
console.profileEnd('startup');
|
||||
console.log("Switch to the Profiles tab to view the created startup profile")
|
||||
handleSetupError(error)
|
||||
}
|
||||
};
|
||||
|
||||
var currentWindow = require('remote').getCurrentWindow();
|
||||
if (currentWindow.devToolsWebContents) {
|
||||
profile();
|
||||
} else {
|
||||
currentWindow.openDevTools();
|
||||
currentWindow.once('devtools-opened', function() {
|
||||
setTimeout(profile, 100);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var parseLoadSettings = function() {
|
||||
var rawLoadSettings = decodeURIComponent(location.hash.substr(1));
|
||||
try {
|
||||
loadSettings = JSON.parse(rawLoadSettings);
|
||||
} catch (error) {
|
||||
console.error("Failed to parse load settings: " + rawLoadSettings);
|
||||
loadSettingsError = error;
|
||||
}
|
||||
}
|
||||
|
||||
var setupWindowBackground = function() {
|
||||
if (loadSettings && loadSettings.isSpec) {
|
||||
return;
|
||||
}
|
||||
|
||||
var backgroundColor = window.localStorage.getItem('atom:window-background-color');
|
||||
if (!backgroundColor) {
|
||||
return;
|
||||
function setLoadTime (loadTime) {
|
||||
if (global.atom) {
|
||||
global.atom.loadTime = loadTime
|
||||
console.log('Window load time: ' + global.atom.getWindowLoadTime() + 'ms')
|
||||
}
|
||||
}
|
||||
|
||||
var backgroundStylesheet = document.createElement('style');
|
||||
backgroundStylesheet.type = 'text/css';
|
||||
backgroundStylesheet.innerText = 'html, body { background: ' + backgroundColor + '; }';
|
||||
document.head.appendChild(backgroundStylesheet);
|
||||
function handleSetupError (error) {
|
||||
var currentWindow = require('remote').getCurrentWindow()
|
||||
currentWindow.setSize(800, 600)
|
||||
currentWindow.center()
|
||||
currentWindow.show()
|
||||
currentWindow.openDevTools()
|
||||
console.error(error.stack || error)
|
||||
}
|
||||
|
||||
// Remove once the page loads
|
||||
window.addEventListener("load", function loadWindow() {
|
||||
window.removeEventListener("load", loadWindow, false);
|
||||
setTimeout(function() {
|
||||
backgroundStylesheet.remove();
|
||||
backgroundStylesheet = null;
|
||||
}, 1000);
|
||||
}, false);
|
||||
}
|
||||
function setupWindow (loadSettings) {
|
||||
var CompileCache = require('../src/compile-cache')
|
||||
CompileCache.setAtomHomeDirectory(process.env.ATOM_HOME)
|
||||
|
||||
var isRunningCoreSpecs = function(loadSettings) {
|
||||
return !!(loadSettings &&
|
||||
loadSettings.isSpec &&
|
||||
loadSettings.specDirectory &&
|
||||
loadSettings.resourcePath &&
|
||||
path.dirname(loadSettings.specDirectory) === loadSettings.resourcePath);
|
||||
}
|
||||
var ModuleCache = require('../src/module-cache')
|
||||
ModuleCache.register(loadSettings)
|
||||
ModuleCache.add(loadSettings.resourcePath)
|
||||
|
||||
parseLoadSettings();
|
||||
setupWindowBackground();
|
||||
// Only include deprecated APIs when running core spec
|
||||
require('grim').includeDeprecatedAPIs = isRunningCoreSpecs(loadSettings)
|
||||
|
||||
})();
|
||||
// Start the crash reporter before anything else.
|
||||
require('crash-reporter').start({
|
||||
productName: 'Atom',
|
||||
companyName: 'GitHub',
|
||||
// By explicitly passing the app version here, we could save the call
|
||||
// of "require('remote').require('app').getVersion()".
|
||||
extra: {_version: loadSettings.appVersion}
|
||||
})
|
||||
|
||||
setupVmCompatibility()
|
||||
setupCsonCache(CompileCache.getCacheDirectory())
|
||||
|
||||
require(loadSettings.bootstrapScript)
|
||||
require('ipc').sendChannel('window-command', 'window:loaded')
|
||||
}
|
||||
|
||||
function setupAtomHome () {
|
||||
if (!process.env.ATOM_HOME) {
|
||||
var home
|
||||
if (process.platform === 'win32') {
|
||||
home = process.env.USERPROFILE
|
||||
} else {
|
||||
home = process.env.HOME
|
||||
}
|
||||
var atomHome = path.join(home, '.atom')
|
||||
try {
|
||||
atomHome = fs.realpathSync(atomHome)
|
||||
} catch (error) {
|
||||
// Ignore since the path might just not exist yet.
|
||||
}
|
||||
process.env.ATOM_HOME = atomHome
|
||||
}
|
||||
}
|
||||
|
||||
function setupCsonCache (cacheDir) {
|
||||
require('season').setCacheDir(path.join(cacheDir, 'cson'))
|
||||
}
|
||||
|
||||
function setupVmCompatibility () {
|
||||
var vm = require('vm')
|
||||
if (!vm.Script.createContext) {
|
||||
vm.Script.createContext = vm.createContext
|
||||
}
|
||||
}
|
||||
|
||||
function setupDeprecatedPackages () {
|
||||
var metadata = require('../package.json')
|
||||
if (!metadata._deprecatedPackages) {
|
||||
try {
|
||||
metadata._deprecatedPackages = require('../build/deprecated-packages.json')
|
||||
} catch(requireError) {
|
||||
console.error('Failed to setup deprecated packages list', requireError.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function profileStartup (loadSettings, initialTime) {
|
||||
function profile () {
|
||||
console.profile('startup')
|
||||
try {
|
||||
var startTime = Date.now()
|
||||
setupWindow(loadSettings)
|
||||
setLoadTime(Date.now() - startTime + initialTime)
|
||||
} catch (error) {
|
||||
handleSetupError(error)
|
||||
} finally {
|
||||
console.profileEnd('startup')
|
||||
console.log('Switch to the Profiles tab to view the created startup profile')
|
||||
}
|
||||
}
|
||||
|
||||
var currentWindow = require('remote').getCurrentWindow()
|
||||
if (currentWindow.devToolsWebContents) {
|
||||
profile()
|
||||
} else {
|
||||
currentWindow.openDevTools()
|
||||
currentWindow.once('devtools-opened', function () {
|
||||
setTimeout(profile, 100)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function parseLoadSettings () {
|
||||
var rawLoadSettings = decodeURIComponent(window.location.hash.substr(1))
|
||||
try {
|
||||
loadSettings = JSON.parse(rawLoadSettings)
|
||||
} catch (error) {
|
||||
console.error('Failed to parse load settings: ' + rawLoadSettings)
|
||||
loadSettingsError = error
|
||||
}
|
||||
}
|
||||
|
||||
function setupWindowBackground () {
|
||||
if (loadSettings && loadSettings.isSpec) {
|
||||
return
|
||||
}
|
||||
|
||||
var backgroundColor = window.localStorage.getItem('atom:window-background-color')
|
||||
if (!backgroundColor) {
|
||||
return
|
||||
}
|
||||
|
||||
var backgroundStylesheet = document.createElement('style')
|
||||
backgroundStylesheet.type = 'text/css'
|
||||
backgroundStylesheet.innerText = 'html, body { background: ' + backgroundColor + '; }'
|
||||
document.head.appendChild(backgroundStylesheet)
|
||||
|
||||
// Remove once the page loads
|
||||
window.addEventListener('load', function loadWindow () {
|
||||
window.removeEventListener('load', loadWindow, false)
|
||||
setTimeout(function () {
|
||||
backgroundStylesheet.remove()
|
||||
backgroundStylesheet = null
|
||||
}, 1000)
|
||||
}, false)
|
||||
}
|
||||
|
||||
function isRunningCoreSpecs (loadSettings) {
|
||||
return !!(loadSettings &&
|
||||
loadSettings.isSpec &&
|
||||
loadSettings.specDirectory &&
|
||||
loadSettings.resourcePath &&
|
||||
path.dirname(loadSettings.specDirectory) === loadSettings.resourcePath)
|
||||
}
|
||||
|
||||
parseLoadSettings()
|
||||
setupWindowBackground()
|
||||
})()
|
||||
|
||||
Reference in New Issue
Block a user