Skip to content

Commit 1b36b57

Browse files
committed
Added "string | list" type implentation
1 parent de79220 commit 1b36b57

File tree

5 files changed

+68
-16
lines changed

5 files changed

+68
-16
lines changed

src/compiler/commandLineParser.ts

+42-14
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ import {
103103
returnTrue,
104104
ScriptTarget,
105105
startsWith,
106+
stringContains,
106107
StringLiteral,
107108
SyntaxKind,
108109
sys,
@@ -1658,11 +1659,14 @@ export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value:
16581659
}
16591660

16601661
/** @internal */
1661-
export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push<Diagnostic>): (string | number)[] | undefined {
1662+
export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push<Diagnostic>): string | (string | number)[] | undefined {
16621663
value = trimString(value);
16631664
if (startsWith(value, "-")) {
16641665
return undefined;
16651666
}
1667+
if (opt.type === "string | list" && !stringContains(value, ",")) {
1668+
return validateJsonOptionValue(opt, value, errors);
1669+
}
16661670
if (value === "") {
16671671
return [];
16681672
}
@@ -1672,6 +1676,10 @@ export function parseListTypeOption(opt: CommandLineOptionOfListType, value = ""
16721676
return mapDefined(values, v => validateJsonOptionValue(opt.element, parseInt(v), errors));
16731677
case "string":
16741678
return mapDefined(values, v => validateJsonOptionValue(opt.element, v || "", errors));
1679+
case "boolean":
1680+
case "object":
1681+
case "string | list":
1682+
return Debug.fail(`List of ${opt.element.type} is not yet supported.`);
16751683
default:
16761684
return mapDefined(values, v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors));
16771685
}
@@ -1843,6 +1851,7 @@ function parseOptionValue(
18431851
options[opt.name] = validateJsonOptionValue(opt, args[i] || "", errors);
18441852
i++;
18451853
break;
1854+
case "string | list":
18461855
case "list":
18471856
const result = parseListTypeOption(opt, args[i], errors);
18481857
options[opt.name] = result || [];
@@ -2362,7 +2371,7 @@ export function convertToObjectWorker(
23622371
if (!isDoubleQuotedString(valueExpression)) {
23632372
errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected));
23642373
}
2365-
reportInvalidOptionValue(option && isString(option.type) && option.type !== "string" && (option.type !== "listOrElement" || (isString(option.element.type) && option.element.type !== "string")));
2374+
reportInvalidOptionValue(option && isString(option.type) && option.type !== "string" && (option.type !== "listOrElement" || (isString(option.element.type) && option.element.type !== "string")) && option.type !== "string | list");
23662375
const text = (valueExpression as StringLiteral).text;
23672376
if (option) {
23682377
Debug.assert(option.type !== "listOrElement" || option.element.type === "string", "Only string or array of string is handled for now");
@@ -2394,7 +2403,7 @@ export function convertToObjectWorker(
23942403
return validateValue(-Number(((valueExpression as PrefixUnaryExpression).operand as NumericLiteral).text));
23952404

23962405
case SyntaxKind.ObjectLiteralExpression:
2397-
reportInvalidOptionValue(option && option.type !== "object" && (option.type !== "listOrElement" || option.element.type !== "object"));
2406+
reportInvalidOptionValue(option && option.type !== "object" && (option.type !== "listOrElement" || option.element.type !== "object") && option.type !== "string | list");
23982407
const objectLiteralExpression = valueExpression as ObjectLiteralExpression;
23992408

24002409
// Currently having element option declaration in the tsconfig with type "object"
@@ -2472,6 +2481,9 @@ function isCompilerOptionsValue(option: CommandLineOption | undefined, value: an
24722481
if (option.type === "listOrElement") {
24732482
return isArray(value) || isCompilerOptionsValue(option.element, value);
24742483
}
2484+
if (option.type === "string | list") {
2485+
return typeof value === "string" || isArray(value);
2486+
}
24752487
const expectedType = isString(option.type) ? option.type : "string";
24762488
return typeof value === expectedType;
24772489
}
@@ -2576,15 +2588,29 @@ function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined,
25762588
}
25772589

25782590
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string, string | number> | undefined {
2579-
if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean" || optionDefinition.type === "object") {
2580-
// this is of a type CommandLineOptionOfPrimitiveType
2581-
return undefined;
2582-
}
2583-
else if (optionDefinition.type === "list" || optionDefinition.type === "listOrElement") {
2584-
return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
2585-
}
2586-
else {
2587-
return optionDefinition.type;
2591+
// if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean" || optionDefinition.type === "object") {
2592+
// // this is of a type CommandLineOptionOfPrimitiveType
2593+
// return undefined;
2594+
// }
2595+
// else if (optionDefinition.type === "list" || optionDefinition.type === "listOrElement") {
2596+
// return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
2597+
// }
2598+
// else {
2599+
// return optionDefinition.type;
2600+
// }
2601+
switch (optionDefinition.type) {
2602+
case "string":
2603+
case "number":
2604+
case "boolean":
2605+
case "object":
2606+
case "string | list":
2607+
// this is of a type CommandLineOptionOfPrimitiveType
2608+
return undefined;
2609+
case "list":
2610+
case "listOrElement":
2611+
return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
2612+
default:
2613+
return optionDefinition.type;
25882614
}
25892615
}
25902616

@@ -3495,15 +3521,15 @@ function convertOptionsFromJson(optionsNameMap: Map<string, CommandLineOption>,
34953521
export function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Push<Diagnostic>): CompilerOptionsValue {
34963522
if (isCompilerOptionsValue(opt, value)) {
34973523
const optType = opt.type;
3498-
if (optType === "list" && isArray(value)) {
3524+
if ((optType === "list" || opt.type === "string | list") && isArray(value)) {
34993525
return convertJsonOptionOfListType(opt, value, basePath, errors);
35003526
}
35013527
else if (optType === "listOrElement") {
35023528
return isArray(value) ?
35033529
convertJsonOptionOfListType(opt, value, basePath, errors) :
35043530
convertJsonOption(opt.element, value, basePath, errors);
35053531
}
3506-
else if (!isString(optType)) {
3532+
else if (!isString(opt.type)) {
35073533
return convertJsonOptionOfCustomType(opt as CommandLineOptionOfCustomType, value as string, errors);
35083534
}
35093535
const validatedValue = validateJsonOptionValue(opt, value, errors);
@@ -3949,6 +3975,7 @@ function getOptionValueWithEmptyStrings(value: any, option: CommandLineOption):
39493975
if (!isArray(value)) return getOptionValueWithEmptyStrings(value, option.element);
39503976
// fall through to list
39513977
case "list":
3978+
case "string | list":
39523979
const elementType = option.element;
39533980
return isArray(value) ? value.map(v => getOptionValueWithEmptyStrings(v, elementType)) : "";
39543981
default:
@@ -3968,6 +3995,7 @@ function getDefaultValueForOption(option: CommandLineOption): {} {
39683995
case "boolean":
39693996
return true;
39703997
case "string":
3998+
case "string | list":
39713999
const defaultValue = option.defaultValueDescription;
39724000
return option.isFilePath ? `./${defaultValue && typeof defaultValue === "string" ? defaultValue : ""}` : "";
39734001
case "list":

src/compiler/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6960,7 +6960,7 @@ export interface CreateProgramOptions {
69606960
/** @internal */
69616961
export interface CommandLineOptionBase {
69626962
name: string;
6963-
type: "string" | "number" | "boolean" | "object" | "list" | "listOrElement" | Map<string, number | string> ; // a value of a primitive type, or an object literal mapping named values to actual values
6963+
type: "string" | "number" | "boolean" | "object" | "list" | "listOrElement" | "string | list" | Map<string, number | string> ; // a value of a primitive type, or an object literal mapping named values to actual values
69646964
isFilePath?: boolean; // True if option value is a path or fileName
69656965
shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'
69666966
description?: DiagnosticMessage; // The message describing what the command line switch does.
@@ -7030,7 +7030,7 @@ export interface TsConfigOnlyOption extends CommandLineOptionBase {
70307030

70317031
/** @internal */
70327032
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
7033-
type: "list" | "listOrElement";
7033+
type: "list" | "listOrElement" | "string | list";
70347034
element: CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption;
70357035
listPreserveFalsyValues?: boolean;
70367036
}

src/executeCommandLine/executeCommandLine.ts

+4
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign
372372
case "boolean":
373373
return getDiagnosticText(Diagnostics.type_Colon);
374374
case "list":
375+
case "string | list":
375376
return getDiagnosticText(Diagnostics.one_or_more_Colon);
376377
default:
377378
return getDiagnosticText(Diagnostics.one_of_Colon);
@@ -390,6 +391,9 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign
390391
case "listOrElement":
391392
possibleValues = getPossibleValues(option.element);
392393
break;
394+
case "string | list":
395+
possibleValues = "string";
396+
break;
393397
case "object":
394398
possibleValues = "";
395399
break;

src/harness/harnessIO.ts

+1
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ export namespace Compiler {
380380
}
381381
// If not a primitive, the possible types are specified in what is effectively a map of options.
382382
case "list":
383+
case "string | list":
383384
return ts.parseListTypeOption(option, value, errors);
384385
default:
385386
return ts.parseCustomTypeOption(option as ts.CommandLineOptionOfCustomType, value, errors);

src/testRunner/unittests/config/showConfig.ts

+19
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,24 @@ describe("unittests:: config:: showConfig", () => {
126126
if (option.name === "project") return;
127127
let args: string[];
128128
let optionValue: object | undefined;
129+
if (option.type === "string | list") {
130+
if (option.isTSConfigOnly) {
131+
showTSConfigCorrectly(
132+
`Shows tsconfig for single option/${option.name}WithStringValue`,
133+
["-p", "tsconfig.json"],
134+
isCompilerOptions ?
135+
{ compilerOptions: { [option.name]: "someString" } } :
136+
{ watchOptions: { [option.name]: "someString" } }
137+
);
138+
}
139+
else {
140+
showTSConfigCorrectly(
141+
`Shows tsconfig for single option/${option.name}WithStringValue`,
142+
[`--${option.name}`, "someString"],
143+
/*configJson*/ undefined,
144+
);
145+
}
146+
}
129147
switch (option.type) {
130148
case "boolean": {
131149
if (option.isTSConfigOnly) {
@@ -137,6 +155,7 @@ describe("unittests:: config:: showConfig", () => {
137155
}
138156
break;
139157
}
158+
case "string | list":
140159
case "list": {
141160
if (option.isTSConfigOnly) {
142161
args = ["-p", "tsconfig.json"];

0 commit comments

Comments
 (0)