Skip to content

Commit 874c356

Browse files
committed
Init commit
0 parents  commit 874c356

File tree

8 files changed

+2215
-0
lines changed

8 files changed

+2215
-0
lines changed

.flowconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[ignore]
2+
3+
[include]
4+
5+
[libs]
6+
7+
[options]

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
*.log

LICENSE

Whitespace-only changes.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# babel-react-components
2+
3+
> Utils for working with React components in Babel
4+
5+
```js
6+
import {isReactComponentClass} from 'babel-react-components';
7+
8+
isReactComponentClass(path); // true/false
9+
```

index.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// @flow
2+
'use strict';
3+
4+
/*::
5+
type Node = {
6+
type: string,
7+
[key: string]: any,
8+
};
9+
10+
type Path = {
11+
node: Node,
12+
[key: string]: any,
13+
};
14+
*/
15+
16+
const GLOBAL_NAME = 'React';
17+
const MODULE_NAME = 'react';
18+
19+
let getBinding = path => {
20+
return path.scope.getBinding(path.node.name);
21+
};
22+
23+
let isReactComponentMember = path => {
24+
return path.node.name === 'Component' || path.node.name === 'PureComponent';
25+
};
26+
27+
let getSourceFromSpecifier = path => {
28+
return path.parent.source.value;
29+
};
30+
31+
function isReactComponentClass(path /*: Path */) {
32+
if (!path.isClass()) return false;
33+
34+
let superClass = path.get('superClass');
35+
if (!superClass.node) return false;
36+
37+
if (superClass.isMemberExpression()) {
38+
let object = superClass.get('object');
39+
let property = superClass.get('property');
40+
41+
if (!object.isIdentifier()) return false;
42+
43+
let binding = getBinding(object);
44+
45+
if (!binding) {
46+
if (object.node.name !== GLOBAL_NAME) return false;
47+
} else {
48+
if (binding.kind !== 'module') return false;
49+
if (!binding.path.isImportDefaultSpecifier()) return false;
50+
if (getSourceFromSpecifier(binding.path) !== MODULE_NAME) return false;
51+
}
52+
53+
return isReactComponentMember(property);
54+
}
55+
56+
if (superClass.isIdentifier()) {
57+
let binding = getBinding(superClass);
58+
if (!binding) return false;
59+
60+
if (binding.kind !== 'module') return false;
61+
if (!binding.path.isImportSpecifier()) return false;
62+
if (getSourceFromSpecifier(binding.path) !== MODULE_NAME) return false;
63+
if (!isReactComponentMember(binding.path.get('imported'))) return false;
64+
65+
return true;
66+
}
67+
68+
throw superClass.buildCodeFrameError(
69+
`Unexpected super class type: ${superClass.type}`,
70+
);
71+
}
72+
73+
exports.isReactComponentClass = isReactComponentClass;

package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "babel-react-components",
3+
"description": "Utils for working with React components in Babel",
4+
"version": "0.0.0",
5+
"main": "index.js",
6+
"repository": "[email protected]:babel-utils/babel-react-components.git",
7+
"author": "James Kyle <[email protected]>",
8+
"license": "MIT",
9+
"scripts": {
10+
"test": "jest"
11+
},
12+
"devDependencies": {
13+
"babel-plugin-tester": "^3.0.0",
14+
"flow-bin": "^0.46.0",
15+
"jest": "^20.0.3"
16+
}
17+
}

test.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// @flow
2+
'use strict';
3+
4+
const {isReactComponentClass} = require('./');
5+
const pluginTester = require('babel-plugin-tester');
6+
7+
const plugin = function({types: t}) {
8+
return {
9+
name: 'test-plugin',
10+
visitor: {
11+
ClassDeclaration(path) {
12+
if (isReactComponentClass(path)) {
13+
path.replaceWith(t.identifier('MATCHED'));
14+
}
15+
},
16+
},
17+
};
18+
};
19+
20+
pluginTester({
21+
plugin: plugin,
22+
babelOptions: {
23+
parserOpts: {plugins: ['flow']},
24+
},
25+
tests: [
26+
{
27+
title: 'dont match no super class',
28+
code: 'class Foo {}',
29+
output: 'class Foo {}',
30+
},
31+
{
32+
title: 'dont match super class not react',
33+
code: 'class Foo extends Bar {}',
34+
output: 'class Foo extends Bar {}',
35+
},
36+
{
37+
title: 'dont match super class member expression not react',
38+
code: 'class Foo extends Bar.Baz {}',
39+
output: 'class Foo extends Bar.Baz {}',
40+
},
41+
{
42+
title: 'dont match super class member expression react not component',
43+
code: 'class Foo extends React.Baz {}',
44+
output: 'class Foo extends React.Baz {}',
45+
},
46+
{
47+
title: 'match super class member expression react component',
48+
code: 'class Foo extends React.Component {}',
49+
output: `MATCHED;`,
50+
},
51+
{
52+
title: 'match super class member expression react pure component',
53+
code: `class Foo extends React.PureComponent {}`,
54+
output: `MATCHED;`,
55+
},
56+
{
57+
title: 'dont match React if binding not correct import',
58+
code: `let React = {};\nclass Foo extends React.Component {}`,
59+
},
60+
{
61+
title: 'match React if binding correct default import',
62+
code: `import React from "react";\nclass Foo extends React.Component {}`,
63+
output: `import React from "react";\nMATCHED;`,
64+
},
65+
{
66+
title: 'match React if binding correct named import',
67+
code: `import { Component } from "react";\nclass Foo extends Component {}`,
68+
output: `import { Component } from "react";\nMATCHED;`,
69+
},
70+
{
71+
title: 'dont match React if binding incorrect named import',
72+
code: `import { x } from "react";\nclass Foo extends x {}`,
73+
},
74+
{
75+
title: 'match React if binding correct renamed named import',
76+
code: `import { Component as x } from "react";\nclass Foo extends x {}`,
77+
output: `import { Component as x } from "react";\nMATCHED;`,
78+
},
79+
{
80+
title: 'dont match React if binding incorrect renamed named import',
81+
code: `import { x as Component } from 'react';\nclass Foo extends Component {}`,
82+
},
83+
],
84+
});

0 commit comments

Comments
 (0)