-
Notifications
You must be signed in to change notification settings - Fork 201
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
Calling .replaceWithText(getFullText(...)) is inconsistent #721
Comments
Perhaps related to #178 |
@abirmingham I'll read this and answer it sometime soon, but perhaps consider just doing the following: if (functionDec.isDefaultExport()) {
// will remove if it's default exported on a separate line
functionDec.setIsDefaultExport(false);
// Side note: I should have named this setIsNamedExport... will open an issue about that
functionDeclaration.setIsExported(true);
} Does doing that not work here? |
@dsherret that did work! Thank you very much :) |
Just read this now. So when using Instead, you'll want to use I just ran this test: const { Project } = require("ts-morph")
const project = new Project({ useVirtualFileSystem: true });
const sourceFile = project.createSourceFile("test1.ts", `// tslint:disable-next-line:no-any only-arrow-functions
export default function Foo() {}`);
const sourceFile2 = project.createSourceFile("test2.ts", `/** This is Foo */
export default function Foo() {}`);
const sourceFile3 = project.createSourceFile("test3.ts", ` /**
* Comment
*/
// tslint:disable-next-line:only-arrow-functions
export function Foo() {
}`);
doTest(sourceFile);
doTest(sourceFile2);
doTest(sourceFile3);
function doTest(sourceFile) {
const func = sourceFile.getFunctions()[0];
func.replaceWithText(func.getText(true));
console.log(sourceFile.getFullText());
} And it outputs the following as I would expect: "// tslint:disable-next-line:no-any only-arrow-functions\nexport default function Foo() {}"
"/** This is Foo */\nexport default function Foo() {}"
" /**\n * Comment\n */\n // tslint:disable-next-line:only-arrow-functions\nexport function Foo() {\n}" I've opened #725 to update the documentation to recommend using But yes, please use the regular api for doing this (ex. |
Thanks so much for the above-and-beyond explanation @dsherret ! I really appreciate that. I think that you see my confusion, but I wanted to give you a smaller example that illustrates how this can be confusing: declare const node: Node;
node.replaceWithText(node.getFullText()); As a user I would expect this to be a no-op, but that only seems to be the case if there is no JSDoc comment. If there is a JSDoc comment, the comment is duplicated. Anyway I think this smaller example is probably redundant at this point, as you understood my confusion and explained the reasoning well, but I wanted to add it because I realized that I could describe my original point of confusion with fewer words :) Finally, I wonder if there should be a |
Yeah, it's slightly confusing, but that's what the compiler API does. In the compiler API and ts-morph it returns all the text from the last significant token of the previous node (comments not included) to the end of the node. So for example, calling
Finally,
Do you mean, the comment is duplicated? (not the jsdoc comment) Could you show an example where it duplicates the jsdoc comment? That might be a bug.
|
@dsherret thanks again for the thoughtful response!
Example import { Project, SyntaxKind } from 'ts-morph';
const printWithSeperator = (header: string, str: string) => {
console.log(`-- ${header} --`);
console.log(str + `\n`);
};
const project = new Project();
const file = project.createSourceFile(
'src/tmp.ts',
[
`// tslint:disable-next-line:no-any`,
`const printName = (name: any) => console.log(name);`,
].join(`\n`),
);
// Print initial file
printWithSeperator('file.getFullText()', file.getFullText());
// Loop through children of SyntaxKind and print them (note dupe in output)
printWithSeperator(
'file.getChildren()[0].getChildren()...',
file
.getChildren()[0]
.getChildren()
.map(x => x.getFullText())
.join(', '),
);
// Get 'printName' variable statement
const functionDec = file.getFirstDescendantByKindOrThrow(
SyntaxKind.VariableStatement,
);
// Replace functionDec with text of itself
functionDec.replaceWithText(functionDec.getFullText());
// Print final file (note dupe in output)
printWithSeperator('file.getFullText()', file.getFullText()); Prints
Note the duplicate comment that appears in the second and third printed blocks. Again, I'll likely steer clear of Anyway, hope that helps! |
@abirmingham so in that scenario in the compiler api there is actually only one child that's the variable statement. Using Then using https://ts-ast-viewer.com/#code/PTAEBcGcBsEsDtwC4AmtIEMBG0CmBaeXAD3HziKXgHt8N4BPAAwBoBYAKAGNr5JxQABwBOCcADkMAW1ygAvKAAU8abiSh6DAJTyAfKB59qeAHTRqAc2WqtAbiA (toggle the "tree mode" in the options) Since comments are useful to know about for refactoring purposes, ts-morph superimposes certain kinds of comments so they appear in the results of So in this case, calling Generally I would recommend avoiding using |
@dsherret sorry to keep pinging you on this, but I have a question that I think is related to comment nodes, and I'm not sure if it warrants opening up a new issue. I'm writing a morph that aims to remove a selection of comments which disable the Here is a simple reproduction: import { Project, SyntaxKind } from 'ts-morph';
const project = new Project();
const file = project.createSourceFile(
'src/tmp.ts',
[
`const sorted = [5, 3, 2, 7].sort(`,
` // tslint:disable-next-line:no-any`,
` (a, b) => {`,
` if (a === b) return 0;`,
` return a < b ? -1 : 1;`,
` },`,
`);`,
].join(`\n`),
);
console.log(
file.getDescendantsOfKind(SyntaxKind.SingleLineCommentTrivia).length,
); // 0 I also tried all of the other trivia kinds, Note also that Any insight you could provide in order to accomplish this task would be greatly appreciated! |
@abirmingham sorry for not responding to this until now. By the way, I met a few of your colleagues on Friday! Hope you're feeling better this week. ts-morph only parses out comments in the position of statements or members of something like an interface or class. That said, after reading through what you wrote, I've opened up #737 to build on the work that was previously done and will probably pursue that. The current implementation is better than before, but I can definitely see how it's confusing and not so useful in your scenario. It also doesn't give people the ability to edit/remove those comments easily. For now, you'll have to parse the comments out as if you were using the compiler API... basically, you'll need to call |
@dsherret thank you as always for the thoughtful response! #737 looks great and should solve the problem. In the meantime, if I call This isn't too urgent, so I may just wait for #737, but I am curious :) Also I'm glad you were able to connect with my colleagues and I hope that TSConf was a positive experience! You're always more than welcome at the Seattle TS Meetup if you find yourself in the area. |
@abirmingham you basically have to edit the text directly using something like For sure--I'd love to come again! I actually made it to the tail end of the meetup and caught the last talk. |
@abirmingham in case you are interested, I have opened #757 that describes how this will work on a lower level (in ts-morph |
Describe the bug
Version: 4.0.1
Hello! I'm trying to migrate all
export default
cases in my codebase to named exports. In order to do so, I'm using the following code:ts-morph code
Note the acrobatics in order to define
oldText
. This is becausegetFullText()
returns bothSingleLineCommentTrivia
and js doc comments, butSingleLineCommentTrivia
exist as sibling nodes while the latter does not. SoexportAssignment.replaceWithText(x)
must definex
to include js doc comments but excludeSingleLineCommentTrivia
. This requires testing the previous sibling node. Is this desired? Am I doing it wrong?Thanks!
Example Default Import 1
Example Default Import 2
Example Default Import 3
The text was updated successfully, but these errors were encountered: