get-pfm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/cjs/__tests__/index.test.cjs +292 -0
- package/dist/cjs/__tests__/index.test.cjs.map +1 -0
- package/dist/cjs/__tests__/index.test.d.cts +4 -0
- package/dist/cjs/checksum.cjs +132 -0
- package/dist/cjs/checksum.cjs.map +1 -0
- package/dist/cjs/checksum.d.cts +35 -0
- package/dist/cjs/convert.cjs +120 -0
- package/dist/cjs/convert.cjs.map +1 -0
- package/dist/cjs/convert.d.cts +31 -0
- package/dist/cjs/index.cjs +45 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +26 -0
- package/dist/cjs/parser.cjs +195 -0
- package/dist/cjs/parser.cjs.map +1 -0
- package/dist/cjs/parser.d.cts +55 -0
- package/dist/cjs/serialize.cjs +146 -0
- package/dist/cjs/serialize.cjs.map +1 -0
- package/dist/cjs/serialize.d.cts +33 -0
- package/dist/cjs/types.cjs +29 -0
- package/dist/cjs/types.cjs.map +1 -0
- package/dist/cjs/types.d.cts +55 -0
- package/dist/esm/__tests__/conformance.test.d.ts +9 -0
- package/dist/esm/__tests__/conformance.test.d.ts.map +1 -0
- package/dist/esm/__tests__/conformance.test.js +170 -0
- package/dist/esm/__tests__/conformance.test.js.map +1 -0
- package/dist/esm/__tests__/index.test.d.ts +5 -0
- package/dist/esm/__tests__/index.test.d.ts.map +1 -0
- package/dist/esm/__tests__/index.test.js +287 -0
- package/dist/esm/__tests__/index.test.js.map +1 -0
- package/dist/esm/checksum.d.ts +36 -0
- package/dist/esm/checksum.d.ts.map +1 -0
- package/dist/esm/checksum.js +95 -0
- package/dist/esm/checksum.js.map +1 -0
- package/dist/esm/convert.d.ts +32 -0
- package/dist/esm/convert.d.ts.map +1 -0
- package/dist/esm/convert.js +115 -0
- package/dist/esm/convert.js.map +1 -0
- package/dist/esm/index.d.ts +27 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +30 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/parser.d.ts +56 -0
- package/dist/esm/parser.d.ts.map +1 -0
- package/dist/esm/parser.js +189 -0
- package/dist/esm/parser.js.map +1 -0
- package/dist/esm/serialize.d.ts +34 -0
- package/dist/esm/serialize.d.ts.map +1 -0
- package/dist/esm/serialize.js +143 -0
- package/dist/esm/serialize.js.map +1 -0
- package/dist/esm/types.d.ts +56 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +26 -0
- package/dist/esm/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PFM Serializer — Write PFM documents back to text.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Python PFMWriter logic:
|
|
5
|
+
* - Magic line with format version
|
|
6
|
+
* - Meta section with key: value pairs
|
|
7
|
+
* - Index section with byte offsets
|
|
8
|
+
* - Content sections with escape of #@ and #! prefixes
|
|
9
|
+
* - EOF marker
|
|
10
|
+
*/
|
|
11
|
+
import type { PFMDocument } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Serialize a PFMDocument to .pfm text format.
|
|
14
|
+
*
|
|
15
|
+
* Computes checksum and byte-offset index automatically.
|
|
16
|
+
*
|
|
17
|
+
* @param doc - The document to serialize.
|
|
18
|
+
* @returns The complete .pfm file content as a string.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { serialize } from 'pfm';
|
|
23
|
+
*
|
|
24
|
+
* const text = await serialize({
|
|
25
|
+
* formatVersion: '1.0',
|
|
26
|
+
* isStream: false,
|
|
27
|
+
* meta: { id: 'abc', agent: 'my-agent', model: 'gpt-4' },
|
|
28
|
+
* sections: [{ name: 'content', content: 'Hello, world!' }],
|
|
29
|
+
* });
|
|
30
|
+
* fs.writeFileSync('output.pfm', text);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function serialize(doc: PFMDocument): Promise<string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PFM Types — TypeScript definitions for the PFM file format.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SECTION_TYPES = exports.META_FIELDS = void 0;
|
|
7
|
+
/** Known standard metadata field descriptions. */
|
|
8
|
+
exports.META_FIELDS = {
|
|
9
|
+
id: 'Unique document identifier (UUID v4)',
|
|
10
|
+
agent: 'Name/identifier of the generating agent',
|
|
11
|
+
model: 'Model ID used for generation',
|
|
12
|
+
created: 'ISO-8601 creation timestamp',
|
|
13
|
+
checksum: 'SHA-256 hash of all content sections',
|
|
14
|
+
parent: 'ID of parent .pfm document (for chains)',
|
|
15
|
+
tags: 'Comma-separated tags',
|
|
16
|
+
version: 'Document version (user-defined)',
|
|
17
|
+
};
|
|
18
|
+
/** Known standard section type descriptions. */
|
|
19
|
+
exports.SECTION_TYPES = {
|
|
20
|
+
content: 'Primary output content from the agent',
|
|
21
|
+
chain: 'Prompt chain / conversation that produced this output',
|
|
22
|
+
tools: 'Tool calls made during generation',
|
|
23
|
+
artifacts: 'Generated code, files, or structured data',
|
|
24
|
+
reasoning: 'Agent reasoning / chain-of-thought',
|
|
25
|
+
context: 'Context window snapshot at generation time',
|
|
26
|
+
errors: 'Errors encountered during generation',
|
|
27
|
+
metrics: 'Performance metrics (tokens, latency, cost)',
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAsDH,kDAAkD;AACrC,QAAA,WAAW,GAA2B;IACjD,EAAE,EAAE,sCAAsC;IAC1C,KAAK,EAAE,yCAAyC;IAChD,KAAK,EAAE,8BAA8B;IACrC,OAAO,EAAE,6BAA6B;IACtC,QAAQ,EAAE,sCAAsC;IAChD,MAAM,EAAE,yCAAyC;IACjD,IAAI,EAAE,sBAAsB;IAC5B,OAAO,EAAE,iCAAiC;CAC3C,CAAC;AAEF,gDAAgD;AACnC,QAAA,aAAa,GAA2B;IACnD,OAAO,EAAE,uCAAuC;IAChD,KAAK,EAAE,uDAAuD;IAC9D,KAAK,EAAE,mCAAmC;IAC1C,SAAS,EAAE,2CAA2C;IACtD,SAAS,EAAE,oCAAoC;IAC/C,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,sCAAsC;IAC9C,OAAO,EAAE,6CAA6C;CACvD,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PFM Types — TypeScript definitions for the PFM file format.
|
|
3
|
+
*/
|
|
4
|
+
/** A single section in a PFM document. */
|
|
5
|
+
export interface PFMSection {
|
|
6
|
+
/** Section name (e.g. "content", "chain", "tools"). */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Section content (unescaped). */
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
11
|
+
/** Parsed metadata from a PFM document. */
|
|
12
|
+
export interface PFMMeta {
|
|
13
|
+
/** Unique document identifier (UUID v4). */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Name/identifier of the generating agent. */
|
|
16
|
+
agent?: string;
|
|
17
|
+
/** Model ID used for generation. */
|
|
18
|
+
model?: string;
|
|
19
|
+
/** ISO-8601 creation timestamp. */
|
|
20
|
+
created?: string;
|
|
21
|
+
/** SHA-256 hash of all content sections. */
|
|
22
|
+
checksum?: string;
|
|
23
|
+
/** ID of parent .pfm document (for chains). */
|
|
24
|
+
parent?: string;
|
|
25
|
+
/** Comma-separated tags. */
|
|
26
|
+
tags?: string;
|
|
27
|
+
/** Document version (user-defined). */
|
|
28
|
+
version?: string;
|
|
29
|
+
/** Any additional custom metadata fields. */
|
|
30
|
+
[key: string]: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** A fully parsed PFM document. */
|
|
33
|
+
export interface PFMDocument {
|
|
34
|
+
/** Format version (e.g. "1.0"). */
|
|
35
|
+
formatVersion: string;
|
|
36
|
+
/** Whether this is a streaming-mode document. */
|
|
37
|
+
isStream: boolean;
|
|
38
|
+
/** Document metadata. */
|
|
39
|
+
meta: PFMMeta;
|
|
40
|
+
/** Content sections (in order). */
|
|
41
|
+
sections: PFMSection[];
|
|
42
|
+
}
|
|
43
|
+
/** Result of checksum validation. */
|
|
44
|
+
export interface ChecksumResult {
|
|
45
|
+
/** Whether the checksum is valid. */
|
|
46
|
+
valid: boolean;
|
|
47
|
+
/** Expected checksum from metadata (empty string if missing). */
|
|
48
|
+
expected: string;
|
|
49
|
+
/** Computed checksum from section contents. */
|
|
50
|
+
computed: string;
|
|
51
|
+
}
|
|
52
|
+
/** Known standard metadata field descriptions. */
|
|
53
|
+
export declare const META_FIELDS: Record<string, string>;
|
|
54
|
+
/** Known standard section type descriptions. */
|
|
55
|
+
export declare const SECTION_TYPES: Record<string, string>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PFM Cross-Implementation Conformance Tests
|
|
3
|
+
*
|
|
4
|
+
* Loads shared test vectors from tests/conformance/vectors.json
|
|
5
|
+
* and runs them against the JS parser/serializer.
|
|
6
|
+
* Both Python and JS implementations MUST pass all of these.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=conformance.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/conformance.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PFM Cross-Implementation Conformance Tests
|
|
3
|
+
*
|
|
4
|
+
* Loads shared test vectors from tests/conformance/vectors.json
|
|
5
|
+
* and runs them against the JS parser/serializer.
|
|
6
|
+
* Both Python and JS implementations MUST pass all of these.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it } from 'node:test';
|
|
9
|
+
import assert from 'node:assert/strict';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { resolve, dirname } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { parse, serialize, computeChecksum } from '../index.js';
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
// Find vectors.json by walking up to the pfm-js dir, then up to repo root
|
|
16
|
+
// Works from both src/__tests__/ (2 up) and dist/esm/__tests__/ (3 up)
|
|
17
|
+
function findVectors() {
|
|
18
|
+
for (let levels = 2; levels <= 4; levels++) {
|
|
19
|
+
const candidate = resolve(__dirname, ...Array(levels).fill('..'), 'tests', 'conformance', 'vectors.json');
|
|
20
|
+
try {
|
|
21
|
+
readFileSync(candidate);
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
catch { /* next */ }
|
|
25
|
+
}
|
|
26
|
+
throw new Error('vectors.json not found');
|
|
27
|
+
}
|
|
28
|
+
const VECTORS_PATH = findVectors();
|
|
29
|
+
const vectors = JSON.parse(readFileSync(VECTORS_PATH, 'utf-8'));
|
|
30
|
+
// ================================================================
|
|
31
|
+
// Escape Round-Trip Tests
|
|
32
|
+
// ================================================================
|
|
33
|
+
describe('conformance: escape round-trip', () => {
|
|
34
|
+
for (const c of vectors.escape_roundtrip.cases) {
|
|
35
|
+
it(`[${c.desc}] serialize -> parse preserves content`, async () => {
|
|
36
|
+
// Create a doc with this content, serialize, parse back
|
|
37
|
+
const doc = {
|
|
38
|
+
formatVersion: '1.0',
|
|
39
|
+
isStream: false,
|
|
40
|
+
meta: { agent: 'conformance-test' },
|
|
41
|
+
sections: [{ name: 'content', content: c.input }],
|
|
42
|
+
};
|
|
43
|
+
const text = await serialize(doc);
|
|
44
|
+
const restored = parse(text);
|
|
45
|
+
assert.equal(restored.sections[0].content, c.input, `Round-trip failed for ${JSON.stringify(c.input)}`);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
it('multi-roundtrip stability (10x escape/unescape)', async () => {
|
|
49
|
+
const dangerous = ['#@section', '#!PFM/1.0', '#!END', '\\#@marker', '\\\\#@deep'];
|
|
50
|
+
for (const original of dangerous) {
|
|
51
|
+
// Escape 10 times by nesting in serialize/parse
|
|
52
|
+
let content = original;
|
|
53
|
+
for (let i = 0; i < 10; i++) {
|
|
54
|
+
const doc = {
|
|
55
|
+
formatVersion: '1.0',
|
|
56
|
+
isStream: false,
|
|
57
|
+
meta: { agent: 'test' },
|
|
58
|
+
sections: [{ name: 'content', content }],
|
|
59
|
+
};
|
|
60
|
+
const text = await serialize(doc);
|
|
61
|
+
const restored = parse(text);
|
|
62
|
+
// Each round-trip should be identity
|
|
63
|
+
assert.equal(restored.sections[0].content, content, `Round ${i} failed for ${JSON.stringify(original)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
// ================================================================
|
|
69
|
+
// Parse/Serialize Round-Trip Tests
|
|
70
|
+
// ================================================================
|
|
71
|
+
describe('conformance: parse/serialize round-trip', () => {
|
|
72
|
+
for (const c of vectors.parse_serialize_roundtrip.cases) {
|
|
73
|
+
it(`[${c.desc}]`, async () => {
|
|
74
|
+
const doc = {
|
|
75
|
+
formatVersion: '1.0',
|
|
76
|
+
isStream: false,
|
|
77
|
+
meta: c.meta,
|
|
78
|
+
sections: c.sections.map((s) => ({
|
|
79
|
+
name: s.name,
|
|
80
|
+
content: s.content,
|
|
81
|
+
})),
|
|
82
|
+
};
|
|
83
|
+
const text = await serialize(doc);
|
|
84
|
+
const restored = parse(text);
|
|
85
|
+
assert.equal(restored.sections.length, doc.sections.length, `Section count mismatch`);
|
|
86
|
+
for (let i = 0; i < doc.sections.length; i++) {
|
|
87
|
+
assert.equal(restored.sections[i].name, doc.sections[i].name, `Name mismatch at ${i}`);
|
|
88
|
+
assert.equal(restored.sections[i].content, doc.sections[i].content, `Content mismatch in '${doc.sections[i].name}'`);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
// ================================================================
|
|
94
|
+
// Checksum Tests
|
|
95
|
+
// ================================================================
|
|
96
|
+
describe('conformance: checksum', () => {
|
|
97
|
+
for (const c of vectors.checksum.cases) {
|
|
98
|
+
it(`[${c.desc}]`, async () => {
|
|
99
|
+
const sections = c.sections.map((s) => ({
|
|
100
|
+
name: s.name,
|
|
101
|
+
content: s.content,
|
|
102
|
+
}));
|
|
103
|
+
const hash = await computeChecksum(sections);
|
|
104
|
+
assert.equal(hash, c.expected_checksum, `Checksum mismatch`);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// ================================================================
|
|
109
|
+
// Adversarial Tests
|
|
110
|
+
// ================================================================
|
|
111
|
+
describe('conformance: adversarial', () => {
|
|
112
|
+
it('content with all PFM markers survives round-trip', async () => {
|
|
113
|
+
const dangerous = 'Line before\n#@fake-section\n#!PFM/1.0\n#!END\n\\#@escaped\n\\\\#@double\nLine after';
|
|
114
|
+
const doc = {
|
|
115
|
+
formatVersion: '1.0',
|
|
116
|
+
isStream: false,
|
|
117
|
+
meta: { agent: 'test' },
|
|
118
|
+
sections: [{ name: 'content', content: dangerous }],
|
|
119
|
+
};
|
|
120
|
+
const text = await serialize(doc);
|
|
121
|
+
const restored = parse(text);
|
|
122
|
+
assert.equal(restored.sections[0].content, dangerous);
|
|
123
|
+
});
|
|
124
|
+
it('unicode content round-trips', async () => {
|
|
125
|
+
const content = 'Hello 世界 🌍 مرحبا Ñoño → résumé';
|
|
126
|
+
const doc = {
|
|
127
|
+
formatVersion: '1.0',
|
|
128
|
+
isStream: false,
|
|
129
|
+
meta: { agent: 'test' },
|
|
130
|
+
sections: [{ name: 'content', content }],
|
|
131
|
+
};
|
|
132
|
+
const text = await serialize(doc);
|
|
133
|
+
const restored = parse(text);
|
|
134
|
+
assert.equal(restored.sections[0].content, content);
|
|
135
|
+
});
|
|
136
|
+
it('empty section round-trips', async () => {
|
|
137
|
+
const doc = {
|
|
138
|
+
formatVersion: '1.0',
|
|
139
|
+
isStream: false,
|
|
140
|
+
meta: { agent: 'test' },
|
|
141
|
+
sections: [
|
|
142
|
+
{ name: 'content', content: '' },
|
|
143
|
+
{ name: 'chain', content: 'data' },
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
const text = await serialize(doc);
|
|
147
|
+
const restored = parse(text);
|
|
148
|
+
assert.equal(restored.sections[0].content, '');
|
|
149
|
+
assert.equal(restored.sections[1].content, 'data');
|
|
150
|
+
});
|
|
151
|
+
it('many sections round-trip', async () => {
|
|
152
|
+
const sections = Array.from({ length: 50 }, (_, i) => ({
|
|
153
|
+
name: `section${String(i).padStart(3, '0')}`,
|
|
154
|
+
content: `content-${i}`,
|
|
155
|
+
}));
|
|
156
|
+
const doc = {
|
|
157
|
+
formatVersion: '1.0',
|
|
158
|
+
isStream: false,
|
|
159
|
+
meta: { agent: 'test' },
|
|
160
|
+
sections,
|
|
161
|
+
};
|
|
162
|
+
const text = await serialize(doc);
|
|
163
|
+
const restored = parse(text);
|
|
164
|
+
assert.equal(restored.sections.length, 50);
|
|
165
|
+
for (let i = 0; i < 50; i++) {
|
|
166
|
+
assert.equal(restored.sections[i].content, `content-${i}`);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=conformance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.test.js","sourceRoot":"","sources":["../../../src/__tests__/conformance.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAc,eAAe,EAAE,MAAM,aAAa,CAAC;AAE5E,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,0EAA0E;AAC1E,uEAAuE;AACvE,SAAS,WAAW;IAClB,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;QAC1G,IAAI,CAAC;YAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAAC,OAAO,SAAS,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAC5C,CAAC;AACD,MAAM,YAAY,GAAG,WAAW,EAAE,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhE,mEAAmE;AACnE,0BAA0B;AAC1B,mEAAmE;AAEnE,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC/C,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,wCAAwC,EAAE,KAAK,IAAI,EAAE;YAChE,wDAAwD;YACxD,MAAM,GAAG,GAAG;gBACV,aAAa,EAAE,KAAK;gBACpB,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE;gBACnC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;aAClD,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,CAAC,KAAK,CACV,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAC5B,CAAC,CAAC,KAAK,EACP,yBAAyB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CACnD,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,SAAS,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;QAClF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,gDAAgD;YAChD,IAAI,OAAO,GAAG,QAAQ,CAAC;YACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG;oBACV,aAAa,EAAE,KAAK;oBACpB,QAAQ,EAAE,KAAK;oBACf,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;oBACvB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;iBACzC,CAAC;gBACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC7B,qCAAqC;gBACrC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC3G,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,mEAAmE;AACnE,mCAAmC;AACnC,mEAAmE;AAEnE,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,yBAAyB,CAAC,KAAK,EAAE,CAAC;QACxD,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,KAAK,IAAI,EAAE;YAC3B,MAAM,GAAG,GAAG;gBACV,aAAa,EAAE,KAAK;gBACpB,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAoC,EAAE,EAAE,CAAC,CAAC;oBAClE,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;iBACnB,CAAC,CAAC;aACJ,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,CAAC,KAAK,CACV,QAAQ,CAAC,QAAQ,CAAC,MAAM,EACxB,GAAG,CAAC,QAAQ,CAAC,MAAM,EACnB,wBAAwB,CACzB,CAAC;YACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,CAAC,CAAC;gBACvF,MAAM,CAAC,KAAK,CACV,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAC5B,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EACvB,wBAAwB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAChD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mEAAmE;AACnE,iBAAiB;AACjB,mEAAmE;AAEnE,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACvC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,EAAE,KAAK,IAAI,EAAE;YAC3B,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAoC,EAAE,EAAE,CAAC,CAAC;gBACzE,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;aACnB,CAAC,CAAC,CAAC;YACJ,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mEAAmE;AACnE,oBAAoB;AACpB,mEAAmE;AAEnE,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,SAAS,GACb,sFAAsF,CAAC;QACzF,MAAM,GAAG,GAAG;YACV,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;YACvB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;SACpD,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,OAAO,GAAG,iCAAiC,CAAC;QAClD,MAAM,GAAG,GAAG;YACV,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;YACvB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;SACzC,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,GAAG,GAAG;YACV,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;YACvB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;gBAChC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE;aACnC;SACF,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YACrD,IAAI,EAAE,UAAU,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YAC5C,OAAO,EAAE,WAAW,CAAC,EAAE;SACxB,CAAC,CAAC,CAAC;QACJ,MAAM,GAAG,GAAG;YACV,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;YACvB,QAAQ;SACT,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PFM npm package tests — uses Node.js built-in test runner.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
import { parse, isPFM, getSection, getSections, computeChecksum, validateChecksum, toJSON, fromJSON, toMarkdown, serialize, META_FIELDS, SECTION_TYPES, } from '../index.js';
|
|
7
|
+
const EXAMPLE_PFM = `#!PFM/1.0
|
|
8
|
+
#@meta
|
|
9
|
+
id: abc-123
|
|
10
|
+
agent: test-agent
|
|
11
|
+
model: test-model
|
|
12
|
+
created: 2026-01-01T00:00:00Z
|
|
13
|
+
checksum: placeholder
|
|
14
|
+
tags: test,demo
|
|
15
|
+
version: 1.0
|
|
16
|
+
#@index
|
|
17
|
+
content 200 13
|
|
18
|
+
chain 220 10
|
|
19
|
+
#@content
|
|
20
|
+
Hello, world!
|
|
21
|
+
#@chain
|
|
22
|
+
Some chain
|
|
23
|
+
#!END
|
|
24
|
+
`;
|
|
25
|
+
// ================================================================
|
|
26
|
+
// Parser
|
|
27
|
+
// ================================================================
|
|
28
|
+
describe('parse', () => {
|
|
29
|
+
it('parses magic line and format version', () => {
|
|
30
|
+
const doc = parse(EXAMPLE_PFM);
|
|
31
|
+
assert.equal(doc.formatVersion, '1.0');
|
|
32
|
+
assert.equal(doc.isStream, false);
|
|
33
|
+
});
|
|
34
|
+
it('parses metadata fields', () => {
|
|
35
|
+
const doc = parse(EXAMPLE_PFM);
|
|
36
|
+
assert.equal(doc.meta.id, 'abc-123');
|
|
37
|
+
assert.equal(doc.meta.agent, 'test-agent');
|
|
38
|
+
assert.equal(doc.meta.model, 'test-model');
|
|
39
|
+
assert.equal(doc.meta.tags, 'test,demo');
|
|
40
|
+
});
|
|
41
|
+
it('parses sections in order', () => {
|
|
42
|
+
const doc = parse(EXAMPLE_PFM);
|
|
43
|
+
assert.equal(doc.sections.length, 2);
|
|
44
|
+
assert.equal(doc.sections[0].name, 'content');
|
|
45
|
+
assert.equal(doc.sections[0].content, 'Hello, world!');
|
|
46
|
+
assert.equal(doc.sections[1].name, 'chain');
|
|
47
|
+
assert.equal(doc.sections[1].content, 'Some chain');
|
|
48
|
+
});
|
|
49
|
+
it('handles stream mode flag', () => {
|
|
50
|
+
const stream = '#!PFM/1.0:STREAM\n#@meta\nagent: x\n#@content\nhi\n#!END\n';
|
|
51
|
+
const doc = parse(stream);
|
|
52
|
+
assert.equal(doc.isStream, true);
|
|
53
|
+
assert.equal(doc.formatVersion, '1.0');
|
|
54
|
+
});
|
|
55
|
+
it('unescapes content lines', () => {
|
|
56
|
+
const pfm = '#!PFM/1.0\n#@meta\n#@content\nline1\n\\#@fake\n\\#!END\nline4\n#!END\n';
|
|
57
|
+
const doc = parse(pfm);
|
|
58
|
+
assert.equal(doc.sections[0].content, 'line1\n#@fake\n#!END\nline4');
|
|
59
|
+
});
|
|
60
|
+
it('handles missing EOF marker', () => {
|
|
61
|
+
const noeof = '#!PFM/1.0\n#@meta\nagent: x\n#@content\nhello';
|
|
62
|
+
const doc = parse(noeof);
|
|
63
|
+
assert.equal(doc.sections.length, 1);
|
|
64
|
+
assert.equal(doc.sections[0].content, 'hello');
|
|
65
|
+
});
|
|
66
|
+
it('handles empty sections', () => {
|
|
67
|
+
const pfm = '#!PFM/1.0\n#@meta\n#@content\n#@chain\ndata\n#!END\n';
|
|
68
|
+
const doc = parse(pfm);
|
|
69
|
+
assert.equal(doc.sections.length, 2);
|
|
70
|
+
assert.equal(doc.sections[0].name, 'content');
|
|
71
|
+
assert.equal(doc.sections[0].content, '');
|
|
72
|
+
assert.equal(doc.sections[1].content, 'data');
|
|
73
|
+
});
|
|
74
|
+
it('handles multiline content', () => {
|
|
75
|
+
const pfm = '#!PFM/1.0\n#@meta\n#@content\nline1\nline2\nline3\n#!END\n';
|
|
76
|
+
const doc = parse(pfm);
|
|
77
|
+
assert.equal(doc.sections[0].content, 'line1\nline2\nline3');
|
|
78
|
+
});
|
|
79
|
+
it('handles custom meta fields', () => {
|
|
80
|
+
const pfm = '#!PFM/1.0\n#@meta\nagent: x\ncustom_field: custom_value\n#@content\nhi\n#!END\n';
|
|
81
|
+
const doc = parse(pfm);
|
|
82
|
+
assert.equal(doc.meta.custom_field, 'custom_value');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
// ================================================================
|
|
86
|
+
// isPFM
|
|
87
|
+
// ================================================================
|
|
88
|
+
describe('isPFM', () => {
|
|
89
|
+
it('returns true for PFM text', () => {
|
|
90
|
+
assert.equal(isPFM('#!PFM/1.0\n'), true);
|
|
91
|
+
assert.equal(isPFM('#!PFM/1.0:STREAM\n'), true);
|
|
92
|
+
});
|
|
93
|
+
it('returns false for non-PFM text', () => {
|
|
94
|
+
assert.equal(isPFM('not a pfm file'), false);
|
|
95
|
+
assert.equal(isPFM(''), false);
|
|
96
|
+
assert.equal(isPFM('{"json": true}'), false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
// ================================================================
|
|
100
|
+
// getSection / getSections
|
|
101
|
+
// ================================================================
|
|
102
|
+
describe('getSection', () => {
|
|
103
|
+
const doc = parse(EXAMPLE_PFM);
|
|
104
|
+
it('returns section content by name', () => {
|
|
105
|
+
assert.equal(getSection(doc, 'content'), 'Hello, world!');
|
|
106
|
+
assert.equal(getSection(doc, 'chain'), 'Some chain');
|
|
107
|
+
});
|
|
108
|
+
it('returns undefined for missing section', () => {
|
|
109
|
+
assert.equal(getSection(doc, 'nope'), undefined);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('getSections', () => {
|
|
113
|
+
it('returns all sections with given name', () => {
|
|
114
|
+
const pfm = '#!PFM/1.0\n#@meta\n#@content\nfirst\n#@content\nsecond\n#!END\n';
|
|
115
|
+
const doc = parse(pfm);
|
|
116
|
+
const contents = getSections(doc, 'content');
|
|
117
|
+
assert.equal(contents.length, 2);
|
|
118
|
+
assert.equal(contents[0], 'first');
|
|
119
|
+
assert.equal(contents[1], 'second');
|
|
120
|
+
});
|
|
121
|
+
it('returns empty array for missing section', () => {
|
|
122
|
+
const doc = parse(EXAMPLE_PFM);
|
|
123
|
+
assert.deepEqual(getSections(doc, 'nope'), []);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
// ================================================================
|
|
127
|
+
// Checksum
|
|
128
|
+
// ================================================================
|
|
129
|
+
describe('computeChecksum', () => {
|
|
130
|
+
it('returns hex SHA-256 digest', async () => {
|
|
131
|
+
const hash = await computeChecksum([{ name: 'content', content: 'hello' }]);
|
|
132
|
+
assert.equal(typeof hash, 'string');
|
|
133
|
+
assert.equal(hash.length, 64);
|
|
134
|
+
assert.match(hash, /^[0-9a-f]{64}$/);
|
|
135
|
+
});
|
|
136
|
+
it('is deterministic', async () => {
|
|
137
|
+
const sections = [{ name: 'a', content: 'test' }];
|
|
138
|
+
const h1 = await computeChecksum(sections);
|
|
139
|
+
const h2 = await computeChecksum(sections);
|
|
140
|
+
assert.equal(h1, h2);
|
|
141
|
+
});
|
|
142
|
+
it('changes with different content', async () => {
|
|
143
|
+
const h1 = await computeChecksum([{ name: 'a', content: 'hello' }]);
|
|
144
|
+
const h2 = await computeChecksum([{ name: 'a', content: 'world' }]);
|
|
145
|
+
assert.notEqual(h1, h2);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('validateChecksum', () => {
|
|
149
|
+
it('returns valid=false when no checksum in meta', async () => {
|
|
150
|
+
const doc = parse('#!PFM/1.0\n#@meta\nagent: x\n#@content\nhi\n#!END\n');
|
|
151
|
+
const result = await validateChecksum(doc);
|
|
152
|
+
assert.equal(result.valid, false);
|
|
153
|
+
});
|
|
154
|
+
it('validates a correct checksum', async () => {
|
|
155
|
+
// First compute what the checksum should be
|
|
156
|
+
const hash = await computeChecksum([{ name: 'content', content: 'hi' }]);
|
|
157
|
+
const pfm = `#!PFM/1.0\n#@meta\nchecksum: ${hash}\n#@content\nhi\n#!END\n`;
|
|
158
|
+
const doc = parse(pfm);
|
|
159
|
+
const result = await validateChecksum(doc);
|
|
160
|
+
assert.equal(result.valid, true);
|
|
161
|
+
assert.equal(result.expected, hash);
|
|
162
|
+
assert.equal(result.computed, hash);
|
|
163
|
+
});
|
|
164
|
+
it('rejects incorrect checksum', async () => {
|
|
165
|
+
const pfm = '#!PFM/1.0\n#@meta\nchecksum: deadbeef\n#@content\nhi\n#!END\n';
|
|
166
|
+
const doc = parse(pfm);
|
|
167
|
+
const result = await validateChecksum(doc);
|
|
168
|
+
assert.equal(result.valid, false);
|
|
169
|
+
assert.equal(result.expected, 'deadbeef');
|
|
170
|
+
assert.notEqual(result.computed, 'deadbeef');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
// ================================================================
|
|
174
|
+
// Converters
|
|
175
|
+
// ================================================================
|
|
176
|
+
describe('toJSON / fromJSON', () => {
|
|
177
|
+
it('round-trips through JSON', () => {
|
|
178
|
+
const doc = parse(EXAMPLE_PFM);
|
|
179
|
+
const json = toJSON(doc);
|
|
180
|
+
const parsed = JSON.parse(json);
|
|
181
|
+
assert.equal(parsed.pfm_version, '1.0');
|
|
182
|
+
assert.equal(parsed.meta.agent, 'test-agent');
|
|
183
|
+
assert.equal(parsed.sections.length, 2);
|
|
184
|
+
assert.equal(parsed.sections[0].name, 'content');
|
|
185
|
+
});
|
|
186
|
+
it('fromJSON restores document structure', () => {
|
|
187
|
+
const doc = parse(EXAMPLE_PFM);
|
|
188
|
+
const json = toJSON(doc);
|
|
189
|
+
const restored = fromJSON(json);
|
|
190
|
+
assert.equal(restored.formatVersion, '1.0');
|
|
191
|
+
assert.equal(restored.meta.agent, 'test-agent');
|
|
192
|
+
assert.equal(restored.sections.length, 2);
|
|
193
|
+
assert.equal(restored.sections[0].content, 'Hello, world!');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('toMarkdown', () => {
|
|
197
|
+
it('produces markdown with frontmatter', () => {
|
|
198
|
+
const doc = parse(EXAMPLE_PFM);
|
|
199
|
+
const md = toMarkdown(doc);
|
|
200
|
+
assert.ok(md.startsWith('---\n'));
|
|
201
|
+
assert.ok(md.includes('agent: test-agent'));
|
|
202
|
+
assert.ok(md.includes('## content'));
|
|
203
|
+
assert.ok(md.includes('Hello, world!'));
|
|
204
|
+
assert.ok(md.includes('## chain'));
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// ================================================================
|
|
208
|
+
// Serialize
|
|
209
|
+
// ================================================================
|
|
210
|
+
describe('serialize', () => {
|
|
211
|
+
it('produces valid PFM text', async () => {
|
|
212
|
+
const doc = {
|
|
213
|
+
formatVersion: '1.0',
|
|
214
|
+
isStream: false,
|
|
215
|
+
meta: { agent: 'test', model: 'test-model' },
|
|
216
|
+
sections: [{ name: 'content', content: 'Hello!' }],
|
|
217
|
+
};
|
|
218
|
+
const text = await serialize(doc);
|
|
219
|
+
assert.ok(text.startsWith('#!PFM/1.0\n'));
|
|
220
|
+
assert.ok(text.includes('#@meta\n'));
|
|
221
|
+
assert.ok(text.includes('agent: test\n'));
|
|
222
|
+
assert.ok(text.includes('#@content\n'));
|
|
223
|
+
assert.ok(text.includes('Hello!\n'));
|
|
224
|
+
assert.ok(text.includes('#!END\n'));
|
|
225
|
+
assert.ok(text.includes('#@index\n'));
|
|
226
|
+
});
|
|
227
|
+
it('round-trips parse -> serialize -> parse', async () => {
|
|
228
|
+
const original = {
|
|
229
|
+
formatVersion: '1.0',
|
|
230
|
+
isStream: false,
|
|
231
|
+
meta: { agent: 'roundtrip', model: 'gpt-4' },
|
|
232
|
+
sections: [
|
|
233
|
+
{ name: 'content', content: 'Line one\nLine two' },
|
|
234
|
+
{ name: 'chain', content: 'User: hello\nAgent: hi' },
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
const text = await serialize(original);
|
|
238
|
+
const restored = parse(text);
|
|
239
|
+
assert.equal(restored.meta.agent, 'roundtrip');
|
|
240
|
+
assert.equal(restored.sections.length, 2);
|
|
241
|
+
assert.equal(restored.sections[0].content, 'Line one\nLine two');
|
|
242
|
+
assert.equal(restored.sections[1].content, 'User: hello\nAgent: hi');
|
|
243
|
+
});
|
|
244
|
+
it('serialized checksum validates', async () => {
|
|
245
|
+
const doc = {
|
|
246
|
+
formatVersion: '1.0',
|
|
247
|
+
isStream: false,
|
|
248
|
+
meta: { agent: 'test' },
|
|
249
|
+
sections: [{ name: 'content', content: 'Check me' }],
|
|
250
|
+
};
|
|
251
|
+
const text = await serialize(doc);
|
|
252
|
+
const parsed = parse(text);
|
|
253
|
+
const result = await validateChecksum(parsed);
|
|
254
|
+
assert.equal(result.valid, true);
|
|
255
|
+
});
|
|
256
|
+
it('escapes dangerous content lines', async () => {
|
|
257
|
+
const doc = {
|
|
258
|
+
formatVersion: '1.0',
|
|
259
|
+
isStream: false,
|
|
260
|
+
meta: {},
|
|
261
|
+
sections: [{ name: 'content', content: '#@fake\n#!END\nnormal line' }],
|
|
262
|
+
};
|
|
263
|
+
const text = await serialize(doc);
|
|
264
|
+
assert.ok(text.includes('\\#@fake'));
|
|
265
|
+
assert.ok(text.includes('\\#!END'));
|
|
266
|
+
// Verify round-trip preserves the dangerous content
|
|
267
|
+
const parsed = parse(text);
|
|
268
|
+
assert.equal(parsed.sections[0].content, '#@fake\n#!END\nnormal line');
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
// ================================================================
|
|
272
|
+
// Constants
|
|
273
|
+
// ================================================================
|
|
274
|
+
describe('constants', () => {
|
|
275
|
+
it('META_FIELDS has standard keys', () => {
|
|
276
|
+
assert.ok('id' in META_FIELDS);
|
|
277
|
+
assert.ok('agent' in META_FIELDS);
|
|
278
|
+
assert.ok('checksum' in META_FIELDS);
|
|
279
|
+
});
|
|
280
|
+
it('SECTION_TYPES has standard sections', () => {
|
|
281
|
+
assert.ok('content' in SECTION_TYPES);
|
|
282
|
+
assert.ok('chain' in SECTION_TYPES);
|
|
283
|
+
assert.ok('tools' in SECTION_TYPES);
|
|
284
|
+
assert.ok('metrics' in SECTION_TYPES);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/__tests__/index.test.ts"],"names":[],"mappings":"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"}
|