├── .gitignore ├── package.json ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-to-jsx", 3 | "version": "1.3.2", 4 | "main": "index.js", 5 | "author": "Alex Lande", 6 | "license": "MIT", 7 | "dependencies": { 8 | "jstoxml": "^0.2.3", 9 | "lodash": "^3.2.0", 10 | "react": "^0.13.3" 11 | }, 12 | "description": "Generates a JSX string representation of React elements", 13 | "keywords": [ 14 | "react", 15 | "jsx", 16 | "style-guide" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/alexlande/react-to-jsx" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alex Lande 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Important: `react-to-jsx` is deprecated and unmaintained. Use [react-element-to-jsx-string](https://github.com/algolia/react-element-to-jsx-string) instead!** 2 | 3 | # React to JSX 4 | 5 | Generates a JSX string representation of React elements. Takes a React Element (or an array of React Elements). Useful for generating React component style guides. 6 | 7 | ## Usage 8 | 9 | ### Install 10 | 11 | ``` 12 | npm install react-to-jsx 13 | ``` 14 | 15 | ### Basic Usage 16 | 17 | ```js 18 | var reactToJsx = require('react-to-jsx'); 19 | 20 | var jsxString = reactToJsx( 21 | 26 | ); 27 | 28 | // 33 | 34 | console.log(jsxString); 35 | ``` 36 | 37 | ### Options 38 | 39 | `reactToJsx` takes an optional `options` object: `reactToJsx(reactElement, options)`. 40 | 41 | #### `indent` 42 | 43 | Type: `String` Default: `'\t'` (Tab) 44 | 45 | Sets the indent string for returned JSX. Should probably match your preferred 46 | code style. Two spaces? Four? Three? The choice is yours, friend. 47 | 48 | #### `includeNull` 49 | 50 | Type: 'Boolean' Default: `true` 51 | 52 | Determines whether to include props with a value of `null` in the returned JSX. 53 | 54 | #### `exclude` 55 | 56 | Type: `Array` Default: `[]` 57 | 58 | Array of props to exclude from the returned JSX. Hide those weird props, they shouldn't be in your docs anyway. 59 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var jstoxml = require('jstoxml'); 3 | var React = require('react'); 4 | 5 | var componentToJson = function (component, config) { 6 | var componentJson = {}; 7 | var componentArray = []; 8 | var name; 9 | 10 | if (_.isArray(component)) { 11 | _.forEach(component, function (item) { 12 | componentArray.push(componentToJson(item, config)); 13 | }); 14 | 15 | return componentArray; 16 | } 17 | 18 | if (component.type && (component.type.displayName || component.type.name)) { 19 | name = component.type.displayName || component.type.name; 20 | } else if (component.type) { 21 | name = component.type; 22 | } else { 23 | return component; 24 | } 25 | 26 | var children; 27 | 28 | if (component.props && component.props.children) { 29 | children = component.props.children; 30 | children = _.isArray(children) ? children : [children]; 31 | children = _.map(children, function (child, config) { 32 | return componentToJson(child, config); 33 | }); 34 | } 35 | 36 | var matchingProps; 37 | 38 | if (component.type && component.type.defaultProps) { 39 | matchingProps = _.omit(component.props, function (val, key) { 40 | return component.type.defaultProps[key] === component.props[key]; 41 | }); 42 | } else { 43 | matchingProps = component.props; 44 | } 45 | 46 | var props = _.chain(matchingProps) 47 | .omit(['children']) 48 | .transform(function (result, prop, key) { 49 | if (_.isUndefined(prop)) { 50 | return; 51 | } else if (_.isNull(prop) && !config.includeNull) { 52 | return; 53 | } else if (config.exclude && config.exclude.indexOf(key) !== -1) { 54 | return; 55 | } else if (_.isString(prop)) { 56 | result[key] = prop; 57 | } else if (_.isFunction(prop)) { 58 | result[key] = 'LITERAL!function!LITERAL'; 59 | } else if (React.isValidElement(prop)) { 60 | result[key] = 'LITERAL!ReactElement!LITERAL'; 61 | } else { 62 | var stringified; 63 | 64 | try { 65 | stringified = JSON.stringify(prop); 66 | } catch(e) { 67 | stringified = '[Circular JSON]'; 68 | } 69 | 70 | result[key] = 'LITERAL!' + stringified + '!LITERAL'; 71 | } 72 | }) 73 | .value(); 74 | 75 | componentJson = { 76 | _name: name, 77 | _attrs: props, 78 | _content: children 79 | }; 80 | 81 | return componentJson; 82 | } 83 | 84 | var reactToJsx = function (component, options) { 85 | var defaults = { 86 | indent: '\t', 87 | includeNull: true, 88 | exclude: [] 89 | }; 90 | 91 | var config = _.extend({}, defaults, options); 92 | 93 | var componentXml = jstoxml.toXML(componentToJson(component, config), { 94 | indent: config.indent 95 | }); 96 | 97 | componentXml = componentXml 98 | .replace(/"LITERAL!/g, '{') 99 | .replace(/!LITERAL"/g, '}') 100 | 101 | var componentArray = componentXml.split('\n'); 102 | 103 | componentArray = _.map(componentArray, function (line) { 104 | var attributeMatcher = /\s+(?=\S*=)/g; 105 | 106 | if ((line.match(attributeMatcher) || []).length < 2) { 107 | return line; 108 | } 109 | 110 | var indentRegex = new RegExp(config.indent, 'g'); 111 | 112 | var indentDepth = (line.match(indentRegex) || []).length; 113 | var newlineString = '\n' + config.indent; 114 | 115 | for (var i = 0; i < indentDepth; i++) { 116 | newlineString += config.indent; 117 | } 118 | 119 | line = line.replace(attributeMatcher, newlineString); 120 | 121 | return line; 122 | }); 123 | 124 | componentXml = componentArray.join('\n'); 125 | 126 | return componentXml; 127 | }; 128 | 129 | module.exports = reactToJsx; 130 | --------------------------------------------------------------------------------