}>;
5 | declare var Choose: React$ComponentType<{}>;
6 | declare var When: React$ComponentType<{condition: boolean}>;
7 | declare var Otherwise: React$ComponentType<{}>;
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel-plugin-jsx-control-statements",
3 | "version": "4.1.2",
4 | "description": "Neater control statements (if/for) for jsx",
5 | "author": {
6 | "name": "Alex Gilleran",
7 | "email": "alex@alexgilleran.com"
8 | },
9 | "main": "src/index.js",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/AlexGilleran/jsx-control-statements"
13 | },
14 | "types": "index.d.ts",
15 | "bugs": {
16 | "url": "https://github.com/AlexGilleran/jsx-control-statements/issues"
17 | },
18 | "keywords": [
19 | "react",
20 | "jsx",
21 | "if",
22 | "else",
23 | "for",
24 | "each",
25 | "loop",
26 | "babel",
27 | "react-component"
28 | ],
29 | "license": "MIT",
30 | "scripts": {
31 | "lint": "eslint src spec",
32 | "test": "mocha spec/tests.js",
33 | "cover": "istanbul cover -x \"**/spec/**\" node_modules/mocha/bin/_mocha spec/*.js"
34 | },
35 | "dependencies": {
36 | "@babel/core": "^7.1.2"
37 | },
38 | "devDependencies": {
39 | "@babel/preset-react": "^7.0.0",
40 | "@babel/register": "^7.0.0",
41 | "babel-eslint": "^10.0.1",
42 | "chai": "^4.2.0",
43 | "chai-spies": "^1.0.0",
44 | "coveralls": "^3.0.9",
45 | "eslint": "^6.8.0",
46 | "eslint-config-airbnb": "^18.1.0",
47 | "eslint-plugin-jsx-control-statements": "^2.1.0",
48 | "eslint-plugin-react": "^7.19.0",
49 | "istanbul": "^0.4.1",
50 | "mocha": "^7.1.0",
51 | "react": "^16.13.0",
52 | "react-dom": "^16.13.0"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/spec/fixtures/basic/without-any-control-statements.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | class Iff extends React.Component {
4 | render() {
5 | return (Test);
6 | }
7 | }
8 |
9 | module.exports = class extends React.Component {
10 | render() {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/spec/fixtures/choose/choose-empty.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 | // Can"t have "If" as the root because if the condition isn"t true then render returns undefined.
7 | // Note that this means that this fixture also tests if behaviour when the If tag is not the root of render().
8 |
9 |
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/choose/choose-with-otherwise.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | WhenBlock1
9 |
10 |
11 | OtherwiseBlock
12 |
13 |
14 | );
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/spec/fixtures/choose/choose.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 | // Can"t have "If" as the root because if the condition isn"t true then render returns undefined.
7 | // Note that this means that this fixture also tests if behaviour when the If tag is not the root of render().
8 |
9 |
10 |
11 | WhenBlock1
12 |
13 |
14 | WhenBlock2
15 |
16 |
17 |
18 | );
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/spec/fixtures/choose/chooses-within-if.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | Blah A
12 |
13 |
14 |
15 |
16 | Blah B
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Blah C
25 |
26 |
27 |
28 |
29 | Blah D
30 |
31 |
32 |
33 |
34 |
35 | );
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/spec/fixtures/choose/nested-choose-no-inner-component.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | When-When
12 |
13 |
14 | When-Otherwise
15 |
16 |
17 |
18 |
19 | Otherwise
20 |
21 |
22 |
23 | );
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/spec/fixtures/choose/nested-choose.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | test
10 |
11 |
12 | When-When
13 |
14 |
15 | When-Otherwise
16 |
17 |
18 |
19 |
20 | test
21 |
22 |
23 | Otherwise-When
24 |
25 |
26 | Otherwise-Otherwise
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/choose-with-multiple-otherwise.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 | Fails here!
11 |
12 |
13 |
14 |
15 | );
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/choose-with-no-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/choose-with-no-when.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | Fails here!
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/choose-with-otherwise-not-last.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | Fails here!
10 |
11 |
12 |
13 |
14 | );
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/choose-with-wrong-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | not allowed!
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/else-with-no-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 | IfBlock
8 |
9 |
10 | );
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/for-with-no-attributes.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 |
10 | {blah + this.test}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/for-with-no-of.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 |
10 | {blah + this.test}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/for-with-non-expression-of.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | Fails
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/for-with-non-string-each.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | Fails
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/for-with-non-string-index.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | var x = "i";
6 | return (
7 |
8 |
9 | Fails
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/if-with-no-condition.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | IfBlock
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/if-with-non-expression-condition.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | IfBlock
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/when-with-no-condition.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | WhenBlock
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/errors/when-with-non-expression-condition.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | IfBlock
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/choose-with-multiple-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | const {when, ...otherProps} = this.props;
6 |
7 | return (
8 |
9 |
10 |
11 | When1
12 | When2
13 |
14 |
15 | Other1
16 | Other2
17 |
18 |
19 |
20 | );
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/for-with-expression-container.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 |
10 | {item}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/for-with-multiple-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {item}
9 | {item + "test"}
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/if-with-expression-container.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {"if rendered"}
9 |
10 | {"else rendered"}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/if-with-multiple-children-nested.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {"outer1"}
9 | outer2
10 |
11 | inner1
12 | inner2
13 | inner3
14 |
15 | outer3
16 | outer4
17 |
18 |
19 | );
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/if-with-multiple-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | const {condition, ...passdown} = this.props;
6 |
7 | return (
8 |
9 |
10 | {"if rendered"}
11 | test
12 |
13 | {"else rendered"}
14 | test
15 |
16 |
17 | );
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/spec/fixtures/extension/if-with-string-literal.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | if rendered
9 |
10 | else rendered
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for-backwards-attributes.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 |
10 | {item + this.test}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for-empty.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for-tsx-syntax.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 | {item + this.test}}
12 | />
13 |
14 | );
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for-with-index-without-each.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {$index}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for-with-index.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 |
10 | {item + this.test + $index}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for-without-each.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | ABC
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/for/for.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.test = "test";
6 |
7 | return (
8 |
9 |
10 | {item + this.test}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/for/nested-for-with-indexes.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | {otherItem + item + $index2 + $index1}
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/for/nested-for.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | {otherItem + item}
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/if/if-empty.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 | // Can"t have "If" as the root because if the condition isn"t true then render returns undefined.
7 | // Note that this means that this fixture also tests if behaviour when the If tag is not the root of render().
8 |
9 |
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/if/if-with-else.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 | IfBlock
8 |
9 | ElseBlock
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/if/if.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 | // Can"t have "If" as the root because if the condition isn"t true then render returns undefined.
7 | // Note that this means that this fixture also tests if behaviour when the If tag is not the root of render().
8 |
9 |
10 | IfBlock
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/if/nested-if.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | test
9 |
10 | If-If
11 |
12 | If-Else
13 |
14 |
15 | test2
16 |
17 | Else-If
18 |
19 | Else-Else
20 |
21 |
22 |
23 | );
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/spec/fixtures/mixed/for-inside-if.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | {blah}
10 |
11 |
12 |
13 | {otherBlah}
14 |
15 |
16 |
17 | );
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/spec/fixtures/mixed/if-inside-for.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | {blah}
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-element-child.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-empty-content.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-expression-attribute.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 | "expr" + "ession"}>
8 | {attr()}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-multiple-attributes.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr1 + attr2 + attr3}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-multiple-children.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr}
9 | {attr}
10 | {attr}
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-nested-shadowed-restored.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr}
9 |
10 | {attr}
11 |
12 | {attr}
13 |
14 |
15 | );
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-nested-shadowed.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | {attr}
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-nested.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 |
9 | {attr1 + attr2}
10 |
11 |
12 |
13 | );
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-no-attributes.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | let test = "test"
6 | return (
7 |
8 |
9 | {test}
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-outer-shadowed-restored.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | var foo = "variable"
6 | return (
7 |
8 | {foo}
9 |
10 | {foo}
11 |
12 | {foo}
13 |
14 | );
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-outer-shadowed.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | var foo = "variable"
6 | return (
7 |
8 |
9 | {foo}
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-outer-this.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | this.foo = "outer"
6 | return (
7 |
8 |
9 | {foo + this.foo}
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-outer.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | var foo = "variable"
6 | return (
7 |
8 |
9 | {foo + bar}
10 |
11 |
12 | );
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-single-attribute.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-string-attribute.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-text-child.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | text child {attr}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-toplevel-component.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 | {attr}
8 |
9 | );
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/spec/fixtures/with/with-unused-attribute.jsx:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 |
3 | module.exports = class extends React.Component {
4 | render() {
5 | return (
6 |
7 |
8 | {attr1}
9 |
10 |
11 | );
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/spec/test/basic.js:
--------------------------------------------------------------------------------
1 | var util = require("../testUtil");
2 | var expect = require("chai").expect;
3 |
4 | describe("Other JSXElements should not be affected", function() {
5 | var Fixture = require("../fixtures/basic/without-any-control-statements");
6 |
7 | it("should not affect other JSXElements", function() {
8 | var rendered = util.render(Fixture);
9 | expect(rendered).to.match(/]*>
]*>Test<\/span><\/div>/);
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/spec/test/choose.js:
--------------------------------------------------------------------------------
1 | var chai = require("chai");
2 | var spies = require("chai-spies");
3 | var util = require("../testUtil");
4 |
5 | chai.use(spies);
6 | var expect = chai.expect;
7 |
8 |
9 | describe("requiring in component with empty when", function() {
10 | var Fixture = require("../fixtures/choose/choose-empty.jsx");
11 |
12 | it("should render nothing when condition true, but when is empty", function() {
13 | var rendered = util.render(Fixture);
14 | expect(rendered).to.match(util.matchEmptyDiv());
15 | });
16 | });
17 |
18 | describe("requiring in component with choose", function() {
19 | var Fixture = require("../fixtures/choose/choose.jsx");
20 |
21 | it("should render first when block when condition true", function() {
22 | var rendered = util.render(Fixture, {when1: true});
23 | expect(rendered).to.match(util.matchTextWithinSpanWithinDiv("WhenBlock1"));
24 | });
25 |
26 | it("should render first when block when both conditions true", function() {
27 | var rendered = util.render(Fixture, {when1: true, when2: true});
28 | expect(rendered).to.match(util.matchTextWithinSpanWithinDiv("WhenBlock1"));
29 | });
30 |
31 | it("should render second when block when condition true", function() {
32 | var rendered = util.render(Fixture, {when2: true});
33 | expect(rendered).to.match(util.matchTextWithinSpanWithinDiv("WhenBlock2"));
34 | });
35 |
36 | it("should render nothing when condition false", function() {
37 | var rendered = util.render(Fixture);
38 | expect(rendered).to.match(util.matchEmptyDiv());
39 | });
40 | });
41 |
42 | describe("requiring in component with choose/otherwise", function() {
43 | var Fixture = require("../fixtures/choose/choose-with-otherwise.jsx");
44 |
45 | it("should render choose block when condition true", function() {
46 | var rendered = util.render(Fixture, {when1: true});
47 | expect(rendered).to.match(util.matchTextWithinSpan("WhenBlock1"));
48 | });
49 |
50 | it("should render else block when condition false", function() {
51 | var rendered = util.render(Fixture);
52 | expect(rendered).to.match(util.matchTextWithinSpan("OtherwiseBlock"));
53 | });
54 | });
55 |
56 | describe("requiring in component with nested choose", function() {
57 | var Fixture = require("../fixtures/choose/nested-choose.jsx");
58 | var consoleSpy;
59 |
60 | beforeEach(function() {
61 | consoleSpy = chai.spy.on(console, "error");
62 | });
63 |
64 | afterEach(function() {
65 | chai.spy.restore(console, "error");
66 | });
67 |
68 | it("should render when-when block when both conditions true", function() {
69 | var rendered = util.render(Fixture, {outerWhen: true, innerWhen: true});
70 | expect(rendered).to.match(util.matchTextWithinSpansWithinDiv("test", "When-When"));
71 | expect(consoleSpy).to.not.have.been.called();
72 | });
73 |
74 | it("should render when-otherwise block when outer condition true, inner false", function() {
75 | var rendered = util.render(Fixture, {outerWhen: true});
76 | expect(rendered).to.match(util.matchTextWithinSpansWithinDiv("test", "When-Otherwise"));
77 | expect(consoleSpy).to.not.have.been.called();
78 | });
79 |
80 | it("should render otherwise-when block when outer condition false, inner true", function() {
81 | var rendered = util.render(Fixture, {innerWhen: true});
82 | expect(rendered).to.match(util.matchTextWithinSpansWithinDiv("test", "Otherwise-When"));
83 | expect(consoleSpy).to.not.have.been.called();
84 | });
85 |
86 | it("should render otherwise-otherwise block when both conditions false", function() {
87 | var rendered = util.render(Fixture);
88 | expect(rendered).to.match(util.matchTextWithinSpansWithinDiv("test", "Otherwise-Otherwise"));
89 | expect(consoleSpy).to.not.have.been.called();
90 | });
91 | });
92 |
93 | describe("requiring in component with nested choose and a key (issue #52)", function() {
94 | // This is to guard against against a specific case that actually breaks compilation - the fact that this code even
95 | // runs probably means it's OK but we'll do a proper test because why not.
96 |
97 | var Fixture = require("../fixtures/choose/nested-choose-no-inner-component.jsx");
98 | var consoleSpy;
99 |
100 | beforeEach(function() {
101 | consoleSpy = chai.spy.on(console, "error");
102 | });
103 |
104 | afterEach(function() {
105 | chai.spy.restore(console, "error");
106 | });
107 |
108 | it("should render when-when block when both conditions true", function() {
109 | var rendered = util.render(Fixture, {outerWhen: true, innerWhen: true});
110 | expect(rendered).to.match(util.matchTextWithinSpanWithinDiv("When-When"));
111 | expect(consoleSpy).to.not.have.been.called();
112 | });
113 | });
114 |
115 | describe("requiring in component with adjacent chooses within if", function() {
116 | var Fixture = require("../fixtures/choose/chooses-within-if.jsx");
117 |
118 | it("a", function() {
119 | var rendered = util.render(Fixture, {type: "a"});
120 | expect(rendered).to.match(util.matchTextWithinSpansWithinDiv("Blah A", "Blah C"));
121 | });
122 |
123 | it("b", function() {
124 | var rendered = util.render(Fixture, {type: "b"});
125 | expect(rendered).to.match(util.matchTextWithinSpansWithinDiv("Blah B", "Blah D"));
126 | });
127 | });
128 |
--------------------------------------------------------------------------------
/spec/test/error.js:
--------------------------------------------------------------------------------
1 | var expect = require("chai").expect;
2 |
3 | var errorUtil = require("../../src/util/error");
4 | var renderError = errorUtil.renderErrorMessage;
5 | var errors = errorUtil.ERRORS;
6 |
7 | describe("when encountering errors", function() {
8 | it("should fail for an with no condition", function() {
9 | expect(function() {
10 | require("../fixtures/errors/if-with-no-condition.jsx");
11 | }).to.throw(Error, renderError(errors.NO_ATTRIBUTE, {attribute: "condition", element: "If"}));
12 | });
13 |
14 | it("should fail for a without children", function() {
15 | expect(function() {
16 | require("../fixtures/errors/choose-with-no-children.jsx");
17 | }).to.throw(Error, renderError(errors.CHOOSE_WITHOUT_WHEN));
18 | });
19 |
20 | it("should fail for a with no ", function() {
21 | expect(function() {
22 | require("../fixtures/errors/choose-with-no-when.jsx");
23 | }).to.throw(Error, renderError(errors.CHOOSE_WITHOUT_WHEN));
24 | });
25 |
26 | it("should fail for a with not as last element", function() {
27 | expect(function() {
28 | require("../fixtures/errors/choose-with-otherwise-not-last.jsx");
29 | }).to.throw(Error, renderError(errors.CHOOSE_OTHERWISE_NOT_LAST));
30 | });
31 |
32 | it("should fail for a with multiple ", function() {
33 | expect(function() {
34 | require("../fixtures/errors/choose-with-multiple-otherwise.jsx");
35 | }).to.throw(Error, renderError(errors.CHOOSE_WITH_MULTIPLE_OTHERWISE));
36 | });
37 |
38 | it("should fail for a with wrong children", function() {
39 | expect(function() {
40 | require("../fixtures/errors/choose-with-wrong-children.jsx");
41 | }).to.throw(Error, renderError(errors.CHOOSE_WITH_WRONG_CHILDREN));
42 | });
43 |
44 | it("should fail for a with no condition", function() {
45 | expect(function() {
46 | require("../fixtures/errors/when-with-no-condition.jsx");
47 | }).to.throw(Error, renderError(errors.NO_ATTRIBUTE, {attribute: "condition", element: "When"}));
48 | });
49 |
50 | it("should fail for a with no of", function() {
51 | expect(function() {
52 | require("../fixtures/errors/for-with-no-of.jsx");
53 | }).to.throw(Error, renderError(errors.NO_ATTRIBUTE, {attribute: "of", element: "For"}));
54 | });
55 |
56 | it("should give location of errors", function() {
57 | expect(function() {
58 | require("../fixtures/errors/if-with-no-condition.jsx");
59 | }).to.throw(Error, /.*7,8.*/);
60 | });
61 | });
62 |
63 | describe("when encountering the wrong data type", function() {
64 | it("should fail for a with a non expression \"condition\" attribute", function() {
65 | expect(function() {
66 | require("../fixtures/errors/if-with-non-expression-condition.jsx");
67 | }).to.throw(Error, renderError(errors.NOT_EXPRESSION_TYPE, {element: "If", attribute: "condition"}));
68 | });
69 |
70 | it("should fail for a with a non expression \"condition\" attribute", function() {
71 | expect(function() {
72 | require("../fixtures/errors/when-with-non-expression-condition.jsx");
73 | }).to.throw(Error, renderError(errors.NOT_EXPRESSION_TYPE, {element: "When", attribute: "condition"}));
74 | });
75 |
76 | it("should fail for a with a non string \"each\" attribute", function() {
77 | expect(function() {
78 | require("../fixtures/errors/for-with-non-string-each.jsx");
79 | }).to.throw(Error, renderError(errors.NOT_STRING_TYPE, {element: "For", attribute: "each"}));
80 | });
81 |
82 | it("should fail for a with non string \"index\" attribute", function() {
83 | expect(function() {
84 | require("../fixtures/errors/for-with-non-string-index.jsx");
85 | }).to.throw(Error, renderError(errors.NOT_STRING_TYPE, {element: "For", attribute: "index"}));
86 | });
87 |
88 | it("should fail for a with non ExpressionContainer \"of\" attribute", function() {
89 | expect(function() {
90 | require("../fixtures/errors/for-with-non-expression-of.jsx");
91 | }).to.throw(Error, renderError(errors.NOT_EXPRESSION_TYPE, {element: "For", attribute: "of"}));
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/spec/test/extension.js:
--------------------------------------------------------------------------------
1 | var chai = require("chai");
2 | var spies = require("chai-spies");
3 | var util = require("../testUtil");
4 |
5 | chai.use(spies);
6 | var expect = chai.expect;
7 |
8 | describe("extension: data type handling", function() {
9 | var IfStringLiteral = require("../fixtures/extension/if-with-string-literal.jsx");
10 | var IfExpressionContainer = require("../fixtures/extension/if-with-expression-container.jsx");
11 | var ForExpressionContainer = require("../fixtures/extension/for-with-expression-container.jsx");
12 |
13 | it("should handle string literals within if tag", function() {
14 | var rendered = util.render(IfStringLiteral, {condition: true});
15 | expect(rendered).to.match(util.matchTextWithinDiv("if rendered"));
16 | });
17 |
18 | it("should handle string literals within else tag", function() {
19 | var rendered = util.render(IfStringLiteral, {condition: false});
20 | expect(rendered).to.match(util.matchTextWithinDiv("else rendered"));
21 | });
22 |
23 | it("should handle expression containers within if tag", function() {
24 | var rendered = util.render(IfExpressionContainer, {condition: true});
25 | expect(rendered).to.match(util.matchTextWithinDiv("if rendered"));
26 | });
27 |
28 | it("should handle expression containers within else tag", function() {
29 | var rendered = util.render(IfExpressionContainer, {condition: false});
30 | expect(rendered).to.match(util.matchTextWithinDiv("else rendered"));
31 | });
32 |
33 | it("should handle expression containers within for tag", function() {
34 | var rendered = util.render(ForExpressionContainer, {items: ["test1", "test2", "test3"]});
35 |
36 | expect(rendered).to.match(
37 | util.createDivMatcher()
38 | .addReactText("test1")
39 | .addReactText("test2")
40 | .addReactText("test3")
41 | .build()
42 | );
43 | });
44 | });
45 |
46 | describe("extension: multiple children", function() {
47 | var FixtureIf = require("../fixtures/extension/if-with-multiple-children.jsx");
48 | var FixtureIfNested = require("../fixtures/extension/if-with-multiple-children-nested.jsx");
49 | var FixtureChoose = require("../fixtures/extension/choose-with-multiple-children.jsx");
50 | var FixtureFor = require("../fixtures/extension/for-with-multiple-children.jsx");
51 |
52 | var consoleSpy;
53 |
54 | beforeEach(function() {
55 | consoleSpy = chai.spy.on(console, "error");
56 | });
57 |
58 | afterEach(function() {
59 | chai.spy.restore(console, "error");
60 | });
61 |
62 | it("should allow for multiple children within ", function() {
63 | var rendered = util.render(FixtureIf, {condition: true});
64 |
65 | expect(rendered).to.contain("if rendered");
66 | expect(rendered).to.contain("test");
67 | expect(consoleSpy).to.not.have.been.called();
68 | });
69 |
70 | it("should allow for multiple children within nested s", function() {
71 | var rendered = util.render(FixtureIfNested, {conditionInner: true});
72 |
73 | expect(rendered).to.match(
74 | util.createDivMatcher()
75 | .addReactText("outer1")
76 | .addSpan("outer2")
77 | .addSpan("inner1")
78 | .addSpan("inner2")
79 | .addSpan("inner3")
80 | .addSpan("outer3")
81 | .addSpan("outer4")
82 | .build()
83 | );
84 | expect(consoleSpy).to.not.have.been.called();
85 | });
86 |
87 | it("should allow for multiple children within ", function() {
88 | var rendered = util.render(FixtureIf);
89 |
90 | expect(rendered).to.match(
91 | util.createDivMatcher()
92 | .addReactText("else rendered")
93 | .addSpan("test")
94 | .build()
95 | );
96 | expect(consoleSpy).to.not.have.been.called();
97 | });
98 |
99 | it("should allow for multiple children within ", function() {
100 | var rendered = util.render(FixtureChoose, {when: true});
101 |
102 | expect(rendered).to.match(
103 | util.createDivMatcher()
104 | .addSpan("When1")
105 | .addSpan("When2")
106 | .build()
107 | );
108 | expect(consoleSpy).to.not.have.been.called();
109 | });
110 |
111 | it("should allow for multiple children within ", function() {
112 | var rendered = util.render(FixtureChoose);
113 |
114 | expect(rendered).to.match(
115 | util.createDivMatcher()
116 | .addSpan("Other1")
117 | .addSpan("Other2")
118 | .build()
119 | );
120 | expect(consoleSpy).to.not.have.been.called();
121 | });
122 |
123 | it("should allow for multiple children within ", function() {
124 | var rendered = util.render(FixtureFor, {items: [1, 2, 3]});
125 |
126 | expect(rendered).to.match(
127 | util.createDivMatcher()
128 | .addSpan("1")
129 | .addSpan("1test")
130 | .addSpan("2")
131 | .addSpan("2test")
132 | .addSpan("3")
133 | .addSpan("3test")
134 | .build()
135 | );
136 | expect(consoleSpy).to.not.have.been.called();
137 | });
138 | });
139 |
--------------------------------------------------------------------------------
/spec/test/for.js:
--------------------------------------------------------------------------------
1 | var expect = require("chai").expect;
2 | var util = require("../testUtil");
3 |
4 | describe("requiring in component with minimalistic for", function() {
5 | var FixtureEmpty = require("../fixtures/for/for-empty.jsx");
6 | var FixtureNoEach = require("../fixtures/for/for-without-each.jsx");
7 |
8 | describe("should render nothing if loop is empty", function() {
9 | var rendered = util.render(FixtureEmpty);
10 | expect(rendered).to.match(/]*><\/div>/);
11 | });
12 |
13 | describe("should simply iterate without each", function() {
14 | var rendered = util.render(FixtureNoEach);
15 | expect(rendered).to.match(
16 | /
]*>(ABC()?){3}<\/div>/
17 | );
18 | });
19 | });
20 |
21 | describe("requiring in component with for", function() {
22 | var ForView = require("../fixtures/for/for.jsx");
23 | var ForViewRevAttrs = require("../fixtures/for/for-backwards-attributes.jsx");
24 |
25 | function runForTests(ComponentDefinition) {
26 | it("should render list of items", function() {
27 | var rendered = util.render(ComponentDefinition, {
28 | items: ["item1", "item2", "item3"]
29 | });
30 | expect(rendered).to.match(
31 | /.*span.*item1test..*span.*span.*item2test.*span.*item3test.*span.*/
32 | );
33 | });
34 |
35 | it("should render empty list of items as blank", function() {
36 | var rendered = util.render(ComponentDefinition, { items: [] });
37 | expect(rendered).to.match(/
<\/div>/);
38 | });
39 | }
40 |
41 | describe("when attributes in normal order", runForTests.bind(this, ForView));
42 | describe(
43 | "when attributes in reverse order",
44 | runForTests.bind(this, ForViewRevAttrs)
45 | );
46 | });
47 |
48 | describe("using tsx syntax with for", function() {
49 | var ForView = require("../fixtures/for/for-tsx-syntax.jsx");
50 |
51 | function runForTests(ComponentDefinition) {
52 | it("should render list of items", function() {
53 | var rendered = util.render(ComponentDefinition, {
54 | items: ["item1", "item2", "item3"]
55 | });
56 | expect(rendered).to.match(
57 | /.*span.*item1test..*span.*span.*item2test.*span.*item3test.*span.*/
58 | );
59 | });
60 |
61 | it("should render empty list of items as blank", function() {
62 | var rendered = util.render(ComponentDefinition, { items: [] });
63 | expect(rendered).to.match(/<\/div>/);
64 | });
65 | }
66 |
67 | describe("when attributes in normal order", runForTests.bind(this, ForView));
68 | });
69 |
70 | describe("requiring in component with for with index", function() {
71 | var ForWithIndex = require("../fixtures/for/for-with-index.jsx");
72 | var ForWithIndexWithoutEach = require("../fixtures/for/for-with-index-without-each.jsx");
73 |
74 | it("should render list of items", function() {
75 | var rendered = util.render(ForWithIndex, {
76 | items: ["item1", "item2", "item3"]
77 | });
78 | expect(rendered).to.match(
79 | /.*span.*item1test0..*span.*span.*item2test1.*span.*item3test2.*span.*/
80 | );
81 | });
82 |
83 | it("should render empty list of items as blank", function() {
84 | var rendered = util.render(ForWithIndex, { items: [] });
85 | expect(rendered).to.match(/<\/div>/);
86 | });
87 |
88 | it("should render indices without values", function() {
89 | var rendered = util.render(ForWithIndexWithoutEach, {
90 | items: ["one", "two", "three"]
91 | });
92 | expect(rendered).to.match(/.*span.*0.*1.*2.*/);
93 | });
94 | });
95 |
96 | describe("nesting for within for", function() {
97 | var ForInsideFor = require("../fixtures/for/nested-for.jsx");
98 |
99 | it("should render only the first loop when if condition is true", function() {
100 | var rendered = util.render(ForInsideFor, {
101 | items: ["item1", "item2", "item3"],
102 | otherItems: ["1hlab", "2hlab", "3hlab"],
103 | test: true
104 | });
105 |
106 | expect(rendered).to.contain("1hlabitem1");
107 | expect(rendered).to.contain("1hlabitem2");
108 | expect(rendered).to.contain("1hlabitem3");
109 | expect(rendered).to.contain("2hlabitem1");
110 | expect(rendered).to.contain("2hlabitem2");
111 | expect(rendered).to.contain("2hlabitem3");
112 | expect(rendered).to.contain("3hlabitem1");
113 | expect(rendered).to.contain("3hlabitem2");
114 | expect(rendered).to.contain("3hlabitem3");
115 | });
116 | });
117 |
118 | describe("nesting for within for with indexes", function() {
119 | var ForInsideFor = require("../fixtures/for/nested-for-with-indexes.jsx");
120 |
121 | it("should render a list of items using indexes from both Fors", function() {
122 | var rendered = util.render(ForInsideFor, {
123 | items: ["item1", "item2", "item3"],
124 | otherItems: ["1hlab", "2hlab", "3hlab"],
125 | test: true
126 | });
127 |
128 | expect(rendered).to.contain("1hlabitem100");
129 | expect(rendered).to.contain("1hlabitem210");
130 | expect(rendered).to.contain("1hlabitem320");
131 | expect(rendered).to.contain("2hlabitem101");
132 | expect(rendered).to.contain("2hlabitem211");
133 | expect(rendered).to.contain("2hlabitem321");
134 | expect(rendered).to.contain("3hlabitem102");
135 | expect(rendered).to.contain("3hlabitem212");
136 | expect(rendered).to.contain("3hlabitem322");
137 | });
138 | });
139 |
--------------------------------------------------------------------------------
/spec/test/if.js:
--------------------------------------------------------------------------------
1 | var chai = require("chai");
2 | var spies = require("chai-spies");
3 | var util = require("../testUtil");
4 |
5 | chai.use(spies);
6 | var expect = chai.expect;
7 |
8 |
9 | describe("requiring in component with empty if", function() {
10 | var Fixture = require("../fixtures/if/if-empty.jsx");
11 |
12 | it("should render nothing when condition true, but if is empty", function() {
13 | var rendered = util.render(Fixture);
14 | expect(rendered).to.match(/^]*><\/div>$/);
15 | });
16 | });
17 |
18 | describe("requiring in component with if", function() {
19 | var IfWithoutElse = require("../fixtures/if/if.jsx");
20 |
21 | it("should render if block when condition true", function() {
22 | var rendered = util.render(IfWithoutElse, {condition: "blah"});
23 | expect(rendered).to.contain("
If-If<");
68 | expect(rendered).not.to.contain("Else");
69 | expect(consoleSpy).to.not.have.been.called();
70 | });
71 |
72 | it("should render if-else block when outer condition true, inner false", function() {
73 | var rendered = util.render(Fixture, {ifCondition: true});
74 | expect(rendered).to.contain(">If-Else<");
75 | expect(rendered).not.to.contain("If<");
76 | expect(rendered).not.to.contain(">Else");
77 | expect(consoleSpy).to.not.have.been.called();
78 | });
79 |
80 | it("should render else-if block when outer condition false, inner true", function() {
81 | var rendered = util.render(Fixture, {nestedIfCondition: "other"});
82 | expect(rendered).to.contain(">Else-If<");
83 | expect(rendered).not.to.contain("If-");
84 | expect(rendered).not.to.contain("-Else");
85 | expect(consoleSpy).to.not.have.been.called();
86 | });
87 |
88 | it("should render else-else block when both conditions false", function() {
89 | var rendered = util.render(Fixture);
90 | expect(rendered).to.contain("Else-Else");
91 | expect(rendered).not.to.contain("If");
92 | expect(consoleSpy).to.not.have.been.called();
93 | });
94 | });
95 |
--------------------------------------------------------------------------------
/spec/test/mixed.js:
--------------------------------------------------------------------------------
1 | var expect = require("chai").expect;
2 | var util = require("../testUtil");
3 |
4 | describe("nesting if within for", function() {
5 | var IfInsideFor = require("../fixtures/mixed/if-inside-for.jsx");
6 |
7 | it("should render only the item where if condition is true", function() {
8 | var rendered = util.render(IfInsideFor, {blahs: ["blah1", "blah2", "blah3"]});
9 | expect(rendered).to.contain("blah1");
10 | expect(rendered).to.not.contain("blah2");
11 | });
12 |
13 | it("should render nothing if condition is false", function() {
14 | var rendered = util.render(IfInsideFor, {blahs: ["nope", "nope2", "nope3"]});
15 | expect(rendered).to.not.contain("Not Rendered");
16 | expect(rendered).to.not.contain("]*>]*>test<\/span><\/div>$/);
10 | });
11 |
12 | it("should render with a single attribute", function() {
13 | var Fixture = require("../fixtures/with/with-single-attribute.jsx");
14 | var rendered = util.render(Fixture);
15 | expect(rendered).to.match(/^]*>
]*>value<\/span><\/div>$/);
16 | });
17 |
18 | it("should render with multiple attributes", function() {
19 | var Fixture = require("../fixtures/with/with-multiple-attributes.jsx");
20 | var rendered = util.render(Fixture);
21 | expect(rendered).to.match(/^]*>
]*>value1value2value3<\/span><\/div>$/);
22 | });
23 |
24 | it("should render with an unused attribute", function() {
25 | var Fixture = require("../fixtures/with/with-unused-attribute.jsx");
26 | var rendered = util.render(Fixture);
27 | expect(rendered).to.match(/^]*>
]*>used<\/span><\/div>$/);
28 | });
29 |
30 | it("should render a string attribute", function() {
31 | var Fixture = require("../fixtures/with/with-string-attribute.jsx");
32 | var rendered = util.render(Fixture);
33 | expect(rendered).to.match(/^]*>
]*>string<\/span><\/div>$/);
34 | });
35 |
36 | it("should render an expression attribute", function() {
37 | var Fixture = require("../fixtures/with/with-expression-attribute.jsx");
38 | var rendered = util.render(Fixture);
39 | expect(rendered).to.match(/^]*>
]*>expression<\/span><\/div>$/);
40 | });
41 |
42 | it("should inherit nested attributes", function() {
43 | var Fixture = require("../fixtures/with/with-nested.jsx");
44 | var rendered = util.render(Fixture);
45 | expect(rendered).to.match(/^]*>
]*>outerinner<\/span><\/div>$/);
46 | });
47 |
48 | it("should shadow nested attributes", function() {
49 | var Fixture = require("../fixtures/with/with-nested-shadowed.jsx");
50 | var rendered = util.render(Fixture);
51 | expect(rendered).to.match(/^]*>
]*>inner<\/span><\/div>$/);
52 | });
53 |
54 | it("should restore shadowed nested attributes", function() {
55 | var Fixture = require("../fixtures/with/with-nested-shadowed-restored.jsx");
56 | var rendered = util.render(Fixture);
57 | expect(rendered).to.match(
58 | /^]*>
]*>outer<\/span>]*>inner<\/span>]*>outer<\/span><\/div>$/
59 | );
60 | });
61 |
62 | it("should preserve access to outer variables", function() {
63 | var Fixture = require("../fixtures/with/with-outer.jsx");
64 | var rendered = util.render(Fixture);
65 | expect(rendered).to.match(/^]*>
]*>variableattribute<\/span><\/div>$/);
66 | });
67 |
68 | it("should shadow outer variables", function() {
69 | var Fixture = require("../fixtures/with/with-outer-shadowed.jsx");
70 | var rendered = util.render(Fixture);
71 | expect(rendered).to.match(/^]*>
]*>attribute<\/span><\/div>$/);
72 | });
73 |
74 | it("should restore shadowed outer variables", function() {
75 | var Fixture = require("../fixtures/with/with-outer-shadowed-restored.jsx");
76 | var rendered = util.render(Fixture);
77 | expect(rendered).to.match(
78 | /^]*>
]*>variable<\/span>]*>attribute<\/span>]*>variable<\/span><\/div>$/
79 | );
80 | });
81 |
82 | it("should preserve access to outer this", function() {
83 | var Fixture = require("../fixtures/with/with-outer-this.jsx");
84 | var rendered = util.render(Fixture);
85 | expect(rendered).to.match(/^]*>
]*>attributeouter<\/span><\/div>$/);
86 | });
87 |
88 | it("should render nothing if content is empty", function() {
89 | var Fixture = require("../fixtures/with/with-empty-content.jsx");
90 | var rendered = util.render(Fixture);
91 | expect(rendered).to.match(/^]*><\/div>$/);
92 | });
93 |
94 | it("should render a text child", function() {
95 | var Fixture = require("../fixtures/with/with-text-child.jsx");
96 | var rendered = util.render(Fixture);
97 | expect(rendered).to.match(/^
]*>text child value<\/div>$/);
98 | });
99 |
100 | it("should render a single element child", function() {
101 | var Fixture = require("../fixtures/with/with-element-child.jsx");
102 | var rendered = util.render(Fixture);
103 | expect(rendered).to.match(/^
]*>
]*>value<\/span><\/div>$/);
104 | });
105 |
106 | it("should render multiple children", function() {
107 | var Fixture = require("../fixtures/with/with-multiple-children.jsx");
108 | var rendered = util.render(Fixture);
109 | expect(rendered).to.match(
110 | /^]*>
]*>value<\/span>]*>value<\/span>]*>value<\/span><\/div>$/
111 | );
112 | });
113 |
114 | it("should render as toplevel component", function() {
115 | var Fixture = require("../fixtures/with/with-toplevel-component.jsx");
116 | var rendered = util.render(Fixture);
117 | expect(rendered).to.match(/^]*>value<\/span>$/);
118 | });
119 | });
120 |
--------------------------------------------------------------------------------
/spec/testUtil.js:
--------------------------------------------------------------------------------
1 | var React = require("react");
2 | var ReactDOMServer = require("react-dom/server");
3 |
4 | exports.render = function(Fixture, args) {
5 | var fixture = React.createElement(Fixture, args);
6 | return ReactDOMServer.renderToString(fixture);
7 | };
8 |
9 | function getSpan(content) {
10 | return "]*>" + content + "";
11 | }
12 |
13 | function getDiv(content) {
14 | return "]*>" + content + "
";
15 | }
16 |
17 | function buildRegExp(matcher) {
18 | return new RegExp("^" + matcher + "$");
19 | }
20 |
21 | exports.matchTextWithinSpan = function(text) {
22 | return buildRegExp(getSpan(text));
23 | };
24 |
25 | exports.matchTextWithinDiv = function(text) {
26 | return buildRegExp(getDiv(text));
27 | };
28 |
29 | exports.matchTextWithinSpanWithinDiv = function(text) {
30 | return buildRegExp(getDiv(getSpan(text)));
31 | };
32 |
33 | exports.matchTextWithinSpansWithinDiv = function(text1, text2) {
34 | return buildRegExp(getDiv(getSpan(text1) + getSpan(text2)));
35 | };
36 |
37 | exports.matchEmptyDiv = function() {
38 | return buildRegExp(getDiv(""));
39 | };
40 |
41 | var Builder = function(type) {
42 | var items = [];
43 |
44 | return {
45 | addReactText: function(content) {
46 | items.push({ text: content, type: "react-text" });
47 | return this;
48 | },
49 | addSpan: function(content) {
50 | items.push({ text: getSpan(content) });
51 | return this;
52 | },
53 | addDiv: function(content) {
54 | items.push({ text: getDiv(content) });
55 | return this;
56 | },
57 | build: function() {
58 | var result = "";
59 |
60 | for (var i = 0; i < items.length; i++) {
61 | result += items[i].text;
62 | var nextI = i + 1;
63 |
64 | if (
65 | nextI < items.length &&
66 | items[i].type === "react-text" &&
67 | items[nextI].type === "react-text"
68 | ) {
69 | result += "";
70 | }
71 | }
72 |
73 | return buildRegExp(type === "div" ? getDiv(result) : getSpan(result));
74 | }
75 | };
76 | };
77 |
78 | exports.createDivMatcher = function() {
79 | return new Builder("div");
80 | };
81 |
--------------------------------------------------------------------------------
/spec/tests.js:
--------------------------------------------------------------------------------
1 | var plugin = require("../src/index");
2 |
3 | require("@babel/register")({
4 | presets: ["@babel/preset-react"],
5 | plugins: [plugin],
6 | cache: false
7 | });
8 |
9 | require("./test/basic");
10 | require("./test/if");
11 | require("./test/choose");
12 | require("./test/for");
13 | require("./test/with");
14 | require("./test/mixed");
15 | require("./test/extension");
16 | require("./test/error");
17 |
--------------------------------------------------------------------------------
/src/chooseStatement.js:
--------------------------------------------------------------------------------
1 | var astUtil = require("./util/ast");
2 | var conditionalUtil = require("./util/conditional");
3 | var errorUtil = require("./util/error");
4 |
5 | var ELEMENTS = {
6 | CHOOSE: "Choose",
7 | WHEN: "When",
8 | OTHERWISE: "Otherwise"
9 | };
10 |
11 |
12 | function getBlocks(types, children, errorInfos, key) {
13 | var childNodes;
14 | var startResult = {};
15 | startResult[ELEMENTS.WHEN] = [];
16 |
17 | var result = children.reduceRight(function(resultSoFar, child) {
18 | if (astUtil.isTag(child, ELEMENTS.OTHERWISE)) {
19 | childNodes = astUtil.getChildren(types, child);
20 | errorInfos.element = ELEMENTS.OTHERWISE;
21 | errorInfos.node = child;
22 |
23 | if (resultSoFar[ELEMENTS.WHEN].length) {
24 | errorUtil.throwChooseOtherwiseNotLast(errorInfos);
25 | }
26 | else if (resultSoFar[ELEMENTS.OTHERWISE]) {
27 | errorUtil.throwChooseWithMultipleOtherwise(errorInfos);
28 | }
29 |
30 | resultSoFar[ELEMENTS.OTHERWISE] = astUtil.getSanitizedExpressionForContent(types, childNodes, key);
31 | }
32 | else if (astUtil.isTag(child, ELEMENTS.WHEN)) {
33 | childNodes = astUtil.getChildren(types, child);
34 | errorInfos.element = ELEMENTS.WHEN;
35 | errorInfos.node = child;
36 |
37 | resultSoFar[ELEMENTS.WHEN].push({
38 | condition: conditionalUtil.getConditionExpression(child, errorInfos),
39 | children: astUtil.getSanitizedExpressionForContent(types, childNodes, key)
40 | });
41 | }
42 | else {
43 | errorInfos.element = ELEMENTS.CHOOSE;
44 | errorInfos.node = child;
45 | errorUtil.throwChooseWithWrongChildren(errorInfos);
46 | }
47 |
48 | return resultSoFar;
49 | }, startResult);
50 |
51 | if (!result[ELEMENTS.OTHERWISE]) {
52 | result[ELEMENTS.OTHERWISE] = types.NullLiteral();
53 | }
54 |
55 | return result;
56 | }
57 |
58 | module.exports = function(babel) {
59 | var types = babel.types;
60 |
61 | return function(node, file) {
62 | var errorInfos = { node: node, file: file, element: ELEMENTS.CHOOSE };
63 | var children = astUtil.getChildren(types, node);
64 | var key = astUtil.getKey(node);
65 | var blocks = getBlocks(types, children, errorInfos, key);
66 | var ternaryExpression = blocks[ELEMENTS.OTHERWISE];
67 |
68 | if (!blocks[ELEMENTS.WHEN].length) {
69 | errorInfos.node = node;
70 | errorUtil.throwChooseWithoutWhen(errorInfos);
71 | }
72 |
73 | blocks[ELEMENTS.WHEN].forEach(function(whenBlock) {
74 | ternaryExpression = types.ConditionalExpression(whenBlock.condition, whenBlock.children, ternaryExpression);
75 | });
76 |
77 | return ternaryExpression;
78 | };
79 | };
80 |
--------------------------------------------------------------------------------
/src/forStatement.js:
--------------------------------------------------------------------------------
1 | var astUtil = require("./util/ast");
2 | var errorUtil = require("./util/error");
3 |
4 | var ELEMENTS = {
5 | FOR: "For"
6 | };
7 | var ATTRIBUTES = {
8 | EACH: "each",
9 | OF: "of",
10 | INDEX: "index",
11 | BODY: "body"
12 | };
13 |
14 | function addMapParam(types, params, attributes, attributeKey) {
15 | var attribute = attributes[attributeKey];
16 | if (attribute && attribute.value) {
17 | params.push(types.Identifier(attribute.value.value));
18 | }
19 | else {
20 | params.push(types.Identifier(attributeKey));
21 | }
22 | }
23 |
24 | function checkForString(attributes, name, errorInfos) {
25 | if (attributes[name] && !astUtil.isStringLiteral(attributes[name])) {
26 | errorUtil.throwNotStringType(name, errorInfos);
27 | }
28 | }
29 |
30 | function checkForExpression(attributes, name, errorInfos) {
31 | if (attributes[name] && !astUtil.isExpressionContainer(attributes[name])) {
32 | errorUtil.throwNotExpressionType(name, errorInfos);
33 | }
34 | }
35 |
36 | module.exports = function(babel) {
37 | var types = babel.types;
38 |
39 | return function(node, file) {
40 | var mapParams = [];
41 | var errorInfos = { node: node, file: file, element: ELEMENTS.FOR };
42 | var attributes = astUtil.getAttributeMap(node);
43 | var children = astUtil.getChildren(types, node);
44 | var returnExpression = astUtil.getSanitizedExpressionForContent(
45 | types,
46 | children
47 | );
48 |
49 | // required attribute
50 | if (!attributes[ATTRIBUTES.OF]) {
51 | errorUtil.throwNoAttribute(ATTRIBUTES.OF, errorInfos);
52 | }
53 |
54 | if (attributes[ATTRIBUTES.BODY]) {
55 | return types.callExpression(
56 | types.memberExpression(
57 | attributes[ATTRIBUTES.OF].value.expression,
58 | types.identifier("map")
59 | ),
60 | [attributes[ATTRIBUTES.BODY].value.expression, types.identifier("this")]
61 | );
62 | }
63 | // check for correct data types, as far as possible
64 | checkForExpression(attributes, ATTRIBUTES.OF, errorInfos);
65 | checkForString(attributes, ATTRIBUTES.EACH, errorInfos);
66 | checkForString(attributes, ATTRIBUTES.INDEX, errorInfos);
67 |
68 | // simply return without any child nodes
69 | if (!children.length) {
70 | return returnExpression;
71 | }
72 |
73 | addMapParam(types, mapParams, attributes, ATTRIBUTES.EACH);
74 | addMapParam(types, mapParams, attributes, ATTRIBUTES.INDEX);
75 |
76 | return types.callExpression(
77 | types.memberExpression(
78 | attributes[ATTRIBUTES.OF].value.expression,
79 | types.identifier("map")
80 | ),
81 | [
82 | types.functionExpression(
83 | null,
84 | mapParams,
85 | types.blockStatement([types.returnStatement(returnExpression)])
86 | ),
87 | types.identifier("this")
88 | ]
89 | );
90 | };
91 | };
92 |
--------------------------------------------------------------------------------
/src/ifStatement.js:
--------------------------------------------------------------------------------
1 | var astUtil = require("./util/ast");
2 | var conditionalUtil = require("./util/conditional");
3 |
4 | var ELEMENTS = {
5 | IF: "If",
6 | ELSE: "Else"
7 | };
8 |
9 | function getBlocks(nodes) {
10 | var result = {
11 | ifBlock: [],
12 | elseBlock: []
13 | };
14 | var currentBlock = result.ifBlock;
15 |
16 | nodes.forEach(function(node) {
17 | if (astUtil.isTag(node, ELEMENTS.ELSE)) {
18 | currentBlock = result.elseBlock;
19 | }
20 | else {
21 | currentBlock.push(node);
22 | }
23 | });
24 |
25 | return result;
26 | }
27 |
28 | module.exports = function ifStatement(babel) {
29 | var types = babel.types;
30 |
31 | return function(node, file) {
32 | var ifBlock;
33 | var elseBlock;
34 | var errorInfos = {node: node, file: file, element: ELEMENTS.IF};
35 | var condition = conditionalUtil.getConditionExpression(node, errorInfos);
36 | var key = astUtil.getKey(node);
37 | var children = astUtil.getChildren(types, node);
38 | var blocks = getBlocks(children);
39 |
40 | ifBlock = astUtil.getSanitizedExpressionForContent(types, blocks.ifBlock, key);
41 | elseBlock = astUtil.getSanitizedExpressionForContent(types, blocks.elseBlock, key);
42 |
43 | return types.ConditionalExpression(condition, ifBlock, elseBlock);
44 | };
45 | };
46 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | var transformFor = require("./forStatement");
2 | var transformIf = require("./ifStatement");
3 | var transformChoose = require("./chooseStatement");
4 | var transformWith = require("./withStatement");
5 |
6 |
7 | module.exports = function jcsPlugin(babel) {
8 | var nodeHandlers = {
9 | For: transformFor(babel),
10 | If: transformIf(babel),
11 | Choose: transformChoose(babel),
12 | With: transformWith(babel)
13 | };
14 |
15 | var visitor = {
16 | JSXElement: function(path) {
17 | var nodeName = path.node.openingElement.name.name;
18 | var handler = nodeHandlers[nodeName];
19 |
20 | if (handler) {
21 | path.replaceWith(handler(path.node, path.hub.file));
22 | }
23 | }
24 | };
25 |
26 | return {
27 | visitor: visitor
28 | };
29 | };
30 |
--------------------------------------------------------------------------------
/src/util/ast.js:
--------------------------------------------------------------------------------
1 | var TYPES = {
2 | ELEMENT: "JSXElement",
3 | EXPRESSION_CONTAINER: "JSXExpressionContainer",
4 | STRING_LITERAL: "StringLiteral"
5 | };
6 |
7 | function getTagName(node) {
8 | return node.openingElement.name.name;
9 | }
10 |
11 | /**
12 | * Test if this is a custom JSX element with the given name.
13 | *
14 | * @param {object} node - Current node to test
15 | * @param {string} tagName - Name of element
16 | * @returns {boolean} whether the searched for element was found
17 | */
18 | exports.isTag = function(node, tagName) {
19 | return node.type === TYPES.ELEMENT && getTagName(node) === tagName;
20 | };
21 |
22 |
23 | /**
24 | * Tests whether this is an JSXExpressionContainer and returns it if true.
25 | *
26 | * @param {object} attribute - The attribute the value of which is tested
27 | * @returns {boolean}
28 | */
29 | exports.isExpressionContainer = function(attribute) {
30 | return attribute && attribute.value.type === TYPES.EXPRESSION_CONTAINER;
31 | };
32 |
33 | /**
34 | * Get expression from given attribute.
35 | *
36 | * @param {JSXAttribute} attribute
37 | * @returns {Expression}
38 | */
39 | exports.getExpression = function(attribute) {
40 | return attribute.value.expression;
41 | };
42 |
43 | /**
44 | * Tests whether this is an StringLiteral and returns it if true.
45 | *
46 | * @param {object} attribute - The attribute the value of which is tested
47 | * @returns {boolean}
48 | */
49 | exports.isStringLiteral = function(attribute) {
50 | return attribute && attribute.value.type === TYPES.STRING_LITERAL;
51 | };
52 |
53 | /**
54 | * Get all attributes from given element.
55 | *
56 | * @param {JSXElement} node - Current node from which attributes are gathered
57 | * @returns {object} Map of all attributes with their name as key
58 | */
59 | exports.getAttributeMap = function(node) {
60 | return node.openingElement.attributes.reduce(function(result, attr) {
61 | result[attr.name.name] = attr;
62 | return result;
63 | }, {});
64 | };
65 |
66 | /**
67 | * Get the string value of a node's key attribute if present.
68 | *
69 | * @param {JSXElement} node - Node to get attributes from
70 | * @returns {object} The string value of the key attribute of this node if present, otherwise undefined.
71 | */
72 | exports.getKey = function(node) {
73 | var key = exports.getAttributeMap(node).key;
74 | return key ? key.value.value : undefined;
75 | };
76 |
77 | /**
78 | * Get all children from given element. Normalizes JSXText and JSXExpressionContainer to expressions.
79 | *
80 | * @param {object} babelTypes - Babel lib
81 | * @param {JSXElement} node - Current node from which children are gathered
82 | * @returns {array} List of all children
83 | */
84 | exports.getChildren = function(babelTypes, node) {
85 | return babelTypes.react.buildChildren(node);
86 | };
87 |
88 | /**
89 | * Adds attribute "key" to given node, if not already preesent.
90 | *
91 | * @param {object} babelTypes - Babel lib
92 | * @param {JSXElement} node - Current node to which the new attribute is added
93 | * @param {string} keyValue - Value of the key
94 | */
95 | var addKeyAttribute = function(babelTypes, node, keyValue) {
96 | var keyFound = false;
97 |
98 | node.openingElement.attributes.forEach(function(attrib) {
99 | if (babelTypes.isJSXAttribute(attrib) && attrib.name.name === "key") {
100 | keyFound = true;
101 | return false;
102 | }
103 | });
104 |
105 | if (!keyFound) {
106 | var keyAttrib = babelTypes.jSXAttribute(babelTypes.jSXIdentifier("key"), babelTypes.stringLiteral("" + keyValue));
107 | node.openingElement.attributes.push(keyAttrib);
108 | }
109 | };
110 | exports.addKeyAttribute = addKeyAttribute;
111 |
112 | /**
113 | * Return either a NullLiteral (if no content is available) or
114 | * the single expression (if there is only one) or an ArrayExpression.
115 | *
116 | * @param babelTypes - Babel lib
117 | * @param blocks - the content blocks
118 | * @param keyPrefix - a prefix to use when automatically generating keys
119 | * @returns {NullLiteral|Expression|ArrayExpression}
120 | */
121 | exports.getSanitizedExpressionForContent = function(babelTypes, blocks, keyPrefix) {
122 | if (!blocks.length) {
123 | return babelTypes.NullLiteral();
124 | }
125 | else if (blocks.length === 1) {
126 | var firstBlock = blocks[0];
127 |
128 | if (keyPrefix && firstBlock.openingElement) {
129 | addKeyAttribute(babelTypes, firstBlock, keyPrefix);
130 | }
131 |
132 | return firstBlock;
133 | }
134 |
135 | for (var i = 0; i < blocks.length; i++) {
136 | var thisBlock = blocks[i];
137 | if (babelTypes.isJSXElement(thisBlock)) {
138 | var key = keyPrefix ? keyPrefix + "-" + i : i;
139 | addKeyAttribute(babelTypes, thisBlock, key);
140 | }
141 | }
142 |
143 | return babelTypes.arrayExpression(blocks);
144 | };
145 |
--------------------------------------------------------------------------------
/src/util/conditional.js:
--------------------------------------------------------------------------------
1 | var astUtil = require("./ast");
2 | var errorUtil = require("./error");
3 |
4 |
5 | var ATTRIBUTES = {
6 | CONDITION: "condition"
7 | };
8 |
9 | exports.getConditionExpression = function(node, errorInfos) {
10 | var condition = astUtil.getAttributeMap(node)[ATTRIBUTES.CONDITION];
11 |
12 | if (!condition) {
13 | errorUtil.throwNoAttribute(ATTRIBUTES.CONDITION, errorInfos);
14 | }
15 | if (!astUtil.isExpressionContainer(condition)) {
16 | errorUtil.throwNotExpressionType(ATTRIBUTES.CONDITION, errorInfos);
17 | }
18 |
19 | return astUtil.getExpression(condition);
20 | };
21 |
--------------------------------------------------------------------------------
/src/util/error.js:
--------------------------------------------------------------------------------
1 | // http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format#answer-4673436
2 | function formatString(format) {
3 | var args = Array.prototype.slice.call(arguments, 1);
4 | return format.replace(/{(\d+)}/g, function(match, number) {
5 | return typeof args[number] !== "undefined" ? args[number] : match;
6 | });
7 | }
8 |
9 | function throwError(errorMsg, infos) {
10 | throw new Error(
11 | [
12 | exports.renderErrorMessage(errorMsg, infos),
13 | " at ",
14 | infos.file.opts.filename,
15 | ": ",
16 | infos.node.loc.start.line,
17 | ",",
18 | infos.node.loc.start.column
19 | ].join("")
20 | );
21 | }
22 |
23 | var ERRORS = exports.ERRORS = {
24 | NO_ATTRIBUTE: "Attribute \"{0}\" is required for <{1}>, but missing!",
25 | NOT_EXPRESSION_TYPE: "Attribute \"{0}\" of <{1}> tag must be an expression, e.g. \"{0}={ ... }\"",
26 | NOT_STRING_TYPE: "Attribute \"{0}\" of <{1}> tag must be of type String, e.g. {0}=\"...\"",
27 | CHOOSE_WITHOUT_WHEN: " statement requires at least one element!",
28 | CHOOSE_OTHERWISE_NOT_LAST: " must be the last element within a statement!",
29 | CHOOSE_WITH_MULTIPLE_OTHERWISE: " statement allows only for one block!",
30 | CHOOSE_WITH_WRONG_CHILDREN: "Only and are allowed child elements for !"
31 | };
32 |
33 | exports.renderErrorMessage = function(errorMsg, infos) {
34 | var args = [];
35 | if (infos) {
36 | args.push(infos.attribute);
37 | args.push(infos.element);
38 | }
39 | return formatString(errorMsg, args);
40 | };
41 |
42 | exports.throwNoAttribute = function(attributeName, infos) {
43 | infos.attribute = attributeName;
44 | throwError(ERRORS.NO_ATTRIBUTE, infos);
45 | };
46 |
47 | exports.throwNotExpressionType = function(attributeName, infos) {
48 | infos.attribute = attributeName;
49 | throwError(ERRORS.NOT_EXPRESSION_TYPE, infos);
50 | };
51 |
52 | exports.throwNotStringType = function(attributeName, infos) {
53 | infos.attribute = attributeName;
54 | throwError(ERRORS.NOT_STRING_TYPE, infos);
55 | };
56 |
57 | exports.throwChooseWithoutWhen = function(infos) {
58 | throwError(ERRORS.CHOOSE_WITHOUT_WHEN, infos);
59 | };
60 |
61 | exports.throwChooseOtherwiseNotLast = function(infos) {
62 | throwError(ERRORS.CHOOSE_OTHERWISE_NOT_LAST, infos);
63 | };
64 |
65 | exports.throwChooseWithMultipleOtherwise = function(infos) {
66 | throwError(ERRORS.CHOOSE_WITH_MULTIPLE_OTHERWISE, infos);
67 | };
68 |
69 | exports.throwChooseWithWrongChildren = function(infos) {
70 | throwError(ERRORS.CHOOSE_WITH_WRONG_CHILDREN, infos);
71 | };
72 |
--------------------------------------------------------------------------------
/src/withStatement.js:
--------------------------------------------------------------------------------
1 | var astUtil = require("./util/ast");
2 |
3 | module.exports = function(babel) {
4 | var types = babel.types;
5 |
6 | return function(node) {
7 | var params = [];
8 | var values = [];
9 | var key = astUtil.getKey(node);
10 | var attributes = astUtil.getAttributeMap(node);
11 | var children = astUtil.getChildren(types, node);
12 |
13 | Object.keys(attributes).forEach(function(attribute) {
14 | params.push(types.identifier(attribute));
15 | if (astUtil.isExpressionContainer(attributes[attribute])) {
16 | values.push(attributes[attribute].value.expression);
17 | }
18 | else {
19 | values.push(attributes[attribute].value);
20 | }
21 | });
22 |
23 | values.unshift(types.identifier("this"));
24 |
25 | return types.callExpression(
26 | types.memberExpression(
27 | types.functionExpression(
28 | null,
29 | params,
30 | types.blockStatement([
31 | types.returnStatement(
32 | astUtil.getSanitizedExpressionForContent(types, children, key)
33 | )
34 | ])
35 | ),
36 | types.identifier("call")
37 | ),
38 | values
39 | );
40 | };
41 | };
42 |
--------------------------------------------------------------------------------
/wallaby.js:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | return {
3 | files: [
4 | "src/**/*.js",
5 | "spec/testUtil.js",
6 | {
7 | pattern: "spec/**/*.jsx",
8 | instrument: false,
9 | load: false,
10 | ignore: false
11 | }
12 | ],
13 |
14 | tests: ["spec/**/*.js", "!spec/tests.js", "!spec/testUtil.js"],
15 |
16 | env: {
17 | type: "node",
18 | runner: "node"
19 | },
20 |
21 | setup: function(wallaby) {
22 | var plugin = require("./src/index");
23 | require("@babel/register")({
24 | presets: ["@babel/preset-react"],
25 | plugins: [plugin],
26 | cache: false
27 | });
28 | }
29 | };
30 | };
31 |
--------------------------------------------------------------------------------