Skip to content

Commit 5eb1cc4

Browse files
committed
Merge remote-tracking branch 'upstream/master' into jsDoc2
2 parents e223b2e + a861913 commit 5eb1cc4

76 files changed

Lines changed: 1622 additions & 343 deletions

File tree

Some content is hidden

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

src/compiler/checker.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8228,31 +8228,12 @@ namespace ts {
82288228
return jsxElementType || anyType;
82298229
}
82308230

8231-
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
8232-
if (lhs.kind !== rhs.kind) {
8233-
return false;
8234-
}
8235-
8236-
if (lhs.kind === SyntaxKind.Identifier) {
8237-
return (<Identifier>lhs).text === (<Identifier>rhs).text;
8238-
}
8239-
8240-
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
8241-
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
8242-
}
8243-
82448231
function checkJsxElement(node: JsxElement) {
82458232
// Check attributes
82468233
checkJsxOpeningLikeElement(node.openingElement);
82478234

8248-
// Check that the closing tag matches
8249-
if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) {
8250-
error(node.closingElement, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNode(node.openingElement.tagName));
8251-
}
8252-
else {
8253-
// Perform resolution on the closing tag so that rename/go to definition/etc work
8254-
getJsxElementTagSymbol(node.closingElement);
8255-
}
8235+
// Perform resolution on the closing tag so that rename/go to definition/etc work
8236+
getJsxElementTagSymbol(node.closingElement);
82568237

82578238
// Check children
82588239
for (const child of node.children) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,5 +2586,9 @@
25862586
"A type assertion expression is not allowed in the left-hand side of an exponentiation expression. Consider enclosing the expression in parentheses.": {
25872587
"category": "Error",
25882588
"code": 17007
2589+
},
2590+
"JSX element '{0}' has no corresponding closing tag.": {
2591+
"category": "Error",
2592+
"code": 17008
25892593
}
25902594
}

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6990,7 +6990,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
69906990

69916991
write(text);
69926992
}
6993-
write(`], function(${exportFunctionForFile}, __moduleName) {`);
6993+
write(`], function(${exportFunctionForFile}) {`);
69946994
writeLine();
69956995
increaseIndent();
69966996
const startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true, /*ensureUseStrict*/ true);

src/compiler/parser.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3478,6 +3478,20 @@ namespace ts {
34783478
return finishNode(node);
34793479
}
34803480

3481+
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
3482+
if (lhs.kind !== rhs.kind) {
3483+
return false;
3484+
}
3485+
3486+
if (lhs.kind === SyntaxKind.Identifier) {
3487+
return (<Identifier>lhs).text === (<Identifier>rhs).text;
3488+
}
3489+
3490+
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
3491+
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
3492+
}
3493+
3494+
34813495
function parseJsxElementOrSelfClosingElement(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement {
34823496
const opening = parseJsxOpeningOrSelfClosingElement(inExpressionContext);
34833497
let result: JsxElement | JsxSelfClosingElement;
@@ -3487,6 +3501,11 @@ namespace ts {
34873501

34883502
node.children = parseJsxChildren(node.openingElement.tagName);
34893503
node.closingElement = parseJsxClosingElement(inExpressionContext);
3504+
3505+
if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) {
3506+
parseErrorAtPosition(node.closingElement.pos, node.closingElement.end - node.closingElement.pos, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, node.openingElement.tagName));
3507+
}
3508+
34903509
result = finishNode(node);
34913510
}
34923511
else {
@@ -3546,10 +3565,13 @@ namespace ts {
35463565
while (true) {
35473566
token = scanner.reScanJsxToken();
35483567
if (token === SyntaxKind.LessThanSlashToken) {
3568+
// Closing tag
35493569
break;
35503570
}
35513571
else if (token === SyntaxKind.EndOfFileToken) {
3552-
parseErrorAtCurrentToken(Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, openingTagName));
3572+
// If we hit EOF, issue the error at the tag that lacks the closing element
3573+
// rather than at the end of the file (which is useless)
3574+
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
35533575
break;
35543576
}
35553577
result.push(parseJsxChild());

src/compiler/program.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ namespace ts {
5353
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
5454
const failedLookupLocations: string[] = [];
5555
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
56-
let resolvedFileName = loadNodeModuleFromFile(supportedExtensions, candidate, failedLookupLocations, host);
56+
let resolvedFileName = loadNodeModuleFromFile(supportedExtensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, host);
5757

5858
if (resolvedFileName) {
5959
return { resolvedModule: { resolvedFileName }, failedLookupLocations };
6060
}
6161

62-
resolvedFileName = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, host);
62+
resolvedFileName = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, host);
6363
return resolvedFileName
6464
? { resolvedModule: { resolvedFileName }, failedLookupLocations }
6565
: { resolvedModule: undefined, failedLookupLocations };
@@ -69,12 +69,22 @@ namespace ts {
6969
}
7070
}
7171

72-
function loadNodeModuleFromFile(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
72+
/* @internal */
73+
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean } ): boolean {
74+
// if host does not support 'directoryExists' assume that directory will exist
75+
return !host.directoryExists || host.directoryExists(directoryName);
76+
}
77+
78+
/**
79+
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
80+
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
81+
*/
82+
function loadNodeModuleFromFile(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, host: ModuleResolutionHost): string {
7383
return forEach(extensions, tryLoad);
7484

7585
function tryLoad(ext: string): string {
7686
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
77-
if (host.fileExists(fileName)) {
87+
if (!onlyRecordFailures && host.fileExists(fileName)) {
7888
return fileName;
7989
}
8090
else {
@@ -84,9 +94,10 @@ namespace ts {
8494
}
8595
}
8696

87-
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
97+
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, host: ModuleResolutionHost): string {
8898
const packageJsonPath = combinePaths(candidate, "package.json");
89-
if (host.fileExists(packageJsonPath)) {
99+
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, host);
100+
if (directoryExists && host.fileExists(packageJsonPath)) {
90101

91102
let jsonContent: { typings?: string };
92103

@@ -100,7 +111,8 @@ namespace ts {
100111
}
101112

102113
if (typeof jsonContent.typings === "string") {
103-
const result = loadNodeModuleFromFile(extensions, normalizePath(combinePaths(candidate, jsonContent.typings)), failedLookupLocation, host);
114+
const path = normalizePath(combinePaths(candidate, jsonContent.typings));
115+
const result = loadNodeModuleFromFile(extensions, path, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(path), host), host);
104116
if (result) {
105117
return result;
106118
}
@@ -111,7 +123,7 @@ namespace ts {
111123
failedLookupLocation.push(packageJsonPath);
112124
}
113125

114-
return loadNodeModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocation, host);
126+
return loadNodeModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocation, !directoryExists, host);
115127
}
116128

117129
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
@@ -121,14 +133,15 @@ namespace ts {
121133
const baseName = getBaseFileName(directory);
122134
if (baseName !== "node_modules") {
123135
const nodeModulesFolder = combinePaths(directory, "node_modules");
136+
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, host);
124137
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
125138
// Load only typescript files irrespective of allowJs option if loading from node modules
126-
let result = loadNodeModuleFromFile(supportedTypeScriptExtensions, candidate, failedLookupLocations, host);
139+
let result = loadNodeModuleFromFile(supportedTypeScriptExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, host);
127140
if (result) {
128141
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
129142
}
130143

131-
result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, host);
144+
result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, host);
132145
if (result) {
133146
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
134147
}
@@ -281,7 +294,8 @@ namespace ts {
281294
getCanonicalFileName,
282295
getNewLine: () => newLine,
283296
fileExists: fileName => sys.fileExists(fileName),
284-
readFile: fileName => sys.readFile(fileName)
297+
readFile: fileName => sys.readFile(fileName),
298+
directoryExists: directoryName => sys.directoryExists(directoryName)
285299
};
286300
}
287301

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,6 +2649,8 @@ namespace ts {
26492649
// readFile function is used to read arbitrary text files on disk, i.e. when resolution procedure needs the content of 'package.json'
26502650
// to determine location of bundled typings for node module
26512651
readFile(fileName: string): string;
2652+
2653+
directoryExists?(directoryName: string): boolean;
26522654
}
26532655

26542656
export interface ResolvedModule {

src/harness/harnessLanguageService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,10 @@ namespace Harness.LanguageService {
267267
log(s: string): void { this.nativeHost.log(s); }
268268
trace(s: string): void { this.nativeHost.trace(s); }
269269
error(s: string): void { this.nativeHost.error(s); }
270+
directoryExists(directoryName: string): boolean {
271+
// for tests pessimistically assume that directory always exists
272+
return true;
273+
}
270274
}
271275

272276
class ClassifierShimProxy implements ts.Classifier {

src/lib/dom.generated.d.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ interface AudioContext extends EventTarget {
321321
destination: AudioDestinationNode;
322322
listener: AudioListener;
323323
sampleRate: number;
324+
state: string;
324325
createAnalyser(): AnalyserNode;
325326
createBiquadFilter(): BiquadFilterNode;
326327
createBuffer(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer;
@@ -2774,6 +2775,7 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec
27742775
tagName: string;
27752776
id: string;
27762777
className: string;
2778+
innerHTML: string;
27772779
getAttribute(name?: string): string;
27782780
getAttributeNS(namespaceURI: string, localName: string): string;
27792781
getAttributeNode(name: string): Attr;
@@ -2969,7 +2971,7 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec
29692971
removeAttributeNode(oldAttr: Attr): Attr;
29702972
requestFullscreen(): void;
29712973
requestPointerLock(): void;
2972-
setAttribute(name?: string, value?: string): void;
2974+
setAttribute(name: string, value: string): void;
29732975
setAttributeNS(namespaceURI: string, qualifiedName: string, value: string): void;
29742976
setAttributeNode(newAttr: Attr): Attr;
29752977
setAttributeNodeNS(newAttr: Attr): Attr;
@@ -5512,7 +5514,7 @@ interface HTMLMediaElement extends HTMLElement {
55125514
* Gets or sets the current playback position, in seconds.
55135515
*/
55145516
preload: string;
5515-
readyState: any;
5517+
readyState: number;
55165518
/**
55175519
* Returns a TimeRanges object that represents the ranges of the current media resource that can be seeked.
55185520
*/
@@ -6169,6 +6171,7 @@ interface HTMLSelectElement extends HTMLElement {
61696171
* Returns whether an element will successfully validate based on forms validation rules and constraints.
61706172
*/
61716173
willValidate: boolean;
6174+
selectedOptions: HTMLCollection;
61726175
/**
61736176
* Adds an element to the areas, controlRange, or options collection.
61746177
* @param element Variant of type Number that specifies the index position in the collection where the element is placed. If no value is given, the method places the element at the end of the collection.

0 commit comments

Comments
 (0)