If each module is individually transpiled with Buble or Babel, sure. But if JSX were a first class construct in ES then different @jsx
pragmas would not work with scope hoisting in the context of a single file:
https://github.com/rollup/rollup/issues/1512
The first @jsx
pragma found anywhere in a given file dictates what it'll be:
$ cat jsx.js
f(<A/>);
/** @jsx Bar */
f(<B/>);
/** @jsx Foo */
f(<C/>);
$ babel jsx.js
"use strict";
f(Bar(A, null));
/** @jsx Bar */
f(Bar(B, null));
/** @jsx Foo */
f(Bar(C, null));
No mention of the @jsx
pragma here: https://facebook.github.io/jsx/
My only point is that people are building code against an unofficial standard that is subject to change and will not be part of ECMAScript.
If you think about it, this pragma would not work in Rollup if various source files with different @jsx
pragmas were combined. The first comment pragma found anywhere in the file would "win". Such a pragma should be either module-scoped or block-scoped. No matter - it clearly hasn't affected anyone.
The removal of the /* @jsx override */
pragma from babel@7
was unintentional:
https://github.com/babel/babel/issues/6141#issuecomment-326624560
Noticed it on https://twitter.com/babeljs .
This sort of thing happens when a feature is not in the ECMAScript standard - and the rest of JSX for that matter.
I'm not the project maintainer, but the latest PR changes look reasonable.
This would be a useful feature.
FYI - Babel: Removed the deprecated jsx pragma detection code
In the top post Bar is not derived from Foo. Did you intend to do the following?
$ echo 'class Bar extends Foo {
set foo(v) {super.foo = v}
get foo() {return super.foo}
}
' | buble
var Bar = (function (Foo) {
function Bar () {
Foo.apply(this, arguments);
}
if ( Foo ) Bar.__proto__ = Foo;
Bar.prototype = Object.create( Foo && Foo.prototype );
Bar.prototype.constructor = Bar;
var prototypeAccessors = { foo: {} };
prototypeAccessors.foo.set = function (v) {Foo.prototype.foo = v};
prototypeAccessors.foo.get = function () {return Foo.prototype.foo};
Object.defineProperties( Bar.prototype, prototypeAccessors );
return Bar;
}(Foo));
transformed
will be set to undefined
in the event of a buble exception. No different than the following:
$ cat test.js
function transform() {
throw "err";
return "not reached";
}
try {
var transformed = transform();
} catch (e) {}
console.log("transformed is", transformed);
$ node test.js
transformed is undefined
Duplicate of #182 and #189 (closed)
Workaround - wrap object literal with parens.
$ echo 'const x={...state, inner: ({[id]: value})}' | buble --objectAssign
var x=Object.assign({}, state, {inner: (( obj = {}, obj[id] = value, obj ))})
var obj;
Duplicate of #182 and #189 (closed)
Workaround - terminate line with semicolon or wrap object literal with parens.
$ echo 'function f(id, value){return{[id]:value};}' | buble
function f(id, value){return( obj = {}, obj[id] = value, obj );
var obj;}
$ echo 'function f(id, value){return({[id]:value})}' | buble
function f(id, value){return(( obj = {}, obj[id] = value, obj ))
var obj;}
https://gitlab.com/Rich-Harris/buble/blob/v0.15.2/src/program/types/VariableDeclaration.js#L42
--- a/src/program/types/VariableDeclaration.js
+++ b/src/program/types/VariableDeclaration.js
@@ -39,8 +39,6 @@ export default class VariableDeclaration extends Node {
const name = simple ? declarator.init.name : declarator.findScope( true ).createIdentifier( 'ref' );
- let c = declarator.start;
-
let statementGenerators = [];
if ( simple ) {
Brought to light when trying to rebuild Buble from uglify-es
minified sources. Buble failed to build a minified version of itself due to Buble loop scope issues.
Buble version:
$ buble -v
Bublé version 0.15.2
Input code:
$ cat for-in.js
function foo(e) {
for (const i in e) {
const e = i;
console.log(e);
}
}
foo("AB");
foo([10, 20]);
Expected result:
$ cat for-in.js | node
0
1
0
1
Result with Buble:
$ cat for-in.js | buble | node
$
Incorrect code generated by Buble:
$ cat for-in.js | buble
function foo(e) {
for (var i in e$1) {
var e$1 = i;
console.log(e$1);
}
}
foo("AB");
foo([10, 20]);
Please add a trailing comma to make future commit diffs smaller.
However, I'll likely try to reverse the preference order, making comments override the CLI setting (for the current module only).
That's fine. As long as it matches Babel's behavior.
does Babel make a persistent change to its JSX pragma setting when it encounters such a comment? So that a project with two or more different
/** @jsx ... */
declarations has a somewhat unpredictable/arbitrary result?
Within one source file Babel appears to use the first jsx pragma encountered - regardless of its location in the file.
babel@5.8.29
appears to reset the jsx pragma for each new module, using the value of --jsx-pragma
if present, otherwise React.createElement
.
This following patch appears to match babel@5.8.29
's behavior:
--- a/src/index.js
+++ b/src/index.js
@@ -46,17 +46,26 @@ export function target ( target ) {
export function transform ( source, options = {} ) {
let ast;
+ let jsx = null;
try {
ast = parse( source, {
ecmaVersion: 7,
preserveParens: true,
sourceType: 'module',
+ onComment: ( block, text, start, end ) => {
+ if ( !jsx ) {
+ let match = /@jsx\s+([^\s]+)/.exec( text );
+ if ( match ) jsx = match[1];
+ }
+ },
plugins: {
jsx: true,
objectSpread: true
}
});
+
+ options.jsx = jsx || options.jsx;
} catch ( err ) {
err.snippet = getSnippet( source, err.loc );
err.toString = () => `${err.name}: ${err.message}\n${err.snippet}`;
$ echo 'foo( <Bar>hello<Baz/></Bar> );' | bin/buble
foo( React.createElement( Bar, null, "hello", React.createElement( Baz, null ) ) );
$ echo 'foo( <Bar>hello<Baz/></Bar> );' | bin/buble --jsx CLI.jsx.wins
foo( CLI.jsx.wins( Bar, null, "hello", CLI.jsx.wins( Baz, null ) ) );
$ echo '/** @jsx MyJSX1 */ /** @jsx MyJSX2 */ foo( <Bar>hello<Baz/></Bar> );' | bin/buble
/** @jsx MyJSX1 */ /** @jsx MyJSX2 */ foo( MyJSX1( Bar, null, "hello", MyJSX1( Baz, null ) ) );
$ echo '/** @jsx MyJSX1 */ /** @jsx MyJSX2 */ foo( <Bar>hello<Baz/></Bar> );' | bin/buble --jsx CLI.jsx.wins
/** @jsx MyJSX1 */ /** @jsx MyJSX2 */ foo( MyJSX1( Bar, null, "hello", MyJSX1( Baz, null ) ) );