UNPKG

5.01 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
6
7const t = require('@babel/types');
8
9const Path = require('path');
10
11const fs = require('fs');
12
13const template = require('@babel/template').default;
14
15const logger = require('@parcel/logger');
16
17const bufferTemplate = template('Buffer(CONTENT, ENC)');
18module.exports = {
19 AssignmentExpression(path) {
20 if (!isRequire(path.node.right, 'fs', 'readFileSync')) {
21 return;
22 }
23
24 for (let name in path.getBindingIdentifiers()) {
25 const binding = path.scope.getBinding(name);
26 if (!binding) continue;
27 binding.path.setData('__require', path.node);
28 }
29 },
30
31 CallExpression(path, asset) {
32 if (referencesImport(path, 'fs', 'readFileSync')) {
33 let vars = {
34 __dirname: Path.dirname(asset.name),
35 __filename: asset.basename
36 };
37 let filename, args, res;
38
39 try {
40 var _path$get$map = path.get('arguments').map(arg => evaluate(arg, vars));
41
42 var _path$get$map2 = (0, _toArray2.default)(_path$get$map);
43
44 filename = _path$get$map2[0];
45 args = _path$get$map2.slice(1);
46 filename = Path.resolve(filename);
47 res = fs.readFileSync(filename, ...args);
48 } catch (err) {
49 if (err instanceof NodeNotEvaluatedError) {
50 // Warn using a code frame
51 err.fileName = asset.name;
52 asset.generateErrorMessage(err);
53 logger.warn(err);
54 return;
55 } // Add location info so we log a code frame with the error
56
57
58 err.loc = path.node.arguments.length > 0 ? path.node.arguments[0].loc.start : path.node.loc.start;
59 throw err;
60 }
61
62 let replacementNode;
63
64 if (Buffer.isBuffer(res)) {
65 replacementNode = bufferTemplate({
66 CONTENT: t.stringLiteral(res.toString('base64')),
67 ENC: t.stringLiteral('base64')
68 });
69 } else {
70 replacementNode = t.stringLiteral(res);
71 }
72
73 asset.addDependency(filename, {
74 includedInParent: true
75 });
76 path.replaceWith(replacementNode);
77 asset.isAstDirty = true;
78 }
79 }
80
81};
82
83function isRequire(node, name, method) {
84 // e.g. require('fs').readFileSync
85 if (t.isMemberExpression(node) && node.property.name === method) {
86 node = node.object;
87 }
88
89 if (!t.isCallExpression(node)) {
90 return false;
91 }
92
93 let _node = node,
94 callee = _node.callee,
95 args = _node.arguments;
96 let isRequire = t.isIdentifier(callee) && callee.name === 'require' && args.length === 1 && t.isStringLiteral(args[0]);
97
98 if (!isRequire) {
99 return false;
100 }
101
102 if (name && args[0].value !== name) {
103 return false;
104 }
105
106 return true;
107}
108
109function referencesImport(path, name, method) {
110 let callee = path.node.callee;
111 let bindingPath; // e.g. readFileSync()
112
113 if (t.isIdentifier(callee)) {
114 bindingPath = getBindingPath(path, callee.name);
115 } else if (t.isMemberExpression(callee)) {
116 if (callee.property.name !== method) {
117 return false;
118 } // e.g. fs.readFileSync()
119
120
121 if (t.isIdentifier(callee.object)) {
122 bindingPath = getBindingPath(path, callee.object.name); // require('fs').readFileSync()
123 } else if (isRequire(callee.object, name)) {
124 return true;
125 }
126 } else {
127 return false;
128 }
129
130 if (!bindingPath) {
131 return;
132 }
133
134 let bindingNode = bindingPath.getData('__require') || bindingPath.node;
135 let parent = bindingPath.parentPath; // e.g. import fs from 'fs';
136
137 if (parent.isImportDeclaration()) {
138 if (bindingPath.isImportSpecifier() && bindingPath.node.imported.name !== method) {
139 return false;
140 }
141
142 return parent.node.source.value === name; // e.g. var fs = require('fs');
143 } else if (t.isVariableDeclarator(bindingNode) || t.isAssignmentExpression(bindingNode)) {
144 let left = bindingNode.id || bindingNode.left;
145 let right = bindingNode.init || bindingNode.right; // e.g. var {readFileSync} = require('fs');
146
147 if (t.isObjectPattern(left)) {
148 let prop = left.properties.find(p => p.value.name === callee.name);
149
150 if (!prop || prop.key.name !== method) {
151 return false;
152 }
153 } else if (!t.isIdentifier(left)) {
154 return false;
155 }
156
157 return isRequire(right, name, method);
158 }
159
160 return false;
161}
162
163function getBindingPath(path, name) {
164 let binding = path.scope.getBinding(name);
165 return binding && binding.path;
166}
167
168function NodeNotEvaluatedError(node) {
169 this.message = 'Cannot statically evaluate fs argument';
170 this.node = node;
171 this.loc = node.loc.start;
172}
173
174function evaluate(path, vars) {
175 // Inline variables
176 path.traverse({
177 Identifier: function Identifier(ident) {
178 let key = ident.node.name;
179
180 if (key in vars) {
181 ident.replaceWith(t.valueToNode(vars[key]));
182 }
183 }
184 });
185 let res = path.evaluate();
186
187 if (!res.confident) {
188 throw new NodeNotEvaluatedError(path.node);
189 }
190
191 return res.value;
192}
\No newline at end of file