-
Notifications
You must be signed in to change notification settings - Fork 15
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
base: main
Are you sure you want to change the base?
fix: handle deeply nested whole exports #111
Conversation
@@ -92,7 +93,7 @@ const createLanguageService = ({ | |||
projectRoot: string; | |||
fileService: FileService; | |||
}) => { | |||
const languageService = ts.createLanguageService({ | |||
return ts.createLanguageService({ |
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.
Tell me if you want me to revert these kind of changes, I've got some OCDs about this kind of stuffs 😬
@@ -148,7 +147,7 @@ const updateExportDeclaration = (code: string, unused: string[]) => { | |||
|
|||
const printer = ts.createPrinter(); | |||
const printed = result ? printer.printFile(result).replace(/\n$/, '') : ''; | |||
const leading = code.match(/^([\s]+)/)?.[0] || ''; | |||
const leading = code.match(/^(\s+)/)?.[0] || ''; |
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.
\s
is the same as [\s]
@@ -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'; |
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've used namespaces to organise the code. This way you can do stuff like
Export.DeclarationWholeExport.isFileFound
Tell me what you think about 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.
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 😎
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’ve been thinking about this, but can we use import { foo } from 'foo'
to keep the style consistent? Sorry for the confusion🙏
dbdf754
to
1e5eda1
Compare
@@ -424,23 +475,19 @@ const processFile = ({ | |||
break; | |||
} | |||
case 'whole': { | |||
if (!item.file) { | |||
if (!Export.WholeExportDeclaration.isFileFound(item)) { |
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 had to create a type guard because TypeScript
couldn't determine that item.file
couldn't be undefined
in my deeplyGetExportNames
function
@@ -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#'; | |||
const CIRCULAR_DEPENDENCY = '#circular_dependency#'; |
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 doesn't the whole circular import issue though
@@ -128,143 +129,6 @@ const getChange = ( | |||
}; | |||
}; | |||
|
|||
type Export = |
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.
Refactored in their own files
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.
Thank you for your awesome work 🚀
@@ -536,13 +583,11 @@ export {};\n`, | |||
} | |||
|
|||
if (changes.length === 0) { | |||
const result = { | |||
return { |
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.
actually, I created the result
const intentionally so that I get the correct type inference without having to annotate the return type of the function. Would you mind reverting this?
/** | ||
* Whole export when the file is found within the destFiles | ||
*/ | ||
export type FileFound = { |
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.
declaring a type which is almost the same seems a bit redundant. How about
export type FileFound = WholeExportDeclaration & { file: string }
@@ -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#'; |
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 like your idea of using #
for special keywords. Definitely better than my original implementation!
* | ||
* No need to memoize this function because `parseFile` already memoizes the file parsing. |
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.
* | |
* No need to memoize this function because `parseFile` already memoizes the file parsing. |
I think this comment is too much [nit]
@@ -0,0 +1,16 @@ | |||
import ts from 'typescript'; |
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 just a matter of preference, but I like to avoid splitting files until its absolutely necessary. I think the export.ts
file is okay but can you move the code of namedExports.ts
and wholeExportDeclaration.ts
into this single file to align with the other parts of the project?
files, | ||
fileNames, | ||
options, | ||
filesAlreadyVisited = new Set<string>(), |
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 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)
@@ -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', () => { |
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 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?
@@ -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'; |
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 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 😎
Fixes #109
But if you have a loop in your whole exports, now you are doomed 😬