UNPKG

typescript-compile

Version:

node.js typescript compile adapter

285 lines (252 loc) 11 kB
/*** * TypeScript Compile * ---------------------------------------------------------------------------- * <typescript-compile.js> - 2014/7/26 * @version 0.0.1 * @author Joye, maolion.j@gmail.com * @website http://maolion.com */ 'use strict'; var Fs = require("fs"), Path = require("path"), TS = require("./ts") ; var Utils = function(){ var Utils = {}; Utils.mix = function(dest, sources) { var sources = Array.prototype.slice.call(arguments, 1) ; if (!dest) return; if (!sources.length) return dest; for(var i = 0, l = sources.length; i < l; i++) { var source = sources[i]; for(var k in source) { if (!source.hasOwnProperty(k)) continue; dest[k] = source[k]; } } return dest; }; return Utils; }(); /** * TSCompile(filepath, setting) * @param {String} filepath * * @param {JSON/String} setting ��������ѡ�� * JSON ���ܵ������� */ var Compile = module.exports = function(){ var DEF_SETTING = new TS.CompilationSettings(), UID = new Date().getTime(), schema = { "--out" : { type : String, target : "outFileOption" }, // Specify path to output file //"--outDir" : { type : String, target : "outDirOption" }, //Specify path to output dir "--module" : { type : String, target : "moduleGenTarget", enum : { default : TS.ModuleGenTarget.Unspecified, commonjs : TS.ModuleGenTarget.Synchronous, amd : TS.ModuleGenTarget.Asynchronous } }, // Specify module code generation: 'commonjs' or 'amd' "--target" : { type : String, target : "codeGenTarget", enum : { default : TS.LanguageVersion.EcmaScript3, ES3 : TS.LanguageVersion.EcmaScript3, ES5 : TS.LanguageVersion.EcmaScript5 } }, // Specify ECMAScript target version: 'ES3' (default), or 'ES5' "--noImplicitAny" : { type : Boolean, target : "noImplicitAny"}, // Warn on expressions and declarations with an implied 'any' type. //"--noResolve" : { type : Boolean, target : "noResolve" }, // Skip resolution and preprocessing. "--removeComments" : { type : Boolean, target : "removeComments" }, // Do not emit comments to output. //"--sourcemap" : { type : Boolean, target : "mapSourceFiles" }, //Generates corresponding .map file. "--noLib" : { type : Boolean, target : "noLib" }, //Do not include default library //"--mapRoot" : { type : String, target : "mapRoot" }, //Specifies the location where debugger should locate map files instead of generated locations. //"--sourceRoot" : { type : String, target : "sourceRoot" } //Specifies the location where debugger should locate TypeScript files instead of source locations. "--root" : { type : String, target : "root" }, "--file": { type: String, target: "file" }, "--nodejs" : { type : Boolean, target : "nodejs" } } ; function normalizerCompilationSetting(args, filter) { var setting = Utils.mix({outFileOption:"code.js"}, DEF_SETTING); if (typeof args === "string" || args instanceof String) { args = args.split(/\s+/g); for(var i = 0, l= args.length; i < l; i ++) { var opt = args[i], s = schema[opt] ; if ( !schema.hasOwnProperty(opt) || (filter && filter.hasOwnProperty(opt.slice(2))) ) continue; if (s.type === String) { var next = args[i+1]; if (next && schema.hasOwnProperty(opt)) { setting[s.target] = s.enum ? s.enum.hasOwnProperty(next) ? s.enum[next] : s.enum.default : next; i++; } } else { setting[s.target] = true; } } } else { for(var k in args) { var s = schema["--" + k]; if ( !s || (filter && filter.hasOwnProperty(k)) ) continue; setting[s.target] = s.type === Boolean ? !!args[k] : s.enum ? (s.enum.hasOwnProperty(args[k]) ? s.enum[args[k]] : s.enum.default) : args[k] ; } } return setting; } function CodeUnit(path, scriptSnapshot) { this.path = path; this.scriptSnapshot = new TS.ScriptSnapshot.fromString(typeof scriptSnapshot === 'undefined' ? Fs.readFileSync(path, "utf8") : scriptSnapshot); this.references = []; this.referenced = {}; } var referenceBaseLibUnit = function(){ var cache = {}, libs = [ { path : TS.LIB_DPATH, when : function(setting) { return !setting.noLib(); } }, { path : TS.COMMONJS_DPATH, when: function (setting) { return !setting.isNodeJs && (setting.moduleGenTarget() === TS.ModuleGenTarget.Synchronous || setting.moduleGenTarget() === TS.ModuleGenTarget.Asynchronous); } }, { path: TS.NODEJS_DPATH, when: function (setting) { return setting.isNodeJs; } } ] ; return function referenceBaseLibUnit(current, host) { for(var i = 0, l = libs.length; i < l; i++) { var lib = libs[i], unit = null ; if (!lib.when(host._setting)) continue; current.references.push(lib.path); unit = cache[lib.path] = cache[lib.path] || new CodeUnit(lib.path); host._compiler.addFile(unit.path, unit.scriptSnapshot, 3, 0, false, unit.references); current.referenced[unit.path] = unit; } } }(); var RE_REF_TAG = /^\/{3}\s*<reference\s/i ; function resolve(current, host) { host._resolveCache[current.path] = current; referenceBaseLibUnit(current, host); var code = current.scriptSnapshot.text.replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, function(match){ return RE_REF_TAG.test(match) ? match : ''; }); var re = /\/{3}\s*<reference\s+path\s*=\s*['"]([^'"]+?)['"]|\bimport\s+\w+\s*=\s*require\s*\(\s*['"]([^'"]+?)['"]\s*\)/ig, isDFile = /\.d\.ts$/i.test(current.path), RE_REQUIRE = /\bimport\s+\w+\s*=\s*require\s*\(\s*['"][^'"]+?['"]\s*\)/i, match = null ; while(match = re.exec(code)) { var file = host.resolvePath(match[1]||match[2], Path.dirname(current.path)), unit = null ; if (isDFile && RE_REQUIRE.test(match[0])) { continue; } if (current.referenced.hasOwnProperty(file)) continue; if (match[2]) { if (current.referenced.hasOwnProperty(file + ".d.ts") || current.referenced.hasOwnProperty(file + ".ts")) continue; if (Fs.existsSync(file + ".ts")) { file += ".ts"; } else if(Fs.existsSync(file + ".d.ts")){ file += '.d.ts'; } else { continue; } } unit = host._resolveCache[file] || new CodeUnit(file); current.references.push(match[1]||match[2]); current.referenced[file] = unit; resolve(unit, host); } host._compiler.addFile(current.path, current.scriptSnapshot, 3, 0, false, current.references); } function C(code, setting) { var setting = normalizerCompilationSetting(setting), __root = setting.root, __file = setting.file, __nodejs = setting.nodejs ; this._setting = TS.ImmutableCompilationSettings.fromCompilationSettings(setting); this._setting.isNodeJs = __nodejs; this._references = []; this._referenced = {}; this._resolveCache = {}; this._compiler = new TS.TypeScriptCompiler(null, this._setting); this._root = __root || Fs.realpathSync("."); var unit = /^[^\n]+\.ts$/i.test(code) ? new CodeUnit(this.resolvePath(code)) : new CodeUnit(__file || "~temp" + (UID++) + ".ts", code); this._references = unit.references; this._referenced = unit.referenced; resolve(unit, this); } var api = C.prototype; api.complie = function(){ var last = null; for (var it = this._compiler.compile(function (path) { return path; }); it.moveNext();) { var result = it.current(); if (result.diagnostics.length) { result.diagnostics.forEach(function(diagnostic){ //process.stderr.write process.stderr.write( diagnostic.message() + "\n\t" + diagnostic.fileName() + "(line:" + diagnostic.line() + ", char:" + diagnostic.start() + ")\n" ); }); return; } last = result; } if (!last) return; return last.outputFiles[last.outputFiles.length - 1].text; }; api.resolvePath = function(path, root) { return Path.resolve(root||this._root, path); }; api.getReferenced = function() { return this._referenced; }; api.setting = function(){ return this._setting; }; return function Compile(code, setting){ var compiler = new C(code, setting, root); return { path : compiler.resolvePath(compiler.setting().outFileOption()), code : compiler.complie(), referenced : compiler.getReferenced(), compiler : compiler } }; }();