Skip to content

Commit ec38ca4

Browse files
committed
Merge branch 'master' into tsbuildWatchImprovements
2 parents 6c57ebd + e1daa47 commit ec38ca4

File tree

88 files changed

+715
-392
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+715
-392
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19208,12 +19208,16 @@ namespace ts {
1920819208
let aboveArgCount = Number.POSITIVE_INFINITY;
1920919209

1921019210
let argCount = args.length;
19211+
let closestSignature: Signature | undefined;
1921119212
for (const sig of signatures) {
1921219213
const minCount = getMinArgumentCount(sig);
1921319214
const maxCount = getParameterCount(sig);
1921419215
if (minCount < argCount && minCount > belowArgCount) belowArgCount = minCount;
1921519216
if (argCount < maxCount && maxCount < aboveArgCount) aboveArgCount = maxCount;
19216-
min = Math.min(min, minCount);
19217+
if (minCount < min) {
19218+
min = minCount;
19219+
closestSignature = sig;
19220+
}
1921719221
max = Math.max(max, maxCount);
1921819222
}
1921919223

@@ -19226,16 +19230,29 @@ namespace ts {
1922619230
argCount--;
1922719231
}
1922819232

19233+
let related: DiagnosticWithLocation | undefined;
19234+
if (closestSignature && getMinArgumentCount(closestSignature) > argCount && closestSignature.declaration) {
19235+
const paramDecl = closestSignature.declaration.parameters[closestSignature.thisParameter ? argCount + 1 : argCount];
19236+
if (paramDecl) {
19237+
related = createDiagnosticForNode(
19238+
paramDecl,
19239+
isBindingPattern(paramDecl.name) ? Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided : Diagnostics.An_argument_for_0_was_not_provided,
19240+
!paramDecl.name ? argCount : !isBindingPattern(paramDecl.name) ? idText(getFirstIdentifier(paramDecl.name)) : undefined
19241+
);
19242+
}
19243+
}
1922919244
if (hasRestParameter || hasSpreadArgument) {
1923019245
const error = hasRestParameter && hasSpreadArgument ? Diagnostics.Expected_at_least_0_arguments_but_got_1_or_more :
1923119246
hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 :
1923219247
Diagnostics.Expected_0_arguments_but_got_1_or_more;
19233-
return createDiagnosticForNode(node, error, paramRange, argCount);
19248+
const diagnostic = createDiagnosticForNode(node, error, paramRange, argCount);
19249+
return related ? addRelatedInfo(diagnostic, related) : diagnostic;
1923419250
}
1923519251
if (min < argCount && argCount < max) {
1923619252
return createDiagnosticForNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, argCount, belowArgCount, aboveArgCount);
1923719253
}
19238-
return createDiagnosticForNode(node, Diagnostics.Expected_0_arguments_but_got_1, paramRange, argCount);
19254+
const diagnostic = createDiagnosticForNode(node, Diagnostics.Expected_0_arguments_but_got_1, paramRange, argCount);
19255+
return related ? addRelatedInfo(diagnostic, related) : diagnostic;
1923919256
}
1924019257

1924119258
function getTypeArgumentArityError(node: Node, signatures: ReadonlyArray<Signature>, typeArguments: NodeArray<TypeNode>) {

src/compiler/commandLineParser.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,8 +1844,21 @@ namespace ts {
18441844
if (hasProperty(raw, "files") && !isNullOrUndefined(raw.files)) {
18451845
if (isArray(raw.files)) {
18461846
filesSpecs = <ReadonlyArray<string>>raw.files;
1847-
if (filesSpecs.length === 0) {
1848-
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
1847+
const hasReferences = hasProperty(raw, "references") && !isNullOrUndefined(raw.references);
1848+
const hasZeroOrNoReferences = !hasReferences || raw.references.length === 0;
1849+
if (filesSpecs.length === 0 && hasZeroOrNoReferences) {
1850+
if (sourceFile) {
1851+
const fileName = configFileName || "tsconfig.json";
1852+
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
1853+
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
1854+
const error = nodeValue
1855+
? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName)
1856+
: createCompilerDiagnostic(diagnosticMessage, fileName);
1857+
errors.push(error);
1858+
}
1859+
else {
1860+
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
1861+
}
18491862
}
18501863
}
18511864
else {
@@ -2066,11 +2079,6 @@ namespace ts {
20662079
createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0)
20672080
);
20682081
return;
2069-
case "files":
2070-
if ((<ReadonlyArray<string>>value).length === 0) {
2071-
errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueNode, Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"));
2072-
}
2073-
return;
20742082
}
20752083
},
20762084
onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, _value: CompilerOptionsValue, _valueNode: Expression) {
@@ -2080,6 +2088,7 @@ namespace ts {
20802088
}
20812089
};
20822090
const json = convertToObjectWorker(sourceFile, errors, /*returnValue*/ true, getTsconfigRootOptionsMap(), optionsIterator);
2091+
20832092
if (!typeAcquisition) {
20842093
if (typingOptionstypeAcquisition) {
20852094
typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) ?

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3708,6 +3708,14 @@
37083708
"category": "Message",
37093709
"code": 6209
37103710
},
3711+
"An argument for '{0}' was not provided.": {
3712+
"category": "Message",
3713+
"code": 6210
3714+
},
3715+
"An argument matching this binding pattern was not provided.": {
3716+
"category": "Message",
3717+
"code": 6211
3718+
},
37113719

37123720
"Projects to reference": {
37133721
"category": "Message",

src/compiler/emitter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2818,7 +2818,8 @@ namespace ts {
28182818
const parameter = singleOrUndefined(parameters);
28192819
return parameter
28202820
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
2821-
&& !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation
2821+
&& isArrowFunction(parentNode) // only arrow functions may have simple arrow head
2822+
&& !parentNode.type // arrow function may not have return type annotation
28222823
&& !some(parentNode.decorators) // parent may not have decorators
28232824
&& !some(parentNode.modifiers) // parent may not have modifiers
28242825
&& !some(parentNode.typeParameters) // parent may not have type parameters

src/compiler/program.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ namespace ts {
250250
Blue = "\u001b[94m",
251251
Cyan = "\u001b[96m"
252252
}
253-
const gutterStyleSequence = "\u001b[30;47m";
253+
const gutterStyleSequence = "\u001b[7m";
254254
const gutterSeparator = " ";
255255
const resetEscapeSequence = "\u001b[0m";
256256
const ellipsis = "...";

src/compiler/tsbuild.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,6 @@ namespace ts {
10171017
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Config file errors" });
10181018
return resultFlags;
10191019
}
1020-
10211020
if (configFile.fileNames.length === 0) {
10221021
// Nothing to build - must be a solution file, basically
10231022
return BuildResultFlags.None;
@@ -1221,19 +1220,22 @@ namespace ts {
12211220

12221221
const queue = graph.buildQueue;
12231222
reportBuildQueue(graph);
1224-
12251223
let anyFailed = false;
12261224
for (const next of queue) {
12271225
const proj = parseConfigFile(next);
12281226
if (proj === undefined) {
12291227
anyFailed = true;
12301228
break;
12311229
}
1230+
1231+
// report errors early when using continue or break statements
1232+
const errors = proj.errors;
12321233
const status = getUpToDateStatus(proj);
12331234
verboseReportProjectStatus(next, status);
12341235

12351236
const projName = proj.options.configFilePath!;
12361237
if (status.type === UpToDateStatusType.UpToDate && !options.force) {
1238+
reportErrors(errors);
12371239
// Up to date, skip
12381240
if (defaultOptions.dry) {
12391241
// In a dry build, inform the user of this fact
@@ -1243,17 +1245,20 @@ namespace ts {
12431245
}
12441246

12451247
if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes && !options.force) {
1248+
reportErrors(errors);
12461249
// Fake build
12471250
updateOutputTimestamps(proj);
12481251
continue;
12491252
}
12501253

12511254
if (status.type === UpToDateStatusType.UpstreamBlocked) {
1255+
reportErrors(errors);
12521256
if (options.verbose) reportStatus(Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, projName, status.upstreamProjectName);
12531257
continue;
12541258
}
12551259

12561260
if (status.type === UpToDateStatusType.ContainerOnly) {
1261+
reportErrors(errors);
12571262
// Do nothing
12581263
continue;
12591264
}
@@ -1265,6 +1270,10 @@ namespace ts {
12651270
return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success;
12661271
}
12671272

1273+
function reportErrors(errors: Diagnostic[]) {
1274+
errors.forEach((err) => host.reportDiagnostic(err));
1275+
}
1276+
12681277
/**
12691278
* Report the build ordering inferred from the current project graph if we're in verbose mode
12701279
*/

src/testRunner/unittests/tsbuild.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,48 @@ namespace ts {
292292
});
293293
}
294294

295+
export namespace EmptyFiles {
296+
const projFs = loadProjectFromDisk("tests/projects/empty-files");
297+
298+
const allExpectedOutputs = [
299+
"/src/core/index.js",
300+
"/src/core/index.d.ts",
301+
"/src/core/index.d.ts.map",
302+
];
303+
304+
describe("tsbuild - empty files option in tsconfig", () => {
305+
it("has empty files diagnostic when files is empty and no references are provided", () => {
306+
const fs = projFs.shadow();
307+
const host = new fakes.SolutionBuilderHost(fs);
308+
const builder = createSolutionBuilder(host, ["/src/no-references"], { dry: false, force: false, verbose: false });
309+
310+
host.clearDiagnostics();
311+
builder.buildAllProjects();
312+
host.assertDiagnosticMessages(Diagnostics.The_files_list_in_config_file_0_is_empty);
313+
314+
// Check for outputs to not be written.
315+
for (const output of allExpectedOutputs) {
316+
assert(!fs.existsSync(output), `Expect file ${output} to not exist`);
317+
}
318+
});
319+
320+
it("does not have empty files diagnostic when files is empty and references are provided", () => {
321+
const fs = projFs.shadow();
322+
const host = new fakes.SolutionBuilderHost(fs);
323+
const builder = createSolutionBuilder(host, ["/src/with-references"], { dry: false, force: false, verbose: false });
324+
325+
host.clearDiagnostics();
326+
builder.buildAllProjects();
327+
host.assertDiagnosticMessages(/*empty*/);
328+
329+
// Check for outputs to be written.
330+
for (const output of allExpectedOutputs) {
331+
assert(fs.existsSync(output), `Expect file ${output} to exist`);
332+
}
333+
});
334+
});
335+
}
336+
295337
describe("tsbuild - graph-ordering", () => {
296338
let host: fakes.SolutionBuilderHost | undefined;
297339
const deps: [string, string][] = [

src/testRunner/unittests/tsconfigParsing.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ namespace ts {
6161
}
6262
}
6363

64+
function assertParseFileDiagnosticsExclusion(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedExcludedDiagnosticCode: number) {
65+
{
66+
const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList);
67+
assert.isTrue(parsed.errors.length >= 0);
68+
assert.isTrue(parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${JSON.stringify(parsed.errors)}`);
69+
}
70+
{
71+
const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList);
72+
assert.isTrue(parsed.errors.length >= 0);
73+
assert.isTrue(parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${JSON.stringify(parsed.errors)}`);
74+
}
75+
}
76+
6477
it("returns empty config for file with only whitespaces", () => {
6578
assertParseResult("", { config : {} });
6679
assertParseResult(" ", { config : {} });
@@ -280,6 +293,30 @@ namespace ts {
280293
Diagnostics.The_files_list_in_config_file_0_is_empty.code);
281294
});
282295

296+
it("generates errors for empty files list when no references are provided", () => {
297+
const content = `{
298+
"files": [],
299+
"references": []
300+
}`;
301+
assertParseFileDiagnostics(content,
302+
"/apath/tsconfig.json",
303+
"tests/cases/unittests",
304+
["/apath/a.ts"],
305+
Diagnostics.The_files_list_in_config_file_0_is_empty.code);
306+
});
307+
308+
it("does not generate errors for empty files list when one or more references are provided", () => {
309+
const content = `{
310+
"files": [],
311+
"references": [{ "path": "/apath" }]
312+
}`;
313+
assertParseFileDiagnosticsExclusion(content,
314+
"/apath/tsconfig.json",
315+
"tests/cases/unittests",
316+
["/apath/a.ts"],
317+
Diagnostics.The_files_list_in_config_file_0_is_empty.code);
318+
});
319+
283320
it("generates errors for directory with no .ts files", () => {
284321
const content = `{
285322
}`;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts(5,1): error TS2554: Expected 3 arguments, but got 2.
2+
tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts(7,1): error TS2554: Expected 3 arguments, but got 2.
3+
4+
5+
==== tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts (2 errors) ====
6+
function foo(a, b, {c}): void {}
7+
8+
function bar(a, b, [c]): void {}
9+
10+
foo("", 0);
11+
~~~~~~~~~~
12+
!!! error TS2554: Expected 3 arguments, but got 2.
13+
!!! related TS6211 tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts:1:20: An argument matching this binding pattern was not provided.
14+
15+
bar("", 0);
16+
~~~~~~~~~~
17+
!!! error TS2554: Expected 3 arguments, but got 2.
18+
!!! related TS6211 tests/cases/compiler/arityErrorRelatedSpanBindingPattern.ts:3:20: An argument matching this binding pattern was not provided.
19+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [arityErrorRelatedSpanBindingPattern.ts]
2+
function foo(a, b, {c}): void {}
3+
4+
function bar(a, b, [c]): void {}
5+
6+
foo("", 0);
7+
8+
bar("", 0);
9+
10+
11+
//// [arityErrorRelatedSpanBindingPattern.js]
12+
function foo(a, b, _a) {
13+
var c = _a.c;
14+
}
15+
function bar(a, b, _a) {
16+
var c = _a[0];
17+
}
18+
foo("", 0);
19+
bar("", 0);

0 commit comments

Comments
 (0)