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

Expose a prefix that plugins can use to annotate labelled statements and directives so they will be stripped out. #7544

Closed
wants to merge 1 commit into from

Conversation

loganfsmyth
Copy link
Member

Q                       A
Fixed Issues?
Patch: Bug Fix? N
Major: Breaking Change? N
Minor: New Feature? Y
Tests Added + Pass? Yes
Documentation PR
Any Dependency Changes?
License MIT

Posting for thoughts. This idea popped into my head a while back and I'm curious what people think about it.

We have this problem where sometimes plugins will flag nodes with either random properties, or Symbols, or store them in WeakSets. I think that's a great approach when you are confident that the node won't be duplicated later, like if you are in direct control of a subtraversal and no other plugins can get in your way. On the other hand, it's entirely possible for unrelated plugins to copy or replace a node for one reason or another, and often this will clear random flags on the node.

This PR makes Babel automatically strip out directives like:

"BABEL_PREFIX_some whatever";

and whole labeled statements like

BABEL_PREFIX_whatever: {
  // a normal JS block
}

I'm proposing this PR because it seems like it could be kind of handy for us. It would be relatively straightforward to inject directives that contain metadata about a given block. The labeled statements I could also see, though they are probably harder to manage. On the other hand since they allow actually non-string content, they can interact with other transforms.

Essentially it exposes a prefix field on the plugin API object that can be used inside directive literals or inside the labels of labeled statements to make them be deleted at the end of Babel's transformation phase. We could for instance use this approach to mark each of Babel's helper functions with a directive, so they are easier to pick out when transforming a given file. It could also be useful as a way of injecting metadata about a function's bindings or something.

Thoughts?

…and directives so they will be stripped out.
@loganfsmyth loganfsmyth added PR: Internal 🏠 A type of pull request used for our changelog categories i: discussion i: enhancement pkg: core labels Mar 10, 2018
@babel-bot
Copy link
Collaborator

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

1 similar comment
@babel-bot
Copy link
Collaborator

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

@mAAdhaTTah
Copy link
Contributor

This might solve the precendence issue we're seeing in #7154; we could use this to label await expressions that have been transformed into yield for the pipeline operator.

@loganfsmyth
Copy link
Member Author

Good question. I haven't looked closely at that discussion before. You can't label expressions, so I don't know that it would be as simple as your description, but it might still be helpful. Hard to say.

@mAAdhaTTah
Copy link
Contributor

Would this work?

co(function* foo () {
  "BABEL_PREFIX_await_transformed"
  const bar = yield baz;
})

@loganfsmyth
Copy link
Member Author

That'd be stripped out, but I'm not sure it would be enough information for that other plugin to work. It needs to know specifically which yield statements used to be await statements. Assuming all yields inside a function with that directive were previously await will fail for async generator functions since they use both yield and await in the same function.

My preference would be something like #7154 (comment) for that issue.

@mAAdhaTTah
Copy link
Contributor

mAAdhaTTah commented Mar 12, 2018

@loganfsmyth In the above, my assumption was that statement would be injected above every transpiled instance. So it wouldn't apply to the whole block, just the next line, but maybe that's not the intention of this PR?

Plugin ordering seemed like a much stickier problem than using something like this to flag individual lines, and I was hoping to push along that PR.

@loganfsmyth
Copy link
Member Author

This PR only removes directives, which are strings at the start of a function, so it would not apply to general standalone strings between statements.

using something like this to flag individual lines

Flagging individual lines is too granular unfortunately. You could certainly see someone doing

async function * fn() {
  var foo = await yield 42;
}

in the same statement.

Plugin ordering seemed like a much stickier problem

No argument there, but it's already a problem we have to deal with, and at least in this specific case it seems like we can pretty reasonably throw a clear error to let users know when they get the ordering wrong.

@mAAdhaTTah
Copy link
Contributor

Is that legal syntax? I can't get it to parse in the repl. I get unexpected token errors when turning on proposal-async-generators. (As an aside, it doesn't appear the repl shows you a list of the currently enabled plugins.)

Flagging individual lines is too granular unfortunately.

I'm assuming you mean not granular enough :). If flagging individual lines is enough, are you open to stripping directives throughout a block to provide this as a potential solution to that problem or is that just a no-go for you?

@loganfsmyth
Copy link
Member Author

Is that legal syntax? I can't get it to parse in the repl.

Ah woops, it needs parens: await (yield 42)

is that just a no-go for you?

I'd rather not add more complexity to work around plugin ordering issues, unless there's literally no way to achieve what we want, and I'm not convinced that is the case here.

@hzoo hzoo requested a review from jridgewell April 30, 2018 18:27
@hzoo
Copy link
Member

hzoo commented Apr 30, 2018

Should ping some people that have had to do this before

@loganfsmyth
Copy link
Member Author

I'm gonna close this for now. It's not clear that it's the right approach, and it's a performance hit we may or may not want to take.

@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Oct 4, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 4, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
i: discussion i: enhancement outdated A closed issue/PR that is archived due to age. Recommended to make a new issue pkg: core PR: Internal 🏠 A type of pull request used for our changelog categories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants