blob: 658b7fff334c8f4c7485a8a107d1603d662cd3d4 [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed un der the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export class CommandLineParser {
public static createStringArrayOption(optionName: string, help: string, defaultValue: string[]): CommandLineArgument {
return new StringArrayOption(optionName, help, defaultValue);
}
public static createBooleanOption(optionName: string, help: string, defaultValue: boolean): CommandLineArgument {
return new BooleanOption(optionName, help, defaultValue);
}
public static createStringOption(optionName: string, help: string, defaultValue: string | null): CommandLineArgument {
return new StringOption(optionName, help, defaultValue);
}
public constructor(private readonly argumentTypes: {[name: string]: CommandLineArgument}) {
}
public parse(argv: string[]): object {
const result = Object.assign({});
let index = 2; //argv[0] - node interpreter, argv[1] - index.js
for(const argumentField in this.argumentTypes) {
result[argumentField] = this.argumentTypes[argumentField].getDefaultValue();
}
while(index < argv.length) {
let knownArgument = false;
for(const argumentField in this.argumentTypes) {
const argumentType = this.argumentTypes[argumentField];
const argumentValue = argumentType.tryRead(argv, index);
if(argumentValue) {
knownArgument = true;
index += argumentValue.consumed;
result[argumentField] = argumentValue.value;
break;
}
}
if(!knownArgument) {
throw new Error(`Unknown argument ${argv[index]}`);
}
}
return result;
}
}
interface CommandLineArgumentReadResult {
consumed: number;
value: any;
}
export interface CommandLineArgument {
getDefaultValue(): any;
tryRead(argv: string[], startIndex: number): CommandLineArgumentReadResult | null;
}
abstract class CommandLineOption implements CommandLineArgument {
protected constructor(protected readonly optionName: string, protected readonly help: string, private readonly defaultValue: any) {
}
public tryRead(argv: string[], startIndex: number): CommandLineArgumentReadResult | null {
if(argv[startIndex] !== "--" + this.optionName) {
return null;
}
const readArgumentsResult = this.readArguments(argv, startIndex + 1);
if(!readArgumentsResult) {
return null;
}
readArgumentsResult.consumed++; // Add option name
return readArgumentsResult;
}
public getDefaultValue(): any {
return this.defaultValue;
}
protected abstract readArguments(argv: string[], startIndex: number) : CommandLineArgumentReadResult | null;
}
class StringArrayOption extends CommandLineOption {
public constructor(optionName: string, help: string, defaultValue: string[]) {
super(optionName, help, defaultValue);
}
protected readArguments(argv: string[], startIndex: number): CommandLineArgumentReadResult {
const result = [];
let index = startIndex;
while(index < argv.length) {
if(argv[index].startsWith("--")) {
break;
}
result.push(argv[index]);
index++;
}
return {
consumed: index - startIndex,
value: result
}
}
}
class BooleanOption extends CommandLineOption {
public constructor(optionName: string, help: string, defaultValue: boolean) {
super(optionName, help, defaultValue);
}
protected readArguments(argv: string[], startIndex: number): CommandLineArgumentReadResult {
return {
consumed: 0,
value: true
}
}
}
class StringOption extends CommandLineOption {
public constructor(optionName: string, help: string, defaultValue: string | null) {
super(optionName, help, defaultValue);
}
protected readArguments(argv: string[], startIndex: number): CommandLineArgumentReadResult | null {
if(startIndex >= argv.length) {
return null;
}
return {
consumed: 1,
value: argv[startIndex]
}
}
}