fix(plist): end OpenStep comments at native line separators (#7793)

This commit is contained in:
ShuaixinHuang authored and GitHub committed 2026-10-28 22:23:16 +08:00
1 parent 6fd5d347c7
commit 8f97a45483
3 files changed
+74 -3

No files matched your search

+43 -1
View File
@@ -2,7 +2,10 @@ import { expect, it } from "vitest";
import { parseOpenStep } from "plist";
import { plistNestingLimitMessage } from "./apple/plistValue.js";
import { decodeOpenStepPropertyList } from "./propertyListOpenStep.js";
import {
decodeOpenStepPropertyList,
startsOpenStepPropertyList,
} from "./propertyListOpenStep.js";
it.each([
"{ numeric = (42, -2.5, 0x10, YES); path = /a/b:c$; }",
@@ -94,3 +97,42 @@ it.each(["(x,", "{ key ="])(
);
},
);
it.each(["\n", "\r\n", "\r", "\u2028", "\u2029"])(
"ends OpenStep line comments at %j without dropping following values",
(newline) => {
const text =
"// leading" +
newline +
"{ kept = first; // inline" +
newline +
"hidden = second;\n items = (one, // array" +
newline +
"two,); }";
expect(
decodeOpenStepPropertyList(
"{ kept = first; // inline" + newline + "hidden = second;\n }",
),
).toEqual({ kept: "first", hidden: "second" });
expect(startsOpenStepPropertyList(text)).toBe(true);
expect(decodeOpenStepPropertyList(text)).toEqual({
kept: "first",
hidden: "second",
items: ["one", "two"],
});
},
);
it("does not treat nonterminating whitespace or quoted comment text as line ends", () => {
expect(
decodeOpenStepPropertyList(
'{ kept = first; // comment\vhidden = second;\n text = "// still literal\rtext"; }',
),
).toEqual({ kept: "first", text: "// still literal\rtext" });
expect(startsOpenStepPropertyList("// comment without a line end")).toBe(
false,
);
expect(() =>
decodeOpenStepPropertyList("// comment without a line end"),
).toThrow("Unexpected end of input");
});
+8 -2
View File
@@ -14,8 +14,14 @@ const skipTrivia = (text: string, start: number, strict = true): number => {
while (cursor < text.length) {
if (/\s/u.test(text[cursor]!)) cursor += 1;
else if (text.startsWith("//", cursor)) {
const end = text.indexOf("\n", cursor + 2);
cursor = end < 0 ? text.length : end + 1;
cursor += 2;
// CoreFoundation line comments end at LF, CR, LS or PS. Do not consume
// subsequent data merely because the producer used another line ending.
while (
cursor < text.length &&
!"\n\r\u2028\u2029".includes(text[cursor]!)
)
cursor += 1;
} else if (text.startsWith("/*", cursor)) {
const end = text.indexOf("*/", cursor + 2);
if (end < 0) {
+23
View File
@@ -970,3 +970,26 @@ it("retains JSON source spelling when XML integers collide after rounding", () =
expect.stringContaining("2 number(s)"),
]);
});
it.each(["\n", "\r\n", "\r", "\u2028", "\u2029"])(
"retains native OpenStep fields after line comments ending in %j",
(newline) => {
const source =
"// exported metadata" +
newline +
"{ CFBundleIdentifier = org.example.original; // note" +
newline +
"CFBundleName = Retained;\n }";
const result = parsePlistXmlSource(Buffer.from(source));
expect(result).toMatchObject({
ok: true,
value: {
value: {
CFBundleIdentifier: "org.example.original",
CFBundleName: "Retained",
},
bundle: { identifier: "org.example.original", name: "Retained" },
},
});
},
);