UNPKG

systemjs-builder

Version:
261 lines (210 loc) 9.25 kB
var traceur = require('traceur'); var traceurGet = require('../lib/utils').traceurGet; var syntaxDynamicImport = require('babel-plugin-syntax-dynamic-import'); var ParseTreeTransformer = traceurGet('codegeneration/ParseTreeTransformer.js').ParseTreeTransformer; var ModuleSpecifier = traceurGet('syntax/trees/ParseTrees.js').ModuleSpecifier; var createStringLiteralToken = traceurGet('codegeneration/ParseTreeFactory.js').createStringLiteralToken; var InstantiateModuleTransformer = traceurGet('codegeneration/InstantiateModuleTransformer.js').InstantiateModuleTransformer; var extend = require('../lib/utils').extend; // patch pending https://github.com/google/traceur-compiler/pull/2053 var createUseStrictDirective = traceurGet('codegeneration/ParseTreeFactory.js').createUseStrictDirective; InstantiateModuleTransformer.prototype.__proto__.moduleProlog = function() { return [createUseStrictDirective()]; }; var CollectingErrorReporter = traceurGet('util/CollectingErrorReporter.js').CollectingErrorReporter; var UniqueIdentifierGenerator = traceurGet('codegeneration/UniqueIdentifierGenerator.js').UniqueIdentifierGenerator; function TraceurImportNormalizeTransformer(map) { this.map = map; return ParseTreeTransformer.apply(this, arguments); } TraceurImportNormalizeTransformer.prototype = Object.create(ParseTreeTransformer.prototype); TraceurImportNormalizeTransformer.prototype.transformModuleSpecifier = function(tree) { var depName = this.map(tree.token.processedValue) || tree.token.processedValue; return new ModuleSpecifier(tree.location, createStringLiteralToken(depName)); }; exports.TraceurImportNormalizeTransformer = TraceurImportNormalizeTransformer; function remap(source, map, fileName) { var compiler = new traceur.Compiler(); var tree = compiler.parse(source, fileName); tree = new TraceurImportNormalizeTransformer(map).transformAny(tree); return Promise.resolve({ source: compiler.write(tree) }); } exports.remap = remap; // override System instantiate to handle esm tracing exports.attach = function(loader) { var systemInstantiate = loader.instantiate; loader.instantiate = function(load) { // skip plugin loader attachment || non es modules || es modules handled by internal transpilation layer if (!loader.builder || load.metadata.format != 'esm' || load.metadata.originalSource) return systemInstantiate.call(this, load); var depsList = load.metadata.deps.concat([]); var babel = require('babel-core'); var output = babel.transform(load.source, { babelrc: false, compact: false, filename: load.path, //sourceFileName: load.path, inputSourceMap: load.metadata.sourceMap, ast: true, plugins: [syntaxDynamicImport], resolveModuleSource: function(dep) { if (depsList.indexOf(dep) == -1) depsList.push(dep); return dep; } }); // turn back on comments (for some reason!) output.ast.comments.forEach(function(comment) { comment.ignore = false; }); load.metadata.ast = output.ast; return Promise.resolve({ deps: depsList, execute: null }); }; }; var versionCheck = true; exports.compile = function(load, opts, loader) { if (!load.metadata.originalSource || load.metadata.loader && load.metadata.format == 'esm') { var babel = require('babel-core'); var babelOptions = { babelrc: false, compact: false, plugins: [syntaxDynamicImport, [require('babel-plugin-transform-es2015-modules-systemjs'), { systemGlobal: opts.systemGlobal }]], filename: load.path, //sourceFileName: load.path, sourceMaps: !!opts.sourceMaps, inputSourceMap: load.metadata.sourceMap, moduleIds: !opts.anonymous, moduleId: !opts.anonymous && load.name, code: true, resolveModuleSource: function(dep) { if (opts.normalize) return load.depMap[dep]; else return dep; } }; var source = load.metadata.originalSource || load.source; var output; if (load.metadata.ast) output = babel.transformFromAst(load.metadata.ast, source, babelOptions); else output = babel.transform(source, babelOptions); // NB this can be removed with merging of () if (opts.systemGlobal != 'System') output.code = output.code.replace(/(\s|^)System\.register\(/, '$1' + opts.systemGlobal + '.register('); // for some reason Babel isn't respecting sourceFileName... if (output.map && !load.metadata.sourceMap) output.map.sources[0] = load.path; return Promise.resolve({ source: output.code, sourceMap: output.map }); } // ... legacy transpilation, to be deprecated with internal transpilation layer return Promise.resolve(global[loader.transpiler == 'typescript' ? 'ts' : loader.transpiler] || loader.pluginLoader.import(loader.transpiler)) .then(function(transpiler) { if (transpiler.__useDefault) transpiler = transpiler['default']; if (transpiler.Compiler) { var options = loader.traceurOptions || {}; options.modules = 'instantiate'; options.script = false; options.sourceRoot = true; options.moduleName = !opts.anonymous; if (opts.sourceMaps) options.sourceMaps = 'memory'; if (opts.lowResSourceMaps) options.lowResolutionSourceMap = true; if (load.metadata.sourceMap) options.inputSourceMap = load.metadata.sourceMap; var compiler = new transpiler.Compiler(options); var tree = compiler.parse(load.source, load.path); var transformer = new TraceurImportNormalizeTransformer(function(dep) { return opts.normalize ? load.depMap[dep] : dep; }); tree = transformer.transformAny(tree); tree = compiler.transform(tree, load.name); var outputSource = compiler.write(tree, load.path); if (outputSource.match(/\$traceurRuntime/)) load.metadata.usesTraceurRuntimeGlobal = true; return Promise.resolve({ source: outputSource, sourceMap: compiler.getSourceMap() }); } else if (transpiler.createLanguageService) { var options = loader.typescriptOptions || {}; if (options.target === undefined) options.target = transpiler.ScriptTarget.ES5; options.module = transpiler.ModuleKind.System; var transpileOptions = { compilerOptions: options, renamedDependencies: load.depMap, fileName: load.path, moduleName: !opts.anonymous && load.name }; var transpiled = transpiler.transpileModule(load.source, transpileOptions); return Promise.resolve({ source: transpiled.outputText, sourceMap: transpiled.sourceMapText }); } else { if (versionCheck) { var babelVersion = transpiler.version; if (babelVersion.split('.')[0] > 5) console.log('Warning - using Babel ' + babelVersion + '. This version of SystemJS builder is designed to run against Babel 5.'); versionCheck = false; } var options = extend({}, loader.babelOptions || {}); options.modules = 'system'; if (opts.sourceMaps) options.sourceMap = true; if (load.metadata.sourceMap) options.inputSourceMap = load.metadata.sourceMap; options.filename = load.path; options.filenameRelative = load.name; options.sourceFileName = load.path; options.keepModuleIdExtensions = true; options.code = true; options.ast = false; options.moduleIds = !opts.anonymous; options.externalHelpers = true; if (transpiler.version.match(/^4/)) options.returnUsedHelpers = true; else if (transpiler.version.match(/^5\.[01234]\./)) options.metadataUsedHelpers = true; if (opts.normalize) options.resolveModuleSource = function(dep) { return load.depMap[dep] || dep; }; var output = transpiler.transform(load.source, options); var usedHelpers = output.usedHelpers || output.metadata && output.metadata.usedHelpers; if ((!options.optional || options.optional.indexOf('runtime') == -1) && usedHelpers.length) load.metadata.usesBabelHelpersGlobal = true; // pending Babel v5, we need to manually map the helpers if (options.optional && options.optional.indexOf('runtime') != -1) load.deps.forEach(function(dep) { if (dep.match(/^babel-runtime/)) output.code = output.code.replace(dep, load.depMap[dep]); }); // clear options for reuse delete options.filenameRelative; delete options.sourceFileName; return Promise.resolve({ source: output.code, sourceMap: output.map }); } }) .then(function(output) { if (opts.systemGlobal != 'System') output.source = output.source.replace(/System\.register\(/, opts.systemGlobal + '.register('); return output; }); };