Merge branch 'master' into fixContextualReturnTypes

# Conflicts:
#	src/compiler/checker.ts
This commit is contained in:
Anders Hejlsberg
2019-02-01 10:28:50 -08:00
168 changed files with 69625 additions and 4024 deletions
+2 -2
View File
@@ -35,8 +35,8 @@ function createCancellationToken(args: string[]): ServerCancellationToken {
}
// cancellationPipeName is a string without '*' inside that can optionally end with '*'
// when client wants to signal cancellation it should create a named pipe with name=<cancellationPipeName>
// server will synchronously check the presence of the pipe and treat its existance as indicator that current request should be canceled.
// in case if client prefers to use more fine-grained schema than one name for all request it can add '*' to the end of cancelellationPipeName.
// server will synchronously check the presence of the pipe and treat its existence as indicator that current request should be canceled.
// in case if client prefers to use more fine-grained schema than one name for all request it can add '*' to the end of cancellationPipeName.
// in this case pipe name will be build dynamically as <cancellationPipeName><request_seq>.
if (cancellationPipeName.charAt(cancellationPipeName.length - 1) === "*") {
const namePrefix = cancellationPipeName.slice(0, -1);
+2 -2
View File
@@ -550,7 +550,7 @@ namespace ts {
}
}
// We create a return control flow graph for IIFEs and constructors. For constructors
// we use the return control flow graph in strict property intialization checks.
// we use the return control flow graph in strict property initialization checks.
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor ? createBranchLabel() : undefined;
currentBreakTarget = undefined;
currentContinueTarget = undefined;
@@ -3445,7 +3445,7 @@ namespace ts {
// If a FunctionDeclaration is generator function and is the body of a
// transformed async function, then this node can be transformed to a
// down-level generator.
// Currently we do not support transforming any other generator fucntions
// Currently we do not support transforming any other generator functions
// down level.
if (node.asteriskToken) {
transformFlags |= TransformFlags.AssertGenerator;
+1 -1
View File
@@ -27,7 +27,7 @@ namespace ts {
currentChangedFilePath: Path | undefined;
/**
* Map of file signatures, with key being file path, calculated while getting current changed file's affected files
* These will be commited whenever the iteration through affected files of current changed file is complete
* These will be committed whenever the iteration through affected files of current changed file is complete
*/
currentAffectedFilesSignatures: Map<string> | undefined;
/**
+3 -3
View File
@@ -37,7 +37,7 @@ namespace ts {
*/
readonly referencedMap: ReadonlyMap<BuilderState.ReferencedSet> | undefined;
/**
* Contains the map of exported modules ReferencedSet=exorted module files from the file if module emit is enabled
* Contains the map of exported modules ReferencedSet=exported module files from the file if module emit is enabled
* Otherwise undefined
*/
readonly exportedModulesMap: Map<BuilderState.ReferencedSet> | undefined;
@@ -268,9 +268,9 @@ namespace ts.BuilderState {
*/
export function getFilesAffectedBy(state: BuilderState, programOfThisState: Program, path: Path, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash, cacheToUpdateSignature?: Map<string>, exportedModulesMapCache?: ComputingExportedModulesMap): ReadonlyArray<SourceFile> {
// Since the operation could be cancelled, the signatures are always stored in the cache
// They will be commited once it is safe to use them
// They will be committed once it is safe to use them
// eg when calling this api from tsserver, if there is no cancellation of the operation
// In the other cases the affected files signatures are commited only after the iteration through the result is complete
// In the other cases the affected files signatures are committed only after the iteration through the result is complete
const signatureCache = cacheToUpdateSignature || createMap();
const sourceFile = programOfThisState.getSourceFileByPath(path);
if (!sourceFile) {
+266 -181
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1935,7 +1935,7 @@ namespace ts {
function directoryOfCombinedPath(fileName: string, basePath: string) {
// Use the `getNormalizedAbsolutePath` function to avoid canonicalizing the path, as it must remain noncanonical
// until consistient casing errors are reported
// until consistent casing errors are reported
return getDirectoryPath(getNormalizedAbsolutePath(fileName, basePath));
}
+1 -1
View File
@@ -1,7 +1,7 @@
namespace ts {
// WARNING: The script `configureNightly.ts` uses a regexp to parse out these values.
// If changing the text in this section, be sure to test `configureNightly` too.
export const versionMajorMinor = "3.3";
export const versionMajorMinor = "3.4";
/** The version of the TypeScript compiler release */
export const version = `${versionMajorMinor}.0-dev`;
}
+31 -3
View File
@@ -1023,6 +1023,14 @@
"category": "Error",
"code": 1353
},
"'readonly' type modifier is only permitted on array and tuple types.": {
"category": "Error",
"code": 1354
},
"A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.": {
"category": "Error",
"code": 1355
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -2092,15 +2100,15 @@
"category": "Error",
"code": 2577
},
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node` and then add `node` to the types field in your tsconfig.": {
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node`.": {
"category": "Error",
"code": 2580
},
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery` and then add `jquery` to the types field in your tsconfig.": {
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`.": {
"category": "Error",
"code": 2581
},
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig.": {
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.": {
"category": "Error",
"code": 2582
},
@@ -2128,6 +2136,26 @@
"category": "Error",
"code": 2588
},
"Type instantiation is excessively deep and possibly infinite.": {
"category": "Error",
"code": 2589
},
"Expression produces a union type that is too complex to represent.": {
"category": "Error",
"code": 2590
},
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node` and then add `node` to the types field in your tsconfig.": {
"category": "Error",
"code": 2591
},
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery` and then add `jquery` to the types field in your tsconfig.": {
"category": "Error",
"code": 2592
},
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig.": {
"category": "Error",
"code": 2593
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
+3 -3
View File
@@ -876,8 +876,8 @@ namespace ts {
}
export function createTypeOperatorNode(type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | TypeNode, type?: TypeNode) {
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | TypeNode, type?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
node.operator = typeof operatorOrType === "number" ? operatorOrType : SyntaxKind.KeyOfKeyword;
node.type = parenthesizeElementTypeMember(typeof operatorOrType === "number" ? type! : operatorOrType);
@@ -2874,7 +2874,7 @@ namespace ts {
return node.emitNode = { annotatedNodes: [node] } as EmitNode;
}
const sourceFile = getSourceFileOfNode(node);
const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node)));
getOrCreateEmitNode(sourceFile).annotatedNodes!.push(node);
}
+3 -1
View File
@@ -2966,6 +2966,7 @@ namespace ts {
case SyntaxKind.NumberKeyword:
case SyntaxKind.BigIntKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UniqueKeyword:
case SyntaxKind.VoidKeyword:
@@ -3055,7 +3056,7 @@ namespace ts {
return finishNode(postfix);
}
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword) {
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) {
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
parseExpected(operator);
node.operator = operator;
@@ -3077,6 +3078,7 @@ namespace ts {
switch (operator) {
case SyntaxKind.KeyOfKeyword:
case SyntaxKind.UniqueKeyword:
case SyntaxKind.ReadonlyKeyword:
return parseTypeOperator(operator);
case SyntaxKind.InferKeyword:
return parseInferType();
+3 -3
View File
@@ -230,18 +230,18 @@ namespace ts {
const readFileWithCache = (fileName: string): string | undefined => {
const key = toPath(fileName);
const value = readFileCache.get(key);
if (value !== undefined) return value || undefined;
if (value !== undefined) return value !== false ? value : undefined;
return setReadFileCache(key, fileName);
};
const setReadFileCache = (key: Path, fileName: string) => {
const newValue = originalReadFile.call(host, fileName);
readFileCache.set(key, newValue || false);
readFileCache.set(key, newValue !== undefined ? newValue : false);
return newValue;
};
host.readFile = fileName => {
const key = toPath(fileName);
const value = readFileCache.get(key);
if (value !== undefined) return value; // could be .d.ts from output
if (value !== undefined) return value !== false ? value : undefined; // could be .d.ts from output
if (!fileExtensionIs(fileName, Extension.Json)) {
return originalReadFile.call(host, fileName);
}
+8 -1
View File
@@ -661,8 +661,15 @@ namespace ts {
let pendingKind!: CommentKind;
let pendingHasTrailingNewLine!: boolean;
let hasPendingCommentRange = false;
let collecting = trailing || pos === 0;
let collecting = trailing;
let accumulator = initial;
if (pos === 0) {
collecting = true;
const shebang = getShebang(text);
if (shebang) {
pos = shebang.length;
}
}
scan: while (pos >= 0 && pos < text.length) {
const ch = text.charCodeAt(pos);
switch (ch) {
+6 -1
View File
@@ -1934,8 +1934,13 @@ namespace ts {
case SyntaxKind.ConditionalType:
return serializeTypeList([(<ConditionalTypeNode>node).trueType, (<ConditionalTypeNode>node).falseType]);
case SyntaxKind.TypeQuery:
case SyntaxKind.TypeOperator:
if ((<TypeOperatorNode>node).operator === SyntaxKind.ReadonlyKeyword) {
return serializeTypeNode((<TypeOperatorNode>node).type);
}
break;
case SyntaxKind.TypeQuery:
case SyntaxKind.IndexedAccessType:
case SyntaxKind.MappedType:
case SyntaxKind.TypeLiteral:
+2 -1
View File
@@ -1233,7 +1233,7 @@ namespace ts {
export interface TypeOperatorNode extends TypeNode {
kind: SyntaxKind.TypeOperator;
operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword;
operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword;
type: TypeNode;
}
@@ -4063,6 +4063,7 @@ namespace ts {
export interface TupleType extends GenericType {
minLength: number;
hasRestElement: boolean;
readonly: boolean;
associatedNames?: __String[];
}
+5
View File
@@ -5607,6 +5607,11 @@ namespace ts {
return node.kind === SyntaxKind.TypeAssertionExpression;
}
export function isConstTypeReference(node: Node) {
return isTypeReferenceNode(node) && isIdentifier(node.typeName) &&
node.typeName.escapedText === "const" && !node.typeArguments;
}
export function isParenthesizedExpression(node: Node): node is ParenthesizedExpression {
return node.kind === SyntaxKind.ParenthesizedExpression;
}
+13 -10
View File
@@ -375,6 +375,15 @@ namespace fakes {
}
}
export type ExpectedDiagnostic = [ts.DiagnosticMessage, ...(string | number)[]];
function expectedDiagnosticToText([message, ...args]: ExpectedDiagnostic) {
let text = ts.getLocaleSpecificMessage(message);
if (args.length) {
text = ts.formatStringFromArgs(text, args);
}
return text;
}
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost<ts.BuilderProgram> {
createProgram = ts.createAbstractBuilder;
now() {
@@ -395,16 +404,10 @@ namespace fakes {
this.diagnostics.length = 0;
}
assertDiagnosticMessages(...expected: ts.DiagnosticMessage[]) {
const actual = this.diagnostics.slice();
if (actual.length !== expected.length) {
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
}
for (let i = 0; i < actual.length; i++) {
if (actual[i].code !== expected[i].code) {
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
}
}
assertDiagnosticMessages(...expectedDiagnostics: ExpectedDiagnostic[]) {
const actual = this.diagnostics.slice().map(d => d.messageText as string);
const expected = expectedDiagnostics.map(expectedDiagnosticToText);
assert.deepEqual(actual, expected, "Diagnostic arrays did not match");
}
printDiagnostics(header = "== Diagnostics ==") {
+2 -2
View File
@@ -103,7 +103,7 @@ interface Atomics {
* Wakes up sleeping agents that are waiting on the given index of the array, returning the
* number of agents that were awoken.
*/
wake(typedArray: Int32Array, index: number, count: number): number;
notify(typedArray: Int32Array, index: number, count: number): number;
/**
* Stores the bitwise XOR of a value with the value at the given position in the array,
@@ -115,4 +115,4 @@ interface Atomics {
readonly [Symbol.toStringTag]: "Atomics";
}
declare var Atomics: Atomics;
declare var Atomics: Atomics;
+1 -1
View File
@@ -904,7 +904,7 @@ namespace ts.server {
getPreferences(file: NormalizedPath): protocol.UserPreferences {
const info = this.getScriptInfoForNormalizedPath(file);
return info && info.getPreferences() || this.hostConfiguration.preferences;
return { ...this.hostConfiguration.preferences, ...info && info.getPreferences() };
}
getHostFormatCodeOptions(): FormatCodeSettings {
+3 -4
View File
@@ -1178,8 +1178,7 @@ namespace ts.server {
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
const preferences = this.getHostPreferences();
return project.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: preferences.allowRenameOfImportPath });
return project.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getPreferences(file).allowRenameOfImportPath });
}
private getProjects(args: protocol.FileRequestArgs, getScriptInfoEnsuringProjectsUptoDate?: boolean, ignoreNoProjectError?: boolean): Projects {
@@ -1234,12 +1233,12 @@ namespace ts.server {
{ fileName: args.file, pos: position },
!!args.findInStrings,
!!args.findInComments,
this.getHostPreferences()
this.getPreferences(file)
);
if (!simplifiedResult) return locations;
const defaultProject = this.getDefaultProject(args);
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getHostPreferences().allowRenameOfImportPath }), Debug.assertDefined(this.projectService.getScriptInfo(file)));
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getPreferences(file).allowRenameOfImportPath }), Debug.assertDefined(this.projectService.getScriptInfo(file)));
return { info: renameInfo, locs: this.toSpanGroups(locations) };
}
+1
View File
@@ -41,6 +41,7 @@ namespace ts.FindAllReferences {
readonly implementations?: boolean;
/**
* True to opt in for enhanced renaming of shorthand properties and import/export specifiers.
* The options controls the behavior for the whole rename operation; it cannot be changed on a per-file basis.
* Default is false for backwards compatibility.
*/
readonly providePrefixAndSuffixTextForRename?: boolean;
+1
View File
@@ -43,6 +43,7 @@
"unittests/asserts.ts",
"unittests/base64.ts",
"unittests/builder.ts",
"unittests/comments.ts",
"unittests/compilerCore.ts",
"unittests/convertToBase64.ts",
"unittests/customTransforms.ts",
+32
View File
@@ -0,0 +1,32 @@
namespace ts {
describe("comment parsing", () => {
const withShebang = `#! node
/** comment */
// another one
;`;
const noShebang = `/** comment */
// another one
;`;
const withTrailing = `;/* comment */
// another one
`;
it("skips shebang", () => {
const result = getLeadingCommentRanges(withShebang, 0);
assert.isDefined(result);
assert.strictEqual(result!.length, 2);
});
it("treats all comments at start of file as leading comments", () => {
const result = getLeadingCommentRanges(noShebang, 0);
assert.isDefined(result);
assert.strictEqual(result!.length, 2);
});
it("returns leading comments if position is not 0", () => {
const result = getLeadingCommentRanges(withTrailing, 1);
assert.isDefined(result);
assert.strictEqual(result!.length, 1);
assert.strictEqual(result![0].kind, SyntaxKind.SingleLineCommentTrivia);
});
});
}
+40
View File
@@ -400,6 +400,46 @@ namespace Foo {
}
}).outputText;
});
// https://github.com/Microsoft/TypeScript/issues/24709
testBaseline("issue24709", () => {
const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true);
const transformed = transform(createSourceFile("source.ts", "class X { echo(x: string) { return x; } }", ScriptTarget.ES3), [transformSourceFile]);
const transformedSourceFile = transformed.transformed[0];
transformed.dispose();
const host = new fakes.CompilerHost(fs);
host.getSourceFile = () => transformedSourceFile;
const program = createProgram(["source.ts"], {
target: ScriptTarget.ES3,
module: ModuleKind.None,
noLib: true
}, host);
program.emit(transformedSourceFile, (_p, s, b) => host.writeFile("source.js", s, b));
return host.readFile("source.js")!.toString();
function transformSourceFile(context: TransformationContext) {
const visitor: Visitor = (node) => {
if (isMethodDeclaration(node)) {
return updateMethod(
node,
node.decorators,
node.modifiers,
node.asteriskToken,
createIdentifier("foobar"),
node.questionToken,
node.typeParameters,
node.parameters,
node.type,
node.body,
);
}
return visitEachChild(node, visitor, context);
};
return (node: SourceFile) => visitNode(node, visitor);
}
});
});
}
+81 -42
View File
@@ -1,5 +1,10 @@
namespace ts {
let currentTime = 100;
function getExpectedDiagnosticForProjectsInBuild(...projects: string[]): fakes.ExpectedDiagnostic {
return [Diagnostics.Projects_in_this_build_Colon_0, projects.map(p => "\r\n * " + p).join("")];
}
export namespace Sample1 {
tick();
const projFs = loadProjectFromDisk("tests/projects/sample1");
@@ -67,7 +72,11 @@ namespace ts {
const host = new fakes.SolutionBuilderHost(fs);
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
host.assertDiagnosticMessages(
[Diagnostics.A_non_dry_build_would_build_project_0, "/src/core/tsconfig.json"],
[Diagnostics.A_non_dry_build_would_build_project_0, "/src/logic/tsconfig.json"],
[Diagnostics.A_non_dry_build_would_build_project_0, "/src/tests/tsconfig.json"]
);
// Check for outputs to not be written. Not an exhaustive list
for (const output of allExpectedOutputs) {
@@ -86,7 +95,11 @@ namespace ts {
host.clearDiagnostics();
builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
host.assertDiagnosticMessages(
[Diagnostics.Project_0_is_up_to_date, "/src/core/tsconfig.json"],
[Diagnostics.Project_0_is_up_to_date, "/src/logic/tsconfig.json"],
[Diagnostics.Project_0_is_up_to_date, "/src/tests/tsconfig.json"]
);
});
});
@@ -146,13 +159,15 @@ namespace ts {
host.clearDiagnostics();
builder.resetBuildContext();
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0);
host.assertDiagnosticMessages(
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"),
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"],
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"],
[Diagnostics.Building_project_0, "/src/logic/tsconfig.json"],
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/tests/tsconfig.json", "src/tests/index.js"],
[Diagnostics.Building_project_0, "/src/tests/tsconfig.json"]
);
tick();
});
@@ -161,10 +176,12 @@ namespace ts {
host.clearDiagnostics();
builder.resetBuildContext();
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
host.assertDiagnosticMessages(
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"),
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"],
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/logic/tsconfig.json", "src/logic/index.ts", "src/logic/index.js"],
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/tests/tsconfig.json", "src/tests/index.ts", "src/tests/index.js"]
);
tick();
});
@@ -175,11 +192,13 @@ namespace ts {
builder.resetBuildContext();
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
Diagnostics.Building_project_0);
host.assertDiagnosticMessages(
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"),
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/core/tsconfig.json", "src/core/anotherModule.ts", "src/core/anotherModule.js"],
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, "src/logic/tsconfig.json", "src/logic/index.ts", "src/logic/index.js"],
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, "src/tests/tsconfig.json", "src/tests/index.js", "src/tests/index.ts"],
[Diagnostics.Building_project_0, "/src/tests/tsconfig.json"]
);
tick();
});
@@ -190,13 +209,15 @@ namespace ts {
builder.resetBuildContext();
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies,
Diagnostics.Updating_output_timestamps_of_project_0,
Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies,
Diagnostics.Updating_output_timestamps_of_project_0);
host.assertDiagnosticMessages(
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"),
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, "src/core/tsconfig.json", "src/core/anotherModule.js", "src/core/index.ts"],
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
[Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies, "src/logic/tsconfig.json"],
[Diagnostics.Updating_output_timestamps_of_project_0, "/src/logic/tsconfig.json"],
[Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies, "src/tests/tsconfig.json"],
[Diagnostics.Updating_output_timestamps_of_project_0, "/src/tests/tsconfig.json"]
);
});
});
@@ -210,14 +231,14 @@ namespace ts {
replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`);
builder.buildAllProjects();
host.assertDiagnosticMessages(
Diagnostics.Projects_in_this_build_Colon_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0,
Diagnostics.Property_0_does_not_exist_on_type_1,
Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors,
Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json", "src/tests/tsconfig.json"),
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"],
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"],
[Diagnostics.Building_project_0, "/src/logic/tsconfig.json"],
[Diagnostics.Property_0_does_not_exist_on_type_1, "muitply", `typeof import("/src/core/index")`],
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, "src/tests/tsconfig.json", "src/logic"],
[Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, "/src/tests/tsconfig.json", "/src/logic"]
);
});
});
@@ -281,12 +302,12 @@ export class cNew {}`);
const projFs = loadProjectFromDisk("tests/projects/resolveJsonModuleAndComposite");
const allExpectedOutputs = ["/src/tests/dist/src/index.js", "/src/tests/dist/src/index.d.ts", "/src/tests/dist/src/hello.json"];
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: fakes.ExpectedDiagnostic[]) {
const fs = projFs.shadow();
verifyProjectWithResolveJsonModuleWithFs(fs, configFile, allExpectedOutputs, ...expectedDiagnosticMessages);
}
function verifyProjectWithResolveJsonModuleWithFs(fs: vfs.FileSystem, configFile: string, allExpectedOutputs: ReadonlyArray<string>, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
function verifyProjectWithResolveJsonModuleWithFs(fs: vfs.FileSystem, configFile: string, allExpectedOutputs: ReadonlyArray<string>, ...expectedDiagnosticMessages: fakes.ExpectedDiagnostic[]) {
const host = new fakes.SolutionBuilderHost(fs);
const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false });
builder.buildAllProjects();
@@ -300,7 +321,10 @@ export class cNew {}`);
}
it("with resolveJsonModule and include only", () => {
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withInclude.json", Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern);
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withInclude.json", [
Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern,
"/src/tests/src/hello.json"
]);
});
it("with resolveJsonModule and include of *.json along with other include", () => {
@@ -415,7 +439,7 @@ export default hello.hello`);
"/src/c.ts"
];
function verifyBuild(modifyDiskLayout: (fs: vfs.FileSystem) => void, allExpectedOutputs: ReadonlyArray<string>, expectedDiagnostics: DiagnosticMessage[], expectedFileTraces: ReadonlyArray<string>) {
function verifyBuild(modifyDiskLayout: (fs: vfs.FileSystem) => void, allExpectedOutputs: ReadonlyArray<string>, expectedFileTraces: ReadonlyArray<string>, ...expectedDiagnostics: fakes.ExpectedDiagnostic[]) {
const fs = projFs.shadow();
const host = new fakes.SolutionBuilderHost(fs);
modifyDiskLayout(fs);
@@ -442,11 +466,11 @@ export const b = new A();`);
}
it("verify that it builds correctly", () => {
verifyBuild(noop, allExpectedOutputs, emptyArray, expectedFileTraces);
verifyBuild(noop, allExpectedOutputs, expectedFileTraces);
});
it("verify that it builds correctly when the referenced project uses different module resolution", () => {
verifyBuild(fs => modifyFsBTsToNonRelativeImport(fs, "classic"), allExpectedOutputs, emptyArray, expectedFileTraces);
verifyBuild(fs => modifyFsBTsToNonRelativeImport(fs, "classic"), allExpectedOutputs, expectedFileTraces);
});
it("verify that it build reports error about module not found with node resolution with external module name", () => {
@@ -458,10 +482,25 @@ export const b = new A();`);
];
verifyBuild(fs => modifyFsBTsToNonRelativeImport(fs, "node"),
allExpectedOutputs,
[Diagnostics.Cannot_find_module_0],
expectedFileTraces);
expectedFileTraces,
[Diagnostics.Cannot_find_module_0, "a"],
);
});
});
it("unittests:: tsbuild - when tsconfig extends the missing file", () => {
const projFs = loadProjectFromDisk("tests/projects/missingExtendedConfig");
const fs = projFs.shadow();
const host = new fakes.SolutionBuilderHost(fs);
const builder = createSolutionBuilder(host, ["/src/tsconfig.json"], {});
builder.buildAllProjects();
host.assertDiagnosticMessages(
[Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"],
[Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.first.json", "[\"**/*\"]", "[]"],
[Diagnostics.The_specified_path_does_not_exist_Colon_0, "/src/foobar.json"],
[Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, "/src/tsconfig.second.json", "[\"**/*\"]", "[]"]
);
});
}
export namespace OutFile {
@@ -564,7 +603,7 @@ export const b = new A();`);
host.clearDiagnostics();
builder.buildAllProjects();
host.assertDiagnosticMessages(Diagnostics.The_files_list_in_config_file_0_is_empty);
host.assertDiagnosticMessages([Diagnostics.The_files_list_in_config_file_0_is_empty, "/src/no-references/tsconfig.json"]);
// Check for outputs to not be written.
for (const output of allExpectedOutputs) {
+107 -1
View File
@@ -7,6 +7,7 @@ namespace ts.projectSystem {
const session = createSession(createServerHost([aTs, bTs]));
openFilesForSession([bTs], session);
// rename fails with allowRenameOfImportPath disabled
const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, {
info: {
@@ -16,6 +17,7 @@ namespace ts.projectSystem {
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
});
// rename succeeds with allowRenameOfImportPath enabled in host
session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: true } });
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
@@ -30,6 +32,23 @@ namespace ts.projectSystem {
},
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
});
// rename succeeds with allowRenameOfImportPath enabled in file
session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: false } });
session.getProjectService().setHostConfiguration({ file: "/b.ts", formatOptions: {}, preferences: { allowRenameOfImportPath: true } });
const response3 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response3, {
info: {
canRename: true,
fileToRename: aTs.path,
displayName: aTs.path,
fullDisplayName: aTs.path,
kind: ScriptElementKind.moduleElement,
kindModifiers: "",
triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }),
},
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
});
});
it("works with prefixText and suffixText when enabled", () => {
@@ -61,7 +80,7 @@ namespace ts.projectSystem {
],
});
// rename with prefixText and suffixText enabled
// rename with prefixText and suffixText enabled in host
session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: true } });
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
@@ -84,6 +103,93 @@ namespace ts.projectSystem {
},
],
});
// rename with prefixText and suffixText enabled for file
session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: false } });
session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } });
const response3 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response3, {
info: {
canRename: true,
fileToRename: undefined,
displayName: "x",
fullDisplayName: "x",
kind: ScriptElementKind.constElement,
kindModifiers: ScriptElementKindModifier.none,
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"),
},
locs: [
{
file: aTs.path,
locs: [
protocolRenameSpanFromSubstring(aTs.content, "x"),
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 1 }, { prefixText: "x: " }),
],
},
],
});
});
it("rename behavior is based on file of rename initiation", () => {
const aTs: File = { path: "/a.ts", content: "const x = 1; export { x };" };
const bTs: File = { path: "/b.ts", content: `import { x } from "./a"; const y = x + 1;` };
const host = createServerHost([aTs, bTs]);
const session = createSession(host);
openFilesForSession([aTs, bTs], session);
// rename from file with prefixText and suffixText enabled
session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } });
const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, {
info: {
canRename: true,
fileToRename: undefined,
displayName: "x",
fullDisplayName: "x",
kind: ScriptElementKind.constElement,
kindModifiers: ScriptElementKindModifier.none,
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"),
},
locs: [
{
file: aTs.path,
locs: [
protocolRenameSpanFromSubstring(aTs.content, "x"),
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 2 }, { suffixText: " as x" }),
],
},
],
});
// rename from file with prefixText and suffixText disabled
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, "x"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
info: {
canRename: true,
fileToRename: undefined,
displayName: "x",
fullDisplayName: "x",
kind: ScriptElementKind.alias,
kindModifiers: ScriptElementKindModifier.none,
triggerSpan: protocolTextSpanFromSubstring(bTs.content, "x"),
},
locs: [
{
file: bTs.path,
locs: [
protocolRenameSpanFromSubstring(bTs.content, "x"),
protocolRenameSpanFromSubstring(bTs.content, "x", { index: 1 })
]
},
{
file: aTs.path,
locs: [
protocolRenameSpanFromSubstring(aTs.content, "x"),
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 2 }),
],
},
],
});
});
});
}