Skip to content

Commit 3ea81d1

Browse files
Update dependency js-yaml to v5 (#3289)
1 parent 41a05d2 commit 3ea81d1

4 files changed

Lines changed: 80 additions & 60 deletions

File tree

packages/lib-common/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@types/tinycolor2": "^1.4.6",
3030
"cross-spawn": "^7.0.6",
3131
"fast-check": "^4.8.0",
32-
"js-yaml": "^4.2.0",
32+
"js-yaml": "^5.2.1",
3333
"web-tree-sitter": "^0.26.10"
3434
}
3535
}
Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,82 @@
1-
// From https://github.com/nodeca/js-yaml/issues/586#issuecomment-814310104
21
// This file ensures that simple objects and arrays (ie without array or object
32
// children) will be serialized inline, and also ensures that "fullTargets" will be inlined as well
43

5-
import { dump, Type, DEFAULT_SCHEMA } from "js-yaml";
6-
import type { DumpOptions } from "js-yaml";
4+
import type { Document, MappingNode, Node, SequenceNode } from "js-yaml";
5+
import { CORE_SCHEMA, dump, visit, YAML11_SCHEMA } from "js-yaml";
76

8-
class CustomDump {
9-
constructor(
10-
private readonly data: unknown,
11-
private readonly opts: DumpOptions,
12-
) {}
13-
14-
represent(): string {
15-
let result = dump(this.data, { replacer, schema, ...this.opts });
16-
result = result.trim();
17-
if (result.includes("\n")) {
18-
result = `\n${result}`;
19-
}
20-
return result;
21-
}
7+
export function serialize(obj: unknown): string {
8+
return dump(toSerializableObject(obj), {
9+
noRefs: true,
10+
quoteStyle: "double",
11+
// CORE_SCHEMA preserves existing fixture output for numeric-looking strings
12+
// like `1_01_001`, which js-yaml's default schema would quote.
13+
schema: CORE_SCHEMA,
14+
transform: inlineSimpleCollections,
15+
});
2216
}
2317

24-
const customDumpType = new Type("!format", {
25-
kind: "scalar",
26-
resolve: () => false,
27-
instanceOf: CustomDump,
28-
represent: (d: unknown) => (d as CustomDump).represent(),
29-
});
30-
31-
const schema = DEFAULT_SCHEMA.extend({ implicit: [customDumpType] });
32-
33-
const isObject = (value: unknown): value is object =>
34-
typeof value === "object" && value != null;
35-
36-
function hasSimpleChildren(value: unknown): boolean {
37-
if (isObject(value)) {
38-
return Object.values(value).every(
39-
(value) => !isObject(value) && !Array.isArray(value),
40-
);
41-
}
18+
function toSerializableObject(value: unknown): unknown {
4219
if (Array.isArray(value)) {
43-
return value.every((value) => !isObject(value) && !Array.isArray(value));
20+
return value.map(toSerializableObject);
4421
}
45-
return false;
46-
}
4722

48-
function replacer(key: string, value: unknown): unknown {
49-
// top-level, don't change this
50-
if (key === "") {
23+
if (value == null || typeof value !== "object") {
5124
return value;
5225
}
5326

54-
if (hasSimpleChildren(value)) {
55-
return new CustomDump(value, { flowLevel: 0 });
56-
}
27+
return Object.fromEntries(
28+
Object.entries(value).map(([key, value]) => [
29+
key,
30+
toSerializableObject(value),
31+
]),
32+
);
33+
}
34+
35+
function inlineSimpleCollections(documents: Document[]): void {
36+
visit(documents, (node: Node, { depth, isKey, parent }) => {
37+
// Keep nested simple objects and arrays in flow style, eg `{line: 0}` and
38+
// `[default.a]`, while leaving top-level mappings in block style.
39+
if (depth > 0 && isCollectionNode(node) && hasOnlyScalarChildren(node)) {
40+
node.style.flow = true;
41+
}
5742

58-
// default
59-
return value;
43+
// Existing fixtures use single quotes for flow scalar values that need
44+
// quoting, eg `{character: ']'}`. Do not apply this to keys, non-string
45+
// scalars, block scalars, or multiline strings.
46+
if (
47+
!isKey &&
48+
parent != null &&
49+
parent.style.flow &&
50+
node.kind === "scalar" &&
51+
node.tag === "tag:yaml.org,2002:str" &&
52+
!node.value.includes("\n") &&
53+
scalarNeedsQuotesInFlow(node.value)
54+
) {
55+
node.style.singleQuoted = true;
56+
}
57+
});
6058
}
6159

62-
export function serialize(obj: unknown): string {
63-
const dump = new CustomDump(obj, {
64-
noRefs: true,
65-
quotingType: '"',
66-
})
67-
.represent()
68-
.trim();
69-
return `${dump}\n`;
60+
function isCollectionNode(node: Node): node is MappingNode | SequenceNode {
61+
return node.kind === "mapping" || node.kind === "sequence";
62+
}
63+
64+
function hasOnlyScalarChildren(node: MappingNode | SequenceNode): boolean {
65+
return node.kind === "mapping"
66+
? node.items.every((item) => item.value.kind === "scalar")
67+
: node.items.every((item) => item.kind === "scalar");
68+
}
69+
70+
function scalarNeedsQuotesInFlow(value: string): boolean {
71+
// Dump the value inside a flow array so js-yaml applies the same scalar
72+
// rules it would use for an inline collection. If the result starts with
73+
// `["`, the value cannot be emitted plainly in flow style, so we switch the
74+
// actual fixture value to single quotes to match the existing fixtures.
75+
return dump([value], {
76+
flowLevel: 0,
77+
quoteStyle: "double",
78+
// Use YAML 1.1 schema to preserve existing fixtures where legacy
79+
// boolean-like strings such as `y` and `n` are quoted in flow collections.
80+
schema: YAML11_SCHEMA,
81+
}).startsWith('["');
7082
}

packages/lib-node-common/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
"devDependencies": {
2222
"@types/js-yaml": "^4.0.9",
2323
"@types/lodash-es": "^4.17.12",
24-
"js-yaml": "^4.2.0"
24+
"js-yaml": "^5.2.1"
2525
}
2626
}

pnpm-lock.yaml

Lines changed: 12 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)