Skip to content

Commit 2b52a0d

Browse files
committed
Add namespaces options for spec compliancy and better linting support.
Fixes #27.
1 parent b94017c commit 2b52a0d

File tree

5 files changed

+105
-4
lines changed

5 files changed

+105
-4
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@ var ast = acorn.parse(code, {
3737
});
3838
```
3939

40+
Note that official spec doesn't support mix of XML namespaces and object-style access in tag names (#27) like in `<namespace:Object.Property />`, so it was deprecated in `[email protected]`. If you still want to opt-in to support of such constructions, you can pass the following option:
41+
42+
```javascript
43+
var ast = acorn.parse(code, {
44+
plugins: {
45+
jsx: { allowNamespacedObjects: true }
46+
}
47+
});
48+
```
49+
50+
Also, since most apps use pure React transformer, a new option was introduced that allows to prohibit namespaces completely:
51+
52+
```javascript
53+
var ast = acorn.parse(code, {
54+
plugins: {
55+
jsx: { allowNamespaces: false }
56+
}
57+
});
58+
```
59+
60+
Note that by default `allowNamespaces` is enabled for spec compliancy.
61+
4062
## License
4163

4264
This plugin is issued under the [MIT license](./LICENSE).

inject.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ module.exports = function(acorn) {
198198
pp.jsx_parseNamespacedName = function() {
199199
var startPos = this.start, startLoc = this.startLoc;
200200
var name = this.jsx_parseIdentifier();
201-
if (!this.eat(tt.colon)) return name;
201+
if (!this.options.plugins.jsx.allowNamespaces || !this.eat(tt.colon)) return name;
202202
var node = this.startNodeAt(startPos, startLoc);
203203
node.namespace = name;
204204
node.name = this.jsx_parseIdentifier();
@@ -211,6 +211,9 @@ module.exports = function(acorn) {
211211
pp.jsx_parseElementName = function() {
212212
var startPos = this.start, startLoc = this.startLoc;
213213
var node = this.jsx_parseNamespacedName();
214+
if (this.type === tt.dot && node.type === 'JSXNamespacedName' && !this.options.plugins.jsx.allowNamespacedObjects) {
215+
this.unexpected();
216+
}
214217
while (this.eat(tt.dot)) {
215218
var newNode = this.startNodeAt(startPos, startLoc);
216219
newNode.object = node;
@@ -356,7 +359,20 @@ module.exports = function(acorn) {
356359
return this.jsx_parseElementAt(startPos, startLoc);
357360
};
358361

359-
acorn.plugins.jsx = function(instance) {
362+
acorn.plugins.jsx = function(instance, opts) {
363+
if (!opts) {
364+
return;
365+
}
366+
367+
if (typeof opts !== 'object') {
368+
opts = {};
369+
}
370+
371+
instance.options.plugins.jsx = {
372+
allowNamespaces: opts.allowNamespaces !== false,
373+
allowNamespacedObjects: !!opts.allowNamespacedObjects
374+
};
375+
360376
instance.extend('parseExprAtom', function(inner) {
361377
return function(refShortHandDefaultPos) {
362378
if (this.type === tt.jsxText)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "acorn-jsx",
33
"description": "Alternative, faster React.js JSX parser",
44
"homepage": "https://github.com/RReverser/acorn-jsx",
5-
"version": "2.0.1",
5+
"version": "3.0.0",
66
"maintainers": [
77
{
88
"name": "Ingvar Stepanyan",

test/driver.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ exports.runTests = function(config, callback) {
2525
if (expected.onToken = testOpts.onToken) {
2626
testOpts.onToken = [];
2727
}
28-
testOpts.plugins = { jsx: true };
28+
testOpts.plugins = testOpts.plugins || { jsx: true };
2929
var ast = parse(test.code, testOpts);
3030
if (test.error) {
3131
if (config.loose) {

test/tests-jsx.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3639,6 +3639,69 @@ if (typeof exports !== "undefined") {
36393639

36403640
testFail("var x = <div>one</div><div>two</div>;", "Adjacent JSX elements must be wrapped in an enclosing tag (1:22)");
36413641

3642+
testFail("<a:b.c />", "Unexpected token (1:4)");
3643+
3644+
test("<a:b.c />", {
3645+
type: "Program",
3646+
range: [0, 9],
3647+
body: [{
3648+
type: "ExpressionStatement",
3649+
range: [0, 9],
3650+
expression: {
3651+
type: "JSXElement",
3652+
range: [0, 9],
3653+
openingElement: {
3654+
type: "JSXOpeningElement",
3655+
range: [0, 9],
3656+
attributes: [],
3657+
name: {
3658+
type: "JSXMemberExpression",
3659+
range: [1, 6],
3660+
object: {
3661+
type: "JSXNamespacedName",
3662+
range: [1, 4],
3663+
namespace: {
3664+
type: "JSXIdentifier",
3665+
range: [1, 2],
3666+
name: "a"
3667+
},
3668+
name: {
3669+
type: "JSXIdentifier",
3670+
range: [3, 4],
3671+
name: "b"
3672+
}
3673+
},
3674+
property: {
3675+
type: "JSXIdentifier",
3676+
range: [5, 6],
3677+
name: "c"
3678+
}
3679+
},
3680+
selfClosing: true
3681+
},
3682+
closingElement: null,
3683+
children: []
3684+
}
3685+
}]
3686+
}, {
3687+
ranges: true,
3688+
plugins: {
3689+
jsx: { allowNamespacedObjects: true }
3690+
}
3691+
});
3692+
3693+
testFail('<ns:div />', 'Unexpected token (1:3)', {
3694+
plugins: {
3695+
jsx: { allowNamespaces: false }
3696+
}
3697+
});
3698+
3699+
testFail('<div ns:attr />', 'Unexpected token (1:7)', {
3700+
plugins: {
3701+
jsx: { allowNamespaces: false }
3702+
}
3703+
});
3704+
36423705
test('<a>{/* foo */}</a>', {}, {
36433706
onToken: [
36443707
{

0 commit comments

Comments
 (0)