1 && arguments[1] !== undefined ? arguments[1] : 12;
29 |
30 | // y is 12 if not passed (or passed as undefined)
31 | return x + y;
32 | }
33 |
34 | function f(x) {
35 | // y is an Array
36 | return x * (arguments.length <= 1 ? 0 : arguments.length - 1);
37 | }
38 |
39 | function f(x, y, z) {
40 | return x + y + z;
41 | }
42 | // Pass each elem of array as argument
43 |
44 |
45 | function f() {
46 | {
47 | var x = void 0;
48 | {
49 | // okay, block scoped name
50 | var _x2 = "sneaky";
51 | }
52 | // okay, declared with `let`
53 | x = "bar";
54 | }
55 | }
56 |
57 | function factorial(n) {
58 | var acc = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
59 |
60 | if (n <= 1) return acc;
61 | return factorial(n - 1, n * acc);
62 | }
63 |
64 | // Stack overflow in most implementations today,
65 | // but safe on arbitrary inputs in ES2015
66 | return {
67 | setters: [function (_globalJs) {}, function (_exampleJs) {}],
68 | execute: function () {
69 | odds = evens.map(function (v) {
70 | return v + 1;
71 | });
72 | nums = evens.map(function (v, i) {
73 | return v + i;
74 | });
75 |
76 |
77 | // Statement bodies
78 | nums.forEach(function (v) {
79 | if (v % 5 === 0) fives.push(v);
80 | });
81 |
82 | // Lexical this
83 | bob = {
84 | _name: "Bob",
85 | _friends: [],
86 | printFriends: function printFriends() {
87 | var _this = this;
88 |
89 | this._friends.forEach(function (f) {
90 | return console.log(_this._name + " knows " + f);
91 | });
92 | }
93 | };
94 | _ref = [1, 2, 3];
95 | a = _ref[0];
96 | b = _ref[2];
97 |
98 | a === 1;
99 | b === 3;
100 |
101 | // object matching
102 | _getASTNode = getASTNode();
103 | a = _getASTNode.op;
104 | b = _getASTNode.lhs.op;
105 | c = _getASTNode.rhs;
106 | _getASTNode2 = getASTNode();
107 | op = _getASTNode2.op;
108 | lhs = _getASTNode2.lhs;
109 | rhs = _getASTNode2.rhs;
110 | g({ name: 5 });
111 |
112 | // Fail-soft destructuring
113 | _ref3 = [];
114 | a = _ref3[0];
115 |
116 | a === undefined;
117 |
118 | // Fail-soft destructuring with defaults
119 | _ref4 = [];
120 | _ref4$ = _ref4[0];
121 | a = _ref4$ === undefined ? 1 : _ref4$;
122 |
123 | a === 1;r({ x: 1, y: 2 }) === 23;f(3) == 15;f(3, "hello", true) == 6;f.apply(undefined, [1, 2, 3]) == 6;
124 | _export("tail", tail = factorial(100000));
125 |
126 | _export("tail", tail);
127 | }
128 | };
129 | });
130 |
131 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImJhYmVsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBb0NBO0FBQ0EsV0FBUyxDQUFULFFBQXNCO0FBQUEsUUFBSixDQUFJLFNBQVYsSUFBVTs7QUFDcEIsWUFBUSxHQUFSLENBQVksQ0FBWjtBQUNEOzs7QUFXRDtBQUNBLFdBQVMsQ0FBVCxRQUFtQztBQUFBLFFBQXZCLENBQXVCLFNBQXZCLENBQXVCO0FBQUEsUUFBcEIsQ0FBb0IsU0FBcEIsQ0FBb0I7QUFBQSx3QkFBakIsQ0FBaUI7QUFBQSxRQUFqQixDQUFpQiwyQkFBYixFQUFhO0FBQUEsd0JBQVQsQ0FBUztBQUFBLFFBQVQsQ0FBUywyQkFBTCxFQUFLOztBQUNqQyxXQUFPLElBQUksQ0FBSixHQUFRLENBQVIsR0FBWSxDQUFuQjtBQUNEOzs7QUFJRCxXQUFTLENBQVQsQ0FBVyxDQUFYLEVBQW9CO0FBQUEsUUFBTixDQUFNLHVFQUFKLEVBQUk7O0FBQ2xCO0FBQ0EsV0FBTyxJQUFJLENBQVg7QUFDRDs7QUFFRCxXQUFTLENBQVQsQ0FBVyxDQUFYLEVBQW9CO0FBQ2xCO0FBQ0EsV0FBTyxzREFBUDtBQUNEOztBQUVELFdBQVMsQ0FBVCxDQUFXLENBQVgsRUFBYyxDQUFkLEVBQWlCLENBQWpCLEVBQW9CO0FBQ2xCLFdBQU8sSUFBSSxDQUFKLEdBQVEsQ0FBZjtBQUNEO0FBQ0Q7OztBQUlBLFdBQVMsQ0FBVCxHQUFhO0FBQ1g7QUFDRSxVQUFJLFVBQUo7QUFDQTtBQUNFO0FBQ0EsWUFBTSxNQUFJLFFBQVY7QUFDRDtBQUNEO0FBQ0EsVUFBSSxLQUFKO0FBQ0Q7QUFDRjs7QUFHRCxXQUFTLFNBQVQsQ0FBbUIsQ0FBbkIsRUFBK0I7QUFBQSxRQUFULEdBQVMsdUVBQUgsQ0FBRzs7QUFDN0IsUUFBSSxLQUFLLENBQVQsRUFBWSxPQUFPLEdBQVA7QUFDWixXQUFPLFVBQVUsSUFBSSxDQUFkLEVBQWlCLElBQUksR0FBckIsQ0FBUDtBQUNEOztBQUVEO0FBQ0E7Ozs7QUF6RkksVSxHQUFPLE1BQU0sR0FBTixDQUFVO0FBQUEsZUFBSyxJQUFJLENBQVQ7QUFBQSxPQUFWLEM7QUFDUCxVLEdBQU8sTUFBTSxHQUFOLENBQVUsVUFBQyxDQUFELEVBQUksQ0FBSjtBQUFBLGVBQVUsSUFBSSxDQUFkO0FBQUEsT0FBVixDOzs7QUFFWDtBQUNBLFdBQUssT0FBTCxDQUFhLGFBQUs7QUFDaEIsWUFBSSxJQUFJLENBQUosS0FBVSxDQUFkLEVBQ0UsTUFBTSxJQUFOLENBQVcsQ0FBWDtBQUNILE9BSEQ7O0FBS0E7QUFDSSxTLEdBQU07QUFDUixlQUFPLEtBREM7QUFFUixrQkFBVSxFQUZGO0FBR1Isb0JBSFEsMEJBR087QUFBQTs7QUFDYixlQUFLLFFBQUwsQ0FBYyxPQUFkLENBQXNCO0FBQUEsbUJBQ3BCLFFBQVEsR0FBUixDQUFZLE1BQUssS0FBTCxHQUFhLFNBQWIsR0FBeUIsQ0FBckMsQ0FEb0I7QUFBQSxXQUF0QjtBQUVEO0FBTk8sTzthQVVJLENBQUMsQ0FBRCxFQUFHLENBQUgsRUFBSyxDQUFMLEM7QUFBVCxPO0FBQUksTzs7QUFDVCxZQUFNLENBQU47QUFDQSxZQUFNLENBQU47O0FBRUE7b0JBRUksWTtBQURNLE8sZUFBSixFO0FBQWtCLE8sZUFBWCxHLENBQU8sRTtBQUFjLE8sZUFBTCxHO3FCQUtSLFk7QUFBaEIsUSxnQkFBQSxFO0FBQUksUyxnQkFBQSxHO0FBQUssUyxnQkFBQSxHO0FBTWQsUUFBRSxFQUFDLE1BQU0sQ0FBUCxFQUFGOztBQUVBO2NBQ1UsRTtBQUFMLE87O0FBQ0wsWUFBTSxTQUFOOztBQUVBO2NBQ2MsRTs7QUFBVCxPLDBCQUFJLEM7O0FBQ1QsWUFBTSxDQUFOLENBTUEsRUFBRSxFQUFDLEdBQUUsQ0FBSCxFQUFNLEdBQUUsQ0FBUixFQUFGLE1BQWtCLEVBQWxCLENBT0EsRUFBRSxDQUFGLEtBQVEsRUFBUixDQUtBLEVBQUUsQ0FBRixFQUFLLE9BQUwsRUFBYyxJQUFkLEtBQXVCLENBQXZCLENBS0EsbUJBQUssQ0FBQyxDQUFELEVBQUcsQ0FBSCxFQUFLLENBQUwsQ0FBTCxLQUFpQixDQUFqQjtzQkF1QmEsSSxHQUFPLFVBQVUsTUFBVixDIiwiZmlsZSI6InJlZ2lzdGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFwiLi9nbG9iYWwuanNcIjtcbmltcG9ydCBcIi4vZXhhbXBsZS5qc1wiO1xuXG4vLyBFeHByZXNzaW9uIGJvZGllc1xudmFyIG9kZHMgPSBldmVucy5tYXAodiA9PiB2ICsgMSk7XG52YXIgbnVtcyA9IGV2ZW5zLm1hcCgodiwgaSkgPT4gdiArIGkpO1xuXG4vLyBTdGF0ZW1lbnQgYm9kaWVzXG5udW1zLmZvckVhY2godiA9PiB7XG4gIGlmICh2ICUgNSA9PT0gMClcbiAgICBmaXZlcy5wdXNoKHYpO1xufSk7XG5cbi8vIExleGljYWwgdGhpc1xudmFyIGJvYiA9IHtcbiAgX25hbWU6IFwiQm9iXCIsXG4gIF9mcmllbmRzOiBbXSxcbiAgcHJpbnRGcmllbmRzKCkge1xuICAgIHRoaXMuX2ZyaWVuZHMuZm9yRWFjaChmID0+XG4gICAgICBjb25zb2xlLmxvZyh0aGlzLl9uYW1lICsgXCIga25vd3MgXCIgKyBmKSk7XG4gIH1cbn07XG5cbi8vIGxpc3QgbWF0Y2hpbmdcbnZhciBbYSwgLGJdID0gWzEsMiwzXTtcbmEgPT09IDE7XG5iID09PSAzO1xuXG4vLyBvYmplY3QgbWF0Y2hpbmdcbnZhciB7IG9wOiBhLCBsaHM6IHsgb3A6IGIgfSwgcmhzOiBjIH1cbiAgPSBnZXRBU1ROb2RlKClcblxuLy8gb2JqZWN0IG1hdGNoaW5nIHNob3J0aGFuZFxuLy8gYmluZHMgYG9wYCwgYGxoc2AgYW5kIGByaHNgIGluIHNjb3BlXG52YXIge29wLCBsaHMsIHJoc30gPSBnZXRBU1ROb2RlKClcblxuLy8gQ2FuIGJlIHVzZWQgaW4gcGFyYW1ldGVyIHBvc2l0aW9uXG5mdW5jdGlvbiBnKHtuYW1lOiB4fSkge1xuICBjb25zb2xlLmxvZyh4KTtcbn1cbmcoe25hbWU6IDV9KVxuXG4vLyBGYWlsLXNvZnQgZGVzdHJ1Y3R1cmluZ1xudmFyIFthXSA9IFtdO1xuYSA9PT0gdW5kZWZpbmVkO1xuXG4vLyBGYWlsLXNvZnQgZGVzdHJ1Y3R1cmluZyB3aXRoIGRlZmF1bHRzXG52YXIgW2EgPSAxXSA9IFtdO1xuYSA9PT0gMTtcblxuLy8gRGVzdHJ1Y3R1cmluZyArIGRlZmF1bHRzIGFyZ3VtZW50c1xuZnVuY3Rpb24gcih7eCwgeSwgdyA9IDEwLCBoID0gMTB9KSB7XG4gIHJldHVybiB4ICsgeSArIHcgKyBoO1xufVxucih7eDoxLCB5OjJ9KSA9PT0gMjNcblxuXG5mdW5jdGlvbiBmKHgsIHk9MTIpIHtcbiAgLy8geSBpcyAxMiBpZiBub3QgcGFzc2VkIChvciBwYXNzZWQgYXMgdW5kZWZpbmVkKVxuICByZXR1cm4geCArIHk7XG59XG5mKDMpID09IDE1XG5mdW5jdGlvbiBmKHgsIC4uLnkpIHtcbiAgLy8geSBpcyBhbiBBcnJheVxuICByZXR1cm4geCAqIHkubGVuZ3RoO1xufVxuZigzLCBcImhlbGxvXCIsIHRydWUpID09IDZcbmZ1bmN0aW9uIGYoeCwgeSwgeikge1xuICByZXR1cm4geCArIHkgKyB6O1xufVxuLy8gUGFzcyBlYWNoIGVsZW0gb2YgYXJyYXkgYXMgYXJndW1lbnRcbmYoLi4uWzEsMiwzXSkgPT0gNlxuXG5cbmZ1bmN0aW9uIGYoKSB7XG4gIHtcbiAgICBsZXQgeDtcbiAgICB7XG4gICAgICAvLyBva2F5LCBibG9jayBzY29wZWQgbmFtZVxuICAgICAgY29uc3QgeCA9IFwic25lYWt5XCI7XG4gICAgfVxuICAgIC8vIG9rYXksIGRlY2xhcmVkIHdpdGggYGxldGBcbiAgICB4ID0gXCJiYXJcIjtcbiAgfVxufVxuXG5cbmZ1bmN0aW9uIGZhY3RvcmlhbChuLCBhY2MgPSAxKSB7XG4gIGlmIChuIDw9IDEpIHJldHVybiBhY2M7XG4gIHJldHVybiBmYWN0b3JpYWwobiAtIDEsIG4gKiBhY2MpO1xufVxuXG4vLyBTdGFjayBvdmVyZmxvdyBpbiBtb3N0IGltcGxlbWVudGF0aW9ucyB0b2RheSxcbi8vIGJ1dCBzYWZlIG9uIGFyYml0cmFyeSBpbnB1dHMgaW4gRVMyMDE1XG5leHBvcnQgY29uc3QgdGFpbCA9IGZhY3RvcmlhbCgxMDAwMDApIl19
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 | API Documentation
2 | ===
3 | * [**Builder**](#builder)
4 | * [**Expression Strings**](#module-tree-expressions)
5 |
6 | Builder
7 | ---
8 | * [**new Builder()**](#new-builderconfig)
9 | * [**config()**](#builderconfigconfig-saveforreset-ignorebaseurl)
10 | * [**loadConfig()**](#builderloadconfigconfigfile-saveforreset-ignorebaseurl)
11 | * [**loadConfigSync()**](#builderloadconfigsyncconfigfilepath)
12 | * [**reset()**](#builderreset)
13 | * [**invalidate()**](#builderinvalidatemodulename)
14 | * [**bundle()**](#builderbundletree-outfile-options)
15 | * [**buildStatic()**](#builderbuildstatictree-outfile-options)
16 | * [**trace()**](#buildertraceexpression)
17 | * [**addTrees()**](#builderaddtreesfirsttree-secondtree)
18 | * [**subtractTrees()**](#buildersubtracttreesfirsttree-secondtree)
19 | * [**intersectTrees()**](#builderintersecttreesfirsttree-secondtree)
20 |
21 | ### new Builder(baseURL[, configFilePath])
22 | `baseURL`: Sets the root for the loader
23 | `configFilePath`: A systemjs config file conforming to the [systemjs config api] (https://github.com/systemjs/systemjs/blob/master/docs/config-api.md)
24 | #### Example
25 | ```javascript
26 | new Builder('/scripts', 'config.js');
27 | ```
28 |
29 | ### builder.config(config)
30 | `config`: An object conforming to the [config api] (https://github.com/systemjs/systemjs/blob/master/docs/config-api.md)
31 | #### Example
32 | ```javascript
33 | builder.config({
34 | map: {
35 | 'a': 'b.js'
36 | }
37 | });
38 | ```
39 |
40 | ### builder.loadConfig(configFilePath)
41 | `configFilePath`: A systemjs config file conforming to the [systemjs config api] (https://github.com/systemjs/systemjs/blob/master/docs/config-api.md)
42 |
43 | Returns a promise which resolves when config has been loaded
44 | #### Example
45 | ```javascript
46 | builder.loadConfig('config.js').then(() => {
47 | });
48 | ```
49 | ### builder.loadConfigSync(configFilePath)
50 | Synchronous version of `builder.loadConfig()`
51 |
52 | `configFilePath`: A systemjs config file conforming to the [systemjs config api] (https://github.com/systemjs/systemjs/blob/master/docs/config-api.md)
53 | #### Example
54 | ```javascript
55 | builder.loadConfigSync('config.js');
56 | ```
57 |
58 | ### builder.reset()
59 | Reset the builder config to its initial state and clear loader registry. This will remove any registered modules, but will maintain the builder's compiled module cache. For efficiency, use [builder.invalidate()](#builderinvalidatemodulename) to clear individual modules from the cache.
60 | #### Example
61 | ```javascript
62 | builder.reset();
63 | ```
64 |
65 | ### builder.invalidate(moduleName)
66 | Removes a module from the loader cache
67 |
68 | `moduleName`: The name of the module to invalidate, this can include wildcards
69 |
70 | Returns the list of invalidated modules
71 | #### Example
72 | ```javascript
73 | builder.invalidate("/jquery.js");
74 | builder.invalidate("someLib/*");
75 | ```
76 |
77 | ### builder.bundle(tree[, outfile][, options])
78 | ### builder.bundle(expression[, outfile][, options])
79 | ### builder.bundle(moduleNames[, outfile][, options])
80 | Concatenate all modules in the tree or module tree expression and optionally write them out to a file
81 |
82 | `tree`: A tree object as returned from builder.trace(), or one of the arithmetic functions
83 | `expression`: A [module tree expression](#module-tree-expressions)
84 | `moduleNames`: An array of exact, unnormalized module names \
85 | **Important**: The module names in `expression` or `moduleNames` should only be `/` separated (On Windows, do NOT use `\` as your path separator for this argument). The module names are specified in URL space; in particular, they are not file-paths. \
86 | `outfile`: The file to write out the bundle to
87 | `options`: Additional bundle options as outlined below
88 |
89 | Returns a promise which resolves with the bundle content
90 | #### Bundle options
91 | `minify`: Minify source in bundle output _(Default:true)_
92 | `uglify`: Options to pass to uglifyjs
93 | `mangle`: Allow the minifier to shorten non-public variable names _(Default:false)_
94 | `sourceMaps`: Generate source maps for minified code _(Default:false)_
95 | `sourceMapContents`: Include original source in the generated sourceMaps, this will generate a self-contained sourceMap which will not require the browser to load the original source file during debugging _(Default:false)_
96 | `lowResSourceMaps`: When true, use line-number level source maps, when false, use character level source maps _(Default:false)_
97 | `globalName`: When building a self-executing bundle, assign the bundle output to a global variable _(Default:null)_
98 | `globalDeps`: When building a self-executing bundle, indicates external dependendencies available in the global context _(Default:{})_
99 | `fetch`: Override the fetch function to retrieve module source manually _(Default:undefined)_
100 | `normalize`: Rewrite required module names to their normalized names _(Default:false)_
101 | `anonymous`: Compile modules as anonymous modules _(Default:false)_
102 | `systemGlobal`: The global used to register compiled modules with systemjs _(Default:'System')_
103 | `format`: Module format to compile modules to _(Default:'umd')_
104 |
105 | #### Example
106 | ```javascript
107 | builder.bundle('moduleA.js', { minify:true }).then((bundle) => {
108 | //bundle contains source to moduleA.js + dependencies
109 | });
110 | ```
111 | ### builder.buildStatic(tree[, outfile][, options])
112 | ### builder.buildStatic(expression[, outfile][, options])
113 | Similar to builder.bundle() but builds a self-executing bundle
114 |
115 | `tree`: A tree object as returned from builder.trace(), or one of the arithmetic functions
116 | `expression`: A [module tree expression](#module-tree-expressions) \
117 | **Important**: The module names in `expression` or `moduleNames` should only be `/` separated (On Windows, do NOT use `\` as your path separator for this argument). The module names are specified in URL space; in particular, they are not file-paths. \
118 | `outfile`: The file to write out the bundle to
119 | `options`: Additional bundle options as outlined in `builder.bundle()`
120 |
121 | Returns a promise which resolves with the bundle content
122 | #### Example
123 | ```javascript
124 | builder.buildStatic('moduleA.js').then((sfxBundle) => {
125 | //sfxBundle contains source to moduleA.js + dependencies + self-executing intialization code
126 | });
127 | ```
128 |
129 | ### builder.trace(expression)
130 | Creates the module tree object represented by `expression`
131 |
132 | `expression`: A [module tree expression](#module-tree-expressions) \
133 | **Important**: The module names in `expression` should only be `/` separated (On Windows, do NOT use `\` as your path separator for this argument). The module names are specified in URL space; in particular, they are not file-paths.
134 |
135 | Returns a promise which resolves with the module tree
136 |
137 | #### Example
138 | ```javascript
139 | builder.trace('moduleA.js').then((moduleTree) => {
140 | });
141 | ```
142 |
143 | ### builder.addTrees(firstTree, secondTree)
144 | ```javascript
145 | let moduleTree = builder.addTrees('moduleA.js', 'moduleB.js')
146 | ```
147 |
148 | ### builder.subtractTrees(firstTree, secondTree)
149 | ```javascript
150 | let moduleTree = builder.subtractTrees('moduleA.js', 'moduleB.js');
151 | ```
152 |
153 | ### builder.intersectTrees(firstTree, secondTree)
154 | ```javascript
155 | let moduleTree = builder.intersectTrees('moduleA.js', 'moduleB.js');
156 | ```
157 |
158 | ## Module Tree Expressions
159 | `builder.buildStatic`, `builder.bundle` and `builder.trace` accept module tree expressions
160 |
161 | ### Module Tree
162 | Represents moduleA and all of its dependencies
163 | ```javascript
164 | 'moduleA.js'
165 | ```
166 |
167 | ### Single Module
168 | Represents moduleA only
169 | ```javascript
170 | '[moduleA.js]'
171 | ```
172 |
173 | ### Addition
174 | Represents a tree that combines moduleA, moduleB and their dependencies
175 | ```javascript
176 | 'moduleA.js + moduleB.js'
177 | ```
178 |
179 | ### Subtraction
180 | Represents a tree that includes moduleA and its dependencies, excluding moduleB and its dependencies
181 | ```javascript
182 | 'moduleA.js - moduleB.js'
183 | ```
184 |
185 | ### Intersection
186 | Represents the dependencies shared between moduleA and moduleB
187 | ```javascript
188 | 'moduleA.js & moduleB.js'
189 | ```
190 |
191 | ### Module Glob
192 | Represents the combination of all modules in dirA and their dependencies
193 | ```javascript
194 | 'dirA/*'
195 | ```
196 |
197 | ### Parenthesis
198 | Use parenthesis to group module tree operations
199 | ```javascript
200 | '(moduleA.js & moduleB.js) + moduleC.js'
201 | ```
202 |
--------------------------------------------------------------------------------
/test/test-build.js:
--------------------------------------------------------------------------------
1 | var Builder = require('../index');
2 | var inline = require('../lib/output').inlineSourceMap;
3 | var fs = require('fs');
4 | var path = require('path');
5 | var spawn = require('child_process').spawn;
6 | if (process.argv[2] == 'typescript')
7 | global.ts = require('typescript');
8 |
9 | var minify = true;
10 |
11 | var err = function(e) {
12 | setTimeout(function() {
13 | throw e;
14 | });
15 | };
16 |
17 | var builder = new Builder('test/fixtures/test-tree', 'test/fixtures/test-tree.config.js');
18 |
19 | function getCommandPath(command) {
20 | return path.resolve('./node_modules/.bin/' + command + (process.platform.match(/^win/) ? '.cmd' : ''));
21 | }
22 |
23 | function testPhantom(html) {
24 | return new Promise(function(resolve, reject) {
25 | spawn(getCommandPath('mocha-phantomjs'), ['-p', getCommandPath('phantomjs'), html], { stdio: 'inherit' })
26 | .on('close', function(code) {
27 | if (code !== 0)
28 | reject(Error('Phantom test failed ' + html + ' failed.'));
29 | else
30 | resolve();
31 | });
32 | });
33 | }
34 |
35 | function doTests(transpiler) {
36 |
37 | test('In-memory build', function() {
38 | builder.reset();
39 | builder.config({ transpiler: transpiler });
40 | return builder.bundle('first.js', { sourceMaps: true, minify: minify })
41 | .then(function(output) {
42 | fs.writeFileSync('test/output/memory-test.js', inline(output.source, output.sourceMap));
43 | });
44 | });
45 |
46 | test('Multi-format tree build', function() {
47 | builder.reset();
48 | builder.config({ transpiler: transpiler });
49 |
50 | return builder.bundle('first.js', 'test/output/tree-build.js', { sourceMaps: true, minify: minify, globalDefs: { DEBUG: false } })
51 | .then(function(output) {
52 | assert(output.assetList[0].url);
53 | var treeFirst;
54 | Promise.all(['first.js', 'amd.js'].map(builder.trace.bind(builder)))
55 | .then(function(trees) {
56 | treeFirst = trees[0];
57 | return builder.bundle(builder.subtractTrees(trees[0], trees[1]), 'test/output/excluded.js');
58 | })
59 |
60 | .then(function() {
61 | return builder.trace('global-inner.js').then(function(tree) {
62 | return builder.bundle(tree, 'test/output/global-inner.js');
63 | });
64 | })
65 |
66 | .then(function() {
67 | return builder.trace('global-outer.js').then(function(tree) {
68 | return builder.bundle(tree, 'test/output/global-outer.js');
69 | });
70 | })
71 |
72 | .then(function() {
73 | return builder.trace('amd-1.js').then(function(tree) {
74 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-1.js');
75 | });
76 | })
77 |
78 | .then(function() {
79 | return builder.trace('amd-2.js').then(function(tree) {
80 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-2.js');
81 | });
82 | })
83 |
84 | .then(function() {
85 | return builder.trace('amd-3.js').then(function(tree) {
86 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-3.js');
87 | });
88 | })
89 |
90 | .then(function() {
91 | return builder.trace('amd-4.js').then(function(tree) {
92 | return builder.getDeferredImports(tree)
93 | .then(function(deferredImports) {
94 | assert(deferredImports[0].name == 'x');
95 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-4.js');
96 | });
97 | });
98 | })
99 |
100 | .then(function() {
101 | return builder.trace('amd-5a.js').then(function(tree) {
102 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-5a.js');
103 | });
104 | })
105 |
106 | .then(function() {
107 | return builder.trace('amd-5b.js').then(function(tree) {
108 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-5b.js');
109 | });
110 | })
111 |
112 |
113 | .then(function() {
114 | return builder.trace('amd-6a.js').then(function(tree) {
115 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-6a.js');
116 | });
117 | })
118 |
119 | .then(function() {
120 | return builder.trace('amd-6b.js').then(function(tree) {
121 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/amd-6b.js');
122 | });
123 | })
124 |
125 | .then(function() {
126 | return builder.trace('umd.js').then(function(tree) {
127 | return builder.bundle(builder.subtractTrees(tree, treeFirst), 'test/output/umd.js');
128 | });
129 | })
130 |
131 | .then(function() {
132 | return builder.bundle('amd-7.js', 'test/output/amd-7.js');
133 | })
134 |
135 | .then(function() {
136 | return builder.bundle('amd-8.js', 'test/output/amd-8.js');
137 | })
138 |
139 | .then(function() {
140 | return builder.bundle('amd-9.js', 'test/output/amd-9.js');
141 | })
142 |
143 | .then(function() {
144 | return builder.bundle('amd-10.js', 'test/output/amd-10.js');
145 | })
146 |
147 | .then(function() {
148 | return builder.bundle('amd-11.js', 'test/output/amd-11.js');
149 | })
150 |
151 | .then(function() {
152 | return builder.bundle('amd-12.js', 'test/output/amd-12.js');
153 | })
154 |
155 | .then(function() {
156 | builder.loader.config({ paths: { 'output/*': './test/output/*' } });
157 | return builder.bundle('cjs-globals.js - output/amd-8.js', 'test/output/cjs-globals.js');
158 | })
159 |
160 | .then(function() {
161 | return builder.bundle('cjs-resolve.js', 'test/output/cjs-resolve.js');
162 | })
163 |
164 | .then(function() {
165 | return builder.bundle('runtime.js', 'test/output/runtime.js');
166 | })
167 | })
168 | .then(function () {
169 | return testPhantom('test/test-build.html');
170 | })
171 | ['catch'](function(err) {
172 | throw err;
173 | });
174 | });
175 |
176 | // traceur runtime function.bind fails in Phantom
177 | if (transpiler != 'traceur')
178 | test('SFX tree build', function() {
179 | builder.reset();
180 | builder.config({ transpiler: transpiler });
181 | builder.config({
182 | map: {
183 | 'toamd1': 'amd-1.js'
184 | },
185 | meta: {
186 | 'jquery-cdn': {
187 | build: false
188 | }
189 | }
190 | });
191 | return builder.buildStatic('toamd1', 'test/output/sfx.js', {
192 | runtime: true,
193 | minify: minify,
194 | format: 'global',
195 | globalDefs: { DEBUG: false },
196 | globalName: 'amd1',
197 | globalDeps: {
198 | 'jquery-cdn': '$'
199 | }
200 | })
201 | .then(function() {
202 | return testPhantom('test/test-sfx.html');
203 | });
204 | });
205 | }
206 |
207 | suite('Basics', function() {
208 | test('Circular map config', function() {
209 | builder.reset();
210 | return builder.bundle('lodash');
211 | });
212 | });
213 |
214 | suite('Test tree builds - Traceur', function() {
215 |
216 | doTests('traceur');
217 |
218 | });
219 |
220 | suite('Test tree builds - Babel', function() {
221 |
222 | doTests('babel');
223 |
224 | });
225 |
226 | suite('Test tree builds - TypeScript', function() {
227 |
228 | doTests('typescript');
229 |
230 | });
231 |
232 | suite('Bundle Format', function() {
233 | test('Test AMD format', function() {
234 | return Promise.resolve()
235 | .then(function() {
236 | return builder.buildStatic('sfx-format-01.js', 'test/output/sfx-amd-01.js', { format: 'amd' });
237 | })
238 | .then(function() {
239 | return builder.buildStatic('sfx-format-02.js', 'test/output/sfx-amd-02.js', { format: 'amd' });
240 | })
241 | .then(function() {
242 | return testPhantom('test/test-sfx-amd.html');
243 | });
244 | });
245 | });
246 |
247 | suite('Test ES6 minification', function() {
248 | test('ES6 syntax minify, unmangled', function() {
249 | builder.reset();
250 | return builder.bundle('class-def.js', { minify: true , mangle: false })
251 | .then(function(output) {
252 | assert.match(output.source, /class Foo{constructor\(\){/, 'source contains literal class');
253 | });
254 | });
255 |
256 | test('ES6 syntax minify, mangled', function() {
257 | builder.reset();
258 | return builder.bundle('class-def.js', { minify: true , mangle: true })
259 | .then(function(output) {
260 | assert.match(output.source, /class \w{constructor\(\){/, 'source contains literal class, mangled');
261 | });
262 | });
263 | });
264 |
--------------------------------------------------------------------------------
/test/test-build.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
285 |
291 |
--------------------------------------------------------------------------------
/test/test-build-cache.js:
--------------------------------------------------------------------------------
1 | var Builder = require('../index');
2 | var expect = require('chai').expect;
3 | var toFileURL = require('../lib/utils.js').toFileURL;
4 | var fs = require('fs');
5 |
6 | suite('Test compiler cache', function() {
7 | var builder = new Builder('test/fixtures/test-cache-tree');
8 | builder.config({ transpiler: 'babel' });
9 |
10 | test('Use compile cache entry when available', function() {
11 | var loadName = 'simple.js';
12 | var outputPath = 'test/output/cached.js';
13 | var cacheObj;
14 | var tree;
15 |
16 | return builder.trace(loadName).then(function(_tree) {
17 | tree = _tree;
18 | return builder.bundle(tree);
19 | })
20 | .then(function() {
21 | var cacheEntry = builder.getCache();
22 |
23 | expect(cacheEntry).to.be.an('object');
24 |
25 | cacheObj = cacheEntry.compile.loads['simple.js'];
26 |
27 | expect(cacheObj).to.be.an('object');
28 | expect(cacheObj.hash).to.be.a('string');
29 | expect(cacheObj.output).to.be.an('object');
30 |
31 | // poison cache
32 | cacheObj.output.source = cacheObj.output.source.replace('hate', 'love');
33 |
34 | return builder.bundle(tree);
35 | })
36 | .then(function(output) {
37 | // verify buildTree use poisoned cache rather than recompiling
38 | var outputSource = output.source;
39 | expect(outputSource).not.to.contain('hate caches');
40 | expect(outputSource).to.contain('love caches');
41 |
42 | // invalidate poisoned cache entry and rebuild
43 | cacheObj.hash = 'out of date';
44 | return builder.bundle(tree);
45 | })
46 | .then(function(output) {
47 | // verify original source is used once more
48 | var outputSource = output.source;
49 | expect(outputSource).to.contain('hate caches');
50 | expect(outputSource).not.to.contain('love caches');
51 | });
52 | });
53 |
54 | test('Use trace cache when available', function() {
55 | // construct the load record for the cache
56 | var cacheObj = {
57 | trace: {
58 | 'simple.js': {
59 | name: 'simple.js',
60 | path: 'fixtures/test-cache-tree/simple.js',
61 | metadata: {
62 | deps: [],
63 | format: 'amd',
64 | isAnon: true
65 | },
66 | deps: [],
67 | depMap: {},
68 | source: 'define([], function(module) {\n console.log(\'fake cache\');\n});\n',
69 | originalSource: 'define([], function(module) {\n console.log(\'fake cache\');\n});\n'
70 | }
71 | }
72 | };
73 |
74 | builder.reset();
75 | builder.setCache(cacheObj);
76 |
77 | return builder.bundle('simple.js').then(function(output) {
78 | expect(output.source).to.contain('fake cache');
79 | });
80 | });
81 |
82 | test('Cache invalidation', function() {
83 | var cacheObj = {
84 | trace: {
85 | 'simple.js': {},
86 | 'another/path.js': {}
87 | }
88 | };
89 |
90 | builder.reset();
91 | builder.setCache(cacheObj);
92 |
93 | var invalidated = builder.invalidate('*');
94 | assert.deepEqual(invalidated, [builder.loader.normalizeSync('simple.js'), builder.loader.normalizeSync('another/path.js')]);
95 |
96 | cacheObj = {
97 | trace: {
98 | 'simple.js': {},
99 | 'new/path.js': {},
100 | 'deep/wildcard/test.js': {}
101 | }
102 | };
103 |
104 | builder.setCache(cacheObj);
105 |
106 | invalidated = builder.invalidate('new/path.js');
107 | assert.deepEqual(invalidated, [builder.loader.normalizeSync('new/path.js')]);
108 |
109 | invalidated = builder.invalidate('deep/*.js');
110 | assert.deepEqual(invalidated, [builder.loader.normalizeSync('deep/wildcard/test.js')]);
111 | });
112 |
113 | test('builder.loader.fetch sets load.metadata.timestamp', function() {
114 | var source = 'export var p = 5;';
115 | var builder = new Builder('test/output');
116 | fs.writeFileSync('./test/output/timestamp-module.js', source);
117 | var address = builder.loader.normalizeSync('./test/output/timestamp-module.js');
118 | var load = { name: address, address: address, metadata: {} };
119 | return builder.loader.fetch(load)
120 | .then(function(text) {
121 | //console.log(JSON.stringify(load));
122 | assert(text == source); // true
123 | assert(load.metadata.deps); // true
124 | assert(load.metadata.timestamp); // false
125 | })
126 | });
127 |
128 | test('Bundle example', function() {
129 | var builder = new Builder('test/output');
130 | fs.writeFileSync('./test/output/dynamic-module.js', 'export var p = 5;');
131 |
132 | return builder.bundle('dynamic-module.js')
133 | .then(function(output) {
134 | assert(output.source.match(/p = 5/));
135 |
136 | fs.writeFileSync('./test/output/dynamic-module.js', 'export var p = 6;');
137 | builder.invalidate('dynamic-module.js');
138 |
139 | return builder.bundle('dynamic-module.js');
140 | })
141 | .then(function(output) {
142 | assert(output.source.match(/p = 6/));
143 | });
144 | });
145 |
146 | test('Bundle example with imported file', function() {
147 | var builder = new Builder('test/output');
148 |
149 | fs.writeFileSync('./test/output/dynamic-import.js', [
150 | 'const d = 9;',
151 | 'export default d;'
152 | ].join('\n'));
153 |
154 | fs.writeFileSync('./test/output/dynamic-main.js', [
155 | 'import d from "./dynamic-import.js";',
156 | 'console.log(d);'
157 | ].join('\n'));
158 |
159 | return builder.bundle('dynamic-main.js')
160 | .then(function(output) {
161 | assert(output.source.match(/d = 9/));
162 | assert(output.source.match(/console/));
163 |
164 | fs.writeFileSync('./test/output/dynamic-import.js', [
165 | 'import "./dynamic-import2.js";', // Add another transitive dependency.
166 | 'const d = 7;',
167 | 'export default d;'
168 | ].join('\n'));
169 | builder.invalidate('dynamic-import.js');
170 |
171 | fs.writeFileSync('./test/output/dynamic-import2.js', [
172 | 'const u = "transitive";',
173 | 'export default u;'
174 | ].join('\n'));
175 |
176 | return builder.bundle('dynamic-main.js');
177 | })
178 | .then(function(output) {
179 | assert(output.source.match(/transitive/));
180 | assert(output.source.match(/d = 7/));
181 | assert(output.source.match(/console/));
182 |
183 | // Remove the transitive dependency from the build.
184 | fs.writeFileSync('./test/output/dynamic-import.js', [
185 | 'const d = 7;',
186 | 'export default d;'
187 | ].join('\n'));
188 | builder.invalidate('dynamic-import.js');
189 |
190 | return builder.bundle('dynamic-main.js');
191 | })
192 | .then(function(output) {
193 | assert(!output.source.match(/transitive/));
194 | });
195 | });
196 |
197 | test('Static build example statting check', function() {
198 | var builder = new Builder('test/output');
199 |
200 | fs.writeFileSync('./test/output/static-main.js', "import { testThing } from './static-test-module.js'; testThing();");
201 | fs.writeFileSync('./test/output/static-test-module.js', "export function testThing() { console.log('test'); }");
202 |
203 | return builder.buildStatic('static-main.js')
204 | .then(function() {
205 | builder.invalidate('static-main.js');
206 | // despite removing the file, it remains cached
207 | fs.unlinkSync('./test/output/static-test-module.js');
208 | return builder.buildStatic('static-main.js');
209 | });
210 | });
211 |
212 | test('Static build example dependency reload check', function() {
213 | var builder = new Builder('test/output');
214 |
215 | fs.writeFileSync('./test/output/static-main.js', "import { testThing } from './static-test-module.js'; testThing();");
216 | fs.writeFileSync('./test/output/static-test-module.js', "export function testThing() { console.log('test'); }");
217 |
218 | return builder.buildStatic('static-main.js')
219 | .then(function() {
220 | fs.writeFileSync('./test/output/static-test-module.js', "export function testThing() { console.log('new test'); }")
221 | builder.invalidate('static-test-module.js');
222 | return builder.buildStatic('static-main.js');
223 | });
224 | });
225 |
226 | test('Static build, fetch override', function () {
227 | var builder = new Builder('test/fixtures/test-tree');
228 | return builder.buildStatic('foo.js', {
229 | fetch: function (load, fetch) {
230 | if (load.name.indexOf('foo.js') !== -1) {
231 | return fs.readFileSync('test/fixtures/test-tree/cjs.js', 'utf8');
232 | } else {
233 | return fetch(load);
234 | }
235 | }
236 | });
237 | });
238 |
239 | test('Static build, fetch override with callback', function () {
240 | var builder = new Builder('test/fixtures/test-tree');
241 | return builder.buildStatic('cjs.js', {
242 | fetch: function (load, fetch) {
243 | return fetch(load);
244 | }
245 | });
246 | });
247 |
248 | test('Static string build', function () {
249 | var builder = new Builder('test/fixtures/test-tree');
250 | return builder.bundle('foo.js', {
251 | fetch: function (load, fetch) {
252 | if (load.name.indexOf('foo.js') !== -1) {
253 | return fs.readFileSync('test/fixtures/test-tree/cjs.js', 'utf8');
254 | } else {
255 | return fetch(load);
256 | }
257 | }
258 | });
259 | });
260 | });
261 |
--------------------------------------------------------------------------------
/test/sourcemaps.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var Builder = require('../index');
3 |
4 | function atob(str) {
5 | return new Buffer(str, 'base64').toString('binary');
6 | }
7 |
8 | var err = function(e) {
9 | setTimeout(function() {
10 | throw e;
11 | });
12 | };
13 |
14 | var buildOpts = { sourceMaps: true };
15 | var configFile = './test/fixtures/test-tree.config.js';
16 |
17 | var compareSourceMaps = function(filename, expectation, done, transpiler) {
18 | var instance = new Builder();
19 | instance.loadConfigSync(configFile);
20 | buildOpts.config = buildOpts.config || {};
21 | buildOpts.config.transpiler = transpiler || 'traceur';
22 | instance.bundle(filename, null, buildOpts)
23 | .then(function(output) {
24 | assert.equal(output.sourceMap.toString(), expectation);
25 | })
26 | .then(done)
27 | .catch(err);
28 | };
29 |
30 | var readExpectation = function(filename) {
31 | return fs.readFileSync('test/fixtures/sourcemaps-expectations/' + filename).toString().replace(/\n$/, '');
32 | };
33 |
34 | function writeTestOutput() {
35 | var builder = new Builder();
36 | return builder.loadConfig(configFile)
37 | .then(function() {
38 | builder.buildStatic('first.js', 'test/output/output.js', buildOpts);
39 | });
40 | }
41 |
42 | function writeSourceMaps(moduleName, transpiler, sourceMapFile) {
43 | var instance = new Builder();
44 | instance.loadConfigSync(configFile);
45 | buildOpts.config = buildOpts.config || {};
46 | buildOpts.config.transpiler = transpiler || 'traceur';
47 | instance.bundle(moduleName, null, buildOpts)
48 | .then(function(output) {
49 | fs.writeFile('test/fixtures/sourcemaps-expectations/' + sourceMapFile, output.sourceMap.toString());
50 | })
51 | .catch(err);
52 | }
53 |
54 | var toJSON = function(map) {
55 | return JSON.parse(map.toString());
56 | };
57 |
58 | var getSources = function(map) {
59 | return toJSON(map).sources;
60 | };
61 |
62 | suite('Source Maps', function() {
63 | suiteSetup(writeTestOutput);
64 |
65 | test('can render inline', function(done) {
66 | var module = 'amd-2.js + cjs.js';
67 |
68 | var instance = new Builder();
69 | instance.loadConfigSync(configFile);
70 | instance.bundle(module, null, { sourceMaps: 'inline' })
71 | .then(function(output) {
72 | assert.equal(undefined, output.sourceMap);
73 | var source = output.source;
74 | assert.equal(1, source.match(/sourceMappingURL=/g).length);
75 | var lines = output.source.split("\n");
76 | var lastLine = lines[lines.length - 1];
77 | var commentPrefix = /^\/\/# sourceMappingURL=data:application\/json;base64,/;
78 | assert(lastLine.match(commentPrefix));
79 | var encoding = lastLine.replace(commentPrefix, "");
80 | var decoded = JSON.parse(atob(encoding));
81 | assert.deepEqual(decoded.sources,
82 | [ "test/fixtures/test-tree/amd-2.js",
83 | "test/fixtures/test-tree/cjs.js" ]);
84 | })
85 | .then(done)
86 | .catch(err);
87 | });
88 |
89 | test('can consume input source maps', function(done) {
90 | var module = 'register.js';
91 |
92 | var instance = new Builder();
93 | instance.loadConfigSync(configFile);
94 | instance.bundle(module, null, { sourceMaps: true })
95 | .then(function(output) {
96 | var sources = getSources(output.sourceMap);
97 | assert.deepEqual(sources,
98 | [ "test/fixtures/test-tree/jquery.js",
99 | "test/fixtures/test-tree/global.js",
100 | "test/fixtures/test-tree/example",
101 | "test/fixtures/test-tree/babel.js" ]);
102 | })
103 | .then(done)
104 | .catch(err);
105 | });
106 |
107 | test('can be disabled for tracing', function(done) {
108 | var module = 'register.js';
109 | var instance = new Builder();
110 |
111 | // Load our test configuration.
112 | instance.loadConfigSync(configFile);
113 |
114 | instance
115 | .bundle(module, { sourceMaps: false })
116 | .then(function(output) {
117 | assert.isUndefined(output.sourceMap);
118 | })
119 | .then(done)
120 | .catch(err);
121 | });
122 |
123 | suite('sources paths', function() {
124 |
125 | test('are relative to outFile', function(done) {
126 | var builder = new Builder();
127 | builder.loadConfigSync(configFile);
128 | builder.buildStatic('first.js', 'test/output/output.js', buildOpts)
129 | .then(function(outputs) {
130 | var sources = getSources(outputs.sourceMap);
131 | assert.deepEqual(sources,
132 | [ '../fixtures/test-tree/third.js',
133 | '../fixtures/test-tree/cjs.js',
134 | '../fixtures/test-tree/second.js',
135 | '../fixtures/test-tree/jquery.js',
136 | '../fixtures/test-tree/global.js',
137 | '../fixtures/test-tree/text.txt',
138 | '../fixtures/test-tree/amd.js',
139 | '../fixtures/test-tree/unknown', // component.jsx
140 | '../fixtures/test-tree/file.json',
141 | '../fixtures/test-tree/first.js' ]);
142 | })
143 | .then(done)
144 | .catch(err);
145 | });
146 |
147 | test('are relative to baseURL, if no outFile', function(done) {
148 | var builder = new Builder();
149 | builder.config({ baseURL: 'test/fixtures/test-tree' });
150 | builder.loadConfigSync(configFile);
151 | var opts = { sourceMaps: true };
152 | builder.buildStatic('first.js', null, opts)
153 | .then(function(outputs) {
154 | var sources = getSources(outputs.sourceMap);
155 | assert.deepEqual(sources,
156 | [ 'third.js',
157 | 'cjs.js',
158 | 'second.js',
159 | 'jquery.js',
160 | 'global.js',
161 | 'text.txt',
162 | 'amd.js',
163 | 'unknown', // component.jsx
164 | 'file.json',
165 | 'first.js' ]);
166 | })
167 | .then(done)
168 | .catch(err);
169 | });
170 | });
171 |
172 | suite('Option: sourceMapContents', function() {
173 | test.skip('includes all file contents', function(done) {
174 | var builder = new Builder();
175 | builder.loadConfigSync(configFile);
176 | var opts = { sourceMaps: true, sourceMapContents: true };
177 | builder.buildStatic('first.js', null, opts)
178 | .then(function(outputs) {
179 | var map = toJSON(outputs.sourceMap);
180 | var sources = map.sources;
181 | var contents = map.sourcesContent;
182 | assert.equal(sources.length, contents.length);
183 | for (var i=0; i 0, 'empty sourcemap content');
186 | assert.equal(content, fs.readFileSync(sources[i]).toString());
187 | }
188 | })
189 | .then(done)
190 | .catch(err);
191 | });
192 | });
193 |
194 |
195 | suite('Traceur', function() {
196 | var transpiler = 'traceur';
197 |
198 | suite('without input source maps', function() {
199 | test('handles single compilation targets correctly', function(done) {
200 | var module = 'amd-2.js';
201 | var source = 'traceur.tree.single.json';
202 | if (process.env.UPDATE_EXPECTATIONS)
203 | writeSourceMaps(module, transpiler, source);
204 | var expected = readExpectation(source);
205 | compareSourceMaps(module, expected, done, transpiler);
206 | });
207 |
208 | test('handles multiple compilation targets correctly', function(done) {
209 | var module = 'first.js';
210 | var source = 'traceur.tree.multi.json';
211 | if (process.env.UPDATE_EXPECTATIONS)
212 | writeSourceMaps(module, transpiler, source);
213 | var expected = readExpectation(source);
214 | compareSourceMaps(module, expected, done, transpiler);
215 | });
216 | });
217 | });
218 |
219 | suite('babel', function() {
220 | var transpiler = 'babel';
221 |
222 | suite('without input source maps', function() {
223 | test('handles single compilation targets correctly', function(done) {
224 | var module = 'amd-2.js';
225 | var source = 'babel.tree.single.json';
226 | if (process.env.UPDATE_EXPECTATIONS)
227 | writeSourceMaps(module, transpiler, source);
228 | var expected = readExpectation(source);
229 | compareSourceMaps(module, expected, done, transpiler);
230 | });
231 |
232 | test('handles multiple compilation targets correctly', function(done) {
233 | var module = 'first.js';
234 | var source = 'babel.tree.multi.json';
235 | if (process.env.UPDATE_EXPECTATIONS)
236 | writeSourceMaps(module, transpiler, source);
237 | var expected = readExpectation(source);
238 | compareSourceMaps(module, expected, done, transpiler);
239 | });
240 | });
241 | });
242 |
243 | test('can handle multiple transpiled files with same name', function(done) {
244 | var module = 'sameName/1/amd.js + sameName/2/amd.js';
245 |
246 | var instance = new Builder();
247 | instance.loadConfigSync(configFile);
248 | instance.config({
249 | transpiler: 'plugin-babel',
250 | map: {
251 | 'plugin-babel': './node_modules/systemjs-plugin-babel/plugin-babel.js',
252 | 'systemjs-babel-build': './node_modules/systemjs-plugin-babel/systemjs-babel-node.js',
253 | },
254 | packages: {
255 | sameName: {
256 | format: 'amd',
257 | },
258 | },
259 | });
260 | instance.buildStatic(module, null, { sourceMaps: true, sourceMapContents: true })
261 | .then(function() {
262 | done()
263 | })
264 | .catch(err);
265 | });
266 | });
267 |
--------------------------------------------------------------------------------
/compilers/esm.js:
--------------------------------------------------------------------------------
1 | var traceur = require('traceur');
2 | var traceurGet = require('../lib/utils').traceurGet;
3 |
4 | var syntaxDynamicImport = require('babel-plugin-syntax-dynamic-import');
5 |
6 | var ParseTreeTransformer = traceurGet('codegeneration/ParseTreeTransformer.js').ParseTreeTransformer;
7 | var ModuleSpecifier = traceurGet('syntax/trees/ParseTrees.js').ModuleSpecifier;
8 | var createStringLiteralToken = traceurGet('codegeneration/ParseTreeFactory.js').createStringLiteralToken;
9 | var InstantiateModuleTransformer = traceurGet('codegeneration/InstantiateModuleTransformer.js').InstantiateModuleTransformer;
10 |
11 | var extend = require('../lib/utils').extend;
12 |
13 | // patch pending https://github.com/google/traceur-compiler/pull/2053
14 | var createUseStrictDirective = traceurGet('codegeneration/ParseTreeFactory.js').createUseStrictDirective;
15 | InstantiateModuleTransformer.prototype.__proto__.moduleProlog = function() {
16 | return [createUseStrictDirective()];
17 | };
18 |
19 |
20 | var CollectingErrorReporter = traceurGet('util/CollectingErrorReporter.js').CollectingErrorReporter;
21 | var UniqueIdentifierGenerator = traceurGet('codegeneration/UniqueIdentifierGenerator.js').UniqueIdentifierGenerator;
22 |
23 | function TraceurImportNormalizeTransformer(map) {
24 | this.map = map;
25 | return ParseTreeTransformer.apply(this, arguments);
26 | }
27 | TraceurImportNormalizeTransformer.prototype = Object.create(ParseTreeTransformer.prototype);
28 | TraceurImportNormalizeTransformer.prototype.transformModuleSpecifier = function(tree) {
29 | var depName = this.map(tree.token.processedValue) || tree.token.processedValue;
30 |
31 | return new ModuleSpecifier(tree.location, createStringLiteralToken(depName));
32 | };
33 |
34 | exports.TraceurImportNormalizeTransformer = TraceurImportNormalizeTransformer;
35 |
36 |
37 | function remap(source, map, fileName) {
38 | var compiler = new traceur.Compiler();
39 |
40 | var tree = compiler.parse(source, fileName);
41 |
42 | tree = new TraceurImportNormalizeTransformer(map).transformAny(tree);
43 |
44 | return Promise.resolve({
45 | source: compiler.write(tree)
46 | });
47 | }
48 | exports.remap = remap;
49 |
50 | // override System instantiate to handle esm tracing
51 | exports.attach = function(loader) {
52 | var systemInstantiate = loader.instantiate;
53 | loader.instantiate = function(load) {
54 | // skip plugin loader attachment || non es modules || es modules handled by internal transpilation layer
55 | if (!loader.builder || load.metadata.format != 'esm' || load.metadata.originalSource)
56 | return systemInstantiate.call(this, load);
57 |
58 | var depsList = load.metadata.deps.concat([]);
59 |
60 | var babel = require('babel-core');
61 | var output = babel.transform(load.source, {
62 | babelrc: false,
63 | compact: false,
64 | filename: load.path,
65 | //sourceFileName: load.path,
66 | inputSourceMap: load.metadata.sourceMap,
67 | ast: true,
68 | plugins: [syntaxDynamicImport],
69 | resolveModuleSource: function(dep) {
70 | if (depsList.indexOf(dep) == -1)
71 | depsList.push(dep);
72 | return dep;
73 | }
74 | });
75 | // turn back on comments (for some reason!)
76 | output.ast.comments.forEach(function(comment) {
77 | comment.ignore = false;
78 | });
79 | load.metadata.ast = output.ast;
80 |
81 | return Promise.resolve({
82 | deps: depsList,
83 | execute: null
84 | });
85 | };
86 | };
87 |
88 | var versionCheck = true;
89 |
90 | exports.compile = function(load, opts, loader) {
91 | if (!load.metadata.originalSource || load.metadata.loader && load.metadata.format == 'esm') {
92 | var babel = require('babel-core');
93 |
94 | var babelOptions = {
95 | babelrc: false,
96 | compact: false,
97 | plugins: [syntaxDynamicImport, [require('babel-plugin-transform-es2015-modules-systemjs'), { systemGlobal: opts.systemGlobal }]],
98 | filename: load.path,
99 | //sourceFileName: load.path,
100 | sourceMaps: !!opts.sourceMaps,
101 | inputSourceMap: load.metadata.sourceMap,
102 | moduleIds: !opts.anonymous,
103 | moduleId: !opts.anonymous && load.name,
104 | code: true,
105 | resolveModuleSource: function(dep) {
106 | if (opts.normalize)
107 | return load.depMap[dep];
108 | else
109 | return dep;
110 | }
111 | };
112 |
113 | var source = load.metadata.originalSource || load.source;
114 |
115 | var output;
116 | if (load.metadata.ast)
117 | output = babel.transformFromAst(load.metadata.ast, source, babelOptions);
118 | else
119 | output = babel.transform(source, babelOptions);
120 |
121 | // NB this can be removed with merging of ()
122 | if (opts.systemGlobal != 'System')
123 | output.code = output.code.replace(/(\s|^)System\.register\(/, '$1' + opts.systemGlobal + '.register(');
124 |
125 | // for some reason Babel isn't respecting sourceFileName...
126 | if (output.map && !load.metadata.sourceMap)
127 | output.map.sources[0] = load.path;
128 |
129 | return Promise.resolve({
130 | source: output.code,
131 | sourceMap: output.map
132 | });
133 | }
134 |
135 | // ... legacy transpilation, to be deprecated with internal transpilation layer
136 | return Promise.resolve(global[loader.transpiler == 'typescript' ? 'ts' : loader.transpiler] || loader.pluginLoader.import(loader.transpiler))
137 | .then(function(transpiler) {
138 | if (transpiler.__useDefault)
139 | transpiler = transpiler['default'];
140 |
141 | if (transpiler.Compiler) {
142 | var options = loader.traceurOptions || {};
143 | options.modules = 'instantiate';
144 | options.script = false;
145 | options.sourceRoot = true;
146 | options.moduleName = !opts.anonymous;
147 |
148 | if (opts.sourceMaps)
149 | options.sourceMaps = 'memory';
150 | if (opts.lowResSourceMaps)
151 | options.lowResolutionSourceMap = true;
152 |
153 | if (load.metadata.sourceMap)
154 | options.inputSourceMap = load.metadata.sourceMap;
155 |
156 | var compiler = new transpiler.Compiler(options);
157 |
158 | var tree = compiler.parse(load.source, load.path);
159 |
160 | var transformer = new TraceurImportNormalizeTransformer(function(dep) {
161 | return opts.normalize ? load.depMap[dep] : dep;
162 | });
163 |
164 | tree = transformer.transformAny(tree);
165 |
166 | tree = compiler.transform(tree, load.name);
167 |
168 | var outputSource = compiler.write(tree, load.path);
169 |
170 | if (outputSource.match(/\$traceurRuntime/))
171 | load.metadata.usesTraceurRuntimeGlobal = true;
172 |
173 | return Promise.resolve({
174 | source: outputSource,
175 | sourceMap: compiler.getSourceMap()
176 | });
177 | }
178 | else if (transpiler.createLanguageService) {
179 | var options = loader.typescriptOptions || {};
180 | if (options.target === undefined)
181 | options.target = transpiler.ScriptTarget.ES5;
182 | options.module = transpiler.ModuleKind.System;
183 |
184 | var transpileOptions = {
185 | compilerOptions: options,
186 | renamedDependencies: load.depMap,
187 | fileName: load.path,
188 | moduleName: !opts.anonymous && load.name
189 | };
190 |
191 | var transpiled = transpiler.transpileModule(load.source, transpileOptions);
192 |
193 | return Promise.resolve({
194 | source: transpiled.outputText,
195 | sourceMap: transpiled.sourceMapText
196 | });
197 | }
198 | else {
199 | if (versionCheck) {
200 | var babelVersion = transpiler.version;
201 | if (babelVersion.split('.')[0] > 5)
202 | console.log('Warning - using Babel ' + babelVersion + '. This version of SystemJS builder is designed to run against Babel 5.');
203 | versionCheck = false;
204 | }
205 |
206 | var options = extend({}, loader.babelOptions || {});
207 | options.modules = 'system';
208 | if (opts.sourceMaps)
209 | options.sourceMap = true;
210 | if (load.metadata.sourceMap)
211 | options.inputSourceMap = load.metadata.sourceMap;
212 | options.filename = load.path;
213 | options.filenameRelative = load.name;
214 | options.sourceFileName = load.path;
215 | options.keepModuleIdExtensions = true;
216 | options.code = true;
217 | options.ast = false;
218 | options.moduleIds = !opts.anonymous;
219 | options.externalHelpers = true;
220 |
221 | if (transpiler.version.match(/^4/))
222 | options.returnUsedHelpers = true;
223 | else if (transpiler.version.match(/^5\.[01234]\./))
224 | options.metadataUsedHelpers = true;
225 |
226 | if (opts.normalize)
227 | options.resolveModuleSource = function(dep) {
228 | return load.depMap[dep] || dep;
229 | };
230 |
231 | var output = transpiler.transform(load.source, options);
232 |
233 | var usedHelpers = output.usedHelpers || output.metadata && output.metadata.usedHelpers;
234 |
235 | if ((!options.optional || options.optional.indexOf('runtime') == -1) && usedHelpers.length)
236 | load.metadata.usesBabelHelpersGlobal = true;
237 |
238 | // pending Babel v5, we need to manually map the helpers
239 | if (options.optional && options.optional.indexOf('runtime') != -1)
240 | load.deps.forEach(function(dep) {
241 | if (dep.match(/^babel-runtime/))
242 | output.code = output.code.replace(dep, load.depMap[dep]);
243 | });
244 |
245 | // clear options for reuse
246 | delete options.filenameRelative;
247 | delete options.sourceFileName;
248 |
249 | return Promise.resolve({
250 | source: output.code,
251 | sourceMap: output.map
252 | });
253 | }
254 | })
255 | .then(function(output) {
256 | if (opts.systemGlobal != 'System')
257 | output.source = output.source.replace(/System\.register\(/, opts.systemGlobal + '.register(');
258 | return output;
259 | });
260 | };
261 |
--------------------------------------------------------------------------------
/templates/sfx-core.js:
--------------------------------------------------------------------------------
1 | (function (global) {
2 | var registry = {};
3 |
4 | var BASE_OBJECT = typeof Symbol !== 'undefined' ? Symbol() : '@@baseObject';
5 |
6 | function extendNamespace (key) {
7 | Object.defineProperty(this, key, {
8 | enumerable: true,
9 | get: function () {
10 | return this[BASE_OBJECT][key];
11 | }
12 | });
13 | }
14 |
15 | function createExternalModule (exports) {
16 | // a real ES module or SystemJS ES Module
17 | if (typeof System !== 'undefined' && System.isModule ? System.isModule(exports) :
18 | Object.prototype.toString.call(exports) === '[object Module]') {
19 | return exports;
20 | }
21 |
22 | var esModule = { default: exports, __useDefault: exports };
23 |
24 | // CJS es module -> lift into namespace
25 | if (exports && exports.__esModule) {
26 | for (var p in exports) {
27 | if (Object.hasOwnProperty.call(exports, p))
28 | esModule[p] = exports[p];
29 | }
30 | }
31 |
32 | return new Module(esModule);
33 | }
34 |
35 | function Module (bindings) {
36 | Object.defineProperty(this, BASE_OBJECT, {
37 | value: bindings
38 | });
39 | Object.keys(bindings).forEach(extendNamespace, this);
40 | }
41 | Module.prototype = Object.create(null);
42 | if (typeof Symbol !== 'undefined' && Symbol.toStringTag)
43 | Module.prototype[Symbol.toStringTag] = 'Module';
44 |
45 | var nodeRequire = typeof System != 'undefined' && System._nodeRequire || typeof require != 'undefined' && typeof require.resolve != 'undefined' && typeof process != 'undefined' && process.platform && require;
46 |
47 | function getLoad (key) {
48 | if (key.substr(0, 6) === '@node/')
49 | return defineModule(key, createExternalModule(nodeRequire(key.substr(6))), {});
50 | else
51 | return registry[key];
52 | }
53 |
54 | function load (key) {
55 | var load = getLoad(key);
56 |
57 | if (!load)
58 | throw new Error('Module "' + key + '" expected, but not contained in build.');
59 |
60 | if (load.module)
61 | return load.module;
62 |
63 | var link = load.linkRecord;
64 |
65 | instantiate(load, link);
66 |
67 | doEvaluate(load, link, []);
68 |
69 | return load.module;
70 | }
71 |
72 | function instantiate (load, link) {
73 | // circular stop condition
74 | if (link.depLoads)
75 | return;
76 |
77 | if (link.declare)
78 | registerDeclarative(load, link);
79 |
80 | link.depLoads = [];
81 | for (var i = 0; i < link.deps.length; i++) {
82 | var depLoad = getLoad(link.deps[i]);
83 | link.depLoads.push(depLoad);
84 | if (depLoad.linkRecord)
85 | instantiate(depLoad, depLoad.linkRecord);
86 |
87 | var setter = link.setters && link.setters[i];
88 | if (setter) {
89 | setter(depLoad.module || depLoad.linkRecord.moduleObj);
90 | depLoad.importerSetters.push(setter);
91 | }
92 | }
93 |
94 | return load;
95 | }
96 |
97 | function registerDeclarative (load, link) {
98 | var moduleObj = link.moduleObj;
99 | var importerSetters = load.importerSetters;
100 |
101 | var locked = false;
102 |
103 | // closure especially not based on link to allow link record disposal
104 | var declared = link.declare.call(global, function (name, value) {
105 | // export setter propogation with locking to avoid cycles
106 | if (locked)
107 | return;
108 |
109 | if (typeof name == 'object') {
110 | for (var p in name)
111 | if (p !== '__useDefault')
112 | moduleObj[p] = name[p];
113 | }
114 | else {
115 | moduleObj[name] = value;
116 | }
117 |
118 | locked = true;
119 | for (var i = 0; i < importerSetters.length; i++)
120 | importerSetters[i](moduleObj);
121 | locked = false;
122 |
123 | return value;
124 | }, { id: load.key });
125 |
126 | if (typeof declared !== 'function') {
127 | link.setters = declared.setters;
128 | link.execute = declared.execute;
129 | }
130 | else {
131 | link.setters = [];
132 | link.execute = declared;
133 | }
134 | }
135 |
136 | function register (key, deps, declare) {
137 | return registry[key] = {
138 | key: key,
139 | module: undefined,
140 | importerSetters: [],
141 | linkRecord: {
142 | deps: deps,
143 | depLoads: undefined,
144 | declare: declare,
145 | setters: undefined,
146 | execute: undefined,
147 | moduleObj: {}
148 | }
149 | };
150 | };
151 |
152 | function registerDynamic (key, deps, executingRequire, execute) {
153 | var exports = {};
154 | return registry[key] = {
155 | key: key,
156 | module: undefined,
157 | importerSetters: [],
158 | linkRecord: {
159 | deps: deps,
160 | depLoads: undefined,
161 | declare: undefined,
162 | execute: execute,
163 | executingRequire: executingRequire,
164 | moduleObj: {
165 | default: exports,
166 | __useDefault: exports
167 | },
168 | setters: undefined
169 | }
170 | };
171 | }
172 |
173 | function makeDynamicRequire (deps, depLoads, seen) {
174 | // we can only require from already-known dependencies
175 | return function (name) {
176 | for (var i = 0; i < deps.length; i++)
177 | if (deps[i] === name) {
178 | var depLoad = depLoads[i];
179 | var depLink = depLoad.linkRecord;
180 | var module;
181 | if (depLink) {
182 | if (seen.indexOf(depLoad) === -1)
183 | module = doEvaluate(depLoad, depLink, seen);
184 | else
185 | module = depLink.moduleObj;
186 | }
187 | else {
188 | module = depLoad.module;
189 | }
190 | return '__useDefault' in module ? module.__useDefault : module;
191 | }
192 | };
193 | }
194 |
195 | function doEvaluate (load, link, seen) {
196 | seen.push(load);
197 |
198 | if (load.module)
199 | return load.module;
200 |
201 | var err;
202 |
203 | // es modules evaluate dependencies first
204 | if (link.setters) {
205 | for (var i = 0; i < link.deps.length; i++) {
206 | var depLoad = link.depLoads[i];
207 | var depLink = depLoad.linkRecord;
208 |
209 | if (depLink && seen.indexOf(depLoad) === -1)
210 | err = doEvaluate(depLoad, depLink, depLink.setters ? seen : []);
211 | }
212 |
213 | link.execute.call(nullContext);
214 | }
215 | else {
216 | var module = { id: load.key };
217 | var moduleObj = link.moduleObj;
218 | Object.defineProperty(module, 'exports', {
219 | configurable: true,
220 | set: function (exports) {
221 | moduleObj.default = moduleObj.__useDefault = exports;
222 | },
223 | get: function () {
224 | return moduleObj.__useDefault;
225 | }
226 | });
227 | var require = makeDynamicRequire(link.deps, link.depLoads, seen);
228 |
229 | // evaluate deps first
230 | if (!link.executingRequire)
231 | for (var i = 0; i < link.deps.length; i++)
232 | require(link.deps[i]);
233 |
234 | var output = link.execute.call(global, require, moduleObj.__useDefault, module);
235 | if (output !== undefined)
236 | moduleObj.default = moduleObj.__useDefault = output;
237 | else if (module.exports !== moduleObj.__useDefault)
238 | moduleObj.default = moduleObj.__useDefault = module.exports;
239 |
240 | var moduleDefault = moduleObj.__useDefault;
241 |
242 | // __esModule flag extension support
243 | if (moduleDefault && moduleDefault.__esModule)
244 | for (var p in moduleDefault)
245 | if (Object.hasOwnProperty.call(moduleDefault, p))
246 | moduleObj[p] = moduleDefault[p];
247 | }
248 |
249 | var module = load.module = new Module(link.moduleObj);
250 |
251 | if (!link.setters)
252 | for (var i = 0; i < load.importerSetters.length; i++)
253 | load.importerSetters[i](module);
254 |
255 | return module;
256 | }
257 |
258 | // {} is the closest we can get to call(undefined)
259 | var nullContext = {};
260 | if (Object.freeze)
261 | Object.freeze(nullContext);
262 |
263 | function defineModule (name, module) {
264 | return registry[name] = {
265 | key: name,
266 | module: module,
267 | importerSetters: [],
268 | linkRecord: undefined
269 | };
270 | }
271 |
272 | return function (mains, depNames, exportDefault, declare) {
273 | return function (formatDetect) {
274 | formatDetect(function (deps) {
275 | var System = {
276 | _nodeRequire: nodeRequire,
277 | register: register,
278 | registerDynamic: registerDynamic,
279 | registry: {
280 | get: function (name) {
281 | return registry[name].module;
282 | },
283 | set: defineModule
284 | },
285 | newModule: function (module) {
286 | return new Module(module);
287 | }
288 | };
289 |
290 | defineModule('@empty', new Module({}));
291 |
292 | // register external dependencies
293 | for (var i = 0; i < depNames.length; i++)
294 | defineModule(depNames[i], createExternalModule(arguments[i], {}));
295 |
296 | // register modules in this bundle
297 | declare(System);
298 |
299 | // load mains
300 | var firstLoad = load(mains[0]);
301 | if (mains.length > 1)
302 | for (var i = 1; i < mains.length; i++)
303 | load(mains[i]);
304 |
305 | if (exportDefault)
306 | return firstLoad.__useDefault;
307 |
308 | if (firstLoad instanceof Module)
309 | Object.defineProperty(firstLoad, '__esModule', {
310 | value: true
311 | });
312 |
313 | return firstLoad;
314 | });
315 | };
316 | };
317 |
318 | })((typeof self !== 'undefined') ? self : (typeof global !== 'undefined') ? global : this)
319 | /* (['mainModule'], ['external-dep'], false, function($__System) {
320 | System.register(...);
321 | })
322 | (function(factory) {
323 | if (typeof define && define.amd)
324 | define(['external-dep'], factory);
325 | // etc UMD / module pattern
326 | })*/
327 |
--------------------------------------------------------------------------------
/test/arithmetic.js:
--------------------------------------------------------------------------------
1 | var Builder = require('../index');
2 | var builder = new Builder();
3 |
4 | builder.loadConfigSync('./test/fixtures/test-tree.config.js');
5 |
6 | builder.config({ transpiler: 'babel' });
7 |
8 | suite('Bundle Expressions', function() {
9 | test('Addition', function(done) {
10 | builder.trace('amd.js + amd-2.js')
11 | .then(function(tree) {
12 | assert.deepEqual(Object.keys(tree).sort(),
13 | ['amd-2.js', 'amd.js', 'global.js', 'jquery.js', 'some.js!plugin.js', 'text.txt!text-plugin.js']);
14 | })
15 | .then(done, done);
16 | });
17 |
18 | test('Single module subtraction', function(done) {
19 | builder.trace('amd.js + amd-2.js - [amd-1.js]')
20 | .then(function(tree) {
21 | assert.deepEqual(Object.keys(tree).sort(),
22 | ['amd-2.js', 'amd.js', 'global.js', 'jquery.js', 'some.js!plugin.js', 'text.txt!text-plugin.js']);
23 | })
24 | .then(done, done);
25 | });
26 |
27 | test('Commonality operator', function(done) {
28 | builder.trace('amd-5b.js & second.js')
29 | .then(function(tree) {
30 | assert.deepEqual(Object.keys(tree).sort(), ['cjs.js', 'second.js', 'third.js']);
31 | })
32 | .then(done, done);
33 | });
34 |
35 | test('Wildcard bundling', function(done) {
36 | builder.trace('*.js - [amd-*] - [sfx-format-*]')
37 | .then(function(tree) {
38 | assert.deepEqual(Object.keys(tree).sort(), [
39 | 'Buffer.js', 'amd.js', 'babel', 'babel.js', 'cjs space.js', 'cjs-1.js', 'cjs-2.js', 'cjs-3.js', 'cjs-4.js', 'cjs-5.js', 'cjs-globals.js', 'cjs-in-12.js', 'cjs-in-13.js',
40 | 'cjs-resolve.js', 'cjs.js', 'class-def.js', 'component.jsx!jsx.js', 'example.js', 'file.json', 'first.js',
41 | 'global-inner.js', 'global-outer.js', 'global.js', 'jquery-cdn', 'jquery.js', 'json-plugin.js', 'jsx.js', 'plugin.js', 'register.js', 'runtime.js',
42 | 'second.js', 'some.js!plugin.js', 'text-plugin.js', 'text.txt!text-plugin.js', 'third.js', 'umd.js']);
43 | })
44 | .then(done, done);
45 | });
46 |
47 | test('Wildcard plugin', function(done) {
48 | builder.trace('*.jsx!jsx.js - [component.jsx!jsx.js]')
49 | .then(function(tree) {
50 | assert.deepEqual(Object.keys(tree).sort(), []);
51 | })
52 | .then(done, done);
53 | });
54 |
55 | test('cjs bundles added', function(done){
56 | builder.trace('cjs-1.js + cjs-2.js + cjs-3.js')
57 | .then(function(tree) {
58 | assert.deepEqual(Object.keys(tree).sort(), [
59 | 'cjs-1.js', 'cjs-2.js', 'cjs-3.js', 'cjs-in-12.js', 'cjs-in-13.js']);
60 | })
61 | .then(done, done);
62 | });
63 |
64 | test('cjs bundles added with parens and extra spaces', function(done){
65 | builder.trace(' ( cjs-1.js & cjs-2.js ) + ( cjs-1.js & cjs-3.js)')
66 | .then(function(tree) {
67 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js', 'cjs-in-13.js']);
68 | })
69 | .then(done, done);
70 | });
71 |
72 | test('cjs bundles added with single-value parameters', function(done){
73 | builder.trace('(cjs-1.js) + (cjs-2.js) + (cjs-3.js)')
74 | .then(function(tree) {
75 | assert.deepEqual(Object.keys(tree).sort(), [
76 | 'cjs-1.js', 'cjs-2.js', 'cjs-3.js', 'cjs-in-12.js', 'cjs-in-13.js']);
77 | })
78 | .then(done, done);
79 | });
80 |
81 | test('cjs bundles added with parens', function(done){
82 | builder.trace('(cjs-1.js & cjs-2.js) + (cjs-1.js & cjs-3.js)')
83 | .then(function(tree) {
84 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js', 'cjs-in-13.js']);
85 | })
86 | .then(done, done);
87 | });
88 |
89 | test('cjs bundles added with parens 2', function(done){
90 | builder.trace('(cjs-1.js & cjs-2.js)')
91 | .then(function(tree) {
92 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js']);
93 | })
94 | .then(done, done);
95 | });
96 |
97 | test('cjs bundles added with parens 3', function(done){
98 | builder.trace('(cjs-1.js & cjs-2.js) + cjs-in-13.js - cjs-in-13.js')
99 | .then(function(tree) {
100 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js']);
101 | })
102 | .then(done, done);
103 | });
104 |
105 | test('cjs bundles added with parens 4', function(done){
106 | builder.trace('(cjs-1.js & cjs-2.js) + cjs-in-13.js - cjs-in-13.js')
107 | .then(function(tree) {
108 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js']);
109 | })
110 | .then(done, done);
111 | });
112 |
113 | test('cjs bundles added with parens 5', function(done){
114 | builder.trace('cjs-in-13.js + (cjs-1.js & cjs-2.js) - cjs-in-13.js')
115 | .then(function(tree) {
116 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js']);
117 | })
118 | .then(done, done);
119 | });
120 |
121 | test('cjs bundles added with multiple parens', function(done){
122 | builder.trace('cjs-in-13.js + (cjs-1.js & cjs-2.js) - (cjs-in-13.js)')
123 | .then(function(tree) {
124 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js']);
125 | })
126 | .then(done, done);
127 | });
128 |
129 | test('cjs bundles added with multiple parens 2', function(done){
130 | builder.trace('(cjs-1.js & cjs-2.js) + (cjs-1.js & cjs-3.js) - cjs-in-12.js')
131 | .then(function(tree) {
132 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-13.js']);
133 | })
134 | .then(done, done);
135 | });
136 |
137 | test('cjs bundles with nested parens', function(done){
138 | builder.trace('(cjs-1.js + cjs-2.js - ([cjs-1.js] + [cjs-2.js])) - (cjs-in-12.js)')
139 | .then(function(tree) {
140 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-13.js']);
141 | })
142 | .then(done, done);
143 | });
144 |
145 | test('cjs bundles with nested parens 2', function(done){
146 | builder.trace('(cjs-1.js + cjs-2.js - ([cjs-1.js] + [cjs-2.js])) - (cjs-in-12.js) + (cjs-4.js + cjs-5.js)')
147 | .then(function(tree) {
148 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-4.js', 'cjs-5.js', 'cjs-in-13.js']);
149 | })
150 | .then(done, done);
151 | });
152 |
153 | test('cjs bundles with nested parens 3', function(done){
154 | builder.trace('((cjs-1.js + cjs-2.js - ([cjs-1.js] + [cjs-2.js])) - (cjs-in-12.js) + (cjs-4.js + cjs-5.js)) - ([cjs-4.js] + [cjs-5.js])')
155 | .then(function(tree) {
156 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-13.js']);
157 | })
158 | .then(done, done);
159 | });
160 |
161 | test('cjs bundles with nested parens 4', function(done){
162 | builder.trace('((cjs-1.js + cjs-2.js - ([cjs-1.js] + [cjs-2.js] + ([cjs-4.js] + [cjs-5.js]))) - (cjs-4.js + cjs-5.js))')
163 | .then(function(tree) {
164 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js', 'cjs-in-13.js']);
165 | })
166 | .then(done, done);
167 | });
168 |
169 |
170 | test('ibid with single module subtracted', function(done){
171 | builder.trace('(cjs-1.js + cjs-2.js - ([cjs-1.js] + [cjs-2.js])) - ([cjs-in-12.js])')
172 | .then(function(tree) {
173 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-13.js']);
174 | })
175 | .then(done, done);
176 | });
177 |
178 | test('cjs bundles added with nested parens', function(done){
179 | builder.trace('(cjs-1.js + cjs-2.js - (cjs-1.js & cjs-2.js))')
180 | .then(function(tree) {
181 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-1.js', 'cjs-2.js', 'cjs-in-13.js']);
182 | })
183 | .then(done, done);
184 | });
185 |
186 | test('cjs bundles with parens and single modules', function(done){
187 | builder.trace('(cjs-1.js + cjs-2.js) - ([cjs-1.js] + [cjs-2.js])')
188 | .then(function(tree) {
189 | assert.deepEqual(Object.keys(tree).sort(), ['cjs-in-12.js', 'cjs-in-13.js']);
190 | })
191 | .then(done, done);
192 | });
193 |
194 | test('file with space', function(done){
195 | builder.trace('cjs-1.js + cjs space.js')
196 | .then(function(tree) {
197 | assert.deepEqual(Object.keys(tree).sort(), [
198 | 'cjs space.js', 'cjs-1.js', 'cjs-in-12.js', 'cjs-in-13.js']);
199 | })
200 | .then(done, done);
201 | });
202 |
203 | test('file with space 2', function(done){
204 | builder.trace('cjs-1.js + cjs space.js ')
205 | .then(function(tree) {
206 | assert.deepEqual(Object.keys(tree).sort(), [
207 | 'cjs space.js', 'cjs-1.js', 'cjs-in-12.js', 'cjs-in-13.js']);
208 | })
209 | .then(done, done);
210 | });
211 |
212 | test('file with space 3', function(done){
213 | builder.trace('cjs-1.js + cjs space.js + cjs-2.js')
214 | .then(function(tree) {
215 | assert.deepEqual(Object.keys(tree).sort(), [
216 | 'cjs space.js', 'cjs-1.js', 'cjs-2.js', 'cjs-in-12.js', 'cjs-in-13.js']);
217 | })
218 | .then(done, done);
219 | });
220 |
221 | test('file with space 4', function(done){
222 | builder.trace('cjs-1.js + cjs space.js + cjs-2.js ')
223 | .then(function(tree) {
224 | assert.deepEqual(Object.keys(tree).sort(), [
225 | 'cjs space.js', 'cjs-1.js', 'cjs-2.js', 'cjs-in-12.js', 'cjs-in-13.js']);
226 | })
227 | .then(done, done);
228 | });
229 |
230 | });
231 |
232 | suite('Bundle Expression Validation', function() {
233 | test('missing identifier 1', function(){
234 | return validateInvalidExpression('cjs-1.js + +');
235 | });
236 |
237 | test('missing identifier 2', function(){
238 | return validateInvalidExpression('cjs-1.js + -');
239 | });
240 |
241 | test('missing identifier 3', function(){
242 | return validateInvalidExpression('cjs-1.js + &');
243 | });
244 |
245 | test('unclosed parens 1', function(){
246 | return validateInvalidExpression('(cjs-1.js + cjs-2.js');
247 | });
248 |
249 | test('unclosed parens 2', function(){
250 | return validateInvalidExpression('(cjs-1.js + (cjs-2.js + cjs-3.js');
251 | });
252 |
253 | test('unclosed parens 3', function(){
254 | return validateInvalidExpression('(cjs-1.js + (cjs-2.js + cjs-3.js)');
255 | });
256 |
257 | test('unclosed parens 4', function(){
258 | return validateInvalidExpression('(cjs-2.js + cjs-3.js) + (cjs-1.js + (cjs-2.js + cjs-3.js)');
259 | });
260 |
261 | function validateInvalidExpression(expression){
262 | return Promise
263 | .resolve()
264 | .then(function(){ return builder.trace(expression) })
265 | .then(
266 | function(){ return Promise.reject('Invalid expression <' + expression + '> was parsed without error'); }, //it worked but shouldn't have
267 | function(err){
268 | //uncomment this line to view the Syntax Errors' wordings in the test console
269 | //console.log(err);
270 | if (typeof err !== 'string' || !/^Syntax Error/i.test(err)){
271 | return Promise.reject('Syntax error was expected, but not generated')
272 | } else {
273 | return Promise.resolve(1);
274 | }
275 | }
276 | )
277 | }
278 |
279 | });
280 |
281 |
282 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SystemJS Build Tool [![Build Status][travis-image]][travis-url] [](https://supporterhq.com/support/33df4abbec4d39260f49015d2457eafe/SystemJS)
2 | ===
3 |
4 | **This project has been deprecated as of SystemJS 2.0. It will continue to support SystemJS 0.21 legacy builds though. Instead, [Rollup code splitting builds](https://rollupjs.org/guide/en#experimental-code-splitting) are encouraged.**
5 |
6 | _[SystemJS Builder 0.16 release notes](https://github.com/systemjs/builder/releases/tag/0.16.0)_
7 |
8 | _Note for SystemJS 0.19 support use SystemJS Builder 0.15_
9 |
10 | Provides a single-file build for SystemJS of mixed-dependency module trees.
11 |
12 | Builds ES6 into ES5, CommonJS, AMD and globals into a single file in a way that supports the CSP SystemJS loader
13 | as well as circular references.
14 |
15 | Example
16 | ---
17 |
18 | app.js
19 | ```javascript
20 | import $ from "./jquery.js";
21 | export var hello = 'es6';
22 | ```
23 |
24 | jquery.js
25 | ```javascript
26 | define(function() {
27 | return 'this is jquery';
28 | });
29 | ```
30 |
31 | Will build the module `app` into a bundle containing both `app` and `jquery` defined through `System.register` calls.
32 |
33 | Circular references and bindings in ES6, CommonJS and AMD all behave exactly as they should, including maintaining execution order.
34 |
35 | Documentation
36 | ---
37 | [API Reference](docs/api.md)
38 |
39 | Usage
40 | ---
41 |
42 | ### Install
43 |
44 | ```javascript
45 | npm install systemjs-builder
46 | ```
47 |
48 | ### Basic Use
49 |
50 | Ensure that the transpiler is installed separately (`npm install babel-core` here).
51 |
52 | ```javascript
53 | var path = require("path");
54 | var Builder = require('systemjs-builder');
55 |
56 | // optional constructor options
57 | // sets the baseURL and loads the configuration file
58 | var builder = new Builder('path/to/baseURL', 'path/to/system/config-file.js');
59 |
60 | builder
61 | .bundle('local/module.js', 'outfile.js')
62 | .then(function() {
63 | console.log('Build complete');
64 | })
65 | .catch(function(err) {
66 | console.log('Build error');
67 | console.log(err);
68 | });
69 | ```
70 |
71 | ### Setting Configuration
72 |
73 | Configuration can be injected via `builder.config`:
74 |
75 | ```javascript
76 | builder.config({
77 | map: {
78 | 'a': 'b.js'
79 | }
80 | });
81 | builder.build('a');
82 | ```
83 |
84 | To load custom configuration files use `builder.loadConfig`:
85 |
86 | ```javascript
87 | // `builder.loadConfig` will load config from a file containing `System.config({...})`
88 | builder.loadConfig('./cfg.js')
89 | .then(function() {
90 | // ready to build
91 | });
92 | ```
93 |
94 | Multiple config calls can be run, which will combine into the loader configuration.
95 |
96 | #### Resetting Configuration
97 |
98 | To reset the loader state and configuration use `builder.reset()`.
99 |
100 | When config was passed into the `new Builder(baseURL, configFile)` constructor, the config will be reset to this exact `configFile` state.
101 |
102 | ### Self-Executing (SFX) Bundles
103 |
104 | To make a bundle that is independent of the SystemJS loader entirely, we can make SFX bundles:
105 |
106 | ```javascript
107 | builder.buildStatic('myModule.js', 'outfile.js', options);
108 | ```
109 |
110 | This bundle file can then be included with a `
138 |
139 | ```
140 |
141 | Note that another way of excluding `react` would be with `externals`.
142 |
143 | ```javascript
144 | builder.buildStatic('src/NavBar.js', 'dist/NavBarStaticBuild.js', {
145 | externals: ['react'],
146 | globalName: 'NavBar',
147 | globalDeps: {
148 | 'react': 'React'
149 | }
150 | });
151 | ```
152 |
153 | This would also exclude react but, if react defined any dependencies which NavBar *also* defined, those dependencies would be *included* in the build.
154 |
155 | Of course the above explanations involving `globalDeps` and `globalName` only apply to when your end user loads the static file from a script tag. Since the output is (by default, see below) UMD, a
156 | script loader like SystemJS or requireJS would process it as configured, or via AMD respectively.
157 |
158 | By default, the Traceur or Babel runtime are automatically included in the SFX bundle if needed. To exclude the Babel or Traceur runtime set the `runtime` build option to false:
159 |
160 | ```javascript
161 | builder.buildStatic('myModule.js', 'outfile.js', { runtime: false });
162 | ```
163 |
164 | #### SFX Format
165 |
166 | SFX bundles can also be output as a custom module format - `amd`, `cjs` or `es6` for consumption in different environments.
167 |
168 | This is handled via the `format` (previously `sfxFormat`) option:
169 |
170 | ```javascript
171 | builder.buildStatic('myModule.js', 'outfile.js', { format: 'cjs' });
172 | ```
173 |
174 | The first module used as input (`myModule.js` here) will then have its exports output as the CommonJS exports of the whole SFX bundle itself
175 | when run in a CommonJS environment.
176 |
177 | #### Adapter Modules
178 |
179 | To have globals like `jQuery` not included, and included in a separate script tag, set up an adapter module something like:
180 |
181 | jquery.js
182 | ```javascript
183 | module.exports = window.jQuery;
184 | ```
185 |
186 | ### Minification & Source Maps
187 |
188 | As well as an `options.config` parameter, it is also possible to specify minification and source maps options:
189 |
190 | ```javascript
191 | builder.bundle('myModule.js', 'outfile.js', { minify: true, sourceMaps: true, config: cfg });
192 | ```
193 |
194 | Compile time with source maps can also be improved with the `lowResSourceMaps` option, where the mapping granularity is per-line instead of per-character:
195 |
196 | ```javascript
197 | builder.bundle('myModule.js', 'outfile.js', { sourceMaps: true, lowResSourceMaps: true });
198 | ```
199 |
200 | #### Minification Options
201 |
202 | * `mangle`, defaults to true.
203 | * `globalDefs`, object allowing for global definition assignments for dead code removal.
204 |
205 | ```javascript
206 | builder.bundle('myModule.js', 'outfile.js', { minify: true, mangle: false, globalDefs: { DEBUG: false } });
207 | ```
208 |
209 | #### SourceMap Options
210 |
211 | * `sourceMaps`, Either boolean value (enable/disable) or string value `'inline'` which will inline the SourceMap data as Base64 data URI right in the generated output file (never use in production). *(Default is `false`)*
212 | * `sourceMapContents`, Boolean value that determines if original sources shall be directly included in the SourceMap. Using inline source contents generates truely self contained SourceMaps which will not need to load the external original source files during debugging. *(Default is `false`; when using `sourceMaps='inline'` it defaults `true`)*
213 |
214 |
215 | ### In-Memory Builds
216 |
217 | Leave out the `outFile` option to run an in-memory build:
218 |
219 | ```javascript
220 | builder.bundle('myModule.js', { minify: true }).then(function(output) {
221 | output.source; // generated bundle source
222 | output.sourceMap; // generated bundle source map
223 | output.modules; // array of module names defined in the bundle
224 | });
225 | ```
226 |
227 | The `output` object above is provided for all builds, including when `outFile` is set.
228 |
229 | `output.modules` can be used to directly populate SystemJS bundles configuration.
230 |
231 | ### Ignore Resources
232 |
233 | If loading resources that shouldn't even be traced as part of the build (say an external import), these
234 | can be configured with:
235 |
236 | ```javascript
237 | builder.config({
238 | meta: {
239 | 'resource/to/ignore.js': {
240 | build: false
241 | }
242 | }
243 | });
244 | ```
245 |
246 | ### Overriding Fetch
247 |
248 | The framework fetch function can be overridden in order to provide the source for a file manually. This is useful if you want to pre-process the source of a file before using the builder.
249 |
250 | ```javascript
251 | var mySource = 'import * from foo; var foo = "bar";'; // get source as a string
252 | builder.bundle('foo.js', {
253 | fetch: function (load, fetch) {
254 | if (load.name.indexOf('foo.js') !== -1) {
255 | return mySource;
256 | } else {
257 | // fall back to the normal fetch method
258 | return fetch(load);
259 | }
260 | }
261 | });
262 | ```
263 |
264 | The `load` variable describes the file that is trying to be loaded. This is called once for every file that is trying to be fetched, including dependencies.
265 |
266 | The `fetch` function should return a string.
267 |
268 | ### Bundle Arithmetic
269 |
270 | Both `builder.build` and `builder.buildStatic` support bundle arithmetic expressions. This allows for the easy construction of custom bundles.
271 |
272 | There is also a `builder.trace` for building direct trace tree objects, which can be directly passed into `builder.bundle` or `builder.buildStatic`.
273 |
274 | #### Example - Arithmetic Expressions
275 |
276 | In this example we build all our application code in `app/` excluding the tree `app/corelibs`:
277 |
278 | ```javascript
279 | var Builder = require('systemjs-builder');
280 |
281 | var builder = new Builder({
282 | baseURL: '...',
283 | map: {
284 | } // etc. config
285 | });
286 |
287 | builder.bundle('app/* - app/corelibs.js', 'output-file.js', { minify: true, sourceMaps: true });
288 | ```
289 |
290 | #### Example - Common Bundles
291 |
292 | To build the dependencies in common between two modules, use the `&` operator:
293 |
294 | ```javascript
295 | builder.bundle('app/page1.js & app/page2.js', 'common.js');
296 | ```
297 |
298 | We can then exclude this common bundle in future builds:
299 |
300 | ```javascript
301 | builder.bundle('app/componentA.js - common.js', { minify: true, sourceMaps: true });
302 | ```
303 |
304 | #### Example - Third-Party Dependency Bundles
305 |
306 | Build a bundle of all dependencies of the `app/` package excluding anything from `app/` itself.
307 |
308 | For this we can use the `[module]` syntax which represents a single module instead of all its dependencies as well:
309 |
310 | ```javascript
311 | builder.bundle('app/**/* - [app/**/*]', 'dependencies.js', { minify: true, sourceMaps: true });
312 | ```
313 |
314 | The above means _take the tree of app and all its dependencies, and subtract just the modules in app_, thus leaving us with just the tree of dependencies of the app package.
315 |
316 | #### Example - Multiple Common Bundles
317 |
318 | Parentheses are supported, so the following would bundle everything in common with `page1` and `page2`, and also everything in common between `page3` and `page4`:
319 |
320 | ```javascript
321 | builder.bundle('(app/page1.js & app/page2.js) + (app/page3.js & app/page4.js)', 'common.js');
322 | ```
323 |
324 | #### Example - Direct Trace API
325 |
326 | Instead of using the arithmetic syntax, we can construct the trace ourselves.
327 |
328 | In this example we build `app/first` and `app/second` into two separate bundles, while creating a separate shared bundle:
329 |
330 | ```javascript
331 | var Builder = require('systemjs-builder');
332 |
333 | var builder = new Builder({
334 | // ...
335 | });
336 |
337 | Promise.all([builder.trace('app/first.js'), builder.trace('app/second.js')])
338 | .then(function(trees) {
339 | var commonTree = builder.intersectTrees(trees[0], trees[1]);
340 | return Promise.all([
341 | builder.bundle(commonTree, 'shared-bundle.js'),
342 | builder.bundle(builder.subtractTrees(trees[0], commonTree), 'first-bundle.js'),
343 | builder.bundle(builder.subtractTrees(trees[1], commonTree), 'second-bundle.js')
344 | ]);
345 | });
346 | ```
347 |
348 | License
349 | ---
350 |
351 | MIT
352 |
353 | [travis-url]: https://travis-ci.org/systemjs/builder
354 | [travis-image]: https://travis-ci.org/systemjs/builder.svg?branch=master
355 |
--------------------------------------------------------------------------------
/lib/rollup.js:
--------------------------------------------------------------------------------
1 | var rollup = require('rollup');
2 | var traverseTree = require('./arithmetic').traverseTree;
3 | var getConditionModule = require('./trace').getConditionModule;
4 | var extend = require('./utils').extend;
5 | var getAlias = require('./utils').getAlias;
6 | var pluginBundleHook = require('./compile').pluginBundleHook;
7 |
8 | exports.rollupTree = function(loader, tree, entryPoints, traceOpts, compileOpts, outputOpts) {
9 | /*
10 | * 1. Determine the tree entry points and optimization points
11 | *
12 | * eg for the tree:
13 | *
14 | * A -> B -> C
15 | * D -> C
16 | *
17 | * A and D are the entry points.
18 | * Optimization points are ES module entry points to be optimized
19 | *
20 | */
21 |
22 | entryPoints = entryPoints.concat([]);
23 |
24 | var optimizationPoints = [];
25 |
26 | var entryMap = {};
27 |
28 | function isESM(moduleName) {
29 | return tree[moduleName] && tree[moduleName].metadata && tree[moduleName].metadata.format == 'esm' && !tree[moduleName].metadata.originalSource && !tree[moduleName].source.match(/\s+import\s*\(/);
30 | }
31 |
32 | // for each module in the tree, we traverse the whole tree
33 | // we then relate each module in the tree to the first traced entry point
34 | Object.keys(tree).forEach(function(entryPoint) {
35 | traverseTree(tree, entryPoint, function(depName, parentName) {
36 | // esm from a non-esm parent means this is an optimization entry point from the linking alogorithm perspective
37 | if (parentName && isESM(depName) && !isESM(parentName) && optimizationPoints.indexOf(depName) == -1)
38 | optimizationPoints.push(depName);
39 |
40 | // if we have a entryMap for the given module, then stop
41 | if (entryMap[depName])
42 | return false;
43 |
44 | if (parentName)
45 | entryMap[depName] = entryPoint;
46 | }, traceOpts);
47 | });
48 |
49 | // the entry points are then the modules not represented in entryMap
50 | Object.keys(tree).forEach(function(entryPoint) {
51 | if (!entryMap[entryPoint] && tree[entryPoint] && entryPoints.indexOf(entryPoint) == -1)
52 | entryPoints.push(entryPoint);
53 | });
54 |
55 | // if all the entry points are ES modules,
56 | // then we can create a single dummy entry point
57 | // that represents the tree
58 | var esmEntryPoints = 0;
59 | entryPoints.forEach(function(entryPoint) {
60 | if (tree[entryPoint].metadata && tree[entryPoint].metadata.format == 'esm')
61 | esmEntryPoints ++;
62 | });
63 |
64 | if (esmEntryPoints > 1 && esmEntryPoints == entryPoints.length) {
65 | var dummySource = 'export * from "' + entryPoints[0] + '";\n';
66 | var dummyDepMap = {};
67 |
68 | entryPoints.forEach(function(entryPoint) {
69 | dummyDepMap[entryPoint] = entryPoint;
70 |
71 | dummySource += 'import "' + entryPoint + '";';
72 | });
73 |
74 | tree['@dummy-entry-point'] = {
75 | name: '@dummy-entry-point',
76 | path: null,
77 | metadata: { format: 'esm' },
78 | deps: entryPoints,
79 | depMap: dummyDepMap,
80 | source: dummySource
81 | };
82 | entryPoints = ['@dummy-entry-point'];
83 | }
84 |
85 | // optimization points are then es module entry points
86 | entryPoints.forEach(function(entryPoint) {
87 | if (isESM(entryPoint) && optimizationPoints.indexOf(entryPoint) == -1)
88 | optimizationPoints.push(entryPoint);
89 | });
90 |
91 | /*
92 | * 2. Determine unoptimizable modules, splitting them out into their own optimization points
93 | *
94 | * eg for the tree:
95 | * A -> B -> C -> D
96 | * E -> C -> D
97 | *
98 | * A, E are top-level entry points detected by the previous step
99 | * (and hence optimization points if they are es modules)
100 | * C is not optimizable because it has two unique parent entry points
101 | * (which is what this step looks for)
102 | * So C becomes its own optimization point
103 | * Leading to D inlining into C and B inlining into A
104 | *
105 | */
106 |
107 | // for each module in the tree, we track its parent optimization point
108 | // as soon as a module has two parent entry points, it is not optimizable
109 | // and we set it to undefined here. It then becomes its own optimizationPoint.
110 | var optimizationParentMap = {};
111 |
112 | // build up the parent entry point map as above
113 | // we use for over forEach because this list will grow as we go
114 | for (var i = 0; i < optimizationPoints.length; i++) {
115 | var entryPoint = optimizationPoints[i];
116 | traverseTree(tree, entryPoint, function(depName, parentName) {
117 |
118 | // we only traverse ES module tree subgraphs
119 | if (!isESM(depName))
120 | return false;
121 |
122 | if (depName == entryPoint)
123 | return;
124 |
125 | // dont traverse through other entry points
126 | if (optimizationPoints.indexOf(depName) != -1)
127 | return false;
128 |
129 | if (!optimizationParentMap[depName]) {
130 | optimizationParentMap[depName] = entryPoint;
131 | return;
132 | }
133 |
134 | // module in two separate entry point graphs -> it becomes its own optimization entry point
135 | if (optimizationParentMap[depName] != entryPoint) {
136 | optimizationParentMap[depName] = undefined;
137 |
138 | // this new optimization point will then be traversed in turn as part of this loop later
139 | optimizationPoints.push(depName);
140 | }
141 | }, traceOpts);
142 | }
143 |
144 | /*
145 | * 3. Given complete optimization points, populate subgraph externals
146 | *
147 | * eg for the graph
148 | * A -> B -> C
149 | *
150 | * Where A is the optimization point, and C is not ESM, another optimization point,
151 | * or not contained in our build tree, then we mark 'C' as an external.
152 | *
153 | * That is, optimizationGraphExternals[A] = [C]
154 | *
155 | * This externals input is used in the Rollup API.
156 | * This way we just optimize B into A, retaining an explicit dependency on C.
157 | */
158 |
159 | var inlinedModules = [];
160 | var optimizationGraphExternals = {};
161 |
162 | optimizationPoints.forEach(function(entryPoint) {
163 | // the subgraph object is the list of modules in the subgraph
164 | // and the list of modules that are "external" boundaries of the subgraph
165 | var externals = [];
166 |
167 | // this traversal is a bit odd, since we need to traverse the full
168 | // dependency graph to detect externals, not just the direct build graph
169 | traverseTree(tree, entryPoint, function(depName, parentName) {
170 | if (!isESM(depName) || (depName != entryPoint && optimizationPoints.indexOf(depName) != -1))
171 | return false;
172 |
173 | var depLoad = tree[depName];
174 | depLoad.deps && depLoad.deps.forEach(function(depName) {
175 | depName = depLoad.depMap[depName];
176 | if (depName == entryPoint)
177 | return;
178 |
179 | // anything not ESM, not in the tree, or an optimization point, is external
180 | if (!isESM(depName) || optimizationPoints.indexOf(depName) != -1) {
181 | if (externals.indexOf(depName) == -1)
182 | externals.push(depName);
183 | }
184 | else {
185 | if (inlinedModules.indexOf(depName) == -1)
186 | inlinedModules.push(depName);
187 | }
188 | }, traceOpts);
189 | });
190 |
191 | optimizationGraphExternals[entryPoint] = externals;
192 | });
193 |
194 | // finally we rollup each optimization graph
195 | var rolledUpTree = {};
196 | Object.keys(tree).forEach(function(moduleName) {
197 | if (inlinedModules.indexOf(moduleName) == -1)
198 | rolledUpTree[moduleName] = tree[moduleName];
199 | });
200 |
201 | // compute the inlineMap
202 | var inlineMap = {};
203 | inlinedModules.forEach(function(moduleName) {
204 | var optimizationParent = optimizationParentMap[moduleName];
205 | (inlineMap[optimizationParent] = inlineMap[optimizationParent] || []).push(moduleName);
206 | });
207 |
208 | // if every module in the tree is rolled-up, then we can do a full tree rollup
209 | var fullTreeRollup = entryPoints.length == 1 && optimizationPoints.length == 1 && Object.keys(optimizationGraphExternals).length == 1;
210 |
211 | return Promise.all(Object.keys(optimizationGraphExternals).map(function(entryPoint) {
212 | var externals = optimizationGraphExternals[entryPoint];
213 | var loadList = [];
214 | var entryPointLoad;
215 |
216 | // if all externals are outside the tree then this really is a full tree rollup
217 | // also @node/x requires mean we do need sfx core (pending a better output of these)
218 | if (fullTreeRollup)
219 | externals.forEach(function(external) {
220 | if (external.substr(0, 5) == '@node' || tree[external])
221 | fullTreeRollup = false;
222 | });
223 |
224 | var aliasedExternals = externals.map(function(external) {
225 | var alias = getAlias(loader, external) || externals;
226 | if (alias.indexOf('#:') != -1)
227 | alias = alias.replace('#:', '/');
228 | return alias;
229 | });
230 |
231 | return rollup.rollup({
232 | entry: entryPoint,
233 | external: aliasedExternals,
234 | acorn: {
235 | allowReserved: true,
236 | ecmaVersion: 8
237 | },
238 | plugins: [{
239 | resolveId: function(id, importer, options) {
240 | var resolved = importer ? tree[importer].depMap[id] : id;
241 | var externalIndex = externals.indexOf(resolved);
242 | if (externalIndex != -1)
243 | return aliasedExternals[externalIndex];
244 | return resolved;
245 | },
246 | load: function(id, options) {
247 | if (loadList.indexOf(tree[id]) == -1)
248 | loadList.push(tree[id]);
249 | loadList.push(tree[id]);
250 | return {
251 | code: tree[id].metadata.originalSource || tree[id].source,
252 | map: tree[id].metadata.sourceMap
253 | };
254 | }
255 | }],
256 | onwarn: function(message) {}
257 | })
258 | .then(function(bundle) {
259 | entryPointLoad = tree[entryPoint];
260 |
261 | var defaultExport = compileOpts.defaultExport;
262 | if (entryPointLoad.metadata.format == 'register')
263 | throw new Error('Assertion failed: internal format should be "system" not "register".');
264 |
265 | if (entryPointLoad.metadata.format != 'esm' && entryPointLoad.metadata.format != 'system')
266 | defaultExport = true;
267 |
268 | var generateOptions = {
269 | format: 'es',
270 | sourceMap: !!compileOpts.sourceMaps,
271 | exports: defaultExport ? 'default' : 'named',
272 | dest: 'output.js' // workaround for rollup/rollup#1015
273 | };
274 |
275 | // for a full tree rollup, we pass all the output options into rollup itself
276 | if (fullTreeRollup) {
277 | generateOptions.format = compileOpts.format;
278 | if (generateOptions.format == 'global')
279 | generateOptions.format = 'iife';
280 | if (generateOptions.format == 'esm')
281 | generateOptions.format = 'es';
282 |
283 | if ((generateOptions.format == 'iife' || generateOptions.format == 'umd') &&
284 | !compileOpts.globalName)
285 | throw new Error('The globalName option must be set for full-tree rollup global and UMD builds.');
286 |
287 | if (compileOpts.globalName)
288 | generateOptions.name = compileOpts.globalName;
289 |
290 | if (compileOpts.globalDeps)
291 | generateOptions.globals = compileOpts.globalDeps;
292 | }
293 |
294 | return bundle.generate(generateOptions);
295 | })
296 | .then(function(output) {
297 |
298 | // convert sources list into paths
299 | if (output.map) {
300 | output.map.sources = output.map.sources.map(function(name) {
301 | name = loader.getCanonicalName(loader.decanonicalize(name));
302 | return tree[name] && tree[name].path || loader.decanonicalize(name);
303 | });
304 | }
305 |
306 | if (fullTreeRollup)
307 | return {
308 | source: output.code,
309 | sourceMap: output.map
310 | };
311 |
312 | // replace the entry point module itself with the inlined subgraph module
313 | var curInlined = inlineMap[entryPoint] || [];
314 |
315 | // the process of running rollup will itself normalize all dependencies
316 | // the depMap then just becomes the identity map for non-externals
317 | var inlinedDepMap = {};
318 | aliasedExternals.forEach(function(dep, index) {
319 | inlinedDepMap[dep] = externals[index];
320 | });
321 |
322 | rolledUpTree[entryPoint] = extend(extend({}, entryPointLoad), {
323 | deps: aliasedExternals,
324 | depMap: inlinedDepMap,
325 | metadata: extend(extend({}, entryPointLoad.metadata), {
326 | originalSource: undefined,
327 | sourceMap: output.map
328 | }),
329 | source: output.code,
330 | compactedLoads: loadList
331 | });
332 | });
333 | }))
334 | .then(function(outputs) {
335 | if (fullTreeRollup) {
336 | // for the full tree rollup case, we need to run the plugin bundle hook as we skip compile entirely
337 | return pluginBundleHook(loader, Object.keys(tree).map(function(name) {
338 | return tree[name];
339 | }).filter(function(load) {
340 | return load;
341 | }), compileOpts, outputOpts)
342 | .then(function(pluginResult) {
343 | return {
344 | outputs: outputs.concat(pluginResult.outputs),
345 | assetList: pluginResult.assetList
346 | };
347 | });
348 | }
349 |
350 | return {
351 | tree: rolledUpTree,
352 | inlineMap: inlineMap
353 | };
354 | });
355 | };
356 |
--------------------------------------------------------------------------------
/lib/arithmetic.js:
--------------------------------------------------------------------------------
1 | var asp = require('bluebird').promisify;
2 | var Promise = require('bluebird');
3 | var glob = require('glob');
4 | var path = require('path');
5 | var url = require('url');
6 |
7 | var getLoadDependencies = require('./trace').getLoadDependencies;
8 |
9 | var fromFileURL = require('./utils').fromFileURL;
10 | var toFileURL = require('./utils').toFileURL;
11 |
12 | var verifyTree = require('./utils').verifyTree;
13 |
14 | function parseExpression(expressionString) {
15 | expressionString = ' + ' + expressionString;
16 |
17 | var index = 0;
18 | var operations = [];
19 | var operatorRegex = /[\+\-\&]/;
20 | var errorMessagesFromIndex = 3;
21 |
22 | function getNextIdentifier() {
23 | eatWhitespace();
24 | var firstChar = expressionString.charAt(index);
25 |
26 | if (operatorRegex.test(firstChar)){
27 | throw 'Syntax Error: Identifier or sub expression expected after <' + expressionString.slice(errorMessagesFromIndex).substr(0, index - errorMessagesFromIndex) + '> but found <' + firstChar + '> instead';
28 | }
29 |
30 | if (firstChar === '(') {
31 | var closingParenIndex = index,
32 | numOpenBeforeSelf = 0;
33 |
34 | while (++closingParenIndex < expressionString.length){
35 | if (expressionString.charAt(closingParenIndex) === '('){
36 | numOpenBeforeSelf++;
37 | } else if (expressionString.charAt(closingParenIndex) === ')') {
38 | if (numOpenBeforeSelf){
39 | numOpenBeforeSelf--;
40 | } else {
41 | break;
42 | }
43 | }
44 | }
45 | if (expressionString.charAt(closingParenIndex) !== ')'){
46 | throw 'Syntax Error: Expression <' + expressionString.substr(index) + '> is never terminated. Did you forget to add a closing ")"?';
47 | }
48 |
49 | var wholeExpression = expressionString.substring(index + 1, closingParenIndex);
50 | index = closingParenIndex + 1;
51 | return { bulkOperation: wholeExpression };
52 | }
53 |
54 | var result = "";
55 | //scan the identifier
56 | for (; index < expressionString.length; index++) {
57 | var currentChar = expressionString.charAt(index);
58 | //can have spaces in file names - so we need whitespace, operator, whitespace.
59 | if (/^\s+[\+\-\&]\s+/.test(expressionString.substr(index))) {
60 | return result;
61 | } else {
62 | result += currentChar;
63 | }
64 | }
65 | return result.replace(/\s+$/, ''); //it appears as though trailing whitespace is trimmed downstream, but I'm snipping here to be safe
66 | }
67 |
68 | function getNextOperator() {
69 | eatWhitespace();
70 | if (index === expressionString.length) return null;
71 |
72 | var candidateResult = expressionString.charAt(index++); //all operators are single characters at the moment
73 |
74 | if (!operatorRegex.test(candidateResult)){
75 | throw 'Syntax Error: An operator was expected after <' + expressionString.slice(errorMessagesFromIndex).substr(0, index - 1 - errorMessagesFromIndex) + '> but found <' + expressionString.substring(index - 1) + '> instead';
76 | }
77 |
78 | return candidateResult;
79 | }
80 |
81 | function eatWhitespace() {
82 | //wind past whitespace
83 | for (; index < expressionString.length; index++) {
84 | if (/\S/.test(expressionString.charAt(index))) {
85 | break;
86 | }
87 | }
88 | }
89 |
90 | var operator;
91 | while (index < expressionString.length && (operator = getNextOperator())) {
92 | var moduleNameOrSubExpression = getNextIdentifier();
93 |
94 | if (typeof moduleNameOrSubExpression === 'object'){
95 | operations.push({
96 | operator: operator,
97 | bulkOperation: moduleNameOrSubExpression.bulkOperation
98 | });
99 | } else {
100 | // detect [moduleName] syntax for individual modules not trees
101 | var singleModule = moduleNameOrSubExpression.substr(0, 1) == '[' && moduleNameOrSubExpression.substr(moduleNameOrSubExpression.length - 1, 1) == ']';
102 | if (singleModule) {
103 | moduleNameOrSubExpression = moduleNameOrSubExpression.substr(1, moduleNameOrSubExpression.length - 2);
104 | }
105 |
106 | var canonicalized = moduleNameOrSubExpression.substr(0, 1) == '`' && moduleNameOrSubExpression.substr(moduleNameOrSubExpression.length - 1, 1) == '`';
107 | if (canonicalized) {
108 | moduleNameOrSubExpression = moduleNameOrSubExpression.substr(1, moduleNameOrSubExpression.length - 2);
109 | }
110 |
111 | operations.push({
112 | operator: operator,
113 | moduleName: moduleNameOrSubExpression,
114 | singleModule: singleModule,
115 | canonicalized: canonicalized
116 | });
117 | }
118 | }
119 |
120 | return operations;
121 | }
122 |
123 | function getTreeOperation(symbol) {
124 | if (symbol == '+')
125 | return addTrees;
126 | else if (symbol == '-')
127 | return subtractTrees;
128 | else if (symbol == '&')
129 | return intersectTrees;
130 | else
131 | throw new TypeError('Unknown operator ' + symbol);
132 | }
133 |
134 | function getTreeModuleOperation(builder, symbol, traceOpts) {
135 | if (symbol == '+')
136 | return function(tree, canonical) {
137 | var addedTree = {};
138 | for (var p in tree)
139 | addedTree[p] = tree[p];
140 |
141 | return builder.tracer.getLoadRecord(canonical, traceOpts).then(function(load) {
142 | addedTree[canonical] = load;
143 | return addedTree;
144 | });
145 | };
146 | else if (symbol == '-')
147 | return function(tree, canonical) {
148 | var subtractedTree = {};
149 | for (var p in tree) {
150 | if (p != canonical)
151 | subtractedTree[p] = tree[p];
152 | }
153 | return subtractedTree;
154 | };
155 | else if (symbol == '&')
156 | throw new TypeError('Single modules cannot be intersected.');
157 | else
158 | throw new TypeError('Unknown operator ' + symbol);
159 | }
160 |
161 | function expandGlobAndCanonicalize(builder, operation) {
162 | var loader = builder.loader;
163 |
164 | // no glob -> just canonicalize
165 | if (operation.moduleName.indexOf('*') == -1) {
166 | if (operation.canonicalized)
167 | return [operation];
168 |
169 | return loader.normalize(operation.moduleName)
170 | .then(function(normalized) {
171 | operation.moduleName = builder.getCanonicalName(normalized);
172 | return [operation];
173 | });
174 | }
175 |
176 | // globbing
177 | var metadata = {};
178 | var globSuffix = operation.moduleName[operation.moduleName.length - 1] == '*';
179 | var pluginSyntax = operation.moduleName.indexOf('!') != -1;
180 |
181 | return Promise.resolve()
182 | .then(function() {
183 | if (operation.canonicalized) {
184 | return loader.decanonicalize(operation.moduleName);
185 | }
186 | else {
187 | // normalizeSync avoids package config loading which we don't want for wildcards
188 | return loader.normalizeSync(operation.moduleName);
189 | }
190 | })
191 | .then(function(normalized) {
192 | // remove ALL extension adding when globbing
193 | if (globSuffix && !operation.canonicalized) {
194 | var extIndex = normalized.lastIndexOf('.');
195 | if (extIndex != -1 && normalized[extIndex - 1] == '*')
196 | normalized = normalized.substr(0, extIndex);
197 | }
198 |
199 | return loader.locate({ name: normalized, metadata: metadata });
200 | })
201 | .then(function(address) {
202 | // now we have a file path to glob -> glob the pattern
203 | return asp(glob)(fromFileURL(address), {
204 | nobrace: true,
205 | noext: true,
206 | nodir: true
207 | });
208 | })
209 | .then(function(addresses) {
210 | return (metadata.loader && pluginSyntax ? loader.normalize(metadata.loader) : Promise.resolve())
211 | .then(function(loaderSyntaxName) {
212 | return addresses.map(function(file) {
213 | return {
214 | operator: operation.operator,
215 | moduleName: builder.getCanonicalName(toFileURL(file) + (loaderSyntaxName ? '!' + loader.getCanonicalName(loaderSyntaxName) : '')),
216 | singleModule: operation.singleModule
217 | };
218 | });
219 | });
220 | });
221 | }
222 |
223 | exports.traceExpression = function(builder, expression, traceOpts) {
224 | if (!expression)
225 | throw new Error('A module expression must be provided to trace.');
226 |
227 | if (expression instanceof Array) {
228 | var tree = {};
229 | return Promise.all(expression.map(function(moduleName) {
230 | return builder.loader.normalize(moduleName)
231 | .then(function(normalized) {
232 | var canonical = builder.getCanonicalName(normalized);
233 | return builder.tracer.getLoadRecord(canonical, traceOpts)
234 | .then(function(load) {
235 | tree[canonical] = load;
236 | });
237 | });
238 | }))
239 | .then(function() {
240 | return tree;
241 | });
242 | }
243 |
244 | return Promise
245 | .resolve(expandAndCanonicalizeExpression(builder, expression))
246 | .then(function processExpandedOperations(expandedOperations) {
247 | // chain the operations, applying them with the trace of the next module
248 | return expandedOperations.reduce(function(p, op) {
249 | return p.then(function(curTree) {
250 | // tree . module
251 | if (op.singleModule)
252 | return getTreeModuleOperation(builder, op.operator, traceOpts)(curTree, op.moduleName);
253 |
254 | if (op.operationsTree){
255 | return processExpandedOperations(op.operationsTree).then(function(expandedTree){
256 | return getTreeOperation(op.operator)(curTree, expandedTree);
257 | });
258 | }
259 | // tree . tree
260 | return builder.tracer.traceCanonical(op.moduleName, traceOpts)
261 | .then(function(nextTrace) {
262 | return getTreeOperation(op.operator)(curTree, nextTrace.tree);
263 | });
264 | });
265 | }, Promise.resolve({}));
266 | });
267 | };
268 |
269 | function expandAndCanonicalizeExpression(builder, expression) {
270 | var operations = parseExpression(expression);
271 | var expandPromise = Promise.resolve(1);
272 | var expandedOperations = [];
273 |
274 | operations.forEach(function(operation){
275 | if (operation.bulkOperation) {
276 | var expandedTreePromise = expandAndCanonicalizeExpression(builder, operation.bulkOperation);
277 | expandPromise = expandPromise.then(function() {
278 | return Promise.resolve(expandedTreePromise)
279 | .then(function(expressionsOperations){
280 | expandedOperations = expandedOperations.concat({ operator: operation.operator, operationsTree: expressionsOperations });
281 | });
282 | });
283 | } else {
284 | expandPromise = expandPromise.then(function() {
285 | return Promise.resolve(expandGlobAndCanonicalize(builder, operation))
286 | .then(function (expanded) {
287 | expandedOperations = expandedOperations.concat(expanded);
288 | });
289 | })
290 | }
291 | });
292 |
293 | return Promise.resolve(expandPromise).then(function(){ return expandedOperations; });
294 | }
295 |
296 | // returns a new tree containing tree1 n tree2
297 | exports.intersectTrees = intersectTrees;
298 | function intersectTrees(tree1, tree2) {
299 | verifyTree(tree1);
300 | verifyTree(tree2);
301 |
302 | var name;
303 | var intersectTree = {};
304 |
305 | var tree1Names = [];
306 | for (name in tree1)
307 | tree1Names.push(name);
308 |
309 | for (name in tree2) {
310 | if (tree1Names.indexOf(name) == -1)
311 | continue;
312 | // intersect deps layer (load: false) and actual bundle includes separately
313 | if (tree1[name] === false && tree2[name] === false)
314 | continue;
315 |
316 | intersectTree[name] = tree1[name] || tree2[name];
317 | }
318 |
319 | return intersectTree;
320 | }
321 |
322 | // returns a new tree containing tree1 + tree2
323 | exports.addTrees = addTrees;
324 | function addTrees(tree1, tree2) {
325 | verifyTree(tree1);
326 | verifyTree(tree2);
327 |
328 | var name;
329 | var unionTree = {};
330 |
331 | for (name in tree2)
332 | unionTree[name] = tree2[name];
333 |
334 | for (name in tree1)
335 | if (!(name in unionTree))
336 | unionTree[name] = tree1[name];
337 |
338 | return unionTree;
339 | }
340 |
341 | // returns a new tree containing tree1 - tree2
342 | exports.subtractTrees = subtractTrees;
343 | function subtractTrees(tree1, tree2) {
344 | verifyTree(tree1);
345 | verifyTree(tree2);
346 |
347 | var name;
348 | var subtractTree = {};
349 |
350 | for (name in tree1)
351 | subtractTree[name] = tree1[name];
352 |
353 | for (name in tree2) {
354 | if (tree2[name] !== false)
355 | delete subtractTree[name];
356 | }
357 |
358 | return subtractTree;
359 | }
360 |
361 | // pre-order tree traversal with a visitor and stop condition
362 | exports.traverseTree = traverseTree;
363 | function traverseTree(tree, moduleName, visitor, traceOpts, reversePost, parent, seen) {
364 | if (!seen) {
365 | // NB traceOpts.conditions should be strictly canonicalized on the first run
366 | traceOpts = traceOpts || {};
367 | verifyTree(tree);
368 | }
369 |
370 | seen = seen || [];
371 | seen.push(moduleName);
372 | parent = parent || null;
373 |
374 | var curNode = tree[moduleName];
375 |
376 | if (curNode && visitor(moduleName, parent) !== false) {
377 | var deps = getLoadDependencies(curNode, traceOpts, traceOpts.conditions, traceOpts.inlineConditions);
378 | if (reversePost)
379 | deps = deps.reverse();
380 | deps.forEach(function(dep) {
381 | if (seen.indexOf(dep) == -1)
382 | traverseTree(tree, dep, visitor, traceOpts, reversePost, moduleName, seen);
383 | });
384 | }
385 | }
--------------------------------------------------------------------------------