UNPKG

nativescript

Version:

Command-line interface for building NativeScript projects

410 lines • 22.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Options = void 0; const helpers = require("./common/helpers"); const yargs = require("yargs"); const helpers_1 = require("yargs/helpers"); const _ = require("lodash"); const yok_1 = require("./common/yok"); const constants_1 = require("./constants"); class Options { setupOptions(commandSpecificDashedOptions) { if (commandSpecificDashedOptions) { _.extend(this.options, commandSpecificDashedOptions); this.setArgv(); } this.argv.bundle = "webpack"; // Check if the user has explicitly provide --hmr and --release options from command line if (this.initialArgv.release && this.initialArgv.hmr) { this.$errors.fail("The options --release and --hmr cannot be used simultaneously."); } if (this.argv.hmr) { this.argv.hmr = !this.argv.release; } if (this.argv.debugBrk) { // we cannot use HMR along with debug-brk because we have to restart the app // on each livesync in order to stop and allow debugging on app start this.argv.hmr = false; } if (this.argv.justlaunch) { this.argv.hmr = false; } } constructor($errors, $settingsService) { this.$errors = $errors; this.$settingsService = $settingsService; this.optionsWhiteList = [ "ui", "recursive", "reporter", "require", "timeout", "_", "$0", ]; // These options shouldn't be validated this.globalOptions = { log: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, verbose: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, version: { type: "boolean" /* OptionType.Boolean */, alias: "v", hasSensitiveValue: false }, help: { type: "boolean" /* OptionType.Boolean */, alias: "h", hasSensitiveValue: false }, profileDir: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, analyticsClient: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, path: { type: "string" /* OptionType.String */, alias: "p", hasSensitiveValue: true }, config: { type: "string" /* OptionType.String */, alias: "c", hasSensitiveValue: true }, // This will parse all non-hyphenated values as strings. _: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, }; this.options = _.extend({}, this.commonOptions, this.globalOptions); this.setArgv(); } get shorthands() { const result = []; _.each(_.keys(this.options), (optionName) => { if (this.options[optionName].alias) { result.push(this.options[optionName].alias); } }); return result; } get commonOptions() { return { ipa: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, frameworkPath: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, frameworkName: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, framework: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, frameworkVersion: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, forDevice: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, iCloudContainerEnvironment: { type: "string" /* OptionType.String */, hasSensitiveValue: false, }, provision: { type: "object" /* OptionType.Object */, hasSensitiveValue: true }, client: { type: "boolean" /* OptionType.Boolean */, default: true, hasSensitiveValue: false, }, env: { type: "object" /* OptionType.Object */, hasSensitiveValue: false }, production: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, debugTransport: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, keyStorePath: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, keyStorePassword: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, keyStoreAlias: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, keyStoreAliasPassword: { type: "string" /* OptionType.String */, hasSensitiveValue: true, }, ignoreScripts: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, disableNpmInstall: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, compileSdk: { type: "number" /* OptionType.Number */, hasSensitiveValue: false }, port: { type: "number" /* OptionType.Number */, hasSensitiveValue: false }, copyTo: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, js: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, javascript: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, ng: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, angular: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, react: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, reactjs: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, vue: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, vuejs: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, svelte: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, vision: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, "vision-ng": { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, "vision-react": { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, "vision-solid": { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, "vision-svelte": { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, "vision-vue": { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, tsc: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, ts: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, typescript: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, yarn: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, yarn2: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, pnpm: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, androidTypings: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, bundle: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, all: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, teamId: { type: "object" /* OptionType.Object */, hasSensitiveValue: true }, chrome: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, inspector: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, clean: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, watch: { type: "boolean" /* OptionType.Boolean */, default: true, hasSensitiveValue: false, }, background: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, username: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, pluginName: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, includeTypeScriptDemo: { type: "string" /* OptionType.String */, hasSensitiveValue: false, }, includeAngularDemo: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, hmr: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false, default: true, }, collection: { type: "string" /* OptionType.String */, alias: "c", hasSensitiveValue: false, }, json: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, avd: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, // check not used config: { type: "array" /* OptionType.Array */, hasSensitiveValue: false }, insecure: { type: "boolean" /* OptionType.Boolean */, alias: "k", hasSensitiveValue: false, }, debug: { type: "boolean" /* OptionType.Boolean */, alias: "d", hasSensitiveValue: false }, timeout: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, device: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, availableDevices: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, appid: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, geny: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, debugBrk: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, debugPort: { type: "number" /* OptionType.Number */, hasSensitiveValue: false }, start: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, stop: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, ddi: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, // the path to developer disk image justlaunch: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, file: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, force: { type: "boolean" /* OptionType.Boolean */, alias: "f", hasSensitiveValue: false }, emulator: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, simulator: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, sdk: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, template: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, certificate: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, certificatePassword: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, release: { type: "boolean" /* OptionType.Boolean */, alias: "r", hasSensitiveValue: false, }, markingMode: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, var: { type: "object" /* OptionType.Object */, hasSensitiveValue: true }, default: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, count: { type: "number" /* OptionType.Number */, hasSensitiveValue: false }, analyticsLogFile: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, disableAnalytics: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, cleanupLogFile: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, hooks: { type: "boolean" /* OptionType.Boolean */, default: true, hasSensitiveValue: false, }, link: { type: "boolean" /* OptionType.Boolean */, default: false, hasSensitiveValue: false, }, gradlePath: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, gradleArgs: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, hostProjectPath: { type: "string" /* OptionType.String */, hasSensitiveValue: false }, hostProjectModuleName: { type: "string" /* OptionType.String */, hasSensitiveValue: false, default: constants_1.APP_FOLDER_NAME, }, aab: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, performance: { type: "object" /* OptionType.Object */, hasSensitiveValue: true }, appleApplicationSpecificPassword: { type: "string" /* OptionType.String */, hasSensitiveValue: true, }, appleSessionBase64: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, jar: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, aar: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, filter: { type: "string" /* OptionType.String */, hasSensitiveValue: true }, git: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false, default: true, }, dryRun: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, uniqueBundle: { type: "boolean" /* OptionType.Boolean */, hasSensitiveValue: false }, }; } get optionNames() { return _.keys(this.options); } getOptionValue(optionName) { optionName = this.getCorrectOptionName(optionName); return this.argv[optionName]; } validateOptions(commandSpecificDashedOptions) { this.setupOptions(commandSpecificDashedOptions); const parsed = {}; for (const key of Object.keys(this.argv)) { const optionName = `${this.argv[key]}`; parsed[optionName] = this.getOptionValue(optionName); } _.each(parsed, (value, originalOptionName) => { // when this.options are passed to yargs, it returns all of them and the ones that are not part of process.argv are set to undefined. if (value === undefined) { return; } const optionName = this.getCorrectOptionName(originalOptionName); if (!_.includes(this.optionsWhiteList, optionName)) { if (!this.isOptionSupported(optionName)) { this.$errors.failWithHelp(`The option '${originalOptionName}' is not supported.`); } const optionType = this.getOptionType(optionName), optionValue = parsed[optionName]; if (_.isArray(optionValue) && optionType !== "array" /* OptionType.Array */) { this.$errors.failWithHelp("The '%s' option requires a single value.", originalOptionName); } else if (optionType === "string" /* OptionType.String */ && helpers.isNullOrWhitespace(optionValue)) { this.$errors.failWithHelp("The option '%s' requires non-empty value.", originalOptionName); } else if (optionType === "array" /* OptionType.Array */ && optionValue.length === 0) { this.$errors.failWithHelp(`The option '${originalOptionName}' requires one or more values, separated by a space.`); } } }); } getCorrectOptionName(optionName) { const secondaryOptionName = this.getNonDashedOptionName(optionName); return _.includes(this.optionNames, secondaryOptionName) ? secondaryOptionName : optionName; } getOptionType(optionName) { const option = this.options[optionName] || this.tryGetOptionByAliasName(optionName); return option ? option.type : ""; } tryGetOptionByAliasName(aliasName) { const option = _.find(this.options, (opt) => opt.alias === aliasName); return option; } isOptionSupported(option) { if (!this.options[option]) { const opt = this.tryGetOptionByAliasName(option); return !!opt; } return true; } // If you pass value with dash, yargs adds it to yargs.argv in two ways: // with dash and without dash, replacing first symbol after it with its toUpper equivalent // ex, "$ <cli name> emulate android --profile-dir" will add profile-dir to yargs.argv as profile-dir and profileDir // IMPORTANT: In your code, it is better to use the value without dashes (profileDir in the example). // This way your code will work in case "$ <cli name> emulate android --profile-dir" or "$ <cli name> emulate android --profileDir" is used by user. getNonDashedOptionName(optionName) { const matchUpperCaseLetters = optionName.match(Options.NONDASHED_OPTION_REGEX); if (matchUpperCaseLetters) { // get here if option with upperCase letter is specified, for example profileDir // check if in knownOptions we have its kebabCase presentation const secondaryOptionName = matchUpperCaseLetters[1] + matchUpperCaseLetters[2].toUpperCase() + matchUpperCaseLetters[3] || ""; return this.getNonDashedOptionName(secondaryOptionName); } return optionName; } getDashedOptionName(optionName) { const matchUpperCaseLetters = optionName.match(Options.DASHED_OPTION_REGEX); if (matchUpperCaseLetters) { const secondaryOptionName = `${matchUpperCaseLetters[1]}-${matchUpperCaseLetters[2].toLowerCase()}${matchUpperCaseLetters[3] || ""}`; return this.getDashedOptionName(secondaryOptionName); } return optionName; } setArgv() { const opts = {}; _.each(this.options, (value, key) => { opts[this.getDashedOptionName(key)] = value; }); const parsed = yargs((0, helpers_1.hideBin)(process.argv)) .version(false) .help(false) .completion("completion_generate_script", async (current_, argv) => { var _a; const args = argv._.slice(1); const commands = yok_1.injector .getRegisteredCommandsNames(false) .filter((c) => c != "/?"); // remove the /? command, looks weird... :D const currentDepth = args.length > 0 ? args.length - 1 : 0; const current = (_a = current_ !== null && current_ !== void 0 ? current_ : args[currentDepth]) !== null && _a !== void 0 ? _a : ""; // split all commands into their components ie. "device|list" => ["device", "list"] const matchGroups = commands.map((c) => c.split("|")); // find all commands that match the current depth and all the previous args const possibleMatches = matchGroups.filter((group) => { return group.slice(0, currentDepth).every((g, i) => { return g === args[i] || args[i].at(0) === "-"; }); }); // filter out duplicates const completions = [ ...new Set(possibleMatches .map((match) => { return match[currentDepth]; }) .filter(Boolean)), ]; // autocomplete long -- options if (current.startsWith("--")) { return this.optionNames.filter((o) => o !== "_").map((o) => `--${o}`); } // autocomple short - options if (current.startsWith("-")) { return this.shorthands.map((o) => `-${o}`); } // autocomplete matched completions return completions; }); this.initialArgv = parsed.argv; this.argv = parsed.options(opts).argv; // For backwards compatibility // Previously profileDir had a default option and calling `this.$options.profileDir` always returned valid result. // Now the profileDir should be used from $settingsService, but ensure the `this.$options.profileDir` returns the same value. this.$settingsService.setSettings({ profileDir: this.argv.profileDir, }); this.argv.profileDir = this.argv["profile-dir"] = this.$settingsService.getProfileDir(); // if justlaunch is set, it takes precedence over the --watch flag and the default true value if (this.argv.justlaunch) { this.argv.watch = false; } if (this.argv.ts || this.argv.typescript) { this.argv.tsc = true; } if (this.argv.angular) { this.argv.ng = true; } if (this.argv.vuejs) { this.argv.vue = true; } if (this.argv.javascript) { this.argv.js = true; } // alias --simulator to --emulator if (this.argv.simulator) { this.argv.emulator = this.argv.simulator; } this.argv.bundle = "webpack"; this.adjustDashedOptions(); } adjustDashedOptions() { _.each(this.optionNames, (optionName) => { Object.defineProperty(Options.prototype, optionName, { configurable: true, get: () => { return this.getOptionValue(optionName); }, set: (value) => { this.argv[optionName] = value; }, }); }); } } exports.Options = Options; Options.DASHED_OPTION_REGEX = /(.+?)([A-Z])(.*)/; Options.NONDASHED_OPTION_REGEX = /(.+?)[-]([a-zA-Z])(.*)/; yok_1.injector.register("options", Options); //# sourceMappingURL=options.js.map