mirror of
https://github.com/atom/atom.git
synced 2026-01-24 14:28:14 -05:00
243 lines
7.0 KiB
JavaScript
243 lines
7.0 KiB
JavaScript
'use strict'
|
|
|
|
// For now, we're not using babel or ES6 features like `let` and `const` in
|
|
// this file, because `apm` requires this file directly in order to pre-warm
|
|
// Atom's compile-cache when installing or updating packages, using an older
|
|
// version of node.js
|
|
|
|
var path = require('path')
|
|
var fs = require('fs-plus')
|
|
var sourceMapSupport = require('@atom/source-map-support')
|
|
|
|
var PackageTranspilationRegistry = require('./package-transpilation-registry')
|
|
var CSON = null
|
|
|
|
var packageTranspilationRegistry = new PackageTranspilationRegistry()
|
|
|
|
var COMPILERS = {
|
|
'.js': packageTranspilationRegistry.wrapTranspiler(require('./babel')),
|
|
'.ts': packageTranspilationRegistry.wrapTranspiler(require('./typescript')),
|
|
'.tsx': packageTranspilationRegistry.wrapTranspiler(require('./typescript')),
|
|
'.coffee': packageTranspilationRegistry.wrapTranspiler(require('./coffee-script'))
|
|
}
|
|
|
|
exports.addTranspilerConfigForPath = function (packagePath, packageName, packageMeta, config) {
|
|
packagePath = fs.realpathSync(packagePath)
|
|
packageTranspilationRegistry.addTranspilerConfigForPath(packagePath, packageName, packageMeta, config)
|
|
}
|
|
|
|
exports.removeTranspilerConfigForPath = function (packagePath) {
|
|
packagePath = fs.realpathSync(packagePath)
|
|
packageTranspilationRegistry.removeTranspilerConfigForPath(packagePath)
|
|
}
|
|
|
|
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(cacheDir, '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())
|
|
}
|
|
return CSON.readFileSync(filePath)
|
|
} else {
|
|
var compiler = COMPILERS[extension]
|
|
if (compiler) {
|
|
return 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 = compiler.compile(sourceCode, 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')
|
|
}
|
|
|
|
var INLINE_SOURCE_MAP_REGEXP = /\/\/[#@]\s*sourceMappingURL=([^'"\n]+)\s*$/mg
|
|
|
|
exports.install = function (resourcesPath, nodeRequire) {
|
|
const snapshotSourceMapConsumer = {
|
|
originalPositionFor ({line, column}) {
|
|
const {relativePath, row} = snapshotResult.translateSnapshotRow(line)
|
|
return {
|
|
column,
|
|
line: row,
|
|
source: path.join(resourcesPath, 'app', 'static', relativePath),
|
|
name: null
|
|
}
|
|
}
|
|
}
|
|
|
|
sourceMapSupport.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 (filePath === '<embedded>') {
|
|
return {map: snapshotSourceMapConsumer}
|
|
}
|
|
|
|
if (!cacheDirectory || !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)]
|
|
if (!compiler) compiler = COMPILERS['.js']
|
|
|
|
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
|
|
}
|
|
}
|
|
})
|
|
|
|
var prepareStackTraceWithSourceMapping = Error.prepareStackTrace
|
|
var prepareStackTrace = prepareStackTraceWithSourceMapping
|
|
|
|
function prepareStackTraceWithRawStackAssignment (error, frames) {
|
|
if (error.rawStack) { // avoid infinite recursion
|
|
return prepareStackTraceWithSourceMapping(error, frames)
|
|
} else {
|
|
error.rawStack = frames
|
|
return prepareStackTrace(error, frames)
|
|
}
|
|
}
|
|
|
|
Error.stackTraceLimit = 30
|
|
|
|
Object.defineProperty(Error, 'prepareStackTrace', {
|
|
get: function () {
|
|
return prepareStackTraceWithRawStackAssignment
|
|
},
|
|
|
|
set: function (newValue) {
|
|
prepareStackTrace = newValue
|
|
process.nextTick(function () {
|
|
prepareStackTrace = prepareStackTraceWithSourceMapping
|
|
})
|
|
}
|
|
})
|
|
|
|
Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native
|
|
// Access this.stack to ensure prepareStackTrace has been run on this error
|
|
// because it assigns this.rawStack as a side-effect
|
|
this.stack
|
|
return this.rawStack
|
|
}
|
|
|
|
Object.keys(COMPILERS).forEach(function (extension) {
|
|
var compiler = COMPILERS[extension]
|
|
|
|
Object.defineProperty(nodeRequire.extensions, extension, {
|
|
enumerable: true,
|
|
writable: false,
|
|
value: function (module, filePath) {
|
|
var code = compileFileAtPath(compiler, filePath, extension)
|
|
return module._compile(code, filePath)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
exports.supportedExtensions = Object.keys(COMPILERS)
|
|
exports.resetCacheStats()
|