UNPKG

5.41 kBJavaScriptView Raw
1// This is all from https://github.com/jaredhanson/deamdify
2/**
3 * Module dependencies.
4 */
5var estraverse = require('estraverse');
6var optionsNormalize = require('./options_normalize');
7var getAst = require("./get_ast");
8
9/**
10 * Transform AMD to CommonJS.
11 *
12 * This transform translates AMD modules into CommonJS modules. AMD modules
13 * are defined by calling the `define` function that is available as a free
14 * or global variable. The transform translates that call into traditional
15 * CommonJS require statements. Any value returned from the factory function
16 * is assigned to `module.exports`.
17 *
18 * After the transform is complete, Browserify will be able to parse and
19 * bundle the module as if it were a Node.js module.
20 *
21 * @param {String} file
22 * @return {Stream}
23 * @api public
24 */
25module.exports = function (load, options) {
26
27 var ast = getAst(load);
28 var tast;
29 var isAMD = false;
30
31 //console.log('-- ORIGINAL AST --');
32 //console.log(util.inspect(ast, false, null));
33 //console.log('------------------');
34
35 // TODO: Ensure that define is a free variable.
36 // TODO: Implement support for amdWeb UMD modules.
37 estraverse.replace(ast, {
38 enter: function(node) {
39 if (isDefine(node)) {
40 var parents = this.parents();
41
42 // Check that this module is an AMD module, as evidenced by invoking
43 // `define` at the top-level. Any CommonJS or UMD modules are pass
44 // through unmodified.
45 if (parents.length == 2 && parents[0].type == 'Program' && parents[1].type == 'ExpressionStatement') {
46 isAMD = true;
47 }
48 }
49 },
50
51 leave: function(node) {
52 if (isDefine(node)) {
53 var ids;
54 var vars;
55 var reqs;
56 var factory;
57 var dependencies;
58
59 if (node.arguments.length == 1 && node.arguments[0].type == 'FunctionExpression') {
60 factory = node.arguments[0];
61
62 if (factory.params.length == 0) {
63 tast = createProgram(factory.body.body);
64 this.break();
65 } else if (factory.params.length > 0) {
66 // simplified CommonJS wrapper
67 tast = createProgram(factory.body.body);
68 this.break();
69 }
70 } else if (node.arguments.length == 1 && node.arguments[0].type == 'ObjectExpression') {
71 // object literal
72 var obj = node.arguments[0];
73
74 tast = createModuleExport(obj);
75 this.break();
76 } else if (node.arguments.length == 2 && node.arguments[0].type == 'ArrayExpression' && node.arguments[1].type == 'FunctionExpression') {
77 dependencies = node.arguments[0];
78 factory = node.arguments[1];
79
80 ids = dependencies.elements.map(function(el) { return el.value });
81 vars = factory.params.map(function(el) { return el.name });
82 reqs = createRequires(ids, vars, load, options);
83 if (reqs) {
84 tast = createProgram(reqs.concat(factory.body.body));
85 } else {
86 tast = createProgram(factory.body.body);
87 }
88 this.break();
89 } else if (node.arguments.length == 3 && node.arguments[0].type == 'Literal' && node.arguments[1].type == 'ArrayExpression' && node.arguments[2].type == 'FunctionExpression') {
90 dependencies = node.arguments[1]
91 factory = node.arguments[2];
92
93 ids = dependencies.elements.map(function(el) { return el.value });
94 vars = factory.params.map(function(el) { return el.name });
95 reqs = createRequires(ids, vars, load, options);
96 if (reqs) {
97 tast = createProgram(reqs.concat(factory.body.body));
98 } else {
99 tast = createProgram(factory.body.body);
100 }
101 this.break();
102 }
103 } else if (isReturn(node)) {
104 var parents = this.parents();
105
106 if (parents.length == 5 && isDefine(parents[2]) && isAMD) {
107 return createModuleExport(node.argument);
108 }
109 }
110 }
111 });
112
113 tast = tast || ast;
114
115 return tast;
116};
117
118function isDefine(node) {
119 var callee = node.callee;
120 return callee &&
121 node.type == 'CallExpression' &&
122 callee.type == 'Identifier' &&
123 callee.name == 'define';
124}
125
126function isReturn(node) {
127 return node.type == 'ReturnStatement';
128}
129
130function createProgram(body) {
131 return {
132 type: 'Program',
133 body: body
134 };
135}
136
137function createRequires(ids, vars, load, options) {
138 var decls = [];
139
140 for (var i = 0, len = ids.length; i < len; ++i) {
141 if (['require', 'module', 'exports'].indexOf(ids[i]) != -1) { continue; }
142
143 if(vars[i]) {
144 decls.push({
145 type: 'VariableDeclaration',
146 declarations: [{
147 type: 'VariableDeclarator',
148 id: { type: 'Identifier', name: vars[i] },
149 init: {
150 type: 'CallExpression',
151 callee: { type: 'Identifier', name: 'require' },
152 arguments: [ { type: 'Literal', value: optionsNormalize(options, ids[i], load.name, load.address) } ]
153 }
154 }],
155 kind: 'var'
156 });
157 } else {
158 decls.push({
159 "type": "ExpressionStatement",
160 "expression": {
161 "type": "CallExpression",
162 "callee": {
163 "type": "Identifier",
164 "name": "require"
165 },
166 "arguments": [
167 {
168 "type": "Literal",
169 "value": optionsNormalize(options, ids[i], load.name, load.address)
170 }
171 ]
172 }
173 });
174 }
175 }
176
177 if (decls.length == 0) { return null; }
178
179 return decls;
180}
181
182function createModuleExport(obj) {
183 return {
184 type: 'ExpressionStatement',
185 expression: {
186 type: 'AssignmentExpression',
187 operator: '=',
188 left: {
189 type: 'MemberExpression',
190 computed: false,
191 object: { type: 'Identifier', name: 'module' },
192 property: { type: 'Identifier', name: 'exports' }
193 },
194 right: obj
195 }
196 };
197}