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

update babylon to babel/parser 7.x #30

Merged
merged 23 commits into from
May 29, 2020

Conversation

firsttris
Copy link
Contributor

@firsttris firsttris commented Jan 24, 2020

Hey jest-community,

i update babylon to babel/parser 7.x as suggested by @seanpoulter #29

now the typescriptt_parser.js is actually no longer relevant and could possibly be removed. also the typescript dependency in package.json.
since the babel_parser.js is now able to parse typescript as well.

i did not delete typescript_parser.js and corresponding test yet. (even if it would no longer be used after this PR)

i add a addtional test - babel_typescript_parser.test.js which executes babel_parser in typescript mode.

i checked that all tests are green, and fixed a few eslint issues.

if you are happy with this PR, i would proceed update the jest parser to new features like test.each.

regards
Tristan

Copy link
Member

@stephtr stephtr left a comment

Choose a reason for hiding this comment

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

Why would we want to keep typescript_parser.js but not babylon_parser.js?

fixtures/parser_tests.js Show resolved Hide resolved
src/parsers/babel_parser.js Outdated Show resolved Hide resolved
src/parsers/babel_parser.js Outdated Show resolved Hide resolved
@connectdotz
Copy link
Collaborator

connectdotz commented Jan 26, 2020

@firsttris thanks for the PR, before diving into the code, here is a conversation over a year ago that you might find relevant.

IMHO, the most uncertain part of this migration is the plugin list. We used to load all the plugin (yeah, that is a bit crazy), now with an explicit plugin list, I am not sure if we will encounter issues that the user plugin list != our parser's. Will that be an issue for parsing their code? If it does, do we need to consider allow users to pass in their plugin list or even reading their babel config? (a can of worms...) Thoughts?

@firsttris
Copy link
Contributor Author

firsttris commented Jan 26, 2020

reading the users babel config sounds complex to me . big fan of kiss principle.

if the parser supports more features that then user is using everything works well.
if the parser does not support features the user is using it will probably not parse the code and generate errors.

if adding all plugins has worked before.. why not continue this way?

i tried to add as many plugins as possible.
there was no measurable speed difference when adding all those plugin.
(did a tests but exacly the same ms when executing tests)

some plugins:

  • decorators
  • pipelineOperator
    did not work

they outputed this errors:
The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean. If you are migrating from Babylon/Babel 6 or want to use the old decorators proposal, you should use the 'decorators-legacy' plugin instead of 'decorators'.
'pipelineOperator' requires 'proposal' option whose value should be one of: 'minimal', 'smart', 'fsharp'

i actually added them as an array of strings?

also removed the typescript_parser as @stephtr suggested.

@connectdotz
Copy link
Collaborator

connectdotz commented Jan 26, 2020

if adding all plugins has worked before.. why not continue this way?

reasonable starting point.

some plugins ... did not work

see discussion

i actually added them as an array of strings?

should be... but we should probably create some fixtures with some of these features, such as optional-chaining, dynamic import etc, to make sure they can be parsed.

@stephtr
Copy link
Member

stephtr commented Jan 26, 2020

Will that be an issue for parsing their code? If it does, do we need to consider allow users to pass in their plugin list or even reading their Babel config?

There could be situations where Babel won't work with our configuration, but I'm quite sure that also the Babylon parser (as it is currently used) would have failed for them, it therefore wouldn't be a regression.

@rossknudsen rossknudsen mentioned this pull request Jan 26, 2020
Copy link
Member

@seanpoulter seanpoulter left a comment

Choose a reason for hiding this comment

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

Hurrah! I think this is a big step in the right direction! Thank you! There's only one question that @connectdotz and/or @stephtr didn't seem to already cover - is the CHANGELOG.md OK like that? I'll approve it now so we're not stuck with me being sloooooooooow. 😪

You've already had the discussion about use plugins. We'll probably want a seam / way for the user to provide options, but we can add options to the parse functions in another PR.

CHANGELOG.md Outdated Show resolved Hide resolved
fixtures/parser_tests.js Show resolved Hide resolved
fixtures/parser_tests.js Show resolved Hide resolved
fixtures/parser_tests.js Show resolved Hide resolved
src/parsers/babel_parser.js Outdated Show resolved Hide resolved
src/__tests__/runner.test.js Show resolved Hide resolved
@seanpoulter
Copy link
Member

Oh!! I am tired and forgot to ask about Yarn. Does Yarn update package-lock.json now too or did you use npm? I'm not bothered by the politics of it, I just want to make sure we're all on board with our build process (which seems to be undocumented).

Copy link
Collaborator

@connectdotz connectdotz left a comment

Choose a reason for hiding this comment

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

@stephtr and @seanpoulter already covered many grounds, I will just add a few relatively simple requests. I think we are quite close to merging this!

P.S. I assume you are going to do the actual parser change for the test.each in a separate PR, this is just to switch over to the babel-7 world, right?

src/parsers/babel_parser.js Outdated Show resolved Hide resolved
src/parsers/index.js Outdated Show resolved Hide resolved
@firsttris
Copy link
Contributor Author

firsttris commented Feb 2, 2020

are going to do the actual parser change for the test.each in a separate PR, this is just to switch over to the babel-7 world, right?

yes, in those enterprises they told to always keep my PR's small :)

i don't wanted to extend two parsers.

@firsttris
Copy link
Contributor Author

Oh!! I am tired and forgot to ask about Yarn. Does Yarn update package-lock.json now too or did you use npm? I'm not bothered by the politics of it, I just want to make sure we're all on board with our build process (which seems to be undocumented).

i think i used npm, as far as i know package-lock.json is only created by npm

@connectdotz
Copy link
Collaborator

i think i used npm, as far as i know package-lock.json is only created by npm

I wonder if we allow both yarn and npm lock files, will we encounter a situation that developers will end up with different versions of the dependencies based on their pm preference? Or otherwise we will ask developers to update both lock files by running boh yarn and npm? 🤔 Maybe it is best to standardize on the PM, which right now is yarn...

src/parsers/index.js Outdated Show resolved Hide resolved
Copy link
Collaborator

@connectdotz connectdotz left a comment

Choose a reason for hiding this comment

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

@firsttris lots of good change here 👍, a few notes:

  • plugin customization: nice feature, but suggest we still have a solid default, more detail inline
  • readme: great start, some minor comment inline, might need to be updated if plugin customization changed.
  • npm support: personally I prefer us to simply standardize on yarn. But if you would like to add npm support that would be fine as long as there is a mechanism to sync the 2 lock files automatically so they won't get out of sync.

Comment on lines 174 to 180
export const plugins = ['jsx', 'classProperties'];

// Its not possible to use the parser with flow and typescript active at the same time
export const parseJs = (file: string, data: ?string, additionalPlugins: string[] = []): ParseResult =>
parse(file, data, {plugins: [...plugins, ...additionalPlugins, 'flow']});
export const parseTs = (file: string, data: ?string, additionalPlugins: string[] = []): ParseResult =>
parse(file, data, {plugins: [...plugins, ...additionalPlugins, 'typescript']});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Allow customization of the plugin is great 👍 , but I think I would make it more "optional" by providing a solid default set of plugins but allow override (customization might mean add or remove plugins). I think this way it provides the least interruption while adding flexibility.

Copy link
Contributor Author

@firsttris firsttris Feb 25, 2020

Choose a reason for hiding this comment

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

i provided a more solid list of default plugins. (for feature i see used more regularly).
With spreading those plugins together the consumer is able to add addtional plugins.
But i don't see why anyone would want to remove plugins, this would require a different implementation. maybe like: use the alternativePlugins instead of plugins if provided.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
parse('fileName.ts', codeTobeParsed, false, additionalPlugins);
expect(spy).toBeCalledWith(codeTobeParsed, parserConfigTypescript);
});
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

not sure if I missed it but I didn't see any additional fixture for testing plugin specific syntax?

Copy link
Contributor Author

@firsttris firsttris Feb 9, 2020

Choose a reason for hiding this comment

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

no you didn't missed them, i have not added any yet.
i thought about this topic, normally you would only test your package, not the 3rd party depdenencies the project is using.
the plugin features should have already been tested in the babel project.

i mean we could not even fix a issue, if some tests were red, since its not within this project.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see where you are coming from. I think I am less concerned about "if babel implemented the plugin correctly" but "if the plugin list we passed in has the effect we anticipated"...

I played with the new babel-parser_plugin.test.js to try to answer my own question:

  • comment out all additional plugins, it passed; ok, maybe all of our code fixures/snippets are just standard js that requires no additional plugin...?
  • passed in a garbage plugin, it still passed. ok, maybe babel load plugin like a best-effort...?
  • I then created some optional chaining code-snippet with empty additional plugin list, thinking for sure it should fail without passing the correct plugin, right? But surprise surprise, it still passed.

At this point, I feel there is something I don't understand or misunderstand about this plugins thing... maybe it is reading the babel.config.js locally? does that mean it will be impacted by users' env as well once we deployed, which might be good, or bad... How do tools like vscode-jest or yours decide what plugin list to pass in? If they can't decide then should all users now need to pass in their own list, even if they don't use babel? With the current implementation (minimal default), how disruptive the next release will be? Do we really need to get tangled with the rather complex user babel config/env?

Anyway, tests mean to surface issues, and I think without the simple additional tests I would not have discovered the unexpected behaviors and questions... in addition to tests, we should answer the questions above to make sure we fully understand what the community and users might face with these changes... thoughts?

Copy link
Contributor Author

@firsttris firsttris Feb 11, 2020

Choose a reason for hiding this comment

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

i don't have an answer to your questions yet but i appreciate that you are trying to understand it properly. so please don't get my comment wrong.

just one side thought, which might be interesting (in terms of testing)

majestic doesn't seem to take this topic that seriously:
https://github.com/Raathigesh/majestic/blob/master/server/services/ast/parser.ts#L10

they just use 3 plugins => "jsx", "classProperties", "optionalChaining"

Copy link
Contributor

Choose a reason for hiding this comment

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

Hey @connectdotz. I had a look at this too and think that I've made some headway. Have a look at this babel documentation that I found helpful (I thought I knew what the plugins did by the names - I wasn't always right). That page will give you some useful snippets to test with later on.

Experimenting with babel-parser_plugin.test.js:
Hopefully I'm not pointing out the obvious, but this file is aimed at testing whether the correct plugin config is passed to the parser rather than whether that configured parser can parse the code correctly. You can see this by the fact that the "code" it is asked to parse is on line 26:

const codeTobeParsed = 'const bla = 1';

which as you can see is pretty simple JS and is not testing any of the experimental language features that the plugins are supposed to be supporting. Which is probably why when you removed all the plugins, it still parsed correctly and the tests passed.

When I extended that line with snippets from the Babel documentation like this:

const codeTobeParsed = `
//classPrivateProperties
class A { #b = 1; }

//classPrivateMethods
class B { #c() {} }

//doExpressions
var a = do { if (true) { 'hi'; } };
`;

I got test failures when the appropriate plugins were not enabled. Hope that helps.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

exacly @rossknudsen this test was only to verfiy if the addtionalPlugins have been merged with the default plugins correctly.

since i have added this feature i thought it make sense to test it.

Copy link
Contributor Author

@firsttris firsttris Feb 25, 2020

Choose a reason for hiding this comment

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

also did some research on this topic.

babel-parser_plugin.test.js is a good place to test the babel plugins.

i found that for example ObjectRestSpread works even if no plugin is activated. While classPrivateProperties or doExpressions do only work with plugins activated.

that is probably because some proposal are already on a later stage and work even without explicitly activating them.

ObjectRestSpread and OptionalChaining are already in stage 4.

does this answer your concerns @connectdotz ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@firsttris yes it does! thanks for doing the research 👍

I also dig into the babel-parser code today and found that it checked for only a small set (~11) of plugins, such as logicalAssignment, classProperties, and the document did mention

The latest ECMAScript version enabled by default (ES2017).

This is great and does eliminate my biggest concern. Obviously, as the language evolves the extra plugin list will too, but as long as we keep the babel-parser up to date we should be able to support the majority of the use cases.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Another take away from babel-parser code: The logic to recognize and process these non-standard language features are already in the parser, the plugin strings are just like flags to allow processing the corresponding syntax if encountered in the content-to-parse.

For jest-editor-support, I don't see much downside to allow the parser to parse as much as it can. If the users choose to constraint it for their specific use case, which should be rare, they can certainly provide its plugin list to narrow and override the default.

there are 2 plugins require additional flags, if there is really no obvious winner (more commonly used), then whichever flag is fine, provided we document it so users know how to override it if need to.

There is no point to pass in "new" plugin because the babel-parser we packaged will not understand them anyway...

@rossknudsen
Copy link
Contributor

rossknudsen commented Feb 26, 2020

@firsttris yeah it's because the JS files have Flow typings in them. TS compiler doesn't understand them. Which is why we're using Babel to transpile, as it understands everything.

So the tsconfig is really only being used to typecheck the TS files and we want it to ignore the JS files.

@firsttris
Copy link
Contributor Author

hey @connectdotz & jest-community, i did my best to implement your suggestions and change requests.

If you have additional change request please let me know. once i find time between my worktime, i will do my best to implement them.

really want to continue extend that parser with test.each support, i see many projects heavely using this and our addons are not supporting this feature.

From the user's perspective, that's a bug.
jest-community/vscode-jest#427
firsttris/vscode-jest-runner#55

@connectdotz
Copy link
Collaborator

hey @firsttris sorry for the long delay, was really busy this month, I will try to take a look this weekend, thanks for being patient.

Copy link
Collaborator

@connectdotz connectdotz left a comment

Choose a reason for hiding this comment

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

hey @firsttris not sure if you are still interested in this PR or maybe we both are waiting for the other to take the next step...?

I see the major blocker is in how we invoke babel-parser, i.e. the options, as well as how we customize it... see the inline comments.

This change will most likely impact the README, tests, and maybe others... let me know when you are happy with the changes, I will do a final review then

Sorry for such a long delay, hope you haven't given up...

CHANGELOG.md Outdated Show resolved Hide resolved
Comment on lines 174 to 189
export const plugins = [
'jsx',
'classProperties',
'exportDefaultFrom',
'logicalAssignment',
'nullishCoalescingOperator',
'objectRestSpread',
'optionalChaining',
'topLevelAwait',
];

// Its not possible to use the parser with flow and typescript active at the same time
export const parseJs = (file: string, data: ?string, additionalPlugins: string[] = []): ParseResult =>
parse(file, data, {plugins: [...plugins, ...additionalPlugins, 'flow']});
export const parseTs = (file: string, data: ?string, additionalPlugins: string[] = []): ParseResult =>
parse(file, data, {plugins: [...plugins, ...additionalPlugins, 'typescript']});
Copy link
Collaborator

Choose a reason for hiding this comment

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

giving the plugins here are just "flags" for the babel-parser, I suggest we add all of them, you can reference their list here.

Once we enabled everything, there is no point to add "additional"... the customization should be very rare, if any, and it could be simply an override.

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 was not possible to add every plugin, but i added almost every plugin. i removed the ones which caused conflicts.

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 wonder if adding all those plugins is even necessary

@firsttris
Copy link
Contributor Author

firsttris commented Apr 22, 2020

hey @connectdotz to be honest is was not totally clear for me what tasks where missing to complete this PR.
the PR is really big, and its seems not really transparent in general on github.

to summarize

the open tasks are:

  • we remove the option to pass additional plugins, instead we include all plugins
  • update readme accordingly
  • update changelog (add author)

do you see any additional changes to be done @connectdotz ?
(sorry if i missed something the PR is so big)

@connectdotz
Copy link
Collaborator

@firsttris your summary is right, I will take another look when you are done...

@firsttris
Copy link
Contributor Author

did it

but travis now says

The command "eval yarn --frozen-lockfile " failed 3 times.
The command "yarn --frozen-lockfile" failed and exited with 1 during .

what can i do about it?

@rossknudsen
Copy link
Contributor

This is the error:

error semver@7.3.2: The engine "node" is incompatible with this module. Expected version ">=10". Got "8.17.0"

I think you need to change the node version to 10 in the Travis config. I think I had to do that in my PR.

@firsttris
Copy link
Contributor Author

thx @rossknudsen that worked.

just coveralls is complaining now.

Copy link
Collaborator

@connectdotz connectdotz left a comment

Choose a reason for hiding this comment

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

@firsttris thanks for the update, we are almost there! a few non-blocking document comments, and a question about the plugin list.

Don't worry about coverage complaint, we should be good to go once we resolve the issues below

README.md Outdated Show resolved Hide resolved
- filePath = Path to the file you want to parse.
- serializedData = Serialized data, will be used instead of the filePath if available (optional).
- strictMode = If this option is activated the parser throws an exception if the filetype is not detected, defaults to false.

Copy link
Collaborator

Choose a reason for hiding this comment

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

great way to start documenting the API 👍 , can we throw in an example, I am a big fan of "learn-by-example'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

would be best to create an example with typescript and to link it in the readme (maybe follow up PR)

package.json Outdated Show resolved Hide resolved
Comment on lines +174 to +198
export const plugins = [
'asyncGenerators',
'bigInt',
'classPrivateMethods',
'classPrivateProperties',
'classProperties',
'doExpressions',
'dynamicImport',
'estree',
'exportDefaultFrom',
'exportNamespaceFrom', // deprecated
'functionBind',
'functionSent',
'importMeta',
'jsx',
'logicalAssignment',
'nullishCoalescingOperator',
'numericSeparator',
'objectRestSpread',
'optionalCatchBinding',
'optionalChaining',
'partialApplication',
'throwExpressions',
'topLevelAwait',
];
Copy link
Collaborator

Choose a reason for hiding this comment

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

looks like there is something missing from the babel plugin list, is it intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

there are conflicts between various plugins, tried to include all and removed the ones which caused conflicts

@connectdotz
Copy link
Collaborator

hmm... on the 2nd thought, I think this is a good enough start, I can fix the remaining minor issues in another PR so we can free you to move on to the original thing you wanted to fix:

if you are happy with this PR, i would proceed update the jest parser to new features like test.each.

@firsttris if there is anything you want to add I can wait, otherwise I can merge it tonight.

@firsttris
Copy link
Contributor Author

@connectdotz i'm rdy

@connectdotz connectdotz merged commit 5e122c5 into jest-community:master May 29, 2020
@connectdotz
Copy link
Collaborator

@firsttris thank you for your hard work 🙏 and sorry it took so long.

@seanpoulter
Copy link
Member

Yay! Thank you Tristan! 🥇

@connectdotz
Copy link
Collaborator

@firsttris while testing the new typescript babel_parser, noticed a discrepancy vs the old typescript parser. While the old parser does not return the right "name" for the jest.each, it still returns the test block. The new parser completely skipped the block...

If you already started to work on the jest.each then I will just wait, otherwise, I can take a look to at least closing the parity...

@firsttris
Copy link
Contributor Author

Have not yet started looking in to this topic.

@connectdotz
Copy link
Collaborator

ok, I did some quick fix at #47, would love to have you review it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants