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

fix: handle deeply nested whole exports #111

Merged

Conversation

FredericEspiau
Copy link
Contributor

@FredericEspiau FredericEspiau commented Dec 19, 2024

Fixes #109

But if you have a loop in your whole exports, now you are doomed 😬

lib/util/edit.ts Outdated
@@ -92,7 +93,7 @@ const createLanguageService = ({
projectRoot: string;
fileService: FileService;
}) => {
const languageService = ts.createLanguageService({
return ts.createLanguageService({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tell me if you want me to revert these kind of changes, I've got some OCDs about this kind of stuffs 😬

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted

lib/util/edit.ts Outdated
@@ -12,6 +12,7 @@ import { MemoryFileService } from './MemoryFileService.js';
import { findFileUsage } from './findFileUsage.js';
import { parseFile } from './parseFile.js';
import { Output } from './Output.js';
import * as Export from './export.js';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've used namespaces to organise the code. This way you can do stuff like

Export.DeclarationWholeExport.isFileFound

Tell me what you think about this

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't have any particular opinion about using namespace imports (besides, it's not an issue in terms of detecting unused code since tsr can detect these 😎

Copy link
Contributor

@kazushisan kazushisan Dec 20, 2024

Choose a reason for hiding this comment

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

I’ve been thinking about this, but can we use import { foo } from 'foo' to keep the style consistent? Sorry for the confusion🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@FredericEspiau FredericEspiau force-pushed the fix/handle-deeply-nested-whole-exports branch from dbdf754 to 1e5eda1 Compare December 19, 2024 13:01
lib/util/edit.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@kazushisan kazushisan left a comment

Choose a reason for hiding this comment

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

Thank you for your awesome work 🚀

lib/util/edit.ts Outdated
@@ -536,13 +583,11 @@ export {};\n`,
}

if (changes.length === 0) {
const result = {
return {
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's your project mate, ask me and I'll do it 😄. This is done.

/**
* Whole export when the file is found within the destFiles
*/
export type FileFound = {
Copy link
Contributor

Choose a reason for hiding this comment

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

declaring a type which is almost the same seems a bit redundant. How about

export type FileFound = WholeExportDeclaration & { file: string }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this kind of case what I usually is

type Base = { ... };
type SubCase1 = Base & { ... };
type SubCase2 = Base & { ... };
type Whole = SubCase1 | SubCase2;

Because Base isn't actually a type you can use as it's not really a WholeExportDeclaration, which has either file: string or file: null, WDYT?

@@ -2,7 +2,8 @@ import ts from 'typescript';
import { Vertexes } from './DependencyGraph.js';
import { parseFile } from './parseFile.js';

const ALL_EXPORTS_OF_UNKNOWN_FILE = '__all_exports_of_unknown_file__';
const ALL_EXPORTS_OF_UNKNOWN_FILE = '#all_exports_of_unknown_file#';
Copy link
Contributor

Choose a reason for hiding this comment

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

I like your idea of using # for special keywords. Definitely better than my original implementation!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The best way to do it would be a Symbol though

lib/util/edit.ts Outdated
Comment on lines 186 to 187
*
* No need to memoize this function because `parseFile` already memoizes the file parsing.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
*
* No need to memoize this function because `parseFile` already memoizes the file parsing.

I think this comment is too much [nit]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

lib/util/export.ts Show resolved Hide resolved
lib/util/edit.ts Outdated
files,
fileNames,
options,
filesAlreadyVisited = new Set<string>(),
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that this field is exposing unnecessary choice/information outside of the function's boundary. Can this be declared inside the function?

function foo() {
 const visited = new Set();

  // do something then
  deeply(theOtherArgs, visited)
}

or maybe using a stack instead of recursively calling functions is better to have a shared context. (converting to using a stack is just a suggestion, not a must)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, I've kept the recursion because I didn't know how to do it with the stack 😄

@@ -1130,6 +1130,26 @@ export const b = 'b';`,
assert.equal(fileService.exists('/app/a_reexport.ts'), false);
assert.equal(fileService.exists('/app/a.ts'), false);
});

it('should look for deeply nested whole re-export without removing files', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the logic not supporting loops is acceptable as long as the behavior is defined 👍 Can you add a test case to assure what happens when there's a loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well your test case will just hang until you stop it, so there isn't much I can do about this

lib/util/edit.ts Outdated
@@ -12,6 +12,7 @@ import { MemoryFileService } from './MemoryFileService.js';
import { findFileUsage } from './findFileUsage.js';
import { parseFile } from './parseFile.js';
import { Output } from './Output.js';
import * as Export from './export.js';
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't have any particular opinion about using namespace imports (besides, it's not an issue in terms of detecting unused code since tsr can detect these 😎

Copy link
Contributor

@kazushisan kazushisan left a comment

Choose a reason for hiding this comment

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

Thank you!

@kazushisan kazushisan merged commit c709443 into line:main Jan 8, 2025
1 check passed
@kazushisan kazushisan added the bug Something isn't working label Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

export * doesn't work for deeply nested exports
2 participants