Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Print function children #607

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,24 @@ console.log(reactElementToJSXString(<div a="1" b="2">Hello, world!</div>));

If false, default props are omitted unless they differ from from the default value.

**options.showFunctions: boolean, default false**
**options.showFunctions: boolean | (fn: Function, prop: string) => boolean, default false**

If true, functions bodies are shown.

If false, functions bodies are replaced with `function noRefCheck() {}`.

**options.functionValue: function, default `(fn) => fn`**
If a function is passed, it will be called for each function prop with its value and key, and will not print bodies of functions that return false.

**options.functionValue: (fn: Function, prop: string) => Function | string, default undefined**

Allows you to override the default formatting of function values.

`functionValue` receives the original function reference as input
and should send any value as output.
and should return a new function or formatted string.

Pre-defined inline and multi-line formatters are exported as `inlineFunction` and `preserveFunctionLineBreak` respectively.

The default formatting depends on context: multi-line for function children and inline for props.

**options.tabStop: number, default 2**

Expand Down
3 changes: 2 additions & 1 deletion src/formatter/formatComplexDataStructure.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Options } from './../options';

export default (
value: Object | Array<any>,
name: string,
inline: boolean,
lvl: number,
options: Options
Expand All @@ -31,7 +32,7 @@ export default (
}

if (typeof currentValue === 'function') {
return formatFunction(currentValue, options);
return formatFunction(currentValue, name, true, lvl, options);
}

return originalResult;
Expand Down
58 changes: 35 additions & 23 deletions src/formatter/formatComplexDataStructure.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ describe('formatComplexDataStructure', () => {
it('should format an object', () => {
const fixture = { a: 1, b: { c: 'ccc' } };

expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(
expect(
formatComplexDataStructure(fixture, 'foo', false, 0, options)
).toEqual(
`{
a: 1,
b: {
Expand All @@ -28,19 +30,23 @@ describe('formatComplexDataStructure', () => {
it('should format inline an object', () => {
const fixture = { a: 1, b: { c: 'ccc' } };

expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual(
"{a: 1, b: {c: 'ccc'}}"
);
expect(
formatComplexDataStructure(fixture, 'foo', true, 0, options)
).toEqual("{a: 1, b: {c: 'ccc'}}");
});

it('should format an empty object', () => {
expect(formatComplexDataStructure({}, false, 0, options)).toEqual('{}');
expect(formatComplexDataStructure({}, 'foo', false, 0, options)).toEqual(
'{}'
);
});

it('should order the object keys', () => {
const fixture = { b: { d: 'ddd', c: 'ccc' }, a: 1 };

expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(
expect(
formatComplexDataStructure(fixture, 'foo', false, 0, options)
).toEqual(
`{
a: 1,
b: {
Expand All @@ -54,7 +60,9 @@ describe('formatComplexDataStructure', () => {
it('should format an array', () => {
const fixture = [1, '2', true, false, null];

expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(
expect(
formatComplexDataStructure(fixture, 'foo', false, 0, options)
).toEqual(
`[
1,
'2',
Expand All @@ -68,39 +76,43 @@ describe('formatComplexDataStructure', () => {
it('should format inline an array ', () => {
const fixture = [1, '2', true, false, null];

expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual(
"[1, '2', true, false, null]"
);
expect(
formatComplexDataStructure(fixture, 'foo', true, 0, options)
).toEqual("[1, '2', true, false, null]");
});

it('should format an object that contains a react element', () => {
const fixture = { a: createFakeReactElement('BarBar') };

expect(formatComplexDataStructure(fixture, false, 0, options)).toEqual(
expect(
formatComplexDataStructure(fixture, 'foo', false, 0, options)
).toEqual(
`{
a: <BarBar />
}`
);
});

it('should format an empty array', () => {
expect(formatComplexDataStructure([], false, 0, options)).toEqual('[]');
expect(formatComplexDataStructure([], 'foo', false, 0, options)).toEqual(
'[]'
);
});

it('should format an object that contains a date', () => {
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')}`
);
expect(
formatComplexDataStructure(fixture, 'foo', true, 0, options)
).toEqual(`{a: new Date('2017-11-13T00:00:00.000Z')}`);
});

it('should format an object that contains a regexp', () => {
const fixture = { a: /test/g };

expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual(
`{a: /test/g}`
);
expect(
formatComplexDataStructure(fixture, 'foo', true, 0, options)
).toEqual(`{a: /test/g}`);
});

it('should replace a function with noRefCheck', () => {
Expand All @@ -110,9 +122,9 @@ describe('formatComplexDataStructure', () => {
},
};

expect(formatComplexDataStructure(fixture, true, 0, options)).toEqual(
'{a: function noRefCheck() {}}'
);
expect(
formatComplexDataStructure(fixture, 'foo', true, 0, options)
).toEqual('{a: function noRefCheck() {}}');
});

it('should format a function', () => {
Expand All @@ -123,7 +135,7 @@ describe('formatComplexDataStructure', () => {
};

expect(
formatComplexDataStructure(fixture, true, 0, {
formatComplexDataStructure(fixture, 'foo', true, 0, {
...options,
showFunctions: true,
})
Expand All @@ -138,7 +150,7 @@ describe('formatComplexDataStructure', () => {
};

expect(
formatComplexDataStructure(fixture, true, 0, {
formatComplexDataStructure(fixture, 'foo', true, 0, {
...options,
functionValue: () => '<Test />',
})
Expand Down
30 changes: 22 additions & 8 deletions src/formatter/formatFunction.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Options } from './../options';
import spacer from './spacer';

function noRefCheck() {}

Expand All @@ -11,13 +12,26 @@ export const inlineFunction = (fn: any): string =>

export const preserveFunctionLineBreak = (fn: any): string => fn.toString();

const defaultFunctionValue = inlineFunction;
export default (
fn: Function,
prop: string,
inline: boolean,
lvl: number,
options: Options
): string => {
const { functionValue, showFunctions } = options;
const functionFn =
functionValue || (inline ? inlineFunction : preserveFunctionLineBreak);
const shouldShowFunction = Boolean(
functionValue ||
(typeof showFunctions === 'function'
? showFunctions(fn, prop)
: showFunctions)
);

export default (fn: Function, options: Options): string => {
const { functionValue = defaultFunctionValue, showFunctions } = options;
if (!showFunctions && functionValue === defaultFunctionValue) {
return functionValue(noRefCheck);
}

return functionValue(fn);
return String(functionFn(shouldShowFunction ? fn : noRefCheck, prop))
.split('\n')
.map(ln => spacer(lvl, options.tabStop) + ln)
.join('\n')
.trim();
};
52 changes: 37 additions & 15 deletions src/formatter/formatFunction.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,40 @@ function hello() {

describe('formatFunction', () => {
it('should replace a function with noRefCheck without showFunctions option', () => {
expect(formatFunction(hello, {})).toEqual('function noRefCheck() {}');
expect(formatFunction(hello, 'prop', true, 0, {})).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, 'prop', true, 0, { 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, 'prop', true, 0, { 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, 'prop', true, 0, { showFunctions: true })
).toEqual('function () {return 1;}');
});

it('should use the functionValue option', () => {
expect(formatFunction(hello, { functionValue: () => '<Test />' })).toEqual(
'<Test />'
);
expect(
formatFunction(hello, 'prop', true, 0, {
functionValue: () => '<Test />',
})
).toEqual('<Test />');
});

it('should use the functionValue option even if showFunctions is true', () => {
expect(
formatFunction(hello, {
formatFunction(hello, 'prop', true, 0, {
showFunctions: true,
functionValue: () => '<Test />',
})
Expand All @@ -50,10 +54,28 @@ describe('formatFunction', () => {

it('should use the functionValue option even if showFunctions is false', () => {
expect(
formatFunction(hello, {
formatFunction(hello, 'prop', true, 0, {
showFunctions: false,
functionValue: () => '<Test />',
})
).toEqual('<Test />');
});

it('should format multi-line function', () => {
expect(
formatFunction(hello, 'prop', false, 0, {
showFunctions: true,
tabStop: 2,
})
).toEqual('function hello() {\n return 1;\n}');
});

it('should format multi-line function with indentation', () => {
expect(
formatFunction(hello, 'prop', false, 1, {
showFunctions: true,
tabStop: 2,
})
).toEqual('function hello() {\n return 1;\n }');
});
});
8 changes: 7 additions & 1 deletion src/formatter/formatProp.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ export default (

const { useBooleanShorthandSyntax, tabStop } = options;

const formattedPropValue = formatPropValue(usedValue, inline, lvl, options);
const formattedPropValue = formatPropValue(
usedValue,
name,
inline,
lvl,
options
);

let attributeFormattedInline = ' ';
let attributeFormattedMultiline = `\n${spacer(lvl + 1, tabStop)}`;
Expand Down
Loading