diff --git a/.DS_Store b/.DS_Store index 35e1e90..b004549 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 1d0b53f..0000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["es2015", "react"], - "plugins": ["transform-object-rest-spread"] -} \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1e04ccd..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "node": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "ecmaFeatures": { - "experimentalObjectRestSpread": true, - "jsx": true - }, - "sourceType": "module" - }, - "plugins": [ - "react" - ], - "rules": { - "indent": [ - "error", - 2 - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ], - "no-console": 0 - } -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 58214ba..a76c363 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ -react-json-pretty.sublime-project -react-json-pretty.sublime-workspace node_modules npm-debug.log .DS_Store tests/lcov-report -tests/lcov.info \ No newline at end of file +tests/lcov.info +dist +themes +types +coverage \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 232b582..0000000 --- a/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -.babelrc -.gitignore -.eslintrc.json -.travis.yml -example -tests \ No newline at end of file diff --git a/JSONPretty.jsx b/JSONPretty.jsx deleted file mode 100644 index 6732c74..0000000 --- a/JSONPretty.jsx +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable no-unused-vars */ -var React = require('react'); -/* eslint-enable no-unused-vars */ -var createReactClass = require('create-react-class'); - -module.exports = createReactClass({ - // 格式化函数 - _replace: function (match, ind, key, val, tra) { - var spanEnd = ''; - var keySpan = ''; - var valSpan = ''; - var strSpan = ''; - var booSpan = ''; - var sps = ind || ''; - if (key) { - sps = sps + '"' + keySpan + key.replace(/^"|":\s$/g, '')+ spanEnd + '": '; - } - - if (val) { - if (val === 'true' || val === 'false') { - sps = sps + booSpan + val + spanEnd; - } - else { - sps = sps + (val[0] == '"' ? strSpan : valSpan) + val + spanEnd; - } - } - - return sps + (tra || ''); - }, - // JSON =》 HTML转换器 - _pretty: function (obj, replacer, space) { - // 逐行匹配,列举:“key”: "value" | "key": value | "key": [ | "key": { | "key": [],| "Key": {}, - var regLine = /^( *)("[^"]+": )?("[^"]*"|[\w.+-]*)?([,[{]|\[\s*\],?|\{\s*\},?)?$/mg; - var text = JSON.stringify(obj, typeof replacer === 'function' ? replacer : null, isNaN(space) ? 2 : space); - - if (!text) { - return text; - } - - return text.replace(/&/g, '&').replace(/\\"([^,])/g, '\\"$1') - .replace(//g, '>') - .replace(regLine, this._replace); - }, - render: function () { - - // See https://facebook.github.io/react/warnings/unknown-prop.html - var { json, replacer, space, className, themeClassName, ...rest } = this.props; - - themeClassName = themeClassName ? themeClassName.trim() : themeClassName; - className = className ? className.trim() : className; - var themeClassNameFinal = themeClassName || 'json-pretty'; - var classNameFinal = className ? (className + ' ' + themeClassNameFinal) : themeClassNameFinal; - - if (typeof json === 'string') { - try { - json = JSON.parse(json); - } - catch (e) { - console.error('The string is not a valid json data!', e); - return( -
-          
- ); - } - } - - return ( -
-      
- ); - } -}); diff --git a/LICENSE b/LICENSE index d7b7079..6efcaae 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2015 Fractal +Copyright (c) 2013-2015 Fractal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 37f1496..77cabcd 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Introduction -This is a react component that help you to prettify your json strings on the browser based on JavaScript. Presently, it provides a monikai theme style for you, and of course you are free to add your own theme if you like for this is pretty easy. +This is a lightweight and tiny react component that helps you to prettify JSON data in the browser. ## Install ```bash @@ -37,16 +37,18 @@ Next, in your 'jsx' file use it like the following: Where `obj` is the JSON string or just a valid JavaScript object. -And also you can import the style to the document, here is an example of using webpack loaders(`style!css!stylus`) to load style, You can visit [webpack](https://webpack.github.io/) to get more details: +### Use themes with css-loader and webpack + +And also you can import the style to the document, here is an example of using webpack loaders(`style!css`) to load style, You can visit [webpack](https://webpack.github.io/) to get more details: ```javascript -require('react-json-pretty/JSONPretty.monikai.styl'); +require('react-json-pretty/themes/JSONPretty.monikai.css'); ``` -Or use the es2015 +Or use `import` ```javascript -import 'react-json-pretty/JSONPretty.monikai.styl'; +import 'react-json-pretty/themes/JSONPretty.monikai.css'; ``` If you still don't get it, visit the [example](https://github.com/chenckang/react-json-pretty/tree/master/example). @@ -55,16 +57,20 @@ Lastly, if you succeed so far the preview will look like the below: ![previews, you can also find it in the example folder](https://github.com/chenckang/react-json-pretty/blob/master/example/preview.png?raw=true) -## Upgrade +### Use themes with `theme` property + +theme={main: '', key: '', value: '', boolean: '', string: ''} + +## Others ### Formation Actually, react-json-pretty is based on `JSON.stringify(value[, replacer[, space]])`. However, `JSON.stringify(value[, replacer[, space]])` has some optional parameters additionally such as `replacer` and `space`. so since the version 1.7.0, we extend react-json-pretty to support these two parameters. -Here is the example: +Here is an example: ```javascript - ``` -The default value for property `replacer` is `null`,and `space` is `2`. +** Note: The default value for property `replacer` is `null`,and `space` is `2`. ** You can visit the [example](https://github.com/chenckang/react-json-pretty/tree/master/example) to see the details. -### Class +### Custom `className` Since the version 1.7.0, we add `themeClassName` property for adding custom theme `className`,the default `className` for theme is `json-pretty`. but in case you want to have your own name, you use `themeClassName` property to modify it; diff --git a/example/.babelrc b/example/.babelrc index 1515f32..85e86ab 100644 --- a/example/.babelrc +++ b/example/.babelrc @@ -1,3 +1,3 @@ { - "presets": ["react"] + "presets": ["@babel/preset-react"] } \ No newline at end of file diff --git a/example/app/Example.jsx b/example/app/Example.jsx index 5622000..661e293 100644 --- a/example/app/Example.jsx +++ b/example/app/Example.jsx @@ -21,24 +21,74 @@ var obj2 = { }; var JSONPretty = require('react-json-pretty'); -require('react-json-pretty/JSONPretty.adventure_time.styl'); +require('react-json-pretty/themes/JSONPretty.adventure_time.css'); require('../assets/custom.styl'); obj.text = true; obj.abc = false; obj.number = 1234567890; -ReactDOM.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; -var obj3 = CircularJSON.stringify(ReactDOM); +document.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'; +var obj3 = CircularJSON.stringify(document); + +class Tick extends React.Component { + constructor() { + super(); + this.themes = [ + { + main: 'background-color: #999', + key: 'color:rgba(255,94,94,1);', + value: 'color:rgba(253,176,130,1);', + string: 'color:rgba(233,253,172,1);', + boolean: 'rgba(102,153,204,1);', + }, + { + main: 'background-color:rgba(116,128,150,1)', + key: 'color:rgba(181,83,191,1);', + value: 'color:rgba(147,163,191,1);', + string: 'color:rgba(251,168,86,1);', + boolean: 'color:rgba(68,138,169,1);', + }, + { + main: 'background-color#1e1e1e;color:rgba(245,187,18,1)', + key: 'color:rgba(211,66,46,1);', + value: 'color:rgba(191,215,219,1);', + string: 'color:rgba(127,214,250,1);', + boolean: 'color:rgba(75,174,22,1);', + } + ]; + this.state = { + acc: 0, + }; + } + + render() { + return ( + + ); + } + + componentDidMount() { + setInterval(() => { + this.setState({ + acc: this.state.acc + 1, + }); + }, 3000); + } +} ReactDOM.render(
- +
- - - + + + } space="2">
- - - + + +
, document.getElementById('example') diff --git a/example/assets/custom.styl b/example/assets/custom.styl index 8d82a77..cf4066e 100644 --- a/example/assets/custom.styl +++ b/example/assets/custom.styl @@ -8,14 +8,17 @@ white-space -o-pre-wrap; word-wrap break-word - .json-key + .__json-key__ color #F92672 - .json-value + .__json-value__ color #A6E22E - .json-string + .__json-string__ color #FD971F - .json-boolean - color #AC81Fe \ No newline at end of file + .__json-boolean__ + color #AC81Fe + +.test-3 + font-size 1.5em \ No newline at end of file diff --git a/example/package.json b/example/package.json index 53ccf14..dc4f428 100644 --- a/example/package.json +++ b/example/package.json @@ -6,25 +6,25 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "watch": "webpack --watch", - "dev": "webpack-dev-server --content-base build/" + "dev": "webpack-dev-server --content-base public/" }, "author": "", "license": "MIT", "devDependencies": { - "babel-core": "^6.24.1", - "babel-loader": "^6.2.0", - "babel-preset-react": "^6.3.13", - "css-loader": "^0.23.1", - "html-webpack-plugin": "^1.7.0", - "json-loader": "^0.5.4", - "style-loader": "^0.13.0", - "stylus": "^0.54.5", - "stylus-loader": "^3.0.1", - "webpack": "^1.12.9" + "@babel/core": "^7.2.2", + "@babel/preset-react": "^7.0.0", + "babel-loader": "^8.0.4", + "css-loader": "^2.1.0", + "html-webpack-plugin": "^3.2.0", + "json-loader": "^0.5.7", + "style-loader": "^0.23.1", + "webpack": "^4.28.3", + "webpack-cli": "^3.1.2", + "webpack-dev-server": "^3.1.14" }, "dependencies": { - "circular-json": "^0.3.1", - "react": "^15.4.2", - "react-dom": "^15.4.2" + "circular-json": "^0.5.9", + "react": "^16.7.0", + "react-dom": "^16.7.0" } } diff --git a/example/webpack.config.js b/example/webpack.config.js index 49aaf26..96a72a6 100644 --- a/example/webpack.config.js +++ b/example/webpack.config.js @@ -2,6 +2,8 @@ var path = require('path'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { + target: 'web', + mode: 'development', entry: { example: "./app/Example.jsx", common: ['react'] @@ -11,10 +13,9 @@ module.exports = { filename: "[name].js" }, module: { - loaders: [ + rules: [ {test: /\.css$/, loader: "style-loader!css-loader"}, {test: /\.jsx?$/, loader: "babel-loader"}, - {test: /\.json$/, loader: "json-loader"}, {test: /\.styl$/, loader: "style-loader!css-loader!stylus-loader"} ] }, @@ -24,5 +25,8 @@ module.exports = { filename: 'index.html', inject: 'body' }) - ] + ], + devServer: { + host: '0.0.0.0' + } }; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..5c9240b --- /dev/null +++ b/jest.config.js @@ -0,0 +1,17 @@ +module.exports = { + "roots": [ + "/tests", + ], + "transform": { + "^.+\\.tsx?$": "ts-jest", + }, + "testRegex": "test\\.tsx?$", + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx" + ], + "snapshotSerializers": ["enzyme-to-json/serializer"], + "setupTestFrameworkScriptFile": "/tests/setupEnzyme.ts", +} \ No newline at end of file diff --git a/package.json b/package.json index a35c81b..a53bdfa 100644 --- a/package.json +++ b/package.json @@ -2,21 +2,29 @@ "name": "react-json-pretty", "version": "1.7.9", "description": "A code formatting tool for raw json data", - "main": "src/JSONPretty.js", + "main": "dist/JSONPretty.js", + "files": [ + "dist", + "themes", + "types", + "LICENSE", + "README.md", + "CHANGELOG.md" + ], "scripts": { - "test": "jest --coverage --silent", + "test": "jest --verbose=true --coverage", "build": "npm run build-styl && npm run build-jsx", - "eslint": "eslint JSONPretty.jsx", - "precommit": "npm run build && npm run eslint", + "lint": "tslint --project tsconfig.json --config tslint.json './src/**/*.tsx'", + "precommit": "npm run build && npm run lint", "prepush": "npm test", "release": "standard-version", "patch": "npm run release -- --release-as patch", - "build-styl-monikai": "stylus --compress < JSONPretty.monikai.styl > src/JSONPretty.monikai.css", - "build-styl-1337": "stylus --compress < JSONPretty.1337.styl > src/JSONPretty.1337.css", - "build-styl-acai": "stylus --compress < JSONPretty.acai.styl > src/JSONPretty.acai.css", - "build-styl-adventure": "stylus --compress < JSONPretty.adventure_time.styl > src/JSONPretty.adventure_time.css", + "build-styl-monikai": "stylus --compress < src/JSONPretty.monikai.styl > themes/JSONPretty.monikai.css", + "build-styl-1337": "stylus --compress < src/JSONPretty.1337.styl > themes/JSONPretty.1337.css", + "build-styl-acai": "stylus --compress < src/JSONPretty.acai.styl > themes/JSONPretty.acai.css", + "build-styl-adventure": "stylus --compress < src/JSONPretty.adventure_time.styl > themes/JSONPretty.adventure_time.css", "build-styl": "npm run build-styl-monikai && npm run build-styl-1337 && npm run build-styl-acai && npm run build-styl-adventure", - "build-jsx": "babel --presets react --plugins 'transform-object-rest-spread' JSONPretty.jsx -d src" + "build-jsx": "tsc -p tsconfig.json" }, "keywords": [ "react", @@ -32,30 +40,35 @@ "react-dom": ">=15.0" }, "devDependencies": { - "babel-cli": "~6.3.17", - "babel-core": "^6.3.26", - "babel-jest": "^19.0.0", - "babel-loader": "^6.2.0", - "babel-plugin-transform-object-rest-spread": "^6.8.0", - "babel-preset-es2015": "^6.24.1", - "babel-preset-react": "^6.24.1", - "eslint": "^3.19.0", - "eslint-plugin-react": "^6.10.3", - "husky": "^0.13.3", - "jest": "^19.0.2", - "react": "^15.5.4", - "react-dom": "^15.5.4", - "react-test-renderer": "^15.5.4", + "@types/chai": "^4.1.7", + "@types/enzyme": "^3.1.15", + "@types/enzyme-adapter-react-16": "^1.0.3", + "@types/jest": "^23.3.11", + "@types/prop-types": "^15.5.8", + "@types/react": "^16.7.18", + "@types/react-dom": "^16.0.11", + "chai": "^4.2.0", + "enzyme": "^3.8.0", + "enzyme-adapter-react-16": "^1.7.1", + "enzyme-to-json": "^3.3.5", + "husky": "^1.3.1", + "jest": "^23.6.0", + "react": "^16.7.0", + "react-dom": "^16.7.0", + "react-test-renderer": "^16.7.0", "standard-version": "^4.4.0", "stylus": "^0.54.5", - "webpack": "^2.4.1" + "ts-jest": "^23.10.5", + "tslint": "^5.12.0", + "typescript": "^3.2.2", + "webpack": "^4.28.3" }, "repository": { "type": "git", "url": "https://github.com/chenckang/react-json-pretty" }, "dependencies": { - "create-react-class": "^15.5.2" + "prop-types": "^15.6.2" }, "jest": { "collectCoverageFrom": [ diff --git a/src/JSONPretty.1337.css b/src/JSONPretty.1337.css deleted file mode 100644 index b71d87c..0000000 --- a/src/JSONPretty.1337.css +++ /dev/null @@ -1 +0,0 @@ -.json-pretty{line-height:1.3;color:#f8f8f2;background:#1e1e1e;}.json-pretty .json-key{color:#ff5e5e}.json-pretty .json-value{color:#fdb082}.json-pretty .json-string{color:#e9fdac}.json-pretty .json-boolean{color:#69c} diff --git a/JSONPretty.1337.styl b/src/JSONPretty.1337.styl similarity index 66% rename from JSONPretty.1337.styl rename to src/JSONPretty.1337.styl index a44091d..8ff204b 100644 --- a/JSONPretty.1337.styl +++ b/src/JSONPretty.1337.styl @@ -1,17 +1,18 @@ /****** monikai ******/ -.json-pretty +.__json-pretty__ line-height 1.3 color rgba(248,248,242,1) background #1e1e1e + overflow auto - .json-key + .__json-key__ color rgba(255,94,94,1) - .json-value + .__json-value__ color rgba(253,176,130,1) - .json-string + .__json-string__ color rgba(233,253,172,1) - .json-boolean + .__json-boolean__ color rgba(102,153,204,1) diff --git a/src/JSONPretty.acai.css b/src/JSONPretty.acai.css deleted file mode 100644 index 4447705..0000000 --- a/src/JSONPretty.acai.css +++ /dev/null @@ -1 +0,0 @@ -.json-pretty{line-height:1.3;color:#748096;background:#1e1e1e;}.json-pretty .json-key{color:#b553bf}.json-pretty .json-value{color:#93a3bf}.json-pretty .json-string{color:#fba856}.json-pretty .json-boolean{color:#448aa9} diff --git a/JSONPretty.acai.styl b/src/JSONPretty.acai.styl similarity index 66% rename from JSONPretty.acai.styl rename to src/JSONPretty.acai.styl index 7fc8f56..6568641 100644 --- a/JSONPretty.acai.styl +++ b/src/JSONPretty.acai.styl @@ -1,17 +1,18 @@ /****** monikai ******/ -.json-pretty +.__json-pretty__ line-height 1.3 color rgba(116,128,150,1) background #1e1e1e + overflow auto - .json-key + .__json-key__ color rgba(181,83,191,1) - .json-value + .__json-value__ color rgba(147,163,191,1) - .json-string + .__json-string__ color rgba(251,168,86,1) - .json-boolean + .__json-boolean__ color rgba(68,138,169,1) diff --git a/src/JSONPretty.adventure_time.css b/src/JSONPretty.adventure_time.css deleted file mode 100644 index 97a4b0b..0000000 --- a/src/JSONPretty.adventure_time.css +++ /dev/null @@ -1 +0,0 @@ -.json-pretty{line-height:1.3;color:#f5bb12;background:#1e1e1e;}.json-pretty .json-key{color:#d3422e}.json-pretty .json-value{color:#bfd7db}.json-pretty .json-string{color:#7fd6fa}.json-pretty .json-boolean{color:#4bae16} diff --git a/JSONPretty.adventure_time.styl b/src/JSONPretty.adventure_time.styl similarity index 66% rename from JSONPretty.adventure_time.styl rename to src/JSONPretty.adventure_time.styl index 99754f2..72d5c59 100644 --- a/JSONPretty.adventure_time.styl +++ b/src/JSONPretty.adventure_time.styl @@ -1,17 +1,18 @@ /****** monikai ******/ -.json-pretty +.__json-pretty__ line-height 1.3 color rgba(245,187,18,1) background #1e1e1e + overflow auto - .json-key + .__json-key__ color rgba(211,66,46,1) - .json-value + .__json-value__ color rgba(191,215,219,1) - .json-string + .__json-string__ color rgba(127,214,250,1) - .json-boolean + .__json-boolean__ color rgba(75,174,22,1) diff --git a/src/JSONPretty.js b/src/JSONPretty.js deleted file mode 100644 index 9ea8220..0000000 --- a/src/JSONPretty.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; - -var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } - -/* eslint-disable no-unused-vars */ -var React = require('react'); -/* eslint-enable no-unused-vars */ -var createReactClass = require('create-react-class'); - -module.exports = createReactClass({ - displayName: 'exports', - - // 格式化函数 - _replace: function _replace(match, ind, key, val, tra) { - var spanEnd = '
'; - var keySpan = ''; - var valSpan = ''; - var strSpan = ''; - var booSpan = ''; - var sps = ind || ''; - if (key) { - sps = sps + '"' + keySpan + key.replace(/^"|":\s$/g, '') + spanEnd + '": '; - } - - if (val) { - if (val === 'true' || val === 'false') { - sps = sps + booSpan + val + spanEnd; - } else { - sps = sps + (val[0] == '"' ? strSpan : valSpan) + val + spanEnd; - } - } - - return sps + (tra || ''); - }, - // JSON =》 HTML转换器 - _pretty: function _pretty(obj, replacer, space) { - // 逐行匹配,列举:“key”: "value" | "key": value | "key": [ | "key": { | "key": [],| "Key": {}, - var regLine = /^( *)("[^"]+": )?("[^"]*"|[\w.+-]*)?([,[{]|\[\s*\],?|\{\s*\},?)?$/mg; - var text = JSON.stringify(obj, typeof replacer === 'function' ? replacer : null, isNaN(space) ? 2 : space); - - if (!text) { - return text; - } - - return text.replace(/&/g, '&').replace(/\\"([^,])/g, '\\"$1').replace(//g, '>').replace(regLine, this._replace); - }, - render: function render() { - - // See https://facebook.github.io/react/warnings/unknown-prop.html - var _props = this.props, - json = _props.json, - replacer = _props.replacer, - space = _props.space, - className = _props.className, - themeClassName = _props.themeClassName, - rest = _objectWithoutProperties(_props, ['json', 'replacer', 'space', 'className', 'themeClassName']); - - themeClassName = themeClassName ? themeClassName.trim() : themeClassName; - className = className ? className.trim() : className; - var themeClassNameFinal = themeClassName || 'json-pretty'; - var classNameFinal = className ? className + ' ' + themeClassNameFinal : themeClassNameFinal; - - if (typeof json === 'string') { - try { - json = JSON.parse(json); - } catch (e) { - console.error('The string is not a valid json data!', e); - return React.createElement('pre', _extends({}, rest, { className: classNameFinal || 'json-pretty', dangerouslySetInnerHTML: { __html: json } })); - } - } - - return React.createElement('pre', _extends({}, rest, { className: classNameFinal || 'json-pretty', dangerouslySetInnerHTML: { __html: this._pretty(json, replacer, +space) } })); - } -}); \ No newline at end of file diff --git a/src/JSONPretty.monikai.css b/src/JSONPretty.monikai.css deleted file mode 100644 index c20a822..0000000 --- a/src/JSONPretty.monikai.css +++ /dev/null @@ -1 +0,0 @@ -.json-pretty{line-height:1.3;color:#66d9ef;background:#272822;}.json-pretty .json-key{color:#f92672}.json-pretty .json-value{color:#a6e22e}.json-pretty .json-string{color:#fd971f}.json-pretty .json-boolean{color:#ac81fe} diff --git a/JSONPretty.monikai.styl b/src/JSONPretty.monikai.styl similarity index 59% rename from JSONPretty.monikai.styl rename to src/JSONPretty.monikai.styl index 05830b1..17e46bc 100644 --- a/JSONPretty.monikai.styl +++ b/src/JSONPretty.monikai.styl @@ -1,17 +1,18 @@ /****** monikai ******/ -.json-pretty +.__json-pretty__ line-height 1.3 color #66d9ef background #272822 + overflow auto - .json-key + .__json-key__ color #F92672 - .json-value + .__json-value__ color #A6E22E - .json-string + .__json-string__ color #FD971F - .json-boolean + .__json-boolean__ color #AC81Fe diff --git a/src/JSONPretty.tsx b/src/JSONPretty.tsx new file mode 100644 index 0000000..09dc3ae --- /dev/null +++ b/src/JSONPretty.tsx @@ -0,0 +1,116 @@ +import * as PropTypes from 'prop-types'; +import * as React from 'react'; + +interface ITheme {[key: string]: string; } +interface IProps { + json?: any; + data?: any; + replacer?: (key: string, value: any) => any | null; + space?: number | string; + themeClassName?: string; + theme?: ITheme; + silent?: boolean; +} + +function getStyle(name: string, theme: ITheme): string { + return theme ? theme[name] ? ` style="${theme[name]}"` : '' : ''; +} + +class JSONPretty extends React.Component { + public static propTypes = { + data: PropTypes.any, + json: PropTypes.any, + replacer: PropTypes.func, + silent: PropTypes.bool, + space: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + theme: PropTypes.object, + themeClassName: PropTypes.string, + }; + + public static defaultProps = { + data: '', + json: '', + silent: true, + space: 2, + themeClassName: '__json-pretty__', + }; + + public render() { + const { json, data, replacer, space, themeClassName, theme, silent, ...rest } = this.props; + + let obj = data || json; + + // See https://facebook.github.io/react/warnings/unknown-prop.html + if (typeof obj === 'string') { + try { + obj = JSON.parse(obj); + } catch (e) { + if (!silent) { + console.warn(`[react-json-pretty]: ${e.message}`); + } + + return( +
${obj}` + } + }> +
+ ); + } + } + + return ( +
${ + this._pretty.call(this, theme, obj, replacer, +space) + }` + } + }> +
+ ); + } + + // JSON =》 HTML转换器 + private _pretty(theme: ITheme, obj: any, replacer: () => {}, space: number) { + // 逐行匹配,列举:“key”: "value" | "key": value | "key": [ | "key": { | "key": [],| "Key": {}, + const regLine = /^( *)("[^"]+": )?("[^"]*"|[\w.+-]*)?([,[{]|\[\s*\],?|\{\s*\},?)?$/mg; + const text = JSON.stringify(obj, typeof replacer === 'function' ? replacer : null, isNaN(space) ? 2 : space); + + /* istanbul ignore next */ + if (!text) { + return text; + } + + return text.replace(/&/g, '&').replace(/\\"([^,])/g, '\\"$1') + .replace(//g, '>') + .replace(regLine, this._replace.bind(null, theme)); + } + + // 格式化函数 + private _replace(theme: ITheme, match: any, ind: string, key: string, val: string, tra: string) { + const spanEnd = '
'; + const keySpan = ``; + const valSpan = ``; + const strSpan = ``; + const booSpan = ``; + + let sps = ind || ''; + if (key) { + sps = sps + '"' + keySpan + key.replace(/^"|":\s$/g, '') + spanEnd + '": '; + } + + if (val) { + if (val === 'true' || val === 'false') { + sps = sps + booSpan + val + spanEnd; + } else { + sps = sps + (val[0] === '"' ? strSpan : valSpan) + val + spanEnd; + } + } + + return sps + (tra || ''); + } +} + +export = JSONPretty; diff --git a/tests/JSONPretty.test.tsx b/tests/JSONPretty.test.tsx new file mode 100644 index 0000000..f079395 --- /dev/null +++ b/tests/JSONPretty.test.tsx @@ -0,0 +1,290 @@ +import { shallow } from 'enzyme'; +import * as React from 'react'; + +import { expect } from 'chai'; + +import JSONPretty from '../src/JSONPretty'; + +test('simple', () => { + const box = shallow(); + expect(box.html()).to.equal('
123
'); +}); + +test('complex object', () => { + const box = shallow(); + + `
{
+    "aaaa": 1,
+    "bb:bb": true,
+    "cccc": "ab\\"cd\\\\",
+    ":i\\"iii:": ":ii:ii",
+    "dddd": {
+      "eeee": 1,
+      "ffff": [
+        {
+          "gggg": 3
+        },
+        2,
+        "str:ing"
+      ]
+    }
+  }
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); + +test('complex string', () => { + const box = shallow(); + + `
{
+    "aaaa": 1,
+    "bb:bb": true,
+    "cccc": "ab\\"cd\\\\",
+    ":i\\"iii:": ":ii:ii",
+    "dddd": {
+      "eeee": 1,
+      "ffff": [
+        {
+          "gggg": 3
+        },
+        2,
+        "str:ing"
+      ]
+    }
+  }
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); + +test('complex string with theme', () => { + const box = shallow(); + + `
{
+    "aaaa": 1,
+    "bb:bb": true,
+    "cccc": "ab\\"cd\\\\",
+    ":i\\"iii:": ":ii:ii",
+    "dddd": {
+      "eeee": 1,
+      "ffff": [
+        {
+          "gggg": 3
+        },
+        2,
+        "str:ing"
+      ]
+    }
+  }
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); + +test('complex string with theme missing boolean theme', () => { + const box = shallow(); + + `
{
+    "aaaa": 1,
+    "bb:bb": true,
+    "cccc": "ab\\"cd\\\\",
+    ":i\\"iii:": ":ii:ii",
+    "dddd": {
+      "eeee": 1,
+      "ffff": [
+        {
+          "gggg": 3
+        },
+        2,
+        "str:ing"
+      ]
+    }
+  }
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); + +test('invalid', () => { + const box = shallow(); + expect(box.html()).to.equal('
'); +}); + +test('invalid json', () => { + const box = shallow(); + + `
12345,78907
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); + +test('invalid space', () => { + const box = shallow(); + + console.log(box.html()); + + `
12345
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); + +test('complex object with format', () => { + const box = shallow(); + + `
{
+    "aaaa": 1,
+    "bb:bb": true,
+    "cccc": "ab\\"cd\\\\~~~abc",
+    ":i\\"iii:": ":ii:ii",
+    "dddd": {
+      "eeee": 1,
+      "ffff": [
+        {
+          "gggg": 30
+        },
+        2,
+        "str:ing"
+      ]
+    }
+  }
` + .split('\n') + .map((line) => line.trim()) + .forEach((line) => { + expect(box.html()).to.include(line); + }); +}); diff --git a/tests/__snapshots__/pretty_js_snapshot.test.js.snap b/tests/__snapshots__/pretty_js_snapshot.test.js.snap deleted file mode 100644 index 7662b4a..0000000 --- a/tests/__snapshots__/pretty_js_snapshot.test.js.snap +++ /dev/null @@ -1,62 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`JSONPretty.js -- StringInvalid 1`] = ` -
-`;
-
-exports[`src/JSONPretty.js -- string 1`] = `
-
aaaa\\": 1,
-      \\"bbbb\\": true,
-      \\"cccc\\": \\"ab\\\\"cd\\\\\\\\\\",
-      \\"dddd\\": {
-        \\"eeee\\": 1,
-        \\"ffff\\": [
-          {
-            \\"gggg\\": 3
-          },
-          2,
-          \\"string\\"
-        ]
-      }
-    }",
-    }
-  }
-/>
-`;
-
-exports[`src/JSONPretty.js 1`] = `
-
aaaa\\": 1,
-      \\"bbbb\\": true,
-      \\"cccc\\": \\"ab\\\\"cd\\\\\\\\\\",
-      \\"dddd\\": {
-        \\"eeee\\": 1,
-        \\"ffff\\": [
-          {
-            \\"gggg\\": 3
-          },
-          2,
-          \\"string\\"
-        ]
-      }
-    }",
-    }
-  }
-/>
-`;
diff --git a/tests/__snapshots__/pretty_jsx_snapshot.test.js.snap b/tests/__snapshots__/pretty_jsx_snapshot.test.js.snap
deleted file mode 100644
index 26d21c9..0000000
--- a/tests/__snapshots__/pretty_jsx_snapshot.test.js.snap
+++ /dev/null
@@ -1,68 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`JSONPretty.jsx -- String 1`] = `
-
aaaa\\": 1,
-      \\"bbbb\\": true,
-      \\"efef\\": \\"true\\",
-      \\"efed\\": \\"false\\",
-      \\"efee\\": false,
-      \\"cccc\\": \\"ab\\\\"cd\\\\\\\\\\",
-      \\"dddd\\": {
-        \\"eeee\\": 1,
-        \\"ffff\\": [
-          {
-            \\"gggg\\": 3
-          },
-          2,
-          \\"string\\"
-        ]
-      }
-    }",
-    }
-  }
-/>
-`;
-
-exports[`JSONPretty.jsx -- StringInvalid 1`] = `
-
-`;
-
-exports[`JSONPretty.jsx 1`] = `
-
aaaa\\": 1,
-      \\"bbbb\\": true,
-      \\"efef\\": \\"true\\",
-      \\"efed\\": \\"false\\",
-      \\"efee\\": false,
-      \\"cccc\\": \\"ab\\\\"cd\\\\\\\\\\",
-      \\"dddd\\": {
-        \\"eeee\\": 1,
-        \\"ffff\\": [
-          {
-            \\"gggg\\": 3
-          },
-          2,
-          \\"string\\"
-        ]
-      }
-    }",
-    }
-  }
-/>
-`;
diff --git a/tests/pretty_js_snapshot.test.js b/tests/pretty_js_snapshot.test.js
deleted file mode 100644
index 5b20e4e..0000000
--- a/tests/pretty_js_snapshot.test.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from 'react';
-import JSONPretty from '../src/JSONPretty';
-import renderer from 'react-test-renderer';
-
-var obj2 = {
-  aaaa: 1,
-  bbbb: true,
-  cccc: "ab\"cd\\",
-  dddd: {
-    eeee: 1,
-    ffff: [
-      {
-        gggg: 3
-      },
-      2,
-      "string"
-    ]
-  }
-};
-
-test('src/JSONPretty.js', () => {
-	const json = renderer.create(
-		
-  );
-
-	let tree = json.toJSON();
-	expect(tree).toMatchSnapshot();
-});
-
-test('src/JSONPretty.js -- string', () => {
-	const json = renderer.create(
-		
-  );
-
-	let tree = json.toJSON();
-	expect(tree).toMatchSnapshot();
-});
-
-test('JSONPretty.js -- StringInvalid', () => {
-	const json = renderer.create(
-		
-	);
-
-	let tree = json.toJSON();
-	expect(tree).toMatchSnapshot();
-});
\ No newline at end of file
diff --git a/tests/pretty_jsx_snapshot.test.js b/tests/pretty_jsx_snapshot.test.js
deleted file mode 100644
index a63b051..0000000
--- a/tests/pretty_jsx_snapshot.test.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import React from 'react';
-import JSONPretty from '../JSONPretty';
-import renderer from 'react-test-renderer';
-
-var obj2 = {
-  aaaa: 1,
-  bbbb: true,
-	efef: "true",
-	efed: "false",
-	efee: false,
-  cccc: "ab\"cd\\",
-  dddd: {
-    eeee: 1,
-    ffff: [
-      {
-        gggg: 3
-      },
-      2,
-      "string"
-    ]
-  }
-};
-
-test('JSONPretty.jsx', () => {
-	const json = renderer.create(
-		
-  );
-
-	let tree = json.toJSON();
-	expect(tree).toMatchSnapshot();
-});
-
-test('JSONPretty.jsx -- String', () => {
-	const json = renderer.create(
-		
-  );
-
-	let tree = json.toJSON();
-	expect(tree).toMatchSnapshot();
-});
-
-test('JSONPretty.jsx -- StringInvalid', () => {
-	const json = renderer.create(
-		
-	);
-
-	let tree = json.toJSON();
-	expect(tree).toMatchSnapshot();
-});
\ No newline at end of file
diff --git a/tests/setupEnzyme.ts b/tests/setupEnzyme.ts
new file mode 100644
index 0000000..82edfc9
--- /dev/null
+++ b/tests/setupEnzyme.ts
@@ -0,0 +1,4 @@
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+
+configure({ adapter: new Adapter() });
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..3aa05a5
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "outDir": "./dist/",
+    "sourceMap": false,
+    "noImplicitAny": true,
+    "module": "commonjs",
+    "esModuleInterop": true,
+    "target": "es5",
+    "declaration": true,
+    "declarationDir": "./types",
+    "jsx": "react"
+  },
+  "include": [
+    "./src/**/*.tsx"
+  ]
+}
\ No newline at end of file
diff --git a/tslint.json b/tslint.json
new file mode 100644
index 0000000..3fe2788
--- /dev/null
+++ b/tslint.json
@@ -0,0 +1,35 @@
+{
+  "defaultSeverity": "error",
+  "extends": [
+    "tslint:recommended"
+  ],
+  "linterOptions": {
+    "exclude": [
+      "node_modules/**",
+      "tests/**"
+    ]
+  },
+  "jsRules": {},
+  "rules": {
+    "max-line-length": {
+      "options": [
+        120
+      ]
+    },
+    "quotemark": [
+      true,
+      "single"
+    ],
+    "trailing-comma": [
+      true,
+      {
+        "functions": "never",
+        "singleline": "never"
+      }
+    ],
+    "no-console": [
+      false
+    ]
+  },
+  "rulesDirectory": []
+}
\ No newline at end of file