UNPKG

2.49 kBJavaScriptView Raw
1var types = require("ast-types");
2var first = require("lodash/first");
3var last = require("lodash/last");
4var concat = require("lodash/concat");
5var estemplate = require("estemplate");
6
7var n = types.namedTypes;
8
9module.exports = function(ast) {
10 var variableNames = collectVariableNames(ast);
11
12 appendToDefineFactory(
13 ast,
14 concat(variableNames.map(patchHelperCallTemplate), patchHelperTemplate())
15 );
16
17 return ast;
18};
19
20/**
21 * Collects the identifiers of Babel generated import assignments
22 *
23 * E.g, given the AST of the code below:
24 *
25 * var _bar2 = _interopRequireDefault('bar');
26 * var _foo2 = _interopRequireDefault('foo');
27 *
28 * this function will return an array with the AST nodes of the _bar2 and
29 * _foo2 identifiers.
30 *
31 * @param {Object} ast - The code's AST
32 * @return {Array.<Object>} A list of identifiers (AST nodes)
33 */
34function collectVariableNames(ast) {
35 var names = [];
36
37 types.visit(ast, {
38 visitVariableDeclarator: function(path) {
39 var node = path.node;
40
41 if (this.isBabelRequireInteropCall(node.init)) {
42 names.push(node.id);
43 }
44
45 this.traverse(path);
46 },
47
48 isBabelRequireInteropCall: function(node) {
49 return (
50 n.CallExpression.check(node) &&
51 node.callee.name === "_interopRequireDefault"
52 );
53 }
54 });
55
56 return names;
57}
58
59/**
60 * Appends the given node to the `define` factory function body
61 *
62 * MUTATES THE AST
63 *
64 * @param {Object} ast - The AMD module AST
65 * @param {Array.<Object>} nodes - The AST nodes to be appended
66 */
67function appendToDefineFactory(ast, nodes) {
68 types.visit(ast, {
69 visitCallExpression: function(path) {
70 var node = path.node;
71
72 if (this.isDefineIdentifier(node.callee)) {
73 var factory = last(node.arguments);
74 factory.body.body = concat(factory.body.body, nodes);
75 this.abort();
76 }
77
78 this.traverse(path);
79 },
80
81 isDefineIdentifier: function(node) {
82 return n.Identifier.check(node) && node.name === "define";
83 }
84 });
85}
86
87function patchHelperCallTemplate(identifier) {
88 return first(
89 estemplate.compile("_patchCircularDependency(%= name %)")({
90 name: identifier
91 }).body
92 );
93}
94
95function patchHelperTemplate() {
96 return first(
97 estemplate.compile(`
98 function _patchCircularDependency(obj) {
99 var defaultExport;
100 Object.defineProperty(obj.default, "default", {
101 set: function(value) {
102 if (obj.default.__esModule) {
103 obj.default = value;
104 }
105 defaultExport = value;
106 },
107 get: function() {
108 return defaultExport;
109 }
110 });
111 }
112 `)({}).body
113 );
114}