1 | import { __awaiter, __generator, __values } from "tslib";
|
2 | import { readdir, readFile, stat, writeFile } from 'mz/fs';
|
3 | import { basename, dirname, extname, join } from 'path';
|
4 | import { convert, modernizeJS } from './index';
|
5 | import PatchError from './utils/PatchError';
|
6 |
|
7 | var pkg = require('../package');
|
8 |
|
9 |
|
10 |
|
11 | export default function run(args) {
|
12 | return __awaiter(this, void 0, void 0, function () {
|
13 | var options;
|
14 | return __generator(this, function (_a) {
|
15 | switch (_a.label) {
|
16 | case 0:
|
17 | options = parseArguments(args);
|
18 | if (!options.paths.length) return [3 , 2];
|
19 | return [4 , runWithPaths(options.paths, options)];
|
20 | case 1:
|
21 | _a.sent();
|
22 | return [3 , 4];
|
23 | case 2: return [4 , runWithStdio(options)];
|
24 | case 3:
|
25 | _a.sent();
|
26 | _a.label = 4;
|
27 | case 4: return [2 ];
|
28 | }
|
29 | });
|
30 | });
|
31 | }
|
32 | function parseArguments(args) {
|
33 | var paths = [];
|
34 | var baseOptions = {};
|
35 | var modernizeJS = false;
|
36 | for (var i = 0; i < args.length; i++) {
|
37 | var arg = args[i];
|
38 | switch (arg) {
|
39 | case '-h':
|
40 | case '--help':
|
41 | usage();
|
42 | process.exit(0);
|
43 | break;
|
44 | case '-v':
|
45 | case '--version':
|
46 | version();
|
47 | process.exit(0);
|
48 | break;
|
49 | case '--use-cs2':
|
50 | baseOptions.useCS2 = true;
|
51 | break;
|
52 | case '--modernize-js':
|
53 | modernizeJS = true;
|
54 | break;
|
55 | case '--literate':
|
56 | baseOptions.literate = true;
|
57 | break;
|
58 | case '--disable-suggestion-comment':
|
59 | baseOptions.disableSuggestionComment = true;
|
60 | break;
|
61 | case '--no-array-includes':
|
62 | baseOptions.noArrayIncludes = true;
|
63 | break;
|
64 | case '--use-optional-chaining':
|
65 | console.warn("NOTE: " + arg + " is disabled and has no effect");
|
66 | break;
|
67 | case '--use-js-modules':
|
68 | baseOptions.useJSModules = true;
|
69 | break;
|
70 | case '--loose-js-modules':
|
71 | baseOptions.looseJSModules = true;
|
72 | break;
|
73 | case '--safe-import-function-identifiers':
|
74 | i++;
|
75 | baseOptions.safeImportFunctionIdentifiers = args[i].split(',');
|
76 | break;
|
77 | case '--prefer-let':
|
78 | baseOptions.preferLet = true;
|
79 | break;
|
80 | case '--disable-babel-constructor-workaround':
|
81 | baseOptions.disableBabelConstructorWorkaround = true;
|
82 | break;
|
83 | case '--disallow-invalid-constructors':
|
84 | baseOptions.disallowInvalidConstructors = true;
|
85 | break;
|
86 | case '--loose':
|
87 | baseOptions.loose = true;
|
88 | break;
|
89 | case '--loose-default-params':
|
90 | baseOptions.looseDefaultParams = true;
|
91 | break;
|
92 | case '--loose-for-expressions':
|
93 | baseOptions.looseForExpressions = true;
|
94 | break;
|
95 | case '--loose-for-of':
|
96 | baseOptions.looseForOf = true;
|
97 | break;
|
98 | case '--loose-includes':
|
99 | baseOptions.looseIncludes = true;
|
100 | break;
|
101 | case '--loose-comparison-negation':
|
102 | baseOptions.looseComparisonNegation = true;
|
103 | break;
|
104 |
|
105 | case '--prefer-const':
|
106 | case '--keep-commonjs':
|
107 | case '--enable-babel-constructor-workaround':
|
108 | break;
|
109 |
|
110 | case '--force-default-export':
|
111 | baseOptions.useJSModules = true;
|
112 | break;
|
113 | case '--allow-invalid-constructors':
|
114 | baseOptions.disableBabelConstructorWorkaround = true;
|
115 | break;
|
116 | default:
|
117 | if (arg.startsWith('-')) {
|
118 | console.error("Error: unrecognized option '" + arg + "'");
|
119 | process.exit(1);
|
120 | }
|
121 | paths.push(arg);
|
122 | break;
|
123 | }
|
124 | }
|
125 | return { paths: paths, baseOptions: baseOptions, modernizeJS: modernizeJS };
|
126 | }
|
127 |
|
128 |
|
129 |
|
130 | function runWithPaths(paths, options) {
|
131 | return __awaiter(this, void 0, void 0, function () {
|
132 | function processPath(path) {
|
133 | return __awaiter(this, void 0, void 0, function () {
|
134 | var info;
|
135 | return __generator(this, function (_a) {
|
136 | switch (_a.label) {
|
137 | case 0: return [4 , stat(path)];
|
138 | case 1:
|
139 | info = _a.sent();
|
140 | if (!info.isDirectory()) return [3 , 3];
|
141 | return [4 , processDirectory(path)];
|
142 | case 2:
|
143 | _a.sent();
|
144 | return [3 , 5];
|
145 | case 3: return [4 , processFile(path)];
|
146 | case 4:
|
147 | _a.sent();
|
148 | _a.label = 5;
|
149 | case 5: return [2 ];
|
150 | }
|
151 | });
|
152 | });
|
153 | }
|
154 | function processDirectory(path) {
|
155 | return __awaiter(this, void 0, void 0, function () {
|
156 | var children, children_1, children_1_1, child, childPath, childStat, e_2_1;
|
157 | var e_2, _a;
|
158 | return __generator(this, function (_b) {
|
159 | switch (_b.label) {
|
160 | case 0: return [4 , readdir(path)];
|
161 | case 1:
|
162 | children = _b.sent();
|
163 | _b.label = 2;
|
164 | case 2:
|
165 | _b.trys.push([2, 13, 14, 15]);
|
166 | children_1 = __values(children), children_1_1 = children_1.next();
|
167 | _b.label = 3;
|
168 | case 3:
|
169 | if (!!children_1_1.done) return [3 , 12];
|
170 | child = children_1_1.value;
|
171 | childPath = join(path, child);
|
172 | return [4 , stat(childPath)];
|
173 | case 4:
|
174 | childStat = _b.sent();
|
175 | if (!childStat.isDirectory()) return [3 , 6];
|
176 | return [4 , processDirectory(childPath)];
|
177 | case 5:
|
178 | _b.sent();
|
179 | return [3 , 11];
|
180 | case 6:
|
181 | if (!options.modernizeJS) return [3 , 9];
|
182 | if (!child.endsWith('.js')) return [3 , 8];
|
183 | return [4 , processPath(childPath)];
|
184 | case 7:
|
185 | _b.sent();
|
186 | _b.label = 8;
|
187 | case 8: return [3 , 11];
|
188 | case 9:
|
189 | if (!(child.endsWith('.coffee') || child.endsWith('.litcoffee') || child.endsWith('.coffee.md'))) return [3 , 11];
|
190 | return [4 , processPath(childPath)];
|
191 | case 10:
|
192 | _b.sent();
|
193 | _b.label = 11;
|
194 | case 11:
|
195 | children_1_1 = children_1.next();
|
196 | return [3 , 3];
|
197 | case 12: return [3 , 15];
|
198 | case 13:
|
199 | e_2_1 = _b.sent();
|
200 | e_2 = { error: e_2_1 };
|
201 | return [3 , 15];
|
202 | case 14:
|
203 | try {
|
204 | if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
|
205 | }
|
206 | finally { if (e_2) throw e_2.error; }
|
207 | return [7 ];
|
208 | case 15: return [2 ];
|
209 | }
|
210 | });
|
211 | });
|
212 | }
|
213 | function processFile(path) {
|
214 | return __awaiter(this, void 0, void 0, function () {
|
215 | var extension, outputPath, data, resultCode;
|
216 | return __generator(this, function (_a) {
|
217 | switch (_a.label) {
|
218 | case 0:
|
219 | extension = path.endsWith('.coffee.md') ? '.coffee.md' : extname(path);
|
220 | outputPath = join(dirname(path), basename(path, extension)) + '.js';
|
221 | console.log(path + " \u2192 " + outputPath);
|
222 | return [4 , readFile(path, 'utf8')];
|
223 | case 1:
|
224 | data = _a.sent();
|
225 | resultCode = runWithCode(path, data, options);
|
226 | return [4 , writeFile(outputPath, resultCode)];
|
227 | case 2:
|
228 | _a.sent();
|
229 | return [2 ];
|
230 | }
|
231 | });
|
232 | });
|
233 | }
|
234 | var paths_1, paths_1_1, path, e_1_1;
|
235 | var e_1, _a;
|
236 | return __generator(this, function (_b) {
|
237 | switch (_b.label) {
|
238 | case 0:
|
239 | _b.trys.push([0, 5, 6, 7]);
|
240 | paths_1 = __values(paths), paths_1_1 = paths_1.next();
|
241 | _b.label = 1;
|
242 | case 1:
|
243 | if (!!paths_1_1.done) return [3 , 4];
|
244 | path = paths_1_1.value;
|
245 | return [4 , processPath(path)];
|
246 | case 2:
|
247 | _b.sent();
|
248 | _b.label = 3;
|
249 | case 3:
|
250 | paths_1_1 = paths_1.next();
|
251 | return [3 , 1];
|
252 | case 4: return [3 , 7];
|
253 | case 5:
|
254 | e_1_1 = _b.sent();
|
255 | e_1 = { error: e_1_1 };
|
256 | return [3 , 7];
|
257 | case 6:
|
258 | try {
|
259 | if (paths_1_1 && !paths_1_1.done && (_a = paths_1.return)) _a.call(paths_1);
|
260 | }
|
261 | finally { if (e_1) throw e_1.error; }
|
262 | return [7 ];
|
263 | case 7: return [2 ];
|
264 | }
|
265 | });
|
266 | });
|
267 | }
|
268 | function runWithStdio(options) {
|
269 | return __awaiter(this, void 0, void 0, function () {
|
270 | return __generator(this, function (_a) {
|
271 | return [2 , new Promise(function (resolve) {
|
272 | var data = '';
|
273 | process.stdin.on('data', function (chunk) { return (data += chunk); });
|
274 | process.stdin.on('end', function () {
|
275 | var resultCode = runWithCode('stdin', data, options);
|
276 | process.stdout.write(resultCode);
|
277 | resolve();
|
278 | });
|
279 | })];
|
280 | });
|
281 | });
|
282 | }
|
283 |
|
284 |
|
285 |
|
286 | function runWithCode(name, code, options) {
|
287 | var baseOptions = Object.assign({ filename: name }, options.baseOptions);
|
288 | try {
|
289 | if (options.modernizeJS) {
|
290 | return modernizeJS(code, baseOptions).code;
|
291 | }
|
292 | else {
|
293 | return convert(code, baseOptions).code;
|
294 | }
|
295 | }
|
296 | catch (err) {
|
297 | if (PatchError.detect(err)) {
|
298 | console.error(name + ": " + PatchError.prettyPrint(err));
|
299 | process.exit(1);
|
300 | }
|
301 | throw err;
|
302 | }
|
303 | }
|
304 |
|
305 |
|
306 |
|
307 | function version() {
|
308 | console.log('%s v%s', pkg.name, pkg.version);
|
309 | }
|
310 |
|
311 |
|
312 |
|
313 | function usage() {
|
314 | var exe = basename(process.argv[1]);
|
315 | console.log('%s [OPTIONS] PATH [PATH …]', exe);
|
316 | console.log('%s [OPTIONS] < INPUT', exe);
|
317 | console.log();
|
318 | console.log('Move your CoffeeScript source to JavaScript using modern syntax.');
|
319 | console.log();
|
320 | console.log('OPTIONS');
|
321 | console.log();
|
322 | console.log(' -h, --help Display this help message.');
|
323 | console.log(' --use-cs2 Treat the input as CoffeeScript 2 code. CoffeeScript 2 has');
|
324 | console.log(' some small breaking changes and differences in behavior');
|
325 | console.log(' compared with CS1, so decaffeinate assumes CS1 by default');
|
326 | console.log(' and allows CS2 via this flag.');
|
327 | console.log(' --modernize-js Treat the input as JavaScript and only run the');
|
328 | console.log(' JavaScript-to-JavaScript transforms, modifying the file(s)');
|
329 | console.log(' in-place.');
|
330 | console.log(' --literate Treat the input file as Literate CoffeeScript.');
|
331 | console.log(' --disable-suggestion-comment');
|
332 | console.log(' Do not include a comment with followup suggestions at the');
|
333 | console.log(' top of the output file.');
|
334 | console.log(' --no-array-includes Do not use Array.prototype.includes in generated code.');
|
335 | console.log(' --use-optional-chaining Use the upcoming optional chaining syntax for operators like `?.`.');
|
336 | console.log(' NOTE: this is disabled and has no effect.');
|
337 | console.log(' --use-js-modules Convert require and module.exports to import and export.');
|
338 | console.log(' --loose-js-modules Allow named exports when converting to JS modules.');
|
339 | console.log(' --safe-import-function-identifiers');
|
340 | console.log(' Comma-separated list of function names that may safely be in the ');
|
341 | console.log(' import/require section of the file. All other function calls ');
|
342 | console.log(' will disqualify later requires from being converted to imports.');
|
343 | console.log(' --prefer-let Use let instead of const for most variables in output code.');
|
344 | console.log(' --loose Enable all --loose... options.');
|
345 | console.log(' --loose-default-params Convert CS default params to JS default params.');
|
346 | console.log(' --loose-for-expressions Do not wrap expression loop targets in Array.from.');
|
347 | console.log(' --loose-for-of Do not wrap JS for...of loop targets in Array.from.');
|
348 | console.log(' --loose-includes Do not wrap in Array.from when converting in to includes.');
|
349 | console.log(' --loose-comparison-negation');
|
350 | console.log(' Allow unsafe simplifications like `!(a > b)` to `a <= b`.');
|
351 | console.log(' --disable-babel-constructor-workaround');
|
352 | console.log(' Never include the Babel/TypeScript workaround code to allow');
|
353 | console.log(' this before super in constructors.');
|
354 | console.log(' --disallow-invalid-constructors');
|
355 | console.log(' Give an error when constructors use this before super or');
|
356 | console.log(' omit the super call in a subclass.');
|
357 | console.log();
|
358 | console.log('EXAMPLES');
|
359 | console.log();
|
360 | console.log(' # Convert a .coffee file to a .js file.');
|
361 | console.log(' $ decaffeinate index.coffee');
|
362 | console.log();
|
363 | console.log(' # Pipe an example from the command-line.');
|
364 | console.log(' $ echo "a = 1" | decaffeinate');
|
365 | console.log();
|
366 | console.log(' # On macOS this may come in handy:');
|
367 | console.log(' $ pbpaste | decaffeinate | pbcopy');
|
368 | console.log();
|
369 | console.log(' # Process everything in a directory.');
|
370 | console.log(' $ decaffeinate src/');
|
371 | console.log();
|
372 | console.log(' # Redirect input from a file.');
|
373 | console.log(' $ decaffeinate < index.coffee');
|
374 | }
|