Skip to content
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
14 changes: 14 additions & 0 deletions ini/stringify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ function sort([_a, valA]: [string, unknown], [_b, valB]: [string, unknown]) {
}

function defaultReplacer(_key: string, value: unknown, _section?: string) {
if (typeof value === "string") {
// Quote strings that would be misread by the parser as a different type.
// parseValue converts "true"/"false" to boolean, "null" to null, and
// bare numeric strings to number. Wrap those in double quotes so a
// parse(stringify(obj)) round-trip preserves the original string value.
if (
value === "true" ||
value === "false" ||
value === "null" ||
(!isNaN(+value) && value !== "")
) {
return `"${value}"`;
}
}
return `${value}`;
}

Expand Down
32 changes: 31 additions & 1 deletion ini/stringify_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018-2026 the Deno authors. MIT license.

import { stringify } from "./mod.ts";
import { parse, stringify } from "./mod.ts";
import { assertEquals } from "@std/assert";

Deno.test({
Expand Down Expand Up @@ -39,5 +39,35 @@ Deno.test({
assertEquals(stringify({ a: false }), "a=false");
assertEquals(stringify({ a: null }), "a=null");
assertEquals(stringify({ a: undefined }), "a=undefined");

// String values that look like other types must be quoted so that
// parse(stringify(obj)) preserves the original string value.
assertEquals(stringify({ a: "true" }), `a="true"`);
assertEquals(stringify({ a: "false" }), `a="false"`);
assertEquals(stringify({ a: "null" }), `a="null"`);
assertEquals(stringify({ a: "123" }), `a="123"`);
assertEquals(stringify({ a: "0" }), `a="0"`);
assertEquals(stringify({ a: "3.14" }), `a="3.14"`);
// Plain strings that cannot be mistaken for another type are not quoted.
assertEquals(stringify({ a: "hello" }), "a=hello");
assertEquals(stringify({ a: "123foo" }), "a=123foo");
},
});

Deno.test({
name: "stringify() round-trips string values that look like other types",
fn() {
// All of these were silently corrupted before the fix: the string was
// written without quotes and then parsed back as a different type.
const obj = {
boolTrue: "true",
boolFalse: "false",
nullVal: "null",
num: "42",
float: "1.5",
zero: "0",
};
const roundTripped = parse(stringify(obj));
assertEquals(roundTripped, obj);
},
});
Loading