From 40ac89aff96cee57b5b5743bdfd29083f32465e8 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Fri, 21 Aug 2020 20:13:24 -0400 Subject: [PATCH] feature(react-json-tree): convert react-json-tree to TypeScript (#601) * eslint base * stash * setup * stash * stash * Add jest.config.js * caught --- .gitattributes | 2 + eslintrc.ts.base.json | 8 +- eslintrc.ts.jest.base.json | 8 +- eslintrc.ts.react.base.json | 30 ++ eslintrc.ts.react.jest.base.json | 21 ++ package.json | 14 +- packages/react-base16-styling/src/index.ts | 3 + packages/react-json-tree/.babelrc | 6 +- packages/react-json-tree/.eslintignore | 2 + packages/react-json-tree/.eslintrc.js | 29 ++ packages/react-json-tree/.prettierignore | 2 + packages/react-json-tree/jest.config.js | 3 + packages/react-json-tree/package.json | 75 ++-- .../src/{ItemRange.js => ItemRange.tsx} | 23 +- .../{JSONArrayNode.js => JSONArrayNode.tsx} | 14 +- .../src/{JSONArrow.js => JSONArrow.tsx} | 17 +- ...ONIterableNode.js => JSONIterableNode.tsx} | 14 +- .../{JSONNestedNode.js => JSONNestedNode.tsx} | 66 +++- .../src/{JSONNode.js => JSONNode.tsx} | 16 +- .../{JSONObjectNode.js => JSONObjectNode.tsx} | 12 +- .../{JSONValueNode.js => JSONValueNode.tsx} | 17 +- ...FromTheme.js => createStylingFromTheme.ts} | 32 +- ...tionEntries.js => getCollectionEntries.ts} | 28 +- .../src/{index.js => index.tsx} | 67 +++- .../src/{objType.js => objType.ts} | 2 +- .../src/themes/{solarized.js => solarized.ts} | 0 packages/react-json-tree/src/types.ts | 74 ++++ .../react-json-tree/src/utils/hexToRgb.js | 10 - .../test/{index.spec.js => index.spec.tsx} | 2 +- .../test/{objType.spec.js => objType.spec.ts} | 6 +- packages/react-json-tree/test/tsconfig.json | 4 + packages/react-json-tree/tsconfig.json | 7 + .../react-json-tree/tsconfig.webpack.json | 4 + ...ck.config.umd.js => webpack.config.umd.ts} | 17 +- tsconfig.base.json | 2 +- tsconfig.react.base.json | 6 + yarn.lock | 343 +++++++----------- 37 files changed, 634 insertions(+), 352 deletions(-) create mode 100644 eslintrc.ts.react.base.json create mode 100644 eslintrc.ts.react.jest.base.json create mode 100644 packages/react-json-tree/.eslintignore create mode 100644 packages/react-json-tree/.eslintrc.js create mode 100644 packages/react-json-tree/.prettierignore create mode 100644 packages/react-json-tree/jest.config.js rename packages/react-json-tree/src/{ItemRange.js => ItemRange.tsx} (70%) rename packages/react-json-tree/src/{JSONArrayNode.js => JSONArrayNode.tsx} (58%) rename packages/react-json-tree/src/{JSONArrow.js => JSONArrow.tsx} (66%) rename packages/react-json-tree/src/{JSONIterableNode.js => JSONIterableNode.tsx} (70%) rename packages/react-json-tree/src/{JSONNestedNode.js => JSONNestedNode.tsx} (78%) rename packages/react-json-tree/src/{JSONNode.js => JSONNode.tsx} (84%) rename packages/react-json-tree/src/{JSONObjectNode.js => JSONObjectNode.tsx} (69%) rename packages/react-json-tree/src/{JSONValueNode.js => JSONValueNode.tsx} (69%) rename packages/react-json-tree/src/{createStylingFromTheme.js => createStylingFromTheme.ts} (86%) rename packages/react-json-tree/src/{getCollectionEntries.js => getCollectionEntries.ts} (79%) rename packages/react-json-tree/src/{index.js => index.tsx} (67%) rename packages/react-json-tree/src/{objType.js => objType.ts} (89%) rename packages/react-json-tree/src/themes/{solarized.js => solarized.ts} (100%) create mode 100644 packages/react-json-tree/src/types.ts delete mode 100644 packages/react-json-tree/src/utils/hexToRgb.js rename packages/react-json-tree/test/{index.spec.js => index.spec.tsx} (91%) rename packages/react-json-tree/test/{objType.spec.js => objType.spec.ts} (90%) create mode 100644 packages/react-json-tree/test/tsconfig.json create mode 100644 packages/react-json-tree/tsconfig.json create mode 100644 packages/react-json-tree/tsconfig.webpack.json rename packages/react-json-tree/{webpack.config.umd.js => webpack.config.umd.ts} (68%) create mode 100644 tsconfig.react.base.json diff --git a/.gitattributes b/.gitattributes index ea92ae4a..159b7455 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,7 @@ *.js text eol=lf *.jsx text eol=lf +*.ts text eol=lf +*.tsx text eol=lf *.json text eol=lf *.css text eol=lf *.html text eol=lf diff --git a/eslintrc.ts.base.json b/eslintrc.ts.base.json index ba7fe944..88ce4c96 100644 --- a/eslintrc.ts.base.json +++ b/eslintrc.ts.base.json @@ -8,5 +8,11 @@ "plugin:@typescript-eslint/recommended-requiring-type-checking", "plugin:prettier/recommended", "prettier/@typescript-eslint" - ] + ], + "rules": { + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off" + } } diff --git a/eslintrc.ts.jest.base.json b/eslintrc.ts.jest.base.json index 09258ad7..39d1899e 100644 --- a/eslintrc.ts.jest.base.json +++ b/eslintrc.ts.jest.base.json @@ -9,5 +9,11 @@ "plugin:jest/style", "plugin:prettier/recommended", "prettier/@typescript-eslint" - ] + ], + "rules": { + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off" + } } diff --git a/eslintrc.ts.react.base.json b/eslintrc.ts.react.base.json new file mode 100644 index 00000000..3444c0ad --- /dev/null +++ b/eslintrc.ts.react.base.json @@ -0,0 +1,30 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + } + }, + "plugins": ["@typescript-eslint", "react"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:react/recommended", + "plugin:prettier/recommended", + "prettier/@typescript-eslint", + "prettier/react" + ], + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off" + } +} diff --git a/eslintrc.ts.react.jest.base.json b/eslintrc.ts.react.jest.base.json new file mode 100644 index 00000000..f7d46f95 --- /dev/null +++ b/eslintrc.ts.react.jest.base.json @@ -0,0 +1,21 @@ +{ + "plugins": ["jest"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:react/recommended", + "plugin:jest/recommended", + "plugin:jest/style", + "plugin:prettier/recommended", + "prettier/@typescript-eslint", + "prettier/react" + ], + "rules": { + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off" + } +} diff --git a/package.json b/package.json index f7425c38..f3a8e428 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,10 @@ "@babel/preset-env": "^7.11.0", "@babel/preset-typescript": "^7.10.4", "@types/jest": "^26.0.9", + "@types/node": "^14.6.0", + "@types/react-test-renderer": "^16.9.3", + "@types/webpack": "^4.41.21", + "@types/webpack-dev-server": "^3.11.0", "@typescript-eslint/eslint-plugin": "^3.9.0", "@typescript-eslint/parser": "^3.9.0", "babel-eslint": "^10.1.0", @@ -16,14 +20,18 @@ "eslint-plugin-jest": "^23.20.0", "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "^7.20.5", - "husky": "^4.2.5", "jest": "^26.2.2", "lerna": "^3.22.1", - "lint-staged": "^10.2.11", "prettier": "^2.0.5", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-test-renderer": "^16.13.1", "rimraf": "^3.0.2", "ts-jest": "^26.2.0", - "typescript": "^3.9.7" + "ts-node": "^9.0.0", + "typescript": "^3.9.7", + "webpack": "^4.44.1", + "webpack-cli": "^3.3.12" }, "scripts": { "lerna": "lerna", diff --git a/packages/react-base16-styling/src/index.ts b/packages/react-base16-styling/src/index.ts index 9d8cca29..6f3c36db 100644 --- a/packages/react-base16-styling/src/index.ts +++ b/packages/react-base16-styling/src/index.ts @@ -288,3 +288,6 @@ export const invertTheme = (theme: Theme | undefined): Theme | undefined => { return theme; }; + +export { Base16Theme }; +export * from './types'; diff --git a/packages/react-json-tree/.babelrc b/packages/react-json-tree/.babelrc index e60d3036..0d42ef44 100644 --- a/packages/react-json-tree/.babelrc +++ b/packages/react-json-tree/.babelrc @@ -1,4 +1,8 @@ { - "presets": ["@babel/preset-env", "@babel/preset-react"], + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript" + ], "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/packages/react-json-tree/.eslintignore b/packages/react-json-tree/.eslintignore new file mode 100644 index 00000000..79681bfb --- /dev/null +++ b/packages/react-json-tree/.eslintignore @@ -0,0 +1,2 @@ +lib +umd diff --git a/packages/react-json-tree/.eslintrc.js b/packages/react-json-tree/.eslintrc.js new file mode 100644 index 00000000..f1079770 --- /dev/null +++ b/packages/react-json-tree/.eslintrc.js @@ -0,0 +1,29 @@ +module.exports = { + extends: '../../.eslintrc', + overrides: [ + { + files: ['*.ts', '*.tsx'], + extends: '../../eslintrc.ts.react.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + }, + { + files: ['test/*.ts', 'test/*.tsx'], + extends: '../../eslintrc.ts.react.jest.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./test/tsconfig.json'], + }, + }, + { + files: ['webpack.config.umd.ts'], + extends: '../../eslintrc.ts.base.json', + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.webpack.json'], + }, + }, + ], +}; diff --git a/packages/react-json-tree/.prettierignore b/packages/react-json-tree/.prettierignore new file mode 100644 index 00000000..79681bfb --- /dev/null +++ b/packages/react-json-tree/.prettierignore @@ -0,0 +1,2 @@ +lib +umd diff --git a/packages/react-json-tree/jest.config.js b/packages/react-json-tree/jest.config.js new file mode 100644 index 00000000..8824c114 --- /dev/null +++ b/packages/react-json-tree/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'ts-jest', +}; diff --git a/packages/react-json-tree/package.json b/packages/react-json-tree/package.json index 1d4c3ef1..fe8c3f61 100644 --- a/packages/react-json-tree/package.json +++ b/packages/react-json-tree/package.json @@ -2,30 +2,15 @@ "name": "react-json-tree", "version": "0.12.1", "description": "React JSON Viewer Component, Extracted from redux-devtools", - "main": "lib/index.js", - "scripts": { - "clean": "rimraf lib", - "build": "babel src --out-dir lib", - "build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.js", - "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js", - "test": "jest", - "prepare": "npm run build", - "prepublishOnly": "npm run test && npm run clean && npm run build && npm run build:umd && npm run build:umd:min", - "start": "cd examples && npm start" - }, - "files": [ - "lib", - "src", - "umd" - ], - "repository": { - "type": "git", - "url": "https://github.com/reduxjs/redux-devtools.git" - }, "keywords": [ "react", "json viewer" ], + "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/react-json-tree", + "bugs": { + "url": "https://github.com/reduxjs/redux-devtools/issues" + }, + "license": "MIT", "author": "Shu Uesugi (http://github.com/chibicode)", "contributors": [ "Alexander Kuznetsov (http://kuzya.org/)", @@ -33,32 +18,38 @@ "Daniele Zannotti (http://www.github.com/dzannotti)", "Mihail Diordiev (https://github.com/zalmoxisus)" ], - "license": "MIT", - "bugs": { - "url": "https://github.com/reduxjs/redux-devtools/issues" + "files": [ + "lib", + "src", + "umd" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/reduxjs/redux-devtools.git" }, - "homepage": "https://github.com/reduxjs/redux-devtools", - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/preset-env": "^7.11.0", - "@babel/preset-react": "^7.10.4", - "babel-loader": "^8.1.0", - "jest": "^26.2.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-test-renderer": "^16.13.1", - "rimraf": "^3.0.2", - "webpack": "^4.44.1", - "webpack-cli": "^3.3.12" - }, - "peerDependencies": { - "react": "^16.3.0", - "react-dom": "^16.3.0" + "scripts": { + "start": "cd examples && npm start", + "build": "npm run build:types && npm run build:js && npm run build:umd && npm run build:umd:min", + "build:types": "tsc --emitDeclarationOnly", + "build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline", + "build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.ts", + "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts", + "clean": "rimraf lib umd", + "test": "jest", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "eslint . --ext .ts,.tsx --fix", + "type-check": "tsc --noEmit", + "type-check:watch": "npm run type-check -- --watch", + "preversion": "npm run type-check && npm run lint && npm run test", + "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { "prop-types": "^15.7.2", "react-base16-styling": "^0.7.0" + }, + "peerDependencies": { + "react": "^16.3.0" } } diff --git a/packages/react-json-tree/src/ItemRange.js b/packages/react-json-tree/src/ItemRange.tsx similarity index 70% rename from packages/react-json-tree/src/ItemRange.js rename to packages/react-json-tree/src/ItemRange.tsx index 5af82f0d..3848783e 100644 --- a/packages/react-json-tree/src/ItemRange.js +++ b/packages/react-json-tree/src/ItemRange.tsx @@ -1,8 +1,21 @@ import React from 'react'; import PropTypes from 'prop-types'; import JSONArrow from './JSONArrow'; +import { CircularPropsPassedThroughItemRange } from './types'; -export default class ItemRange extends React.Component { +interface Props extends CircularPropsPassedThroughItemRange { + data: any; + nodeType: string; + from: number; + to: number; + renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode; +} + +interface State { + expanded: boolean; +} + +export default class ItemRange extends React.Component { static propTypes = { styling: PropTypes.func.isRequired, from: PropTypes.number.isRequired, @@ -11,11 +24,9 @@ export default class ItemRange extends React.Component { nodeType: PropTypes.string.isRequired, }; - constructor(props) { + constructor(props: Props) { super(props); this.state = { expanded: false }; - - this.handleClick = this.handleClick.bind(this); } render() { @@ -42,7 +53,7 @@ export default class ItemRange extends React.Component { ); } - handleClick() { + handleClick = () => { this.setState({ expanded: !this.state.expanded }); - } + }; } diff --git a/packages/react-json-tree/src/JSONArrayNode.js b/packages/react-json-tree/src/JSONArrayNode.tsx similarity index 58% rename from packages/react-json-tree/src/JSONArrayNode.js rename to packages/react-json-tree/src/JSONArrayNode.tsx index f07ae3c3..97440160 100644 --- a/packages/react-json-tree/src/JSONArrayNode.js +++ b/packages/react-json-tree/src/JSONArrayNode.tsx @@ -1,15 +1,23 @@ import React from 'react'; import PropTypes from 'prop-types'; import JSONNestedNode from './JSONNestedNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; // Returns the "n Items" string for this node, // generating and caching it if it hasn't been created yet. -function createItemString(data) { - return `${data.length} ${data.length !== 1 ? 'items' : 'item'}`; +function createItemString(data: any) { + return `${(data as unknown[]).length} ${ + (data as unknown[]).length !== 1 ? 'items' : 'item' + }`; +} + +interface Props extends CircularPropsPassedThroughJSONNode { + data: any; + nodeType: string; } // Configures to render an Array -const JSONArrayNode = ({ data, ...props }) => ( +const JSONArrayNode: React.FunctionComponent = ({ data, ...props }) => ( ( +interface Props { + styling: StylingFunction; + arrowStyle?: 'single' | 'double'; + expanded: boolean; + nodeType: string; + onClick: React.MouseEventHandler; +} + +const JSONArrow: React.FunctionComponent = ({ + styling, + arrowStyle, + expanded, + nodeType, + onClick, +}) => (
{'\u25B6'} diff --git a/packages/react-json-tree/src/JSONIterableNode.js b/packages/react-json-tree/src/JSONIterableNode.tsx similarity index 70% rename from packages/react-json-tree/src/JSONIterableNode.js rename to packages/react-json-tree/src/JSONIterableNode.tsx index f252481c..dff51ad5 100644 --- a/packages/react-json-tree/src/JSONIterableNode.js +++ b/packages/react-json-tree/src/JSONIterableNode.tsx @@ -1,9 +1,10 @@ import React from 'react'; import JSONNestedNode from './JSONNestedNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; // Returns the "n Items" string for this node, // generating and caching it if it hasn't been created yet. -function createItemString(data, limit) { +function createItemString(data: any, limit: number) { let count = 0; let hasMore = false; if (Number.isSafeInteger(data.size)) { @@ -21,8 +22,13 @@ function createItemString(data, limit) { return `${hasMore ? '>' : ''}${count} ${count !== 1 ? 'entries' : 'entry'}`; } +interface Props extends CircularPropsPassedThroughJSONNode { + data: any; + nodeType: string; +} + // Configures to render an iterable -export default function JSONIterableNode({ ...props }) { +const JSONIterableNode: React.FunctionComponent = ({ ...props }) => { return ( ); -} +}; + +export default JSONIterableNode; diff --git a/packages/react-json-tree/src/JSONNestedNode.js b/packages/react-json-tree/src/JSONNestedNode.tsx similarity index 78% rename from packages/react-json-tree/src/JSONNestedNode.js rename to packages/react-json-tree/src/JSONNestedNode.tsx index 289afc2b..e8dbb261 100644 --- a/packages/react-json-tree/src/JSONNestedNode.js +++ b/packages/react-json-tree/src/JSONNestedNode.tsx @@ -4,12 +4,40 @@ import JSONArrow from './JSONArrow'; import getCollectionEntries from './getCollectionEntries'; import JSONNode from './JSONNode'; import ItemRange from './ItemRange'; +import { + CircularPropsPassedThroughJSONNestedNode, + CircularPropsPassedThroughRenderChildNodes, +} from './types'; /** * Renders nested values (eg. objects, arrays, lists, etc.) */ -function renderChildNodes(props, from, to) { +export interface RenderChildNodesProps + extends CircularPropsPassedThroughRenderChildNodes { + data: any; + nodeType: string; +} + +interface Range { + from: number; + to: number; +} + +interface Entry { + key: string | number; + value: any; +} + +function isRange(rangeOrEntry: Range | Entry): rangeOrEntry is Range { + return (rangeOrEntry as Range).to !== undefined; +} + +function renderChildNodes( + props: RenderChildNodesProps, + from?: number, + to?: number +) { const { nodeType, data, @@ -19,7 +47,7 @@ function renderChildNodes(props, from, to) { postprocessValue, sortObjectKeys, } = props; - const childNodes = []; + const childNodes: React.ReactNode[] = []; getCollectionEntries( nodeType, @@ -29,7 +57,7 @@ function renderChildNodes(props, from, to) { from, to ).forEach((entry) => { - if (entry.to) { + if (isRange(entry)) { childNodes.push( ); - - if (node !== false) { - childNodes.push(node); - } } }); return childNodes; } -function getStateFromProps(props) { +interface Props extends CircularPropsPassedThroughJSONNestedNode { + data: any; + nodeType: string; + nodeTypeIndicator: string; + createItemString: (data: any, collectionLimit: number) => string; + expandable: boolean; +} + +interface State { + expanded: boolean; +} + +function getStateFromProps(props: Props) { // calculate individual node expansion if necessary const expanded = props.shouldExpandNode && !props.isCircular @@ -76,7 +112,7 @@ function getStateFromProps(props) { }; } -export default class JSONNestedNode extends React.Component { +export default class JSONNestedNode extends React.Component { static propTypes = { getItemString: PropTypes.func.isRequired, nodeTypeIndicator: PropTypes.any, @@ -104,26 +140,26 @@ export default class JSONNestedNode extends React.Component { expandable: true, }; - constructor(props) { + constructor(props: Props) { super(props); this.state = getStateFromProps(props); } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { const nextState = getStateFromProps(nextProps); if (getStateFromProps(this.props).expanded !== nextState.expanded) { this.setState(nextState); } } - shouldComponentUpdate(nextProps, nextState) { + shouldComponentUpdate(nextProps: Props, nextState: State) { return ( !!Object.keys(nextProps).find( (key) => key !== 'circularCache' && (key === 'keyPath' ? nextProps[key].join('/') !== this.props[key].join('/') - : nextProps[key] !== this.props[key]) + : nextProps[key as keyof Props] !== this.props[key as keyof Props]) ) || nextState.expanded !== this.state.expanded ); } @@ -159,7 +195,7 @@ export default class JSONNestedNode extends React.Component { itemType, createItemString(data, collectionLimit) ); - const stylingArgs = [keyPath, nodeType, expanded, expandable]; + const stylingArgs = [keyPath, nodeType, expanded, expandable] as const; return hideRoot ? (
  • diff --git a/packages/react-json-tree/src/JSONNode.js b/packages/react-json-tree/src/JSONNode.tsx similarity index 84% rename from packages/react-json-tree/src/JSONNode.js rename to packages/react-json-tree/src/JSONNode.tsx index de05f6fc..a95314c0 100644 --- a/packages/react-json-tree/src/JSONNode.js +++ b/packages/react-json-tree/src/JSONNode.tsx @@ -5,8 +5,15 @@ import JSONObjectNode from './JSONObjectNode'; import JSONArrayNode from './JSONArrayNode'; import JSONIterableNode from './JSONIterableNode'; import JSONValueNode from './JSONValueNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; -const JSONNode = ({ +interface Props extends CircularPropsPassedThroughJSONNode { + keyPath: (string | number)[]; + value: any; + isCustomNode: (value: any) => boolean; +} + +const JSONNode: React.FunctionComponent = ({ getItemString, keyPath, labelRenderer, @@ -50,7 +57,10 @@ const JSONNode = ({ return ; case 'String': return ( - `"${raw}"`} /> + `"${raw}"`} + /> ); case 'Number': return ; @@ -97,7 +107,7 @@ const JSONNode = ({ JSONNode.propTypes = { getItemString: PropTypes.func.isRequired, keyPath: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired ).isRequired, labelRenderer: PropTypes.func.isRequired, styling: PropTypes.func.isRequired, diff --git a/packages/react-json-tree/src/JSONObjectNode.js b/packages/react-json-tree/src/JSONObjectNode.tsx similarity index 69% rename from packages/react-json-tree/src/JSONObjectNode.js rename to packages/react-json-tree/src/JSONObjectNode.tsx index 027715ef..6cfcbe06 100644 --- a/packages/react-json-tree/src/JSONObjectNode.js +++ b/packages/react-json-tree/src/JSONObjectNode.tsx @@ -1,16 +1,22 @@ import React from 'react'; import PropTypes from 'prop-types'; import JSONNestedNode from './JSONNestedNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; // Returns the "n Items" string for this node, // generating and caching it if it hasn't been created yet. -function createItemString(data) { +function createItemString(data: any) { const len = Object.getOwnPropertyNames(data).length; return `${len} ${len !== 1 ? 'keys' : 'key'}`; } +interface Props extends CircularPropsPassedThroughJSONNode { + data: any; + nodeType: string; +} + // Configures to render an Object -const JSONObjectNode = ({ data, ...props }) => ( +const JSONObjectNode: React.FunctionComponent = ({ data, ...props }) => ( ( JSONObjectNode.propTypes = { data: PropTypes.object, - nodeType: PropTypes.string, + nodeType: PropTypes.string.isRequired, }; export default JSONObjectNode; diff --git a/packages/react-json-tree/src/JSONValueNode.js b/packages/react-json-tree/src/JSONValueNode.tsx similarity index 69% rename from packages/react-json-tree/src/JSONValueNode.js rename to packages/react-json-tree/src/JSONValueNode.tsx index 40cd679e..c7754256 100644 --- a/packages/react-json-tree/src/JSONValueNode.js +++ b/packages/react-json-tree/src/JSONValueNode.tsx @@ -1,18 +1,25 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { JSONValueNodeCircularPropsProvidedByJSONNode } from './types'; /** * Renders simple values (eg. strings, numbers, booleans, etc) */ -const JSONValueNode = ({ +interface Props extends JSONValueNodeCircularPropsProvidedByJSONNode { + nodeType: string; + value: any; + valueGetter?: (value: any) => any; +} + +const JSONValueNode: React.FunctionComponent = ({ nodeType, styling, labelRenderer, keyPath, valueRenderer, value, - valueGetter, + valueGetter = (value) => value, }) => (