From 039d7e3addbbef9c63919e0e8c545e0d320dc71c Mon Sep 17 00:00:00 2001 From: Armand Abric Date: Sat, 2 Oct 2021 10:00:13 +0200 Subject: [PATCH 01/32] Just run flow-to-ts command --- .eslintrc.js | 20 +- .flowconfig | 18 - .prettierignore | 1 + .prettierrc | 2 +- index.d.ts | 7 +- package.json | 60 +- src/AnonymousStatelessComponent.js | 7 - src/AnonymousStatelessComponent.tsx | 7 + ...ilter.spec.js => createPropFilter.spec.ts} | 18 +- ...reatePropFilter.js => createPropFilter.ts} | 4 +- ....js => formatComplexDataStructure.spec.ts} | 71 +- ...cture.js => formatComplexDataStructure.ts} | 5 +- ...unction.spec.js => formatFunction.spec.ts} | 46 +- .../{formatFunction.js => formatFunction.ts} | 8 +- ...{formatProp.spec.js => formatProp.spec.ts} | 41 +- .../{formatProp.js => formatProp.ts} | 12 +- ...Value.spec.js => formatPropValue.spec.tsx} | 55 +- ...{formatPropValue.js => formatPropValue.ts} | 3 +- ...pec.js => formatReactElementNode.spec.tsx} | 69 +- ...ementNode.js => formatReactElementNode.ts} | 50 +- ...pec.js => formatReactFragmentNode.spec.ts} | 52 +- ...mentNode.js => formatReactFragmentNode.ts} | 13 +- ...{formatTree.spec.js => formatTree.spec.ts} | 7 - .../{formatTree.js => formatTree.ts} | 3 - ...reeNode.spec.js => formatTreeNode.spec.ts} | 70 +- .../{formatTreeNode.js => formatTreeNode.ts} | 7 +- ...SiblingPlainStringChildrenReducer.spec.ts} | 9 - ...mergeSiblingPlainStringChildrenReducer.ts} | 3 - ...{sortObject.spec.js => sortObject.spec.ts} | 58 +- .../{sortObject.js => sortObject.ts} | 2 +- src/formatter/sortPropsByNames.js | 26 - ...Names.spec.js => sortPropsByNames.spec.ts} | 6 - src/formatter/sortPropsByNames.ts | 21 + .../{spacer.spec.js => spacer.spec.ts} | 5 - src/formatter/{spacer.js => spacer.ts} | 2 - src/{index.spec.js => index.spec.tsx} | 593 ++-- src/{index.js => index.ts} | 4 - src/options.js | 17 - src/options.ts | 13 + ...ent.spec.js => parseReactElement.spec.tsx} | 34 +- ...seReactElement.js => parseReactElement.ts} | 39 +- src/{tree.spec.js => tree.spec.ts} | 27 +- src/{tree.js => tree.ts} | 58 +- tests/{setupTests.js => setupTests.ts} | 0 tests/smoke/{prepare.js => prepare.ts} | 43 +- tests/smoke/{run.js => run.ts} | 10 +- tests/smoke/{smoke.js => smoke.ts} | 20 +- tsconfig.eslint.json | 5 + tsconfig.json | 76 + tserrors.txt | 35 + yarn.lock | 2427 ++++++++++++++--- 51 files changed, 2825 insertions(+), 1364 deletions(-) delete mode 100644 .flowconfig delete mode 100644 src/AnonymousStatelessComponent.js create mode 100644 src/AnonymousStatelessComponent.tsx rename src/formatter/{createPropFilter.spec.js => createPropFilter.spec.ts} (82%) rename src/formatter/{createPropFilter.js => createPropFilter.ts} (77%) rename src/formatter/{formatComplexDataStructure.spec.js => formatComplexDataStructure.spec.ts} (81%) rename src/formatter/{formatComplexDataStructure.js => formatComplexDataStructure.ts} (97%) rename src/formatter/{formatFunction.spec.js => formatFunction.spec.ts} (64%) rename src/formatter/{formatFunction.js => formatFunction.ts} (81%) rename src/formatter/{formatProp.spec.js => formatProp.spec.ts} (98%) rename src/formatter/{formatProp.js => formatProp.ts} (92%) rename src/formatter/{formatPropValue.spec.js => formatPropValue.spec.tsx} (88%) rename src/formatter/{formatPropValue.js => formatPropValue.ts} (99%) rename src/formatter/{formatReactElementNode.spec.js => formatReactElementNode.spec.tsx} (84%) rename src/formatter/{formatReactElementNode.js => formatReactElementNode.ts} (85%) rename src/formatter/{formatReactFragmentNode.spec.js => formatReactFragmentNode.spec.ts} (87%) rename src/formatter/{formatReactFragmentNode.js => formatReactFragmentNode.ts} (96%) rename src/formatter/{formatTree.spec.js => formatTree.spec.ts} (96%) rename src/formatter/{formatTree.js => formatTree.ts} (94%) rename src/formatter/{formatTreeNode.spec.js => formatTreeNode.spec.ts} (53%) rename src/formatter/{formatTreeNode.js => formatTreeNode.ts} (94%) rename src/formatter/{mergeSiblingPlainStringChildrenReducer.spec.js => mergeSiblingPlainStringChildrenReducer.spec.ts} (99%) rename src/formatter/{mergeSiblingPlainStringChildrenReducer.js => mergeSiblingPlainStringChildrenReducer.ts} (98%) rename src/formatter/{sortObject.spec.js => sortObject.spec.ts} (53%) rename src/formatter/{sortObject.js => sortObject.ts} (98%) delete mode 100644 src/formatter/sortPropsByNames.js rename src/formatter/{sortPropsByNames.spec.js => sortPropsByNames.spec.ts} (97%) create mode 100644 src/formatter/sortPropsByNames.ts rename src/formatter/{spacer.spec.js => spacer.spec.ts} (96%) rename src/formatter/{spacer.js => spacer.ts} (92%) rename src/{index.spec.js => index.spec.tsx} (86%) rename src/{index.js => index.ts} (98%) delete mode 100644 src/options.js create mode 100644 src/options.ts rename src/parser/{parseReactElement.spec.js => parseReactElement.spec.tsx} (93%) rename src/parser/{parseReactElement.js => parseReactElement.ts} (86%) rename src/{tree.spec.js => tree.spec.ts} (80%) rename src/{tree.js => tree.ts} (59%) rename tests/{setupTests.js => setupTests.ts} (100%) rename tests/smoke/{prepare.js => prepare.ts} (58%) mode change 100755 => 100644 rename tests/smoke/{run.js => run.ts} (92%) mode change 100755 => 100644 rename tests/smoke/{smoke.js => smoke.ts} (78%) mode change 100755 => 100644 create mode 100644 tsconfig.eslint.json create mode 100644 tsconfig.json create mode 100644 tserrors.txt diff --git a/.eslintrc.js b/.eslintrc.js index 673ed1232..da06e7781 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,13 @@ module.exports = { - extends: ['algolia', 'algolia/jest', 'algolia/react'], + extends: ['airbnb-typescript', 'prettier'], + + parserOptions: { + project: './tsconfig.eslint.json', + }, + + // ecmaFeatures: { + // jsx: true, + // }, env: { es6: true, @@ -11,12 +19,12 @@ module.exports = { }, }, - rules: { - 'max-params': ['error', 10], - 'no-warning-comments': 'error', + // rules: { + // 'max-params': ['error', 10], + // 'no-warning-comments': 'error', - 'import/no-commonjs': 'off', - }, + // 'import/no-commonjs': 'off', + // }, overrides: [ { diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 55a8088cb..000000000 --- a/.flowconfig +++ /dev/null @@ -1,18 +0,0 @@ -[ignore] -/node_modules/.*/test/.* -/node_modules/.*.spec\.js -/node_modules/editions/es2015/index.js -/dist/.* -# FIXME: do not ignore local tests -/.*\.spec\.js - -[include] - -[libs] - -[options] -emoji=true -#experimental.const_params=true -munge_underscores=true - -[lints] diff --git a/.prettierignore b/.prettierignore index a253783fa..652634247 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ **/dist/**/* **/node_modules/**/* +src/**/*.js diff --git a/.prettierrc b/.prettierrc index e17e00276..af2e6996d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "parser": "flow", + "parser": "babel-ts", "singleQuote": true, "trailingComma": "es5", "overrides": [ diff --git a/index.d.ts b/index.d.ts index d6c28cd7c..f58e316ba 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ declare module 'react-element-to-jsx-string' { import { ReactNode } from 'react'; - type FilterPropsFunction = (value: any, key: string) => boolean + type FilterPropsFunction = (value: any, key: string) => boolean; interface ReactElementToJSXStringOptions { displayName?: (element: ReactNode) => string; @@ -16,7 +16,10 @@ declare module 'react-element-to-jsx-string' { useFragmentShortSyntax?: boolean; } - const reactElementToJSXString: (element: ReactNode, options?: ReactElementToJSXStringOptions) => string; + const reactElementToJSXString: ( + element: ReactNode, + options?: ReactElementToJSXStringOptions + ) => string; export { ReactElementToJSXStringOptions as Options }; diff --git a/package.json b/package.json index 45bd99328..0d0be8168 100644 --- a/package.json +++ b/package.json @@ -9,26 +9,15 @@ "types": "index.d.ts", "scripts": { "build": "rollup -c", - "build:flow": "flow-copy-source -v --ignore=*.spec.js src/ dist/cjs", "prebuild": "rm -rf dist/", - "postbuild": "npm run build:flow", - "prepare": "npm run build", - "lint": "eslint .", - "lint:fix": "npm run lint -- --fix", - "flow": "flow", - "precommit": "lint-staged", - "prepublishOnly": "npm run build", - "prettier:fix": "prettier --write \"**/*.{js,json}\"", + "lint": "eslint --ext ts --ext tsx src/", + "lint:fix": "yarn run lint -- --fix", + "prettier:fix": "prettier --write \"**/*.{ts,tsx,js}\"", "test": "jest", "test:watch": "jest --watch", "release": "./release.sh", - "smoke": "node tests/smoke/run" - }, - "lint-staged": { - "*.js": [ - "prettier --write \"**/*.{js,json}\"", - "git add" - ] + "smoke": "node tests/smoke/run", + "ts:progress": "tsc > tserrors.txt" }, "author": { "name": "Algolia, Inc.", @@ -47,18 +36,27 @@ "@testing-library/dom": "10.4.0", "@testing-library/jest-dom": "5.17.0", "@testing-library/react": "16.2.0", + "@khanacademy/flow-to-ts": "^0.5.2", + "@types/enzyme": "^3.10.9", + "@types/enzyme-adapter-react-16": "^1.0.6", + "@types/react": "^17.0.26", + "@types/react-is": "^17.0.2", "babel-eslint": "10.1.0", "babel-jest": "24.9.0", "babel-register": "6.26.0", "conventional-changelog-cli": "2.2.2", "doctoc": "1.4.0", - "eslint": "6.8.0", + "enzyme": "3.11.0", + "enzyme-adapter-react-16": "1.15.6", + "eslint": "7.25.0", + "eslint-config-airbnb-typescript": "12.3.1", "eslint-config-algolia": "14.0.1", - "eslint-config-prettier": "6.15.0", - "eslint-plugin-import": "2.29.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-import": "2.22.1", "eslint-plugin-jest": "22.21.0", - "eslint-plugin-prettier": "3.4.1", - "eslint-plugin-react": "7.31.1", + "eslint-plugin-jsx-a11y": "6.4.1", + "eslint-plugin-react": "7.23.2", + "eslint-plugin-react-hooks": "4.2.0", "esm": "3.2.25", "expect": "27.5.1", "flow-bin": "0.119.1", @@ -68,16 +66,17 @@ "json": "10.0.0", "lint-staged": "10.5.4", "mversion": "2.0.1", - "prettier": "1.19.1", - "react": "19.0.0", - "react-dom": "19.0.0", - "react-is": "19.0.0", - "rollup": "2.79.1", + "prettier": "2.4.1", + "react": "16.14.0", + "react-dom": "16.14.0", + "react-test-renderer": "16.14.0", + "rollup": "2.57.0", "rollup-plugin-babel": "4.4.0", "rollup-plugin-node-builtins": "2.1.2", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-node-resolve": "5.2.0", - "rollup-plugin-sourcemaps": "0.6.3" + "rollup-plugin-sourcemaps": "0.6.3", + "typescript": "4.2.4" }, "peerDependencies": { "react": "^19.0.0", @@ -85,12 +84,9 @@ "react-is": "^19.0.0" }, "dependencies": { - "@base2/pretty-print-object": "1.0.2", - "is-plain-object": "5.0.0" + "@base2/pretty-print-object": "1.0.2" }, "jest": { - "setupFilesAfterEnv": [ - "tests/setupTests.js" - ] + "setupFilesAfterEnv": ["tests/setupTests.js"] } } diff --git a/src/AnonymousStatelessComponent.js b/src/AnonymousStatelessComponent.js deleted file mode 100644 index 29b165cf0..000000000 --- a/src/AnonymousStatelessComponent.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -// eslint-disable-next-line react/display-name -export default function(props) { - const { children } = props; // eslint-disable-line react/prop-types - return
{children}
; -} diff --git a/src/AnonymousStatelessComponent.tsx b/src/AnonymousStatelessComponent.tsx new file mode 100644 index 000000000..72b5b3540 --- /dev/null +++ b/src/AnonymousStatelessComponent.tsx @@ -0,0 +1,7 @@ +import React from 'react'; // eslint-disable-next-line react/display-name + +export default function (props) { + const { children } = props; // eslint-disable-line react/prop-types + + return
{children}
; +} diff --git a/src/formatter/createPropFilter.spec.js b/src/formatter/createPropFilter.spec.ts similarity index 82% rename from src/formatter/createPropFilter.spec.js rename to src/formatter/createPropFilter.spec.ts index caf6790b7..278042451 100644 --- a/src/formatter/createPropFilter.spec.js +++ b/src/formatter/createPropFilter.spec.ts @@ -1,24 +1,30 @@ -/* @flow */ - import createPropFilter from './createPropFilter'; describe('createPropFilter', () => { it('should filter based on an array of keys', () => { - const props = { a: 1, b: 2, c: 3 }; - const filter = createPropFilter(props, ['b']); + const props = { + a: 1, + b: 2, + c: 3, + }; + const filter = createPropFilter(props, ['b']); const filteredPropKeys = Object.keys(props).filter(filter); expect(filteredPropKeys).toEqual(['a', 'c']); }); it('should filter based on a callback', () => { - const props = { a: 1, b: 2, c: 3 }; + const props = { + a: 1, + b: 2, + c: 3, + }; + const filter = createPropFilter( props, (val, key) => key !== 'b' && val < 3 ); - const filteredPropKeys = Object.keys(props).filter(filter); expect(filteredPropKeys).toEqual(['a']); diff --git a/src/formatter/createPropFilter.js b/src/formatter/createPropFilter.ts similarity index 77% rename from src/formatter/createPropFilter.js rename to src/formatter/createPropFilter.ts index a9a9dd26f..f00985045 100644 --- a/src/formatter/createPropFilter.js +++ b/src/formatter/createPropFilter.ts @@ -1,8 +1,6 @@ -/* @flow */ - export default function createPropFilter( props: {}, - filter: string[] | ((any, string) => boolean) + filter: string[] | ((propValue: any, key: string) => boolean) ) { if (Array.isArray(filter)) { return (key: string) => filter.indexOf(key) === -1; diff --git a/src/formatter/formatComplexDataStructure.spec.js b/src/formatter/formatComplexDataStructure.spec.ts similarity index 81% rename from src/formatter/formatComplexDataStructure.spec.js rename to src/formatter/formatComplexDataStructure.spec.ts index 81ff66f6f..69a2c03da 100644 --- a/src/formatter/formatComplexDataStructure.spec.js +++ b/src/formatter/formatComplexDataStructure.spec.ts @@ -1,32 +1,41 @@ -/* @flow */ - import React from 'react'; import formatComplexDataStructure from './formatComplexDataStructure'; -jest.mock('./formatReactElementNode.js', () => node => - `<${node.displayName} />` +jest.mock( + './formatReactElementNode', + () => (node) => `<${node.displayName} />` ); const createFakeReactElement = (tagName = 'Foo') => React.createElement(tagName, {}, null); -const options = { tabStop: 2 }; + +const options = { + tabStop: 2, +}; describe('formatComplexDataStructure', () => { it('should format an object', () => { - const fixture = { a: 1, b: { c: 'ccc' } }; - - expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual( - `{ + const fixture = { + a: 1, + b: { + c: 'ccc', + }, + }; + expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(`{ a: 1, b: { c: 'ccc' } - }` - ); + }`); }); it('should format inline an object', () => { - const fixture = { a: 1, b: { c: 'ccc' } }; + const fixture = { + a: 1, + b: { + c: 'ccc', + }, + }; expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual( "{a: 1, b: {c: 'ccc'}}" @@ -38,31 +47,33 @@ describe('formatComplexDataStructure', () => { }); it('should order the object keys', () => { - const fixture = { b: { d: 'ddd', c: 'ccc' }, a: 1 }; + const fixture = { + b: { + d: 'ddd', + c: 'ccc', + }, + a: 1, + }; - expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual( - `{ + expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(`{ a: 1, b: { c: 'ccc', d: 'ddd' } - }` - ); + }`); }); it('should format an array', () => { const fixture = [1, '2', true, false, null]; - expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual( - `[ + expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(`[ 1, '2', true, false, null - ]` - ); + ]`); }); it('should format inline an array ', () => { @@ -74,13 +85,13 @@ describe('formatComplexDataStructure', () => { }); it('should format an object that contains a react element', () => { - const fixture = { a: createFakeReactElement('BarBar') }; + const fixture = { + a: createFakeReactElement('BarBar'), + }; - expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual( - `{ + expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(`{ a: - }` - ); + }`); }); it('should format an empty array', () => { @@ -88,7 +99,9 @@ describe('formatComplexDataStructure', () => { }); it('should format an object that contains a date', () => { - const fixture = { a: new Date('2017-11-13T00:00:00.000Z') }; + const fixture = { + a: new Date('2017-11-13T00:00:00.000Z'), + }; expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual( `{a: new Date('2017-11-13T00:00:00.000Z')}` @@ -96,7 +109,9 @@ describe('formatComplexDataStructure', () => { }); it('should format an object that contains a regexp', () => { - const fixture = { a: /test/g }; + const fixture = { + a: /test/g, + }; expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual( `{a: /test/g}` diff --git a/src/formatter/formatComplexDataStructure.js b/src/formatter/formatComplexDataStructure.ts similarity index 97% rename from src/formatter/formatComplexDataStructure.js rename to src/formatter/formatComplexDataStructure.ts index 57abb6136..cd9fc9b4d 100644 --- a/src/formatter/formatComplexDataStructure.js +++ b/src/formatter/formatComplexDataStructure.ts @@ -1,5 +1,3 @@ -/* @flow */ - import { isValidElement } from 'react'; import { prettyPrint } from '@base2/pretty-print-object'; import sortObject from './sortObject'; @@ -10,13 +8,12 @@ import spacer from './spacer'; import type { Options } from './../options'; export default ( - value: Object | Array, + value: Record | Array, inline: boolean, lvl: number, options: Options ): string => { const normalizedValue = sortObject(value); - const stringifiedValue = prettyPrint(normalizedValue, { transform: (currentObj, prop, originalResult) => { const currentValue = currentObj[prop]; diff --git a/src/formatter/formatFunction.spec.js b/src/formatter/formatFunction.spec.ts similarity index 64% rename from src/formatter/formatFunction.spec.js rename to src/formatter/formatFunction.spec.ts index 8a199696b..76ae46e95 100644 --- a/src/formatter/formatFunction.spec.js +++ b/src/formatter/formatFunction.spec.ts @@ -1,9 +1,7 @@ -/* @flow */ - import formatFunction from './formatFunction'; - -jest.mock('./formatReactElementNode.js', () => node => - `<${node.displayName} />` +jest.mock( + './formatReactElementNode.js', + () => (node) => `<${node.displayName} />` ); function hello() { @@ -14,31 +12,34 @@ describe('formatFunction', () => { it('should replace a function with noRefCheck without showFunctions option', () => { expect(formatFunction(hello, {})).toEqual('function noRefCheck() {}'); }); - it('should replace a function with noRefCheck if showFunctions is false', () => { - expect(formatFunction(hello, { showFunctions: false })).toEqual( - 'function noRefCheck() {}' - ); + expect( + formatFunction(hello, { + showFunctions: false, + }) + ).toEqual('function noRefCheck() {}'); }); - it('should format a function if showFunctions is true', () => { - expect(formatFunction(hello, { showFunctions: true })).toEqual( - 'function hello() {return 1;}' - ); + expect( + formatFunction(hello, { + showFunctions: true, + }) + ).toEqual('function hello() {return 1;}'); }); - it('should format a function without name if showFunctions is true', () => { - expect(formatFunction(() => 1, { showFunctions: true })).toEqual( - 'function () {return 1;}' - ); + expect( + formatFunction(() => 1, { + showFunctions: true, + }) + ).toEqual('function () {return 1;}'); }); - it('should use the functionValue option', () => { - expect(formatFunction(hello, { functionValue: () => '' })).toEqual( - '' - ); + expect( + formatFunction(hello, { + functionValue: () => '', + }) + ).toEqual(''); }); - it('should use the functionValue option even if showFunctions is true', () => { expect( formatFunction(hello, { @@ -47,7 +48,6 @@ describe('formatFunction', () => { }) ).toEqual(''); }); - it('should use the functionValue option even if showFunctions is false', () => { expect( formatFunction(hello, { diff --git a/src/formatter/formatFunction.js b/src/formatter/formatFunction.ts similarity index 81% rename from src/formatter/formatFunction.js rename to src/formatter/formatFunction.ts index f8474436b..5309a798e 100644 --- a/src/formatter/formatFunction.js +++ b/src/formatter/formatFunction.ts @@ -6,15 +6,13 @@ export const inlineFunction = (fn: any): string => fn .toString() .split('\n') - .map(line => line.trim()) + .map((line) => line.trim()) .join(''); - export const preserveFunctionLineBreak = (fn: any): string => fn.toString(); - const defaultFunctionValue = inlineFunction; - -export default (fn: Function, options: Options): string => { +export default (fn: (...args: Array) => any, options: Options): string => { const { functionValue = defaultFunctionValue, showFunctions } = options; + if (!showFunctions && functionValue === defaultFunctionValue) { return functionValue(noRefCheck); } diff --git a/src/formatter/formatProp.spec.js b/src/formatter/formatProp.spec.ts similarity index 98% rename from src/formatter/formatProp.spec.js rename to src/formatter/formatProp.spec.ts index 700c8fa9b..9ff557f20 100644 --- a/src/formatter/formatProp.spec.js +++ b/src/formatter/formatProp.spec.ts @@ -1,24 +1,17 @@ -/* @flow */ - import formatProp from './formatProp'; import formatPropValue from './formatPropValue'; - jest.mock('./formatPropValue'); - const defaultOptions = { useBooleanShorthandSyntax: true, tabStop: 2, }; - describe('formatProp', () => { beforeEach(() => { jest.clearAllMocks(); jest.resetAllMocks(); }); - it('should format prop with only a value', () => { formatPropValue.mockReturnValue('"MockedPropValue"'); - expect( formatProp('foo', true, 'bar', false, null, true, 0, defaultOptions) ).toEqual({ @@ -27,7 +20,6 @@ describe('formatProp', () => { foo="MockedPropValue"`, isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith( 'bar', true, @@ -35,10 +27,8 @@ describe('formatProp', () => { defaultOptions ); }); - it('should format prop with only a default value', () => { formatPropValue.mockReturnValue('"MockedPropValue"'); - expect( formatProp('foo', false, null, true, 'baz', true, 0, defaultOptions) ).toEqual({ @@ -47,7 +37,6 @@ describe('formatProp', () => { foo="MockedPropValue"`, isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith( 'baz', true, @@ -55,10 +44,8 @@ describe('formatProp', () => { defaultOptions ); }); - it('should format prop with a value and a default value', () => { formatPropValue.mockReturnValue('"MockedPropValue"'); - expect( formatProp('foo', true, 'bar', true, 'baz', true, 0, defaultOptions) ).toEqual({ @@ -67,7 +54,6 @@ describe('formatProp', () => { foo="MockedPropValue"`, isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith( 'bar', true, @@ -75,15 +61,12 @@ describe('formatProp', () => { defaultOptions ); }); - it('should format a truthy boolean prop (with short syntax)', () => { const options = { useBooleanShorthandSyntax: true, tabStop: 2, }; - formatPropValue.mockReturnValue('{true}'); - expect( formatProp('foo', true, true, false, false, true, 0, options) ).toEqual({ @@ -92,18 +75,14 @@ describe('formatProp', () => { foo`, isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith(true, true, 0, options); }); - it('should ignore a falsy boolean prop (with short syntax)', () => { const options = { useBooleanShorthandSyntax: true, tabStop: 2, }; - formatPropValue.mockReturnValue('{false}'); - expect( formatProp('foo', true, false, false, null, true, 0, options) ).toEqual({ @@ -111,18 +90,14 @@ describe('formatProp', () => { attributeFormattedMultiline: '', isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith(false, true, 0, options); }); - it('should format a truthy boolean prop (with explicit syntax)', () => { const options = { useBooleanShorthandSyntax: false, tabStop: 2, }; - formatPropValue.mockReturnValue('{true}'); - expect( formatProp('foo', true, true, false, false, true, 0, options) ).toEqual({ @@ -131,18 +106,14 @@ describe('formatProp', () => { foo={true}`, isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith(true, true, 0, options); }); - it('should format a falsy boolean prop (with explicit syntax)', () => { const options = { useBooleanShorthandSyntax: false, tabStop: 2, }; - formatPropValue.mockReturnValue('{false}'); - expect( formatProp('foo', true, false, false, false, true, 0, options) ).toEqual({ @@ -151,16 +122,13 @@ describe('formatProp', () => { foo={false}`, isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith(false, true, 0, options); }); - it('should format a mulitline props', () => { formatPropValue.mockReturnValue(`{[ "a", "b" ]}`); - expect( formatProp( 'foo', @@ -184,7 +152,6 @@ describe('formatProp', () => { ]}`, isMultilineAttribute: true, }); - expect(formatPropValue).toHaveBeenCalledWith( ['a', 'b'], false, @@ -192,7 +159,6 @@ describe('formatProp', () => { defaultOptions ); }); - it('should indent the formatted string', () => { /* * lvl 4 and tabStop 2 : @@ -200,23 +166,20 @@ describe('formatProp', () => { * - One new indentation = 2 spaces * - Expected indentation : 10 spaces */ - const options = { useBooleanShorthandSyntax: true, tabStop: 2, }; - formatPropValue.mockReturnValue('"MockedPropValue"'); - expect( formatProp('foo', true, 'bar', false, null, true, 4, options) ).toEqual({ attributeFormattedInline: ' foo="MockedPropValue"', attributeFormattedMultiline: ` - foo="MockedPropValue"`, // 10 spaces + foo="MockedPropValue"`, + // 10 spaces isMultilineAttribute: false, }); - expect(formatPropValue).toHaveBeenCalledWith('bar', true, 4, options); }); }); diff --git a/src/formatter/formatProp.js b/src/formatter/formatProp.ts similarity index 92% rename from src/formatter/formatProp.js rename to src/formatter/formatProp.ts index 9fcac3c01..91ba2591f 100644 --- a/src/formatter/formatProp.js +++ b/src/formatter/formatProp.ts @@ -1,9 +1,6 @@ -/* @flow */ - import spacer from './spacer'; import formatPropValue from './formatPropValue'; import type { Options } from './../options'; - export default ( name: string, hasValue: boolean, @@ -14,9 +11,9 @@ export default ( lvl: number, options: Options ): { - attributeFormattedInline: string, - attributeFormattedMultiline: string, - isMultilineAttribute: boolean, + attributeFormattedInline: string; + attributeFormattedMultiline: string; + isMultilineAttribute: boolean; } => { if (!hasValue && !hasDefaultValue) { throw new Error( @@ -25,11 +22,8 @@ export default ( } const usedValue = hasValue ? value : defaultValue; - const { useBooleanShorthandSyntax, tabStop } = options; - const formattedPropValue = formatPropValue(usedValue, inline, lvl, options); - let attributeFormattedInline = ' '; let attributeFormattedMultiline = `\n${spacer(lvl + 1, tabStop)}`; const isMultilineAttribute = formattedPropValue.includes('\n'); diff --git a/src/formatter/formatPropValue.spec.js b/src/formatter/formatPropValue.spec.tsx similarity index 88% rename from src/formatter/formatPropValue.spec.js rename to src/formatter/formatPropValue.spec.tsx index 8d0a0eeb4..c457c94dc 100644 --- a/src/formatter/formatPropValue.spec.js +++ b/src/formatter/formatPropValue.spec.tsx @@ -1,11 +1,8 @@ -/* @flow */ - import React from 'react'; import formatPropValue from './formatPropValue'; import parseReactElement from './../parser/parseReactElement'; import formatTreeNode from './formatTreeNode'; import formatComplexDataStructure from './formatComplexDataStructure'; - jest.mock('./../parser/parseReactElement'); jest.mock('./formatTreeNode', () => jest.fn().mockReturnValue('') @@ -13,53 +10,46 @@ jest.mock('./formatTreeNode', () => jest.mock('./formatComplexDataStructure', () => jest.fn().mockReturnValue('*Mocked formatComplexDataStructure result*') ); - describe('formatPropValue', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('should format an integer prop value', () => { expect(formatPropValue(42, false, 0, {})).toBe('{42}'); }); - it('should escape double quote on prop value of string type', () => { expect(formatPropValue('Hello "Jonh"!', false, 0, {})).toBe( '"Hello "Jonh"!"' ); }); - it('should format a symbol prop value', () => { expect(formatPropValue(Symbol('Foo'), false, 0, {})).toBe( "{Symbol('Foo')}" ); - // eslint-disable-next-line symbol-description expect(formatPropValue(Symbol(), false, 0, {})).toBe('{Symbol()}'); }); - it('should replace a function prop value by a an empty generic function by default', () => { - const doThings = a => a * 2; + const doThings = (a) => a * 2; expect(formatPropValue(doThings, false, 0, {})).toBe( '{function noRefCheck() {}}' ); }); - it('should show the function prop value implementation if "showFunctions" option is true', () => { - const doThings = a => a * 2; + const doThings = (a) => a * 2; - expect(formatPropValue(doThings, false, 0, { showFunctions: true })).toBe( - '{function doThings(a) {return a * 2;}}' - ); + expect( + formatPropValue(doThings, false, 0, { + showFunctions: true, + }) + ).toBe('{function doThings(a) {return a * 2;}}'); }); - it('should format the function prop value with the "functionValue" option', () => { - const doThings = a => a * 2; + const doThings = (a) => a * 2; - const functionValue = fn => { + const functionValue = (fn) => { expect(fn).toBe(doThings); - return 'function Myfunction() {}'; }; @@ -69,7 +59,6 @@ describe('formatPropValue', () => { showFunctions: true, }) ).toBe('{function Myfunction() {}}'); - expect( formatPropValue(doThings, false, 0, { functionValue, @@ -77,62 +66,56 @@ describe('formatPropValue', () => { }) ).toBe('{function Myfunction() {}}'); }); - it('should parse and format a react element prop value', () => { expect(formatPropValue(
, false, 0, {})).toBe( '{}' ); - expect(parseReactElement).toHaveBeenCalledTimes(1); expect(formatTreeNode).toHaveBeenCalledTimes(1); }); - it('should format a date prop value', () => { expect( formatPropValue(new Date('2017-01-01T11:00:00.000Z'), false, 0, {}) ).toBe('{new Date("2017-01-01T11:00:00.000Z")}'); }); - it('should format an invalid date prop value', () => { expect(formatPropValue(new Date(NaN), false, 0, {})).toBe( '{new Date(NaN)}' ); }); - it('should format an object prop value', () => { - expect(formatPropValue({ foo: 42 }, false, 0, {})).toBe( - '{*Mocked formatComplexDataStructure result*}' - ); - + expect( + formatPropValue( + { + foo: 42, + }, + false, + 0, + {} + ) + ).toBe('{*Mocked formatComplexDataStructure result*}'); expect(formatComplexDataStructure).toHaveBeenCalledTimes(1); }); - it('should format an array prop value', () => { expect(formatPropValue(['a', 'b', 'c'], false, 0, {})).toBe( '{*Mocked formatComplexDataStructure result*}' ); - expect(formatComplexDataStructure).toHaveBeenCalledTimes(1); }); - it('should format a boolean prop value', () => { expect(formatPropValue(true, false, 0, {})).toBe('{true}'); expect(formatPropValue(false, false, 0, {})).toBe('{false}'); }); - it('should format null prop value', () => { expect(formatPropValue(null, false, 0, {})).toBe('{null}'); }); - it('should format undefined prop value', () => { expect(formatPropValue(undefined, false, 0, {})).toBe('{undefined}'); }); - it('should call the ".toString()" method on object instance prop value', () => { expect(formatPropValue(new Set(['a', 'b', 42]), false, 0, {})).toBe( '{[object Set]}' ); - expect(formatPropValue(new Map(), false, 0, {})).toBe('{[object Map]}'); }); }); diff --git a/src/formatter/formatPropValue.js b/src/formatter/formatPropValue.ts similarity index 99% rename from src/formatter/formatPropValue.js rename to src/formatter/formatPropValue.ts index 5170c3721..f6b8be1b9 100644 --- a/src/formatter/formatPropValue.js +++ b/src/formatter/formatPropValue.ts @@ -1,5 +1,3 @@ -/* @flow */ - import { isPlainObject } from 'is-plain-object'; import { isValidElement } from 'react'; import formatComplexDataStructure from './formatComplexDataStructure'; @@ -57,6 +55,7 @@ const formatPropValue = ( if (isNaN(propValue.valueOf())) { return `{new Date(NaN)}`; } + return `{new Date("${propValue.toISOString()}")}`; } diff --git a/src/formatter/formatReactElementNode.spec.js b/src/formatter/formatReactElementNode.spec.tsx similarity index 84% rename from src/formatter/formatReactElementNode.spec.js rename to src/formatter/formatReactElementNode.spec.tsx index b4475457c..39d641fbf 100644 --- a/src/formatter/formatReactElementNode.spec.js +++ b/src/formatter/formatReactElementNode.spec.tsx @@ -1,8 +1,5 @@ -/* @flow */ - import React from 'react'; import formatReactElementNode from './formatReactElementNode'; - const defaultOptions = { filterProps: [], showDefaultProps: true, @@ -11,7 +8,6 @@ const defaultOptions = { useBooleanShorthandSyntax: true, sortProps: true, }; - describe('formatReactElementNode', () => { it('should format a react element with a string a children', () => { const tree = { @@ -26,14 +22,10 @@ describe('formatReactElementNode', () => { }, ], }; - - expect(formatReactElementNode(tree, false, 0, defaultOptions)).toEqual( - `

+ expect(formatReactElementNode(tree, false, 0, defaultOptions)).toEqual(`

Hello world -

` - ); +`); }); - it('should format a single depth react element', () => { const tree = { type: 'ReactElement', @@ -46,37 +38,41 @@ describe('formatReactElementNode', () => { }, childrens: [], }; - expect(formatReactElementNode(tree, false, 0, defaultOptions)).toEqual( '' ); }); - it('should format a react element with an object as props', () => { const tree = { type: 'ReactElement', displayName: 'div', defaultProps: { - a: { aa: '1', bb: { cc: '3' } }, + a: { + aa: '1', + bb: { + cc: '3', + }, + }, }, props: { - a: { aa: '1', bb: { cc: '3' } }, + a: { + aa: '1', + bb: { + cc: '3', + }, + }, }, childrens: [], }; - - expect(formatReactElementNode(tree, false, 0, defaultOptions)).toEqual( - `
` - ); + />`); }); - it('should format a react element with another react element as props', () => { const tree = { type: 'ReactElement', @@ -89,12 +85,10 @@ describe('formatReactElementNode', () => { }, childrens: [], }; - expect(formatReactElementNode(tree, false, 0, defaultOptions)).toEqual( '
} />' ); }); - it('should format a react element with multiline children', () => { const tree = { type: 'ReactElement', @@ -108,30 +102,28 @@ describe('formatReactElementNode', () => { }, ], }; - - expect(formatReactElementNode(tree, false, 0, defaultOptions)).toEqual( - `
+ expect(formatReactElementNode(tree, false, 0, defaultOptions)) + .toEqual(`
first line second line third line -
` - ); - - expect(formatReactElementNode(tree, false, 2, defaultOptions)).toEqual( - `
+
`); + expect(formatReactElementNode(tree, false, 2, defaultOptions)) + .toEqual(`
first line second line third line -
` - ); +
`); }); - it('should allow filtering props by function', () => { const tree = { type: 'ReactElement', displayName: 'h1', defaultProps: {}, - props: { className: 'myClass', onClick: () => {} }, + props: { + className: 'myClass', + onClick: () => {}, + }, childrens: [ { value: 'Hello world', @@ -139,16 +131,13 @@ describe('formatReactElementNode', () => { }, ], }; - const options = { ...defaultOptions, filterProps: (val, key) => !key.startsWith('on'), }; - - expect(formatReactElementNode(tree, false, 0, options)).toEqual( - `

+ expect(formatReactElementNode(tree, false, 0, options)) + .toEqual(`

Hello world -

` - ); +`); }); }); diff --git a/src/formatter/formatReactElementNode.js b/src/formatter/formatReactElementNode.ts similarity index 85% rename from src/formatter/formatReactElementNode.js rename to src/formatter/formatReactElementNode.ts index 4e2d5820c..9912a62ba 100644 --- a/src/formatter/formatReactElementNode.js +++ b/src/formatter/formatReactElementNode.ts @@ -1,5 +1,3 @@ -/* @flow */ - import spacer from './spacer'; import formatTreeNode from './formatTreeNode'; import formatProp from './formatProp'; @@ -34,20 +32,17 @@ const compensateMultilineStringElementIndentation = ( return formattedElement; }; -const formatOneChildren = ( - inline: boolean, - lvl: number, - options: Options -) => element => - compensateMultilineStringElementIndentation( - element, - formatTreeNode(element, inline, lvl, options), - inline, - lvl, - options - ); +const formatOneChildren = + (inline: boolean, lvl: number, options: Options) => (element) => + compensateMultilineStringElementIndentation( + element, + formatTreeNode(element, inline, lvl, options), + inline, + lvl, + options + ); -const onlyPropsWithOriginalValue = (defaultProps, props) => propName => { +const onlyPropsWithOriginalValue = (defaultProps, props) => (propName) => { const haveDefaultValue = Object.keys(defaultProps).includes(propName); return ( !haveDefaultValue || @@ -60,7 +55,7 @@ const isInlineAttributeTooLong = ( inlineAttributeString: string, lvl: number, tabStop: number, - maxInlineAttributesLineLength: ?number + maxInlineAttributesLineLength: number | null | undefined ): boolean => { if (!maxInlineAttributesLineLength) { return attributes.length > 1; @@ -79,7 +74,7 @@ const shouldRenderMultilineAttr = ( inline: boolean, lvl: number, tabStop: number, - maxInlineAttributesLineLength: ?number + maxInlineAttributesLineLength: number | null | undefined ): boolean => (isInlineAttributeTooLong( attributes, @@ -118,31 +113,25 @@ export default ( sortProps, tabStop, } = options; - let out = `<${displayName}`; - let outInlineAttr = out; let outMultilineAttr = out; let containsMultilineAttr = false; - const visibleAttributeNames = []; - const propFilter = createPropFilter(props, filterProps); - Object.keys(props) .filter(propFilter) .filter(onlyPropsWithOriginalValue(defaultProps, props)) - .forEach(propName => visibleAttributeNames.push(propName)); - + .forEach((propName) => visibleAttributeNames.push(propName)); Object.keys(defaultProps) .filter(propFilter) .filter(() => showDefaultProps) - .filter(defaultPropName => !visibleAttributeNames.includes(defaultPropName)) - .forEach(defaultPropName => visibleAttributeNames.push(defaultPropName)); - + .filter( + (defaultPropName) => !visibleAttributeNames.includes(defaultPropName) + ) + .forEach((defaultPropName) => visibleAttributeNames.push(defaultPropName)); const attributes = sortPropsByNames(sortProps)(visibleAttributeNames); - - attributes.forEach(attributeName => { + attributes.forEach((attributeName) => { const { attributeFormattedInline, attributeFormattedMultiline, @@ -165,7 +154,6 @@ export default ( outInlineAttr += attributeFormattedInline; outMultilineAttr += attributeFormattedMultiline; }); - outMultilineAttr += `\n${spacer(lvl, tabStop)}`; if ( @@ -186,7 +174,6 @@ export default ( if (childrens && childrens.length > 0) { const newLvl = lvl + 1; - out += '>'; if (!inline) { @@ -203,6 +190,7 @@ export default ( out += '\n'; out += spacer(newLvl - 1, tabStop); } + out += ``; } else { if ( diff --git a/src/formatter/formatReactFragmentNode.spec.js b/src/formatter/formatReactFragmentNode.spec.ts similarity index 87% rename from src/formatter/formatReactFragmentNode.spec.js rename to src/formatter/formatReactFragmentNode.spec.ts index 14c9386a8..8d31a1f7f 100644 --- a/src/formatter/formatReactFragmentNode.spec.js +++ b/src/formatter/formatReactFragmentNode.spec.ts @@ -1,7 +1,4 @@ -/* @flow */ - import formatReactFragmentNode from './formatReactFragmentNode'; - const defaultOptions = { filterProps: [], showDefaultProps: true, @@ -11,7 +8,6 @@ const defaultOptions = { useFragmentShortSyntax: true, sortProps: true, }; - describe('formatReactFragmentNode', () => { it('should format a react fragment with a string as children', () => { const tree = { @@ -23,14 +19,10 @@ describe('formatReactFragmentNode', () => { }, ], }; - - expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( - `<> + expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual(`<> Hello world -` - ); +`); }); - it('should format a react fragment with a key', () => { const tree = { type: 'ReactFragment', @@ -42,14 +34,11 @@ describe('formatReactFragmentNode', () => { }, ], }; - - expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( - ` + expect(formatReactFragmentNode(tree, false, 0, defaultOptions)) + .toEqual(` Hello world -` - ); +`); }); - it('should format a react fragment with multiple childrens', () => { const tree = { type: 'ReactFragment', @@ -57,49 +46,45 @@ describe('formatReactFragmentNode', () => { { type: 'ReactElement', displayName: 'div', - props: { a: 'foo' }, + props: { + a: 'foo', + }, childrens: [], }, { type: 'ReactElement', displayName: 'div', - props: { b: 'bar' }, + props: { + b: 'bar', + }, childrens: [], }, ], }; - - expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( - `<> + expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual(`<>
-` - ); +`); }); - it('should format an empty react fragment', () => { const tree = { type: 'ReactFragment', childrens: [], }; - expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( '' ); }); - it('should format an empty react fragment with key', () => { const tree = { type: 'ReactFragment', key: 'foo', childrens: [], }; - expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( '' ); }); - it('should format a react fragment using the explicit syntax', () => { const tree = { type: 'ReactFragment', @@ -110,16 +95,15 @@ describe('formatReactFragmentNode', () => { }, ], }; - expect( formatReactFragmentNode(tree, false, 0, { ...defaultOptions, - ...{ useFragmentShortSyntax: false }, + ...{ + useFragmentShortSyntax: false, + }, }) - ).toEqual( - ` + ).toEqual(` Hello world -` - ); +`); }); }); diff --git a/src/formatter/formatReactFragmentNode.js b/src/formatter/formatReactFragmentNode.ts similarity index 96% rename from src/formatter/formatReactFragmentNode.js rename to src/formatter/formatReactFragmentNode.ts index d6eb06c9d..8b743c1ac 100644 --- a/src/formatter/formatReactFragmentNode.js +++ b/src/formatter/formatReactFragmentNode.ts @@ -1,5 +1,3 @@ -/* @flow */ - import type { Key } from 'react'; import formatReactElementNode from './formatReactElementNode'; import type { Options } from './../options'; @@ -8,18 +6,20 @@ import type { ReactFragmentTreeNode, TreeNode, } from './../tree'; - const REACT_FRAGMENT_TAG_NAME_SHORT_SYNTAX = ''; const REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX = 'React.Fragment'; const toReactElementTreeNode = ( displayName: string, - key: ?Key, + key: Key | null | undefined, childrens: TreeNode[] ): ReactElementTreeNode => { let props = {}; + if (key) { - props = { key }; + props = { + key, + }; } return { @@ -32,6 +32,7 @@ const toReactElementTreeNode = ( }; const isKeyedFragment = ({ key }: ReactFragmentTreeNode) => Boolean(key); + const hasNoChildren = ({ childrens }: ReactFragmentTreeNode) => childrens.length === 0; @@ -50,8 +51,8 @@ export default ( } const { useFragmentShortSyntax } = options; - let displayName; + if (useFragmentShortSyntax) { if (hasNoChildren(node) || isKeyedFragment(node)) { displayName = REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX; diff --git a/src/formatter/formatTree.spec.js b/src/formatter/formatTree.spec.ts similarity index 96% rename from src/formatter/formatTree.spec.js rename to src/formatter/formatTree.spec.ts index f4f5fafd3..228c19ae7 100644 --- a/src/formatter/formatTree.spec.js +++ b/src/formatter/formatTree.spec.ts @@ -1,19 +1,12 @@ -/* @flow */ - import formatTree from './formatTree'; import formatTreeNode from './formatTreeNode'; - jest.mock('./formatTreeNode', () => jest.fn(() => '')); - describe('formatTree', () => { it('should format the node as a root node', () => { const tree = {}; const options = {}; - const result = formatTree(tree, options); - expect(formatTreeNode).toHaveBeenCalledWith(tree, false, 0, options); - expect(result).toBe(''); }); }); diff --git a/src/formatter/formatTree.js b/src/formatter/formatTree.ts similarity index 94% rename from src/formatter/formatTree.js rename to src/formatter/formatTree.ts index 7bc4f4573..d9842656f 100644 --- a/src/formatter/formatTree.js +++ b/src/formatter/formatTree.ts @@ -1,8 +1,5 @@ -/* @flow */ - import formatTreeNode from './formatTreeNode'; import type { Options } from './../options'; import type { TreeNode } from './../tree'; - export default (node: TreeNode, options: Options): string => formatTreeNode(node, false, 0, options); diff --git a/src/formatter/formatTreeNode.spec.js b/src/formatter/formatTreeNode.spec.ts similarity index 53% rename from src/formatter/formatTreeNode.spec.js rename to src/formatter/formatTreeNode.spec.ts index a3d172e51..5ffad4b07 100644 --- a/src/formatter/formatTreeNode.spec.js +++ b/src/formatter/formatTreeNode.spec.ts @@ -1,24 +1,35 @@ -/* @flow */ - import formatTreeNode from './formatTreeNode'; - -jest.mock('./formatReactElementNode', () => () => - '' +jest.mock( + './formatReactElementNode', + () => () => '' ); - describe('formatTreeNode', () => { it('should format number tree node', () => { - expect(formatTreeNode({ type: 'number', value: 42 }, true, 0, {})).toBe( - '42' - ); + expect( + formatTreeNode( + { + type: 'number', + value: 42, + }, + true, + 0, + {} + ) + ).toBe('42'); }); - it('should format string tree node', () => { - expect(formatTreeNode({ type: 'string', value: 'foo' }, true, 0, {})).toBe( - 'foo' - ); + expect( + formatTreeNode( + { + type: 'string', + value: 'foo', + }, + true, + 0, + {} + ) + ).toBe('foo'); }); - it('should format react element tree node', () => { expect( formatTreeNode( @@ -32,13 +43,15 @@ describe('formatTreeNode', () => { ) ).toBe(''); }); - const jsxDelimiters = ['<', '>', '{', '}']; - jsxDelimiters.forEach(char => { + jsxDelimiters.forEach((char) => { it(`should escape string that contains the JSX delimiter "${char}"`, () => { expect( formatTreeNode( - { type: 'string', value: `I contain ${char}, is will be escaped` }, + { + type: 'string', + value: `I contain ${char}, is will be escaped`, + }, true, 0, {} @@ -46,17 +59,30 @@ describe('formatTreeNode', () => { ).toBe(`{\`I contain ${char}, is will be escaped\`}`); }); }); - it('should preserve the format of string', () => { - expect(formatTreeNode({ type: 'string', value: 'foo\nbar' }, true, 0, {})) - .toBe(`foo + expect( + formatTreeNode( + { + type: 'string', + value: 'foo\nbar', + }, + true, + 0, + {} + ) + ).toBe(`foo bar`); - expect( formatTreeNode( { type: 'string', - value: JSON.stringify({ foo: 'bar' }, null, 2), + value: JSON.stringify( + { + foo: 'bar', + }, + null, + 2 + ), }, false, 0, diff --git a/src/formatter/formatTreeNode.js b/src/formatter/formatTreeNode.ts similarity index 94% rename from src/formatter/formatTreeNode.js rename to src/formatter/formatTreeNode.ts index 0d5ea3429..718251d91 100644 --- a/src/formatter/formatTreeNode.js +++ b/src/formatter/formatTreeNode.ts @@ -1,13 +1,11 @@ -/* @flow */ - import formatReactElementNode from './formatReactElementNode'; import formatReactFragmentNode from './formatReactFragmentNode'; import type { Options } from './../options'; import type { TreeNode } from './../tree'; - const jsxStopChars = ['<', '>', '{', '}']; + const shouldBeEscaped = (s: string) => - jsxStopChars.some(jsxStopChar => s.includes(jsxStopChar)); + jsxStopChars.some((jsxStopChar) => s.includes(jsxStopChar)); const escape = (s: string) => { if (!shouldBeEscaped(s)) { @@ -19,6 +17,7 @@ const escape = (s: string) => { const preserveTrailingSpace = (s: string) => { let result = s; + if (result.endsWith(' ')) { result = result.replace(/^(.*?)(\s+)$/, "$1{'$2'}"); } diff --git a/src/formatter/mergeSiblingPlainStringChildrenReducer.spec.js b/src/formatter/mergeSiblingPlainStringChildrenReducer.spec.ts similarity index 99% rename from src/formatter/mergeSiblingPlainStringChildrenReducer.spec.js rename to src/formatter/mergeSiblingPlainStringChildrenReducer.spec.ts index b8bbf6a2b..ee9a0a1fa 100644 --- a/src/formatter/mergeSiblingPlainStringChildrenReducer.spec.js +++ b/src/formatter/mergeSiblingPlainStringChildrenReducer.spec.ts @@ -1,5 +1,3 @@ -/* @flow */ - import mergeSiblingPlainStringChildrenReducer from './mergeSiblingPlainStringChildrenReducer'; import { createNumberTreeNode, @@ -7,14 +5,12 @@ import { createReactElementTreeNode, } from './../tree'; import type { TreeNode } from './../tree'; - test('mergeSiblingPlainStringChildrenReducer should merge sibling string tree nodes', () => { const childrens: TreeNode[] = [ createStringTreeNode('a'), createStringTreeNode('b'), createStringTreeNode('c'), ]; - expect(childrens.reduce(mergeSiblingPlainStringChildrenReducer, [])).toEqual([ { type: 'string', @@ -22,7 +18,6 @@ test('mergeSiblingPlainStringChildrenReducer should merge sibling string tree no }, ]); }); - test('mergeSiblingPlainStringChildrenReducer should consider number as string', () => { expect( [ @@ -36,7 +31,6 @@ test('mergeSiblingPlainStringChildrenReducer should consider number as string', value: 'a51c', }, ]); - expect( [ createStringTreeNode(5), @@ -50,7 +44,6 @@ test('mergeSiblingPlainStringChildrenReducer should consider number as string', }, ]); }); - test('mergeSiblingPlainStringChildrenReducer should detect non string node', () => { const childrens: TreeNode[] = [ createReactElementTreeNode('MyFoo', {}, {}, ['foo']), @@ -61,7 +54,6 @@ test('mergeSiblingPlainStringChildrenReducer should detect non string node', () createNumberTreeNode(42), createReactElementTreeNode('MyBaz', {}, {}, ['baz']), ]; - expect(childrens.reduce(mergeSiblingPlainStringChildrenReducer, [])).toEqual([ { type: 'ReactElement', @@ -94,7 +86,6 @@ test('mergeSiblingPlainStringChildrenReducer should detect non string node', () }, ]); }); - test('mergeSiblingPlainStringChildrenReducer should reduce empty array to an empty array', () => { expect([].reduce(mergeSiblingPlainStringChildrenReducer, [])).toEqual([]); }); diff --git a/src/formatter/mergeSiblingPlainStringChildrenReducer.js b/src/formatter/mergeSiblingPlainStringChildrenReducer.ts similarity index 98% rename from src/formatter/mergeSiblingPlainStringChildrenReducer.js rename to src/formatter/mergeSiblingPlainStringChildrenReducer.ts index 8752f5c8e..9051de591 100644 --- a/src/formatter/mergeSiblingPlainStringChildrenReducer.js +++ b/src/formatter/mergeSiblingPlainStringChildrenReducer.ts @@ -1,8 +1,5 @@ -/* @flow */ - import { createStringTreeNode } from './../tree'; import type { TreeNode } from './../tree'; - export default ( previousNodes: TreeNode[], currentNode: TreeNode diff --git a/src/formatter/sortObject.spec.js b/src/formatter/sortObject.spec.ts similarity index 53% rename from src/formatter/sortObject.spec.js rename to src/formatter/sortObject.spec.ts index 1b6ab3d45..6af956ab5 100644 --- a/src/formatter/sortObject.spec.js +++ b/src/formatter/sortObject.spec.ts @@ -1,32 +1,63 @@ -/* @flow */ - import sortObject from './sortObject'; - describe('sortObject', () => { it('should sort keys in objects', () => { const fixture = { c: 2, - b: { x: 1, c: 'ccc' }, - a: [{ foo: 1, bar: 2 }], + b: { + x: 1, + c: 'ccc', + }, + a: [ + { + foo: 1, + bar: 2, + }, + ], }; - expect(JSON.stringify(sortObject(fixture))).toEqual( JSON.stringify({ - a: [{ bar: 2, foo: 1 }], - b: { c: 'ccc', x: 1 }, + a: [ + { + bar: 2, + foo: 1, + }, + ], + b: { + c: 'ccc', + x: 1, + }, c: 2, }) ); }); - it('should process an array', () => { - const fixture = [{ foo: 1, bar: 2 }, null, { b: 1, c: 2, a: 3 }]; - + const fixture = [ + { + foo: 1, + bar: 2, + }, + null, + { + b: 1, + c: 2, + a: 3, + }, + ]; expect(JSON.stringify(sortObject(fixture))).toEqual( - JSON.stringify([{ bar: 2, foo: 1 }, null, { a: 3, b: 1, c: 2 }]) + JSON.stringify([ + { + bar: 2, + foo: 1, + }, + null, + { + a: 3, + b: 1, + c: 2, + }, + ]) ); }); - it('should not break special values', () => { const date = new Date(); const regexp = /test/g; @@ -35,7 +66,6 @@ describe('sortObject', () => { b: regexp, c: date, }; - expect(sortObject(fixture)).toEqual({ a: [date, regexp], b: regexp, diff --git a/src/formatter/sortObject.js b/src/formatter/sortObject.ts similarity index 98% rename from src/formatter/sortObject.js rename to src/formatter/sortObject.ts index c070ef612..a4a81f1a7 100644 --- a/src/formatter/sortObject.js +++ b/src/formatter/sortObject.ts @@ -1,4 +1,3 @@ -/* @flow */ import * as React from 'react'; function safeSortObject(value: any, seen: WeakSet): any { @@ -37,6 +36,7 @@ function safeSortObject(value: any, seen: WeakSet): any { // eslint-disable-next-line no-param-reassign result[key] = safeSortObject(value[key], seen); } + return result; }, {}); } diff --git a/src/formatter/sortPropsByNames.js b/src/formatter/sortPropsByNames.js deleted file mode 100644 index 649fd73bf..000000000 --- a/src/formatter/sortPropsByNames.js +++ /dev/null @@ -1,26 +0,0 @@ -/* @flow */ - -const isKeyOrRefProps = (propName: string) => ['key', 'ref'].includes(propName); - -export default (shouldSortUserProps: boolean) => ( - props: string[] -): string[] => { - const haveKeyProp = props.includes('key'); - const haveRefProp = props.includes('ref'); - - const userPropsOnly = props.filter(oneProp => !isKeyOrRefProps(oneProp)); - - const sortedProps = shouldSortUserProps - ? [...userPropsOnly.sort()] // We use basic lexical order - : [...userPropsOnly]; - - if (haveRefProp) { - sortedProps.unshift('ref'); - } - - if (haveKeyProp) { - sortedProps.unshift('key'); - } - - return sortedProps; -}; diff --git a/src/formatter/sortPropsByNames.spec.js b/src/formatter/sortPropsByNames.spec.ts similarity index 97% rename from src/formatter/sortPropsByNames.spec.js rename to src/formatter/sortPropsByNames.spec.ts index f77144be2..58f78f070 100644 --- a/src/formatter/sortPropsByNames.spec.js +++ b/src/formatter/sortPropsByNames.spec.ts @@ -1,10 +1,6 @@ -/* @flow */ - import sortPropsByNames from './sortPropsByNames'; - test('sortPropsByNames should always move the `key` and `ref` keys first', () => { const fixtures = ['c', 'key', 'a', 'ref', 'b']; - expect(sortPropsByNames(false)(fixtures)).toEqual([ 'key', 'ref', @@ -13,10 +9,8 @@ test('sortPropsByNames should always move the `key` and `ref` keys first', () => 'b', ]); }); - test('sortPropsByNames should always sort the props and keep `key` and `ref` keys first', () => { const fixtures = ['c', 'key', 'a', 'ref', 'b']; - expect(sortPropsByNames(true)(fixtures)).toEqual([ 'key', 'ref', diff --git a/src/formatter/sortPropsByNames.ts b/src/formatter/sortPropsByNames.ts new file mode 100644 index 000000000..c42f3dc1d --- /dev/null +++ b/src/formatter/sortPropsByNames.ts @@ -0,0 +1,21 @@ +const isKeyOrRefProps = (propName: string) => ['key', 'ref'].includes(propName); + +export default (shouldSortUserProps: boolean) => + (props: string[]): string[] => { + const haveKeyProp = props.includes('key'); + const haveRefProp = props.includes('ref'); + const userPropsOnly = props.filter((oneProp) => !isKeyOrRefProps(oneProp)); + const sortedProps = shouldSortUserProps + ? [...userPropsOnly.sort()] // We use basic lexical order + : [...userPropsOnly]; + + if (haveRefProp) { + sortedProps.unshift('ref'); + } + + if (haveKeyProp) { + sortedProps.unshift('key'); + } + + return sortedProps; + }; diff --git a/src/formatter/spacer.spec.js b/src/formatter/spacer.spec.ts similarity index 96% rename from src/formatter/spacer.spec.js rename to src/formatter/spacer.spec.ts index dc4552ab9..ae91b0896 100644 --- a/src/formatter/spacer.spec.js +++ b/src/formatter/spacer.spec.ts @@ -1,17 +1,12 @@ -/* @flow */ - import spacer from './spacer'; - describe('spacer', () => { it('should generate a spaced string', () => { expect(spacer(0, 1)).toEqual(''); expect(spacer(0, 2)).toEqual(''); expect(spacer(0, 3)).toEqual(''); - expect(spacer(1, 1)).toEqual(' '); expect(spacer(1, 2)).toEqual(' '); expect(spacer(1, 3)).toEqual(' '); - expect(spacer(2, 1)).toEqual(' '); expect(spacer(2, 2)).toEqual(' '); expect(spacer(2, 3)).toEqual(' '); diff --git a/src/formatter/spacer.js b/src/formatter/spacer.ts similarity index 92% rename from src/formatter/spacer.js rename to src/formatter/spacer.ts index b853d5812..42e82d98f 100644 --- a/src/formatter/spacer.js +++ b/src/formatter/spacer.ts @@ -1,5 +1,3 @@ -/* @flow */ - export default (times: number, tabStop: number): string => { if (times === 0) { return ''; diff --git a/src/index.spec.js b/src/index.spec.tsx similarity index 86% rename from src/index.spec.js rename to src/index.spec.tsx index c27217a49..2092e209b 100644 --- a/src/index.spec.js +++ b/src/index.spec.tsx @@ -2,8 +2,6 @@ * @jest-environment jsdom */ -/* @flow */ - /* eslint-disable react/no-string-refs */ /* eslint-disable react/prop-types */ @@ -14,7 +12,7 @@ import AnonymousStatelessComponent from './AnonymousStatelessComponent'; class TestComponent extends React.Component {} -function NamedStatelessComponent(props: { children: React.Children }) { +function NamedStatelessComponent(props: { children: React.ReactChildren }) { const { children } = props; return
{children}
; } @@ -29,7 +27,6 @@ DefaultPropsComponent.defaultProps = { }; class DisplayNamePrecedence extends React.Component {} - DisplayNamePrecedence.displayName = 'This should take precedence'; describe('reactElementToJSXString(ReactElement)', () => { @@ -38,51 +35,46 @@ describe('reactElementToJSXString(ReactElement)', () => { '' ); }); - it('reactElementToJSXString()', () => { expect(reactElementToJSXString()).toEqual( '' ); }); - it('reactElementToJSXString()', () => { expect(reactElementToJSXString()).toEqual( '' ); }); - it('reactElementToJSXString() with a displayName', () => { AnonymousStatelessComponent.displayName = 'I have a name!'; - expect(reactElementToJSXString()).toEqual( '' ); - delete AnonymousStatelessComponent.displayName; }); - it("reactElementToJSXString(React.createElement('div'))", () => { expect(reactElementToJSXString(React.createElement('div'))).toEqual( '
' ); }); - it("reactElementToJSXString(React.createElement('div', {title: 'hello \"you\"'}))", () => { expect( reactElementToJSXString( - React.createElement('div', { title: 'hello "you"' }) + React.createElement('div', { + title: 'hello "you"', + }) ) ).toEqual('
'); }); - it("reactElementToJSXString(React.createElement('div', {title: '<'hello' you & you>'}))", () => { expect( reactElementToJSXString( - React.createElement('div', { title: "<'hello' you & you>" }) + React.createElement('div', { + title: "<'hello' you & you>", + }) ) ).toEqual('
'); }); - it("reactElementToJSXString(
}} />)", () => { /* eslint-disable react/no-unescaped-entities */ expect( @@ -93,15 +85,12 @@ describe('reactElementToJSXString(ReactElement)', () => { }} /> ) - ).toEqual( - `
Hello "' you
}} - />` - ); + />`); }); - it("reactElementToJSXString(
)", () => { expect( reactElementToJSXString( @@ -115,8 +104,7 @@ describe('reactElementToJSXString(ReactElement)', () => { root="root" /> ) - ).toEqual( - `
{ hello: 'world' }} root="root" -/>` - ); +/>`); }); - it("reactElementToJSXString(React.createElement('div', {title: Symbol('hello \"you\"')})", () => { expect( reactElementToJSXString( - React.createElement('div', { title: Symbol('hello "you"') }) + React.createElement('div', { + title: Symbol('hello "you"'), + }) ) ).toEqual('
'); }); - it('reactElementToJSXString(
)', () => { expect(reactElementToJSXString(
)).toEqual('
'); }); - it('reactElementToJSXString(
{}}/>)', () => { expect(reactElementToJSXString(
{}} />)).toEqual( '
' ); }); - it('reactElementToJSXString(
)', () => { // eslint-disable-next-line react/jsx-no-bind expect(reactElementToJSXString(
)).toEqual( '
' ); }); - it('reactElementToJSXString(
} />)', () => { expect(reactElementToJSXString(
} />)).toEqual( '
} />' ); }); - it('reactElementToJSXString(
)', () => { expect(reactElementToJSXString(
)).toEqual( '
' ); }); - it('reactElementToJSXString(
)', () => { expect(reactElementToJSXString(
)).toEqual('
'); }); - it("reactElementToJSXString(
)", () => { - expect(reactElementToJSXString(
)).toEqual( - `
+ ) + ).toEqual(`
` - ); + />`); }); - it('reactElementToJSXString(
)', () => { expect( - reactElementToJSXString(
) - ).toEqual( - `
+ ) + ).toEqual(`
` - ); +/>`); }); - it('reactElementToJSXString(
)', () => { expect( - reactElementToJSXString(
) - ).toEqual( - `
+ ) + ).toEqual(`
` - ); +/>`); }); - it('reactElementToJSXString()', () => { expect( reactElementToJSXString( ) - ).toEqual( - `` - ); +`); }); - it('reactElementToJSXString()', () => { expect( reactElementToJSXString( ) - ).toEqual( - `` - ); +`); }); - it('reactElementToJSXString(
)', () => { expect( reactElementToJSXString( -
+
) - ).toEqual( - `
{ nested: true } }} - />` - ); + />`); }); - it('reactElementToJSXString(
)', () => { expect(reactElementToJSXString(
)).toEqual('
'); }); - it('reactElementToJSXString(
)', () => { /* eslint react/jsx-sort-props: 0 */ - expect(reactElementToJSXString(
)).toEqual( - `
)).toEqual(`
` - ); +/>`); }); - it('reactElementToJSXString(
, {sortProps: false})', () => { /* eslint react/jsx-sort-props: 0 */ expect( reactElementToJSXString(
, { sortProps: false, }) - ).toEqual( - `
` - ); +/>`); }); - it('reactElementToJSXString(
Hello
)', () => { - expect(reactElementToJSXString(
Hello
)).toEqual( - `
+ expect(reactElementToJSXString(
Hello
)).toEqual(`
Hello -
` - ); +
`); }); - it('reactElementToJSXString(
Hello
)', () => { expect( reactElementToJSXString( @@ -297,64 +279,51 @@ describe('reactElementToJSXString(ReactElement)', () => { Hello
) - ).toEqual( - `
Hello -
` - ); +
`); }); - it('reactElementToJSXString(
Hello
)', () => { - expect(reactElementToJSXString(
Hello
)).toEqual( - `
+ expect(reactElementToJSXString(
Hello
)).toEqual(`
Hello -
` - ); +
`); }); - it('reactElementToJSXString(
Hello "Jonh" and \'Mike\'
)', () => { - expect(reactElementToJSXString(
Hello "Jonh" and 'Mike'
)).toEqual( - `
+ expect(reactElementToJSXString(
Hello "Jonh" and 'Mike'
)) + .toEqual(`
Hello "Jonh" and 'Mike' -
` - ); +
`); }); - it('reactElementToJSXString(
{`foo\nbar`}
)', () => { - expect(reactElementToJSXString(
{`foo\nbar`}
)).toEqual( - `
+ expect(reactElementToJSXString(
{`foo\nbar`}
)).toEqual(`
foo bar -
` - ); - +
`); expect( reactElementToJSXString(
{`foo\nbar`}
) - ).toEqual( - `
+ ).toEqual(`
foo bar
-
` - ); +
`); }); - it('reactElementToJSXString(
Hello
, {tabStop: 4})', () => { - expect(reactElementToJSXString(
Hello
, { tabStop: 4 })).toEqual( - `
+ expect( + reactElementToJSXString(
Hello
, { + tabStop: 4, + }) + ).toEqual(`
Hello -
` - ); +
`); }); - it('reactElementToJSXString(
Hello
)', () => { expect( reactElementToJSXString( @@ -362,32 +331,28 @@ describe('reactElementToJSXString(ReactElement)', () => {
Hello
) - ).toEqual( - `
+ ).toEqual(`
Hello
-
` - ); +
`); }); - it('reactElementToJSXString(
Hello
, {tabStop: 4})', () => { expect( reactElementToJSXString(
Hello
, - { tabStop: 4 } + { + tabStop: 4, + } ) - ).toEqual( - `
+ ).toEqual(`
Hello
-
` - ); +
`); }); - it('reactElementToJSXString(
Hello
)', () => { expect( reactElementToJSXString( @@ -395,18 +360,15 @@ describe('reactElementToJSXString(ReactElement)', () => {
Hello
) - ).toEqual( - `
Hello
-
` - ); +
`); }); - it('reactElementToJSXString(
Hello
, {tabStop: 4})', () => { expect( reactElementToJSXString( @@ -417,27 +379,38 @@ describe('reactElementToJSXString(ReactElement)', () => { tabStop: 4, } ) - ).toEqual( - `
Hello
-
` - ); +
`); }); - it('reactElementToJSXString(
Hello
)', () => { expect( reactElementToJSXString( -
-
Hello
+
+
+ Hello +
) - ).toEqual( - `
{ > Hello
-
` - ); +
`); }); - it('reactElementToJSXString()', () => { expect(() => { reactElementToJSXString(); }).toThrow('react-element-to-jsx-string: Expected a ReactElement'); }); - it('reactElementToJSXString(null)', () => { expect(() => { reactElementToJSXString(null); }).toThrow('react-element-to-jsx-string: Expected a ReactElement'); }); - it('ignores object keys order (sortobject)', () => { - expect(reactElementToJSXString(
)).toEqual( - reactElementToJSXString(
) + expect( + reactElementToJSXString( +
+ ) + ).toEqual( + reactElementToJSXString( +
+ ) ); }); - it('reactElementToJSXString(
', () => { expect(reactElementToJSXString(
)).toEqual( reactElementToJSXString(
) ); }); - it('reactElementToJSXString(
', () => { expect(reactElementToJSXString(
)).toEqual( reactElementToJSXString(
) ); }); - it('reactElementToJSXString(
', () => { expect( - reactElementToJSXString(
) - ).toEqual( - `
+ ) + ).toEqual(`
` - ); + />`); }); - it('reactElementToJSXString(
, e: null}}}} />', () => { expect( - reactElementToJSXString(
, e: null } } }} />) - ).toEqual( - `
, + e: null, + }, + }, + }} + /> + ) + ).toEqual(`
{ } } }} - />` - ); + />`); }); - it('reactElementToJSXString(
', () => { - expect(reactElementToJSXString(
)).toEqual( - `
+ ) + ).toEqual(`
` - ); + />`); }); - it('reactElementToJSXString(
', () => { expect(reactElementToJSXString(
)).toEqual('
'); }); - it('reactElementToJSXString(
)', () => { expect( reactElementToJSXString( @@ -539,14 +536,11 @@ describe('reactElementToJSXString(ReactElement)', () => {
) - ).toEqual( - `
+ ).toEqual(`
-
` - ); +
`); }); - it('reactElementToJSXString(
foo
)', () => { expect( reactElementToJSXString( @@ -555,14 +549,11 @@ describe('reactElementToJSXString(ReactElement)', () => {
) - ).toEqual( - `
+ ).toEqual(`
foo
-
` - ); +
`); }); - it('reactElementToJSXString(
\nfoo bar baz qux quux\n
)', () => { expect( reactElementToJSXString( @@ -578,48 +569,45 @@ describe('reactElementToJSXString(ReactElement)', () => { {' '}qux quux
`); }); - it('reactElementToJSXString(
', () => { - expect(reactElementToJSXString(
)).toEqual( - `
)).toEqual(`
` - ); + />`); }); - it("reactElementToJSXString(
)", () => { expect( - reactElementToJSXString(
) - ).toEqual( - `
+ ) + ).toEqual(`
` - ); + />`); }); - it('reactElementToJSXString(
', () => { - expect(reactElementToJSXString(
)).toEqual( - `
)).toEqual(`
` - ); + />`); }); - it('reactElementToJSXString(
', () => { expect(reactElementToJSXString(
)).toEqual('
'); }); - it('reactElementToJSXString(
]} />', () => { expect( reactElementToJSXString( @@ -631,30 +619,24 @@ describe('reactElementToJSXString(ReactElement)', () => { ]} /> ) - ).toEqual( - `
]} - />` - ); + />`); }); - it('reactElementToJSXString(
)', () => { expect(reactElementToJSXString(
)).toEqual( "
" ); }); - it('reactElementToJSXString(
', () => { - expect(reactElementToJSXString(
)).toEqual( - `
)) + .toEqual(`
` - ); +/>`); }); - it('reactElementToJSXString(
', () => { expect( reactElementToJSXString( @@ -662,8 +644,7 @@ describe('reactElementToJSXString(ReactElement)', () => {
) - ).toEqual( - `
@@ -671,81 +652,59 @@ describe('reactElementToJSXString(ReactElement)', () => { ref="wee" zprop="z" /> -
` - ); +
`); }); - it('reactElementToJSXString(
', () => { - expect(reactElementToJSXString(
)).toEqual( - `
)) + .toEqual(`
` - ); +/>`); }); - it('reactElementToJSXString(
\\n {null}\\n
', () => { const element =
{null}
; - expect(reactElementToJSXString(element)).toEqual('
'); }); - it('reactElementToJSXString(
{true}
)', () => { expect(reactElementToJSXString(
{true}
)).toEqual('
'); }); - it('reactElementToJSXString(
{false}
)', () => { expect(reactElementToJSXString(
{false}
)).toEqual('
'); }); - it('reactElementToJSXString(
\n{false}\n
)', () => { expect(reactElementToJSXString(
{false}
)).toEqual('
'); }); - it('reactElementToJSXString(
{false}
)', () => { - expect(reactElementToJSXString(
{false}
)).toEqual( - `
+ expect(reactElementToJSXString(
{false}
)).toEqual(`
{' '} -
` - ); +
`); }); - it('reactElementToJSXString(
{null}
)', () => { expect(reactElementToJSXString(
{null}
)).toEqual('
'); }); - it('reactElementToJSXString(
{123}
)', () => { - expect(reactElementToJSXString(
{123}
)).toEqual( - `
+ expect(reactElementToJSXString(
{123}
)).toEqual(`
123 -
` - ); +
`); }); - it("reactElementToJSXString(
{''}
)", () => { expect(reactElementToJSXString(
{''}
)).toEqual( reactElementToJSXString(
) ); }); - it('reactElementToJSXString(
String with {1} js expression
)', () => { - expect( - reactElementToJSXString(
String with {1} js number
) - ).toEqual( - `
+ expect(reactElementToJSXString(
String with {1} js number
)) + .toEqual(`
String with 1 js number -
` - ); +
`); }); - it('reactElementToJSXString(, { displayName: toUpper })', () => { expect( reactElementToJSXString(, { - displayName: element => element.type.name.toUpperCase(), + displayName: (element) => element.type.name.toUpperCase(), }) ).toEqual(''); }); - it("reactElementToJSXString(, { filterProps: ['key', 'className'] })", () => { expect( reactElementToJSXString( @@ -756,7 +715,6 @@ describe('reactElementToJSXString(ReactElement)', () => { ) ).toEqual(''); }); - it("reactElementToJSXString(, { filterProps: () => !key.startsWith('some')) })", () => { expect( reactElementToJSXString( @@ -767,7 +725,6 @@ describe('reactElementToJSXString(ReactElement)', () => { ) ).toEqual(''); }); - it('reactElementToJSXString(, { useBooleanShorthandSyntax: false })', () => { expect( reactElementToJSXString( @@ -776,25 +733,20 @@ describe('reactElementToJSXString(ReactElement)', () => { useBooleanShorthandSyntax: false, } ) - ).toEqual( - `` - ); +/>`); }); - it('should render default props', () => { - expect(reactElementToJSXString()).toEqual( - `)) + .toEqual(`` - ); +/>`); }); - it('should not render default props if "showDefaultProps" option is false', () => { expect( reactElementToJSXString(, { @@ -802,7 +754,6 @@ describe('reactElementToJSXString(ReactElement)', () => { }) ).toEqual(''); }); - it('should render props that differ from their defaults if "showDefaultProps" option is false', () => { expect( reactElementToJSXString(, { @@ -810,7 +761,6 @@ describe('reactElementToJSXString(ReactElement)', () => { }) ).toEqual(''); }); - it('should render boolean props if value is `false`, default is `true` and "showDefaultProps" is false', () => { expect( reactElementToJSXString(, { @@ -818,41 +768,41 @@ describe('reactElementToJSXString(ReactElement)', () => { }) ).toEqual(''); }); - it('reactElementToJSXString(
} />, { displayName: toUpper })', () => { expect( reactElementToJSXString(
} />, { - displayName: element => element.type.toUpperCase(), + displayName: (element) => element.type.toUpperCase(), }) ).toEqual('
} />'); }); - it('reactElementToJSXString(
}} />, { displayName: toUpper })', () => { expect( - reactElementToJSXString(
}} />, { - displayName: element => element.type.toUpperCase(), - }) - ).toEqual( - `
, + }} + />, + { + displayName: (element) => element.type.toUpperCase(), + } + ) + ).toEqual(`
}} - />` - ); + />`); }); - it('should omit true as value', () => { expect( reactElementToJSXString(
) // eslint-disable-line react/jsx-boolean-value ).toEqual('
'); }); - it('should omit attributes with false as value', () => { expect( reactElementToJSXString(
) // eslint-disable-line react/jsx-boolean-value ).toEqual('
'); }); - it('should return the actual functions when "showFunctions" is true', () => { /* eslint-disable arrow-body-style */ const fn = () => { @@ -865,7 +815,6 @@ describe('reactElementToJSXString(ReactElement)', () => { }) ).toEqual(`
`); }); - it('should expose the multiline "functionValue" formatter', () => { /* eslint-disable arrow-body-style */ const fn = () => { @@ -883,13 +832,11 @@ describe('reactElementToJSXString(ReactElement)', () => { }} />`); }); - it('reactElementToJSXString()', () => { expect(reactElementToJSXString()).toEqual( '' ); }); - // maxInlineAttributesLineLength tests // Validate two props will stay inline if their length is less than the option it('reactElementToJSXString(
, { maxInlineAttributesLineLength: 100 }))', () => { @@ -907,11 +854,9 @@ describe('reactElementToJSXString(ReactElement)', () => { reactElementToJSXString(
, { maxInlineAttributesLineLength: 5, }) - ).toEqual( - `
` - ); +/>`); }); // Validate two props will go be multiline if their length is greater than the given option it('reactElementToJSXString(
, { maxInlineAttributesLineLength: 10 }))', () => { @@ -919,14 +864,11 @@ describe('reactElementToJSXString(ReactElement)', () => { reactElementToJSXString(
, { maxInlineAttributesLineLength: 10, }) - ).toEqual( - `
` - ); +/>`); }); - // Same tests as above but with elements that have children. The closing braces for elements with children and without children // run through different code paths so we have both sets of test to specify the behavior of both when this option is present it('reactElementToJSXString(
content
, { maxInlineAttributesLineLength: 100 }))', () => { @@ -939,24 +881,20 @@ describe('reactElementToJSXString(ReactElement)', () => { maxInlineAttributesLineLength: 100, } ) - ).toEqual( - `
+ ).toEqual(`
content -
` - ); +
`); }); it('reactElementToJSXString(
content
, { maxInlineAttributesLineLength: 5 }))', () => { expect( reactElementToJSXString(
content
, { maxInlineAttributesLineLength: 5, }) - ).toEqual( - `
content -
` - ); +
`); }); it('reactElementToJSXString(
content
, { maxInlineAttributesLineLength: 10 }))', () => { expect( @@ -968,16 +906,13 @@ describe('reactElementToJSXString(ReactElement)', () => { maxInlineAttributesLineLength: 10, } ) - ).toEqual( - `
content -
` - ); +
`); }); - // Multi-level inline attribute test it('reactElementToJSXString(
content
, { maxInlineAttributesLineLength: 24 }))', () => { expect( @@ -991,16 +926,14 @@ describe('reactElementToJSXString(ReactElement)', () => { maxInlineAttributesLineLength: 24, } ) - ).toEqual( - `
+ ).toEqual(`
content
-
` - ); +
`); }); it('should return functionValue result when it returns a string', () => { expect( @@ -1012,15 +945,18 @@ describe('reactElementToJSXString(ReactElement)', () => { }); it('sends the original fn to functionValue', () => { const fn = () => {}; - const functionValue = receivedFn => expect(receivedFn).toBe(fn); - reactElementToJSXString(
, { functionValue }); + + const functionValue = (receivedFn) => expect(receivedFn).toBe(fn); + + reactElementToJSXString(
, { + functionValue, + }); }); it('should return noRefCheck when "showFunctions" is false and "functionValue" is not provided', () => { expect(reactElementToJSXString(
{}} />)).toEqual( '
' ); }); - it('reactElementToJSXString(

foo

bar

)', () => { expect( reactElementToJSXString( @@ -1029,18 +965,15 @@ describe('reactElementToJSXString(ReactElement)', () => {

bar

) - ).toEqual( - `<> + ).toEqual(`<>

foo

bar

-` - ); +`); }); - it('reactElementToJSXString(
)', () => { expect( reactElementToJSXString( @@ -1049,18 +982,14 @@ describe('reactElementToJSXString(ReactElement)', () => {
) - ).toEqual( - ` + ).toEqual(`
-` - ); +`); }); - it('reactElementToJSXString()', () => { expect(reactElementToJSXString()).toEqual(``); }); - it('reactElementToJSXString(
} />)', () => { expect( reactElementToJSXString( @@ -1075,7 +1004,6 @@ describe('reactElementToJSXString(ReactElement)', () => { ) ).toEqual(`
} />`); }); - it('should not cause recursive loop when prop object contains an element', () => { const Test = () =>
Test
; @@ -1083,10 +1011,14 @@ describe('reactElementToJSXString(ReactElement)', () => { class App extends Component { render() { - const inside = }} />; - + const inside = ( + , + }} + /> + ); const insideString = reactElementToJSXString(inside); - return (
{insideString} @@ -1103,7 +1035,6 @@ describe('reactElementToJSXString(ReactElement)', () => { expect(screen.getByText('Hello world!')).toBeInTheDocument(); }); - it('should not cause recursive loop when an element contains a ref', () => { expect.assertions(2); @@ -1112,15 +1043,16 @@ describe('reactElementToJSXString(ReactElement)', () => { super(props); this.inputRef = React.createRef(); } + componentDidMount() { - expect(reactElementToJSXString()).toEqual( - `)) + .toEqual(`` - ); + />`); } + render() { return ( <> @@ -1135,7 +1067,6 @@ describe('reactElementToJSXString(ReactElement)', () => { expect(screen.getByText('Hello world!')).toBeInTheDocument(); }); - it('should use inferred function name as display name for `forwardRef` element', () => { const Tag = React.forwardRef(function Tag({ text }, ref) { return {text}; @@ -1144,7 +1075,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `` ); }); - it('should use `displayName` instead of inferred function name as display name for `forwardRef` element', () => { const Tag = React.forwardRef(function Tag({ text }, ref) { return {text}; @@ -1154,7 +1084,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `` ); }); - it('should use inferred function name as display name for `memo` element', () => { const Tag = React.memo(function Tag({ text }) { return {text}; @@ -1163,7 +1092,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `` ); }); - it('should use `displayName` instead of inferred function name as display name for `memo` element', () => { const Tag = React.memo(function Tag({ text }) { return {text}; @@ -1173,7 +1101,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `` ); }); - it('should use inferred function name as display name for a `forwardRef` wrapped in `memo`', () => { const Tag = React.memo( React.forwardRef(function Tag({ text }, ref) { @@ -1184,7 +1111,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `` ); }); - it('should use inferred function name as display name for a component wrapped in `memo` multiple times', () => { const Tag = React.memo( React.memo( @@ -1197,7 +1123,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `` ); }); - it('should stringify `StrictMode` correctly', () => { const App = () => null; @@ -1211,9 +1136,9 @@ describe('reactElementToJSXString(ReactElement)', () => { `); }); - it('should stringify `Suspense` correctly', () => { const Spinner = () => null; + const ProfilePage = () => null; expect( @@ -1226,7 +1151,6 @@ describe('reactElementToJSXString(ReactElement)', () => { `); }); - it('should stringify `Profiler` correctly', () => { const Navigation = () => null; @@ -1243,9 +1167,9 @@ describe('reactElementToJSXString(ReactElement)', () => { `); }); - it('should stringify `Contex.Provider` correctly', () => { const Ctx = React.createContext(); + const App = () => {}; expect( @@ -1290,18 +1214,17 @@ describe('reactElementToJSXString(ReactElement)', () => { `); }); - it('should stringify `Contex.Consumer` correctly', () => { const Ctx = React.createContext(); + const Button = () => null; expect( reactElementToJSXString( - {theme =>