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

Convert @babel/template from Flow to TS #12317

Merged
merged 3 commits into from Nov 9, 2020

Conversation

nicolo-ribaudo
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Nov 6, 2020

Q                       A
Tests Added + Pass? Yes
Any Dependency Changes? Yes, devDeps
License MIT

This PR is extracted from #11578. Since #11578 is so big that it's almost impossible to review, I'm attempting to enable a gradual migration (package by package) from Flow to TS.

  1. Both flow and TS check their files, until we finish migrating
  2. make tscheck only works after building the monorepo. We can avoid this by migrating packages in topological order if possible.
  3. tsconfig.json files are gitignored: it's easy to compute them in make tscheck, so I think we can avoid committing one new "noise" file per folder.
  4. we need to keep flow definitions of the converted files. This is not necessarily bad, we may even publish them when we have finished.

Btw, while working on this PR I already noticed that TS in VSCode is definitely more helpful than Flow 😁

cc @zxbodya

Comment on lines +39 to +47
// Until we have converted every package, we cannot store
// .d.ts files inside lib/ because it causes conflicts
// with Babel-related type definitions in node_modules/@types
outDir: "./dts",
Copy link
Member Author

Choose a reason for hiding this comment

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

This is because, until all of our packages have .ts files, we:

  1. Rely on some packages that are still .js filed and have the corresponding node_moduels/@types/ definitions
  2. Those packages rely on our already converted packages
  3. They load the .d.ts files (only if we store them in lib)
  4. TS refuses to update the .d.ts files because they are used as inputs

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a tricky one, the issue is happening only when having kinda circular dependency - in other words, generated d.ts files in a package are somehow imported by itself while compiling. And this is something that needs to be fixed, while migrating.

I would suggest, @babel/template is just not the right starting point - dependencies of it can be migrated first, and that would solve the issue.

state.isLegacyRef.value = false;
}
} else if (state.isLegacyRef.value === false || state.syntacticPlaceholders) {
return;
} else if (t.isIdentifier(node) || t.isJSXIdentifier(node)) {
name = ((node: any): BabelNodeIdentifier).name;
name = node.name;
Copy link
Member Author

Choose a reason for hiding this comment

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

Here TS is better than flow at refining node

Copy link
Contributor

Choose a reason for hiding this comment

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

it can be even better - if to first convert @babel/types and @babel/traverse packages (there are many types missing or to be improved comparing to definitely typed)

@babel-bot
Copy link
Collaborator

babel-bot commented Nov 6, 2020

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/32124/

Comment on lines -11 to +14
export function parse(input: string, options?: ParserOptions): import('@babel/types').File;
export function parse(
input: string,
options?: ParserOptions
): import("@babel/types").File;
Copy link
Member Author

Choose a reason for hiding this comment

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

This file is just reformatted, since I enabled Prettier on TS files.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Nov 6, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 4c8ea55:

Sandbox Source
babel-repl-custom-plugin Configuration
babel-plugin-multi-config Configuration

@nicolo-ribaudo nicolo-ribaudo added the Flow -> TS Tracking repository migration from Flow to TS label Nov 6, 2020
@@ -1,31 +0,0 @@
// @flow
Copy link
Contributor

Choose a reason for hiding this comment

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

to avoid loosing file edits history, I would suggest having two separate commits (one to rename the files, and other to convert the content)

@zxbodya
Copy link
Contributor

zxbodya commented Nov 6, 2020

I agree that #11578, if considering entire thing at once - it is too big to be properly reviewed.

But a very big part of the PR is automatically converted from the flow sources, and during that it is already verified to remain exactly the same after types are removed - and so, it does not actually needs to be reviewed, it is safe to merge as is.

Except that automatic step - there are just a few bigger things that would take some time to review, but most of the commits there it a fairly trivial(that is on purpose - I avoided much refactor, trying to have only minimal type fixes, specifically to allow migration to be fast)

And so, I am not sure it worth to go really gradually keeping both flow and typescript type coverage at the same time - I would suggest that would add too much overhead.

And instead, I would suggest following bigger steps:

  • add support for having typescript sources (linter and build configration)
  • convert everything to typescript at once, but - do not yet run typecheck in CI, and do not publish generated type definitions
  • do remaining manual fixes, by the way adding finished packages to by typechecked in CI
  • align types in babel to where possible be the same as in definitely typed, and start publishing them(that is not yet in Migrate Babel from Flow to TypeScript (except Babel parser) #11578 but I already did some progress there - it is not too big)

The biggest drawback would be - for a brief time there would be no type check in the repository, but given flow coverage is not good anyway - so, I do not really worry about that.

@nicolo-ribaudo
Copy link
Member Author

(#12317 (comment)) This is a tricky one, the issue is happening only when having kinda circular dependency - in other words, generated d.ts files in a package are somehow imported by itself while compiling. And this is something that needs to be fixed, while migrating.

I noticed that the @RyanCavanaugh (TS team) was looking into circular project references (microsoft/TypeScript#33685), and the issue is marked as Awaiting More Feedback. Maybe our repository can provide an example of use case 😄

(#12317 (comment)) I would suggest, @babel/template is just not the right starting point - dependencies of it can be migrated first, and that would solve the issue.

Yeah, probably the best starting point would have been something like @babel/helper-validator-identifier which doesn't depend on other @babel/* packages. However, even if we start from something else (@babel/template in this case) is that the types of the package it imports is any until we migrate its dependencies.
However, the only untyped dependency on @babel/template is @babel/code-frame and it's used in a place where any doesn't propagate, so it isn't a real problem.

(#12317 (comment)) And so, I am not sure it worth to go really gradually keeping both flow and typescript type coverage at the same time - I would suggest that would add too much overhead.

I don't think that running both Flow and TS at the same time adds too much overhead. We run type checking as part of CI, and it's definitely not one of the slowest jobs.
During development, TypeScript is run by the editor in the background so it doesn't slow us down.


In the end, both strategies (by "conceptual" chunks as you are proposing, or by groups of packages as I'm proposing) will give the same result, so the decision should just be about what's easier for us to manage during the migration.

I prefer the approach I'm proposing because, even if the automated transform works from a theoretical point of view, there are different things that we might still want to change.
Some examples of things that can only be caught by carefully reviewing the diff (even if it's automated) that I changed in this PR are:

All those things are really nitpicks, but they improve the code quality and are harder to notice in a big automated PR.


@JLHwung / @existentialism / @hzoo / @kaicataldo Do you have any opinion on this?

@hzoo
Copy link
Member

hzoo commented Nov 6, 2020

automated transform works from a theoretical point of view

If we aren't comfortable with automated approach (I think if we were we would of already done it, and we'd have to review it either way), then just doing it slowly manually seems fine, esp if given someone is looking at it you can catch things along the way. If we start this, maybe just need to be disciplined in actually reviewing/merging and having some plan to move things over.

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Nov 7, 2020

If we aren't comfortable with automated approach

Actually, without @zxbodya's tool migrating would be order of magnitudes harder. The automated tool gives us a very good basis, but the output still needs to be tweaked (and thus, reviewed).

What I did in this PR was cherry-picking files from the other PR, and then reviewing and slightly adjusting them.

@JLHwung
Copy link
Contributor

JLHwung commented Nov 9, 2020

The automated tool gives us a very good basis, but the output still needs to be tweaked (and thus, reviewed).

💯 for the current approach. LGTM as well as type check is good. We can always iterate later.

(I have updated the colour of "Flow -> TS" label to match the theme colour of typescriptlang.org)

@nicolo-ribaudo
Copy link
Member Author

(I have updated the colour of "Flow -> TS" label to match the theme colour of typescriptlang.org)

Thanks, I had that intention but just guessed since I was too lazy to check what it should have been 😂

@zxbodya
Copy link
Contributor

zxbodya commented Nov 9, 2020

I don't think that running both Flow and TS at the same time adds too much overhead. We run type checking as part of CI, and it's definitely not one of the slowest jobs.

I mean extra work needed to keep flow working for remaining packages - like adding lib/babel-packages.js.flow in this PR or to have build/bundling config for both type systems. Not sure how much work it is, but still given that would be useful only for a brief time - might be nice to avoid.

I prefer the approach I'm proposing because, even if the automated transform works from a theoretical point of view, there are different things that we might still want to change.

When converting, the tool literally checks that output when using flow preset and output using typescript preset on converted code are the same - so it should be pretty safe from perspective of not breaking anything except the type checks.

Except automated part - there are some manual changes required to fix the differences between type systems, to make type check passing - that indeed needs a review, but can be done separately (if we are ok, to have some broken types for migration time)

The automated tool gives us a very good basis, but the output still needs to be tweaked (and thus, reviewed).

I agree there are many things that would be nice to be tweaked, but I am not sure how much of it should be done during initial migration - my feeling is, better to have as much of it as possible separately from the initial step:

  • this way migration can be faster, because less changes are to be made and so reviewed
  • might be bigger benefit - when doing additional improvements separately, it would be possible to check them against usages in the rest of codebase, which might be helpful to catch errors early

In #11578, I tired to avoid changes that are not really necessary and instead adding todo(flow->ts) where something needs probably non trivial improvement.

Also on type improvements, I would suggest after initial migration it would be nice to consider adding strict type checking in tsconfig, maybe that can be combined with other type improvements…


About migration approach - I do not really have a strong preference.

Both look fine for me, the biggest difference I see - doing each package separately - would be a bit more work, but would also result in more detailed review.

I see two main options:

  1. faster/easier (kinda done in Migrate Babel from Flow to TypeScript (except Babel parser) #11578 - only to split to separate PRs)
    • migrate everything at once (automated part)
    • update build/lint config to support only TS
    • separate PRs with type fixes/improvements
  2. a bit slower, but with more detailed review and maybe a bit safer
    • update build/lint config to support both flow an typescript (I would suggest this would be more complicated)
    • create separate PR to convert each package (automated part + manual fixes)

Lets decide on one - and then, I can split #11578 into multiple PRs(thinking to make a script for that),

  • if option 2 - one PR per package
  • if option 1 - maybe to group some packages to go together (when changes are very minimal)

Anther thing to consider, is how to deal with existing types in definitely typed, like here:
https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/babel__template

I would suggest - postpone this, and and do not publish generated types, while not everything is migrated

Once everything is in typescript - where possible update sources to match types from DefinitelyTyped(often types there are more detailed, and more importantly already used by external projects (like jest). And only then start publishing the types, and to deprecate DefinitelyTyped for newer versions.

{
files: [],
references: tsPkgs.map(({ dir }) => ({
path: path.relative(root, dir),
Copy link
Contributor

@zxbodya zxbodya Nov 9, 2020

Choose a reason for hiding this comment

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

to keep in mind - this is not always correct: some dev packages may need to not be included(because will cause cyclical dependency)

also in many cases - @babel/types, @babel/traverse would need to be added

so, I would say - this should be used only once to generate initial configs which then to be committed

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not tracking devDependencies here, because they are not used in src folders (this also avoids cycles, at least for the non-plugin packages).

@babel/types has its own type building logic (it already has its published .d.ts file) and it isn't build using tsc, so tsc already picks up the type definitions.

@nicolo-ribaudo
Copy link
Member Author

I mean extra work needed to keep flow working for remaining packages - like adding lib/babel-packages.js.flow in this PR or to have build/bundling config for both type systems. Not sure how much work it is, but still given that would be useful only for a brief time - might be nice to avoid.

I'd be glad to help with the Flow definitions! It shouldn't be too much work, and it will give me a clear idea of our API surface which is good.

Also on type improvements, I would suggest after initial migration it would be nice to consider adding strict type checking in tsconfig, maybe that can be combined with other type improvements…

100% agree 😄

Anther thing to consider, is how to deal with existing types in definitely typed, like here:
https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/babel__template

I would suggest - postpone this, and and do not publish generated types, while not everything is migrated

Yeah I agree, we shouldn't publish types yet. I think we can keep checking DefinitelyTyped (and maybe testing our types on the Jest source) as the last step.

Lets decide on one - and then, I can split #11578 into multiple PRs

Since some packages are very small, we'll go with a "mixed" approach. I have prepared a list of "batches" (they are still a small number of packages, but it's a good starting point): they don't have cycles, and they have the correct size to be properly reviewed.
Every PR should contain a commit to rename the files .js -> .ts and then the commits with the actual migration. When squashing/merging I'll make sure to keep two separate commits.

I'll cross-post this list (if it looks good to you) in your draft PR, and I'll start preparing Flow definitions for the first batch.


Batch 1:

  • @babel/helper-validator-identifier
  • @babel/highlight
  • @babel/core-frame

Batch 2:

  • @babel/generator

Batch 3:

  • @babel/helper-get-function-arity
  • @babel/helper-function-name
  • @babel/helper-split-export-declaration

Batch 4: (depends on 2 and 3)

  • @babel/traverse

Batch 5:

  • @babel/helper-module-imports

Batch 6: (depends on 3 and 4)

  • @babel/helper-annotate-as-pure
  • @babel/helper-wrap-function
  • @babel/helper-remap-async-to-generator

nicolo-ribaudo added a commit to nicolo-ribaudo/babel that referenced this pull request Nov 9, 2020
Co-authored-by: Bogdan Savluk <savluk.bogdan@gmail.com>
nicolo-ribaudo added a commit to nicolo-ribaudo/babel that referenced this pull request Nov 9, 2020
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
@zxbodya
Copy link
Contributor

zxbodya commented Nov 9, 2020

I'd be glad to help with the Flow definitions! It shouldn't be too much work, and it will give me a clear idea of our API surface which is good.

As an option to help with flow type definitions - it should be possible to use compilation result after converting to TypeScript.

It is possible to bundle d.ts files(using some of tools mentioned here: timocov/dts-bundle-generator#68, api-extractor btw looks to be most advanced, and probably can be used in future to generate api documentation for babel - but it has some limitations). When d.ts bundle is ready - flowgen can be used to convert it to flow, effectively getting almost complete flow type definition for the package.

btw, I rebased #11578 so it can be used for latest code version.

I think we can keep checking DefinitelyTyped

I would say - we should not use it for now, and only later to use type tests from it to align type definitions later… (if to use it - there would be weird issues because, like - inability to generate files, because they are used as input 😆, or need to rename things(which later, with typescript support can be much easier leveraging IDE features))

about a ways to exclude @types/* - I did a following hack, in top level package.json resolutions:

    "@types/babel__core": "link:./nope",
    "@types/babel__traverse": "link:./nope"

(basically resolving specific type packages to something non-existing…)

Also, as a first steps -- I would say, we should include @babel/types right after Batch1 - there would be are some additional types to be used in next packages, and reducing need in manual fixes.

nicolo-ribaudo added a commit to nicolo-ribaudo/babel that referenced this pull request Nov 9, 2020
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
@nicolo-ribaudo
Copy link
Member Author

I got some type errors while rebasing, so I added f0a2a6d (#12317): we already publish @babel/types dts, but we didn't add type for assert* methods (because of backward compat with older TS versions). I discovered the typesVersions, so I used it and it seems to work.

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
@nicolo-ribaudo
Copy link
Member Author

Also, as a first steps -- I would say, we should include @babel/types right after Batch1 - there would be are some additional types to be used in next packages, and reducing need in manual fixes.

If you think that something is needed in a different order than what I proposed feel free to do it. However, we already generate types for @babel/types so it might have a lower priority.

Btw, since this is a lot of work feel free to ask me to continue when you don't want to.

@nicolo-ribaudo nicolo-ribaudo merged commit 6654c04 into babel:main Nov 9, 2020
@nicolo-ribaudo nicolo-ribaudo deleted the typescript-babel-template branch November 9, 2020 22:15
nicolo-ribaudo added a commit that referenced this pull request Nov 9, 2020
Co-authored-by: Bogdan Savluk <savluk.bogdan@gmail.com>
nicolo-ribaudo added a commit that referenced this pull request Nov 9, 2020
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
@nicolo-ribaudo
Copy link
Member Author

a9bc9be, f80478c and 089c200.

I rebased instead of squashing because the commits are conceptually separated and have different authors.

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Feb 9, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Flow -> TS Tracking repository migration from Flow to TS outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants