Skip to content

Commit d5c18a6

Browse files
authored
Merge branch 'master' into AddDefinitionAndBoundSpan
2 parents c4a675e + a89c055 commit d5c18a6

File tree

150 files changed

+3276
-811
lines changed

Some content is hidden

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

150 files changed

+3276
-811
lines changed

src/compiler/binder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ namespace ts {
192192
return bindSourceFile;
193193

194194
function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean {
195-
if ((opts.alwaysStrict === undefined ? opts.strict : opts.alwaysStrict) && !file.isDeclarationFile) {
195+
if (getStrictOptionValue(opts, "alwaysStrict") && !file.isDeclarationFile) {
196196
// bind in strict mode source files with alwaysStrict option
197197
return true;
198198
}

src/compiler/checker.ts

+170-64
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,13 @@ namespace ts {
11381138
reportInvalidOptionValue(option && option.type !== "number");
11391139
return Number((<NumericLiteral>valueExpression).text);
11401140

1141+
case SyntaxKind.PrefixUnaryExpression:
1142+
if ((<PrefixUnaryExpression>valueExpression).operator !== SyntaxKind.MinusToken || (<PrefixUnaryExpression>valueExpression).operand.kind !== SyntaxKind.NumericLiteral) {
1143+
break; // not valid JSON syntax
1144+
}
1145+
reportInvalidOptionValue(option && option.type !== "number");
1146+
return -Number((<NumericLiteral>(<PrefixUnaryExpression>valueExpression).operand).text);
1147+
11411148
case SyntaxKind.ObjectLiteralExpression:
11421149
reportInvalidOptionValue(option && option.type !== "object");
11431150
const objectLiteralExpression = <ObjectLiteralExpression>valueExpression;

src/compiler/core.ts

+6
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,12 @@ namespace ts {
17101710
return moduleResolution;
17111711
}
17121712

1713+
export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "alwaysStrict";
1714+
1715+
export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean {
1716+
return compilerOptions[flag] === undefined ? compilerOptions.strict : compilerOptions[flag];
1717+
}
1718+
17131719
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
17141720
let seenAsterisk = false;
17151721
for (let i = 0; i < str.length; i++) {

src/compiler/program.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,7 @@ namespace ts {
21312131
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib");
21322132
}
21332133

2134-
if (options.noImplicitUseStrict && (options.alwaysStrict === undefined ? options.strict : options.alwaysStrict)) {
2134+
if (options.noImplicitUseStrict && getStrictOptionValue(options, "alwaysStrict")) {
21352135
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict");
21362136
}
21372137

@@ -2360,7 +2360,7 @@ namespace ts {
23602360
return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
23612361
}
23622362
function needAllowJs() {
2363-
return options.allowJs || !options.noImplicitAny ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
2363+
return options.allowJs || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
23642364
}
23652365
}
23662366

src/compiler/transformers/module/module.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ namespace ts {
9191
startLexicalEnvironment();
9292

9393
const statements: Statement[] = [];
94-
const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
94+
const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
9595
const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor);
9696

9797
if (shouldEmitUnderscoreUnderscoreESModule()) {

src/compiler/transformers/module/system.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ namespace ts {
225225
startLexicalEnvironment();
226226

227227
// Add any prologue directives.
228-
const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
228+
const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
229229
const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor);
230230

231231
// var __moduleName = context_1 && context_1.id;

src/compiler/transformers/ts.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace ts {
4545

4646
const resolver = context.getEmitResolver();
4747
const compilerOptions = context.getCompilerOptions();
48-
const strictNullChecks = typeof compilerOptions.strictNullChecks === "undefined" ? compilerOptions.strict : compilerOptions.strictNullChecks;
48+
const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
4949
const languageVersion = getEmitScriptTarget(compilerOptions);
5050
const moduleKind = getEmitModuleKind(compilerOptions);
5151

@@ -521,7 +521,7 @@ namespace ts {
521521
}
522522

523523
function visitSourceFile(node: SourceFile) {
524-
const alwaysStrict = (compilerOptions.alwaysStrict === undefined ? compilerOptions.strict : compilerOptions.alwaysStrict) &&
524+
const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") &&
525525
!(isExternalModule(node) && moduleKind >= ModuleKind.ES2015);
526526
return updateSourceFileNode(
527527
node,

src/compiler/tsc.ts

+1-13
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,12 @@ namespace ts {
4343
return s;
4444
}
4545

46-
function isJSONSupported() {
47-
return typeof JSON === "object" && typeof JSON.parse === "function";
48-
}
49-
5046
export function executeCommandLine(args: string[]): void {
5147
const commandLine = parseCommandLine(args);
5248

5349
// Configuration file name (if any)
5450
let configFileName: string;
5551
if (commandLine.options.locale) {
56-
if (!isJSONSupported()) {
57-
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale"));
58-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
59-
}
6052
validateLocaleAndSetLanguage(commandLine.options.locale, sys, commandLine.errors);
6153
}
6254

@@ -84,10 +76,6 @@ namespace ts {
8476
}
8577

8678
if (commandLine.options.project) {
87-
if (!isJSONSupported()) {
88-
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project"));
89-
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
90-
}
9179
if (commandLine.fileNames.length !== 0) {
9280
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line));
9381
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
@@ -109,7 +97,7 @@ namespace ts {
10997
}
11098
}
11199
}
112-
else if (commandLine.fileNames.length === 0 && isJSONSupported()) {
100+
else if (commandLine.fileNames.length === 0) {
113101
const searchPath = normalizePath(sys.getCurrentDirectory());
114102
configFileName = findConfigFile(searchPath, sys.fileExists);
115103
}

src/compiler/types.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ namespace ts {
362362
JSDocFunctionType,
363363
JSDocVariadicType,
364364
JSDocComment,
365+
JSDocTypeLiteral,
365366
JSDocTag,
366367
JSDocAugmentsTag,
367368
JSDocClassTag,
@@ -371,7 +372,6 @@ namespace ts {
371372
JSDocTemplateTag,
372373
JSDocTypedefTag,
373374
JSDocPropertyTag,
374-
JSDocTypeLiteral,
375375

376376
// Synthesized list
377377
SyntaxList,
@@ -413,9 +413,9 @@ namespace ts {
413413
LastBinaryOperator = CaretEqualsToken,
414414
FirstNode = QualifiedName,
415415
FirstJSDocNode = JSDocTypeExpression,
416-
LastJSDocNode = JSDocTypeLiteral,
416+
LastJSDocNode = JSDocPropertyTag,
417417
FirstJSDocTagNode = JSDocTag,
418-
LastJSDocTagNode = JSDocTypeLiteral
418+
LastJSDocTagNode = JSDocPropertyTag
419419
}
420420

421421
export const enum NodeFlags {
@@ -3327,6 +3327,7 @@ namespace ts {
33273327
ObjectLiteral = 1 << 7, // Originates in an object literal
33283328
EvolvingArray = 1 << 8, // Evolving array type
33293329
ObjectLiteralPatternWithComputedProperties = 1 << 9, // Object literal pattern with computed properties
3330+
ContainsSpread = 1 << 10, // Object literal contains spread operation
33303331
ClassOrInterface = Class | Interface
33313332
}
33323333

@@ -3609,6 +3610,14 @@ namespace ts {
36093610
compareTypes: TypeComparer; // Type comparer function
36103611
}
36113612

3613+
/* @internal */
3614+
export interface WideningContext {
3615+
parent?: WideningContext; // Parent context
3616+
propertyName?: __String; // Name of property in parent
3617+
siblings?: Type[]; // Types of siblings
3618+
resolvedPropertyNames?: __String[]; // Property names occurring in sibling object literals
3619+
}
3620+
36123621
/* @internal */
36133622
export const enum SpecialPropertyAssignmentKind {
36143623
None,

src/harness/fourslash.ts

+29-23
Original file line numberDiff line numberDiff line change
@@ -818,13 +818,13 @@ namespace FourSlash {
818818
});
819819
}
820820

821-
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean) {
821+
public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean) {
822822
const completions = this.getCompletionListAtCaret();
823823
if (completions) {
824-
this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind, spanIndex, hasAction);
824+
this.assertItemInCompletionList(completions.entries, entryId, text, documentation, kind, spanIndex, hasAction);
825825
}
826826
else {
827-
this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${symbol}'.`);
827+
this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${JSON.stringify(entryId)}'.`);
828828
}
829829
}
830830

@@ -839,7 +839,7 @@ namespace FourSlash {
839839
* @param expectedKind the kind of symbol (see ScriptElementKind)
840840
* @param spanIndex the index of the range that the completion item's replacement text span should match
841841
*/
842-
public verifyCompletionListDoesNotContain(symbol: string, expectedText?: string, expectedDocumentation?: string, expectedKind?: string, spanIndex?: number) {
842+
public verifyCompletionListDoesNotContain(entryId: ts.Completions.CompletionEntryIdentifier, expectedText?: string, expectedDocumentation?: string, expectedKind?: string, spanIndex?: number) {
843843
const that = this;
844844
let replacementSpan: ts.TextSpan;
845845
if (spanIndex !== undefined) {
@@ -868,14 +868,14 @@ namespace FourSlash {
868868

869869
const completions = this.getCompletionListAtCaret();
870870
if (completions) {
871-
let filterCompletions = completions.entries.filter(e => e.name === symbol);
871+
let filterCompletions = completions.entries.filter(e => e.name === entryId.name && e.source === entryId.source);
872872
filterCompletions = expectedKind ? filterCompletions.filter(e => e.kind === expectedKind) : filterCompletions;
873873
filterCompletions = filterCompletions.filter(filterByTextOrDocumentation);
874874
if (filterCompletions.length !== 0) {
875875
// After filtered using all present criterion, if there are still symbol left in the list
876876
// then these symbols must meet the criterion for Not supposed to be in the list. So we
877877
// raise an error
878-
let error = "Completion list did contain \'" + symbol + "\'.";
878+
let error = `Completion list did contain '${JSON.stringify(entryId)}\'.`;
879879
const details = this.getCompletionEntryDetails(filterCompletions[0].name);
880880
if (expectedText) {
881881
error += "Expected text: " + expectedText + " to equal: " + ts.displayPartsToString(details.displayParts) + ".";
@@ -1165,8 +1165,8 @@ Actual: ${stringify(fullActual)}`);
11651165
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition);
11661166
}
11671167

1168-
private getCompletionEntryDetails(entryName: string) {
1169-
return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings);
1168+
private getCompletionEntryDetails(entryName: string, source?: string) {
1169+
return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source);
11701170
}
11711171

11721172
private getReferencesAtCaret() {
@@ -1675,7 +1675,7 @@ Actual: ${stringify(fullActual)}`);
16751675
const longestNameLength = max(entries, m => m.name.length);
16761676
const longestKindLength = max(entries, m => m.kind.length);
16771677
entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0);
1678-
const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n");
1678+
const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers} ${m.source === undefined ? "" : m.source}`).join("\n");
16791679
Harness.IO.log(membersString);
16801680
}
16811681

@@ -2331,13 +2331,13 @@ Actual: ${stringify(fullActual)}`);
23312331
public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) {
23322332
this.goToMarker(markerName);
23332333

2334-
const actualCompletion = this.getCompletionListAtCaret().entries.find(e => e.name === options.name);
2334+
const actualCompletion = this.getCompletionListAtCaret().entries.find(e => e.name === options.name && e.source === options.source);
23352335

23362336
if (!actualCompletion.hasAction) {
23372337
this.raiseError(`Completion for ${options.name} does not have an associated action.`);
23382338
}
23392339

2340-
const details = this.getCompletionEntryDetails(options.name);
2340+
const details = this.getCompletionEntryDetails(options.name, actualCompletion.source);
23412341
if (details.codeActions.length !== 1) {
23422342
this.raiseError(`Expected one code action, got ${details.codeActions.length}`);
23432343
}
@@ -3019,33 +3019,35 @@ Actual: ${stringify(fullActual)}`);
30193019

30203020
private assertItemInCompletionList(
30213021
items: ts.CompletionEntry[],
3022-
name: string,
3022+
entryId: ts.Completions.CompletionEntryIdentifier,
30233023
text: string | undefined,
30243024
documentation: string | undefined,
30253025
kind: string | undefined,
30263026
spanIndex: number | undefined,
30273027
hasAction: boolean | undefined,
30283028
) {
30293029
for (const item of items) {
3030-
if (item.name === name) {
3031-
if (documentation !== undefined || text !== undefined) {
3032-
const details = this.getCompletionEntryDetails(item.name);
3030+
if (item.name === entryId.name && item.source === entryId.source) {
3031+
if (documentation !== undefined || text !== undefined || entryId.source !== undefined) {
3032+
const details = this.getCompletionEntryDetails(item.name, item.source);
30333033

30343034
if (documentation !== undefined) {
3035-
assert.equal(ts.displayPartsToString(details.documentation), documentation, this.assertionMessageAtLastKnownMarker("completion item documentation for " + name));
3035+
assert.equal(ts.displayPartsToString(details.documentation), documentation, this.assertionMessageAtLastKnownMarker("completion item documentation for " + entryId));
30363036
}
30373037
if (text !== undefined) {
3038-
assert.equal(ts.displayPartsToString(details.displayParts), text, this.assertionMessageAtLastKnownMarker("completion item detail text for " + name));
3038+
assert.equal(ts.displayPartsToString(details.displayParts), text, this.assertionMessageAtLastKnownMarker("completion item detail text for " + entryId));
30393039
}
3040+
3041+
assert.deepEqual(details.source, entryId.source === undefined ? undefined : [ts.textPart(entryId.source)]);
30403042
}
30413043

30423044
if (kind !== undefined) {
3043-
assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + name));
3045+
assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + entryId));
30443046
}
30453047

30463048
if (spanIndex !== undefined) {
30473049
const span = this.getTextSpanForRangeAtIndex(spanIndex);
3048-
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + name));
3050+
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + entryId));
30493051
}
30503052

30513053
assert.equal(item.hasAction, hasAction);
@@ -3056,7 +3058,7 @@ Actual: ${stringify(fullActual)}`);
30563058

30573059
const itemsString = items.map(item => stringify({ name: item.name, kind: item.kind })).join(",\n");
30583060

3059-
this.raiseError(`Expected "${stringify({ name, text, documentation, kind })}" to be in list [${itemsString}]`);
3061+
this.raiseError(`Expected "${stringify({ entryId, text, documentation, kind })}" to be in list [${itemsString}]`);
30603062
}
30613063

30623064
private findFile(indexOrName: any) {
@@ -3767,12 +3769,15 @@ namespace FourSlashInterface {
37673769

37683770
// Verifies the completion list contains the specified symbol. The
37693771
// completion list is brought up if necessary
3770-
public completionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean) {
3772+
public completionListContains(entryId: string | ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean) {
3773+
if (typeof entryId === "string") {
3774+
entryId = { name: entryId, source: undefined };
3775+
}
37713776
if (this.negative) {
3772-
this.state.verifyCompletionListDoesNotContain(symbol, text, documentation, kind, spanIndex);
3777+
this.state.verifyCompletionListDoesNotContain(entryId, text, documentation, kind, spanIndex);
37733778
}
37743779
else {
3775-
this.state.verifyCompletionListContains(symbol, text, documentation, kind, spanIndex, hasAction);
3780+
this.state.verifyCompletionListContains(entryId, text, documentation, kind, spanIndex, hasAction);
37763781
}
37773782
}
37783783

@@ -4528,6 +4533,7 @@ namespace FourSlashInterface {
45284533

45294534
export interface VerifyCompletionActionOptions extends NewContentOptions {
45304535
name: string;
4536+
source?: string;
45314537
description: string;
45324538
}
45334539
}

0 commit comments

Comments
 (0)