Merge pull request #5898 from basarat/master

Transpile all .ts files
This commit is contained in:
Kevin Sawicki
2015-03-26 14:33:04 -07:00
8 changed files with 161 additions and 1 deletions

View File

@@ -66,6 +66,7 @@
"temp": "0.8.1",
"text-buffer": "^5.1.0",
"theorist": "^1.0.2",
"typescript-simple": "^1.0.0",
"underscore-plus": "^1.6.6"
},
"packageDependencies": {

View File

@@ -3,26 +3,37 @@ CSON = require 'season'
CoffeeCache = require 'coffee-cash'
babel = require '../src/babel'
typescript = require '../src/typescript'
CompileCache = require '../src/compile-cache'
describe "Compile Cache", ->
describe ".addPathToCache(filePath)", ->
it "adds the path to the correct CSON, CoffeeScript, or babel cache", ->
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()
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
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
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
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

1
spec/fixtures/typescript/invalid.ts vendored Normal file
View File

@@ -0,0 +1 @@
var foo = 123 123; // Syntax error

2
spec/fixtures/typescript/valid.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
var inc = v => v + 1
export = inc

View File

@@ -0,0 +1,30 @@
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')
expect(transpiled(3)).toBe 4
describe "when the .ts file is invalid", ->
it "does not transpile", ->
expect(-> require('./fixtures/typescript/invalid.ts')).toThrow()

View File

@@ -2,6 +2,7 @@ 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
@@ -16,6 +17,7 @@ exports.addPathToCache = (filePath, atomHome) ->
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'
@@ -24,3 +26,5 @@ exports.addPathToCache = (filePath, atomHome) ->
CSON.readFileSync(filePath)
when '.js'
babel.addPathToCache(filePath)
when '.ts'
typescript.addPathToCache(filePath)

104
src/typescript.coffee Normal file
View File

@@ -0,0 +1,104 @@
###
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)
tss ?= new (require 'typescript-simple').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)

View File

@@ -47,6 +47,7 @@ window.onload = function() {
setupCsonCache(cacheDir);
setupSourceMapCache(cacheDir);
setupBabel(cacheDir);
setupTypeScript(cacheDir);
require(loadSettings.bootstrapScript);
require('ipc').sendChannel('window-command', 'window:loaded');
@@ -95,6 +96,12 @@ var setupBabel = function(cacheDir) {
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'));
}