-
-
Notifications
You must be signed in to change notification settings - Fork 13
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
decaffeinate src/apm-cli.js
+ prepair file by file decaffeination
#15
Conversation
I thought I pinged you on Discord. But I do have a PR that decaffeinates the repo at #8. Not sure if you want to keep going with this method, or it could be really helpful to commit directly to the PR of cleaning up the automatic files, since they are quite ugly and not the most readable. Just wanting to make sure you're aware |
@confused-Techie |
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.
Decaffeinate is ok for me
Co-authored-by: GuilleW <[email protected]>
Co-authored-by: GuilleW <[email protected]>
It is admittedly hard to review all ~220-250 lines of code. Can you describe what method you used to decaffeinate? What steps, what programs, so that we can reproduce your output. That would make it so we don't have to manually review every single line, and instead lean a lot heavier on trusting the tool that generated the JS output. If the process you are using is extremely similar to #8, then we should indeed first decide whether to do all of this as one PR (#8) or one PR per file. As @confused-Techie mentioned. (I am sorry to say the Discord link you posted does not take me to the relevant conversation, so I'm not sure exactly what was discussed about this before, who said what, etc.) |
I review his code line by line. |
@DeeDeeG I used the notmal coffeescript compiler to convert the file and the rewrote parts with a more modern style. Reviewing line by line would be simpler than redoing this process. I will try to use the decaffeinating tool in the future to reduce the parts that are changed by me. And I didn't used #8 because it was outdated and will be hard to merge beside other pull requests. |
Thank you @sertonix. This is very helpful information. So, for example, I can run the coffeescript compiler and then do a diff with your file and review only the manual changes you made. (This is much faster than having to read the whole coffeescript file and then the whole JS file and comparing them, function by function, line by line. I don't think any of us has the coffeescript code memorized by heart, so yes, we would have had to review all of the coffeescript just to review this, but now we can look at just the manual changes.) |
I use decaffeinate-project online to convert, and refactor manually. |
I feel at this point as we talk about decaffeination tooling, I'd hate to repeat the past. But I also don't want to make anyone redo any work. Luckily the tests in this PR seem to be passing, so likely not an issue here. But going forward please make sure to take a look at our documentation, as we have guidelines about decaffeination. |
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.
Alright I've gone ahead and fully reviewed this file, while the decaffeination is absolutely fantastic, I do have some notes about the differences between the original source and JavaScript.
For some of these concerns I made a direct recommended change on the code itself. But theres two other more general concerns I wanted to share.
On Lines
- 61
- 123
- 163
Your code pattern looks something like let value = variable || defaultVariable;
While using the logical OR operator is fine and dandy, the original code has a pattern like let value = variable != null ? variable : defaultVariable;
.
My concern is I don't know exactly what values we will be dealing with here. In general use it shouldn't make a difference, but really Logical OR operators check for truthy
and falsy
meanwhile using a Ternary Operator like original used is checking specifically for null
. This could mean that we would find values like 0
, ""
or ''
as valid values, meanwhile with these changes they would instead go to the default options.
I may suggest in these locations we instead revert to the original Ternary Operators being used.
Additionally in lines:
- 67
- 83
You use a logical not !
to check values, but again that checks for truthy
/falsy
values rather than strictly null
like the original code.
Here I would again suggest to revert to checking directly for null
like variable != null
.
Personally I love the use of condensing these operations here, but just because we don't totally know what values we might find being returned in a function like this, I'd really recommend to again using the original checks. As time goes on and we find we are able, I'd love to increase the values we check for, but again only if we know then that it makes sense.
But as always, thanks a ton for contributing!
EDIT:
Thought I should comment on the changes requested below like ??
, it's along the same lines, as those values used a Ternary Operator to check if the value was null and if so change it to the defaults. But since this is an assignment, we could go ahead and use the Nullish Coalescing Operator, to check if the left hand assignment is null, and return the default, otherwise do nothing. More of just matching the original constraints that this code had.
src/apm-cli.js
Outdated
}; | ||
|
||
function printVersions(args, callback) { | ||
const apmVersion = require('../package.json').version || ''; |
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.
const apmVersion = require('../package.json').version || ''; | |
const apmVersion = require('../package.json').version ?? ''; |
src/apm-cli.js
Outdated
|
||
function printVersions(args, callback) { | ||
const apmVersion = require('../package.json').version || ''; | ||
const npmVersion = require('npm/package.json').version || ''; |
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.
const npmVersion = require('npm/package.json').version || ''; | |
const npmVersion = require('npm/package.json').version ?? ''; |
src/apm-cli.js
Outdated
function printVersions(args, callback) { | ||
const apmVersion = require('../package.json').version || ''; | ||
const npmVersion = require('npm/package.json').version || ''; | ||
const nodeVersion = process.versions.node || ''; |
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.
const nodeVersion = process.versions.node || ''; | |
const nodeVersion = process.versions.node ?? ''; |
src/apm-cli.js
Outdated
config.getResourcePath( resourcePath => { | ||
const unknownVersion = 'unknown'; | ||
try { | ||
const version = require(path.join(resourcePath, 'package.json')).version || unknownVersion; |
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.
const version = require(path.join(resourcePath, 'package.json')).version || unknownVersion; | |
const version = require(path.join(resourcePath, 'package.json')).version || 'unknown'; |
Could simply this function without declaring unknownVersion
entirely.
src/apm-cli.js
Outdated
globalconfig: config.getGlobalConfigPath() | ||
}; | ||
npm.load(npmOptions, () => { | ||
let python = npm.config.get('python') || process.env.PYTHON; |
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.
let python = npm.config.get('python') || process.env.PYTHON; | |
let python = npm.config.get('python') != null ? npm.config.get('python') : process.env.PYTHON; |
src/apm-cli.js
Outdated
npm.load(npmOptions, () => { | ||
let python = npm.config.get('python') || process.env.PYTHON; | ||
if (config.isWin32() && !python) { | ||
let rootDir = process.env.SystemDrive || 'C:\\'; |
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.
let rootDir = process.env.SystemDrive || 'C:\\'; | |
let rootDir = process.env.SystemDrive != null ? process.env.SystemDrive : 'C:\\'; |
src/apm-cli.js
Outdated
spawned.on('close', code => { | ||
let version; | ||
if (code === 0) { | ||
version = Buffer.concat(outputChunks).toString().split(' ')[1]?.trim(); |
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.
Love the use of an optional chaining operator to trim()
the version
here.
My only concern is the original decaffienated code produces
[name, version] =Array.from(Buffer.concat(outputChunks).toString().split(' '));
version = version != null ? version.trim() : undefined;
So while the trim()
is added perfectly the defaulting behavior to undefined
isn't retained. I'm not sure if this is used later on or not, but maybe should be addressed? We could add a Nullish coalescing operator to the end to check for null
or undefined
version = Buffer.concat(outputChunks).toString().split(' ')[1]?.trim() ?? undefined;
src/apm-cli.js
Outdated
if (_.isString(error)) { | ||
message = error; | ||
} else { | ||
message = error.message || error; |
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.
message = error.message || error; | |
message = error?.message ?? error; |
EDIT:
As for a quick explanation here, originally this line had the following pattern message = error.message != null ? error.message : error;
Which this checked if that specific method of error
was null. Which is a handy way to check essentially if it's a valid method of the object, while also checking the return value. With your original change we run the method and check it's return only. Which if for whatever reason that's not a valid method, we can use the Optional Chaining ?.
to check one if it's valid, then use the Nullish Coalescing operator to check the return value. Just thought this might protect against the unlikely event of message not being a valid method of error
src/apm-cli.js
Outdated
function parseOptions(args) { | ||
if (!args) args = []; | ||
const options = yargs(args).wrap(Math.min(100, yargs.terminalWidth())); | ||
options.usage("\nPulsar Package Manager powered by https://pulsar-edit.com\n\n Usage: apm <command>\n\n where <command> is one of:\n " + (wordwrap(4, 80)(Object.keys(commands).sort().join(', '))) + ".\n\n Run `apm help <command>` to see the more details about a specific command."); |
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.
We can use the quote syntax here:
options.usage(`
Usage: apm <command>
where <command> is one of:
${wordwrap(4, 80)(Object.keys(commands).sort().join(', '))}.
Run \`apm help <command>\` to see the more details about a specific command.
`)
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 will include all the spaces before the text starts. Therefor it would look like this and I think that is ugly.
options.usage(`
Pulsar Package Manager powered by https://pulsar-edit.com
Usage: apm <command>
where <command> is one of:
${wordwrap(4, 80)(Object.keys(commands).sort().join(', '))}.
Run \`apm help <command>\` to see the more details about a specific command.\
`);
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 multiline boring problem 🙄
And using this style?
options.usage(
"Pulsar Package Manager powered by https://pulsar-edit.com\n"+
"\n"+
"Usage: apm <command>\n"+
"....."
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 do you think of this method?
options.usage([
"",
"Pulsar Package Manager powered by https://pulsar-edit.com",
"",
" Usage: apm <command>",
"",
" where <command> is one of:",
` ${wordwrap(4, 80)(Object.keys(commands).sort().join(', '))}.`,
"",
" Run `apm help <command>` to see the more details about a specific command.",
].join("\n"));
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 multiline boring problem 🙄 And using this style?
options.usage( "Pulsar Package Manager powered by https://pulsar-edit.com\n"+ "\n"+ "Usage: apm <command>\n"+ "....."
Oh, I didn't thought of that. Thanks
This is now based on |
Sorry it has taken so long to get to properly reviewing this. I tried to run I don't think the code is functionally equivalent with the latest commits. (Mainly, the (Note on review etiquette: Please refrain from making huge changes (like switching to a different coffeescript compiler) while a review is already in progress. If you wanted to start over, I think it would make sense only to do that in a new PR, and let maintainers sort out the different approaches from there. But generally being patient is the preferred thing. Fundamentally changing what is on offer for review, while review is ongoing, is mostly just going makes things more complicated. Please only make major changes on an existing pull request if the reviewers say they are okay with it.) Sorry for lack of consensus before charging ahead with decaffeination in general, it seems like someone gave a casual go-ahead in Discord and a lot of work was started from that. Taking a step back to look at the bigger picture for a moment: I think it would be a lot cleaner to just run the decaffeination scripts inherent to the repo ( (More rationale for that move: ppm technically already runs the machine-decaffeinated code in production. Committing the machine-decaffeinated files would not be a radical move, but a fairly conservative one.)
(More thoughts: If we can't figure out consensus on how to clean up the machine-decaffeinated code, IMO we should just roll with the machine-decaffeinated code by default, to make sure we don't end up bike-shedding JS code style forever and ever. And this is an unfortunate type of first contribution, as it lends itself to bike-shedding and lots of small review comments, which would be require tremendous patience for a first-time contributor. Reviewers have no firm consensus to start with for how decaffeinated code should look like. It's really not great to have to all collaboratively figure this out on a first-time-contributor's first PR. So we should go into it understanding this is not an ideal situation, and it may take a lot of patience to get through it.) Sorry for the essay-length comment, just trying to sort this whole thing out as it has already gotten somewhat messy, IMO. I feel bad for the lack of timely review or clear expectations on when review will happen. But this decaf effort moved ahead rather quickly and without a complete plan for how the repo would need to be set up to accommodate the PRs, so that is what happens when things move without a detailed plan, we may enter uncharted territory and draw the map as we go. Running into snags wasn't so predictable. But it shouldn't be a surprise either, with how fast this went. I hope we can agree which way the path forward is and stick to it. Thanks for considering, everyone. |
@DeeDeeG The functions wrapping the code produced from the normal coffeescript compiler is not needed. It ensures that no globals are assigned when directly loaded from html. This is not the case for this repo. (somebody correct me if this is not the real reason but I am 100% that it is not important for this) For this and some other readability differences I strongly suggest using the decaffeinate tool. But aside from this I am ok with a pull request that decafs the complete code without manual changes. Since I have been working on other parts of pulsar lately I would really appreciate if somebody else could do that. @GuilleW you said you could work on this. Sorry if I suggest things that were not really planned. |
Also following this it would be nice is somebody could make the decaffeinate instructions in the "contributing during start" file more clear to prevent something like this in the future. |
Completely correct ! |
Waiting for a step-by-step instructions that admin agreed before working on. |
@sertonix I do apologize for the confusion here. I'll go ahead and draft an update to our decaffeination policy, and would recommend taking a look for another PR. We all really do appreciate the efforts and contributions, just want to make sure we get this right. |
This pull request is the first to decaffeinate the complete repository. It is required for further pull request because it moves
.js
files on build to the output folder.