UNPKG

appcenter-cli

Version:

Command line tool for Visual Studio App Center

179 lines (178 loc) 7.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.help = exports.defaultValue = exports.required = exports.name = exports.position = exports.common = exports.hasArg = exports.longName = exports.shortName = exports.getClassHelpText = exports.getPositionalOptionsDescription = exports.getOptionsDescription = exports.classHelpTextKey = void 0; const util_1 = require("util"); const lodash_1 = require("lodash"); const debug = require("debug")("appcenter-cli:util:commandline:option-decorators"); const optionDescriptionKey = Symbol("OptionParameters"); const positionalDescriptionKey = Symbol("PositionalParameters"); const unknownRequiredsKey = Symbol("UnknownRequireds"); const unknownDefaultValueKey = Symbol("UnknownDefaultValues"); const unknownHelpTextKey = Symbol("UnknownDescription"); exports.classHelpTextKey = Symbol("ClassHelpText"); function getOptionsDescription(target) { // option description can be overridden in children class function getRecursive(accumulator, target) { if (target) { getRecursive(accumulator, Object.getPrototypeOf(target)); } else { return accumulator; } if (target.hasOwnProperty(optionDescriptionKey)) { lodash_1.assign(accumulator, target[optionDescriptionKey]); } return accumulator; } return getRecursive({}, target); } exports.getOptionsDescription = getOptionsDescription; function getLocalOptionsDescription(target) { if (!target.hasOwnProperty(optionDescriptionKey)) { target[optionDescriptionKey] = {}; } return target[optionDescriptionKey]; } function getPositionalOptionsDescription(target) { function getRecursive(accumulator, target) { if (!target || !target.hasOwnProperty(positionalDescriptionKey)) { return accumulator; } let newOpts = []; if (target.hasOwnProperty(positionalDescriptionKey)) { newOpts = target[positionalDescriptionKey]; } return getRecursive(newOpts.concat(accumulator), Object.getPrototypeOf(target)); } return getRecursive([], target); } exports.getPositionalOptionsDescription = getPositionalOptionsDescription; function getLocalPositionalOptionsDescription(target) { if (!target.hasOwnProperty(positionalDescriptionKey)) { target[positionalDescriptionKey] = []; } return target[positionalDescriptionKey]; } function getClassHelpText(target) { return target[exports.classHelpTextKey]; } exports.getClassHelpText = getClassHelpText; function updateUnknownRequireds(option, propertyKey, proto) { if (proto[unknownRequiredsKey] && proto[unknownRequiredsKey].has(propertyKey)) { option.required = true; proto[unknownRequiredsKey].delete(propertyKey); } } function updateUnknownDefaultValues(option, propertyKey, proto) { if (proto[unknownDefaultValueKey] && proto[unknownDefaultValueKey].has(propertyKey)) { option.defaultValue = proto[unknownDefaultValueKey].get(propertyKey); proto[unknownDefaultValueKey].delete(propertyKey); } } function updateUnknownHelpTexts(option, propertyKey, proto) { if (proto[unknownHelpTextKey] && proto[unknownHelpTextKey].has(propertyKey)) { option.helpText = proto[unknownHelpTextKey].get(propertyKey); proto[unknownHelpTextKey].delete(propertyKey); } } function updateUnknowns(option, propertyKey, proto) { updateUnknownRequireds(option, propertyKey, proto); updateUnknownDefaultValues(option, propertyKey, proto); updateUnknownHelpTexts(option, propertyKey, proto); } function makeStringDecorator(descriptionFieldName) { return function decoratorBuilder(name) { return function paramDecorator(proto, propertyKey) { const optionsDescription = getLocalOptionsDescription(proto); const option = optionsDescription[propertyKey] || {}; option[descriptionFieldName] = name; updateUnknowns(option, propertyKey, proto); optionsDescription[propertyKey] = option; }; }; } function makeBoolDecorator(descriptionFieldName) { return function paramDecorator(proto, propertyKey) { const optionsDescription = getLocalOptionsDescription(proto); const option = optionsDescription[propertyKey] || {}; option[descriptionFieldName] = true; updateUnknowns(option, propertyKey, proto); optionsDescription[propertyKey] = option; }; } // Short and long name decorators exports.shortName = makeStringDecorator("shortName"); exports.longName = makeStringDecorator("longName"); exports.hasArg = makeBoolDecorator("hasArg"); exports.common = makeBoolDecorator("common"); function makePositionalDecorator(descriptionFieldName) { return function positionalDecoratorBuilder(value) { return function positionalDecorator(proto, propertyKey) { const optionsDescription = getLocalPositionalOptionsDescription(proto); let option = optionsDescription.find((opt) => opt.propertyName === propertyKey); if (option === undefined) { option = { propertyName: propertyKey, name: "", position: -1 }; optionsDescription.push(option); updateUnknowns(option, propertyKey, proto); } option[descriptionFieldName] = value; }; }; } exports.position = makePositionalDecorator("position"); exports.name = makePositionalDecorator("name"); // // Logic or handling decorators that apply to both positional and // flag arguments. Needs to be slightly special since we may not // know which one the parameter is until a later decorator runs. // function saveDecoratedValue(proto, propertyKey, descriptionProperty, value, unknownFieldKey) { const flagOpts = getLocalOptionsDescription(proto); if (flagOpts.hasOwnProperty(propertyKey.toString())) { flagOpts[propertyKey.toString()][descriptionProperty] = value; return; } const positionalOpts = getLocalPositionalOptionsDescription(proto); const opt = positionalOpts.find((opt) => opt.propertyName === propertyKey); if (opt !== undefined) { opt[descriptionProperty] = value; return; } const unknownValues = (proto[unknownFieldKey] = proto[unknownFieldKey] || new Map()); unknownValues.set(propertyKey.toString(), value); } // Required is special, since it has to work on both flag and positional parameters. // If it's the first decorator, stick name in a set to check later once we know // which one it is function required(proto, propertyKey) { saveDecoratedValue(proto, propertyKey, "required", true, unknownRequiredsKey); } exports.required = required; // DefaultValue is also special, since it has to work with both as well. Same // basic logic function defaultValue(value) { return function defaultValueDecorator(proto, propertyKey) { saveDecoratedValue(proto, propertyKey, "defaultValue", value, unknownDefaultValueKey); }; } exports.defaultValue = defaultValue; // Decorator factory to give a consolidated helptext API across class & parameter function help(helpText) { return function helpDecoratorFactory(...args) { debug(`@help decorator called with ${args.length} arguments: ${util_1.inspect(args)}`); if (args.length === 1) { const ctor = args[0]; ctor[exports.classHelpTextKey] = helpText; return ctor; } // Typescript docs are incorrect - property decorators get three args, and the last one is // undefined if (args.length === 3 && typeof args[0] === "object" && args[2] === undefined) { const proto = args[0]; const propertyName = args[1]; return saveDecoratedValue(proto, propertyName, "helpText", helpText, unknownHelpTextKey); } throw new Error("@help not valid in this location"); }; } exports.help = help;