Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Watch improvements in tsserver #17269

Merged
merged 128 commits into from
Oct 3, 2017
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
21ad26b
When opening a file, if it is using existing project, there is no nee…
sheetalkamat Jun 30, 2017
ae33ae8
Restructure updating the configured project from disk and actual proj…
sheetalkamat Jul 1, 2017
75698a8
Add project roots in the list of root files even if they arent presen…
sheetalkamat Jul 6, 2017
f154910
Move the server file system to handle watches on file/folder create, …
sheetalkamat Jul 7, 2017
0e44367
Remove the functions to trigger watch callbacks now that it is auto o…
sheetalkamat Jul 7, 2017
2a63827
Update the todo list
sheetalkamat Jul 7, 2017
96ffd53
Reload the configured project only once even though there are multipl…
sheetalkamat Jul 7, 2017
6bd42b8
When config file is deleted, apart from removing the projecty, reload…
sheetalkamat Jul 7, 2017
df6f75b
Optimize wildcard watchers and config directory watching as now we ha…
sheetalkamat Jul 7, 2017
9ff9476
Handle the deleted file in update graph better, so that in next updat…
sheetalkamat Jul 10, 2017
62871cc
Only update file list when there are changes in the watched directories
sheetalkamat Jul 11, 2017
48c6513
Update types instantly when the type root changes.
sheetalkamat Jul 11, 2017
19a6a00
Cache the read directory results so that it doesnt end up reading it …
sheetalkamat Jul 11, 2017
68def1b
Use the cached file exists/directory exists for configured project si…
sheetalkamat Jul 11, 2017
029b1f2
Fixes the fourslash runner tests by handling hosts that cannot suppor…
sheetalkamat Jul 12, 2017
f338a70
Remove the done TODO
sheetalkamat Jul 12, 2017
8fedcf7
TODOs for the scheduling update graph and referesh projects
sheetalkamat Jul 13, 2017
e568976
Allows the delayed update graph and project structure which helps in …
sheetalkamat Jul 13, 2017
048e67c
Merge branch 'master' into watchImprovements
sheetalkamat Jul 13, 2017
0365901
use single instance of getCanonicalFileName
sheetalkamat Jul 13, 2017
404aa8f
Logging of the watch add/remove/event
sheetalkamat Jul 14, 2017
71d79c6
Some refactoring to combine files removal from inferred project
sheetalkamat Jul 15, 2017
f12980d
Remove the duplcate error about no input files found
sheetalkamat Jul 15, 2017
00011a5
Refactor root files addition/update for non inferred project
sheetalkamat Jul 15, 2017
0572b15
Instead of watching directories, watch tsconfig files of inferred pro…
sheetalkamat Jul 16, 2017
62663a1
Use map for configured project instead of the array
sheetalkamat Jul 16, 2017
dcbd7b1
Combine the logic to find config file as well as the watch.
sheetalkamat Jul 16, 2017
62ef6b1
Added another todo as now we are watching too many files
sheetalkamat Jul 17, 2017
2439e7a
Reduce the number of watched config files by watching the chain only …
sheetalkamat Jul 17, 2017
ff34a77
Merge branch 'master' into watchImprovements
sheetalkamat Jul 17, 2017
1155c37
Merge branch 'master' into watchImprovements
sheetalkamat Jul 20, 2017
ae87838
Merge branch 'master' into watchImprovements
sheetalkamat Aug 7, 2017
802e283
Refactoring of the builder
sheetalkamat Jul 19, 2017
499fabc
Do not update graph in builder if compile on save is not on
sheetalkamat Jul 19, 2017
273569f
Make the host cache store the fileName instead of undefined for the m…
sheetalkamat Jul 19, 2017
94a589b
Program cannot be reused if the missing file is now present
sheetalkamat Jul 21, 2017
ef5935b
Initial refactoring so that watch from tsc follows the tsserver projects
sheetalkamat Jul 24, 2017
e068475
Refactor so that builder handles only source files and program
sheetalkamat Jul 24, 2017
6237b22
Move the builder to compiler directory
sheetalkamat Jul 24, 2017
9b18f7b
Use builder to emit the files from the tsc.js
sheetalkamat Jul 24, 2017
85b9254
Refactor out the tsc logic into another file so we can use that to te…
sheetalkamat Jul 26, 2017
69e5abd
Refactor watched system from tsserver tests so that tscLib watch can …
sheetalkamat Jul 26, 2017
c814d8e
Add tests for the tsc --watch
sheetalkamat Jul 26, 2017
2dd6aed
Emit tests
sheetalkamat Jul 29, 2017
89c61e7
Modify the api in builder so that it tracks changed files
sheetalkamat Aug 3, 2017
bb91b32
Add tests to verify emitted files
sheetalkamat Aug 3, 2017
46e3d1c
Refactoring so that instead of just using from tsc --watch the new ap…
sheetalkamat Aug 4, 2017
031a637
Switch back to have tsc.ts the only file thats different in tsc.js ge…
sheetalkamat Aug 4, 2017
0d5e6c9
Use cache for module resolution even in watch mode
sheetalkamat Aug 4, 2017
2762232
Test for the module resolution caching
sheetalkamat Aug 4, 2017
65a6ee0
Add test that fails because we dont watch module resolutions failed p…
sheetalkamat Aug 5, 2017
d55150c
Implementation of watching the failed lookup locations
sheetalkamat Aug 5, 2017
8dc6248
Partial implementation for invalidating the program (instead of sourc…
sheetalkamat Aug 5, 2017
7474ba7
Implementation for invalidating source file containing possibly chang…
sheetalkamat Aug 5, 2017
6385f7e
Get semantic diagnostics for the program from builder so that it cach…
sheetalkamat Aug 7, 2017
65521bc
Feedback from the PR
sheetalkamat Aug 7, 2017
27988bf
More updates based on PR feedback
sheetalkamat Aug 7, 2017
02b8a7d
More work on PR feedback
sheetalkamat Aug 7, 2017
f723beb
More updates per PR feedback
sheetalkamat Aug 7, 2017
b071a86
More work on feedback from PR
sheetalkamat Aug 7, 2017
8db05c2
More work on PR feedback update
sheetalkamat Aug 11, 2017
594482d
Merge branch 'master' into watchImprovements
sheetalkamat Aug 12, 2017
d0a23bb
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 12, 2017
59d07dc
Simplified mutate map options
sheetalkamat Aug 14, 2017
9895082
Updating according to feedback from PR
sheetalkamat Aug 14, 2017
f1b1b12
More work based on feedback
sheetalkamat Aug 14, 2017
136b091
Update based on feedback
sheetalkamat Aug 14, 2017
6bf9133
Update to PR feedback
sheetalkamat Aug 14, 2017
a99c04e
Make the failedLookuplocations to be readonly array
sheetalkamat Aug 14, 2017
b66b752
Update based on feedback
sheetalkamat Aug 18, 2017
da0d374
Made updates to not expose methods/types that arent needed.
sheetalkamat Aug 18, 2017
e639ceb
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 18, 2017
8deef58
Remove the unused function from the Project since builder has this lo…
sheetalkamat Aug 18, 2017
c425128
When getting default project from session, get it only if the script …
sheetalkamat Aug 18, 2017
d217bec
Merge branch 'master' into watchImprovements
sheetalkamat Aug 18, 2017
60e2e68
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 18, 2017
84b2e23
More PR feedback work
sheetalkamat Aug 21, 2017
3908325
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 21, 2017
7173da2
Adding test for #16329 to verify the caching of file system when open…
sheetalkamat Aug 18, 2017
e500be2
Adding test for #16456 to verify watched directories in case-sensitiv…
sheetalkamat Aug 19, 2017
6227a36
In Server when polling the file stat's do not send changed event in c…
sheetalkamat Aug 21, 2017
55931c4
Update the failed lookup watches without doing lookups.
sheetalkamat Aug 21, 2017
e65df12
Add test for #16955 which simulates npm install
sheetalkamat Aug 22, 2017
e711238
Add api in builder to get changed files and use it to send project ch…
sheetalkamat Aug 15, 2017
3b85f3f
Add tests to verify project changed event sent
sheetalkamat Aug 22, 2017
ea95f3b
Merge pull request #17820 from Microsoft/tsserverEventChangedFiles
sheetalkamat Aug 31, 2017
9e570c3
Merge pull request #17669 from Microsoft/builder
sheetalkamat Aug 31, 2017
4c79033
Refactoring to watches and caching of system such that we minimize fu…
sheetalkamat Aug 23, 2017
5aafd3f
Reduce number of watches for failed lookup locations as part of modul…
sheetalkamat Aug 23, 2017
17565d8
Handle watches of missing directories and make project the module res…
sheetalkamat Aug 24, 2017
10ea5bf
Script infos while opening/closing shouldnt mark project as dirty if …
sheetalkamat Aug 26, 2017
254e393
Watch failed lookups recursively to reduce number of directory watches
sheetalkamat Aug 28, 2017
a3b9467
Resolve only once in the given directory for name
sheetalkamat Aug 29, 2017
16cf7c4
Watch for the automatic types that included as part of type resolution
sheetalkamat Aug 30, 2017
d7ce95d
Watch node_modules if possible
sheetalkamat Aug 31, 2017
345f36d
Update tests
sheetalkamat Aug 31, 2017
2b97b2c
Print number of files in the project when printing project
sheetalkamat Aug 31, 2017
8d5d4c2
Reduce storage of maps/sets for failed lookups
sheetalkamat Aug 31, 2017
9e5e20c
Remove the configured project if on next open file if it has no open …
sheetalkamat Sep 1, 2017
13aafa2
Update tests
sheetalkamat Sep 1, 2017
6c61293
Test to verify calls to isProgramUptoDate return true when there is n…
sheetalkamat Sep 1, 2017
7b2bab5
Revert to use refcount to keep track of directory watchers for failed…
sheetalkamat Sep 5, 2017
54f64a1
Resolution is valid unless it is invalidated
sheetalkamat Sep 6, 2017
0ff160f
Add files to change set instead of delay reloading project on "change…
sheetalkamat Sep 6, 2017
e6eede1
Update how we get project/script info so that it doesnt start unneces…
sheetalkamat Sep 6, 2017
2a5d954
Reduce the file size for npm install test
sheetalkamat Sep 6, 2017
680994e
Better log for update graph and delay operations
sheetalkamat Sep 6, 2017
c8e711c
Invalidate resolution of the failed lookup only if its one of the def…
sheetalkamat Sep 7, 2017
29e93c3
Update the test cases for project changed event since it doesnt apply…
sheetalkamat Sep 7, 2017
b179cd1
Return configured project being closed by config file
sheetalkamat Sep 7, 2017
67f9533
Limit the resolution invalidation to max number of files as invalidat…
sheetalkamat Sep 8, 2017
de28d02
Add test case to verify correct resolution file is picked when curren…
sheetalkamat Sep 8, 2017
5739b68
Do not create map just to store empty reference files. Also update fi…
sheetalkamat Sep 9, 2017
fdb104b
Merge branch 'master' into watchImprovements
sheetalkamat Sep 11, 2017
aea8630
Merge branch 'master' into watchImprovements
sheetalkamat Sep 12, 2017
b536f9d
Should not remove the reused resolutions in the file when file conten…
sheetalkamat Sep 12, 2017
4f7c0e5
Simplify event sent on background project update since its anyways ju…
sheetalkamat Sep 13, 2017
cf72f2a
Merge branch 'master' into watchImprovements
sheetalkamat Sep 14, 2017
23acff5
Merge branch 'master' into watchImprovements
sheetalkamat Sep 25, 2017
14febe2
Rename watchedProgram.ts to watch.ts
sheetalkamat Sep 26, 2017
38f3a2b
Renamed PartialSystem as DirectoryStructureHost and CachedPartialSyst…
sheetalkamat Sep 26, 2017
68d3605
PR feedback
sheetalkamat Sep 26, 2017
9e08cae
Merge branch 'master' into watchImprovements
sheetalkamat Sep 29, 2017
835153b
PR feedback
sheetalkamat Oct 2, 2017
898559b
Merge branch 'master' into watchImprovements
sheetalkamat Oct 2, 2017
7f969e8
Making APIs as internal so that we can enable them after we have figu…
sheetalkamat Oct 2, 2017
4bb4711
Merge branch 'master' into watchImprovements
sheetalkamat Oct 2, 2017
8ac01d7
Separate namespace declarations in builder of intenal and exported in…
sheetalkamat Oct 3, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 75 additions & 42 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1401,28 +1401,30 @@ namespace ts {
Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined));
const errors: Diagnostic[] = [];

const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors);
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, getCanonicalFileName, resolutionStack, errors);
const { raw } = parsedConfig;
const options = extend(existingOptions, parsedConfig.options || {});
options.configFilePath = configFileName;
setConfigFileInOptions(options, sourceFile);
const { fileNames, wildcardDirectories } = getFileNames();
const { fileNames, wildcardDirectories, spec } = getFileNames();
return {
options,
fileNames,
typeAcquisition: parsedConfig.typeAcquisition || getDefaultTypeAcquisition(),
raw,
errors,
wildcardDirectories,
compileOnSave: !!raw.compileOnSave
compileOnSave: !!raw.compileOnSave,
configFileSpecs: spec
};

function getFileNames(): ExpandResult {
let fileNames: ReadonlyArray<string>;
let filesSpecs: ReadonlyArray<string>;
if (hasProperty(raw, "files")) {
if (isArray(raw["files"])) {
fileNames = <ReadonlyArray<string>>raw["files"];
if (fileNames.length === 0) {
filesSpecs = <ReadonlyArray<string>>raw["files"];
if (filesSpecs.length === 0) {
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
}
}
Expand Down Expand Up @@ -1457,19 +1459,14 @@ namespace ts {
}
}

if (fileNames === undefined && includeSpecs === undefined) {
if (filesSpecs === undefined && includeSpecs === undefined) {
includeSpecs = ["**/*"];
}

const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors, extraFileExtensions, sourceFile);
const result = matchFileNames(filesSpecs, includeSpecs, excludeSpecs, basePath, options, host, errors, extraFileExtensions, sourceFile);

if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0) {
errors.push(
createCompilerDiagnostic(
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
configFileName || "tsconfig.json",
JSON.stringify(includeSpecs || []),
JSON.stringify(excludeSpecs || [])));
errors.push(getErrorForNoInputFiles(result.spec, configFileName));
}

return result;
Expand All @@ -1482,6 +1479,20 @@ namespace ts {
}
}

/*@internal*/
export function isErrorNoInputFiles(error: Diagnostic) {
return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
}

/*@internal*/
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) {
return createCompilerDiagnostic(
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
configFileName || "tsconfig.json",
JSON.stringify(includeSpecs || []),
JSON.stringify(excludeSpecs || []));
}

interface ParsedTsconfig {
raw: any;
options?: CompilerOptions;
Expand All @@ -1503,11 +1514,11 @@ namespace ts {
host: ParseConfigHost,
basePath: string,
configFileName: string,
getCanonicalFileName: (fileName: string) => string,
resolutionStack: Path[],
errors: Push<Diagnostic>,
): ParsedTsconfig {
basePath = normalizeSlashes(basePath);
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
const resolvedPath = toPath(configFileName || "", basePath, getCanonicalFileName);

if (resolutionStack.indexOf(resolvedPath) >= 0) {
Expand Down Expand Up @@ -1689,7 +1700,7 @@ namespace ts {

const extendedDirname = getDirectoryPath(extendedConfigPath);
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
getBaseFileName(extendedConfigPath), resolutionStack, errors);
getBaseFileName(extendedConfigPath), getCanonicalFileName, resolutionStack, errors);
if (sourceFile) {
sourceFile.extendedSourceFiles.push(...extendedResult.extendedSourceFiles);
}
Expand Down Expand Up @@ -1920,29 +1931,62 @@ namespace ts {
/**
* Expands an array of file specifications.
*
* @param fileNames The literal file names to include.
* @param include The wildcard file specifications to include.
* @param exclude The wildcard file specifications to exclude.
* @param filesSpecs The literal file names to include.
* @param includeSpecs The wildcard file specifications to include.
* @param excludeSpecs The wildcard file specifications to exclude.
* @param basePath The base path for any relative file specifications.
* @param options Compiler options.
* @param host The host used to resolve files and directories.
* @param errors An array for diagnostic reporting.
*/
function matchFileNames(
fileNames: ReadonlyArray<string>,
include: ReadonlyArray<string>,
exclude: ReadonlyArray<string>,
filesSpecs: ReadonlyArray<string>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be fileSpecs instead of filesSpecs? The extra "s" seems redundant.

includeSpecs: ReadonlyArray<string>,
excludeSpecs: ReadonlyArray<string>,
basePath: string,
options: CompilerOptions,
host: ParseConfigHost,
errors: Push<Diagnostic>,
extraFileExtensions: ReadonlyArray<JsFileExtensionInfo>,
jsonSourceFile: JsonSourceFile): ExpandResult {
jsonSourceFile: JsonSourceFile
): ExpandResult {
basePath = normalizePath(basePath);
let validatedIncludeSpecs: ReadonlyArray<string>, validatedExcludeSpecs: ReadonlyArray<string>;

// The exclude spec list is converted into a regular expression, which allows us to quickly
// test whether a file or directory should be excluded before recursively traversing the
// file system.

if (includeSpecs) {
validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*allowTrailingRecursion*/ false, jsonSourceFile, "include");
}

if (excludeSpecs) {
validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*allowTrailingRecursion*/ true, jsonSourceFile, "exclude");
}

// Wildcard directories (provided as part of a wildcard path) are stored in a
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
// or a recursive directory. This information is used by filesystem watchers to monitor for
// new entries in these paths.
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);

const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
}

/**
* Gets the file names from the provided config file specs that contain, files, include, exclude and
* other properties needed to resolve the file names
* @param spec The config file specs extracted with file names to include, wildcards to include/exclude and other details
* @param basePath The base path for any relative file specifications.
* @param options Compiler options.
* @param host The host used to resolve files and directories.
* @param extraFileExtensions optionaly file extra file extension information from host
*/
export function getFileNamesFromConfigSpecs(spec: ConfigFileSpecs, basePath: string, options: CompilerOptions, host: ParseConfigHost, extraFileExtensions: ReadonlyArray<JsFileExtensionInfo>): ExpandResult {
basePath = normalizePath(basePath);

const keyMapper = host.useCaseSensitiveFileNames ? caseSensitiveKeyMapper : caseInsensitiveKeyMapper;

// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
Expand All @@ -1955,35 +1999,23 @@ namespace ts {
// via wildcard, and to handle extension priority.
const wildcardFileMap = createMap<string>();

if (include) {
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false, jsonSourceFile, "include");
}

if (exclude) {
exclude = validateSpecs(exclude, errors, /*allowTrailingRecursion*/ true, jsonSourceFile, "exclude");
}

// Wildcard directories (provided as part of a wildcard path) are stored in a
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
// or a recursive directory. This information is used by filesystem watchers to monitor for
// new entries in these paths.
const wildcardDirectories = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
const { filesSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;

// Rather than requery this for each file and filespec, we query the supported extensions
// once and store it on the expansion context.
const supportedExtensions = getSupportedExtensions(options, extraFileExtensions);

// Literal files are always included verbatim. An "include" or "exclude" specification cannot
// remove a literal file.
if (fileNames) {
for (const fileName of fileNames) {
if (filesSpecs) {
for (const fileName of filesSpecs) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fileName be renamed fileSpec?

const file = combinePaths(basePath, fileName);
literalFileMap.set(keyMapper(file), file);
}
}

if (include && include.length > 0) {
for (const file of host.readDirectory(basePath, supportedExtensions, exclude, include, /*depth*/ undefined)) {
if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) {
for (const file of host.readDirectory(basePath, supportedExtensions, validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) {
// If we have already included a literal or wildcard path with a
// higher priority extension, we should skip this file.
//
Expand Down Expand Up @@ -2011,11 +2043,12 @@ namespace ts {
const wildcardFiles = arrayFrom(wildcardFileMap.values());
return {
fileNames: literalFiles.concat(wildcardFiles),
wildcardDirectories
wildcardDirectories,
spec
};
}

function validateSpecs(specs: ReadonlyArray<string>, errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string) {
function validateSpecs(specs: ReadonlyArray<string>, errors: Push<Diagnostic>, allowTrailingRecursion: boolean, jsonSourceFile: JsonSourceFile, specKey: string): ReadonlyArray<string> {
return specs.filter(spec => {
const diag = specToDiagnostic(spec, allowTrailingRecursion);
if (diag !== undefined) {
Expand Down
24 changes: 22 additions & 2 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,13 +459,20 @@ namespace ts {
return result;
}

export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U[] | undefined): U[] {
export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U | U[] | undefined): U[] {
const result: U[] = [];
while (true) {
const { value, done } = iter.next();
if (done) break;
const res = mapfn(value);
if (res) result.push(...res);
if (res) {
if (isArray(res)) {
result.push(...res);
}
else {
result.push(res);
}
}
}
return result;
}
Expand Down Expand Up @@ -515,6 +522,19 @@ namespace ts {
return result;
}

export function mapDefinedIter<T, U>(iter: Iterator<T>, mapFn: (x: T) => U | undefined): U[] {
const result: U[] = [];
while (true) {
const { value, done } = iter.next();
if (done) break;
const res = mapFn(value);
if (res !== undefined) {
result.push(res);
}
}
return result;
}

/**
* Computes the first matching span of elements and returns a tuple of the first span
* and the remaining elements.
Expand Down
4 changes: 0 additions & 4 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3074,10 +3074,6 @@
"category": "Message",
"code": 6128
},
"The config file '{0}' found doesn't contain any source files.": {
"category": "Error",
"code": 6129
},
"Resolving real path for '{0}', result '{1}'.": {
"category": "Message",
"code": 6130
Expand Down
29 changes: 25 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3738,16 +3738,33 @@ namespace ts {
errors: Diagnostic[];
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
compileOnSave?: boolean;
configFileSpecs?: ConfigFileSpecs;
}

export const enum WatchDirectoryFlags {
None = 0,
Recursive = 1 << 0,
}

export interface ConfigFileSpecs {
filesSpecs: ReadonlyArray<string>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be fileSpecs instead of filesSpecs? The extra "s" seems redundant.

/**
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
*/
includeSpecs: ReadonlyArray<string>;
/**
* Present to report errors (user specified specs), validatedExcludeSpecs are used for file name matching
*/
excludeSpecs: ReadonlyArray<string>;
validatedIncludeSpecs: ReadonlyArray<string>;
validatedExcludeSpecs: ReadonlyArray<string>;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be changed to Map?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to keep this MapLike just the way json has to ensure that the conversion is done only on need basis

}

export interface ExpandResult {
fileNames: string[];
wildcardDirectories: MapLike<WatchDirectoryFlags>;
spec: ConfigFileSpecs;
}

/* @internal */
Expand Down Expand Up @@ -3995,9 +4012,11 @@ namespace ts {
}

export interface ResolvedModuleWithFailedLookupLocations {
resolvedModule: ResolvedModuleFull | undefined;
readonly resolvedModule: ResolvedModuleFull | undefined;
/* @internal */
failedLookupLocations: string[];
readonly failedLookupLocations: string[];
/*@internal*/
isInvalidated?: boolean;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this type should be mutable -- could you use a { readonly resolved: ResolvedModuleWithFailedLookupLocations, isInvalidated: boolean } type for that purpose instead?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, I meant to use a different type than ResolvedModuleWithFailedLookupLocations for mutable purposes, not just to add a new field but mark the others readonly.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it looks like you did do that, but forgot to remove the isInvalidated here.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property doesn't really belong here -- this is the return type of functions in moduleNameResolver.ts, which have nothing to do with invalidation. Could you use a { resolved: ResolvedModuleWithFailedLookupLocations, isInvalidated: boolean } tuple for your purposes instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think thats a good idea.. Already there are so many resolutions created for large projects, adding overhead of another object doesnt seem right. Instead I moved the invalidated definition to resolutionCache so shouldnt change anything in modulenameResolver

}

export interface ResolvedTypeReferenceDirective {
Expand All @@ -4008,8 +4027,10 @@ namespace ts {
}

export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
failedLookupLocations: string[];
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
readonly failedLookupLocations: string[];
/*@internal*/
isInvalidated?: boolean;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

}

export interface CompilerHost extends ModuleResolutionHost {
Expand Down
2 changes: 1 addition & 1 deletion src/harness/unittests/cachingInServerLSHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace ts {
const projectService = new server.ProjectService(svcOpts);
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */ true, /*containingProject*/ undefined);

const project = projectService.createInferredProjectWithRootFileIfNecessary(rootScriptInfo);
const project = projectService.assignOrphanScriptInfoToInferredProject(rootScriptInfo);
project.setCompilerOptions({ module: ts.ModuleKind.AMD, noLib: true } );
return {
project,
Expand Down
6 changes: 1 addition & 5 deletions src/harness/unittests/compileOnSave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ namespace ts.projectSystem {

file1Consumer1.content = `let y = 10;`;
host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]);
host.triggerFileWatcherCallback(file1Consumer1.path, FileWatcherEventKind.Changed);

session.executeCommand(changeModuleFile1ShapeRequest1);
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]);
Expand All @@ -226,7 +225,6 @@ namespace ts.projectSystem {
session.executeCommand(changeModuleFile1ShapeRequest1);
// Delete file1Consumer2
host.reloadFS([moduleFile1, file1Consumer1, configFile, libFile]);
host.triggerFileWatcherCallback(file1Consumer2.path, FileWatcherEventKind.Deleted);
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]);
});

Expand All @@ -243,7 +241,6 @@ namespace ts.projectSystem {
content: `import {Foo} from "./moduleFile1"; let y = Foo();`
};
host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3, globalFile3, configFile, libFile]);
host.triggerDirectoryWatcherCallback(ts.getDirectoryPath(file1Consumer3.path), file1Consumer3.path);
host.runQueuedTimeoutCallbacks();
session.executeCommand(changeModuleFile1ShapeRequest1);
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3] }]);
Expand Down Expand Up @@ -476,7 +473,6 @@ namespace ts.projectSystem {

openFilesForSession([referenceFile1], session);
host.reloadFS([referenceFile1, configFile]);
host.triggerFileWatcherCallback(moduleFile1.path, FileWatcherEventKind.Deleted);

const request = makeSessionRequest<server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
sendAffectedFileRequestAndCheckResult(session, request, [
Expand Down Expand Up @@ -604,4 +600,4 @@ namespace ts.projectSystem {
assert.isTrue(outFileContent.indexOf(file3.content) === -1);
});
});
}
}
Loading