-
Notifications
You must be signed in to change notification settings - Fork 650
Implement maxNodeModuleJsDepth, noResolve #1189
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces depth-based controls (maxNodeModuleJsDepth
) for loading JS files in node_modules
and implements the noResolve
option to skip adding resolved modules to the program. It refactors task-loading to track whether a file is loaded and if its depth should increase, simplifying concurrent loading logic.
- Add
loaded
,shouldIncreaseDepth
, andisLoaded
methods to parse- and project-reference tasks - Introduce a generic
fileLoaderWorker
that tracks per-file mutexes and depth limits - Update
fileloader.go
to use aresolvedRef
type, respectmaxNodeModuleJsDepth
, and honornoResolve
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
testdata/baselines/reference/.../moduleResolutionNoResolve.js.diff | Removes outdated diff for noResolve baseline |
testdata/baselines/reference/.../moduleResolutionNoResolve.js | Updates the baseline output for noResolve |
internal/compiler/projectreferenceparsetask.go | Rename start →load , add depth/no-resolve stubs |
internal/compiler/program.go | Remove unused depth-tracking fields in Program |
internal/compiler/parsetask.go | Refactor subtasks to use resolvedRef , track JS depth |
internal/compiler/fileloadertask.go | Generic worker with mutex per file, depth-first logic |
internal/compiler/fileloader.go | Wire up maxNodeModuleJsDepth , implement noResolve logic |
Comments suppressed due to low confidence (2)
internal/compiler/fileloader.go:67
- There are no tests covering the new
maxNodeModuleJsDepth
behavior; consider adding cases where the loader skips JS files beyond the depth limit.
var maxNodeModuleJsDepth int
internal/compiler/fileloader.go:386
- The new
noResolve
flag path isn't exercised by existing tests; add tests to verify that settingnoResolve
prevents modules from being added.
shouldAddFile := resolvedModule.IsResolved() && optionsForFile.NoResolve.IsFalseOrUnknown()
+index.js(10,12): error TS2749: 'Thing' refers to a value, but is being used as a type here. Did you mean 'typeof Thing'? | ||
+index.js(17,16): error TS2749: 'Thing' refers to a value, but is being used as a type here. Did you mean 'typeof Thing'? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected, since @enum
doesn't do anything anymore and so no type is declared.
- | ||
- | ||
-==== validator.ts (10 errors) ==== | ||
+index.js(4,11): error TS2580: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mod1
looks like:
Object.defineProperty(exports, "thing", { value: 42, writable: true });
Object.defineProperty(exports, "readonlyProp", { value: "Smith", writable: false });
Object.defineProperty(exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } });
Object.defineProperty(exports, "readonlyAccessor", { get() { return 21.75 } });
Object.defineProperty(exports, "setonlyAccessor", {
/** @param {string} str */
set(str) {
this.rwAccessors = Number(str)
}
});
This is not being treated as a module for some reason? I don't think I did anything to affect this, probably another bug.
That was previously set for |
Theoretically, the tsconfig parser will set this default for |
shouldAddFile := moduleName != "" && | ||
getResolutionDiagnostic(optionsForFile, resolvedModule, file) == nil && | ||
!optionsForFile.NoResolve.IsTrue() && | ||
!(isJsFile && !optionsForFile.GetAllowJS()) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!(isJsFile && !optionsForFile.GetAllowJS()) && | |
(!isJsFile || optionsForFile.GetAllowJS()) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a direct port, but I could change it.
resolvedFileName := resolvedModule.ResolvedFileName | ||
isFromNodeModulesSearch := resolvedModule.IsExternalLibraryImport | ||
// If this is js file source of project reference, dont treat it as js file but as d.ts | ||
isJsFile := !tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedTSExtensionsWithJsonFlat) && p.projectReferenceFileMapper.getRedirectForResolution(ast.NewHasFileName(resolvedFileName, p.toPath(resolvedFileName))) == nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this just the following? Just a faithful translation?
isJsFile := !tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedTSExtensionsWithJsonFlat) && p.projectReferenceFileMapper.getRedirectForResolution(ast.NewHasFileName(resolvedFileName, p.toPath(resolvedFileName))) == nil | |
isJsFile := tspath.FileExtensionIsOneOf(resolvedFileName, tspath.SupportedJSExtensionsFlat) && p.projectReferenceFileMapper.getRedirectForResolution(ast.NewHasFileName(resolvedFileName, p.toPath(resolvedFileName))) == nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, all of this is a faithful port.
Object.defineProperty(module.exports, "thing", { value: "yes", writable: true }); | ||
+ ~~~~~~ | ||
+!!! error TS2580: Cannot find name 'module'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`. | ||
Object.defineProperty(module.exports, "readonlyProp", { value: "Smith", writable: false }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seemingly this is broken because the new code does not yet handle defineProperty
based exports. But, it's not clear to me why this succeeded in the past.
// reprocess its subtasks to ensure they are loaded. | ||
loadedTask.lowestDepth = currentDepth | ||
subTasks := task.getSubTasks() | ||
w.start(loader, subTasks, currentDepth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The subtasks may or may not have been elided when they were seen at a lower depth—is there a mechanism here to skip them if they’ve already been run?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They'll be deduped by the start
function; if they're at a lower depth the code in this block will skip walking any further, and the loaded
check will have also skipped loading the source file and other info again.
Fixes #931
This was tricky to deal with in a concurrent loader.
The gist of it is that we keep track of the current "JS file depth" as we recurse. If a subtask about to be enqueued is a JS file from
node_modules
, we skip it if the current depth of JS files is too high. If the depth is okay, we'll load it, then recurse. If we ever revisit the same file again, we check to see if the new depth is lower than the last time the file is checked, and if it is we'll recheck its subtasks at that new depth (potentially loading more files).While here, I've simplified a few things; namely I remembered the trick to have a self-referencing generic method and implemented
noResolve
.Sadly, there's now a mutex per file, but I can't think of a cleaner method. The only place where this would matter is when the same file is referenced multiple times, in which case we need to recheck it serially anyhow.
We don't seem to have any tests for
maxNodeModuleJsDepth
; I'll think about how to make some. I'm also not setting upmaxNodeModuleJsDepth
for the the editor. I'm not sure where that goes.