Preserving space
wenq1 opened this issue ยท 21 comments
I have a replacer like this:
let js_source = `testFunc (a, b);`;
let replacer3 = {
report: () => 'nil',
replace: () => ({
'testFunc (__args)': ({__args}, path1) => {
__args.splice (0, 0, __args[1]);
return path1;
},
}),
};
let js_output3 = putout (js_source, {
plugins: [
['replacer3', replacer3],
],
});The output becomes, testFunc(b, a, b), instead of testFunc (b, a, b) which preserves the original spacing. Can space preservation be achieved? For now I just use a linter as a post-step, which I don't think should be necessary.
Further to the question, if js_source is set to testFunc (/** @type a */ (a), b);, the output becomes testFunc/** @type a */(b, a, b);, which adds up to the spacing issue.
Very nice library indeed!
The thing is ๐Putout is code transformer and it do AST-transformation mostly, for formatting you can use ESLint, or prettier, they are best in this feild.
To achive the best possible results I suggest you to use eslint-plugin-putout, you can add your config on top of it, and set whitespaces count with help of indent rule.
Thanks. Iโm using custom plugins, and traverse the Filesystem manually, so eslint can only be used as a post step.
Regarding the second case, the output becomes testFunc/** @type a */(b, a, b);, which looks to me like a bug? As it messes up with the Jsdoc types fed into typescript.
Regarding the second case, the output becomes testFunc/** @type a */(b, a, b);, which looks to me like a bug? As it messes up with the Jsdoc types fed into typescript.
As I see testFunc (/** @type a */ (a), b); transformed to testFunc(/** @type a */ a, b); this is the same result you will have using no-extra-parens of ESLint.
spacing issue is fixable. Let's take a look again at /** @type */ issue. I provide a screenshot below:
Case1:
let js_source = `testFunc (/** @type {string} */ a, b);`;
let replacer3 = {
report: () => 'nil',
replace: () => ({
'testFunc (__args)': ({__args}, path1) => {
__args.splice (0, 0, __args[1]);
return path1;
},
}),
};
let js_output3 = putout (js_source, {
plugins: [
['replacer3', replacer3],
],
});
console.log (`- js_source: ${js_source}`);
console.log (`- js_output3.code: ${js_output3.code}`);Result:
[2023/02/12 10:40:45.433] - js_source: testFunc (/** @type {string} */ a, b);
[2023/02/12 10:40:45.435] - js_output3.code: testFunc(b, /** @type {string} */ a, b);
Case2:
let js_source = `testFunc (/** @type {string} */ (a), b);`; // this line is different from above
let replacer3 = {
report: () => 'nil',
replace: () => ({
'testFunc (__args)': ({__args}, path1) => {
__args.splice (0, 0, __args[1]);
return path1;
},
}),
};
let js_output3 = putout (js_source, {
plugins: [
['replacer3', replacer3],
],
});
console.log (`- js_source: ${js_source}`);
console.log (`- js_output3.code: ${js_output3.code}`);Result:
[2023/02/12 10:42:10.574] - js_source: testFunc (/** @type {string} */ (a), b);
[2023/02/12 10:42:10.574] - js_output3.code: testFunc/** @type {string} */(b, a, b);
We are talking about case 2 here. Look at /** @type {string} */ here. It is before the parenthesis, not inside, which is completely wrong.
This is related mostly to Babel and Recast, ๐Putout build on top of them, so you better write to that repositories about such issues with comments.
Better mention that in the docs.
Look comments is usually a bad practice, they should be made in rare cases when you need to clarify why bad code written. Why don't you just use TypeScript if you need types?
Better mention that in the docs.
PR's are welcome.
OK, we have 3 variants:
- โ
jscodeshift; - โ
jscodeshift + babel; - โ
babel
So the problem in recast. Do you have ideas for a PR? I can merge it to my fork it will be 10 times faster.
Just made in issue benjamn/recast#1272.
Landed support of CallExpression to @putout/recast v1.12.0.
Please re-install ๐Putout. You can support project if it helpful to you :).
Better mention that in the docs.
PR's are welcome.
See #130. Now another question raised based on this: how can we tell whether it is indeed a recast bug or it is a putout one?
Look comments is usually a bad practice, they should be made in rare cases when you need to clarify why bad code written. Why don't you just use TypeScript if you need types?
Not today, thanks.
Regarding the recast issue, I briefly took a look.
The "leading comment" should be for argument1, not for the callee in the CallExpression.
Is fixed version works for you?
is a new version published? I'm currently on 2.16.0
2.16.0 is version of what?
Landed support of CallExpression to @putout/recast v1.12.0.
Please re-install ๐Putout. You can support project if it helpful to you :).
yes it now resolves the commentary issue.
However, the output is still wrong.
Input:
testFunc (/** @type {string} */ (a), b);
Should be transformed into
testFunc(b, /** @type {string} */ (a), b);
not
testFunc(b, /** @type {string} */ a, b);
This is the the way to do casting with JSDoc to allow tsc to work with JS files.
There is no way to keep ( and ).
Have you considered allowing an option to use Prettier with putout? I just came across it and reading its docs. It seems to be a better fork of benjamin's recast's printer.
== Edit: its a bad idea as it seems after I read its doc.
I have experimented with recast the whole afternoon.You are correct. There's a zillion way the output formatting went horribly wrong. (e.g. benjamn/recast#297 is really getting me mad...)
I have experimented with recast the whole afternoon.You are correct. There's a zillion way the output formatting went horribly wrong. (e.g. benjamn/recast#297 is really getting me mad...)
You have a couple options to not be mad:
- Create a better tool, why not? If it will support everything Recast supports, and will have the same API I'll switch :).
- Try to understand Recast codebase, thing that guys doing really-really-really hard (and not really interesting to spend years on).
- Try to understand how comments presented in AST, if we talk about Babel, you have some kind of
leadingCommentsandtrailingCommentsas node properties, but if we talk aboutESTree, the only thing we have is an arraycommentson top of AST:

And try to understand is it leadingComments or trailingComments? Do you have any ideas of algorithm to determine this? Is it a lot of fun to think about it?
Recast supports both, and this is some kind of magic, that we can automatically transform codebase and keep it in "our style", if our style is more or less looks similar to others code, and simple enough to be determined programmatically.
I have experimented with recast the whole afternoon.You are correct. There's a zillion way the output formatting went horribly wrong. (e.g. benjamn/recast#297 is really getting me mad...)
You have a couple options to not be mad:
- Create a better tool, why not? If it will support everything Recast supports, and will have the same API I'll switch :).
- Try to understand Recast codebase, thing that guys doing really-really-really hard (and not really interesting to spend years on).
- Try to understand how comments presented in AST, if we talk about Babel, you have some kind of
leadingCommentsandtrailingCommentsas node properties, but if we talk aboutESTree, the only thing we have is an arraycommentson top of AST:

And try to understand is it leadingComments or trailingComments? Do you have any ideas of algorithm to determine this? Is it a lot of fun to think about it?
Recast supports both, and this is some kind of magic, that we can automatically transform codebase and keep it in "our style", if our style is more or less looks similar to others code, and simple enough to be determined programmatically.