• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16// singleton to parse commandLine infos
17import commandLineArgs from "command-line-args";
18import commandLineUsage from "command-line-usage";
19import * as ts from "typescript";
20import { LOGE } from "./log";
21import * as path from "path";
22import { execute } from "./base/util";
23
24const ts2pandaOptions = [
25    { name: 'modules', alias: 'm', type: Boolean, defaultValue: false, description: "compile as module." },
26    { name: 'debug-log', alias: 'l', type: Boolean, defaultValue: false, description: "show info debug log and generate the json file."},
27    { name: 'dump-assembly', alias: 'a', type: Boolean, defaultValue: false, description: "dump assembly to file." },
28    { name: 'debug', alias: 'd', type: Boolean, defaultValue: false, description: "compile with debug info." },
29    { name: 'debug-add-watch', alias: 'w', type: String, lazyMultiple: true, defaultValue: [], description: "watch expression, abc file path and maybe watchTimeOut(in seconds) in debug mode." },
30    { name: 'keep-persistent-watch', alias: 'k', type: String, lazyMultiple: true, defaultValue: [], description: "keep persistent watch on js file with watched expression." },
31    { name: 'show-statistics', alias: 's', type: String, lazyMultiple: true, defaultValue: "", description: "show compile statistics(ast, histogram, hoisting, all)." },
32    { name: 'output', alias: 'o', type: String, defaultValue: "", description: "set output file." },
33    { name: 'timeout', alias: 't', type: Number, defaultValue: 0, description: "js to abc timeout threshold(unit: seconds)." },
34    { name: 'opt-log-level', type: String, defaultValue: "error", description: "specifie optimizer log level. Possible values: ['debug', 'info', 'error', 'fatal']" },
35    {
36        name: 'opt-level', type: Number, defaultValue: 1, description: "Optimization level. Possible values: [0, 1, 2]. Default: 0\n    0: no optimizations\n    \
37                                                                    1: basic bytecode optimizations, including valueNumber, lowering, constantResolver, regAccAllocator\n    \
38                                                                    2: other bytecode optimizations, unimplemented yet"},
39    { name: 'help', alias: 'h', type: Boolean, description: "Show usage guide." },
40    { name: 'bc-version', alias: 'v', type: Boolean, defaultValue: false, description: "Print ark bytecode version" },
41    { name: 'bc-min-version', type: Boolean, defaultValue: false, description: "Print ark bytecode minimum supported version" },
42    { name: 'included-files', alias: 'i', type: String, lazyMultiple: true, defaultValue: [], description: "The list of dependent files." },
43    { name: 'record-type', alias: 'p', type: Boolean, defaultValue: false, description: "Record type info. Default: true" },
44    { name: 'dts-type-record', alias: 'q', type: Boolean, defaultValue: false, description: "Record type info for .d.ts files. Default: false" },
45    { name: 'debug-type', alias: 'g', type: Boolean, defaultValue: false, description: "Print type-related log. Default: false" },
46    { name: 'output-type', type: Boolean, defaultValue: false, description: "set output type."},
47    { name: 'source-file', type: String, defaultValue: "", description: "specify the file path info recorded in generated abc" },
48    { name: 'generate-tmp-file', type: Boolean, defaultValue: false, description: "whether to generate intermediate temporary files"},
49]
50
51
52
53export class CmdOptions {
54    private static parsedResult: ts.ParsedCommandLine;
55    private static options: commandLineArgs.CommandLineOptions;
56
57    static isEnableDebugLog(): boolean {
58        if (!this.options) {
59            return false;
60        }
61        return this.options["debug-log"];
62    }
63
64    static isAssemblyMode(): boolean {
65        if (!this.options) {
66            return false;
67        }
68        return this.options["dump-assembly"];
69    }
70
71    static isDebugMode(): boolean {
72        if (!this.options) {
73            return false;
74        }
75        return this.options["debug"];
76    }
77
78    static setWatchEvaluateExpressionArgs(watchArgs: string[]) {
79        this.options["debug-add-watch"] = watchArgs;
80    }
81
82    static getDeamonModeArgs(): string[] {
83        if (!this.options) {
84            return [];
85        }
86        return this.options["keep-persistent-watch"];
87    }
88
89    static isWatchEvaluateDeamonMode(): boolean {
90        return CmdOptions.getDeamonModeArgs()[0] == "start";
91    }
92
93    static isStopEvaluateDeamonMode(): boolean {
94        return CmdOptions.getDeamonModeArgs()[0] == "stop";
95    }
96
97    static getEvaluateDeamonPath(): string {
98        return CmdOptions.getDeamonModeArgs()[1];
99    }
100
101    static isWatchEvaluateExpressionMode(): boolean {
102        if (!this.options) {
103            return false;
104        }
105        return this.options["debug-add-watch"].length != 0;
106    }
107
108    static getEvaluateExpression(): string {
109        return this.options["debug-add-watch"][0];
110    }
111
112    static getWatchJsPath(): string {
113        return this.options["debug-add-watch"][1];
114    }
115
116    static getWatchTimeOutValue(): number {
117        if (this.options["debug-add-watch"].length == 2) {
118            return 0;
119        }
120        return this.options["debug-add-watch"][2];
121    }
122
123    static isModules(): boolean {
124        if (!this.options) {
125            return false;
126        }
127        return this.options["modules"];
128    }
129
130    static getOptLevel(): number {
131        return this.options["opt-level"];
132    }
133
134    static getOptLogLevel(): string {
135        return this.options["opt-log-level"];
136    }
137
138    static showASTStatistics(): boolean {
139        if (!this.options) {
140            return false;
141        }
142        return this.options["show-statistics"].includes("ast") || this.options["show-statistics"].includes("all");
143    }
144
145    static showHistogramStatistics(): boolean {
146        if (!this.options) {
147            return false;
148        }
149        return this.options["show-statistics"].includes("all") || this.options["show-statistics"].includes("histogram");
150    }
151
152    static showHoistingStatistics(): boolean {
153        if (!this.options) {
154            return false;
155        }
156        return this.options["show-statistics"].includes("all") || this.options["show-statistics"].includes("hoisting");
157    }
158
159    static getInputFileName(): string {
160        let path = this.parsedResult.fileNames[0];
161        let inputFile = path.substring(0, path.lastIndexOf('.'));
162        return inputFile;
163    }
164
165    static getOutputBinName(): string {
166        let outputFile = this.options.output;
167        if (outputFile == "") {
168            outputFile = CmdOptions.getInputFileName() + ".abc";
169        }
170        return outputFile;
171    }
172
173    static getTimeOut(): Number {
174        if (!this.options) {
175            return 0;
176        }
177        return this.options["timeout"];
178    }
179
180    static isOutputType(): false {
181        if (!this.options) {
182            return false;
183        }
184        return this.options["output-type"];
185    }
186
187    static showHelp(): void {
188        const usage = commandLineUsage([
189            {
190                header: "Ark JavaScript Compiler",
191                content: 'node --expose-gc index.js [options] file.js'
192            },
193            {
194                header: 'Options',
195                optionList: ts2pandaOptions
196            },
197            {
198                content: 'Project Ark'
199            }
200        ])
201        LOGE(usage);
202    }
203
204    static isBcVersion(): boolean {
205        if (!this.options) {
206            return false;
207        }
208        return this.options["bc-version"];
209    }
210
211    static getVersion(isBcVersion: boolean = true): void {
212        let js2abc = path.join(path.resolve(__dirname, '../bin'), "js2abc");
213        let version_arg = isBcVersion ? "--bc-version" : "--bc-min-version"
214        execute(`${js2abc}`, [version_arg]);
215    }
216
217    static isBcMinVersion(): boolean {
218        if (!this.options) {
219            return false;
220        }
221        return this.options["bc-min-version"];
222    }
223
224    static getIncludedFiles(): string[] {
225        if (!this.options) {
226            return [];
227        }
228
229        return this.options["included-files"];
230    }
231
232    static needRecordType(): boolean {
233        if (!this.options) {
234            return false;
235        }
236
237        return !this.options["record-type"];
238    }
239
240    static needRecordDtsType(): boolean {
241        if (!this.options) {
242            return false;
243        }
244        return this.options["dts-type-record"];
245    }
246
247    static enableTypeLog(): boolean {
248        if (!this.options) {
249            return false;
250        }
251        return this.options["debug-type"];
252    }
253
254    static  getSourceFile(): string {
255        return this.options["source-file"];
256    }
257
258    static needGenerateTmpFile(): boolean {
259        if (!this.options) {
260            return false;
261        }
262        return this.options["generate-tmp-file"];
263    }
264
265    // @ts-ignore
266    static parseUserCmd(args: string[]): ts.ParsedCommandLine | undefined {
267        this.options = commandLineArgs(ts2pandaOptions, { partial: true });
268        if (this.options.help) {
269            this.showHelp();
270            return undefined;
271        }
272
273        if (this.isBcVersion() || this.isBcMinVersion()) {
274            this.getVersion(this.isBcVersion());
275            return undefined;
276        }
277
278        if (!this.options._unknown) {
279            LOGE("options at least one file is needed");
280            this.showHelp();
281            return undefined;
282        }
283
284        this.parsedResult = ts.parseCommandLine(this.options._unknown!);
285        return this.parsedResult;
286    }
287
288}
289