


















@@ -5,136 +5,136 @@
55 * with quote-stripping; malformed frontmatter doesn't crash the parser
66 * (soft-error policy: emit diagnostic, recover).
77 */
8-import { describe, expect, it } from 'vitest';
9-import { parseMd } from '../../parse.js';
8+import { describe, expect, it } from "vitest";
9+import { parseMd } from "../../parse.js";
101011-describe('wave-02 frontmatter-edges', () => {
12-it('FM-01 simple kv pairs', () => {
13-const { ast } = parseMd('---\nname: x\ndescription: y\n---\n');
11+describe("wave-02 frontmatter-edges", () => {
12+it("FM-01 simple kv pairs", () => {
13+const { ast } = parseMd("---\nname: x\ndescription: y\n---\n");
1414expect(ast.frontmatter.map((e) => [e.key, e.value])).toEqual([
15-['name', 'x'],
16-['description', 'y'],
15+["name", "x"],
16+["description", "y"],
1717]);
1818});
191920-it('FM-02 unclosed frontmatter emits diagnostic, treats as preamble', () => {
21-const { ast, diagnostics } = parseMd('---\nname: x\nno close fence\nbody\n');
22-expect(diagnostics.some((d) => d.code === 'OC_FRONTMATTER_UNCLOSED')).toBe(true);
20+it("FM-02 unclosed frontmatter emits diagnostic, treats as preamble", () => {
21+const { ast, diagnostics } = parseMd("---\nname: x\nno close fence\nbody\n");
22+expect(diagnostics.map((diagnostic) => diagnostic.code)).toContain("OC_FRONTMATTER_UNCLOSED");
2323expect(ast.frontmatter).toEqual([]);
2424});
252526-it('FM-03 empty frontmatter (just open + close)', () => {
27-const { ast } = parseMd('---\n---\n');
26+it("FM-03 empty frontmatter (just open + close)", () => {
27+const { ast } = parseMd("---\n---\n");
2828expect(ast.frontmatter).toEqual([]);
2929});
303031-it('FM-04 frontmatter only, file has no other content', () => {
32-const { ast } = parseMd('---\nk: v\n---\n');
33-expect(ast.frontmatter).toEqual([{ key: 'k', value: 'v', line: 2 }]);
34-expect(ast.preamble).toBe('');
31+it("FM-04 frontmatter only, file has no other content", () => {
32+const { ast } = parseMd("---\nk: v\n---\n");
33+expect(ast.frontmatter).toEqual([{ key: "k", value: "v", line: 2 }]);
34+expect(ast.preamble).toBe("");
3535expect(ast.blocks).toEqual([]);
3636});
373738-it('FM-05 double-quoted value', () => {
38+it("FM-05 double-quoted value", () => {
3939const { ast } = parseMd('---\ntitle: "Hello, world"\n---\n');
40-expect(ast.frontmatter[0]?.value).toBe('Hello, world');
40+expect(ast.frontmatter[0]?.value).toBe("Hello, world");
4141});
424243-it('FM-06 single-quoted value', () => {
43+it("FM-06 single-quoted value", () => {
4444const { ast } = parseMd("---\ntitle: 'Hello, world'\n---\n");
45-expect(ast.frontmatter[0]?.value).toBe('Hello, world');
45+expect(ast.frontmatter[0]?.value).toBe("Hello, world");
4646});
474748-it('FM-07 unquoted value with internal colons preserved', () => {
49-const { ast } = parseMd('---\nurl: https://example.com:443/p\n---\n');
50-expect(ast.frontmatter[0]?.value).toBe('https://example.com:443/p');
48+it("FM-07 unquoted value with internal colons preserved", () => {
49+const { ast } = parseMd("---\nurl: https://example.com:443/p\n---\n");
50+expect(ast.frontmatter[0]?.value).toBe("https://example.com:443/p");
5151});
525253-it('FM-08 empty value', () => {
54-const { ast } = parseMd('---\nk:\n---\n');
55-expect(ast.frontmatter[0]).toEqual({ key: 'k', value: '', line: 2 });
53+it("FM-08 empty value", () => {
54+const { ast } = parseMd("---\nk:\n---\n");
55+expect(ast.frontmatter[0]).toEqual({ key: "k", value: "", line: 2 });
5656});
575758-it('FM-09 value with leading/trailing whitespace trimmed', () => {
59-const { ast } = parseMd('---\nk: spaced \n---\n');
60-expect(ast.frontmatter[0]?.value).toBe('spaced');
58+it("FM-09 value with leading/trailing whitespace trimmed", () => {
59+const { ast } = parseMd("---\nk: spaced \n---\n");
60+expect(ast.frontmatter[0]?.value).toBe("spaced");
6161});
626263-it('FM-10 list-style continuations are silently dropped (substrate stays opinion-free)', () => {
64-const { ast } = parseMd('---\ntools:\n - gh\n - curl\n---\n');
63+it("FM-10 list-style continuations are silently dropped (substrate stays opinion-free)", () => {
64+const { ast } = parseMd("---\ntools:\n - gh\n - curl\n---\n");
6565// The `tools:` key has an empty inline value; the list continuation
6666// lines ` - gh` and ` - curl` don't match the kv regex and are
6767// skipped. Lint rules can do their own structural reading of
6868// frontmatter; the substrate does not.
69-expect(ast.frontmatter.map((e) => e.key)).toEqual(['tools']);
70-expect(ast.frontmatter[0]?.value).toBe('');
69+expect(ast.frontmatter.map((e) => e.key)).toEqual(["tools"]);
70+expect(ast.frontmatter[0]?.value).toBe("");
7171});
727273-it('FM-11 line numbers are 1-based and accurate', () => {
74-const { ast } = parseMd('---\nk1: v1\nk2: v2\nk3: v3\n---\n');
73+it("FM-11 line numbers are 1-based and accurate", () => {
74+const { ast } = parseMd("---\nk1: v1\nk2: v2\nk3: v3\n---\n");
7575expect(ast.frontmatter.map((e) => [e.key, e.line])).toEqual([
76-['k1', 2],
77-['k2', 3],
78-['k3', 4],
76+["k1", 2],
77+["k2", 3],
78+["k3", 4],
7979]);
8080});
818182-it('FM-12 dash-key allowed', () => {
83-const { ast } = parseMd('---\nuser-invocable: true\n---\n');
84-expect(ast.frontmatter[0]?.key).toBe('user-invocable');
82+it("FM-12 dash-key allowed", () => {
83+const { ast } = parseMd("---\nuser-invocable: true\n---\n");
84+expect(ast.frontmatter[0]?.key).toBe("user-invocable");
8585});
868687-it('FM-13 underscore-key allowed', () => {
88-const { ast } = parseMd('---\nparam_set: foo\n---\n');
89-expect(ast.frontmatter[0]?.key).toBe('param_set');
87+it("FM-13 underscore-key allowed", () => {
88+const { ast } = parseMd("---\nparam_set: foo\n---\n");
89+expect(ast.frontmatter[0]?.key).toBe("param_set");
9090});
919192-it('FM-14 number-only value preserved as string', () => {
93-const { ast } = parseMd('---\ntimeout: 15000\n---\n');
94-expect(ast.frontmatter[0]?.value).toBe('15000');
92+it("FM-14 number-only value preserved as string", () => {
93+const { ast } = parseMd("---\ntimeout: 15000\n---\n");
94+expect(ast.frontmatter[0]?.value).toBe("15000");
9595});
969697-it('FM-15 boolean-like value preserved as string', () => {
98-const { ast } = parseMd('---\nenabled: true\n---\n');
99-expect(ast.frontmatter[0]?.value).toBe('true');
97+it("FM-15 boolean-like value preserved as string", () => {
98+const { ast } = parseMd("---\nenabled: true\n---\n");
99+expect(ast.frontmatter[0]?.value).toBe("true");
100100});
101101102-it('FM-16 blank lines inside frontmatter are skipped', () => {
103-const { ast } = parseMd('---\n\nk1: v1\n\nk2: v2\n\n---\n');
104-expect(ast.frontmatter.map((e) => e.key)).toEqual(['k1', 'k2']);
102+it("FM-16 blank lines inside frontmatter are skipped", () => {
103+const { ast } = parseMd("---\n\nk1: v1\n\nk2: v2\n\n---\n");
104+expect(ast.frontmatter.map((e) => e.key)).toEqual(["k1", "k2"]);
105105});
106106107-it('FM-17 frontmatter with same key twice — both retained (no dedup)', () => {
107+it("FM-17 frontmatter with same key twice — both retained (no dedup)", () => {
108108// Substrate doesn't dedup; lint rules can flag duplicates if needed.
109-const { ast } = parseMd('---\nk: v1\nk: v2\n---\n');
109+const { ast } = parseMd("---\nk: v1\nk: v2\n---\n");
110110expect(ast.frontmatter).toEqual([
111-{ key: 'k', value: 'v1', line: 2 },
112-{ key: 'k', value: 'v2', line: 3 },
111+{ key: "k", value: "v1", line: 2 },
112+{ key: "k", value: "v2", line: 3 },
113113]);
114114});
115115116-it('FM-18 frontmatter must be at start — leading blank line breaks detection', () => {
117-const { ast } = parseMd('\n---\nk: v\n---\n');
116+it("FM-18 frontmatter must be at start — leading blank line breaks detection", () => {
117+const { ast } = parseMd("\n---\nk: v\n---\n");
118118expect(ast.frontmatter).toEqual([]);
119119});
120120121-it('FM-19 frontmatter must be at start — leading text breaks detection', () => {
122-const { ast } = parseMd('intro\n\n---\nk: v\n---\n');
121+it("FM-19 frontmatter must be at start — leading text breaks detection", () => {
122+const { ast } = parseMd("intro\n\n---\nk: v\n---\n");
123123expect(ast.frontmatter).toEqual([]);
124124});
125125126-it('FM-20 BOM before frontmatter open is tolerated', () => {
127-const { ast } = parseMd('---\nname: bom\n---\n');
128-expect(ast.frontmatter[0]?.value).toBe('bom');
126+it("FM-20 BOM before frontmatter open is tolerated", () => {
127+const { ast } = parseMd("---\nname: bom\n---\n");
128+expect(ast.frontmatter[0]?.value).toBe("bom");
129129});
130130131-it('FM-21 single-line file with `---` and `---` is empty frontmatter', () => {
132-const { ast } = parseMd('---\n---');
131+it("FM-21 single-line file with `---` and `---` is empty frontmatter", () => {
132+const { ast } = parseMd("---\n---");
133133expect(ast.frontmatter).toEqual([]);
134134});
135135136-it('FM-22 hash-prefixed lines skipped (not yaml comments — just don\'t match kv regex)', () => {
137-const { ast } = parseMd('---\n# comment\nk: v\n---\n');
138-expect(ast.frontmatter.map((e) => e.key)).toEqual(['k']);
136+it("FM-22 hash-prefixed lines skipped (not yaml comments — just don't match kv regex)", () => {
137+const { ast } = parseMd("---\n# comment\nk: v\n---\n");
138+expect(ast.frontmatter.map((e) => e.key)).toEqual(["k"]);
139139});
140140});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。