babel-plugin-jsx-pragmatic
Advanced tools
Comparing version 0.1.1 to 1.0.0
/** | ||
* Insert code to load the module corresponding to `jsxPragma`. | ||
* Supposed to be implemented via `import` declaration but blocked by | ||
* https://github.com/babel/babel/issues/1777 | ||
* So currently implemented via `require()` and only for CommonJS. | ||
* Insert code to load a module when JSX is detected. | ||
* This is supposed to load a module corresponding to the `pragma` option of | ||
* the JSX transform. | ||
*/ | ||
@@ -11,70 +10,33 @@ | ||
t = babel.types, | ||
// Node representing import declaration. | ||
pragmaImport, | ||
transforms = {}; | ||
visitor = {}; | ||
/** | ||
* Retrieve or generate `pragmaImport`. | ||
* This method should be unnecessary, but currently unaware of a way to | ||
* access options passed to babel in this scope (as opposed to visitor func). | ||
*/ | ||
function getPragmaImport (opts) { | ||
pragmaImport = pragmaImport || | ||
// This shouldn't be necessary, see babel/babel#1777 | ||
t.variableDeclaration( | ||
'var', | ||
[t.variableDeclarator( | ||
t.identifier(opts.jsxPragma), | ||
t.callExpression( | ||
t.identifier('require'), [ | ||
t.literal(opts.jsxPragma) | ||
] | ||
) | ||
)] | ||
) | ||
|| | ||
t.importDeclaration( | ||
[t.importDefaultSpecifier(t.identifier(opts.jsxPragma))], | ||
t.literal(opts.jsxPragma) | ||
); | ||
return pragmaImport; | ||
function getPragmaImport (state) { | ||
return t.importDeclaration( | ||
[t.importSpecifier( | ||
t.identifier(state.opts.import), | ||
t.identifier(state.opts.export || "default") | ||
)], | ||
t.stringLiteral(state.opts.module) | ||
); | ||
} | ||
// getPragmaImport | ||
transforms = { | ||
visitor = { | ||
Program: { | ||
// This whole thing should be unnecessary. See babel/babel#1777. | ||
enter: function (program, parent, scope, file) { | ||
file.set( | ||
'eligible', | ||
['common', 'commonStrict'].indexOf(file.opts.modules) >= 0 | ||
); | ||
enter: function (path, state) { | ||
// TODO | ||
// When I can figure out how to access these options in pre(), move this | ||
// validation there. | ||
if (! (state.opts.module && state.opts.import)) { | ||
throw new Error("babel-plugin-jsx-pragmatic: You must specify `module` and `import`"); | ||
} | ||
}, | ||
// enter | ||
exit: function (program, parent, scope, file) { | ||
var | ||
first = program.body[0], | ||
pragmaImport; | ||
exit: function (path, state) { | ||
if (! state.get('jsxDetected')) return; | ||
if (! (file.get('eligible') && file.get('jsxDetected'))) return; | ||
pragmaImport = getPragmaImport(this.state.opts); | ||
// Detect whether program begins with `use strict` directive, to insert | ||
// module load code in proper location. | ||
if ( | ||
t.isExpressionStatement(first) && | ||
// TODO: This is a flawed check, but currently the same one babel | ||
// itself uses. I could check `node.raw`, but note that it is not yet | ||
// standardized in ESTree. | ||
t.isLiteral(first.expression, { value: "use strict" }) | ||
) { | ||
// Or this.get("body.0"). | ||
this.get("body")[0].insertAfter(pragmaImport); | ||
} | ||
else this.unshiftContainer('body', pragmaImport); | ||
// Apparently it's now safe to do this even if Program begins with | ||
// directives. | ||
path.unshiftContainer('body', getPragmaImport(state)); | ||
}, | ||
@@ -85,10 +47,17 @@ // exit | ||
JSXElement: function (node, parent, scope, file) { | ||
file.set('jsxDetected', true); | ||
// It seems pretty hokey that this'll work even if JSX has already been | ||
// transformed, but apparently that's the basis for the whole plugin | ||
// architecture for babel@6, so I'm rolling with it and maybe it'll make | ||
// more sense to me once I understand it better. | ||
JSXElement: function (path, state) { | ||
state.set('jsxDetected', true); | ||
}, | ||
// CallExpression | ||
// JSXElement | ||
}; | ||
return new babel.Transformer("jsx-pragmatic", transforms); | ||
return { | ||
inherits: require("babel-plugin-syntax-jsx"), | ||
visitor: visitor, | ||
}; | ||
}; | ||
// jsxPragmatic |
{ | ||
"name": "babel-plugin-jsx-pragmatic", | ||
"version": "0.1.1", | ||
"version": "1.0.0", | ||
"main": "jsx-pragmatic.js", | ||
@@ -12,4 +12,12 @@ "license": "MIT", | ||
}, | ||
"dependencies": { | ||
"babel-plugin-syntax-jsx": "^6.0.0" | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^5.0.0" | ||
"babel-core": "^6.0.0", | ||
"babel-plugin-transform-react-jsx": "^6.0.0", | ||
"babel-preset-es2015": "^6.0.0", | ||
"lodash": "^3.10.0", | ||
"mocha": "^2.3.0", | ||
"sinon": "^1.17.0" | ||
}, | ||
@@ -26,3 +34,7 @@ "files": [ | ||
"react" | ||
] | ||
], | ||
"description": "Insert code to load a module corresponding to JSX pragma.", | ||
"scripts": { | ||
"test": "mocha 'test/{unit,integration}.js'" | ||
} | ||
} |
112
README.md
# About | ||
babel / babelify has a `jsxPragma` option that will be used when transforming JSX to function calls instead of the default function `React.createElement`. | ||
[babel-plugin-transform-react-jsx](https://www.npmjs.com/package/babel-plugin-transform-react-jsx) has a `pragma` option that's used when transforming JSX to function calls instead of the default function `React.createElement`. | ||
This babel plugin is a companion to that feature that allows you to dynamically load a module associated with the `jsxPragma` value. | ||
This Babel plugin is a companion to that feature that allows you to dynamically load a module associated with the `pragma` value. | ||
@@ -21,7 +21,11 @@ Example: | ||
By setting the `jsxPragma` option like this: | ||
By setting the `pragma` option like this: | ||
```js | ||
babel.transform(code, { | ||
jsxPragma: 'whatever', | ||
plugins: [ | ||
["babel-plugin-transform-react-jsx", { | ||
pragma: "whatever", | ||
}], | ||
] | ||
}) | ||
@@ -36,8 +40,8 @@ ``` | ||
However, you would still likely need to pull in a module corresponding to `whatever`: | ||
However, you might need to load a module corresponding to `whatever` in each module containing JSX: | ||
```js | ||
import whatever from 'whatever'; | ||
import whatever from "whatever"; | ||
// or | ||
var whatever = require('whatever'); | ||
var whatever = require("whatever"); | ||
``` | ||
@@ -49,15 +53,95 @@ | ||
babel.transform(code, { | ||
jsxPragma: 'whatever', | ||
plugins: ['babel-plugin-jsx-pragmatic'], | ||
plugins: [ | ||
["babel-plugin-transform-react-jsx", { | ||
pragma: "whatever", | ||
}], | ||
["babel-plugin-jsx-pragmatic", { | ||
module: "/something/whatever", | ||
import: "whatever" | ||
}], | ||
] | ||
}) | ||
``` | ||
# Known Issues | ||
Results in: | ||
* This currently relies on the module name exactly matching the `jsxPragma` value. | ||
```js | ||
import {default as whatever} from "/something/whatever"; | ||
``` | ||
* This should be implemented by inserting an `import` declaration to load the module, but due to an issue with babel ([babel/babel#1777](https://github.com/babel/babel/issues/1777)) that's not currently possible and therefore it inserts a `require()` call and only works for CommonJS output. | ||
## Options | ||
* Currently only supports `jsxPragma` value that is a valid identifier. E.g. `some.thing` or `some['thing']` would not work. | ||
### `module` | ||
* Currently does not take into account when a file actually contains a JSX pragma comment. | ||
String. Module ID or pathname. The value of the `ModuleSpecifier` of an import. Required. | ||
### `import` | ||
String. The identifier that you want to import the `module` with. This should correspond to the root identifier of the `pragma` value. Required. Examples: | ||
```js | ||
{ | ||
plugins: [ | ||
["babel-plugin-transform-react-jsx", { | ||
pragma: "x", | ||
}], | ||
["babel-plugin-jsx-pragmatic", { | ||
module: "/something/whatever", | ||
import: "x" | ||
}], | ||
] | ||
} | ||
{ | ||
plugins: [ | ||
["babel-plugin-transform-react-jsx", { | ||
pragma: "x.y", | ||
}], | ||
["babel-plugin-jsx-pragmatic", { | ||
module: "/something/whatever", | ||
import: "x" | ||
}], | ||
] | ||
} | ||
``` | ||
### `export` | ||
String. The export that you want to import as `import` from `module`. Default value is `default` (the default export). Examples: | ||
```js | ||
// Will import the default export (`default`) | ||
{ | ||
module: "whatever", | ||
import: "x" | ||
} | ||
// import {default as x} from "whatever" | ||
// Will import the default export (`default`) | ||
{ | ||
module: "whatever", | ||
import: "x", | ||
export: "default", | ||
} | ||
// import {default as x} from "whatever" | ||
// Will import the export named `something` | ||
{ | ||
module: "whatever", | ||
import: "x", | ||
export: "something", | ||
} | ||
// import {something as x} from "whatever" | ||
``` | ||
# Known Issues | ||
* Doesn't do anything special in the case that the file being transformed | ||
already imports or declares an identifier with the same name as `import`. | ||
* Doesn't take into account when a file actually contains a JSX pragma comment. |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
6650
0
145
1
6
54
+ Addedbabel-plugin-syntax-jsx@6.18.0(transitive)