Skip to content

Commit 8d2fd8f

Browse files
committed
🐛 Correct toJSON to match the specifications of JSON.stringify
`toJSON` returns a JSON value that can be specified to `JSON.stringify`. It is NOT a JSON string that can be specified to `JSON.parse`. This is a breaking change for code that depended on previous incorrect behavior. Previous (incorrect) behaviour: ```ts await useExprString(denops, async (denops) => { await denops.cmd('echo type(value)', { value: { toJSON: () => "123" } }); // output: 0 (equals `v:t_number`) }); ``` New (correct) behaviour: ```ts await useExprString(denops, async (denops) => { await denops.cmd('echo type(value)', { value: { toJSON: () => "123" } }); // output: 1 (equals `v:t_string`) }); ```
1 parent 341fa18 commit 8d2fd8f

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

helper/expr_string.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ export type ExprString = string & {
4343
};
4444

4545
type Jsonable = {
46-
toJSON(key: string | number | undefined): string;
46+
/**
47+
* Returns a JSON value that can be specified to {@link JSON.stringify}.
48+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#tojson_behavior|toJSON() behavior}
49+
*/
50+
toJSON(key: string | number | undefined): unknown;
4751
};
4852

4953
// deno-lint-ignore no-explicit-any
@@ -125,7 +129,7 @@ function isIgnoreRecordValue(x: unknown): boolean {
125129
*/
126130
export function vimStringify(value: unknown, key?: string | number): string {
127131
if (isJsonable(value)) {
128-
return vimStringify(JSON.parse(value.toJSON(key)));
132+
return vimStringify(value.toJSON(key));
129133
}
130134
if (isExprString(value)) {
131135
// Return Vim's expr-string

helper/expr_string_test.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ Deno.test({
160160
fn: () => {
161161
const actual = vimStringify({
162162
foo: 42,
163-
toJSON: () => JSON.stringify([123, "bar"]),
163+
toJSON: () => [123, "bar"],
164164
});
165165
assertEquals(actual, "[123,'bar']");
166166
},
@@ -171,12 +171,20 @@ Deno.test({
171171
const actual = vimStringify(Object.assign(
172172
() => {},
173173
{
174-
toJSON: () => JSON.stringify([123, "bar"]),
174+
toJSON: () => [123, "bar"],
175175
},
176176
));
177177
assertEquals(actual, "[123,'bar']");
178178
},
179179
});
180+
await t.step({
181+
name: "stringify Date that has native `toJSON()` method.",
182+
fn: () => {
183+
// NOTE: `Date.prototype.toJSON` returns a string representing date in the same ISO format as `Date.prototype.toISOString()`.
184+
const actual = vimStringify(new Date("2007-08-31T12:34:56.000Z"));
185+
assertEquals(actual, "'2007-08-31T12:34:56.000Z'");
186+
},
187+
});
180188
await t.step({
181189
name: "raises TypeError if specified BigInt.",
182190
fn: () => {
@@ -197,7 +205,7 @@ Deno.test({
197205
});
198206
try {
199207
const actual = vimStringify(92382417n);
200-
assertEquals(actual, "92382417");
208+
assertEquals(actual, "'92382417'");
201209
} finally {
202210
// deno-lint-ignore no-explicit-any
203211
delete (BigInt.prototype as any).toJSON;
@@ -216,8 +224,9 @@ Deno.test({
216224
Symbol("foo"),
217225
"bar",
218226
{
219-
toJSON: () => JSON.stringify([123, "baz"]),
227+
toJSON: () => [123, "baz"],
220228
},
229+
new Date("2007-08-31T12:34:56.000Z"),
221230
{
222231
k0: null,
223232
k1: undefined,
@@ -232,7 +241,7 @@ Deno.test({
232241
]);
233242
assertEquals(
234243
actual,
235-
`[v:null,v:null,42,v:true,v:null,v:null,'bar',[123,'baz'],{'k0':v:null,'k2':[{'key':234,'expr':"\\U0001F680"}]}]`,
244+
`[v:null,v:null,42,v:true,v:null,v:null,'bar',[123,'baz'],'2007-08-31T12:34:56.000Z',{'k0':v:null,'k2':[{'key':234,'expr':"\\U0001F680"}]}]`,
236245
);
237246
},
238247
});
@@ -419,8 +428,9 @@ test({
419428
Symbol("foo"),
420429
"bar",
421430
{
422-
toJSON: () => JSON.stringify([123, "baz"]),
431+
toJSON: () => [123, "baz"],
423432
},
433+
new Date("2007-08-31T12:34:56.000Z"),
424434
{
425435
k0: null,
426436
k1: undefined,
@@ -448,6 +458,7 @@ test({
448458
123,
449459
"baz",
450460
],
461+
"2007-08-31T12:34:56.000Z",
451462
{
452463
k0: null,
453464
k2: [

0 commit comments

Comments
 (0)