123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /* @flow */
- import spacer from './spacer';
- import formatTreeNode from './formatTreeNode';
- import formatProp from './formatProp';
- import mergeSiblingPlainStringChildrenReducer from './mergeSiblingPlainStringChildrenReducer';
- import sortPropsByNames from './sortPropsByNames';
- import createPropFilter from './createPropFilter';
- import type { Options } from './../options';
- import type { ReactElementTreeNode } from './../tree';
- const compensateMultilineStringElementIndentation = (
- element,
- formattedElement: string,
- inline: boolean,
- lvl: number,
- options: Options
- ) => {
- const { tabStop } = options;
- if (element.type === 'string') {
- return formattedElement
- .split('\n')
- .map((line, offset) => {
- if (offset === 0) {
- return line;
- }
- return `${spacer(lvl, tabStop)}${line}`;
- })
- .join('\n');
- }
- return formattedElement;
- };
- 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 haveDefaultValue = Object.keys(defaultProps).includes(propName);
- return (
- !haveDefaultValue ||
- (haveDefaultValue && defaultProps[propName] !== props[propName])
- );
- };
- const isInlineAttributeTooLong = (
- attributes: string[],
- inlineAttributeString: string,
- lvl: number,
- tabStop: number,
- maxInlineAttributesLineLength: ?number
- ): boolean => {
- if (!maxInlineAttributesLineLength) {
- return attributes.length > 1;
- }
- return (
- spacer(lvl, tabStop).length + inlineAttributeString.length >
- maxInlineAttributesLineLength
- );
- };
- const shouldRenderMultilineAttr = (
- attributes: string[],
- inlineAttributeString: string,
- containsMultilineAttr: boolean,
- inline: boolean,
- lvl: number,
- tabStop: number,
- maxInlineAttributesLineLength: ?number
- ): boolean =>
- (isInlineAttributeTooLong(
- attributes,
- inlineAttributeString,
- lvl,
- tabStop,
- maxInlineAttributesLineLength
- ) ||
- containsMultilineAttr) &&
- !inline;
- export default (
- node: ReactElementTreeNode,
- inline: boolean,
- lvl: number,
- options: Options
- ): string => {
- const {
- type,
- displayName = '',
- childrens,
- props = {},
- defaultProps = {},
- } = node;
- if (type !== 'ReactElement') {
- throw new Error(
- `The "formatReactElementNode" function could only format node of type "ReactElement". Given: ${type}`
- );
- }
- const {
- filterProps,
- maxInlineAttributesLineLength,
- showDefaultProps,
- 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));
- Object.keys(defaultProps)
- .filter(propFilter)
- .filter(() => showDefaultProps)
- .filter(defaultPropName => !visibleAttributeNames.includes(defaultPropName))
- .forEach(defaultPropName => visibleAttributeNames.push(defaultPropName));
- const attributes = sortPropsByNames(sortProps)(visibleAttributeNames);
- attributes.forEach(attributeName => {
- const {
- attributeFormattedInline,
- attributeFormattedMultiline,
- isMultilineAttribute,
- } = formatProp(
- attributeName,
- Object.keys(props).includes(attributeName),
- props[attributeName],
- Object.keys(defaultProps).includes(attributeName),
- defaultProps[attributeName],
- inline,
- lvl,
- options
- );
- if (isMultilineAttribute) {
- containsMultilineAttr = true;
- }
- outInlineAttr += attributeFormattedInline;
- outMultilineAttr += attributeFormattedMultiline;
- });
- outMultilineAttr += `\n${spacer(lvl, tabStop)}`;
- if (
- shouldRenderMultilineAttr(
- attributes,
- outInlineAttr,
- containsMultilineAttr,
- inline,
- lvl,
- tabStop,
- maxInlineAttributesLineLength
- )
- ) {
- out = outMultilineAttr;
- } else {
- out = outInlineAttr;
- }
- if (childrens && childrens.length > 0) {
- const newLvl = lvl + 1;
- out += '>';
- if (!inline) {
- out += '\n';
- out += spacer(newLvl, tabStop);
- }
- out += childrens
- .reduce(mergeSiblingPlainStringChildrenReducer, [])
- .map(formatOneChildren(inline, newLvl, options))
- .join(!inline ? `\n${spacer(newLvl, tabStop)}` : '');
- if (!inline) {
- out += '\n';
- out += spacer(newLvl - 1, tabStop);
- }
- out += `</${displayName}>`;
- } else {
- if (
- !isInlineAttributeTooLong(
- attributes,
- outInlineAttr,
- lvl,
- tabStop,
- maxInlineAttributesLineLength
- )
- ) {
- out += ' ';
- }
- out += '/>';
- }
- return out;
- };
|