Merge remote-tracking branch 'origin/master' into tsserverVS-WIP-projectsystem

This commit is contained in:
Vladimir Matveev 2016-07-05 10:28:50 -07:00
commit ec9a1ad5f8
12 changed files with 413 additions and 71 deletions

View File

@ -650,7 +650,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
}
if (tests && tests.toLocaleLowerCase() === "rwc") {
testTimeout = 100000;
testTimeout = 400000;
}
const colors = cmdLineOptions["colors"];

View File

@ -776,7 +776,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
}
if (tests && tests.toLocaleLowerCase() === "rwc") {
testTimeout = 100000;
testTimeout = 400000;
}
colors = process.env.colors || process.env.color;

View File

@ -13294,8 +13294,8 @@ namespace ts {
}
}
else {
const static = forEach(member.modifiers, m => m.kind === SyntaxKind.StaticKeyword);
const names = static ? staticNames : instanceNames;
const isStatic = forEach(member.modifiers, m => m.kind === SyntaxKind.StaticKeyword);
const names = isStatic ? staticNames : instanceNames;
const memberName = member.name && getPropertyNameForPropertyNameNode(member.name);
if (memberName) {
@ -14560,7 +14560,10 @@ namespace ts {
const local = node.locals[key];
if (!local.isReferenced) {
if (local.valueDeclaration && local.valueDeclaration.kind === SyntaxKind.Parameter) {
if (compilerOptions.noUnusedParameters && !isParameterPropertyDeclaration(<ParameterDeclaration>local.valueDeclaration)) {
const parameter = <ParameterDeclaration>local.valueDeclaration;
if (compilerOptions.noUnusedParameters &&
!isParameterPropertyDeclaration(parameter) &&
!parameterNameStartsWithUnderscore(parameter)) {
error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name);
}
}
@ -14573,6 +14576,10 @@ namespace ts {
}
}
function parameterNameStartsWithUnderscore(parameter: ParameterDeclaration) {
return parameter.name && parameter.name.kind === SyntaxKind.Identifier && (<Identifier>parameter.name).text.charCodeAt(0) === CharacterCodes._;
}
function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression): void {
if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) {
if (node.members) {

View File

@ -891,6 +891,21 @@ namespace ts {
*/
const invalidMultipleRecursionPatterns = /(^|\/)\*\*\/(.*\/)?\*\*($|\/)/;
/**
* Tests for a path where .. appears after a recursive directory wildcard.
* Matches **\..\*, **\a\..\*, and **\.., but not ..\**\*
*
* NOTE: used \ in place of / above to avoid issues with multiline comments.
*
* Breakdown:
* (^|\/) # matches either the beginning of the string or a directory separator.
* \*\*\/ # matches a recursive directory wildcard "**" followed by a directory separator.
* (.*\/)? # optionally matches any number of characters followed by a directory separator.
* \.\. # matches a parent directory path component ".."
* ($|\/) # matches either the end of the string or a directory separator.
*/
const invalidDotDotAfterRecursiveWildcardPattern = /(^|\/)\*\*\/(.*\/)?\.\.($|\/)/;
/**
* Tests for a path containing a wildcard character in a directory component of the path.
* Matches \*\, \?\, and \a*b\, but not \a\ or \a\*.
@ -1023,6 +1038,9 @@ namespace ts {
else if (invalidMultipleRecursionPatterns.test(spec)) {
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec));
}
else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) {
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
}
else {
validSpecs.push(spec);
}
@ -1052,7 +1070,7 @@ namespace ts {
if (include !== undefined) {
const recursiveKeys: string[] = [];
for (const file of include) {
const name = combinePaths(path, file);
const name = normalizePath(combinePaths(path, file));
if (excludeRegex && excludeRegex.test(name)) {
continue;
}

View File

@ -1073,15 +1073,17 @@ namespace ts {
// Storage for literal base paths amongst the include patterns.
const includeBasePaths: string[] = [];
for (const include of includes) {
if (isRootedDiskPath(include)) {
const wildcardOffset = indexOfAnyCharCode(include, wildcardCharCodes);
const includeBasePath = wildcardOffset < 0
? removeTrailingDirectorySeparator(getDirectoryPath(include))
: include.substring(0, include.lastIndexOf(directorySeparator, wildcardOffset));
// We also need to check the relative paths by converting them to absolute and normalizing
// in case they escape the base path (e.g "..\somedirectory")
const absolute: string = isRootedDiskPath(include) ? include : normalizePath(combinePaths(path, include));
// Append the literal and canonical candidate base paths.
includeBasePaths.push(includeBasePath);
}
const wildcardOffset = indexOfAnyCharCode(absolute, wildcardCharCodes);
const includeBasePath = wildcardOffset < 0
? removeTrailingDirectorySeparator(getDirectoryPath(absolute))
: absolute.substring(0, absolute.lastIndexOf(directorySeparator, wildcardOffset));
// Append the literal and canonical candidate base paths.
includeBasePaths.push(includeBasePath);
}
// Sort the offsets array using either the literal or canonical path representations.

View File

@ -2332,6 +2332,10 @@
"category": "Error",
"code": 5064
},
"File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '{0}'.": {
"category": "Error",
"code": 5065
},
"Concatenate and emit output to single file.": {
"category": "Message",
"code": 6001

View File

@ -8,7 +8,12 @@ interface FileInformation {
}
interface FindFileResult {
}
interface IOLogFile {
path: string;
codepage: number;
result?: FileInformation;
}
interface IOLog {
@ -17,11 +22,7 @@ interface IOLog {
executingPath: string;
currentDirectory: string;
useCustomLibraryFile?: boolean;
filesRead: {
path: string;
codepage: number;
result?: FileInformation;
}[];
filesRead: IOLogFile[];
filesWritten: {
path: string;
contents: string;
@ -61,7 +62,7 @@ interface IOLog {
}[];
directoriesRead: {
path: string,
extension: string[],
extensions: string[],
exclude: string[],
include: string[],
result: string[]
@ -170,8 +171,7 @@ namespace Playback {
path => callAndRecord(underlying.fileExists(path), recordLog.fileExists, { path }),
memoize(path => {
// If we read from the file, it must exist
const noResult = {};
if (findResultByPath(wrapper, replayLog.filesRead, path, noResult) !== noResult) {
if (findFileByPath(wrapper, replayLog.filesRead, path, /*throwFileNotFoundError*/ false)) {
return true;
}
else {
@ -215,16 +215,30 @@ namespace Playback {
recordLog.filesRead.push(logEntry);
return result;
},
memoize(path => findResultByPath(wrapper, replayLog.filesRead, path).contents));
memoize(path => findFileByPath(wrapper, replayLog.filesRead, path, /*throwFileNotFoundError*/ true).contents));
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
(path, extension, exclude, include) => {
const result = (<ts.System>underlying).readDirectory(path, extension, exclude, include);
const logEntry = { path, extension, exclude, include, result };
(path, extensions, exclude, include) => {
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include);
const logEntry = { path, extensions, exclude, include, result };
recordLog.directoriesRead.push(logEntry);
return result;
},
(path, extension, exclude) => findResultByPath(wrapper, replayLog.directoriesRead, path));
(path, extensions, exclude) => {
// Because extensions is an array of all allowed extension, we will want to merge each of the replayLog.directoriesRead into one
// if each of the directoriesRead has matched path with the given path (directory with same path but different extension will considered
// different entry).
// TODO (yuisu): We can certainly remove these once we recapture the RWC using new API
const normalizedPath = ts.normalizePath(path).toLowerCase();
const result: string[] = [];
for (const directory of replayLog.directoriesRead) {
if (ts.normalizeSlashes(directory.path).toLowerCase() === normalizedPath) {
result.push(...directory.result);
}
}
return result;
});
wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)(
(path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog.filesWritten, { path, contents, bom: false }),
@ -279,30 +293,22 @@ namespace Playback {
return results[0].result;
}
function findResultByPath<T>(wrapper: { resolvePath(s: string): string }, logArray: { path: string; result?: T }[], expectedPath: string, defaultValue?: T): T {
function findFileByPath(wrapper: { resolvePath(s: string): string }, logArray: IOLogFile[],
expectedPath: string, throwFileNotFoundError: boolean): FileInformation {
const normalizedName = ts.normalizePath(expectedPath).toLowerCase();
// Try to find the result through normal fileName
for (let i = 0; i < logArray.length; i++) {
if (ts.normalizeSlashes(logArray[i].path).toLowerCase() === normalizedName) {
return logArray[i].result;
}
}
// Fallback, try to resolve the target paths as well
if (replayLog.pathsResolved.length > 0) {
const normalizedResolvedName = wrapper.resolvePath(expectedPath).toLowerCase();
for (let i = 0; i < logArray.length; i++) {
if (wrapper.resolvePath(logArray[i].path).toLowerCase() === normalizedResolvedName) {
return logArray[i].result;
}
for (const log of logArray) {
if (ts.normalizeSlashes(log.path).toLowerCase() === normalizedName) {
return log.result;
}
}
// If we got here, we didn't find a match
if (defaultValue === undefined) {
if (throwFileNotFoundError) {
throw new Error("No matching result in log array for path: " + expectedPath);
}
else {
return defaultValue;
return undefined;
}
}

34
src/lib/es5.d.ts vendored
View File

@ -1255,33 +1255,13 @@ declare type PromiseConstructorLike = new <T>(executor: (resolve: (value?: T | P
interface PromiseLike<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>): PromiseLike<TResult>;
/**
* Creates a new Promise with the same internal state of this Promise.
* @returns A Promise.
*/
then(): PromiseLike<T>;
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
}
interface ArrayLike<T> {

View File

@ -0,0 +1,56 @@
tests/cases/compiler/unusedParametersWithUnderscore.ts(2,12): error TS6133: 'a' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(2,19): error TS6133: 'c' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(2,27): error TS6133: 'd' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(2,29): error TS6133: 'e___' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(6,14): error TS6133: '_a' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(6,18): error TS6133: '___b' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(9,14): error TS6133: '_a' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(9,19): error TS6133: '___b' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(12,16): error TS6133: 'arg' is declared but never used.
tests/cases/compiler/unusedParametersWithUnderscore.ts(18,13): error TS6133: 'arg' is declared but never used.
==== tests/cases/compiler/unusedParametersWithUnderscore.ts (10 errors) ====
function f(a, _b, c, ___, d,e___, _f) {
~
!!! error TS6133: 'a' is declared but never used.
~
!!! error TS6133: 'c' is declared but never used.
~
!!! error TS6133: 'd' is declared but never used.
~~~~
!!! error TS6133: 'e___' is declared but never used.
}
function f2({_a, __b}) {
~~
!!! error TS6133: '_a' is declared but never used.
~~~
!!! error TS6133: '___b' is declared but never used.
}
function f3([_a, ,__b]) {
~~
!!! error TS6133: '_a' is declared but never used.
~~~
!!! error TS6133: '___b' is declared but never used.
}
function f4(...arg) {
~~~
!!! error TS6133: 'arg' is declared but never used.
}
function f5(..._arg) {
}
function f6(arg?, _arg?) {
~~~
!!! error TS6133: 'arg' is declared but never used.
}
var f7 = _ => undefined;
var f8 = function (_) { };

View File

@ -0,0 +1,50 @@
//// [unusedParametersWithUnderscore.ts]
function f(a, _b, c, ___, d,e___, _f) {
}
function f2({_a, __b}) {
}
function f3([_a, ,__b]) {
}
function f4(...arg) {
}
function f5(..._arg) {
}
function f6(arg?, _arg?) {
}
var f7 = _ => undefined;
var f8 = function (_) { };
//// [unusedParametersWithUnderscore.js]
function f(a, _b, c, ___, d, e___, _f) {
}
function f2(_c) {
var _a = _c._a, __b = _c.__b;
}
function f3(_c) {
var _a = _c[0], __b = _c[2];
}
function f4() {
var arg = [];
for (var _i = 0; _i < arguments.length; _i++) {
arg[_i - 0] = arguments[_i];
}
}
function f5() {
var _arg = [];
for (var _i = 0; _i < arguments.length; _i++) {
_arg[_i - 0] = arguments[_i];
}
}
function f6(arg, _arg) {
}
var f7 = function (_) { return undefined; };
var f8 = function (_) { };

View File

@ -0,0 +1,25 @@
//@noUnusedLocals:true
//@noUnusedParameters:true
function f(a, _b, c, ___, d,e___, _f) {
}
function f2({_a, __b}) {
}
function f3([_a, ,__b]) {
}
function f4(...arg) {
}
function f5(..._arg) {
}
function f6(arg?, _arg?) {
}
var f7 = _ => undefined;
var f8 = function (_) { };

View File

@ -24,7 +24,8 @@ namespace ts {
"c:/dev/x/y/b.ts",
"c:/dev/js/a.js",
"c:/dev/js/b.js",
"c:/ext/ext.ts"
"c:/ext/ext.ts",
"c:/ext/b/a..b.ts"
]);
const caseSensitiveBasePath = "/dev/";
@ -740,7 +741,7 @@ namespace ts {
"c:/dev/a.ts",
"c:/dev/b.ts",
"c:/dev/c.d.ts",
"c:/ext/ext.ts",
"c:/ext/ext.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.None,
@ -752,6 +753,97 @@ namespace ts {
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("include paths outside of the project using relative paths", () => {
const json = {
include: [
"*",
"../ext/*"
],
exclude: [
"**"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/ext/ext.ts"
],
wildcardDirectories: {
"c:/ext": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("exclude paths outside of the project using relative paths", () => {
const json = {
include: [
"c:/**/*"
],
exclude: [
"../**"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("include files with .. in their name", () => {
const json = {
include: [
"c:/ext/b/a..b.ts"
],
exclude: [
"**"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/ext/b/a..b.ts"
],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("exclude files with .. in their name", () => {
const json = {
include: [
"c:/ext/**/*"
],
exclude: [
"c:/ext/b/a..b.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/ext/ext.ts",
],
wildcardDirectories: {
"c:/ext": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("with jsx=none, allowJs=false", () => {
const json = {
compilerOptions: {
@ -951,6 +1043,108 @@ namespace ts {
assert.deepEqual(actual.errors, expected.errors);
});
});
describe("with parent directory symbols after a recursive directory pattern", () => {
it("in includes immediately after", () => {
const json = {
include: [
"**/../*"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/../*")
],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("in includes after a subdirectory", () => {
const json = {
include: [
"**/y/../*"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/../*")
],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("in excludes immediately after", () => {
const json = {
include: [
"**/a.ts"
],
exclude: [
"**/.."
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/..")
],
fileNames: [
"c:/dev/a.ts",
"c:/dev/x/a.ts",
"c:/dev/x/y/a.ts",
"c:/dev/z/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("in excludes after a subdirectory", () => {
const json = {
include: [
"**/a.ts"
],
exclude: [
"**/y/.."
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/..")
],
fileNames: [
"c:/dev/a.ts",
"c:/dev/x/a.ts",
"c:/dev/x/y/a.ts",
"c:/dev/z/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
});
});
});
}