Skip to content

Commit 79494e8

Browse files
committed
Add plugin override for watchFactory
1 parent 0aca073 commit 79494e8

File tree

40 files changed

+1265
-996
lines changed

40 files changed

+1265
-996
lines changed

src/compiler/commandLineParser.ts

Lines changed: 94 additions & 34 deletions
Large diffs are not rendered by default.

src/compiler/types.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6950,10 +6950,16 @@ export interface CreateProgramOptions {
69506950
configFileParsingDiagnostics?: readonly Diagnostic[];
69516951
}
69526952

6953+
/** @internal */
6954+
export type CommandLineOptionExtraValidation = (value: CompilerOptionsValue, valueExpression?: Expression) =>
6955+
readonly [DiagnosticMessage, ...string[]] |
6956+
{ diagnostics: readonly [DiagnosticMessage, ...string[]]; errorNode: Expression; } |
6957+
undefined;
6958+
69536959
/** @internal */
69546960
export interface CommandLineOptionBase {
69556961
name: string;
6956-
type: "string" | "number" | "boolean" | "object" | "list" | Map<string, number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
6962+
type: "string" | "number" | "boolean" | "object" | "list" | "string | object" | Map<string, number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
69576963
isFilePath?: boolean; // True if option value is a path or fileName
69586964
shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'
69596965
description?: DiagnosticMessage; // The message describing what the command line switch does.
@@ -6973,7 +6979,7 @@ export interface CommandLineOptionBase {
69736979
affectsDeclarationPath?: true; // true if the options affects declaration file path computed
69746980
affectsBuildInfo?: true; // true if this options should be emitted in buildInfo
69756981
transpileOptionValue?: boolean | undefined; // If set this means that the option should be set to this value when transpiling
6976-
extraValidation?: (value: CompilerOptionsValue) => [DiagnosticMessage, ...string[]] | undefined; // Additional validation to be performed for the value to be valid
6982+
extraValidation?: CommandLineOptionExtraValidation; // Additional validation to be performed for the value to be valid
69776983
}
69786984

69796985
/** @internal */
@@ -7015,21 +7021,21 @@ export interface DidYouMeanOptionsDiagnostics {
70157021
}
70167022

70177023
/** @internal */
7018-
export interface TsConfigOnlyOption extends CommandLineOptionBase {
7019-
type: "object";
7024+
export interface CommandLineOptionOfObjectType extends CommandLineOptionBase {
7025+
type: "object" | "string | object";
70207026
elementOptions?: Map<string, CommandLineOption>;
70217027
extraKeyDiagnostics?: DidYouMeanOptionsDiagnostics;
70227028
}
70237029

70247030
/** @internal */
70257031
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
70267032
type: "list";
7027-
element: CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption;
7033+
element: CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | CommandLineOptionOfObjectType;
70287034
listPreserveFalsyValues?: boolean;
70297035
}
70307036

70317037
/** @internal */
7032-
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption | CommandLineOptionOfListType;
7038+
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | CommandLineOptionOfObjectType | CommandLineOptionOfListType;
70337039

70347040
/** @internal */
70357041
export const enum CharacterCodes {

src/executeCommandLine/executeCommandLine.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign
299299
case "string":
300300
case "number":
301301
case "boolean":
302+
case "string | object":
302303
return getDiagnosticText(Diagnostics.type_Colon);
303304
case "list":
304305
return getDiagnosticText(Diagnostics.one_or_more_Colon);
@@ -319,6 +320,9 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign
319320
// TODO: check infinite loop
320321
possibleValues = getPossibleValues(option.element);
321322
break;
323+
case "string | object":
324+
possibleValues = "string";
325+
break;
322326
case "object":
323327
possibleValues = "";
324328
break;

src/harness/harnessIO.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,11 @@ export namespace Compiler {
377377
// If not a primitive, the possible types are specified in what is effectively a map of options.
378378
case "list":
379379
return ts.parseListTypeOption(option, value, errors);
380+
case "object":
381+
case "string | object":
382+
return ts.parseObjectTypeOption(option, value, errors)?.value;
380383
default:
381-
return ts.parseCustomTypeOption(option as ts.CommandLineOptionOfCustomType, value, errors);
384+
return ts.parseCustomTypeOption(option, value, errors);
382385
}
383386
}
384387

src/testRunner/unittests/config/commandLineParsing.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => {
191191
assertParseResult("errors on invalid excludeFiles", ["--excludeFiles", "**/../*", "0.ts"]);
192192
assertParseResult("parse --watchFactory", ["--watchFactory", "somefactory", "0.ts"]);
193193
assertParseResult("errors on invalid watchFactory", ["--watchFactory", "somefactory/../malicious", "0.ts"]);
194+
assertParseResult("parse --watchFactory object", ["--watchFactory", "{\"name\":\"somefactory\",\"myconfig\":\"somethingelse\"}", "0.ts"]);
195+
assertParseResult("errors on invalid watchFactory name", ["--watchFactory", "{\"name\":\"somefactory/../malicious\"}", "0.ts"]);
196+
assertParseResult("errors on invalid watchFactory object", ["--watchFactory", "{\"name\":\"myplugin\"", "0.ts"]);
194197
});
195198
});
196199

@@ -247,5 +250,8 @@ describe("unittests:: config:: commandLineParsing:: parseBuildOptions", () => {
247250
assertParseResult("errors on invalid excludeFiles", ["--excludeFiles", "**/../*"]);
248251
assertParseResult("parse --watchFactory", ["--watchFactory", "somefactory"]);
249252
assertParseResult("errors on invalid watchFactory", ["--watchFactory", "somefactory/../malicious"]);
253+
assertParseResult("parse --watchFactory object", ["--watchFactory", `{"name":"somefactory","myconfig":"somethingelse"}`]);
254+
assertParseResult("errors on invalid watchFactory name", ["--watchFactory", "{\"name\":\"somefactory/../malicious\"}"]);
255+
assertParseResult("errors on invalid watchFactory object", ["--watchFactory", "{\"name\":\"myplugin\""]);
250256
});
251257
});

src/testRunner/unittests/config/showConfig.ts

Lines changed: 19 additions & 0 deletions
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 | object") {
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) {
@@ -167,6 +185,7 @@ describe("unittests:: config:: showConfig", () => {
167185
}
168186
break;
169187
}
188+
case "string | object":
170189
case "object": {
171190
args = ["-p", "tsconfig.json"];
172191
optionValue = { [option.name]: {} };

src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileText
169169
{
170170
json: { watchOptions: { watchFactory: "somefactory/../malicious" } },
171171
},
172+
{
173+
json: { watchOptions: { watchFactory: { name: "somefactory", myconfig: "somethingelse" } } },
174+
},
175+
{
176+
json: { watchOptions: { watchFactory: { name: "somefactory/../malicious" } } },
177+
},
172178
]);
173179

174180
verifyWatchOptions("watch options extending passed in watch options", () => [

src/testRunner/unittests/tscWatch/watchEnvironment.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -928,8 +928,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
928928
scenario,
929929
...input,
930930
subScenario: `${input.subScenario} object`,
931-
sys: () => input.sys({ watchFactory }),
932-
// sys: () => input.sys({ watchFactory: { name: watchFactory, myconfig: "somethingelse" } as ts.PluginImport }),
931+
sys: () => input.sys({ watchFactory: { name: watchFactory, myconfig: "somethingelse" } as ts.PluginImport }),
933932
});
934933
}
935934

@@ -946,8 +945,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po
946945
scenario,
947946
...input,
948947
subScenario: `${input.subScenario} object`,
949-
commandLineArgs: ["-w", "--extendedDiagnostics", "--watchFactory", watchFactory],
950-
// commandLineArgs: ["-w", "--extendedDiagnostics", "--watchFactory", JSON.stringify({ name: watchFactory, myconfig: "somethingelse" })],
948+
commandLineArgs: ["-w", "--extendedDiagnostics", "--watchFactory", JSON.stringify({ name: watchFactory, myconfig: "somethingelse" })],
951949
});
952950
}
953951
});

src/testRunner/unittests/tsserver/watchEnvironment.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -714,9 +714,8 @@ describe("unittests:: tsserver:: watchEnvironment:: watchFile is single watcher
714714
interface PluginImport extends ts.PluginImport {
715715
myconfig: "somethingelse";
716716
}
717-
function getWatchFactory(watchFactory: string, _useObject: boolean): PluginImport | string {
718-
return watchFactory;
719-
// return useObject ? { name: watchFactory, myconfig: "somethingelse" } : watchFactory;
717+
function getWatchFactory(watchFactory: string, useObject: boolean): PluginImport | string {
718+
return useObject ? { name: watchFactory, myconfig: "somethingelse" } : watchFactory;
720719
}
721720

722721
function configureGlobalWatchOptions(session: TestSession, watchFactory: string, useObject: boolean) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--watchFactory {"name":"somefactory/../malicious"}
2+
buildOptions::
3+
{}
4+
WatchOptions::
5+
{}
6+
Projects::
7+
.
8+
Errors::
9+
error TS5096: 'watchFactory' name can only be a package name.

0 commit comments

Comments
 (0)