Support Optional Chaining and Nullish Coalescing
Opened this issue ยท 4 comments
Hi! I would like to use Reflow on our project which uses optional chaining syntax and I run into this error when using reflow
:
๐ฅ Error: [file].js could not be transpiled. Skipping.
๐ฅ Error: [file].js: Support for the experimental syntax 'optionalChaining' isn't currently enabled (50:29):
...
Add @babel/plugin-proposal-optional-chaining (https://git.io/vb4Sk) to the 'plugins' section of your Babel config to enable transformation.
Now, the plugin for optional chaining is setup in our project's babel.config.js
file, but I have noticed that Reflow ignores any Babel configuration from the project:
reflow/src/plugin/util/options.ts
Lines 15 to 20 in a0fedb3
Do you have some recommendation how to handle this? I could use reflow as a Babel plugin, but sadly that option is undocumented. Perhaps the Reflow CLI could accept some extra arguments for customization of the default plugins set (e.g. explicitly pass a path to babelrc or add arguments for plugins)?
I have managed to fix this by adding (hardcoding) relevant options to babel-parser configuration in my fork: jnv@aa43fca
I have also added tests and it seems to work without breaking existing fixtures (I have a problem with TypeScript's ts(2589) error, but that seems to be irrelevant to these changes) โ see the diff of my fork. Would you be interested in PR?
Okay, I was a bit too optimistic. Looks like it is failing on formatting with error Expression expected.
; this is likely due to older version of Prettier used in prettier-reflow, since stage 3 syntax features should be supported since Prettier 1.19 per prettier/prettier#6595
So perhaps I should open a PR there first.
Thank's for the feedback! I agree that the syntax plugins used inside of this plugin should somehow be configurable. The idea to add an option, where the path to a babelrc
file can be passed to Reflow to add other syntax plugins sounds good to me ๐.
For now I've updated the Prettier fork and added support for optional chaining and nullish coalescence by hand, but I will look into a more flexible approach in the next days. Please check out v0.4.0
.
@grubersjoe since you never know what babel version and plugins someone is using, it's more reliable to just load @babel/core
from the project directory and use it to parse the file:
import fs from 'fs-extra'
import path from 'path'
import _resolve from 'resolve'
import { promisify } from 'util'
const resolve = promisify(_resolve)
async function transform(file: string) {
const basedir = path.dirname(file)
const babel = require(await resolve('@babel/core', { basedir }))
const code = await fs.readFile(file, 'utf8')
const ast = await babel.parseAsync(code, {
filename: file
cwd: basedir,
})
// transform the ast...
}
This also gets the applicable babelrc file in a parent directory, which might not work correctly if you have to pass a single babelrc path to Reflow. It's not worth reimplementing any of the logic in @babel/core
.
I've made a lot of CLIs and VSCode extensions that do codemods this way. It's basically either this approach or use flow-parser
(when code has to be compatible with flow) and use something else to traverse the flow AST.
I could make a PR to do this eventually!