pax_global_header00006660000000000000000000000064124602656330014521gustar00rootroot0000000000000052 comment=083207dcb3ed4d91dda07b5086d6556b39c84ad9 es6-module-transpiler-0.10.0/000077500000000000000000000000001246026563300157405ustar00rootroot00000000000000es6-module-transpiler-0.10.0/.editorconfig000066400000000000000000000001501246026563300204110ustar00rootroot00000000000000[*.js] indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true es6-module-transpiler-0.10.0/.gitignore000066400000000000000000000000331246026563300177240ustar00rootroot00000000000000node_modules/ test/results es6-module-transpiler-0.10.0/.jshintrc000066400000000000000000000007131246026563300175660ustar00rootroot00000000000000{ "node" : true, "browser" : false, "boss" : true, "curly": false, "debug": false, "devel": false, "eqeqeq": true, "evil": true, "forin": false, "immed": false, "laxbreak": false, "newcap": true, "noarg": true, "noempty": false, "nonew": false, "nomen": false, "onevar": false, "plusplus": false, "regexp": false, "undef": false, "sub": true, "strict": false, "white": false, "eqnull": true, "esnext": true } es6-module-transpiler-0.10.0/.travis.yml000066400000000000000000000001211246026563300200430ustar00rootroot00000000000000language: node_js node_js: - 0.10 before_install: - npm install -g grunt-cli es6-module-transpiler-0.10.0/AUTHORS000066400000000000000000000000451246026563300170070ustar00rootroot00000000000000Brian Donovan es6-module-transpiler-0.10.0/CHANGELOG.md000066400000000000000000000132631246026563300175560ustar00rootroot00000000000000# Release Notes ## v0.9.5 (2014-11-14) * Fix source maps to include directory names as well as file names. ## v0.9.4 (2014-11-14) * Fix re-exporting module objects created by namespace imports (e.g. `import * as foo from 'foo'; export { foo }`). ## v0.9.3 (2014-11-03) * Fix bundle format support for named exports of class declarations. ## v0.9.2 (2014-11-03) * Add support for exporting ES6 class declarations and expressions. ## v0.9.1 (2014-11-03) * Clarify README to indicate that ES6 module syntax is now stable. * Add `Container#transform` to get transformed code without writing to the file system. ## v0.9.0 (2014-10-22) * Add support for namespace imports (e.g. `import * as foo from 'foo'`). ## v0.8.3 (2014-10-17) * Fixed internal helper `mkdirpSync` that could cause `Container#write` to fail on some machines. ## v0.8.2 (2014-10-15) * Fixed bundle formatter renaming of function or class declarations in export default. Previously they were not properly renamed to prevent collision with other modules. ## v0.8.1 (2014-10-15) * Fixed bundle formatter rewriting identifiers inside named function expressions if the identifier shared a name with a module-scope binding. For example, in this code sample the `a` in `return a` would be rewritten as `mod$$a` when it should have remained `a` (the [fix](https://github.com/benjamn/ast-types/pull/68) was in ast-types). ```js // mod.js var a; var fn = function f() { var a; return a; }; ``` ## v0.8.0 (2014-09-30) * Simplify the CommonJS formatter output to use ES3. ## v0.7.0 (2014-09-30) * Use a common base class for all built-in formatters. * Various internal cleanups. ## v0.6.2 (2014-08-20) * Prevent all instances of export reassignment, not just those at the top level. ## v0.6.1 (2014-08-20) * Reference a custom fork of esprima. * Allow resolvers to set the `Module#src` property to prevent direct file system access. ## v0.6.0 (2014-07-28) * Add support for source maps. * Allow formatters to handle export reassignment. * Update recast to v0.6.6. ## v0.5.1 (2014-06-25) * Fix the file list to be included in npm. ## v0.5.0 (2014-06-24) * Completely re-written using [recast](https://github.com/benjamn/recast). * Removed YUI support, to be re-added as a plugin. * Removed AMD support, to be re-added as a plugin. * Added "bundle" formatter for concatenating all modules together. * Assert on various invalid module syntax usage. ## v0.4.0 (2014-04-03) * Remove trailing whitespace after AMD define (#93) * (**breaking**) Default to anonymous modules for AMD output (use `--infer-name` flag for old behavior). Replaces `--anonymous` flag. ## v0.3.6 (2013-12-16) * Rebuilt & republished to fix regression on quoting `static` property (sorry!) ## v0.3.5 (2013-12-01) * Fixed incorrect module path strings in CJS output (#82) ## v0.3.4 (2013-11-19) * CJS: Build a module object when using `module foo from "foo"` for better forward-compatibility. * Added YUI transpiler, lovingly created & maintained by the YUI team * Fixed `'static'` keyword not being quoted in Esprima, causing issues in some JS runtimes ## v0.3.3 (2013-10-25) * Fix syntax error in CommonJS output with default imports and `compatFix` option ## v0.3.2 (2013-10-18) * Fixes path resolution on the command line (thanks rpflorence!) ## v0.3.1 (2013-10-17) * Use a working commit for Esprima ## v0.3.0 (2013-10-16) This is a **major, breaking version**. See TRANSITION.md for information on upgrading your code. * Rewrote the transpiler using Esprima * Support default exports and named exports in the same module * Default export now exports to `moduleObject.default`, see TRANSITION.md for details * Fixed multiline export parsing * Added support for `module` keyword (i.e. `module foo from "foo"`) * Added support for `import "foo";` form * fixed the `--anonymous` flag with the CLI for recursive transpiling (#20) * Removed relative pathing for AMD resolution & direct CoffeeScript transpilation (see TRANSITION.md) ## v0.2.0 (2013-07-08) * added support for default export (`export default jQuery`) * added support for default import (`import $ from "jquery"`) * added support for re-exporting properties (`export { ajax } from "jquery"`) * removed support for `export =` syntax (use `export default`) * removed support for `import "jquery" as $` (use `import $ from "jquery"`) ## v0.1.3 (2013-06-21) * fixed: import/export statements within block comments are now ignored * added support for `export var foo = …` * added support for `export function foo() { … }` ## v0.1.2 (2013-03-07) * use Grunt for building the project * fixed: use local variables for imports ## v0.1.1 (2013-02-24) * fixed: add missing `--global` option to CLI * documentation and clarifications of examples ## v0.1.0 (2013-02-11) * initial release es6-module-transpiler-0.10.0/LICENSE000066400000000000000000000010531246026563300167440ustar00rootroot00000000000000Copyright 2014 Square Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. es6-module-transpiler-0.10.0/README.md000066400000000000000000000134161246026563300172240ustar00rootroot00000000000000# ES6 Module Transpiler [![Build Status](https://travis-ci.org/esnext/es6-module-transpiler.png)](https://travis-ci.org/esnext/es6-module-transpiler) ES6 Module Transpiler is an experimental compiler that allows you to write your JavaScript using a subset of the ES6 module syntax, and compile it into AMD or CommonJS modules. This compiler provides a way to experiment with ES6 syntax in real world scenarios to see how the syntax holds up. It also provides a nicer, more declarative way to write AMD (or CommonJS) modules. See the [CHANGELOG](./CHANGELOG.md) for the latest updates. ## Usage ### Build tools The easiest way to use the transpiler is from an existing build tool. There several plugins developed for different build tools: * **Grunt:** [grunt-es6-module-transpiler](https://github.com/joefiorini/grunt-es6-module-transpiler), maintained by @joefiorini (not yet compatible with v0.5.x) * **Gulp:** [gulp-es6-module-transpiler](https://github.com/ryanseddon/gulp-es6-module-transpiler), maintained by @ryanseddon * **Brunch:** [es6-module-transpiler-brunch](https://github.com/gcollazo/es6-module-transpiler-brunch), maintained by @gcollazo *(CommonJS only)* (not yet compatible with v0.5.x) * **Broccoli:** [broccoli-es6-concatenator](https://github.com/joliss/broccoli-es6-concatenator), maintained by @joliss (not yet compatible with v0.5.x) * **Mimosa:** [mimosa-es6-module-transpiler](https://github.com/dbashford/mimosa-es6-module-transpiler), maintained by @dbashford (not yet compatible with v0.5.x) * **AMD Formatter:** [es6-module-transpiler-amd-formatter](https://github.com/caridy/es6-module-transpiler-amd-formatter), maintained by @caridy (compatible with v0.5.x+ only) ### Executable The transpiler can be used directly from the command line: ``` $ npm install -g es6-module-transpiler $ compile-modules convert foo.js ``` Here is the basic usage: ``` compile-modules convert -I lib -o out FILE [FILE…] ``` ### Library You can also use the transpiler as a library: ```javascript var transpiler = require('es6-module-transpiler'); var Container = transpiler.Container; var FileResolver = transpiler.FileResolver; var BundleFormatter = transpiler.formatters.bundle; var container = new Container({ resolvers: [new FileResolver(['lib/'])], formatter: new BundleFormatter() }); container.getModule('index'); container.write('out/mylib.js'); ``` ## Supported ES6 Module Syntax ### Named Exports There are two types of exports. *Named exports* like the following: ```javascript // foobar.js var foo = 'foo', bar = 'bar'; export { foo, bar }; ``` This module has two named exports, `foo` and `bar`. You can also write this form as: ```javascript // foobar.js export var foo = 'foo'; export var bar = 'bar'; ``` Either way, another module can then import your exports like so: ```js import { foo, bar } from 'foobar'; console.log(foo); // 'foo' ``` ### Default Exports You can also export a *default* export. For example, an ES6ified jQuery might look like this: ```javascript // jquery.js var jQuery = function() {}; jQuery.prototype = { // ... }; export default jQuery; ``` Then, an app that uses jQuery could import it with: ```javascript import $ from 'jquery'; ``` The default export of the "jquery" module is now aliased to `$`. A default export makes the most sense as a module's "main" export, like the `jQuery` object in jQuery. You can use default and named exports in parallel. ### Other Syntax #### `import "foo";` A "bare import" that doesn't import any identifiers is useful for executing side effects in a module. For example: ```js // alerter.js alert("alert! alert!"); // alertee.js import "alerter"; // will pop up alert box ``` ## Compiled Output ### Default Exports This is super important: **Default exports bind to an identifier on the module called `default`!** Internally, the transpiler will use this default identifer when importing, but any outside consumer needs to be aware that it should use the `default` key and not the module itself. For example, a CommonJS consumer should look like this: ```js var $ = require('jquery')['default']; ``` ## Installation Add this project to your application's package.json by running this: $ npm install --save es6-module-transpiler Or install it globally: $ npm install -g es6-module-transpiler ## Acknowledgements Thanks to [Yehuda Katz](https://twitter.com/wycats) for [js_module_transpiler](https://github.com/wycats/js_module_transpiler), the library on which this one is based. Thanks to [Dave Herman](https://twitter.com/littlecalculist) for his work on ES6 modules. Thanks to [Erik Bryn](https://twitter.com/ebryn) for providing the initial push to write this library. Thanks to [Domenic Denicola](https://twitter.com/domenic), [Jo Liss](https://twitter.com/jo_liss), & [Thomas Boyt](https://twitter.com/thomasaboyt) for their efforts to make this project even better. And finally thanks to the JavaScript community at Square for helping to write and release this library. ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request Any contributors to the master es6-module-transpiler repository must sign the [Individual Contributor License Agreement (CLA)][cla]. It's a short form that covers our bases and makes sure you're eligible to contribute. [cla]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1 When you have a change you'd like to see in the master repository, [send a pull request](https://github.com/esnext/es6-module-transpiler/pulls). Before we merge your request, we'll make sure you're in the list of people who have signed a CLA. Thanks, and enjoy living in the ES6 future! es6-module-transpiler-0.10.0/TRANSITION.md000066400000000000000000000066251246026563300177650ustar00rootroot00000000000000# Transitioning from 0.4.x to 0.5.x ## API Changes The API has completely changed. We still allow transpiling to CommonJS, but any of the other previously supported formats have been removed. Each output format is handled by a "formatter", and 3rd-party formatters may be used by using the `--format` option in the CLI or initialing a `Container` with a particular `formatter` when using as a library. ## Command-line changes The transpiler still has a CLI, but it is structured completely differently. See `compile-modules -h` for details. ## Spec compilance ### Bindings In order to comply with the spec, this project now supports mutable bindings. For example, given this: ```js export var count = 0; export function incr() { count++; } ``` And when it's imported, this will work: ```js import { count, incr } from './count'; assert.equal(count, 0); incr(); assert.equal(count, 1); ``` ### Circular References Cycles now work properly. Note that not all cases of cycles can be properly handled - this is simply the nature of cycles. For example, this works: ```js // a.js import { b } from './b'; export function a(n) { if (n % 2 === 0) { return b(n); } else { return n + 1; } } // b.js import { a } from './a'; export function b(n) { if (n % 2 === 0) { return n; } else { return a(n); } } ``` This works because neither `a` nor `b` uses the other until sometime "later". This second example will not work: ```js // a.js import { b } from './b'; export var a = b; // b.js import { a } from './a'; export var b = a; ``` This is a contrived example, obviously, but many more complicated examples boil down to this same thing. # Transitioning from 0.2.x to 0.3.x ## default export changes ### Spec changes `export default foo;` has been removed in favor of `export default = foo`. ### Internal changes In 0.2.x, the default export was the module's only export. Now, it's internally a named export called `default`: ```js // es6 export default bar; //cjs exports.default = bar; // es6 import bar from "bar"; // cjs var bar = require("bar").default; ``` This means that your "entry point" - anywhere you're importing the transpiled output from AMD or CJS - needs to explicitly import `default`. For example, if your AMD app was using ES6-built Handlebars, you would need to do: ```js define("my-module", ["handlebars"], function (handlebars) { var handlebars = handlebars.default; }) ``` ## New features you should use * Multi line exports! ```js export default = { foo: "\n to your heart's content!" }; ``` * Module keyword! ```js module foo from "foo"; var namedExport = foo.namedExport; ``` * Mixed default/named exports! ```js export default = "foo"; export var bar = "bar"; ``` * Bare imports! ```js // executes side effects in "foo" but doesn't import anything import "foo"; ``` ## Old features you can no longer use * Relative pathing in AMD modules has been removed, as it was broken, hacky, and made people sad. * CoffeeScript support is removed, sort of. If you're using **the original CoffeeScript compiler**, you can use JS passthrough: ```coffeescript foo = "look at this elegant coffeescript!" ` // now we're in sad curly-brace land export default = foo; ` ``` You'll then want to transpile your modules using the compiled JS as a base. Unfortunately, **this doesn't work with CoffeeScript Redux (or EmberScript)**, because that compiler wraps pass-through in an `eval` call. es6-module-transpiler-0.10.0/bin/000077500000000000000000000000001246026563300165105ustar00rootroot00000000000000es6-module-transpiler-0.10.0/bin/compile-modules000077500000000000000000000035041246026563300215360ustar00rootroot00000000000000#!/usr/bin/env node var Path = require('path'); var exe = Path.basename(process.argv[1]); var getopt = require('posix-getopt'); var parser = new getopt.BasicParser('h(help)v(version)', process.argv); var option; function usage(puts) { puts(exe + ' [--help] [--version] []'); puts(); puts('Commands'); puts(); puts(' convert Converts modules from `import`/`export` to an ES5 equivalent.'); puts(' help Display help for a given command.'); } function makeWriteLine(stream) { return function(line) { if (!line || line[line.length - 1] !== '\n') { line = (line || '') + '\n'; } stream.write(line); }; } var puts = makeWriteLine(process.stdout); var eputs = makeWriteLine(process.stderr); while ((option = parser.getopt()) !== undefined) { if (option.error) { usage(eputs); process.exit(1); } switch (option.option) { case 'h': usage(puts); process.exit(0); break; case 'v': puts(exe + ' v' + require(Path.join(__dirname, '../package.json')).version); process.exit(0); break; } } var args = process.argv; var offset = parser.optind(); var commandName = args[offset]; if (commandName === 'help') { commandName = args[offset + 1]; args = ['--help'].concat(args.slice(offset + 2 /* skip 'help' and command name */)); } else { args = args.slice(offset + 1); } if (typeof commandName !== 'string') { usage(puts); process.exit(1); } var command; try { command = require(Path.join('../lib/cli', commandName)); } catch (ex) { usage(eputs); process.exit(1); } try { var exitCode = command.run(args, puts, eputs); process.exit(exitCode); } catch (ex) { if (ex.constructor.name === 'AssertionError') { eputs('error: ' + exe + ' ' + commandName + ' -- ' + ex.message); process.exit(1); } else { throw ex; } } es6-module-transpiler-0.10.0/lib/000077500000000000000000000000001246026563300165065ustar00rootroot00000000000000es6-module-transpiler-0.10.0/lib/browser/000077500000000000000000000000001246026563300201715ustar00rootroot00000000000000es6-module-transpiler-0.10.0/lib/browser/capture_stack_trace_polyfill.js000066400000000000000000000042311246026563300264470ustar00rootroot00000000000000var DEFAULT_STACK_TRACE_LIMIT = 10; // Polyfill Error.captureStackTrace, which exists only in v8 (Chrome). This is // used in depd, which is used by ast-types. if (!Error.captureStackTrace) { /** * Adds a 'stack' property to the given object with stack info. * * @param obj * @returns {Error.stack|*} */ Error.captureStackTrace = function(obj) { var stack = new Error().stack; var prepare = Error.prepareStackTrace; if (prepare) { stack = prepare(stack, parseStack(stack)); } obj.stack = stack; }; } if (typeof Error.stackTraceLimit === 'undefined') { Error.stackTraceLimit = DEFAULT_STACK_TRACE_LIMIT; } /** * Parse a formatted stack string into an array of call sites. * * @param {string} stack * @returns {Array.} */ function parseStack(stack) { return stack.split('\n').slice(0, Error.stackTraceLimit).map(CallSite.parse); } /** * Represents a call site in a stack trace. * * @param {string} fnName * @param {string} fileName * @param {number} lineNumber * @param {number} columnNumber * @param {boolean} isEval * @param {string} evalOrigin * @constructor */ function CallSite(fnName, fileName, lineNumber, columnNumber, isEval, evalOrigin) { this.getFunctionName = function() { return fnName; }; this.getFileName = function() { return fileName; }; this.getLineNumber = function() { return lineNumber; }; this.getColumnNumber = function() { return columnNumber; }; this.isEval = function() { return isEval; }; this.getEvalOrigin = function() { return evalOrigin; }; } /** * Parses a line in a formatted stack trace and returns call site info. * * @param {string} stackTraceLine * @returns {CallSite} */ CallSite.parse = function(stackTraceLine) { var fnNameAndLocation = stackTraceLine.split('@'); var fnName = fnNameAndLocation[0]; var location = fnNameAndLocation[1]; var fileAndLineAndColumn = location ? location.split(':') : []; var fileName = fileAndLineAndColumn[0]; var lineNumber = parseInt(fileAndLineAndColumn[1], 10); var columnNumber = parseInt(fileAndLineAndColumn[2], 10); return new CallSite(fnName, fileName, lineNumber, columnNumber, fnName === 'eval', ''); }; es6-module-transpiler-0.10.0/lib/browser/fs.js000066400000000000000000000001211246026563300211310ustar00rootroot00000000000000var Fs = require('fake-fs'); var fs = new Fs(); fs.patch(); module.exports = fs; es6-module-transpiler-0.10.0/lib/browser/index.js000066400000000000000000000012241246026563300216350ustar00rootroot00000000000000// Polyfill process.umask() since browserify doesn't add it (yet). // Remove it once https://github.com/defunctzombie/node-process/pull/22 is // merged and included in browserify. process.umask = function() { return 0; }; require('./capture_stack_trace_polyfill'); var Container = require('../container'); var FileResolver = require('../file_resolver'); var formatters = require('../formatters'); var Module = require('../module'); exports.FileResolver = FileResolver; exports.Container = Container; exports.formatters = formatters; exports.Module = Module; // Export the fake filesystem so someone can get stuff in and out. exports.fs = require('./fs'); es6-module-transpiler-0.10.0/lib/cli/000077500000000000000000000000001246026563300172555ustar00rootroot00000000000000es6-module-transpiler-0.10.0/lib/cli/convert.js000066400000000000000000000112471246026563300213000ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var fs = require('fs'); var assert = require('assert'); var Path = require('path'); var recast = require('recast'); var formatters = require('../formatters'); var Container = require('../container'); var FileResolver = require('../file_resolver'); var getopt = require('posix-getopt'); var exe = Path.basename(process.argv[1]); exports.run = function(args, puts, eputs) { var offset = 0; var files = []; var includePaths = [process.cwd()]; var output; var formatter = formatters[formatters.DEFAULT]; var resolverClasses = [FileResolver]; while (offset < args.length) { var parser = new getopt.BasicParser('h(help)o:(output)I:(include)f:(format)r:(resolver)', ['', ''].concat(args.slice(offset))); var option; while ((option = parser.getopt()) !== undefined) { if (option.error) { usage(eputs); return 1; } switch (option.option) { case 'h': usage(puts); return 0; case 'o': output = option.optarg; break; case 'I': includePaths.push(option.optarg); break; case 'f': formatter = formatters[option.optarg]; if (!formatter) { try { formatter = require(option.optarg); } catch (ex) {} } if (!formatter) { eputs('Cannot find formatter for ' + option.optarg); usage(eputs); return 1; } break; case 'r': try { var resolverPath = option.optarg; if (fs.existsSync(resolverPath)) { resolverClasses.push(require(Path.join(process.cwd(), resolverPath))); } else { resolverClasses.push(require(option.optarg)); } } catch (ex) { eputs('Error reading resolver ' + option.optarg + ': ' + ex); usage(eputs); return 1; } break; } } for (offset += parser.optind() - 2; args[offset] && args[offset][0] !== '-'; offset++) { files.push(args[offset]); } } assert.ok( files.length > 0, 'Please provide at least one file to convert.' ); if (typeof formatter === 'function') { formatter = new formatter(); } var resolvers = resolverClasses.map(function(resolverClass) { return new resolverClass(includePaths); }); var container = new Container({ formatter: formatter, resolvers: resolvers }); files.forEach(function(file) { container.getModule(file); }); if (output) { container.write(output); } else { var outputs = container.convert(); assert.equal( outputs.length, 1, 'Cannot output ' + outputs.length + ' files to stdout. ' + 'Please use the --output flag to specify where to put the ' + 'files or choose a formatter that concatenates.' ); process.stdout.write(recast.print(outputs[0]).code); } }; function bold(string) { return '\x1b[01m' + string + '\x1b[0m'; } function usage(puts) { puts(exe + ' convert [-I ] [-o ] [-f ] [-r ] [ ...]'); puts(); puts(bold('Description')); puts(); puts(' Converts the given modules by changing `import`/`export` statements to an ES5 equivalent.'); puts(); puts(bold('Options')); puts(); puts(' -I, --include Check the given path for imported modules (usable multiple times).'); puts(' -o, --output File or directory to output converted files.'); puts(' -f, --format Path to custom formatter or choose from built-in formats.'); puts(' -r, --resolver Path to custom resolver (usable multiple times).'); puts(' -h, --help Show this help message.'); puts(); puts(bold('Formats')); puts(); puts(' commonjs - convert modules to files using CommonJS `require` and `exports` objects.'); puts(' bundle - concatenate modules into a single file.'); puts(); puts(' You may provide custom a formatter by passing the path to your module to the `--format` option. See the'); puts(' source of any of the built-in formatters for details on how to build your own.'); puts(); puts(bold('Resolvers')); puts(); puts(' Resolvers resolve import paths to modules. The default resolver will search the include paths provided'); puts(' by `--include` arguments and the current working directory. To provide custom resolver logic, pass the'); puts(' path to your resolver module providing a `resolveModule` function or class with an instance method with'); puts(' this signature: `resolveModule(importedPath:String, fromModule:?Module, container:Container): Module`.'); } es6-module-transpiler-0.10.0/lib/container.js000066400000000000000000000127431246026563300210350ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var Path = require('path'); var Rewriter = require('./rewriter'); var Writer = require('./writer'); var recast = require('recast'); /** @typedef {{resolveModule: function(string, Module, Container): Module}} */ var Resolver; /** * Represents a container of modules for the given options. * * @constructor * @param {{resolvers: Resolver[], formatter: Formatter}} options */ function Container(options) { options = options || {}; var formatter = options.formatter; if (typeof formatter === 'function') { formatter = new formatter(); } assert.ok( formatter, 'missing required option `formatter`' ); var resolvers = options.resolvers; assert.ok( resolvers && resolvers.length > 0, 'at least one resolver is required' ); resolvers.forEach(function(resolver) { assert.equal( typeof resolver.resolveModule, 'function', '`resolver` must have `resolveModule` function: ' + resolver ); }); Object.defineProperties(this, { modules: { value: Object.create(null) }, formatter: { value: formatter }, resolvers: { value: resolvers }, options: { value: options }, basePath: { value: options.basePath || process.cwd() }, sourceRoot: { value: options.sourceRoot || '/' } }); } /** * Gets a module by resolving `path`. If `path` is resolved to the same path * as a previous call, the same object will be returned. * * @param {string} importedPath * @param {Module=} fromModule * @return {Module} */ Container.prototype.getModule = function(importedPath, fromModule) { for (var i = 0, length = this.resolvers.length; i < length; i++) { var resolvedModule = this.resolvers[i].resolveModule( importedPath, fromModule, this ); if (resolvedModule) { this.addModule(resolvedModule); return resolvedModule; } } throw new Error( 'missing module import' + (fromModule ? ' from ' + fromModule.relativePath : '') + ' for path: ' + importedPath ); }; /** * Adds a module to the internal cache and gives it a unique name. * * @private * @param {Module} mod */ Container.prototype.addModule = function(mod) { if (mod.path in this.modules) { return; } if (this._convertResult) { throw new Error( 'container has already converted contained modules ' + 'and cannot add new module: ' + mod.path ); } // We have not seen this module before, so let's give it a unique name. var modules = this.getModules(); var name = mod.name; var baseName = name; var counter = 0; var nameExists; while (true) { nameExists = modules.some(function(existingModule) { return existingModule.name === name; }); if (!nameExists) { break; } else { counter++; name = baseName + counter; } } mod.name = name; delete mod.id; this.modules[mod.path] = mod; }; /** * Get a cached module by a resolved path. * * @param {string} resolvedPath * @return {?Module} */ Container.prototype.getCachedModule = function(resolvedPath) { return this.modules[resolvedPath]; }; /** * Writes the contents of this container to the given path. * * @param {string} target */ Container.prototype.write = function(target) { if (!this._convertResult) { this._convertResult = this.convert(); } var files = this._convertResult; var writer = new Writer(target, { sourceRoot: this.sourceRoot, basePath: this.basePath }); writer.write(files); }; /** * Translate and return the contents of this container. * * @return {{filename: string, code: string, map: object}[]} */ Container.prototype.transform = function() { if (!this._convertResult) { this._convertResult = this.convert(); } var files = this._convertResult; var codes = []; files.forEach(function(file) { var rendered = recast.print(file, { sourceMapName: Path.relative(this.basePath, file.filename), sourceRoot: this.sourceRoot }); var code = rendered.code; var map = rendered.map; codes.push({ filename: file.filename, code: code, map: map }); }, this); return codes; }; /** * Converts the contents of this container using the current formatter. * * @return {File[]} */ Container.prototype.convert = function() { if (this.formatter.beforeConvert) { this.formatter.beforeConvert(this); } var modules = this.getModules(); var rewriter = new Rewriter(this.formatter); rewriter.rewrite(modules); var formatter = this.formatter; return formatter.build(modules); }; /** * Follows all imports/exports looking for new modules to add to this container. */ Container.prototype.findImportedModules = function() { var knownModules; var lastModuleCount = 0; while ((knownModules = this.getModules()).length !== lastModuleCount) { lastModuleCount = knownModules.length; for (var i = 0; i < lastModuleCount; i++) { // Force loading of imported modules. noop(knownModules[i].imports.modules); } } }; /** * Gets the modules in this container in no particular order. * * @return {Module[]} */ Container.prototype.getModules = function() { var modules = this.modules; return Object.keys(modules).map(function(key) { return modules[key]; }); }; /** * Does nothing. This is only here to make JSHint/other static analysis * tools happy about using getters for side effects. */ function noop() {} module.exports = Container; es6-module-transpiler-0.10.0/lib/declaration_info.js000066400000000000000000000044421246026563300223500ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var recast = require('recast'); var types = recast.types; var n = types.namedTypes; /** * Represents information about a declaration that creates a local binding * represented by `identifier`. For example, given that `declaration` is the * following variable declaration: * * var a = 1; * * Then `identifier` references the `a` node in the variable declaration's * first declarator. Likewise, given that `declaration` is this function * declaration: * * function add(a, b) {} * * Then `identifier` references the `add` node, the declaration's `id`. * * @constructor * @param {Node} declaration * @param {Identifier} identifier */ function DeclarationInfo(declaration, identifier) { /** * @type {Node} * @name DeclarationInfo#declaration */ this.declaration = declaration; /** * @type {Identifier} * @name DeclarationInfo#identifier */ this.identifier = identifier; } /** * Get the declaration info for the given identifier path, if the identifier is * actually part of a declaration. * * @param {NodePath} identifierPath * @return {?DeclarationInfo} */ DeclarationInfo.forIdentifierPath = function(identifierPath) { if (n.VariableDeclarator.check(identifierPath.parent.node)) { return new DeclarationInfo( identifierPath.parent.parent.node, identifierPath.node ); } else if (n.ClassDeclaration.check(identifierPath.parent.node)) { return new DeclarationInfo( identifierPath.parent.node, identifierPath.node ); } else if (n.FunctionDeclaration.check(identifierPath.parent.node)) { return new DeclarationInfo( identifierPath.parent.node, identifierPath.node ); } else if (n.ImportSpecifier.check(identifierPath.parent.node)) { return new DeclarationInfo( identifierPath.parent.parent.node, identifierPath.node ); } else if (n.ImportNamespaceSpecifier.check(identifierPath.parent.node)) { return new DeclarationInfo( identifierPath.parent.parent.node, identifierPath.node ); } else if (n.ImportDefaultSpecifier.check(identifierPath.parent.node)) { return new DeclarationInfo( identifierPath.parent.parent.node, identifierPath.node ); } else { return null; } }; module.exports = DeclarationInfo; es6-module-transpiler-0.10.0/lib/exports.js000066400000000000000000000235041246026563300205540ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var ModuleBindingList = require('./module_binding_list'); var ModuleBindingDeclaration = require('./module_binding_declaration'); var ModuleBindingSpecifier = require('./module_binding_specifier'); var DeclarationInfo = require('./declaration_info'); var utils = require('./utils'); var memo = utils.memo; var extend = utils.extend; var sourcePosition = utils.sourcePosition; /** * Represents a list of the exports for the given module. * * @constructor * @extends ModuleBindingList * @param {Module} mod */ function ExportDeclarationList(mod) { ModuleBindingList.call(this, mod); } extend(ExportDeclarationList, ModuleBindingList); /** * @private * @param {AST.Declaration} node * @return {boolean} */ ExportDeclarationList.prototype.isMatchingBinding = function(node) { return n.ExportDeclaration.check(node); }; /** * Gets an export declaration for the given `node`. * * @private * @param {AST.ExportDeclaration} node * @return {ExportDeclaration} */ ExportDeclarationList.prototype.declarationForNode = function(node) { if (node.default) { return new DefaultExportDeclaration(this.module, node); } else if (n.VariableDeclaration.check(node.declaration)) { return new VariableExportDeclaration(this.module, node); } else if (n.FunctionDeclaration.check(node.declaration)) { return new FunctionExportDeclaration(this.module, node); } else if (n.ClassDeclaration.check(node.declaration)) { return new ClassExportDeclaration(this.module, node); } else if (n.ExportBatchSpecifier.check(node.specifiers[0])) { throw new Error( '`export *` found at ' + sourcePosition(this.module, node) + ' is not supported, please use `export { … }` instead' ); } else { return new NamedExportDeclaration(this.module, node); } }; /** * @param {NodePath} referencePath * @return {?ExportSpecifier} */ ExportDeclarationList.prototype.findSpecifierForReference = function(referencePath) { if (n.ExportSpecifier.check(referencePath.parent.node) && referencePath.parent.parent.node.source) { // This is a direct export from another module, e.g. `export { foo } from 'foo'`. return /** @type {ExportSpecifier} */this.findSpecifierByIdentifier(referencePath.node); } var declaration = this.findDeclarationForReference(referencePath); if (!declaration) { return null; } var specifier = /** @type {ExportSpecifier} */this.findSpecifierByName(declaration.node.name); assert.ok( specifier, 'no specifier found for `' + referencePath.node.name + '`! this should not happen!' ); return specifier; }; /** * Contains information about an export declaration. * * @constructor * @abstract * @extends ModuleBindingDeclaration * @param {Module} mod * @param {ExportDeclaration} node */ function ExportDeclaration(mod, node) { assert.ok( n.ExportDeclaration.check(node), 'expected an export declaration, got ' + (node && node.type) ); ModuleBindingDeclaration.call(this, mod, node); } extend(ExportDeclaration, ModuleBindingDeclaration); /** * Returns a string description suitable for debugging. * * @return {string} */ ExportDeclaration.prototype.inspect = function() { return recast.print(this.node).code; }; /** * @see ExportDeclaration#inspect */ ExportDeclaration.prototype.toString = ExportDeclaration.prototype.inspect; /** * Represents an export declaration of the form: * * export default foo; * * @constructor * @extends ExportDeclaration * @param {Module} mod * @param {AST.ExportDeclaration} node */ function DefaultExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); } extend(DefaultExportDeclaration, ExportDeclaration); /** * Contains a list of specifier name information for this export. * * @type {ExportSpecifier[]} * @name DefaultExportSpecifier#specifiers */ memo(DefaultExportDeclaration.prototype, 'specifiers', /** @this DefaultExportDeclaration */function() { var specifier = new DefaultExportSpecifier(this, this.node.declaration); return [specifier]; }); /** * Represents an export declaration of the form: * * export { foo, bar }; * * @constructor * @extends ExportDeclaration * @param {Module} mod * @param {AST.ExportDeclaration} node */ function NamedExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); } extend(NamedExportDeclaration, ExportDeclaration); /** * Contains a list of specifier name information for this export. * * @type {ExportSpecifier[]} * @name NamedExportDeclaration#specifiers */ memo(NamedExportDeclaration.prototype, 'specifiers', /** @this NamedExportDeclaration */function() { var self = this; return this.node.specifiers.map(function(specifier) { return new ExportSpecifier(self, specifier); }); }); /** * Represents an export declaration of the form: * * export var foo = 1; * * @constructor * @extends ExportDeclaration * @param {Module} mod * @param {AST.ExportDeclaration} node */ function VariableExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); } extend(VariableExportDeclaration, ExportDeclaration); /** * Gets the list of export specifiers for this declaration. * * @type {ExportSpecifier[]} * @name VariableExportDeclaration#specifiers */ memo(VariableExportDeclaration.prototype, 'specifiers', /** @this VariableExportDeclaration */function() { var self = this; return this.node.declaration.declarations.map(function(declarator) { return new ExportSpecifier(self, declarator); }); }); /** * Represents an export declaration of the form: * * export class Foo {} * * @constructor * @extends ExportDeclaration * @param {Module} mod * @param {AST.ExportDeclaration} node */ function ClassExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); } extend(ClassExportDeclaration, ExportDeclaration); /** * Gets the list of export specifiers for this declaration. * * @type {ExportSpecifier[]} * @name ClassExportDeclaration#specifiers */ memo(ClassExportDeclaration.prototype, 'specifiers', /** @this ClassExportDeclaration */function() { return [new ExportSpecifier(this, this.node.declaration)]; }); /** * Represents an export declaration of the form: * * export function foo() {} * * @constructor * @extends ExportDeclaration * @param {Module} mod * @param {AST.ExportDeclaration} node */ function FunctionExportDeclaration(mod, node) { ExportDeclaration.call(this, mod, node); } extend(FunctionExportDeclaration, ExportDeclaration); /** * Gets the list of export specifiers for this declaration. * * @type {ExportSpecifier[]} * @name FunctionExportDeclaration#specifiers */ memo(FunctionExportDeclaration.prototype, 'specifiers', /** @this FunctionExportDeclaration */function() { return [new ExportSpecifier(this, this.node.declaration)]; }); /** * Represents an export specifier in an export declaration. * * @constructor * @extends ModuleBindingSpecifier * @param {ExportDeclaration} declaration * @param {AST.Node} node */ function ExportSpecifier(declaration, node) { ModuleBindingSpecifier.call(this, declaration, node); } extend(ExportSpecifier, ModuleBindingSpecifier); /** * Contains the local declaration info for this export specifier. For example, * in this module: * * var a = 1; * export { a }; * * The module declaration info for the `a` export specifier is the variable * declaration plus the `a` identifier in its first declarator. * * @type {?DeclarationInfo} * @name ExportSpecifier#moduleDeclaration */ memo(ExportSpecifier.prototype, 'moduleDeclaration', /** @this ExportSpecifier */function() { if (this.declaration.source) { // This is part of a direct export, e.g. `export { ... } from '...'`, so // there is no declaration as part of this module. return null; } var bindings = this.moduleScope.getBindings(); var identifierPaths = bindings[this.from]; assert.ok( identifierPaths && identifierPaths.length === 1, 'expected exactly one declaration for export `' + this.from + '` at ' + sourcePosition(this.module, this.node) + ', found ' + (identifierPaths ? identifierPaths.length : 'none') ); var identifierPath = identifierPaths[0]; var declarationInfo = DeclarationInfo.forIdentifierPath(identifierPath); assert.ok( declarationInfo, 'cannot detect declaration for `' + identifierPath.node.name + '`, found parent.type `' + identifierPath.parent.node.type + '`' ); return declarationInfo; }); /** * Represents an export specifier in a default export declaration. * * @constructor * @extends ExportSpecifier * @param {ExportDeclaration} declaration * @param {AST.Expression} node */ function DefaultExportSpecifier(declaration, node) { ExportSpecifier.call(this, declaration, node); } extend(DefaultExportSpecifier, ExportSpecifier); /** * The node of a default export specifier is an expression, not a specifier. * * @type {AST.Expression} */ DefaultExportSpecifier.prototype.node = null; /** * Default export specifier names are always "default". * * @type {string} * @name DefaultExportSpecifier#name * @default "default" */ DefaultExportSpecifier.prototype.name = 'default'; /** * Default export specifiers do not bind to a local identifier. * * @type {?Identifier} * @name DefaultExportSpecifier#identifier * @default null */ DefaultExportSpecifier.prototype.identifier = null; /** * Default export specifiers do not have a local bound name. * * @type {?string} * @name DefaultExportSpecifier#from * @default null */ DefaultExportSpecifier.prototype.from = null; /** * Default export specifiers do not have a local declaration. * * @type {?DeclarationInfo} * @name DefaultExportSpecifier#moduleDeclaration * @default null */ DefaultExportSpecifier.prototype.moduleDeclaration = null; module.exports = ExportDeclarationList; es6-module-transpiler-0.10.0/lib/file_resolver.js000066400000000000000000000042001246026563300217000ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var Path = require('path'); var fs = require('fs'); var Module = require('./module'); /** * Provides resolution of absolute paths from module import sources. * * @constructor */ function FileResolver(paths) { assert.ok( paths && paths.length > 0, 'missing required argument `paths`' ); this.paths = paths.map(function(path) { return Path.resolve(path); }); } /** * Resolves `importedPath` imported by the given module `fromModule` to a * module. * * @param {string} importedPath * @param {?Module} fromModule * @param {Container} container * @return {?Module} */ FileResolver.prototype.resolveModule = function(importedPath, fromModule, container) { var resolvedPath = this.resolvePath(importedPath, fromModule); if (resolvedPath) { var cachedModule = container.getCachedModule(resolvedPath); if (cachedModule) { return cachedModule; } else { if (!Path.extname(importedPath)) { importedPath += Path.extname(resolvedPath); } return new Module(resolvedPath, importedPath, container); } } else { return null; } }; /** * Resolves `importedPath` against the importing module `fromModule`, if given, * within this resolver's paths. * * @private * @param {string} importedPath * @param {?Module} fromModule * @return {string} */ FileResolver.prototype.resolvePath = function(importedPath, fromModule) { var paths = this.paths; if (importedPath[0] === '.' && fromModule) { paths = [Path.dirname(fromModule.path)]; } for (var i = 0, length = paths.length; i < length; i++) { var includePath = paths[i]; var resolved = Path.resolve(includePath, importedPath); if (!~resolved.lastIndexOf('.')) { resolved += '.js'; } if (fs.existsSync(resolved)) { return resolved; } // edge cases when a module may have dotted filename, i.e. jquery.min.js // and the module name is passed without the extension resolved += '.js'; if (fs.existsSync(resolved)) { return resolved; } } return null; }; module.exports = FileResolver; es6-module-transpiler-0.10.0/lib/formatters.js000066400000000000000000000003071246026563300212320ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ exports.DEFAULT = 'bundle'; exports.bundle = require('./formatters/bundle_formatter'); exports.commonjs = require('./formatters/commonjs_formatter'); es6-module-transpiler-0.10.0/lib/formatters/000077500000000000000000000000001246026563300206745ustar00rootroot00000000000000es6-module-transpiler-0.10.0/lib/formatters/bundle_formatter.js000066400000000000000000000312211246026563300245650ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var recast = require('recast'); var types = recast.types; var b = types.builders; var n = types.namedTypes; var Replacement = require('../replacement'); var utils = require('../utils'); var IIFE = utils.IIFE; var extend = utils.extend; var sort = require('../sorting').sort; var Formatter = require('./formatter'); /** * The 'bundle' formatter aims to increase the compressibility of the generated * source, especially by tools such as Google Closure Compiler or UglifyJS. * For example, given these modules: * * ```js * // a.js * import { b } from './b'; * console.log(b); * * // b.js * export var b = 3; * export var b2 = 6; * ``` * * The final output will be a single file looking something like this: * * ```js * (function() { * "use strict"; * // b.js * var b$$b = 3; * var b$$b2 = 6; * * // a.js * console.log(b$$b); * }).call(this); * ``` * * @constructor */ function BundleFormatter() { Formatter.call(this); } extend(BundleFormatter, Formatter); /** * This hook is called by the container before it converts its modules. We use * it to ensure all of the imports are included because we need to know about * them at compile time. * * @param {Container} container */ BundleFormatter.prototype.beforeConvert = function(container) { container.findImportedModules(); // Cache all the import and export specifier names. container.getModules().forEach(function(mod) { [mod.imports, mod.exports].forEach(function(bindingList) { bindingList.declarations.forEach(function (declaration) { declaration.specifiers.forEach(function (specifier) { specifier.name; }); }); }); }); }; /** * @override */ BundleFormatter.prototype.build = function(modules) { modules = sort(modules); return [b.file(b.program([b.expressionStatement(IIFE( b.expressionStatement(b.literal('use strict')), this.buildNamespaceImportObjects(modules), modules.length === 1 ? modules[0].ast.program.body : modules.reduce(function(statements, mod) { return statements.concat(mod.ast.program.body); }, []) ))]))]; }; /** * Builds a variable declaration that contains declarations of all the namespace * objects required by `import * as foo from 'foo'` statements. * * @private * @param {Module[]} modules * @return {?AST.VariableDeclaration} */ BundleFormatter.prototype.buildNamespaceImportObjects = function(modules) { var self = this; var namespaceImportedModules = []; // Collect all the modules imported using a namespace import declaration. modules.forEach(function(mod) { mod.imports.namespaceImports.forEach(function(namespaceImportDeclaration) { var namespaceImportedModule = namespaceImportDeclaration.source; if (namespaceImportedModules.indexOf(namespaceImportedModule) < 0) { namespaceImportedModules.push(namespaceImportedModule); } }); }); if (namespaceImportedModules.length === 0) { return null; } /** * Builds a variable declarator for the given module whose initial value is an * object with properties for each export from the module being imported. For * example, given a module "foo" with exports "a" and "b" this object will be * created: * * foo$$ = { * get a() { * return foo$$a; * }, * * get b() { * return foo$$b; * } * } * * @param {Module} mod * @returns {AST.VariableDeclarator} */ function createDeclaratorForModule(mod) { return b.variableDeclarator( b.identifier(mod.id), b.objectExpression( mod.exports.declarations.reduce(function(props, exportDeclaration) { exportDeclaration.specifiers.forEach(function(specifier) { props.push(createGetterForSpecifier(mod, specifier)); }); return props; }, []) ) ); } /** * Builds a getter property for retrieving the value of the given export * specifier at the time it is accessed. For example, given a module "foo" * with export specifier "a" this property will be created: * * get a() { * return foo$$a; * } * * @param {Module} mod * @param {ExportSpecifier} specifier * @returns {AST.Property} */ function createGetterForSpecifier(mod, specifier) { return b.property( 'get', b.identifier(specifier.name), b.functionExpression( null, [], b.blockStatement([ b.returnStatement(self.reference(mod, specifier.name)) ]) ) ); } return b.variableDeclaration( 'var', namespaceImportedModules.map(createDeclaratorForModule) ); }; /** * @override * * ```js * export default * // or * export default ; * ``` */ BundleFormatter.prototype.defaultExport = function(mod, declaration) { if (n.FunctionDeclaration.check(declaration) || n.ClassDeclaration.check(declaration)) { // export default function foo () {} // -> becomes: // function foo () {} // var default = foo; var renamedDeclaration = Object.create(declaration); renamedDeclaration.id = this.reference(mod, declaration.id); return [ renamedDeclaration, b.variableDeclaration( 'var', [b.variableDeclarator( this.reference(mod, 'default'), this.reference(mod, declaration.id) )] ) ]; } return b.variableDeclaration( 'var', [b.variableDeclarator( this.reference(mod, 'default'), declaration )] ); }; /** * Get a reference to the original exported value referenced in `mod` at * `referencePath`. If the given reference path does not correspond to an * export, we do not need to rewrite the reference. For example, since `value` * is not exported it does not need to be rewritten: * * ```js * // a.js * var value = 99; * console.log(value); * ``` * * If `value` was exported then we would need to rewrite it: * * ```js * // a.js * export var value = 3; * console.log(value); * ``` * * In this case we re-write both `value` references to something like * `a$$value`. The tricky part happens when we re-export an imported binding: * * ```js * // a.js * export var value = 11; * * // b.js * import { value } from './a'; * export { value }; * * // c.js * import { value } from './b'; * console.log(value); * ``` * * The `value` reference in a.js will be rewritten as something like `a$$value` * as expected. The `value` reference in c.js will not be rewritten as * `b$$value` despite the fact that it is imported from b.js. This is because * we must follow the binding through to its import from a.js. Thus, our * `value` references will both be rewritten to `a$$value` to ensure they * match. * * @override */ BundleFormatter.prototype.exportedReference = function(mod, referencePath) { var specifier = mod.exports.findSpecifierForReference(referencePath); if (specifier) { specifier = specifier.terminalExportSpecifier; return this.reference(specifier.module, specifier.name); } else { return null; } }; /** * Get a reference to the original exported value referenced in `mod` at * `referencePath`. This is very similar to BundleFormatter#exportedReference * in its approach. * * @override */ BundleFormatter.prototype.importedReference = function(mod, referencePath) { var specifier = mod.imports.findSpecifierForReference(referencePath); if (!specifier) { return null; } if (specifier.from) { specifier = specifier.terminalExportSpecifier; if (n.ImportNamespaceSpecifier.check(specifier.node)) { // Reference the built namespace object, e.g. mod$$. return b.identifier(specifier.declaration.source.id); } return this.reference(specifier.module, specifier.name); } else { return b.identifier(specifier.declaration.source.id); } }; /** * If the given reference has a local declaration at the top-level then we must * rewrite that reference to have a module-scoped name. * * @param {Module} mod * @param {NodePath} referencePath * @return {?Node} */ BundleFormatter.prototype.localReference = function(mod, referencePath) { var scope = referencePath.scope.lookup(referencePath.node.name); if (scope && scope.isGlobal) { return this.reference(mod, referencePath.node); } else { return null; } }; /** * Replaces non-default exports. Exported bindings do not need to be * replaced with actual statements since they only control how local references * are renamed within the module. * * @override */ BundleFormatter.prototype.processExportDeclaration = function(mod, nodePath) { var node = nodePath.node; if (n.FunctionDeclaration.check(node.declaration)) { return Replacement.swaps( // drop `export` nodePath, node.declaration ).and( // transform the function this.processFunctionDeclaration(mod, nodePath.get('declaration')) ); } else if (n.ClassDeclaration.check(node.declaration)) { return Replacement.swaps( // drop `export` nodePath, node.declaration ).and( // transform the class this.processClassDeclaration(mod, nodePath.get('declaration')) ); } else if (n.VariableDeclaration.check(node.declaration)) { return Replacement.swaps( // drop `export` nodePath, node.declaration ).and( // transform the variables this.processVariableDeclaration(mod, nodePath.get('declaration')) ); } else if (node.declaration) { throw new Error( 'unexpected export style, found a declaration of type: ' + node.declaration.type ); } else { /** * This node looks like this: * * ```js * export { foo, bar }; * ``` * * Which means that it has no value in the generated code as its only * function is to control how imports are rewritten. */ return Replacement.removes(nodePath); } }; /** * Since named export reassignment is just a local variable, we can ignore it. * e.g. * * ```js * export var foo = 1; * foo = 2; * ``` * * @override */ BundleFormatter.prototype.processExportReassignment = function(mod, nodePath) { return null; }; /** * Rename the top-level function declaration to a unique name. * * ```js * function foo() {} * ``` * * Becomes e.g. * * ```js * function mod$$foo() {} * ``` * * @override */ BundleFormatter.prototype.processFunctionDeclaration = function(mod, nodePath) { return Replacement.swaps( nodePath.get('id'), this.reference(mod, nodePath.node.id) ); }; /** * Rename the top-level class declaration to a unique name. * * ```js * class Foo {} * ``` * * Becomes e.g. * * ```js * class mod$$Foo {} * ``` * * @override */ BundleFormatter.prototype.processClassDeclaration = function(mod, nodePath) { return Replacement.swaps( nodePath.get('id'), this.reference(mod, nodePath.node.id) ); }; /** * Since import declarations only control how we rewrite references we can just * remove them -- they don't turn into any actual statements. * * @override */ BundleFormatter.prototype.processImportDeclaration = function(mod, nodePath) { return Replacement.removes(nodePath); }; /** * Process a variable declaration found at the top level of the module. We need * to ensure that exported variables are rewritten appropriately, so we may * need to rewrite some or all of this variable declaration. For example: * * ```js * var a = 1, b, c = 3; * ... * export { a, b }; * ``` * * We turn those being exported into assignments as needed, e.g. * * ```js * var c = 3; * mod$$a = 1; * ``` * * @override */ BundleFormatter.prototype.processVariableDeclaration = function(mod, nodePath) { var self = this; return Replacement.map( nodePath.get('declarations'), function(declaratorPath) { return Replacement.swaps( declaratorPath.get('id'), self.reference(mod, declaratorPath.get('id').node) ); } ); }; /** * Returns an expression which globally references the export named by * `identifier` for the given module `mod`. For example: * * ```js * // rsvp/defer.js, export default * rsvp$defer$$default * * // rsvp/utils.js, export function isFunction * rsvp$utils$$isFunction * ``` * * @param {Module} mod * @param {Identifier|string} identifier * @return {Identifier} * @private */ BundleFormatter.prototype.reference = function(mod, identifier) { return b.identifier( mod.id + (n.Identifier.check(identifier) ? identifier.name : identifier) ); }; module.exports = BundleFormatter; es6-module-transpiler-0.10.0/lib/formatters/commonjs_formatter.js000066400000000000000000000326251246026563300251520ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var b = types.builders; var util = require('ast-util'); var extend = require('../utils').extend; var compatMemberExpression = require('../utils').compatMemberExpression; var Replacement = require('../replacement'); var Formatter = require('./formatter'); /** * The 'commonjs' setting for referencing exports aims to produce code that can * be used in environments using the CommonJS module system, such as Node.js. * * @constructor */ function CommonJSFormatter() { Formatter.call(this); } extend(CommonJSFormatter, Formatter); /** * Convert a list of ordered modules into a list of files. * * @param {Module[]} modules Modules in execution order. * @return {File[]} */ CommonJSFormatter.prototype.build = function(modules) { var self = this; return modules.map(function(mod) { var body = mod.ast.program.body; var requiresDeclaration = self.buildRequires(mod); var earlyExportsStatement = self.buildEarlyExports(mod); var lateExports = self.buildLateExports(mod); if (requiresDeclaration) { body.unshift(requiresDeclaration); } if (earlyExportsStatement) { body.unshift(earlyExportsStatement); } body.unshift(b.expressionStatement(b.literal('use strict'))); if (lateExports) { body.push(lateExports); } mod.ast.filename = mod.relativePath; return mod.ast; }); }; /** * Process all export bindings which may be exported before any module code is * actually run, i.e. function declarations. * * @param {Module} mod * @returns {?AST.Statement} * @private */ CommonJSFormatter.prototype.buildEarlyExports = function(mod) { var assignments = []; var exportObject = b.identifier('exports'); this.forEachExportBinding(mod, function(specifier, name) { if (!n.FunctionDeclaration.check(specifier.declaration.node.declaration)) { // Only function declarations are handled as early exports. return; } assignments.push(b.assignmentExpression( '=', compatMemberExpression( exportObject, name ), b.identifier(specifier.from) )); }); if (assignments.length > 0) { return b.expressionStatement( b.sequenceExpression(assignments) ); } else { return null; } }; /** * Process all export bindings which were not exported at the beginning of the * module, i.e. everything except function declarations. * * @param {Module} mod * @returns {?AST.Statement} * @private */ CommonJSFormatter.prototype.buildLateExports = function(mod) { var self = this; var assignments = []; var exportObject = b.identifier('exports'); this.forEachExportBinding(mod, function(specifier, name) { if (n.FunctionDeclaration.check(specifier.declaration.node.declaration)) { // Function declarations are handled as early exports. return; } var from; if (specifier.importSpecifier) { if (n.ImportNamespaceSpecifier.check(specifier.importSpecifier.node)) { from = b.identifier(specifier.importSpecifier.declaration.source.id) } else { from = self.reference( specifier.importSpecifier.declaration.source, specifier.importSpecifier.from ); } } else if (specifier.declaration.source) { from = self.reference( specifier.declaration.source, specifier.name ); } else { from = b.identifier(specifier.from); } assignments.push(b.assignmentExpression( '=', compatMemberExpression( exportObject, name ), from )); }); if (assignments.length > 0) { return b.expressionStatement( b.sequenceExpression(assignments) ); } else { return null; } }; /** * Iterates over each exported binding and calls `iterator` with its specifier. * * @param {Module} mod * @param {function(ModuleBindingSpecifier, string)} iterator * @private */ CommonJSFormatter.prototype.forEachExportBinding = function(mod, iterator) { mod.exports.names.forEach(function(name) { var specifier = mod.exports.findSpecifierByName(name); assert.ok( specifier, 'no export specifier found for export name `' + name + '` from ' + mod.relativePath ); if (!specifier.from) { // Default exports are handled elsewhere. return; } iterator(specifier, name); }); }; /** * Build a series of requires based on the imports (and exports with sources) * in the given module. * * @private * @param {Module} mod * @return {?AST.VariableDeclaration} */ CommonJSFormatter.prototype.buildRequires = function(mod) { var declarators = []; var requiredModules = []; [mod.imports, mod.exports].forEach(function(declarations) { declarations.modules.forEach(function(sourceModule) { if (requiredModules.indexOf(sourceModule) >= 0) { return; } requiredModules.push(sourceModule); var matchingDeclaration; declarations.declarations.some(function(declaration) { if (declaration.source === sourceModule) { matchingDeclaration = declaration; return true; } }); assert.ok( matchingDeclaration, 'no matching declaration for source module: ' + sourceModule.relativePath ); // `(import|export) { ... } from 'math'` -> `math$$ = require('math')` declarators.push(b.variableDeclarator( b.identifier(sourceModule.id), b.callExpression( b.identifier('require'), [b.literal(matchingDeclaration.sourcePath)] ) )); }); }); if (declarators.length > 0) { return b.variableDeclaration('var', declarators); } else { return null; } }; /** * @override * * ```js * export default * // or * export default ; * ``` */ CommonJSFormatter.prototype.defaultExport = function(mod, declaration) { if (n.FunctionDeclaration.check(declaration) || n.ClassDeclaration.check(declaration)) { // export default function foo () {} // -> becomes: // function foo () {} // export['default'] = foo; return [ declaration, b.expressionStatement(b.assignmentExpression( '=', b.memberExpression( b.identifier('exports'), b.literal('default'), true ), declaration.id )) ]; } return b.expressionStatement(b.assignmentExpression( '=', b.memberExpression( b.identifier('exports'), b.literal('default'), true ), declaration )); }; /** * Because exported references are captured via a closure as part of a getter * on the `exports` object, there's no need to rewrite local references to * exported values. For example, `value` in this example can stay as is: * * // a.js * export var value = 1; * * @override */ CommonJSFormatter.prototype.exportedReference = function(mod, referencePath) { return null; }; /** * Gets a reference to an imported binding by getting the value from the * required module on demand. For example, this module: * * // b.js * import { value } from './a'; * console.log(value); * * Would be rewritten to look something like this: * * var a$$ = require('./a'); * console.log(a$$.value): * * If the given reference does not refer to an imported binding then no * rewriting is required and `null` will be returned. * * @override */ CommonJSFormatter.prototype.importedReference = function(mod, referencePath) { var specifier = mod.imports.findSpecifierForReference(referencePath); if (!specifier) { return null; } if (specifier.from) { // import { value } from './a'; // import a from './a'; return this.reference( specifier.declaration.source, specifier.from ); } else { // import * as a from './a' return b.identifier(specifier.declaration.source.id); } }; /** * We do not need to rewrite references to local declarations. * * @override */ CommonJSFormatter.prototype.localReference = function(mod, referencePath) { return null; }; /** * Replaces non-default exports. For declarations we simply remove the `export` * keyword. For export declarations that just specify bindings, e.g. * * export { a, b }; * * we remove them entirely since they'll be handled when we define properties on * the `exports` object. * * @override */ CommonJSFormatter.prototype.processExportDeclaration = function(mod, nodePath) { var node = nodePath.node; if (n.FunctionDeclaration.check(node.declaration)) { return Replacement.swaps(nodePath, node.declaration); } else if (n.VariableDeclaration.check(node.declaration)) { return Replacement.swaps(nodePath, node.declaration); } else if (n.ClassDeclaration.check(node.declaration)) { return Replacement.swaps(nodePath, node.declaration); } else if (node.declaration) { throw new Error('unexpected export style, found a declaration of type: ' + node.declaration.type); } else { return Replacement.removes(nodePath); } }; /** * We explicitly disallow reassignment because we cannot propagate changes to * importing modules as we would in ES5, e.g. these are both disallowed: * * export var foo = 1; * foo = 2; * * export var bar = 1; * bar++; * * @override */ CommonJSFormatter.prototype.processExportReassignment = function(mod, nodePath) { var node = nodePath.node; var exportName; if (n.AssignmentExpression.check(node)) { exportName = node.left.name; } else if (n.UpdateExpression.check(node)) { exportName = node.argument.name; } else { throw new Error('unexpected export reassignment type: ' + node.type); } if (n.UpdateExpression.check(node) && !node.prefix) { /** * The result of `a++` is the value of `a` before it is incremented, so we * can't just use the result as the new value for `exports.a`. The question * is whether we need to preserve the result of `a++` or not. In this case, * we do: * * ```js * foo(a++); * ``` * * But in this case we don't, since the result is ignored: * * ```js * a++; * ``` */ if (n.ExpressionStatement.check(nodePath.parent.node)) { // The result is ignored here, so `a++` can become `a++, exports.a = a`. return Replacement.swaps( nodePath, b.sequenceExpression([ node, b.assignmentExpression( '=', compatMemberExpression( b.identifier('exports'), exportName ), b.identifier(exportName) ) ]) ); } else { // The result is used here, so we need a temporary variable to store it. var result = util.injectVariable(nodePath.scope, util.uniqueIdentifier(nodePath.scope)); return Replacement.swaps( nodePath, b.sequenceExpression([ b.assignmentExpression( '=', result, node ), b.assignmentExpression( '=', compatMemberExpression( b.identifier('exports'), exportName ), b.identifier(exportName) ), result ]) ); } } /** * We can use the result of the update/assignment as-is in this case, e.g. * * ```js * foo(++a); * b = 9; * ``` * * Can become: * * ```js * foo(exports.a = ++a); * exports.b = b = 9; * ``` */ return Replacement.swaps( nodePath, b.assignmentExpression( '=', compatMemberExpression( b.identifier('exports'), exportName ), node ) ); }; /** * Process a function declaration found at the top level of the module. Since * we do not need to rewrite exported functions, we can leave function * declarations alone. * * @override */ CommonJSFormatter.prototype.processFunctionDeclaration = function(mod, nodePath) { return null; }; /** * Process a class declaration found at the top level of the module. Since * we do not need to rewrite exported classes, we can leave class * declarations alone. * * @override */ CommonJSFormatter.prototype.processClassDeclaration = function(mod, nodePath) { return null; }; /** * Since import declarations only control how we rewrite references we can just * remove them -- they don't turn into any actual statements. * * @override */ CommonJSFormatter.prototype.processImportDeclaration = function(mod, nodePath) { return Replacement.removes(nodePath); }; /** * Process a variable declaration found at the top level of the module. Since * we do not need to rewrite exported variables, we can leave variable * declarations alone. * * @override */ CommonJSFormatter.prototype.processVariableDeclaration = function(mod, nodePath) { return null; }; /** * Returns an expression which globally references the export named by * `identifier` for the given module `mod`. For example: * * // rsvp/defer.js, export default * rsvp$defer$$['default'] * * // rsvp/utils.js, export function isFunction * rsvp$utils$$.isFunction * * @param {Module} mod * @param {Identifier} identifier * @return {MemberExpression} * @private */ CommonJSFormatter.prototype.reference = function(mod, identifier) { return compatMemberExpression( b.identifier(mod.id), identifier ); }; module.exports = CommonJSFormatter; es6-module-transpiler-0.10.0/lib/formatters/formatter.js000066400000000000000000000130651246026563300232420ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var b = types.builders; var Replacement = require('../replacement'); /** * This class provides a base for any concrete formatter classes. Subclasses * of this class will be used by Rewriter to determine how to replace various * parts of an AST while walking it to achieve conversion from ES6 modules to * another format. * * @constructor * @abstract */ function Formatter() {} /** * Convert a list of ordered modules into a list of files. * * @param {Module[]} modules Modules in execution order. * @return {File[]} */ Formatter.prototype.build = function(modules) { throw new Error('#build must be implemented in subclasses'); }; /** * Replaces default export declarations with something else. Subclasses will * generally return a statement that takes the declaration value and stashes * it somewhere appropriate for the transpiled format, e.g. creates a local * variable, assigns the value to something, or calls a function with it. * * Given an export statement like so: * * ```js * export default foo(bar); * ``` * * This method will be called with the module containing the statement and * the AST node corresponding to `foo(bar)`. * * @param {Module} mod * @param {Expression} declaration * @return {Statement} */ Formatter.prototype.defaultExport = function(mod, declaration) { throw new Error('#defaultExport must be implemented in subclasses'); }; /** * Resolves references to exported bindings. In the example below, if we refer * to `value` elsewhere in the module then that reference may need to be * rewritten. This method allows us to configure what it is rewritten to. * * ```js * // a.js * export var value = 1; * ``` * * Subclasses should return null if the original reference should be left * intact. * * @param {Module} mod * @param {NodePath} referencePath * @return {?Expression} */ Formatter.prototype.exportedReference = function(mod, referencePath) { throw new Error('#exportedReference must be implemented in subclasses'); }; /** * Gets a reference to an imported binding. In this example, we will be called * with the NodePath for `value` in `console.log(value)`: * * ```js * // b.js * import { value } from './a'; * console.log(value); * ``` * * If the given reference does not refer to an imported binding then no * rewriting is required and `null` should be returned. * * @param {Module} mod * @param {NodePath} referencePath * @return {?Expression} */ Formatter.prototype.importedReference = function(mod, referencePath) { throw new Error('#importedReference must be implemented in subclasses'); }; /** * Determines what the given reference should be rewritten to, if anything. * Subclasses should override this only if they wish to rename bindings not * associated with imports and exports. * * This is used by the bundle formatter, for example, to ensure that bindings * at module scope are rewritten with unique names to prevent collisions with * bindings from other modules. * * @param {Module} mod * @param {NodePath} referencePath * @return {?Node} */ Formatter.prototype.localReference = function(mod, referencePath) { return null; }; /** * Process a function declaration found at the top level of the module. * * @param {Module} mod * @param {NodePath} nodePath * @return {?Node[]} */ Formatter.prototype.processFunctionDeclaration = function(mod, nodePath) { throw new Error('#processFunctionDeclaration must be implemented in subclasses'); }; /** * Process a class declaration found at the top level of the module. * * @param {Module} mod * @param {NodePath} nodePath * @return {?Node[]} */ Formatter.prototype.processClassDeclaration = function(mod, nodePath) { throw new Error('#processClassDeclaration must be implemented in subclasses'); }; /** * Process a variable declaration found at the top level of the module. * * @param {Module} mod * @param {NodePath} nodePath * @return {?Node[]} */ Formatter.prototype.processVariableDeclaration = function(mod, nodePath) { throw new Error('#processVariableDeclaration must be implemented in subclasses'); }; /** * Replaces non-default exports. These exports are of one of the following * forms: * * ```js * export var a = 1; * export function a() {} * export class a {} * export { a }; * ``` * * @param {Module} mod * @param {NodePath} nodePath * @return {?Replacement} */ Formatter.prototype.processExportDeclaration = function(mod, nodePath) { throw new Error('#processExportDeclaration must be implemented in subclasses'); }; /** * Process and optionally replace an update to an exported binding. This can * either be an assignment expression or an update expression, i.e. * * ```js * export var foo = 1; * foo = 2; * foo++; * ``` * * @param {Module} mod * @param {NodePath} nodePath * @return {?Replacement} */ Formatter.prototype.processExportReassignment = function(mod, nodePath) { throw new Error('#processExportReassignment must be implemented in subclasses'); }; /** * Optionally replace an import declaration. Subclasses should almost always * replace import declarations. It may be replaced with a dependency lookup, or * perhaps with nothing. * * @param {Module} mod * @param {NodePath} nodePath * @return {?Replacement} */ Formatter.prototype.processImportDeclaration = function(mod, nodePath) { throw new Error('#processImportDeclaration must be implemented in subclasses'); }; module.exports = Formatter; es6-module-transpiler-0.10.0/lib/imports.js000066400000000000000000000142631246026563300205470ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var ModuleBindingList = require('./module_binding_list'); var ModuleBindingDeclaration = require('./module_binding_declaration'); var ModuleBindingSpecifier = require('./module_binding_specifier'); var utils = require('./utils'); var memo = utils.memo; var extend = utils.extend; var sourcePosition = utils.sourcePosition; /** * Represents a list of the imports for the given module. * * @constructor * @param {Module} mod * @extends ModuleBindingList */ function ImportDeclarationList(mod) { ModuleBindingList.call(this, mod); } extend(ImportDeclarationList, ModuleBindingList); /** * @private * @param {AST.Node} node * @return {boolean} */ ImportDeclarationList.prototype.isMatchingBinding = function(node) { return n.ImportDeclaration.check(node); }; /** * Gets an import declaration for the given `node`. * * @private * @param {AST.ImportDeclaration} node * @return {ImportDeclaration} */ ImportDeclarationList.prototype.declarationForNode = function(node) { return new ImportDeclaration(this.module, node); }; /** * Gets the namespace imports from the list of imports. * * @private * @type {ImportDeclaration[]} * @name ImportDeclaration#namespaceImports */ memo(ImportDeclarationList.prototype, 'namespaceImports', /** @this ImportDeclarationList */function() { return this.declarations.filter(function(declaration) { return declaration.hasNamespaceImport; }); }); /** * Contains information about an import declaration. * * ```js * import foo from 'math'; * import { sin, cos } from 'math'; * import * as bar from 'math'; * import foo, { sin, cos } from 'math'; * import foo, * as bar from 'math'; * ``` * * @constructor * @abstract * @param {Module} mod * @param {AST.ImportDeclaration} node * @extends ModuleBindingDeclaration */ function ImportDeclaration(mod, node) { assert.ok( n.ImportDeclaration.check(node), 'expected an import declaration, got ' + (node && node.type) ); ModuleBindingDeclaration.call(this, mod, node); } extend(ImportDeclaration, ModuleBindingDeclaration); /** * Contains a list of specifier name information for this import. * * @type {ImportSpecifier[]} * @name ImportDeclaration#specifiers */ memo(ImportDeclaration.prototype, 'specifiers', /** @this ImportDeclaration */function() { var self = this; return this.node.specifiers.map(function(specifier) { if (n.ImportDefaultSpecifier.check(specifier)) { return new ImportDefaultSpecifier(self, specifier); } else if (n.ImportNamespaceSpecifier.check(specifier)) { return new ImportNamespaceSpecifier(self, specifier); } return new ImportNamedSpecifier(self, specifier); }); }); /** * @type {boolean} * @name ImportDeclaration#hasNamespaceImport */ memo(ImportDeclaration.prototype, 'hasNamespaceImport', /** @this ImportDeclaration */function() { return this.specifiers.some(function(specifier) { return specifier instanceof ImportNamespaceSpecifier; }); }); /** * Represents an import specifier. The "a" and "b as c" are both import * specifiers in the following import statement. * * import { a, b as c } from "a"; * * @constructor * @extends ModuleBindingSpecifier * @param {ImportDeclaration} declaration * @param {AST.ImportNamedSpecifier} node */ function ImportNamedSpecifier(declaration, node) { assert.ok( declaration instanceof ImportDeclaration, 'expected an instance of ImportDeclaration' ); ModuleBindingSpecifier.call(this, declaration, node); } extend(ImportNamedSpecifier, ModuleBindingSpecifier); /** * @type {ExportSpecifier} * @name ImportNamedSpecifier#exportSpecifier */ memo(ImportNamedSpecifier.prototype, 'exportSpecifier', /** @this ImportNamedSpecifier */function() { var source = this.declaration.source; assert.ok(source, 'import specifiers must have a valid source'); var exportSpecifier = source.exports.findSpecifierByName(this.from); assert.ok( exportSpecifier, 'import `' + this.from + '` at ' + sourcePosition(this.module, this.node) + ' has no matching export in ' + source.relativePath ); return exportSpecifier; }); /** * Represents a default import specifier. The "a" in the following import statement. * * import a from "a"; * * @constructor * @extends ModuleBindingSpecifier * @param {ImportDeclaration} declaration * @param {AST.ImportDefaultSpecifier} node */ function ImportDefaultSpecifier(declaration, node) { assert.ok( declaration instanceof ImportDeclaration, 'expected an instance of ImportDeclaration' ); ModuleBindingSpecifier.call(this, declaration, node); } extend(ImportDefaultSpecifier, ModuleBindingSpecifier); memo(ImportDefaultSpecifier.prototype, 'exportSpecifier', /** @this ImportSpecifier */function() { var source = this.declaration.source; assert.ok(source, 'import specifiers must have a valid source'); var exportSpecifier = source.exports.findSpecifierByName(this.from); assert.ok( exportSpecifier, 'import `default` at ' + sourcePosition(this.module, this.node) + ' has no matching export in ' + source.relativePath ); return exportSpecifier; }); memo(ImportDefaultSpecifier.prototype, 'from', function() { return 'default'; }); /** * Represents a namespace import specifier. The "a" in the following import * statement. * * import * as a from "a"; * * @constructor * @extends ModuleBindingSpecifier * @param {ImportDeclaration} declaration * @param {AST.ImportNamespaceSpecifier} node */ function ImportNamespaceSpecifier(declaration, node) { assert.ok( declaration instanceof ImportDeclaration, 'expected an instance of ImportDeclaration' ); ModuleBindingSpecifier.call(this, declaration, node); } extend(ImportNamespaceSpecifier, ModuleBindingSpecifier); memo(ImportNamespaceSpecifier.prototype, 'exportSpecifier', /** @this ImportNamespaceSpecifier */function() { var source = this.declaration.source; assert.ok(source, 'import specifiers must have a valid source'); return null; }); memo(ImportNamespaceSpecifier.prototype, 'from', function() { return null; }); module.exports = ImportDeclarationList; es6-module-transpiler-0.10.0/lib/index.js000066400000000000000000000005231246026563300201530ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var Container = require('./container'); var FileResolver = require('./file_resolver'); var formatters = require('./formatters'); var Module = require('./module'); exports.FileResolver = FileResolver; exports.Container = Container; exports.formatters = formatters; exports.Module = Module; es6-module-transpiler-0.10.0/lib/module.js000066400000000000000000000104261246026563300203340ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var fs = require('fs'); var Path = require('path'); var esprima = require('esprima-fb'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var b = types.builders; var NodePath = recast.types.NodePath; var ImportDeclarationList = require('./imports'); var ExportDeclarationList = require('./exports'); var utils = require('./utils'); var memo = utils.memo; var endsWith = utils.endsWith; /** * Represents a JavaScript module at a particular location on disk. * * @param {string} path * @param {string} relativePath * @param {Container} container * @constructor */ function Module(path, relativePath, container) { Object.defineProperties(this, { /** * @type {string} * @name Module#path */ path: { value: path, enumerable: true, writable: false }, /** * @type {string} * @name Module#relativePath */ relativePath: { value: relativePath, enumerable: true, writable: false }, /** * @type {string} * @name Module#sourceFileName */ sourceFileName: { value: Path.relative(container.basePath, path), enumerable: true, writable: false }, /** * @type {Container} * @name Module#container */ container: { value: container, enumerable: true, writable: false } }); } /** * Clears the cached data for this module. */ Module.prototype.reload = function() { delete this.src; delete this.ast; delete this.imports; delete this.exports; delete this.scope; }; /** * The list of imports declared by this module. * * @type {ImportDeclarationList} * @name Module#imports */ memo(Module.prototype, 'imports', /** @this Module */function() { var result = new ImportDeclarationList(this); result.readProgram(this.ast.program); return result; }); /** * The list of exports declared by this module. * * @type {ExportDeclarationList} * @name Module#exports */ memo(Module.prototype, 'exports', /** @this Module */function() { var result = new ExportDeclarationList(this); result.readProgram(this.ast.program); return result; }); /** * This module's scope. * * @type {Scope} * @name Module#scope */ memo(Module.prototype, 'scope', /** @this Module */function() { return new NodePath(this.ast).get('program').get('body').scope; }); /** * This module's source code represented as an abstract syntax tree. * * @type {File} * @name Module#ast */ memo(Module.prototype, 'ast', /** @this Module */function() { return recast.parse( this.src, { esprima: esprima, sourceFileName: this.sourceFileName } ); }); /** * This module's source code. * * @type {String} * @name Module#src */ memo(Module.prototype, 'src', /** @this Module */function() { return fs.readFileSync(this.path).toString(); }); /** * A reference to the options from this module's container. * * @type {object} * @name Module#options */ memo(Module.prototype, 'options', /** @this Module */function() { return this.container.options; }); /** * This module's relative name, like {#relativePath} but without the extension. * This may be modified by a Container if this Module is part of a Container. * * @type {string} * @name Module#name */ memo(Module.prototype, 'name', /** @this Module */function() { var relativePath = this.relativePath; if (endsWith(relativePath, '.js')) { return relativePath.slice(0, -3); } else { return relativePath; } }); /** * A string suitable for a JavaScript identifier named for this module. * * @type {string} * @name Module#id */ memo(Module.prototype, 'id', /** @this Module */function() { return this.name.replace(/[^\w$_]/g, '$') + '$$'; }); /** * Gets a Module by path relative to this module. * * @param {string} sourcePath * @return {Module} */ Module.prototype.getModule = function(sourcePath) { return this.container.getModule(sourcePath, this); }; /** * Generate a descriptive string suitable for debugging. * * @return {string} */ Module.prototype.inspect = function() { return '#<' + this.constructor.name + ' ' + this.relativePath + '>'; }; /** * @see Module#inspect */ Module.prototype.toString = Module.prototype.inspect; module.exports = Module; es6-module-transpiler-0.10.0/lib/module_binding_declaration.js000066400000000000000000000063711246026563300243770ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var utils = require('./utils'); var memo = utils.memo; /** * Contains information about a module binding declaration. This corresponds to * the shared functionality of `ExportDeclaration` and `ImportDeclaration` in * the ES6 spec. * * @constructor * @abstract * @param {Module} mod * @param {AST.ImportDeclaration|AST.ExportDeclaration} node */ function ModuleBindingDeclaration(mod, node) { assert.ok( n.ImportDeclaration.check(node) || n.ExportDeclaration.check(node), 'expected an import or export declaration, got ' + (node && node.type) ); Object.defineProperties(this, { /** * @name ModuleBindingDeclaration#node * @type {AST.ImportDeclaration|AST.ExportDeclaration} */ node: { value: node }, /** * @name ModuleBindingDeclaration#module * @type {Module} */ module: { value: mod } }); } /** * Finds the specifier that creates the local binding given by `name`, if one * exists. Otherwise `null` is returned. * * @param {string} name * @return {?ModuleBindingSpecifier} */ ModuleBindingDeclaration.prototype.findSpecifierByName = function(name) { var specifiers = this.specifiers; for (var i = 0, length = specifiers.length; i < length; i++) { var specifier = specifiers[i]; if (specifier.name === name) { return specifier; } } return null; }; /** * @param {AST.Identifier} identifier * @return {?ModuleBindingSpecifier} */ ModuleBindingDeclaration.prototype.findSpecifierByIdentifier = function(identifier) { for (var i = 0, length = this.specifiers.length; i < length; i++) { var specifier = this.specifiers[i]; if (specifier.identifier === identifier) { return specifier; } } return null; }; /** * Gets the raw path of the `from` part of the declaration, if present. For * example: * * ```js * import { map } from "array"; * ``` * * The source path for the above declaration is "array". * * @type {?string} * @name ModuleBindingDeclaration#sourcePath */ memo(ModuleBindingDeclaration.prototype, 'sourcePath', /** @this ModuleBindingDeclaration */function() { return this.node.source ? this.node.source.value : null; }); /** * Gets a reference to the module referenced by this declaration. * * @type {Module} * @name ModuleBindingDeclaration#source */ memo(ModuleBindingDeclaration.prototype, 'source', /** @this ModuleBindingDeclaration */function() { return this.sourcePath ? this.module.getModule(this.sourcePath) : null; }); /** * Gets the containing module's scope. * * @type {Scope} * @name ModuleBindingDeclaration#moduleScope */ memo(ModuleBindingDeclaration.prototype, 'moduleScope', /** @this ModuleBindingDeclaration */function() { return this.module.scope; }); /** * Generate a string representing this object to aid debugging. * * @return {string} */ ModuleBindingDeclaration.prototype.inspect = function() { return recast.print(this.node).code; }; /** * @see ModuleBindingDeclaration#inspect */ ModuleBindingDeclaration.prototype.toString = ModuleBindingDeclaration.prototype.inspect; module.exports = ModuleBindingDeclaration; es6-module-transpiler-0.10.0/lib/module_binding_list.js000066400000000000000000000140221246026563300230550ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var utils = require('./utils'); var memo = utils.memo; var sourcePosition = utils.sourcePosition; /** * Represents a list of bindings for the given module. This corresponds to the * shared functionality from `ExportsList` and `ImportsList` from the ES6 spec. * * @abstract * @constructor * @param {Module} mod */ function ModuleBindingList(mod) { Object.defineProperties(this, { /** * @name ModuleBindingList#_nodes * @type {AST.ImportDeclaration[]|AST.ExportDeclaration[]} * @private */ _nodes: { value: [] }, /** * @name ModuleBindingList#module * @type {Module} */ module: { value: mod } }); } /** * Add all the binding declarations from the given scope body. Generally this * should be the Program node's `body` property, an array of statements. * * @param {AST.Program} program */ ModuleBindingList.prototype.readProgram = function(program) { var body = program.body; for (var i = 0; i < body.length; i++) { if (this.isMatchingBinding(body[i])) { this.addDeclaration(body[i]); } } }; /** * Adds a declaration to the list. * * @private * @param {AST.ImportDeclaration|AST.ExportDeclaration} node */ ModuleBindingList.prototype.addDeclaration = function(node) { assert.ok( this.isMatchingBinding(node), 'expected node to be an declaration, but got ' + (node && node.type) ); this._nodes.push(node); // reset the cache delete this.declarations; delete this.specifiers; delete this.modules; }; /** * Gets the associated module's scope. * * @type {Scope} * @name ModuleBindingList#moduleScope */ memo(ModuleBindingList.prototype, 'moduleScope', /** @this ModuleBindingList */function() { return this.module.scope; }); /** * Gets all the modules referenced by the declarations in this list. * * @type {Module[]} * @name ModuleBindingList#modules */ memo(ModuleBindingList.prototype, 'modules', /** @this ModuleBindingList */function() { var modules = []; this.declarations.forEach(function(declaration) { if (declaration.source && modules.indexOf(declaration.source) < 0) { modules.push(declaration.source); } }); return modules; }); /** * Finds the specifier that creates the local binding given by `name`, if one * exists. Otherwise `null` is returned. * * @private * @param {string} name * @return {?ModuleBindingSpecifier} */ ModuleBindingList.prototype.findSpecifierByName = function(name) { for (var i = 0, length = this.declarations.length; i < length; i++) { var specifier = this.declarations[i].findSpecifierByName(name); if (specifier) { return specifier; } } return null; }; /** * Finds the specifier whose identifier is the given identifier, if one exists. * Otherwise `null` is returned. * * @private * @param {AST.Identifier} identifier * @return {?ModuleBindingSpecifier} */ ModuleBindingList.prototype.findSpecifierByIdentifier = function(identifier) { for (var i = 0, length = this.declarations.length; i < length; i++) { var specifier = this.declarations[i].findSpecifierByIdentifier(identifier); if (specifier && specifier.identifier === identifier) { return specifier; } } return null; }; /** * @param {NodePath} referencePath * @return {?ModuleBindingSpecifier} */ ModuleBindingList.prototype.findSpecifierForReference = function(referencePath) { var declaration = this.findDeclarationForReference(referencePath); if (!declaration) { return null; } var specifier = this.findSpecifierByIdentifier(declaration.node); assert.ok( specifier, 'no specifier found for `' + referencePath.node.name + '`! this should not happen!' ); return specifier; }; /** * @private */ ModuleBindingList.prototype.findDeclarationForReference = function(referencePath) { // Check names to avoid traversing scopes for all references. if (this.names.indexOf(referencePath.node.name) < 0) { return null; } var node = referencePath.node; var declaringScope = referencePath.scope.lookup(node.name); assert.ok( declaringScope, '`' + node.name + '` at ' + sourcePosition(this.module, node) + ' cannot be bound if it is not declared' ); // Bindings are at the top level, so if this isn't then it's shadowing. if (!declaringScope.isGlobal) { return null; } var declarations = declaringScope.getBindings()[node.name]; if (!declarations || declarations.length !== 1) { throw new SyntaxError( 'expected one declaration for `' + node.name + '`, at ' + sourcePosition(this.module, node) + ' but found ' + (declarations ? declarations.length : 'none') ); } return declarations[0]; }; /** * Generate a string representing this object to aid debugging. * * @return {string} */ ModuleBindingList.prototype.inspect = function() { var result = '#<' + this.constructor.name; result += ' module=' + this.module.relativePath; if (this.declarations.length > 0) { result += ' declarations=' + this.declarations.map(function(imp) { return imp.inspect(); }).join(', '); } result += '>'; return result; }; /** * @see ModuleBindingList#inspect */ ModuleBindingList.prototype.toString = ModuleBindingList.prototype.inspect; /** * Contains a list of declarations. * * @type {(ImportDeclaration[]|ExportDeclaration[])} * @name ModuleBindingList#declarations */ memo(ModuleBindingList.prototype, 'declarations', /** @this ModuleBindingList */function() { var self = this; return this._nodes.map(function(child) { return self.declarationForNode(child); }); }); /** * Contains a combined list of names for all the declarations contained in this * list. * * @type {string[]} * @name ModuleBindingList#names */ memo(ModuleBindingList.prototype, 'names', /** @this ModuleBindingList */function() { return this.declarations.reduce(function(names, decl) { return names.concat(decl.specifiers.map(function(specifier) { return specifier.name; })); }, []); }); module.exports = ModuleBindingList; es6-module-transpiler-0.10.0/lib/module_binding_specifier.js000066400000000000000000000161151246026563300240600ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var utils = require('./utils'); var memo = utils.memo; var sourcePosition = utils.sourcePosition; /** * A module binding specifier provides the shared functionality of * ImportSpecifiers and ExportSpecifiers in the ES6 spec. * * @constructor * @param {ModuleBindingDeclaration} declaration * @param {AST.NamedSpecifier} node */ function ModuleBindingSpecifier(declaration, node) { Object.defineProperties(this, { /** * @name ModuleBindingSpecifier#declaration * @type {ModuleBindingDeclaration} */ declaration: { value: declaration }, /** * @name ModuleBindingSpecifier#node * @type {AST.NamedSpecifier} */ node: { value: node } }); } /** * Gets the module this specifier is declared in. * * @type Module * @name ModuleBindingSpecifier#module */ memo(ModuleBindingSpecifier.prototype, 'module', /** @this ModuleBindingSpecifier */function() { return this.declaration.module; }); /** * Gets the scope at the top level of the module. * * @type {Scope} * @name ModuleBindingSpecifier#moduleScope */ memo(ModuleBindingSpecifier.prototype, 'moduleScope', /** @this ModuleBindingSpecifier */function() { return this.declaration.moduleScope; }); /** * Gets the name of this specifier. For import specifiers this is the name of * the binding this specifier will create locally, i.e. "foo" in both of these * import statements: * * import { foo } from "util"; * import { bar as foo } from "util"; * * In export specifiers it is the name of the exported declaration or the alias * given to an internal name, i.e. "foo" in both of these export statements: * * export { bar as foo }; * export var foo = 1; * * @type {string} * @name ModuleBindingSpecifier#name */ memo(ModuleBindingSpecifier.prototype, 'name', /** @this ModuleBindingSpecifier */function() { return this.identifier.name; }); /** * Gets the name of the identifier this specifier comes from as distinct from * `name`. This value will only be set if the local name and the * imported/exported name differ, i.e. it will be "foo" in these statements: * * import { foo as bar } from "util"; * export { foo as bar }; * * And it will be undefined in these statements: * * import { foo } from "util"; * export { foo }; * * @type {string} * @name ModuleBindingSpecifier#from */ memo(ModuleBindingSpecifier.prototype, 'from', /** @this ModuleBindingSpecifier */function() { return this.node.id.name; }); /** * Gets the node that gives this specifier its name as it would be imported, * i.e. "foo" in these statements: * * import { foo } from "utils"; * import { bar as foo } from "utils"; * export { foo }; * export { bar as foo }; * * @type {AST.Identifier} * @name ModuleBindingSpecifier#identifier */ memo(ModuleBindingSpecifier.prototype, 'identifier', /** @this ModuleBindingSpecifier */function() { return this.node.name || this.node.id; }); /** * Gets the export specifier corresponding to this specifier. This can be from * either an import or export declaration, since both can have a "from" part: * * import { map } from "array"; * export { map } from "array"; * * In both of the above examples, the export specifier of `map` would be part * of the export statement in the "array" module that exports it. * * @type {?ExportSpecifier} * @name ModuleBindingSpecifier#exportSpecifier */ memo(ModuleBindingSpecifier.prototype, 'exportSpecifier', /** @this ModuleBindingSpecifier */function() { var source = this.declaration.source; if (source) { var exports = source.exports; return exports.findSpecifierByName(this.from); } else { return null; } }); /** * Gets the import specifier corresponding to this specifier. This should only * happen when exporting a binding that is imported in the same module, like so: * * import { map } from "array"; * export { map }; * * The `map` export specifier has the `map` import specifier as its * `importSpecifier` property value. The `map` import specifier has no * `importSpecifier` property value. * * @type {?ImportSpecifier} * @name ModuleBindingSpecifier#importSpecifier */ memo(ModuleBindingSpecifier.prototype, 'importSpecifier', /** @this ModuleBindingSpecifier */function() { // This may be an export from this module, so find the declaration. var localExportDeclarationInfo = this.moduleDeclaration; if (localExportDeclarationInfo && n.ImportDeclaration.check(localExportDeclarationInfo.declaration)) { // It was imported then exported with two separate declarations. var exportModule = this.module; return exportModule.imports.findSpecifierByIdentifier(localExportDeclarationInfo.identifier); } else { return null; } }); /** * Gets the original export value by following chains of export/import * statements. For example: * * // a.js * export var a = 1; * * // b.js * export { a } from "./a"; * * // c.js * import { a } from "./b"; * export { a }; * * // d.js * import { a } from "./c"; * * The terminal export specifier for all of these specifiers is the export in * a.js, since all of them can be traced back to that one. * * @type {ExportSpecifier} * @name ModuleBindingSpecifier#terminalExportSpecifier */ memo(ModuleBindingSpecifier.prototype, 'terminalExportSpecifier', /** @this ModuleBindingSpecifier */function() { if (this.exportSpecifier) { // This is true for both imports and exports with a source, e.g. // `import { foo } from 'foo'` or `export { foo } from 'foo'`. return this.exportSpecifier.terminalExportSpecifier; } // This is an export from this module, so find the declaration. var importSpecifier = this.importSpecifier; if (importSpecifier) { if (n.ImportNamespaceSpecifier.check(importSpecifier.node)) { // Namespace imports create a local binding, so they are the terminal. return importSpecifier; } var nextExportSpecifier = importSpecifier.exportSpecifier; assert.ok( nextExportSpecifier, 'expected matching export in ' + importSpecifier.declaration.source.relativePath + ' for import of `' + importSpecifier.name + '` at ' + sourcePosition(this.module, this.moduleDeclaration.identifier) ); return nextExportSpecifier.terminalExportSpecifier; } else { // It was declared in this module, so we are the terminal export specifier. return this; } }); /** * @type {?DeclarationInfo} */ ModuleBindingSpecifier.prototype.moduleDeclaration = null; /** * Gets a string representation of this module binding specifier suitable for * debugging. * * @return {string} */ ModuleBindingSpecifier.prototype.inspect = function() { return '#<' + this.constructor.name + ' module=' + this.declaration.module.relativePath + ' name=' + this.name + ' from=' + this.from + '>'; }; /** * @see ModuleBindingSpecifier#inspect */ ModuleBindingSpecifier.prototype.toString = ModuleBindingSpecifier.prototype.inspect; module.exports = ModuleBindingSpecifier; es6-module-transpiler-0.10.0/lib/replacement.js000066400000000000000000000041511246026563300213440ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var recast = require('recast'); /** @typedef [NodePath, AST.Node[]] */ var ReplacementPair; /** * Represents a replacement of a node path with zero or more nodes. * * @constructor * @param {NodePath=} nodePath * @param {AST.Node[]=} nodes */ function Replacement(nodePath, nodes) { /** * @private * @type {ReplacementPair[]} */ this.queue = []; if (nodePath && nodes) { this.queue.push([nodePath, nodes]); } } /** * Performs the replacement. */ Replacement.prototype.replace = function() { for (var i = 0, length = this.queue.length; i < length; i++) { var item = this.queue[i]; item[0].replace.apply(item[0], item[1]); } }; /** * Incorporates the replacements from the given Replacement into this one. * * @param {Replacement} anotherReplacement */ Replacement.prototype.and = function(anotherReplacement) { this.queue.push.apply(this.queue, anotherReplacement.queue); return this; }; /** * Constructs a Replacement that, when run, will remove the node from the AST. * * @param {NodePath} nodePath * @return {Replacement} */ Replacement.removes = function(nodePath) { return new Replacement(nodePath, []); }; /** * Constructs a Replacement that, when run, will insert the given nodes after * the one in nodePath. * * @param {NodePath} nodePath * @param {AST.Node[]} nodes * @return {Replacement} */ Replacement.adds = function(nodePath, nodes) { return new Replacement(nodePath, [nodePath.node].concat(nodes)); }; /** * Constructs a Replacement that, when run, swaps the node in nodePath with the * given node or nodes. * * @param {NodePath} nodePath * @param {AST.Node|AST.Node[]} nodes */ Replacement.swaps = function(nodePath, nodes) { if (!Array.isArray(nodes)) { nodes = [nodes]; } return new Replacement(nodePath, nodes); }; Replacement.map = function(nodePaths, callback) { var result = new Replacement(); nodePaths.each(function(nodePath) { var replacement = callback(nodePath); if (replacement) { result.and(replacement); } }); return result; }; module.exports = Replacement; es6-module-transpiler-0.10.0/lib/rewriter.js000066400000000000000000000276241246026563300207220ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var types = recast.types; var n = types.namedTypes; var b = types.builders; var astUtil = require('ast-util'); var utils = require('./utils'); var extend = utils.extend; var sourcePosition = utils.sourcePosition; var Replacement = require('./replacement'); /** * Replaces references to local bindings created by `mod`'s imports * with references to the original value in the source module. * * @constructor * @param {Formatter} formatter * @extends types.PathVisitor */ function Rewriter(formatter) { types.PathVisitor.call(this); Object.defineProperties(this, { formatter: { value: formatter } }); } extend(Rewriter, types.PathVisitor); /** * Rewrites references to all imported and exported bindings according to the * rules from this rewriter's formatter. For example, this module: * * ```js * import { sin, cos } from './math'; * import fib from './math/fib'; * * assert.equal(sin(0), 0); * assert.equal(cos(0), 1); * assert.equal(fib(1), 1); * ``` * * has its references to the imported bindings `sin`, `cos`, and `fib` * rewritten to reference the source module: * * ```js * assert.equal(math$$.sin(0), 0); * assert.equal(math$$.cos(0), 1); * assert.equal(math$fib$$.fib(1), 1); * ``` * * @param {Module[]} modules */ Rewriter.prototype.rewrite = function(modules) { var replacements = []; // FIXME: This is just here to ensure that all imports and exports know where // they came from. We need this because after we re-write the declarations // will not be there anymore and we'll need to ensure they're cached up front. modules.forEach(function(mod) { [mod.exports, mod.imports].forEach(function(declarations) { declarations.declarations.forEach(function(declaration) { declaration.specifiers.forEach(function(specifier) { return specifier.importSpecifier; }); }); }); }); this.replacements = replacements; for (var i = 0, length = modules.length; i < length; i++) { var mod = modules[i]; if (mod.exports.declarations.length > 0 || mod.imports.declarations.length > 0) { this.currentModule = mod; types.visit(mod.ast.program, this); } else { types.visit(mod.ast.program, new DeclarationLinterVisitor(mod)); } } this.currentModule = null; this.replacements = null; replacements.forEach(function(replacement) { if (replacement.replace) { replacement.replace(); } else { var path = replacement.shift(); path.replace.apply(path, replacement); } }); }; /** * Process all identifiers looking for references to variables in scope. * * @param {NodePath} nodePath * @return {boolean} * @private */ Rewriter.prototype.visitIdentifier = function(nodePath) { if (astUtil.isReference(nodePath)) { var exportReference = this.getExportReferenceForReference(this.currentModule, nodePath); if (exportReference) { this.replacements.push(Replacement.swaps(nodePath, exportReference)); } } return false; }; /** * Process all variable declarations looking for top-level exported variables. * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitVariableDeclaration = function(nodePath) { if (nodePath.scope.isGlobal) { var replacement = this.formatter.processVariableDeclaration(this.currentModule, nodePath); if (replacement) { this.replacements.push(replacement); } } this.traverse(nodePath); }; /** * We need to ensure that the LHS of this assignment is not an imported binding. * If it is, we throw a "compile"-time error since this is not allowed by the * spec (see section 12.14.1, Assignment Operators / Static Semantics: Early * Errors). * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitAssignmentExpression = function(nodePath) { this.assertImportIsNotReassigned(this.currentModule, nodePath.get('left')); if (this.currentModule.exports.findDeclarationForReference(nodePath.get('left'))) { var replacement = this.formatter.processExportReassignment(this.currentModule, nodePath); if (replacement) { this.replacements.push(replacement); } } this.traverse(nodePath); }; /** * Process all top-level function declarations in case they need to be processed. * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitFunctionDeclaration = function(nodePath) { if (n.Program.check(nodePath.parent.node)) { var replacement = this.formatter.processFunctionDeclaration(this.currentModule, nodePath); if (replacement) { this.replacements.push(replacement); } } this.traverse(nodePath); }; /** * Process all top-level class declarations in case they need to be processed. * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitClassDeclaration = function(nodePath) { if (n.Program.check(nodePath.parent.node)) { var replacement = this.formatter.processClassDeclaration(this.currentModule, nodePath); if (replacement) { this.replacements.push(replacement); } } this.traverse(nodePath); }; /** * Look for all export declarations so we can rewrite them. * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitExportDeclaration = function(nodePath) { assertStatementIsTopLevel(this.currentModule, nodePath); var replacement; if (nodePath.node.default) { /** * Default exports do not create bindings, so we can safely turn these * into expressions that do something with the exported value. * * Make sure that the exported value is replaced if it is a reference * to an imported binding. For example: * * import { foo } from './foo'; * export default foo; * * Might become: * * mod$$.default = foo$$.foo; */ var declaration = nodePath.node.declaration; var declarationPath = nodePath.get('declaration'); if (astUtil.isReference(declarationPath)) { var exportReference = this.getExportReferenceForReference(this.currentModule, declarationPath); if (exportReference) { declaration = exportReference; } } replacement = Replacement.swaps(nodePath, this.formatter.defaultExport(this.currentModule, declaration)); } else { replacement = this.formatter.processExportDeclaration(this.currentModule, nodePath); } if (replacement) { this.replacements.push(replacement); } this.traverse(nodePath); }; /** * Process import declarations so they can be rewritten. * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitImportDeclaration = function(nodePath) { assertStatementIsTopLevel(this.currentModule, nodePath); var replacement = this.formatter.processImportDeclaration(this.currentModule, nodePath); if (replacement) { this.replacements.push(replacement); } this.traverse(nodePath); }; /** * Process update expressions (e.g. `a++`) so we can re-write modifications to * exported variables. * * @param {NodePath} nodePath * @private */ Rewriter.prototype.visitUpdateExpression = function(nodePath) { this.assertImportIsNotReassigned(this.currentModule, nodePath.get('argument')); if (this.currentModule.exports.findDeclarationForReference(nodePath.get('argument'))) { var replacement = this.formatter.processExportReassignment(this.currentModule, nodePath); if (replacement) { this.replacements.push(replacement); } } this.traverse(nodePath); }; /** * We need to ensure that reference updates (i.e. `ref =`, `ref++`) are not * allowed for imported bindings. If it is, we throw a "compile"-time error * since this is not allowed by the spec (see section 12.14.1, Assignment * Operators / Static Semantics: Early Errors). * * @private * @param {Module} mod * @param {Identifier} nodePath */ Rewriter.prototype.assertImportIsNotReassigned = function(mod, nodePath) { var declarationPath; var identifierPath; var bindingDescription; if (n.Identifier.check(nodePath.node)) { // Do we have a named import… // // import { foo } from 'foo'; // // …that we then try to assign or update? // // foo++; // foo = 1; // declarationPath = mod.imports.findDeclarationForReference(nodePath); if (!declarationPath || !n.ImportSpecifier.check(declarationPath.parent.node)) { return; } bindingDescription = '`' + declarationPath.node.name + '`'; } else if (n.MemberExpression.check(nodePath.node)) { // Do we have a namespace import… // // import * as foo from 'foo'; // // …with a property that we then try to assign or update? // // foo.a++; // foo.a = 1; // foo['a'] = 1; // var objectPath = nodePath.get('object'); if (!n.Identifier.check(objectPath.node)) { return; } declarationPath = mod.imports.findDeclarationForReference(objectPath); if (!declarationPath || !n.ImportNamespaceSpecifier.check(declarationPath.parent.node)) { return; } var propertyPath = nodePath.get('property'); if (n.Identifier.check(propertyPath.node)) { bindingDescription = '`' + propertyPath.node.name + '`'; } else { bindingDescription = 'of namespace `' + objectPath.node.name + '`'; } } else { return; } throw new SyntaxError( 'Cannot reassign imported binding ' + bindingDescription + ' at ' + sourcePosition(mod, nodePath.node) ); }; /** * @private */ Rewriter.prototype.getExportReferenceForReference = function(mod, referencePath) { if (n.ExportSpecifier.check(referencePath.parent.node) && !referencePath.parent.node.default) { // Do not rewrite non-default export specifiers. return null; } /** * We need to replace references to variables that are imported or * exported with the correct export expression. The export expression * should be named for the original export for a variable. * * That is, imports must be followed to their export. If that exported * value came from an import then repeat the process until you find a * declaration of the exported value. */ var exportSpecifier = mod.exports.findSpecifierByName(referencePath.node.name); if (exportSpecifier && exportSpecifier.declaration.source && exportSpecifier.node !== referencePath.parent.node) { // This is a direct export from another module, e.g. `export { foo } from // 'foo'`. There are no local bindings created by this, so there is no // associated export for this reference and no need to rewrite it. return null; } return this.formatter.exportedReference(mod, referencePath) || this.formatter.importedReference(mod, referencePath) || this.formatter.localReference(mod, referencePath); }; /** * Traverses ASTs only checking for invalid import/export declaration semantics. * * @constructor * @extends types.PathVisitor * @param {Module} mod * @private */ function DeclarationLinterVisitor(mod) { this.module = mod; types.PathVisitor.call(this); } extend(DeclarationLinterVisitor, types.PathVisitor); /** * Checks that the import declaration is at the top level. * * @param {NodePath} nodePath */ DeclarationLinterVisitor.prototype.visitImportDeclaration = function(nodePath) { assertStatementIsTopLevel(this.module, nodePath); }; /** * Checks that the export declaration is at the top level. * * @param {NodePath} nodePath */ DeclarationLinterVisitor.prototype.visitExportDeclaration = function(nodePath) { assertStatementIsTopLevel(this.module, nodePath); }; /** * We need to ensure that all imports/exports are only at the top level. Esprima * should perhaps take care of this for us, but it does not. * * @param {Module} mod * @param {NodePath} nodePath * @private */ function assertStatementIsTopLevel(mod, nodePath) { if (!nodePath.scope.isGlobal) { throw new SyntaxError( 'Unexpected non-top level ' + nodePath.node.type + ' found at ' + sourcePosition(mod, nodePath.node) ); } } module.exports = Rewriter; es6-module-transpiler-0.10.0/lib/sorting.js000066400000000000000000000020501246026563300205260ustar00rootroot00000000000000/** * Determines the execution order of the given modules. This function resolves * cycles by preserving the order in which the modules are visited. * * @param {Module[]} modules * @return {Module[]} */ function sort(modules) { var result = []; var state = {}; modules.forEach(function(mod) { visit(mod, result, state); }); return result; } exports.sort = sort; /** * Visits the given module, adding it to `result` after visiting all of the * modules it imports, recursively. The `state` argument is private and maps * module ids to the current visit state. * * @private * @param {Module} mod * @param {Module[]} result * @param {Object.} state */ function visit(mod, result, state) { if (state[mod.id] === 'added') { // already in the list, ignore it return; } if (state[mod.id] === 'seen') { // cycle found, just ignore it return; } state[mod.id] = 'seen'; mod.imports.modules.forEach(function(mod) { visit(mod, result, state); }); state[mod.id] = 'added'; result.push(mod); } es6-module-transpiler-0.10.0/lib/utils.js000066400000000000000000000064631246026563300202150ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var recast = require('recast'); var n = recast.types.namedTypes; var b = recast.types.builders; var reserved = require('reserved'); var realFS = require('fs'); var Path = require('path'); var proto = '__proto__'; function memo(object, property, getter) { Object.defineProperty(object, property, { get: function() { this[property] = getter.call(this); return this[property]; }, set: function(value) { Object.defineProperty(this, property, { value: value, configurable: true, writable: true }); } }); } exports.memo = memo; function startsWith(string, substring) { return string.lastIndexOf(substring, 0) === 0; } exports.startsWith = startsWith; function endsWith(string, substring) { var expected = string.length - substring.length; return string.indexOf(substring, expected) === expected; } exports.endsWith = endsWith; function extend(subclass, superclass) { subclass[proto] = superclass; subclass.prototype = Object.create(superclass.prototype); subclass.prototype.constructor = subclass; } exports.extend = extend; function sourcePosition(mod, node) { var loc = node && node.loc; if (loc) { return mod.relativePath + ':' + loc.start.line + ':' + (loc.start.column + 1); } else { return mod.relativePath; } } exports.sourcePosition = sourcePosition; function IIFE() { var body = []; var args = Array.prototype.concat.apply(body, arguments); args.forEach(function(node) { if (n.Expression.check(node)) { node = b.expressionStatement(node); } if (n.Statement.check(node)) { body.push(node); } }); return b.callExpression( b.memberExpression( b.functionExpression(null, [], b.blockStatement(body)), b.identifier("call"), false ), [b.thisExpression()] ); } exports.IIFE = IIFE; /** * Create a member express that is compatible with ES3. Which means * reserved words will be treated as computed props. E.g.: * * foo["default"] // instead of `foo.default` * * while still supporting identifiers for non-reserved words: * * foo.bar // since bar is not reserved * * @param {Identifier} obj Identifier for the object reference * @param {Identifier|String} prop Identifier or string name for the member property * @return {b.memberExpression} AST for the member expression */ function compatMemberExpression(obj, prop) { var isIdentifier = n.Identifier.check(prop); var name = isIdentifier ? prop.name : prop; var computed = reserved.indexOf(name) >= 0; return b.memberExpression( obj, computed ? b.literal(name) : (isIdentifier ? prop : b.identifier(prop)), computed ); } exports.compatMemberExpression = compatMemberExpression; /** * Create a hierarchy of directories of it does not already exist. * * @param {string} path * @param {{fs: object=}} options */ function mkdirpSync(path, options) { var fs = options && options.fs || realFS; var ancestors = []; var ancestor = path; while (true) { var nextAncestor = Path.dirname(ancestor); if (nextAncestor === ancestor) { break; } ancestors.unshift(ancestor); ancestor = nextAncestor; } ancestors.forEach(function(dir) { if (!fs.existsSync(dir)) { fs.mkdirSync(dir); } }); } exports.mkdirpSync = mkdirpSync; es6-module-transpiler-0.10.0/lib/writer.js000066400000000000000000000040151246026563300203600ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); var recast = require('recast'); var fs = require('fs'); var Path = require('path'); var mkdirpSync = require('./utils').mkdirpSync; function Writer(target, options) { options = options || {}; this.target = target; this.basePath = options.basePath || process.cwd(); this.sourceRoot = options.sourceRoot; } Writer.prototype.write = function(files) { var target = this.target; switch (files.length) { case 0: throw new Error('expected at least one file to write, got zero'); case 1: // We got a single file, so `target` should refer to either a file or a // directory, but only if the file has a name. var isDirectory = false; try { isDirectory = fs.statSync(target).isDirectory(); } catch (ex) {} assert.ok( !isDirectory || files[0].filename, 'unable to determine filename for output to directory: ' + target ); this.writeFile( files[0], isDirectory ? Path.resolve(target, files[0].filename) : target ); break; default: // We got multiple files to output, so `target` should be a directory or // not exist (so we can create it). var self = this; files.forEach(function(file) { self.writeFile(file, Path.resolve(target, file.filename)); }); break; } }; Writer.prototype.writeFile = function(file, filename) { var sourceMapFilename = filename + '.map'; var rendered = recast.print(file, { sourceMapName: Path.relative(this.basePath, filename), sourceRoot: this.sourceRoot }); var code = rendered.code; assert.ok(filename, 'missing filename for file: ' + code); mkdirpSync(Path.dirname(filename)); if (rendered.map) { code += '\n\n//# sourceMappingURL=' + Path.basename(sourceMapFilename); fs.writeFileSync( sourceMapFilename, JSON.stringify(rendered.map), 'utf8' ); } fs.writeFileSync(filename, code, 'utf8'); }; module.exports = Writer; es6-module-transpiler-0.10.0/package.json000066400000000000000000000032131246026563300202250ustar00rootroot00000000000000{ "name": "es6-module-transpiler", "version": "0.10.0", "description": "es6-module-transpiler is an experimental compiler that allows you to write your JavaScript using a subset of the current ES6 module syntax, and compile it into various formats.", "homepage": "http://esnext.github.io/es6-module-transpiler", "keywords": [ "es6", "module", "transpile", "amd", "commonjs" ], "bugs": "https://github.com/square/es6-module-transpiler/issues", "bin": { "compile-modules": "./bin/compile-modules" }, "files": [ "bin", "lib", "LICENSE", "README.md" ], "directories": { "lib": "./lib", "test": "test" }, "main": "lib/index.js", "repository": { "type": "git", "url": "https://github.com/square/es6-module-transpiler.git" }, "scripts": { "test": "npm run test-bundle && npm run test-commonjs && npm run test-unit", "test-bundle": "node test/runner.js -f bundle", "test-commonjs": "node test/runner.js -f commonjs", "test-unit": "mocha -R spec test/unit", "build-standalone": "browserify -s ModuleTranspiler -e lib/index.js -o es6-module-transpiler.js" }, "author": "Square, Inc.", "license": "Apache-2.0", "dependencies": { "ast-util": "^0.5.1", "esprima-fb": "^7001.1.0-dev-harmony-fb", "posix-getopt": "^1.0.0", "recast": "^0.9.5", "reserved": "^0.1.2" }, "devDependencies": { "browserify": "^6.3.2", "es6-class": "^0.9.2", "example-runner": "^0.2.0", "fake-fs": "^0.5.0", "mocha": "^2.0.1", "tmp": "0.0.24" }, "browser": { "fs": "./lib/browser/fs.js", "./lib/index.js": "./lib/browser/index.js" } }es6-module-transpiler-0.10.0/test/000077500000000000000000000000001246026563300167175ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/000077500000000000000000000000001246026563300205355ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/bare-import/000077500000000000000000000000001246026563300227565ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/bare-import/exporter.js000066400000000000000000000000701246026563300251610ustar00rootroot00000000000000/* jshint esnext:true */ global.sideEffectyValue = 99; es6-module-transpiler-0.10.0/test/examples/bare-import/importer.js000066400000000000000000000001331246026563300251520ustar00rootroot00000000000000/* jshint esnext:true */ import './exporter'; assert.equal(global.sideEffectyValue, 99); es6-module-transpiler-0.10.0/test/examples/bindings/000077500000000000000000000000001246026563300223325ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/bindings/exporter.js000066400000000000000000000001271246026563300245400ustar00rootroot00000000000000/* jshint esnext:true */ export var count = 0; export function incr() { count++; } es6-module-transpiler-0.10.0/test/examples/bindings/importer.js000066400000000000000000000001751246026563300245340ustar00rootroot00000000000000/* jshint esnext:true */ import { count, incr } from './exporter'; assert.equal(count, 0); incr(); assert.equal(count, 1); es6-module-transpiler-0.10.0/test/examples/cycles-defaults/000077500000000000000000000000001246026563300236245ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/cycles-defaults/a.js000066400000000000000000000001421246026563300243770ustar00rootroot00000000000000/* jshint esnext:true */ import b from './b'; export default { a: 1, get b() { return b.b; } }; es6-module-transpiler-0.10.0/test/examples/cycles-defaults/b.js000066400000000000000000000001421246026563300244000ustar00rootroot00000000000000/* jshint esnext:true */ import a from './a'; export default { b: 2, get a() { return a.a; } }; es6-module-transpiler-0.10.0/test/examples/cycles-defaults/importer.js000066400000000000000000000002351246026563300260230ustar00rootroot00000000000000/* jshint esnext:true */ import a from './a'; import b from './b'; assert.equal(a.a, 1); assert.equal(a.b, 2); assert.equal(b.a, 1); assert.equal(b.b, 2); es6-module-transpiler-0.10.0/test/examples/cycles-immediate/000077500000000000000000000000001246026563300237535ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/cycles-immediate/evens.js000066400000000000000000000006721246026563300254360ustar00rootroot00000000000000/* jshint esnext:true */ import { nextOdd } from './odds'; /** * We go through these gymnastics to eager-bind to nextOdd. This is done to * ensure that both this module and the 'odds' module eagerly use something * from the other. */ export var nextEven = (function() { return function(n) { var no = nextOdd(n); return (no === n + 2) ? no - 1 : no; }; })(nextOdd); export function isEven(n) { return n % 2 === 0; } es6-module-transpiler-0.10.0/test/examples/cycles-immediate/main.js000066400000000000000000000017101246026563300252340ustar00rootroot00000000000000/* jshint esnext:true */ /** * The 'evens' and 'odds' modules are configured in such a way that they both * have two exported functions: isEven, nextEven, isOdd, and nextOdd. Normally * these four functions could be in any order regardless of which depends on * which because of JavaScript function hoisting. * * For the purposes of our test we need to prevent function hoisting, so it has * been arranged that two of them will be function expressions assigned to * variables. Specifically, isOdd and nextEven both eagerly evaluate their * dependencies (i.e. isEven and nextOdd). This allows us to test that exported * function declarations are available before what would be a module's * "execute" step, per the spec. */ import { nextEven, isEven } from './evens'; import { nextOdd, isOdd } from './odds'; assert.equal(nextEven(1), 2); assert.equal(nextOdd(1), 3); assert.ok(isOdd(1)); assert.ok(!isOdd(0)); assert.ok(isEven(0)); assert.ok(!isEven(1)); es6-module-transpiler-0.10.0/test/examples/cycles-immediate/odds.js000066400000000000000000000006321246026563300252430ustar00rootroot00000000000000/* jshint esnext:true */ import { isEven } from './evens'; export function nextOdd(n) { return isEven(n) ? n + 1 : n + 2; } /** * We go through these gymnastics to eager-bind to isEven. This is done to * ensure that both this module and the 'evens' module eagerly use something * from the other. */ export var isOdd = (function(isEven) { return function(n) { return !isEven(n); }; })(isEven); es6-module-transpiler-0.10.0/test/examples/cycles/000077500000000000000000000000001246026563300220175ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/cycles/a.js000066400000000000000000000001561246026563300225770ustar00rootroot00000000000000/* jshint esnext:true */ import { b } from './b'; export function getb() { return b; } export var a = 1; es6-module-transpiler-0.10.0/test/examples/cycles/b.js000066400000000000000000000001561246026563300226000ustar00rootroot00000000000000/* jshint esnext:true */ import { a } from './a'; export function geta() { return a; } export var b = 2; es6-module-transpiler-0.10.0/test/examples/cycles/c.js000066400000000000000000000002631246026563300226000ustar00rootroot00000000000000/* jshint esnext:true */ import { a, getb } from './a'; import { b, geta } from './b'; assert.equal(geta(), 1); assert.equal(a, 1); assert.equal(getb(), 2); assert.equal(b, 2); es6-module-transpiler-0.10.0/test/examples/duplicate-import-fails/000077500000000000000000000000001246026563300251135ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/duplicate-import-fails/exporter.js000066400000000000000000000000531246026563300273170ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 1;es6-module-transpiler-0.10.0/test/examples/duplicate-import-fails/importer.js000066400000000000000000000003301246026563300273060ustar00rootroot00000000000000/* jshint esnext:true */ /* error: type=SyntaxError message="expected one declaration for `a`, at importer.js:7:14 but found 2" */ import { a } from './exporter'; import { a } from './exporter'; assert.equal(a, 1);es6-module-transpiler-0.10.0/test/examples/duplicate-import-specifier-fails/000077500000000000000000000000001246026563300270625ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/duplicate-import-specifier-fails/exporter.js000066400000000000000000000000531246026563300312660ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 1;es6-module-transpiler-0.10.0/test/examples/duplicate-import-specifier-fails/importer.js000066400000000000000000000002721246026563300312620ustar00rootroot00000000000000/* jshint esnext:true */ /* error: type=SyntaxError message="expected one declaration for `a`, at importer.js:5:14 but found 2" */ import { a, a } from './exporter'; assert.equal(a, 1);es6-module-transpiler-0.10.0/test/examples/export-and-import-reference-share-var/000077500000000000000000000000001246026563300277505ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-and-import-reference-share-var/first.js000066400000000000000000000000771246026563300314410ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 1; assert.equal(a, 1);es6-module-transpiler-0.10.0/test/examples/export-and-import-reference-share-var/second.js000066400000000000000000000006201246026563300315570ustar00rootroot00000000000000/* jshint esnext:true */ import { a } from './first'; // This variable declaration is going to be altered because `b` needs to be // re-written. We need to make sure that the `a` re-writing and the unaffected // `c` declarator are not being clobbered by that alteration. var a_ = a, b = 9, c = 'c'; assert.equal(a, 1); assert.equal(a_, 1); assert.equal(b, 9); assert.equal(c, 'c'); export { b }; es6-module-transpiler-0.10.0/test/examples/export-class-expression/000077500000000000000000000000001246026563300253565ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-class-expression/exporter.js000066400000000000000000000000631246026563300275630ustar00rootroot00000000000000/* jshint esnext:true */ export default class {}; es6-module-transpiler-0.10.0/test/examples/export-class-expression/importer.js000066400000000000000000000001511246026563300275520ustar00rootroot00000000000000/* jshint esnext:true */ import Foo from './exporter'; assert.strictEqual(new Foo().constructor, Foo); es6-module-transpiler-0.10.0/test/examples/export-class/000077500000000000000000000000001246026563300231615ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-class/exporter.js000066400000000000000000000000561246026563300253700ustar00rootroot00000000000000/* jshint esnext:true */ export class Foo {} es6-module-transpiler-0.10.0/test/examples/export-class/importer.js000066400000000000000000000001551246026563300253610ustar00rootroot00000000000000/* jshint esnext:true */ import { Foo } from './exporter'; assert.strictEqual(new Foo().constructor, Foo); es6-module-transpiler-0.10.0/test/examples/export-default-class/000077500000000000000000000000001246026563300246035ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-default-class/exporter.js000066400000000000000000000001631246026563300270110ustar00rootroot00000000000000/* jshint esnext:true */ export default class Point { constructor(x, y) { this.x = x; this.y = y; } } es6-module-transpiler-0.10.0/test/examples/export-default-class/importer.js000066400000000000000000000002171246026563300270020ustar00rootroot00000000000000/* jshint esnext:true */ import Point from './exporter'; assert.strictEqual(new Point(1, 2).x, 1); assert.strictEqual(new Point(1, 2).y, 2); es6-module-transpiler-0.10.0/test/examples/export-default-function/000077500000000000000000000000001246026563300253235ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-default-function/exporter.js000066400000000000000000000001051246026563300275250ustar00rootroot00000000000000/* jshint esnext:true */ export default function () { return 1; } es6-module-transpiler-0.10.0/test/examples/export-default-function/importer.js000066400000000000000000000002271246026563300275230ustar00rootroot00000000000000/* jshint esnext:true */ import fn1 from './exporter'; import { default as fn2 } from './exporter'; assert.equal(fn1(), 1); assert.equal(fn2(), 1); es6-module-transpiler-0.10.0/test/examples/export-default-named-function/000077500000000000000000000000001246026563300264055ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-default-named-function/exporter.js000066400000000000000000000001351246026563300306120ustar00rootroot00000000000000export default function foo() { return 1; } export function callsFoo() { return foo(); }es6-module-transpiler-0.10.0/test/examples/export-default-named-function/importer.js000066400000000000000000000001551246026563300306050ustar00rootroot00000000000000import foo, { callsFoo } from './exporter'; assert.strictEqual(foo(), 1); assert.strictEqual(callsFoo(), 1);es6-module-transpiler-0.10.0/test/examples/export-default/000077500000000000000000000000001246026563300235005ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-default/exporter.js000066400000000000000000000005401246026563300257050ustar00rootroot00000000000000/* jshint esnext:true */ var a = 42; export function change() { a++; } assert.equal(a, 42); export default a; // Any replacement for the `export default` above needs to happen in the same // location. It cannot be done, say, at the end of the file. Otherwise the new // value of `a` will be used and will be incorrect. a = 0; assert.equal(a, 0); es6-module-transpiler-0.10.0/test/examples/export-default/importer.js000066400000000000000000000003121246026563300256730ustar00rootroot00000000000000/* jshint esnext:true */ import value from './exporter'; import { change } from './exporter'; assert.equal(value, 42); change(); assert.equal( value, 42, 'default export should not be bound' ); es6-module-transpiler-0.10.0/test/examples/export-from-default/000077500000000000000000000000001246026563300244415ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-from-default/first.js000066400000000000000000000000541246026563300261250ustar00rootroot00000000000000/* jshint esnext:true */ export default 1; es6-module-transpiler-0.10.0/test/examples/export-from-default/second.js000066400000000000000000000000751246026563300262540ustar00rootroot00000000000000/* jshint esnext:true */ export { default } from './first'; es6-module-transpiler-0.10.0/test/examples/export-from-default/third.js000066400000000000000000000001101246026563300261010ustar00rootroot00000000000000/* jshint esnext:true */ import a from './second'; assert.equal(a, 1); es6-module-transpiler-0.10.0/test/examples/export-from/000077500000000000000000000000001246026563300230175ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-from/first.js000066400000000000000000000000541246026563300245030ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 1; es6-module-transpiler-0.10.0/test/examples/export-from/second.js000066400000000000000000000003041246026563300246250ustar00rootroot00000000000000/* jshint esnext:true */ export { a } from './first'; // This `a` reference should not be re-written because this export is not // creating a local binding. assert.equal(typeof a, 'undefined'); es6-module-transpiler-0.10.0/test/examples/export-from/third.js000066400000000000000000000001141246026563300244630ustar00rootroot00000000000000/* jshint esnext:true */ import { a } from './second'; assert.equal(a, 1); es6-module-transpiler-0.10.0/test/examples/export-function/000077500000000000000000000000001246026563300237015ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-function/exporter.js000066400000000000000000000001341246026563300261050ustar00rootroot00000000000000/* jshint esnext:true */ export function foo() { return 121; } assert.equal(foo(), 121); es6-module-transpiler-0.10.0/test/examples/export-function/importer.js000066400000000000000000000001261246026563300260770ustar00rootroot00000000000000/* jshint esnext:true */ import { foo } from './exporter'; assert.equal(foo(), 121); es6-module-transpiler-0.10.0/test/examples/export-list/000077500000000000000000000000001246026563300230275ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-list/exporter.js000066400000000000000000000002551246026563300252370ustar00rootroot00000000000000/* jshint esnext:true */ var a = 1; var b = 2; function incr() { var c = a++; // Capture `a++` to force us to use a temporary variable. b++; } export { a, b, incr }; es6-module-transpiler-0.10.0/test/examples/export-list/importer.js000066400000000000000000000002341246026563300252250ustar00rootroot00000000000000/* jshint esnext:true */ import { a, b, incr } from './exporter'; assert.equal(a, 1); assert.equal(b, 2); incr(); assert.equal(a, 2); assert.equal(b, 3); es6-module-transpiler-0.10.0/test/examples/export-mixins/000077500000000000000000000000001246026563300233635ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-mixins/exporter.js000066400000000000000000000000461246026563300255710ustar00rootroot00000000000000export default 1; export var bar = 2; es6-module-transpiler-0.10.0/test/examples/export-mixins/importer.js000066400000000000000000000001241246026563300255570ustar00rootroot00000000000000import foo, { bar } from './exporter'; assert.equal(foo, 1); assert.equal(bar, 2); es6-module-transpiler-0.10.0/test/examples/export-named-class/000077500000000000000000000000001246026563300242435ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-named-class/exporter.js000066400000000000000000000000671246026563300264540ustar00rootroot00000000000000/* jshint esnext:true */ class Foo {} export { Foo }; es6-module-transpiler-0.10.0/test/examples/export-named-class/importer.js000066400000000000000000000001551246026563300264430ustar00rootroot00000000000000/* jshint esnext:true */ import { Foo } from './exporter'; assert.strictEqual(new Foo().constructor, Foo); es6-module-transpiler-0.10.0/test/examples/export-not-at-top-level-fails/000077500000000000000000000000001246026563300262575ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-not-at-top-level-fails/index.js000066400000000000000000000002041246026563300277200ustar00rootroot00000000000000/* jshint esnext:true */ function foo() { /* error: type=Error message="Line 5: Unexpected reserved word" */ export { foo }; } es6-module-transpiler-0.10.0/test/examples/export-var/000077500000000000000000000000001246026563300226445ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/export-var/exporter.js000066400000000000000000000001001246026563300250410ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 1; assert.equal(a, 1); es6-module-transpiler-0.10.0/test/examples/export-var/importer.js000066400000000000000000000001161246026563300250410ustar00rootroot00000000000000/* jshint esnext:true */ import { a } from './exporter'; assert.equal(a, 1); es6-module-transpiler-0.10.0/test/examples/import-as/000077500000000000000000000000001246026563300224505ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/import-as/exporter.js000066400000000000000000000001301246026563300246500ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 'a'; export var b = 'b'; export default 'DEF'; es6-module-transpiler-0.10.0/test/examples/import-as/importer.js000066400000000000000000000002361246026563300246500ustar00rootroot00000000000000/* jshint esnext:true */ import { a as b, b as a, default as def } from './exporter'; assert.equal(b, 'a'); assert.equal(a, 'b'); assert.equal(def, 'DEF'); es6-module-transpiler-0.10.0/test/examples/import-chain/000077500000000000000000000000001246026563300231275ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/import-chain/first.js000066400000000000000000000000611246026563300246110ustar00rootroot00000000000000/* jshint esnext:true */ export var value = 42; es6-module-transpiler-0.10.0/test/examples/import-chain/second.js000066400000000000000000000001151246026563300247350ustar00rootroot00000000000000/* jshint esnext:true */ import { value } from './first'; export { value }; es6-module-transpiler-0.10.0/test/examples/import-chain/third.js000066400000000000000000000001251246026563300245750ustar00rootroot00000000000000/* jshint esnext:true */ import { value } from './second'; assert.equal(value, 42); es6-module-transpiler-0.10.0/test/examples/import-not-at-top-level-fails/000077500000000000000000000000001246026563300262505ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/import-not-at-top-level-fails/index.js000066400000000000000000000002171246026563300277150ustar00rootroot00000000000000/* jshint esnext:true */ function foo() { /* error: type=Error message="Line 5: Unexpected reserved word" */ import foo from './index'; } es6-module-transpiler-0.10.0/test/examples/module-level-declarations/000077500000000000000000000000001246026563300255755ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/module-level-declarations/mod.js000066400000000000000000000001311246026563300267050ustar00rootroot00000000000000var a = 1; assert.equal(a, 1); assert.equal(getA(), 1); function getA() { return a; }es6-module-transpiler-0.10.0/test/examples/named-function-expression/000077500000000000000000000000001246026563300256415ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/named-function-expression/exporter.js000066400000000000000000000000211246026563300300400ustar00rootroot00000000000000export var a = 1;es6-module-transpiler-0.10.0/test/examples/named-function-expression/importer.js000066400000000000000000000002231246026563300300350ustar00rootroot00000000000000import { a } from './exporter'; var getA = function getA() { var a = 2; return a; }; assert.strictEqual(a, 1); assert.strictEqual(getA(), 2);es6-module-transpiler-0.10.0/test/examples/namespace-reassign-import-fails/000077500000000000000000000000001246026563300267065ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/namespace-reassign-import-fails/exporter.js000066400000000000000000000000551246026563300311140ustar00rootroot00000000000000/* jshint esnext:true */ export var foo = 1;es6-module-transpiler-0.10.0/test/examples/namespace-reassign-import-fails/importer.js000066400000000000000000000002541246026563300311060ustar00rootroot00000000000000/* jshint esnext:true */ import * as exp from './exporter'; /* error: type=SyntaxError message="Cannot reassign imported binding `foo` at importer.js:6:1" */ exp.foo = 2;es6-module-transpiler-0.10.0/test/examples/namespace-update-import-fails/000077500000000000000000000000001246026563300263555ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/namespace-update-import-fails/exporter.js000066400000000000000000000000551246026563300305630ustar00rootroot00000000000000/* jshint esnext:true */ export var foo = 1;es6-module-transpiler-0.10.0/test/examples/namespace-update-import-fails/importer.js000066400000000000000000000002721246026563300305550ustar00rootroot00000000000000/* jshint esnext:true */ import * as exp from './exporter'; /* error: type=SyntaxError message="Cannot reassign imported binding of namespace `exp` at importer.js:6:1" */ exp['foo']++;es6-module-transpiler-0.10.0/test/examples/namespaces/000077500000000000000000000000001246026563300226545ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/namespaces/exporter.js000066400000000000000000000001301246026563300250540ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 'a'; export var b = 'b'; export default 'DEF'; es6-module-transpiler-0.10.0/test/examples/namespaces/importer.js000066400000000000000000000004101246026563300250460ustar00rootroot00000000000000/* jshint esnext:true */ import * as foo from './exporter'; assert.equal(foo['default'], 'DEF'); assert.equal(foo.b, 'b'); assert.equal(foo.a, 'a'); var keys = []; for (var key in foo) { keys.push(key); } assert.deepEqual(keys.sort(), ['a', 'b', 'default']); es6-module-transpiler-0.10.0/test/examples/re-export-default-import/000077500000000000000000000000001246026563300254145ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/re-export-default-import/first.js000066400000000000000000000001121246026563300270730ustar00rootroot00000000000000/* jshint esnext:true */ export default function hi() { return 'hi'; } es6-module-transpiler-0.10.0/test/examples/re-export-default-import/second.js000066400000000000000000000001021246026563300272160ustar00rootroot00000000000000/* jshint esnext:true */ import hi from './first'; export { hi }; es6-module-transpiler-0.10.0/test/examples/re-export-default-import/third.js000066400000000000000000000001231246026563300270600ustar00rootroot00000000000000/* jshint esnext:true */ import { hi } from './second'; assert.equal(hi(), 'hi'); es6-module-transpiler-0.10.0/test/examples/re-export-namespace-import/000077500000000000000000000000001246026563300257245ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/re-export-namespace-import/first.js000066400000000000000000000000441246026563300274070ustar00rootroot00000000000000export var a = 1; export var b = 2; es6-module-transpiler-0.10.0/test/examples/re-export-namespace-import/second.js000066400000000000000000000000601246026563300275310ustar00rootroot00000000000000import * as mod from './first'; export { mod }; es6-module-transpiler-0.10.0/test/examples/re-export-namespace-import/third.js000066400000000000000000000001351246026563300273730ustar00rootroot00000000000000import { mod } from './second'; assert.strictEqual(mod.a, 1); assert.strictEqual(mod.b, 2); es6-module-transpiler-0.10.0/test/examples/reassign-import-fails/000077500000000000000000000000001246026563300247545ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/reassign-import-fails/exporter.js000066400000000000000000000000531246026563300271600ustar00rootroot00000000000000/* jshint esnext:true */ export var x = 1;es6-module-transpiler-0.10.0/test/examples/reassign-import-fails/importer.js000066400000000000000000000003711246026563300271540ustar00rootroot00000000000000/* jshint esnext:true */ import { x } from './exporter'; (function() { for(var x = 0; x < 1; x++){} for(var x = 0; x < 1; x++){} }); /* error: type=SyntaxError message="Cannot reassign imported binding `x` at importer.js:11:1" */ x = 10; es6-module-transpiler-0.10.0/test/examples/reassign-import-not-at-top-level-fails/000077500000000000000000000000001246026563300300615ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/reassign-import-not-at-top-level-fails/exporter.js000066400000000000000000000000541246026563300322660ustar00rootroot00000000000000/* jshint esnext:true */ export var x = 1; es6-module-transpiler-0.10.0/test/examples/reassign-import-not-at-top-level-fails/importer.js000066400000000000000000000003521246026563300322600ustar00rootroot00000000000000/* jshint esnext:true */ import { x } from './exporter'; export function foo () { var x = 1; } export function bar () { /* error: type=SyntaxError message="Cannot reassign imported binding `x` at importer.js:10:3" */ x = 1; } es6-module-transpiler-0.10.0/test/examples/this-is-global/000077500000000000000000000000001246026563300233535ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/this-is-global/mod.js000066400000000000000000000002601246026563300244660ustar00rootroot00000000000000/* jshint esnext:true */ assert.strictEqual( this, global, '`this` (keys=' + Object.keys(this) + ') does not equal ' + '`global` (keys=' + Object.keys(global) + ')' );es6-module-transpiler-0.10.0/test/examples/update-expression-of-import-fails/000077500000000000000000000000001246026563300272225ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/examples/update-expression-of-import-fails/exporter.js000066400000000000000000000000531246026563300314260ustar00rootroot00000000000000/* jshint esnext:true */ export var a = 0;es6-module-transpiler-0.10.0/test/examples/update-expression-of-import-fails/importer.js000066400000000000000000000002371246026563300314230ustar00rootroot00000000000000/* jshint esnext:true */ import { a } from './exporter'; /* error: type=SyntaxError message="Cannot reassign imported binding `a` at importer.js:6:1" */ a++;es6-module-transpiler-0.10.0/test/runner.js000066400000000000000000000141321246026563300205670ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ Error.stackTraceLimit = 50; var fs = require('fs'); var Path = require('path'); var vm = require('vm'); var assert = require('assert'); var es6class = require('es6-class'); var modules = require('../lib'); var utils = require('../lib/utils'); var endsWith = utils.endsWith; var ExpectedError = require('./support/expected_error'); var examples = Path.join(__dirname, 'examples'); var paths = []; var formatters = require('../lib/formatters'); var formatterNames = Object.keys(formatters).filter(function(formatter) { return formatter !== 'DEFAULT'; }); var formatter = formatters.DEFAULT; var getopt = require('posix-getopt'); var parser = new getopt.BasicParser('h(help)f:(format)', process.argv); var option; while ((option = parser.getopt()) !== undefined) { if (option.error) { usage(); process.exit(1); } switch (option.option) { case 'f': formatter = option.optarg; if (formatterNames.indexOf(formatter) < 0) { usage(); process.exit(1); } break; case 'h': usage(); process.exit(0); break; } } paths.push.apply(paths, process.argv.slice(parser.optind())); if (paths.length === 0) { paths = fs.readdirSync(examples).map(function(example) { return Path.join(examples, example); }); } else { var cwd = process.cwd(); paths = paths.map(function(example) { return Path.resolve(cwd, example); }); } var results = Path.join(__dirname, 'results'); if (fs.existsSync(results)) { rmrf(results); } fs.mkdirSync(results); runTests(paths); function runTests(paths) { var passed = 0, failed = 0; paths.forEach(function(path) { if (runTestDir(path)) { passed++; } else { failed++; } }); console.log(); console.log('%d passed, %s failed.', passed, failed); process.exit( (passed + failed === 0) ? 1 : // no tests, fail failed === 0 ? 0 : // no failed, pass 1); // some failed, fail } function runTestDir(testDir) { var passed = false; var testName = Path.basename(testDir); var options = { resolvers: [new modules.FileResolver([testDir])], formatter: formatters[formatter] }; var container = new modules.Container(options); var expectedError; try { fs.readdirSync(testDir).forEach(function(child) { var mod = container.getModule(child); var contents = fs.readFileSync(mod.path).toString(); var newExpectedError = ExpectedError.getFromSource(contents); assert.ok( !newExpectedError || !expectedError, 'found more than one error comment!' ); expectedError = newExpectedError; }); var resultPath = Path.join(results, testName + '.js'); container.write(resultPath); var testAssert = wrappedAssert(); if (fs.statSync(resultPath).isDirectory()) { fs.readdirSync(resultPath).forEach(function(child) { if (Path.extname(child) === '.js') { requireTestFile('./' + child, resultPath, testAssert); } }); } else { requireTestFile(resultPath, process.cwd(), testAssert); } assert.ok( expectedError || testAssert.count > 0, 'expected at least one assertion' ); if (expectedError) { expectedError.assertMatch(null); } passed = true; printSuccess(testName); } catch (ex) { if (!(ex instanceof assert.AssertionError) && expectedError) { ex = expectedError.matchError(ex); } if (ex) { printFailure(testName, ex); console.log(); } else { printSuccess(testName); passed = true; } } return passed; } // TODO: Just use the real node require system with proxyquire? var testFileCache; var testFileGlobal; function requireTestFile(path, relativeTo, assert) { if (path[0] === '.') { path = Path.resolve(relativeTo, path); } if (!testFileCache) { testFileCache = {}; } if (path in testFileCache) { return testFileCache[path]; } else if (!fs.existsSync(path) && !endsWith(path, '.js')) { return requireTestFile(path + '.js'); } var code = fs.readFileSync(path); var mod = {exports: {}}; testFileCache[path] = mod.exports; if (!testFileGlobal) { testFileGlobal = {}; } testFileGlobal.assert = assert; testFileGlobal.global = testFileGlobal; testFileGlobal.module = mod; testFileGlobal.exports = mod.exports; testFileGlobal.require = function(requiredPath) { return requireTestFile(requiredPath, Path.dirname(path), assert); }; // Hack to work around an issue where vm does not set `this` to the context. code = '(function(){' + es6class.compile(code).code + '\n}).call(global);'; vm.runInNewContext(code, testFileGlobal, path); testFileCache[path] = mod.exports; return mod.exports; } function wrappedAssert() { var result = {count: 0}; Object.getOwnPropertyNames(assert).forEach(function(property) { result[property] = function() { result.count++; return assert[property].apply(assert, arguments); }; }); return result; } function rmrf(path) { var stat = fs.statSync(path); if (stat.isDirectory()) { fs.readdirSync(path).forEach(function(child) { rmrf(Path.join(path, child)); }); fs.rmdirSync(path); } else if (stat.isFile()) { fs.unlinkSync(path); } } /** * Prints a line to stdout for the given test indicating that it passed. * * @param {string} testName */ function printSuccess(testName) { console.log('\x1b[32m✓ \x1b[0m' + testName); } /** * Prints a line to stdout for the given test indicating that it failed. In * addition, prints any additional information indented one level. * * @param {string} testName * @param {Error} error */ function printFailure(testName, error) { console.log('\x1b[31m✘ ' + testName + '\x1b[0m'); console.log(); if (error.stack) { console.log(error.stack); } else { console.log(error.message); } } function usage() { console.log('node test/runner.js [OPTIONS] [EXAMPLE1 [EXAMPLE2 ...]]'); console.log(); console.log(' -f, --format Choose from: %s.', formatterNames.join(', ')); console.log(' -h, --help Show this help message.'); } es6-module-transpiler-0.10.0/test/support/000077500000000000000000000000001246026563300204335ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/support/expected_error.js000066400000000000000000000055031246026563300240060ustar00rootroot00000000000000/* jshint node:true, undef:true, unused:true */ var assert = require('assert'); /** * @param {string|Error=} type * @param {string=} message * @constructor */ function ExpectedError(type, message) { this.type = type; this.message = message; } /** * Builds an ExpectedError from the given source code. * * @param {string} source * @return {?ExpectedError} */ ExpectedError.getFromSource = function(source) { var errorMatch = source.match(/\/\*\s*error:\s*(.+?)\*\//); if (!errorMatch) { return null; } var errorInfo = errorMatch[1]; var expectedTypeMatch = errorInfo.match(/type=([a-zA-Z]+)/); var expectedMessageMatch = errorInfo.match(/message="([^"]+)"/); assert.ok( expectedTypeMatch || expectedMessageMatch, 'expected error comment contains neither a type or a message: ' + errorInfo ); return new ExpectedError( expectedTypeMatch && expectedTypeMatch[1], expectedMessageMatch && expectedMessageMatch[1] ); }; /** * Determines whether the given error matches the expected error type. * * @param {!Error} error * @return {boolean} */ ExpectedError.prototype.matchesType = function(error) { return !this.type || (typeof this.type === 'function' && error instanceof this.type) || (this.type === error.constructor) || (this.type === error.constructor.name); }; /** * Determines whether the given error matches the expected error message. * * @param {!Error} error * @return {boolean} */ ExpectedError.prototype.matchesMessage = function(error) { return !this.message || (this.message === error.message) || (this.message.test && this.message.test(error.message)); }; /** * Asserts that the given error matches the expected error info. * * @param {?Error} error */ ExpectedError.prototype.assertMatch = function(error) { var matchError = this.matchError(error); if (matchError) { throw matchError; } }; /** * Gets the error to throw if the given error does not match. * * @param {?Error} error * @return {?AssertionError} */ ExpectedError.prototype.matchError = function(error) { var matchesType = error && this.matchesType(error); var matchesMessage = error && this.matchesMessage(error); if (matchesType && matchesMessage) { return null; } var assertMessage = 'expected error'; if (!matchesType && this.type) { assertMessage += ' type to equal ' + this.type; if (!matchesMessage && this.message) { assertMessage += ' and'; } } if (!matchesMessage && this.message) { assertMessage += ' message to match ' + (typeof this.message === 'string' ? '"' + this.message + '"' : this.message); } if (error) { assertMessage += ', but got ' + error; } else { assertMessage += ', but no error was thrown' } return new assert.AssertionError({ message: assertMessage }); }; module.exports = ExpectedError; es6-module-transpiler-0.10.0/test/support/test_formatter.js000066400000000000000000000030451246026563300240350ustar00rootroot00000000000000var Formatter = require('../../lib/formatters/formatter'); var extend = require('../../lib/utils').extend; /** * This basic formatter does not alter the AST at all, and only exists * help write unit tests for things that depend on formatters. * * @class * @extends Formatter */ function TestFormatter() { Formatter.call(this); this.processedExportDeclarationCount = 0; this.processedExportReassignmentCount = 0; this.processedImportDeclarationCount = 0; this.processedFunctionDeclarationCount = 0; this.processedVariableDeclarationCount = 0; } extend(TestFormatter, Formatter); /** * @override */ TestFormatter.prototype.build = function(modules) { return modules.map(function(mod) { var ast = mod.ast; ast.filename = mod.relativePath; return ast; }); }; /** * @override */ TestFormatter.prototype.processExportDeclaration = function() { this.processedExportDeclarationCount++; return null; }; /** * @override */ TestFormatter.prototype.processExportReassignment = function() { this.processedExportReassignmentCount++; return null; }; /** * @override */ TestFormatter.prototype.processImportDeclaration = function() { this.processedImportDeclarationCount++; return null; }; /** * @override */ TestFormatter.prototype.processFunctionDeclaration = function() { this.processedFunctionDeclarationCount++; return null; }; /** * @override */ TestFormatter.prototype.processVariableDeclaration = function() { this.processedVariableDeclarationCount++; return null; }; exports.TestFormatter = TestFormatter; es6-module-transpiler-0.10.0/test/support/test_resolver.js000066400000000000000000000015441246026563300236750ustar00rootroot00000000000000var Module = require('../../lib/module'); var Path = require('path'); /** * This basic resolver just returns a module whose #src is set to an * empty string to prevent an attempt to read from the file system. * * @class * @param {Object.=} sources */ function TestResolver(sources) { this.sources = sources || {}; } /** * @param {string} path * @param {Module} mod * @param {Container} container * @returns {Module} */ TestResolver.prototype.resolveModule = function(path, mod, container) { if (mod) { path = Path.normalize(Path.join(mod.relativePath, '..', path)); } var cachedModule = container.getCachedModule(path); if (cachedModule) { return cachedModule; } var resolved = new Module(path, path, container); resolved.src = this.sources[path] || ''; return resolved; }; exports.TestResolver = TestResolver; es6-module-transpiler-0.10.0/test/unit/000077500000000000000000000000001246026563300176765ustar00rootroot00000000000000es6-module-transpiler-0.10.0/test/unit/container_test.js000066400000000000000000000070541246026563300232630ustar00rootroot00000000000000var Container = require('../../lib/container'); var Module = require('../../lib/module'); var Path = require('path'); var TestFormatter = require('../support/test_formatter').TestFormatter; var TestResolver = require('../support/test_resolver').TestResolver; var assert = require('assert'); var fs = require('fs'); var tmp = require('tmp'); describe('Container', function() { describe('#write', function() { it('allows multiple calls but only converts once', function(done) { var buildCallCount = 0; var source = 'var a = 1;'; var formatter = new TestFormatter(); /** * This formatter only exists to count the number of times #build is * called and create a result of the right data structure. * * @param {Module[]} modules * @returns {File[]} */ formatter.build = function(modules) { buildCallCount++; return TestFormatter.prototype.build.call(this, modules); }; var container = new Container({ formatter: formatter, resolvers: [new TestResolver({ 'a.js': source })] }); // Ensure we have a module to write at all. container.getModule('a.js'); tmp.dir(function(err, path) { if (err) { return done(err); } // Write the contents to a temporary directory. container.write(path); assert.strictEqual(buildCallCount, 1); // Ensure that the written file contains the original code. var a1 = fs.readFileSync(Path.join(path, 'a.js'), 'utf8'); assert.ok( a1.indexOf(source) === 0, 'expected written source to start with original source, but was: ' + a1 ); tmp.dir(function(err, path2) { if (err) { return done(err); } assert.notStrictEqual(path, path2); // Write to yet another temporary directory with the same container. container.write(path2); assert.strictEqual(buildCallCount, 1); // Ensure that the written file contains the original code. var a2 = fs.readFileSync(Path.join(path2, 'a.js'), 'utf8'); assert.ok( a2.indexOf(source) === 0, 'expected written source to start with original source, but was: ' + a2 ); done(); }); }); }); it('freezes the container, effectively preventing adding new modules', function(done) { var container = new Container({ formatter: new TestFormatter(), resolvers: [new TestResolver()] }); container.getModule('a.js'); tmp.dir(function(err, path) { if (err) { return done(err); } container.write(path); try { container.getModule('b.js'); assert.fail('expected an exception'); } catch (ex) { assert.strictEqual( 'container has already converted contained modules and cannot add new module: b.js', ex.message ); } done(); }); }); }); describe('#transform', function() { var formatter = new TestFormatter(); var source = 'export var a = 1;'; var container = new Container({ formatter: formatter, resolvers: [new TestResolver({ 'a.js': source })] }); // Ensure we have a module to write at all. container.getModule('a.js'); var files = container.transform(); assert.strictEqual(files.length, 1); assert.strictEqual(files[0].filename, 'a.js'); assert.strictEqual(files[0].code, source); assert.strictEqual(typeof files[0].map, 'object'); }); }); es6-module-transpiler-0.10.0/test/unit/mkdirp_test.js000066400000000000000000000027721246026563300225710ustar00rootroot00000000000000var assert = require('assert'); var mkdirpSync = require('../../lib/utils').mkdirpSync; describe('mkdirpSync', function() { var calls; var fs = { existsSync: function(path) { calls.push(['existsSync', path]); return path === '/' || path === '/path' || path === 'path'; }, mkdirSync: function(path) { calls.push(['mkdirSync', path]); } }; beforeEach(function() { calls = []; }); context('given absolute paths', function() { it('checks each path component, making the ones that do not exist', function() { mkdirpSync('/path/to/some/dir', { fs: fs }); assert.deepEqual( calls, [ ['existsSync', '/path'], ['existsSync', '/path/to'], ['mkdirSync', '/path/to'], ['existsSync', '/path/to/some'], ['mkdirSync', '/path/to/some'], ['existsSync', '/path/to/some/dir'], ['mkdirSync', '/path/to/some/dir'] ] ); }); }); context('given relative paths', function() { it('checks each path component, making the ones that do not exist', function() { mkdirpSync('path/to/some/dir', { fs: fs }); assert.deepEqual( calls, [ ['existsSync', 'path'], ['existsSync', 'path/to'], ['mkdirSync', 'path/to'], ['existsSync', 'path/to/some'], ['mkdirSync', 'path/to/some'], ['existsSync', 'path/to/some/dir'], ['mkdirSync', 'path/to/some/dir'] ] ); }); }); });es6-module-transpiler-0.10.0/test/unit/module_binding_specifier_test.js000066400000000000000000000074251246026563300263130ustar00rootroot00000000000000var assert = require('assert'); var Container = require('../../lib/container'); var Module = require('../../lib/module'); var TestFormatter = require('../support/test_formatter').TestFormatter; var TestResolver = require('../support/test_resolver').TestResolver; describe('ModuleBindingSpecifier', function() { describe('#terminalExportSpecifier', function() { var sources; var container; beforeEach(function() { container = new Container({ formatter: new TestFormatter(), resolvers: [new TestResolver(sources)] }); }); function getExportSpecifier(modulePath, exportedName) { var mod = container.getModule(modulePath); var specifier = mod.exports.findSpecifierByName(exportedName); if (!specifier) { throw new Error('unable to find export `' + exportedName + '` in module: ' + modulePath); } return specifier; } context('when the export is a variable declaration', function() { before(function() { sources = { 'index.js': 'export var a = 1;' }; }); it('is the export itself', function() { var specifier = getExportSpecifier('index.js', 'a'); assert.strictEqual(specifier.terminalExportSpecifier, specifier); }); }); context('when the export is a function declaration', function() { before(function() { sources = { 'index.js': 'export function a() {}' }; }); it('is the export itself', function() { var specifier = getExportSpecifier('index.js', 'a'); assert.strictEqual(specifier.terminalExportSpecifier, specifier); }); }); context('when the export binds an import by name from another module', function() { before(function() { sources = { 'index.js': 'import { a } from "middle.js";\nexport { a };', 'middle.js': 'import { a } from "root.js";\nexport { a };', 'root.js': 'export var a = 1;' }; }); it('follows the trail of imports until it finds the original', function() { var rootA = getExportSpecifier('root.js', 'a'); var specifier = getExportSpecifier('index.js', 'a'); assert.strictEqual( specifier.terminalExportSpecifier, rootA, 'expected ' + specifier.terminalExportSpecifier + ' to equal ' + rootA ); }); }); context('when the export directly re-exports a binding by name from another module', function() { before(function() { sources = { 'index.js': 'import { a } from "middle.js";\nexport { a };', 'middle.js': 'export { a } from "root.js";', 'root.js': 'export var a = 1;' }; }); it('follows the trail of imports until it finds the original', function() { var rootA = getExportSpecifier('root.js', 'a'); var specifier = getExportSpecifier('index.js', 'a'); assert.strictEqual( specifier.terminalExportSpecifier, rootA, 'expected ' + specifier.terminalExportSpecifier + ' to equal ' + rootA ); }); }); xcontext('when the export binds an import through a batch export', function() { before(function() { sources = { 'index.js': 'import { a } from "middle.js";\nexport { a };', 'middle.js': 'export * from "root.js";', 'root.js': 'export var a = 1;' }; }); it('follows the trail of imports until it finds the original', function() { var rootA = getExportSpecifier('root.js', 'a'); var specifier = getExportSpecifier('index.js', 'a'); assert.strictEqual( getExportSpecifier('index.js', 'a').terminalExportSpecifier, rootA, 'expected ' + specifier.terminalExportSpecifier + ' to equal ' + rootA ); }); }); }); });es6-module-transpiler-0.10.0/test/unit/rewriter_test.js000066400000000000000000000021701246026563300231360ustar00rootroot00000000000000var Container = require('../../lib/container'); var Module = require('../../lib/module'); var Rewriter = require('../../lib/rewriter'); var TestFormatter = require('../support/test_formatter').TestFormatter; var TestResolver = require('../support/test_resolver').TestResolver; var assert = require('assert'); describe('Rewriter', function() { describe('#rewrite', function() { context('when a module has no imports or exports', function() { it('does not traverse the module at all', function() { var formatter = new TestFormatter(); var container = new Container({ formatter: formatter, resolvers: [new TestResolver({ 'a.js': 'var foo = 1\nfunction bar() {}' })] }); var a = container.getModule('a.js'); var rewriter = new Rewriter(formatter); rewriter.rewrite(container.getModules()); assert.strictEqual(formatter.processedExportDeclarationCount, 0); assert.strictEqual(formatter.processedFunctionDeclarationCount, 0); assert.strictEqual(formatter.processedVariableDeclarationCount, 0); }); }); }); });es6-module-transpiler-0.10.0/test/unit/sorting_test.js000066400000000000000000000047641246026563300227730ustar00rootroot00000000000000var sort = require('../../lib/sorting').sort; var assert = require('assert'); var util = require('util'); function assertArraysEqual(a, b) { var message = 'expected ' + util.inspect(a) + ' to equal ' + util.inspect(b); assert.ok(a.length === b.length, message); for (var i = 0, length = a.length; i < length; i++) { assert.ok(a[i] === b[i], message); } } describe('sort', function() { it('returns an empty list given an empty list', function() { assertArraysEqual(sort([]), []); }); it('returns a list of a single module given a single module', function() { var mod = { id: 'testmod', imports: { modules: [] } }; assertArraysEqual(sort([mod]), [mod]); }); it('properly orders a linear set of modules', function() { var a = { id: 'a', imports: { modules: [] } }; var b = { id: 'b', imports: { modules: [a] } }; var c = { id: 'c', imports: { modules: [b] } }; assertArraysEqual(sort([b, a, c]), [a, b, c]); }); it('properly orders a tree of modules', function() { var b = { id: 'b', imports: { modules: [] } }; var c = { id: 'c', imports: { modules: [] } }; var a = { id: 'a', imports: { modules: [b, c] } }; assertArraysEqual(sort([b, a, c]), [b, c, a]); assertArraysEqual(sort([c, a, b]), [c, b, a]); }); it('properly orders a DAG of modules', function() { var a = { id: 'a', imports: { modules: [] } }; var b = { id: 'b', imports: { modules: [] } }; var c = { id: 'c', imports: { modules: [] } }; a.imports.modules.push(b, c); b.imports.modules.push(c); assertArraysEqual(sort([a, b, c]), [c, b, a]); assertArraysEqual(sort([b, a, c]), [c, b, a]); }); it('orders a simple cyclic graph by last-required', function() { var a = { id: 'a', imports: { modules: [] } }; var b = { id: 'b', imports: { modules: [] } }; a.imports.modules.push(b); b.imports.modules.push(a); assertArraysEqual(sort([a, b]), [b, a]); assertArraysEqual(sort([b, a]), [a, b]); }); it('orders a complex cyclic graph by last-required', function() { var a = { id: 'a', imports: { modules: [] } }; var b = { id: 'b', imports: { modules: [a] } }; var c = { id: 'c', imports: { modules: [b] } }; var d = { id: 'd', imports: { modules: [c] } }; a.imports.modules.push(d); assertArraysEqual(sort([b, c, d, a]), [c, d, a, b]); assertArraysEqual(sort([b, c, a, d]), [c, d, a, b]); assertArraysEqual(sort([c, d, a, b]), [d, a, b, c]); assertArraysEqual(sort([c, b, a, d]), [d, a, b, c]); }); });