mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-10 15:25:54 -06:00
Merge pull request #9482 from Microsoft/port_include_relative_path
Port 9475 to release 2.0
This commit is contained in:
commit
69fcb133f6
@ -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;
|
||||
}
|
||||
|
||||
@ -1072,15 +1072,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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user