-
Notifications
You must be signed in to change notification settings - Fork 724
Fix #1034: Improve symlink resolution in module specifier generation #1902
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
base: main
Are you sure you want to change the base?
Conversation
|
My intention is to help fix #1034, which is the only thing left blocking my team from adopting tsgo. I'm not very experienced with Go, but I wanted to expand upon @shinichy's work here: https://github.com/shinichy/typescript-go/tree/symlinks |
|
We have the same issue in our team that's stopping us from adopting So I compiled your branch and ran a test, it doesn't seem to make any difference in our code base. Just wanted to let you know. |
Extends the symlink support in GetEachFileNameOfModule to properly resolve module specifiers across symlinked packages and workspaces. Key changes: - Move knownsymlinks from compiler to dedicated symlinks package - Implement active resolution via ResolveModuleName to populate cache - Add dependency resolution from package.json to detect symlinks early - Improve ignored path handling (node_modules/., .git, .# emacs locks) - Add comprehensive test coverage for symlink resolution - Fix declaration emit to prefer original paths over symlink paths This aligns with upstream TypeScript's symlink resolution behavior, ensuring correct module specifiers in declaration files for monorepos and symlinked dependencies. Fixes baseline mismatches in: - declarationEmitReexportedSymlinkReference2/3 - symlinkedWorkspaceDependencies* tests - nodeModuleReexportFromDottedPath
Optimizes populateSymlinkCacheFromResolutions to avoid redundant dependency resolution. Previously, every module specifier generation would re-resolve all package.json dependencies. Now uses package-level caching to resolve once and reuse results. Performance improvements (measured with benchmarks): - Speed: 9.28x faster (89.2% reduction: 509µs → 55µs per operation) - Memory: 8.64x less (88.4% reduction: 597KB → 69KB) - Allocations: 9.22x fewer (89.2% reduction: 12,177 → 1,321) Key changes: - Add package-level cache tracking in KnownSymlinks - Eliminate intermediate slice allocations - Reduce redundant ToPath() calls - Add comprehensive benchmarks for symlink operations For a project with 50 dependencies and 100 files, this saves multiple seconds of compilation time by avoiding 5,000+ redundant resolutions.
Interesting. This is what I get in Linux after setting up your repo and replacing Seems like this might need some fixes for macOS. |
|
@neo773 should be fixed with the latest commit, the above errors seem like they might be actual errors or at least ones that can be fixed trivially: Patch
diff --git a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/services/imap-message-text-extractor.service.ts b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/services/imap-message-text-extractor.service.ts
index f81f151..335fe77 100644
--- a/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/services/imap-message-text-extractor.service.ts
+++ b/packages/twenty-server/src/modules/messaging/message-import-manager/drivers/imap/services/imap-message-text-extractor.service.ts
@@ -8,10 +8,12 @@ import * as planer from 'planer';
import { safeDecodeURIComponent } from 'src/modules/messaging/message-import-manager/drivers/imap/utils/safe-decode-uri-component.util';
+type DOMPurifyInstance = ReturnType<typeof DOMPurify>;
+
@Injectable()
export class ImapMessageTextExtractorService {
private readonly jsdomInstance: JSDOM;
- private readonly purify: DOMPurify.DOMPurify;
+ private readonly purify: DOMPurifyInstance;
constructor() {
this.jsdomInstance = new JSDOM('');
diff --git a/packages/twenty-server/src/utils/image.ts b/packages/twenty-server/src/utils/image.ts
index 8e98729..ad78167 100644
--- a/packages/twenty-server/src/utils/image.ts
+++ b/packages/twenty-server/src/utils/image.ts
@@ -1,4 +1,4 @@
-import { type Axios } from 'axios';
+import { type AxiosInstance } from 'axios';
const cropRegex = /([w|h])([0-9]+)/;
@@ -24,7 +24,7 @@ export const getCropSize = (value: ShortCropSize): CropSize | null => {
export const getImageBufferFromUrl = async (
url: string,
- axiosInstance: Axios,
+ axiosInstance: AxiosInstance,
): Promise<Buffer> => {
const response = await axiosInstance.get(url, {
responseType: 'arraybuffer',
diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/morph-relation/failing-field-metadata-morph-relation-creation.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/field-metadata/morph-relation/failing-field-metadata-morph-relation-creation.integration-spec.ts
index 0aa4bb7..2981c77 100644
--- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/morph-relation/failing-field-metadata-morph-relation-creation.integration-spec.ts
+++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/morph-relation/failing-field-metadata-morph-relation-creation.integration-spec.ts
@@ -1,4 +1,4 @@
-import { faker } from '@faker-js/faker/.';
+import { faker } from '@faker-js/faker';
import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util';
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; |
|
@chase Thank you for your work on this. |
|
Thanks for working on this! Fixes #1034 (comment) and #1657 also |
internal/checker/nodebuilderimpl.go
Outdated
| // This avoids TS2742 errors for internal library types when skipLibCheck is enabled. | ||
| // TODO: Remove this workaround once syntacticNodeBuilder is implemented. The root cause is that | ||
| // tsgo deeply infers types while upstream reuses existing type nodes, avoiding internal library types. | ||
| if b.ch.compilerOptions.SkipLibCheck.IsTrue() && targetFile != nil && targetFile.IsDeclarationFile { |
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 workaround seems pretty arbitrary; I'm not sure it's good even as a temporary fix, but I haven't looked into the exact situation you're trying to work around here. Is there a test for this?
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.
If I have time this weekend, I'll try to write this up. What's the right way to add test cases for this and the one in #1347 that @AlCalzone mentioned?
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.
You'd want to create a compiler test in testdata/tests/cases/compiler. Symlinks are supported (see _submodules/TypeScript/tests/cases/compiler/moduleResolutionWithSymlinks_notInNodeModules.ts for an example).
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 code in my issue should be able to be used 1:1 in such a compiler test. At least it worked when I tried my hand at this issue and failed.
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.
You can either use f.BaselineAutoImport() (ex. internal/fourslash/tests/autoImportCompletion_test.go) or f.VerifyApplyCodeActionFromCompletion() (ex. internal/fourslash/tests/gen/completionsUniqueSymbol_import_test.go)
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.
To make sure we’re understanding the problem correctly, do you have a real-world repro you can publish somewhere?
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 error is for the file similar to the snippet above, which is proprietary code. This is in a pnpm workspace, wherein this Button component is exported as part of an internal library for the workspace.
This code is valid in tsc. The code that fails is a type that's not used in the result type of Tooltip, the component used. It is used by TooltipPositioner: https://github.com/mui/base-ui/blob/e9f98ed126597668ace576d45904b31bad13b17c/packages/react/src/tooltip/positioner/TooltipPositioner.tsx#L5
Which is exported in the barrel file: https://github.com/mui/base-ui/blob/master/packages/react/src/tooltip/index.parts.ts#L4
But the package.json does not export the utility's types, and block access by: "./esm": null
So, where tsgo seems to respect the exports field for deeply inferred types, tsc doesn't seem to follow that far.
What I inferred was this area of code, dealing with module resolution styles (including respecting exports) had a bug which leads to an erroneous fallback that skips over the correctly resolved symlinks for the library: https://github.com/chase/typescript-go/blob/main/internal/checker/nodebuilderimpl.go#L529-L596
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.
What module/moduleResolution are you using in your project? tsgo always respects exports because every mode that doesn’t respect them is deprecated and not ported.
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.
To make sure we’re understanding the problem correctly, do you have a real-world repro you can publish somewhere?
Sorry, somehow missed your replies! Didn't mean to talk past you.
Unfortunately, I'm not permitted to provide anything like that without permission. As an alternative, I'm trying to make a compiler case for it, but unfortunately they all pass even without the workaround 😂
What module/moduleResolution are you using in your project? tsgo always respects
exportsbecause every mode that doesn’t respect them is deprecated and not ported.
We use "moduleResolution": "Bundler" and "module": "ESNext".
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.
I tried making a minimal reproduction as a separate repo, no error, so there's likely some complex interaction in the real codebase that causes it to misbehave.
Might revisit this later, for now the workaround has been reverted.
Extends the symlink support in GetEachFileNameOfModule to properly resolve module specifiers across symlinked packages and workspaces.
Key changes:
Fixes #1657 and #1034 (comment)
Fixes #1347