UNPKG

16.8 kBJavaScriptView Raw
1import { __awaiter, __generator, __values } from "tslib";
2import { readdir, readFile, stat, writeFile } from 'mz/fs';
3import { basename, dirname, extname, join } from 'path';
4import { convert, modernizeJS } from './index';
5import PatchError from './utils/PatchError';
6// eslint-disable-next-line @typescript-eslint/no-var-requires
7var pkg = require('../package');
8/**
9 * Run the script with the user-supplied arguments.
10 */
11export 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 /*break*/, 2];
19 return [4 /*yield*/, runWithPaths(options.paths, options)];
20 case 1:
21 _a.sent();
22 return [3 /*break*/, 4];
23 case 2: return [4 /*yield*/, runWithStdio(options)];
24 case 3:
25 _a.sent();
26 _a.label = 4;
27 case 4: return [2 /*return*/];
28 }
29 });
30 });
31}
32function 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 // Legacy options that are now a no-op.
105 case '--prefer-const':
106 case '--keep-commonjs':
107 case '--enable-babel-constructor-workaround':
108 break;
109 // Legacy options that are now aliases for other options.
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 * Run decaffeinate on the given paths, changing them in place.
129 */
130function 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 /*yield*/, stat(path)];
138 case 1:
139 info = _a.sent();
140 if (!info.isDirectory()) return [3 /*break*/, 3];
141 return [4 /*yield*/, processDirectory(path)];
142 case 2:
143 _a.sent();
144 return [3 /*break*/, 5];
145 case 3: return [4 /*yield*/, processFile(path)];
146 case 4:
147 _a.sent();
148 _a.label = 5;
149 case 5: return [2 /*return*/];
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 /*yield*/, 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 /*break*/, 12];
170 child = children_1_1.value;
171 childPath = join(path, child);
172 return [4 /*yield*/, stat(childPath)];
173 case 4:
174 childStat = _b.sent();
175 if (!childStat.isDirectory()) return [3 /*break*/, 6];
176 return [4 /*yield*/, processDirectory(childPath)];
177 case 5:
178 _b.sent();
179 return [3 /*break*/, 11];
180 case 6:
181 if (!options.modernizeJS) return [3 /*break*/, 9];
182 if (!child.endsWith('.js')) return [3 /*break*/, 8];
183 return [4 /*yield*/, processPath(childPath)];
184 case 7:
185 _b.sent();
186 _b.label = 8;
187 case 8: return [3 /*break*/, 11];
188 case 9:
189 if (!(child.endsWith('.coffee') || child.endsWith('.litcoffee') || child.endsWith('.coffee.md'))) return [3 /*break*/, 11];
190 return [4 /*yield*/, 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 /*break*/, 3];
197 case 12: return [3 /*break*/, 15];
198 case 13:
199 e_2_1 = _b.sent();
200 e_2 = { error: e_2_1 };
201 return [3 /*break*/, 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 /*endfinally*/];
208 case 15: return [2 /*return*/];
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 /*yield*/, readFile(path, 'utf8')];
223 case 1:
224 data = _a.sent();
225 resultCode = runWithCode(path, data, options);
226 return [4 /*yield*/, writeFile(outputPath, resultCode)];
227 case 2:
228 _a.sent();
229 return [2 /*return*/];
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 /*break*/, 4];
244 path = paths_1_1.value;
245 return [4 /*yield*/, 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 /*break*/, 1];
252 case 4: return [3 /*break*/, 7];
253 case 5:
254 e_1_1 = _b.sent();
255 e_1 = { error: e_1_1 };
256 return [3 /*break*/, 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 /*endfinally*/];
263 case 7: return [2 /*return*/];
264 }
265 });
266 });
267}
268function runWithStdio(options) {
269 return __awaiter(this, void 0, void 0, function () {
270 return __generator(this, function (_a) {
271 return [2 /*return*/, 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 * Run decaffeinate on the given code string and return the resulting code.
285 */
286function 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 * Print version
306 */
307function version() {
308 console.log('%s v%s', pkg.name, pkg.version);
309}
310/**
311 * Print usage help.
312 */
313function 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}