Skip to content

Commit 61fe04b

Browse files
committed
Merge branch 'master' into jsdoc-values-as-namespaces
2 parents e441dd0 + 5ee640d commit 61fe04b

84 files changed

Lines changed: 3049 additions & 766 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.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,4 @@ tests/cases/user/*/**/*.d.ts
6767
!tests/cases/user/zone.js/
6868
!tests/cases/user/bignumber.js/
6969
!tests/cases/user/discord.js/
70+
tests/baselines/reference/dt

lib/typescript.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4487,9 +4487,9 @@ declare namespace ts {
44874487
* @param compilationSettings Some compilation settings like target affects the
44884488
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
44894489
* multiple copies of the same file for different compilation settings.
4490-
* @parm scriptSnapshot Text of the file. Only used if the file was not found
4490+
* @param scriptSnapshot Text of the file. Only used if the file was not found
44914491
* in the registry and a new one was created.
4492-
* @parm version Current version of the file. Only used if the file was not found
4492+
* @param version Current version of the file. Only used if the file was not found
44934493
* in the registry and a new one was created.
44944494
*/
44954495
acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile;

lib/typescriptServices.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4487,9 +4487,9 @@ declare namespace ts {
44874487
* @param compilationSettings Some compilation settings like target affects the
44884488
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
44894489
* multiple copies of the same file for different compilation settings.
4490-
* @parm scriptSnapshot Text of the file. Only used if the file was not found
4490+
* @param scriptSnapshot Text of the file. Only used if the file was not found
44914491
* in the registry and a new one was created.
4492-
* @parm version Current version of the file. Only used if the file was not found
4492+
* @param version Current version of the file. Only used if the file was not found
44934493
* in the registry and a new one was created.
44944494
*/
44954495
acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile;

src/compiler/checker.ts

Lines changed: 107 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ namespace ts {
251251
getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type),
252252
getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
253253
getBaseConstraintOfType,
254+
getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined,
254255
resolveName(name, location, meaning) {
255256
return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false);
256257
},
@@ -4054,25 +4055,30 @@ namespace ts {
40544055
}
40554056
}
40564057

4057-
function collectLinkedAliases(node: Identifier): Node[] {
4058+
function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined {
40584059
let exportSymbol: Symbol;
40594060
if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) {
4060-
exportSymbol = resolveName(node.parent, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, Diagnostics.Cannot_find_name_0, node, /*isUse*/ false);
4061+
exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false);
40614062
}
40624063
else if (node.parent.kind === SyntaxKind.ExportSpecifier) {
40634064
exportSymbol = getTargetOfExportSpecifier(<ExportSpecifier>node.parent, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
40644065
}
4065-
const result: Node[] = [];
4066+
let result: Node[];
40664067
if (exportSymbol) {
40674068
buildVisibleNodeList(exportSymbol.declarations);
40684069
}
40694070
return result;
40704071

40714072
function buildVisibleNodeList(declarations: Declaration[]) {
40724073
forEach(declarations, declaration => {
4073-
getNodeLinks(declaration).isVisible = true;
40744074
const resultNode = getAnyImportSyntax(declaration) || declaration;
4075-
pushIfUnique(result, resultNode);
4075+
if (setVisibility) {
4076+
getNodeLinks(declaration).isVisible = true;
4077+
}
4078+
else {
4079+
result = result || [];
4080+
pushIfUnique(result, resultNode);
4081+
}
40764082

40774083
if (isInternalModuleImportEqualsDeclaration(declaration)) {
40784084
// Add the referenced top container visible
@@ -4231,7 +4237,7 @@ namespace ts {
42314237
/** Return the inferred type for a binding element */
42324238
function getTypeForBindingElement(declaration: BindingElement): Type {
42334239
const pattern = declaration.parent;
4234-
const parentType = getTypeForBindingElementParent(pattern.parent);
4240+
let parentType = getTypeForBindingElementParent(pattern.parent);
42354241
// If parent has the unknown (error) type, then so does this binding element
42364242
if (parentType === unknownType) {
42374243
return unknownType;
@@ -4273,6 +4279,10 @@ namespace ts {
42734279
// or otherwise the type of the string index signature.
42744280
const text = getTextOfPropertyName(name);
42754281

4282+
// Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation
4283+
if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) {
4284+
parentType = getNonNullableType(parentType);
4285+
}
42764286
const declaredType = getTypeOfPropertyOfType(parentType, text);
42774287
type = declaredType && getFlowTypeOfReference(declaration, declaredType) ||
42784288
isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
@@ -15746,61 +15756,95 @@ namespace ts {
1574615756
* except for candidates:
1574715757
* * With no name
1574815758
* * Whose meaning doesn't match the `meaning` parameter.
15749-
* * Whose length differs from the target name by more than 0.3 of the length of the name.
15759+
* * Whose length differs from the target name by more than 0.34 of the length of the name.
1575015760
* * Whose levenshtein distance is more than 0.4 of the length of the name
1575115761
* (0.4 allows 1 substitution/transposition for every 5 characters,
1575215762
* and 1 insertion/deletion at 3 characters)
15753-
* Names longer than 30 characters don't get suggestions because Levenshtein distance is an n**2 algorithm.
1575415763
*/
1575515764
function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined {
15756-
const worstDistance = name.length * 0.4;
15757-
const maximumLengthDifference = Math.min(3, name.length * 0.34);
15758-
let bestDistance = Number.MAX_VALUE;
15759-
let bestCandidate = undefined;
15765+
const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
15766+
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
15767+
let bestCandidate: Symbol | undefined;
1576015768
let justCheckExactMatches = false;
15761-
if (name.length > 30) {
15762-
return undefined;
15763-
}
15764-
name = name.toLowerCase();
15769+
const nameLowerCase = name.toLowerCase();
1576515770
for (const candidate of symbols) {
15766-
let candidateName = symbolName(candidate);
15767-
if (candidate.flags & meaning &&
15768-
candidateName &&
15769-
Math.abs(candidateName.length - name.length) < maximumLengthDifference) {
15770-
candidateName = candidateName.toLowerCase();
15771-
if (candidateName === name) {
15772-
return candidate;
15773-
}
15774-
if (justCheckExactMatches) {
15775-
continue;
15776-
}
15777-
if (candidateName.length < 3 ||
15778-
name.length < 3 ||
15779-
candidateName === "eval" ||
15780-
candidateName === "intl" ||
15781-
candidateName === "undefined" ||
15782-
candidateName === "map" ||
15783-
candidateName === "nan" ||
15784-
candidateName === "set") {
15785-
continue;
15786-
}
15787-
const distance = levenshtein(name, candidateName);
15788-
if (distance > worstDistance) {
15789-
continue;
15790-
}
15791-
if (distance < 3) {
15792-
justCheckExactMatches = true;
15793-
bestCandidate = candidate;
15794-
}
15795-
else if (distance < bestDistance) {
15796-
bestDistance = distance;
15797-
bestCandidate = candidate;
15798-
}
15771+
const candidateName = symbolName(candidate);
15772+
if (!(candidate.flags & meaning && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference)) {
15773+
continue;
15774+
}
15775+
const candidateNameLowerCase = candidateName.toLowerCase();
15776+
if (candidateNameLowerCase === nameLowerCase) {
15777+
return candidate;
15778+
}
15779+
if (justCheckExactMatches) {
15780+
continue;
15781+
}
15782+
if (candidateName.length < 3) {
15783+
// Don't bother, user would have noticed a 2-character name having an extra character
15784+
continue;
15785+
}
15786+
// Only care about a result better than the best so far.
15787+
const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
15788+
if (distance === undefined) {
15789+
continue;
15790+
}
15791+
if (distance < 3) {
15792+
justCheckExactMatches = true;
15793+
bestCandidate = candidate;
15794+
}
15795+
else {
15796+
Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
15797+
bestDistance = distance;
15798+
bestCandidate = candidate;
1579915799
}
1580015800
}
1580115801
return bestCandidate;
1580215802
}
1580315803

15804+
function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined {
15805+
let previous = new Array(s2.length + 1);
15806+
let current = new Array(s2.length + 1);
15807+
/** Represents any value > max. We don't care about the particular value. */
15808+
const big = max + 1;
15809+
15810+
for (let i = 0; i <= s2.length; i++) {
15811+
previous[i] = i;
15812+
}
15813+
15814+
for (let i = 1; i <= s1.length; i++) {
15815+
const c1 = s1.charCodeAt(i - 1);
15816+
const minJ = i > max ? i - max : 1;
15817+
const maxJ = s2.length > max + i ? max + i : s2.length;
15818+
current[0] = i;
15819+
/** Smallest value of the matrix in the ith column. */
15820+
let colMin = i;
15821+
for (let j = 1; j < minJ; j++) {
15822+
current[j] = big;
15823+
}
15824+
for (let j = minJ; j <= maxJ; j++) {
15825+
const dist = c1 === s2.charCodeAt(j - 1)
15826+
? previous[j - 1]
15827+
: Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
15828+
current[j] = dist;
15829+
colMin = Math.min(colMin, dist);
15830+
}
15831+
for (let j = maxJ + 1; j <= s2.length; j++) {
15832+
current[j] = big;
15833+
}
15834+
if (colMin > max) {
15835+
// Give up -- everything in this column is > max and it can't get better in future columns.
15836+
return undefined;
15837+
}
15838+
15839+
const temp = previous;
15840+
previous = current;
15841+
current = temp;
15842+
}
15843+
15844+
const res = previous[s2.length];
15845+
return res > max ? undefined : res;
15846+
}
15847+
1580415848
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) {
1580515849
if (prop &&
1580615850
noUnusedIdentifiers &&
@@ -23335,6 +23379,9 @@ namespace ts {
2333523379

2333623380
function checkExportSpecifier(node: ExportSpecifier) {
2333723381
checkAliasSymbol(node);
23382+
if (compilerOptions.declaration) {
23383+
collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true);
23384+
}
2333823385
if (!(<ExportDeclaration>node.parent.parent).moduleSpecifier) {
2333923386
const exportedName = node.propertyName || node.name;
2334023387
// find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases)
@@ -23372,6 +23419,10 @@ namespace ts {
2337223419
}
2337323420
if (node.expression.kind === SyntaxKind.Identifier) {
2337423421
markExportAsReferenced(node);
23422+
23423+
if (compilerOptions.declaration) {
23424+
collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true);
23425+
}
2337523426
}
2337623427
else {
2337723428
checkExpressionCached(node.expression);
@@ -26243,14 +26294,17 @@ namespace ts {
2624326294
}
2624426295

2624526296
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
26246-
if (node.typeParameters) {
26247-
return grammarErrorAtPos(node, node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
26297+
const typeParameters = getEffectiveTypeParameterDeclarations(node);
26298+
if (typeParameters) {
26299+
const { pos, end } = isNodeArray(typeParameters) ? typeParameters : first(typeParameters);
26300+
return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
2624826301
}
2624926302
}
2625026303

2625126304
function checkGrammarConstructorTypeAnnotation(node: ConstructorDeclaration) {
26252-
if (node.type) {
26253-
return grammarErrorOnNode(node.type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration);
26305+
const type = getEffectiveReturnTypeNode(node);
26306+
if (type) {
26307+
return grammarErrorOnNode(type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration);
2625426308
}
2625526309
}
2625626310

src/compiler/declarationEmitter.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,10 +1249,18 @@ namespace ts {
12491249
writeLine();
12501250
}
12511251

1252+
function bindingNameContainsVisibleBindingElement(node: BindingName): boolean {
1253+
return !!node && isBindingPattern(node) && some(node.elements, elem => !isOmittedExpression(elem) && isVariableDeclarationVisible(elem));
1254+
}
1255+
1256+
function isVariableDeclarationVisible(node: VariableDeclaration | BindingElement) {
1257+
return resolver.isDeclarationVisible(node) || bindingNameContainsVisibleBindingElement(node.name);
1258+
}
1259+
12521260
function emitVariableDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration) {
12531261
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
12541262
// so there is no check needed to see if declaration is visible
1255-
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
1263+
if (node.kind !== SyntaxKind.VariableDeclaration || isVariableDeclarationVisible(node)) {
12561264
if (isBindingPattern(node.name)) {
12571265
emitBindingPattern(<BindingPattern>node.name);
12581266
}
@@ -1324,14 +1332,14 @@ namespace ts {
13241332
}
13251333

13261334
function emitBindingPattern(bindingPattern: BindingPattern) {
1327-
// Only select non-omitted expression from the bindingPattern's elements.
1335+
// Only select visible, non-omitted expression from the bindingPattern's elements.
13281336
// We have to do this to avoid emitting trailing commas.
13291337
// For example:
13301338
// original: var [, c,,] = [ 2,3,4]
13311339
// emitted: declare var c: number; // instead of declare var c:number, ;
13321340
const elements: Node[] = [];
13331341
for (const element of bindingPattern.elements) {
1334-
if (element.kind !== SyntaxKind.OmittedExpression) {
1342+
if (element.kind !== SyntaxKind.OmittedExpression && isVariableDeclarationVisible(element)) {
13351343
elements.push(element);
13361344
}
13371345
}
@@ -1371,7 +1379,7 @@ namespace ts {
13711379
}
13721380

13731381
function isVariableStatementVisible(node: VariableStatement) {
1374-
return forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
1382+
return forEach(node.declarationList.declarations, varDeclaration => isVariableDeclarationVisible(varDeclaration));
13751383
}
13761384

13771385
function writeVariableStatement(node: VariableStatement) {
@@ -1390,7 +1398,7 @@ namespace ts {
13901398
else {
13911399
write("var ");
13921400
}
1393-
emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible);
1401+
emitCommaList(node.declarationList.declarations, emitVariableDeclaration, isVariableDeclarationVisible);
13941402
write(";");
13951403
writeLine();
13961404
}

src/compiler/diagnosticMessages.json

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3766,7 +3766,7 @@
37663766
"category": "Error",
37673767
"code": 90010
37683768
},
3769-
"Import '{0}' from \"{1}\".": {
3769+
"Import '{0}' from module \"{1}\".": {
37703770
"category": "Message",
37713771
"code": 90013
37723772
},
@@ -3886,13 +3886,5 @@
38863886
"Install '{0}'": {
38873887
"category": "Message",
38883888
"code": 95014
3889-
},
3890-
"Import '{0}' = require(\"{1}\").": {
3891-
"category": "Message",
3892-
"code": 95015
3893-
},
3894-
"Import * as '{0}' from \"{1}\".": {
3895-
"category": "Message",
3896-
"code": 95016
38973889
}
38983890
}

src/compiler/parser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,7 +3281,7 @@ namespace ts {
32813281
// Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This
32823282
// isn't actually allowed, but we want to treat it as a lambda so we can provide
32833283
// a good error message.
3284-
if (isModifierKind(second) && lookAhead(nextTokenIsIdentifier)) {
3284+
if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) {
32853285
return Tristate.True;
32863286
}
32873287

@@ -3298,7 +3298,7 @@ namespace ts {
32983298
return Tristate.True;
32993299
case SyntaxKind.QuestionToken:
33003300
nextToken();
3301-
// If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lamnda.
3301+
// If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda.
33023302
if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) {
33033303
return Tristate.True;
33043304
}

0 commit comments

Comments
 (0)