Skip to content

Commit 6ce8383

Browse files
committed
Object function properties should call next()
1 parent ac439a6 commit 6ce8383

File tree

3 files changed

+56
-16
lines changed

3 files changed

+56
-16
lines changed

src/function.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Next } from "./types";
1+
import { Next, ToString } from "./types";
22
import { quoteKey, isValidVariableName } from "./quote";
33

44
/**
@@ -35,12 +35,22 @@ const TOKENS_PRECEDING_REGEXPS = new Set(
3535
).split(" ")
3636
);
3737

38+
/**
39+
* Track function parser usage.
40+
*/
41+
export const USED_METHOD_KEY = new WeakSet<Function>();
42+
3843
/**
3944
* Stringify a function.
4045
*/
41-
export function functionToString(fn: Function, space: string, next: Next) {
42-
return new FunctionParser(fn, space, next).stringify();
43-
}
46+
export const functionToString: ToString = (fn, space, next, key) => {
47+
const name = typeof key === "string" ? key : undefined;
48+
49+
// Track in function parser for object stringify to avoid duplicate output.
50+
if (name !== undefined) USED_METHOD_KEY.add(fn);
51+
52+
return new FunctionParser(fn, space, next, name).stringify();
53+
};
4454

4555
/**
4656
* Rewrite a stringified function to remove initial indentation.
@@ -78,7 +88,7 @@ export class FunctionParser {
7888
public fn: Function,
7989
public indent: string,
8090
public next: Next,
81-
public key?: PropertyKey
91+
public key?: string
8292
) {
8393
this.fnString = Function.prototype.toString.call(fn);
8494
this.fnType = fn.constructor.name as keyof typeof FUNCTION_PREFIXES;

src/index.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,39 @@ describe("javascript-stringify", () => {
857857

858858
expect(result).toEqual("[object Object]");
859859
});
860+
861+
it("should support object functions", () => {
862+
function makeRaw(str: string) {
863+
const fn = () => {
864+
/* Noop. */
865+
};
866+
fn.__expression = str;
867+
return fn;
868+
}
869+
870+
const result = stringify(
871+
{
872+
"no-console": makeRaw(
873+
`process.env.NODE_ENV === 'production' ? 'error' : 'off'`
874+
),
875+
"no-debugger": makeRaw(
876+
`process.env.NODE_ENV === 'production' ? 'error' : 'off'`
877+
)
878+
},
879+
(val, indent, stringify) => {
880+
if (val && val.__expression) {
881+
return val.__expression;
882+
}
883+
return stringify(val);
884+
},
885+
2
886+
);
887+
888+
expect(result).toEqual(`{
889+
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
890+
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
891+
}`);
892+
});
860893
});
861894

862895
describe("max depth", () => {

src/object.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,22 @@ const rawObjectToString: ToString = (obj, indent, next) => {
2727
const values = Object.keys(obj)
2828
.reduce(
2929
function(values, key) {
30-
if (typeof obj[key] === "function") {
31-
const parser = new FunctionParser(obj[key], indent, next, key);
32-
const result = parser.stringify();
33-
values.push(indent + result.split("\n").join(`\n${indent}`));
34-
return values;
35-
}
36-
37-
const result = next(obj[key], key);
30+
const fn = obj[key];
31+
const result = next(fn, key);
3832

3933
// Omit `undefined` object entries.
4034
if (result === undefined) return values;
4135

4236
// String format the value data.
4337
const value = result.split("\n").join(`\n${indent}`);
4438

45-
values.push(
46-
`${indent}${quoteKey(key, next)}:${indent ? " " : ""}${value}`
47-
);
39+
// Skip `key` prefix for function parser.
40+
if (USED_METHOD_KEY.has(fn)) {
41+
values.push(`${indent}${value}`);
42+
return values;
43+
}
4844

45+
values.push(`${indent}${quoteKey(key, next)}:${space}${value}`);
4946
return values;
5047
},
5148
[] as string[]

0 commit comments

Comments
 (0)