werkzeug
Version:
compiles ts, coffee, sass/scss, less/ stylus and packs browser ready bundles
410 lines (284 loc) • 11.1 kB
text/coffeescript
FS = require 'fs'
Path = require 'path'
TS = require 'typescript'
Linter = require 'tslint'
Walk = require 'walkdir'
Home = require 'homedir'
_ = require '../utils/pimped-lodash'
FSU = require '../utils/fsu'
SW = require '../utils/stopwatch'
PH = require '../utils/path-helper'
IPC = require '../utils/ipc'
Log = require '../utils/log'
NGTool = require './ng-tool'
ES5Libs = ['lib.dom.d.ts', 'lib.es5.d.ts', 'lib.scripthost.d.ts']
ES6Libs = ['lib.dom.d.ts', 'lib.dom.iterable.d.ts', 'lib.es6.d.ts', 'lib.scripthost.d.ts']
linterOptions =
formatter: 'json'
configuration: {}
#TODO: check tslint code, if the ts language service or the ts program can be used more effectively
class TSCompiler
constructor: () ->
= false
= null
= null
= null
= []
= {}
= {}
= []
= null
= null
= new IPC(process, @)
= {}
= {}
TS.sys.fileExists =
TS.sys.readFile =
init: () ->
return if not .out
= {}
= PH.getIn , 'ts'
= PH.getOut , 'ts'
null
loadTSConfig: () ->
= FSU.require __dirname, '..', '..', '.default.tsconfig'
= TS.convertCompilerOptionsFromJson .compilerOptions
tscfg = FSU.require .base, 'tsconfig'
if tscfg and tscfg.compilerOptions
tscfg = TS.convertCompilerOptionsFromJson tscfg.compilerOptions
= _.deepExtend , tscfg
.options.sourceMap = true
.options.rootDir =
.options.outDir =
.options.sourceRoot = Path.relative ,
.options.baseUrl = Path.join __dirname, '..', '..', 'node_modules'
null
loadTSLintConfig: () ->
cfg = FSU.require .base, 'tslint'
cfg = FSU.require Home(), 'tslint' if not cfg
cfg = FSU.require __dirname, '..', '..', '.default.tslint' if not cfg
#TODO: handle error
if not cfg
console.log 'ERROR: tslint config not found!!'
_.deepMerge linterOptions.configuration, cfg
null
addTypings: () ->
opt = .options
libs = opt.lib
if not libs or libs.length == 0
target = .options.target
libs = switch target
when 1 then ES5Libs
when 2 then ES6Libs
else []
libPath = Path.join __dirname, '../../node_modules/typescript/lib'
for lib in libs
path = Path.join libPath, lib
if FSU.isFile path
types = opt.types or []
typeRoots = opt.typeRoots or ['node_modules/@types']
#TODO: use configuration
for path in typeRoots
path = Path.resolve .base, path
if FSU.isDir path
Walk.sync path, (typePath, stat) =>
if /\.d\.ts$/.test(typePath) and stat.isFile()
null
addPath: (path) ->
file = [path]
if not file
.push path
[path] = version:0, path:path
else
++file.version
src = FS.readFileSync path, 'utf8'
if .ts.ngTool
src = NGTool.run path, src,
[path] = src
null
removePath: (path) ->
if [path]
.splice .indexOf(path), 1
delete [path]
delete [path]
delete [path]
null
compile: (files) ->
try
if not .out
return
= []
removed = false
for file in files
path = file.path
if not file.removed
path # updates version, if already added
.push [path]
else
removed = true
path
= []
if not
if not or files.length > 20 or removed
else
= .getProgram()
for file in files
if not file.removed
catch e
console.log 'ts error: ', e.toString()
null
compileAll: (paths) ->
=
emitResult = .emit()
allDiagnostics = TS.getPreEmitDiagnostics().concat emitResult.diagnostics
allDiagnostics.forEach (diagnostic) =>
if diagnostic.file
{ line, character } = diagnostic.file.getLineAndCharacterOfPosition diagnostic.start
message = TS.flattenDiagnosticMessageText diagnostic.messageText, '\n'
path: diagnostic.file.fileName
line: line + 1
col: character + 1
error: message
#TODO: handle error somehow
else
console.log 'diagnostic without file: ', diagnostic
null
compilePath: (path) ->
return null if /\.d\.ts/.test path
output = .getEmitOutput path
allDiagnostics = .getSyntacticDiagnostics(path).concat .getSemanticDiagnostics(path)
errors = count:0
allDiagnostics.forEach (diagnostic) =>
if diagnostic.file
++errors.count
{ line, character } = diagnostic.file.getLineAndCharacterOfPosition diagnostic.start
message = TS.flattenDiagnosticMessageText diagnostic.messageText, '\n'
path: diagnostic.file.fileName
line: line + 1
col: character + 1
error: message
#TODO: handle error somehow
else
console.log 'diagnostic without file: ', diagnostic
if errors.count == 0
for file in output.outputFiles
FS.writeFileSync file.name, file.text, "utf8"
null
addError: (error) ->
for e in
equal = true
for key, value of e
equal = equal and (error[key] == value)
return if equal
.push error
createProgram: (paths) ->
host = TS.createCompilerHost .options
host.resolveModuleNames =
= TS.createProgram paths, .options, host
null
createService: () ->
=
getScriptFileNames: () =>
getScriptVersion: (path) =>
[path] and [path].version.toString()
getScriptSnapshot: (path) =>
try
TS.ScriptSnapshot.fromString
catch
undefined
getCurrentDirectory: () =>
.base
getCompilationSettings: () =>
.options
getDefaultLibFileName: (options) ->
or = TS.getDefaultLibFilePath options
resolveModuleNames:
= TS.createLanguageService , TS.createDocumentRegistry()
null
fileExists: (path) =>
###
name = null
if /node_modules/.test path
last = path.lastIndexOf 'node_modules'
name = path.substr last + 13
modulePath = [name]
src = [modulePath]
if src and /\/core\/index.d.ts$/.test path
console.log 'found mapped node module: ', name, path
if src
return modulePath == path
if name and /\/core\/index.d.ts$/.test path
console.log 'initial map node module: ', name, path
[name] = path if name
###
FSU.isFile path
readFile: (path) =>
src = [path]
return src if src
[path] = FS.readFileSync path, 'utf8'
resolveModuleNames: (moduleNames, containingFile) =>
#TODO: try to hack ts module development problem here
map = []
opt = .options
api = {fileExists:, readFile:}
for moduleName in moduleNames
result = TS.resolveModuleName moduleName, containingFile, opt, api
if result.resolvedModule
map.push result.resolvedModule
else if moduleName == 'tslib'
console.log 'resolve tslib: ', Path.resolve('../../node_modules/tslib')
map.push Path.resolve('../../node_modules/tslib')
else
map.push undefined
map
lint: () ->
#remove errors for changed files
errors = []
fmap = {}
emap = {}
for file in
fmap[file.path] = true
for error in
emap[error.path] = true
for error in
errors.push error if not fmap[error.path] and not emap[error.path]
= errors
for file in
path = file.path
if not emap[path]
file = .getSourceFile path
[path] = file.text
path
null
lintFile: (path) ->
linter = new Linter(path, [path], linterOptions, )
result = linter.lint()
for data in result.failures
pos = data.startPosition.lineAndCharacter
.push
path: path
line: pos.line + 1
col: pos.character + 1
warning: data.failure
type: 'tslint'
null
compiled: () ->
if ( or not .tslint.ignoreInitial)
SW.start 'linter'
Log.info 'tslint', 'ready', SW.stop('linter'), .length, true
= true
.send 'compiled', 'ts', .concat()
null
module.exports = new TSCompiler()