@usejunior/docx-core 0.1.2 → 0.3.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/dist/.tsbuildinfo +1 -1
- package/dist/baselines/atomizer/consumerCompatibility.d.ts +2 -0
- package/dist/baselines/atomizer/consumerCompatibility.d.ts.map +1 -0
- package/dist/baselines/atomizer/consumerCompatibility.js +188 -0
- package/dist/baselines/atomizer/consumerCompatibility.js.map +1 -0
- package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
- package/dist/baselines/atomizer/documentReconstructor.js +82 -42
- package/dist/baselines/atomizer/documentReconstructor.js.map +1 -1
- package/dist/baselines/atomizer/inPlaceModifier.d.ts +15 -1
- package/dist/baselines/atomizer/inPlaceModifier.d.ts.map +1 -1
- package/dist/baselines/atomizer/inPlaceModifier.js +111 -16
- package/dist/baselines/atomizer/inPlaceModifier.js.map +1 -1
- package/dist/baselines/atomizer/pipeline.d.ts +4 -0
- package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
- package/dist/baselines/atomizer/pipeline.js +335 -4
- package/dist/baselines/atomizer/pipeline.js.map +1 -1
- package/dist/benchmark/gates.d.ts +17 -0
- package/dist/benchmark/gates.d.ts.map +1 -0
- package/dist/benchmark/gates.js +260 -0
- package/dist/benchmark/gates.js.map +1 -0
- package/dist/benchmark/metrics.d.ts +5 -62
- package/dist/benchmark/metrics.d.ts.map +1 -1
- package/dist/benchmark/metrics.js +7 -28
- package/dist/benchmark/metrics.js.map +1 -1
- package/dist/benchmark/reporter.d.ts +6 -19
- package/dist/benchmark/reporter.d.ts.map +1 -1
- package/dist/benchmark/reporter.js +63 -116
- package/dist/benchmark/reporter.js.map +1 -1
- package/dist/benchmark/runner.d.ts +11 -26
- package/dist/benchmark/runner.d.ts.map +1 -1
- package/dist/benchmark/runner.js +191 -183
- package/dist/benchmark/runner.js.map +1 -1
- package/dist/benchmark/scores.d.ts +24 -0
- package/dist/benchmark/scores.d.ts.map +1 -0
- package/dist/benchmark/scores.js +103 -0
- package/dist/benchmark/scores.js.map +1 -0
- package/dist/benchmark/types.d.ts +81 -0
- package/dist/benchmark/types.d.ts.map +1 -0
- package/dist/benchmark/types.js +7 -0
- package/dist/benchmark/types.js.map +1 -0
- package/dist/primitives/document.d.ts +12 -0
- package/dist/primitives/document.d.ts.map +1 -1
- package/dist/primitives/document.js +17 -2
- package/dist/primitives/document.js.map +1 -1
- package/dist/primitives/document_view.d.ts +5 -1
- package/dist/primitives/document_view.d.ts.map +1 -1
- package/dist/primitives/document_view.js +46 -19
- package/dist/primitives/document_view.js.map +1 -1
- package/dist/primitives/formatting_tags.d.ts +22 -9
- package/dist/primitives/formatting_tags.d.ts.map +1 -1
- package/dist/primitives/formatting_tags.js +166 -92
- package/dist/primitives/formatting_tags.js.map +1 -1
- package/dist/primitives/matching.d.ts +16 -2
- package/dist/primitives/matching.d.ts.map +1 -1
- package/dist/primitives/matching.js +93 -14
- package/dist/primitives/matching.js.map +1 -1
- package/dist/primitives/merge_runs.d.ts.map +1 -1
- package/dist/primitives/merge_runs.js +48 -0
- package/dist/primitives/merge_runs.js.map +1 -1
- package/dist/primitives/namespaces.d.ts +1 -0
- package/dist/primitives/namespaces.d.ts.map +1 -1
- package/dist/primitives/namespaces.js +1 -0
- package/dist/primitives/namespaces.js.map +1 -1
- package/dist/primitives/semantic_tags.d.ts +10 -25
- package/dist/primitives/semantic_tags.d.ts.map +1 -1
- package/dist/primitives/semantic_tags.js +34 -115
- package/dist/primitives/semantic_tags.js.map +1 -1
- package/dist/primitives/styles.d.ts.map +1 -1
- package/dist/primitives/styles.js +21 -6
- package/dist/primitives/styles.js.map +1 -1
- package/dist/primitives/text.d.ts +3 -0
- package/dist/primitives/text.d.ts.map +1 -1
- package/dist/primitives/text.js +65 -20
- package/dist/primitives/text.js.map +1 -1
- package/dist/shared/validators/structural.d.ts +31 -0
- package/dist/shared/validators/structural.d.ts.map +1 -0
- package/dist/shared/validators/structural.js +110 -0
- package/dist/shared/validators/structural.js.map +1 -0
- package/package.json +1 -1
package/dist/benchmark/runner.js
CHANGED
|
@@ -1,225 +1,233 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Quality benchmark runner — gate-then-score architecture.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* For each fixture × engine: produce redline → run gates → if hard gates pass, run scores.
|
|
5
5
|
*/
|
|
6
|
-
import { readFile,
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
for (const entry of
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
6
|
+
import { readFile, access } from 'fs/promises';
|
|
7
|
+
import { resolve, dirname } from 'path';
|
|
8
|
+
import { execFile } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
10
|
+
import { compareDocuments } from '../index.js';
|
|
11
|
+
import { extractTextWithParagraphs } from '../baselines/atomizer/trackChangesAcceptorAst.js';
|
|
12
|
+
import { DocxArchive } from '../shared/docx/DocxArchive.js';
|
|
13
|
+
import { createTimer } from './metrics.js';
|
|
14
|
+
import { runGates } from './gates.js';
|
|
15
|
+
import { scoreDiffMinimality, scoreCompatibility, scoreExtras } from './scores.js';
|
|
16
|
+
import { generateMarkdownReport, generateJsonReport } from './reporter.js';
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
18
|
+
// ── Manifest loading ────────────────────────────────────────────────
|
|
19
|
+
export async function loadManifest(manifestPath) {
|
|
20
|
+
const raw = await readFile(manifestPath, 'utf-8');
|
|
21
|
+
const manifest = JSON.parse(raw);
|
|
22
|
+
const baseDir = resolve(dirname(manifestPath), manifest.base_dir);
|
|
23
|
+
const resolvedFixtures = [];
|
|
24
|
+
const missing = [];
|
|
25
|
+
for (const entry of manifest.fixtures) {
|
|
26
|
+
const resolvedOriginal = resolve(baseDir, entry.original);
|
|
27
|
+
const resolvedRevised = resolve(baseDir, entry.revised);
|
|
28
|
+
try {
|
|
29
|
+
await access(resolvedOriginal);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
missing.push(`${entry.name}: original not found at ${resolvedOriginal}`);
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
await access(resolvedRevised);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
missing.push(`${entry.name}: revised not found at ${resolvedRevised}`);
|
|
39
|
+
}
|
|
40
|
+
resolvedFixtures.push({ ...entry, resolvedOriginal, resolvedRevised });
|
|
41
|
+
}
|
|
42
|
+
if (missing.length > 0) {
|
|
43
|
+
throw new Error(`Manifest path validation failed:\n${missing.join('\n')}`);
|
|
44
|
+
}
|
|
45
|
+
return { manifest, resolvedFixtures };
|
|
46
|
+
}
|
|
47
|
+
// ── Engine dispatch ─────────────────────────────────────────────────
|
|
48
|
+
async function produceRedline(engine, originalBuffer, revisedBuffer, author, asposeCliPath) {
|
|
49
|
+
if (engine === 'atomizer') {
|
|
50
|
+
const result = await compareDocuments(originalBuffer, revisedBuffer, { engine: 'atomizer', author });
|
|
51
|
+
return result.document;
|
|
52
|
+
}
|
|
53
|
+
if (engine === 'diffmatch') {
|
|
54
|
+
const result = await compareDocuments(originalBuffer, revisedBuffer, { engine: 'diffmatch', author });
|
|
55
|
+
return result.document;
|
|
56
|
+
}
|
|
57
|
+
if (engine === 'aspose') {
|
|
58
|
+
if (!asposeCliPath) {
|
|
59
|
+
throw new Error('Aspose CLI path not provided');
|
|
60
|
+
}
|
|
61
|
+
// Use Python subprocess
|
|
62
|
+
const { tmpdir } = await import('os');
|
|
63
|
+
const { mkdtemp, writeFile, unlink } = await import('fs/promises');
|
|
64
|
+
const { join } = await import('path');
|
|
65
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'benchmark-aspose-'));
|
|
66
|
+
const origPath = join(tempDir, 'original.docx');
|
|
67
|
+
const revPath = join(tempDir, 'revised.docx');
|
|
68
|
+
const outPath = join(tempDir, 'result.docx');
|
|
69
|
+
try {
|
|
70
|
+
await writeFile(origPath, originalBuffer);
|
|
71
|
+
await writeFile(revPath, revisedBuffer);
|
|
72
|
+
await execFileAsync('python3', [
|
|
73
|
+
asposeCliPath,
|
|
74
|
+
'--original', origPath,
|
|
75
|
+
'--revised', revPath,
|
|
76
|
+
'--output', outPath,
|
|
77
|
+
'--author', author,
|
|
78
|
+
], { timeout: 120_000 });
|
|
79
|
+
return await readFile(outPath);
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
31
82
|
try {
|
|
32
|
-
await
|
|
33
|
-
await stat(revisedPath);
|
|
34
|
-
fixtures.push({
|
|
35
|
-
name: entry.name,
|
|
36
|
-
originalPath,
|
|
37
|
-
revisedPath,
|
|
38
|
-
});
|
|
83
|
+
await unlink(origPath);
|
|
39
84
|
}
|
|
40
|
-
catch {
|
|
41
|
-
|
|
85
|
+
catch { /* ignore */ }
|
|
86
|
+
try {
|
|
87
|
+
await unlink(revPath);
|
|
42
88
|
}
|
|
43
|
-
|
|
44
|
-
else if (entry.name.endsWith('.original.docx')) {
|
|
45
|
-
// File structure: fixture-name.original.docx + fixture-name.revised.docx
|
|
46
|
-
const baseName = entry.name.replace('.original.docx', '');
|
|
47
|
-
const originalPath = join(fixturesPath, entry.name);
|
|
48
|
-
const revisedPath = join(fixturesPath, `${baseName}.revised.docx`);
|
|
89
|
+
catch { /* ignore */ }
|
|
49
90
|
try {
|
|
50
|
-
await
|
|
51
|
-
fixtures.push({
|
|
52
|
-
name: baseName,
|
|
53
|
-
originalPath,
|
|
54
|
-
revisedPath,
|
|
55
|
-
});
|
|
91
|
+
await unlink(outPath);
|
|
56
92
|
}
|
|
57
|
-
catch {
|
|
58
|
-
|
|
93
|
+
catch { /* ignore */ }
|
|
94
|
+
try {
|
|
95
|
+
await unlink(outPath.replace('.docx', '.manifest.json'));
|
|
59
96
|
}
|
|
97
|
+
catch { /* ignore */ }
|
|
98
|
+
try {
|
|
99
|
+
const { rmdir } = await import('fs/promises');
|
|
100
|
+
await rmdir(tempDir);
|
|
101
|
+
}
|
|
102
|
+
catch { /* ignore */ }
|
|
60
103
|
}
|
|
61
104
|
}
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Run Baseline A (WmlComparer via CLI) on a fixture.
|
|
66
|
-
*/
|
|
67
|
-
async function runBaselineA(original, revised, options) {
|
|
68
|
-
const metrics = createEmptyMetrics();
|
|
69
|
-
const startMemory = measureMemory();
|
|
70
|
-
const timer = createTimer();
|
|
71
|
-
const result = await compareWithDotnet(original, revised, options);
|
|
72
|
-
metrics.wallTimeMs = timer();
|
|
73
|
-
metrics.peakRssMb = Math.max(measureMemory() - startMemory, 0);
|
|
74
|
-
metrics.outputSizeBytes = result.document.length;
|
|
75
|
-
metrics.insertions = result.stats.insertions;
|
|
76
|
-
metrics.deletions = result.stats.deletions;
|
|
77
|
-
metrics.modifications = result.stats.modifications;
|
|
78
|
-
// TODO: Add structural validation
|
|
79
|
-
// - Parse output DOCX
|
|
80
|
-
// - Check for broken relationships
|
|
81
|
-
// - Count actual track changes elements
|
|
82
|
-
return { metrics, output: result.document };
|
|
105
|
+
throw new Error(`Unknown engine: ${engine}`);
|
|
83
106
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
*
|
|
87
|
-
* Uses the diffmatch pipeline:
|
|
88
|
-
* 1. Parse DOCX to extract paragraphs/runs
|
|
89
|
-
* 2. Align paragraphs using LCS
|
|
90
|
-
* 3. Diff matched paragraphs at run level
|
|
91
|
-
* 4. Render track changes back to DOCX
|
|
92
|
-
*/
|
|
93
|
-
async function runBaselineB(original, revised, author) {
|
|
94
|
-
const metrics = createEmptyMetrics();
|
|
95
|
-
const startMemory = measureMemory();
|
|
107
|
+
// ── Single fixture × engine ─────────────────────────────────────────
|
|
108
|
+
async function runEngineOnFixture(engine, originalBuffer, revisedBuffer, author, config) {
|
|
96
109
|
const timer = createTimer();
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
author,
|
|
125
|
-
docxodusPath: config.docxodusPath,
|
|
126
|
-
dotnetPath: config.dotnetPath,
|
|
127
|
-
timeout: config.timeout,
|
|
128
|
-
});
|
|
129
|
-
result.baselineA = metrics;
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
result.baselineAError =
|
|
133
|
-
error instanceof Error ? error.message : String(error);
|
|
110
|
+
try {
|
|
111
|
+
const resultBuffer = await produceRedline(engine, originalBuffer, revisedBuffer, author, config.asposeCliPath);
|
|
112
|
+
const wallTimeMs = timer();
|
|
113
|
+
// Extract text from source documents for gate comparison
|
|
114
|
+
const originalArchive = await DocxArchive.load(originalBuffer);
|
|
115
|
+
const revisedArchive = await DocxArchive.load(revisedBuffer);
|
|
116
|
+
const originalDocXml = await originalArchive.getDocumentXml();
|
|
117
|
+
const revisedDocXml = await revisedArchive.getDocumentXml();
|
|
118
|
+
const originalText = extractTextWithParagraphs(originalDocXml);
|
|
119
|
+
const revisedText = extractTextWithParagraphs(revisedDocXml);
|
|
120
|
+
// Get result document.xml for gates
|
|
121
|
+
const resultArchive = await DocxArchive.load(resultBuffer);
|
|
122
|
+
const resultDocXml = await resultArchive.getDocumentXml();
|
|
123
|
+
// Run gates
|
|
124
|
+
const { gates, hardGatesPassed, softGatesPassed } = await runGates(resultBuffer, resultDocXml, originalText, revisedText, originalBuffer, revisedBuffer);
|
|
125
|
+
// Run scores only if hard gates pass
|
|
126
|
+
let scores = null;
|
|
127
|
+
if (hardGatesPassed) {
|
|
128
|
+
const diffMin = scoreDiffMinimality(resultDocXml);
|
|
129
|
+
const compat = await scoreCompatibility(resultBuffer, config.libreOfficePath, config.timeout);
|
|
130
|
+
const extras = scoreExtras(resultDocXml);
|
|
131
|
+
scores = {
|
|
132
|
+
diffMinimality: diffMin,
|
|
133
|
+
compatibility: compat,
|
|
134
|
+
performance: { wallTimeMs },
|
|
135
|
+
extras,
|
|
136
|
+
};
|
|
134
137
|
}
|
|
138
|
+
return {
|
|
139
|
+
engine,
|
|
140
|
+
gates,
|
|
141
|
+
hardGatesPassed,
|
|
142
|
+
softGatesPassed,
|
|
143
|
+
scores,
|
|
144
|
+
};
|
|
135
145
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
catch (e) {
|
|
147
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
148
|
+
return {
|
|
149
|
+
engine,
|
|
150
|
+
gates: {
|
|
151
|
+
textRoundTrip: {
|
|
152
|
+
normalizedTextParity: { passed: false, detail: 'Skipped (engine error)' },
|
|
153
|
+
paragraphCountParity: { passed: false, detail: 'Skipped (engine error)' },
|
|
154
|
+
xmlParseValidity: { passed: false, detail: 'Skipped (engine error)' },
|
|
155
|
+
},
|
|
156
|
+
formattingProjection: { passed: false, detail: 'Skipped (engine error)' },
|
|
157
|
+
structuralIntegrity: { passed: false, detail: 'Skipped (engine error)' },
|
|
158
|
+
},
|
|
159
|
+
hardGatesPassed: false,
|
|
160
|
+
softGatesPassed: false,
|
|
161
|
+
scores: null,
|
|
162
|
+
error: msg,
|
|
163
|
+
};
|
|
146
164
|
}
|
|
147
|
-
return result;
|
|
148
165
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// Check if Baseline A is available
|
|
154
|
-
const canRunA = config.runBaselineA !== false &&
|
|
155
|
-
await isRedlineAvailable(config.docxodusPath, config.dotnetPath);
|
|
156
|
-
if (config.runBaselineA !== false && !canRunA) {
|
|
157
|
-
console.warn('Baseline A (WmlComparer) not available. Install .NET 8+ and Docxodus.');
|
|
158
|
-
}
|
|
159
|
-
// Discover fixtures
|
|
160
|
-
const fixtures = await discoverFixtures(config.fixturesPath);
|
|
161
|
-
if (fixtures.length === 0) {
|
|
162
|
-
console.warn(`No fixtures found in ${config.fixturesPath}`);
|
|
163
|
-
return [];
|
|
164
|
-
}
|
|
165
|
-
console.log(`Found ${fixtures.length} fixture(s)`);
|
|
166
|
-
// Run benchmarks
|
|
166
|
+
// ── Main entry point ────────────────────────────────────────────────
|
|
167
|
+
export async function runQualityBenchmark(config) {
|
|
168
|
+
const { resolvedFixtures } = await loadManifest(config.manifestPath);
|
|
169
|
+
const author = config.author ?? 'Benchmark';
|
|
167
170
|
const results = [];
|
|
168
|
-
for (const fixture of
|
|
171
|
+
for (const fixture of resolvedFixtures) {
|
|
169
172
|
console.log(`Running: ${fixture.name}`);
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
const originalBuffer = await readFile(fixture.resolvedOriginal);
|
|
174
|
+
const revisedBuffer = await readFile(fixture.resolvedRevised);
|
|
175
|
+
const engines = {};
|
|
176
|
+
for (const engine of config.engines) {
|
|
177
|
+
console.log(` Engine: ${engine}`);
|
|
178
|
+
engines[engine] = await runEngineOnFixture(engine, originalBuffer, revisedBuffer, author, config);
|
|
179
|
+
}
|
|
180
|
+
results.push({
|
|
181
|
+
fixture: fixture.name,
|
|
182
|
+
tags: fixture.tags,
|
|
183
|
+
engines,
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
173
185
|
});
|
|
174
|
-
results.push(result);
|
|
175
186
|
}
|
|
176
187
|
return results;
|
|
177
188
|
}
|
|
178
|
-
|
|
179
|
-
* CLI entry point.
|
|
180
|
-
*/
|
|
189
|
+
// ── CLI entry point ─────────────────────────────────────────────────
|
|
181
190
|
async function main() {
|
|
182
191
|
const args = process.argv.slice(2);
|
|
183
192
|
if (args.length === 0) {
|
|
184
|
-
console.log('Usage:
|
|
193
|
+
console.log('Usage: pnpm benchmark <manifest.json> [options]');
|
|
185
194
|
console.log('');
|
|
186
195
|
console.log('Options:');
|
|
187
|
-
console.log(' --
|
|
188
|
-
console.log(' --
|
|
189
|
-
console.log(' --
|
|
190
|
-
console.log(' --
|
|
191
|
-
console.log(' --
|
|
196
|
+
console.log(' --engines=atomizer,diffmatch Engines to run (comma-separated)');
|
|
197
|
+
console.log(' --aspose-cli=<path> Path to aspose_compare.py');
|
|
198
|
+
console.log(' --libreoffice=<path> Path to LibreOffice binary');
|
|
199
|
+
console.log(' --author=<name> Author name for revisions');
|
|
200
|
+
console.log(' --format=json|markdown Output format (default: json)');
|
|
192
201
|
process.exit(1);
|
|
193
202
|
}
|
|
194
|
-
const
|
|
203
|
+
const manifestPath = args[0];
|
|
195
204
|
const options = {};
|
|
196
205
|
for (let i = 1; i < args.length; i++) {
|
|
197
206
|
const arg = args[i];
|
|
198
|
-
if (arg.startsWith('--')) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
options[key] = value;
|
|
202
|
-
}
|
|
203
|
-
else if (arg.startsWith('--no-')) {
|
|
204
|
-
options[arg.slice(5)] = false;
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
options[arg.slice(2)] = true;
|
|
208
|
-
}
|
|
207
|
+
if (arg.startsWith('--') && arg.includes('=')) {
|
|
208
|
+
const [key, value] = arg.slice(2).split('=', 2);
|
|
209
|
+
options[key] = value;
|
|
209
210
|
}
|
|
210
211
|
}
|
|
212
|
+
const engines = (options.engines ?? 'atomizer,diffmatch')
|
|
213
|
+
.split(',')
|
|
214
|
+
.map((e) => e.trim());
|
|
211
215
|
const config = {
|
|
212
|
-
|
|
216
|
+
manifestPath: resolve(manifestPath),
|
|
217
|
+
engines,
|
|
213
218
|
author: options.author,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
runBaselineA: options['baseline-a'] !== false,
|
|
217
|
-
runBaselineB: options['baseline-b'] !== false,
|
|
219
|
+
asposeCliPath: options['aspose-cli'],
|
|
220
|
+
libreOfficePath: options.libreoffice,
|
|
218
221
|
};
|
|
219
222
|
try {
|
|
220
|
-
const results = await
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
const results = await runQualityBenchmark(config);
|
|
224
|
+
const format = options.format ?? 'json';
|
|
225
|
+
if (format === 'markdown') {
|
|
226
|
+
console.log(generateMarkdownReport(results));
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
console.log(generateJsonReport(results));
|
|
230
|
+
}
|
|
223
231
|
}
|
|
224
232
|
catch (error) {
|
|
225
233
|
console.error('Benchmark failed:', error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/benchmark/runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/benchmark/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality benchmark scores.
|
|
3
|
+
*
|
|
4
|
+
* Q1: Diff minimality — count of ins/del runs
|
|
5
|
+
* Q2: Compatibility — LibreOffice round-trip test
|
|
6
|
+
* Q4: Extras — move detection, table cell diffs
|
|
7
|
+
*/
|
|
8
|
+
export interface DiffMinimalityResult {
|
|
9
|
+
engineRuns: number;
|
|
10
|
+
oracleRuns: number | null;
|
|
11
|
+
ratio: number | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function scoreDiffMinimality(resultDocumentXml: string, oracleDocumentXml?: string | null): DiffMinimalityResult;
|
|
14
|
+
export interface CompatibilityResult {
|
|
15
|
+
opensClean: boolean;
|
|
16
|
+
skipReason?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function scoreCompatibility(resultBuffer: Buffer, libreOfficePath?: string, timeout?: number): Promise<CompatibilityResult>;
|
|
19
|
+
export interface ExtrasResult {
|
|
20
|
+
moveDetection: boolean;
|
|
21
|
+
tableCellDiff: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function scoreExtras(resultDocumentXml: string): ExtrasResult;
|
|
24
|
+
//# sourceMappingURL=scores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scores.d.ts","sourceRoot":"","sources":["../../src/benchmark/scores.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,mBAAmB,CACjC,iBAAiB,EAAE,MAAM,EACzB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAChC,oBAAoB,CAoBtB;AAID,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,OAAO,GAAE,MAAe,GACvB,OAAO,CAAC,mBAAmB,CAAC,CA+C9B;AAID,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,iBAAiB,EAAE,MAAM,GAAG,YAAY,CAsBnE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality benchmark scores.
|
|
3
|
+
*
|
|
4
|
+
* Q1: Diff minimality — count of ins/del runs
|
|
5
|
+
* Q2: Compatibility — LibreOffice round-trip test
|
|
6
|
+
* Q4: Extras — move detection, table cell diffs
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from 'child_process';
|
|
9
|
+
import { writeFile, unlink, access, mkdtemp } from 'fs/promises';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { tmpdir } from 'os';
|
|
12
|
+
import { promisify } from 'util';
|
|
13
|
+
import { parseXml } from '../primitives/xml.js';
|
|
14
|
+
import { findAllByTagName } from '../primitives/dom-helpers.js';
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
16
|
+
export function scoreDiffMinimality(resultDocumentXml, oracleDocumentXml) {
|
|
17
|
+
const doc = parseXml(resultDocumentXml);
|
|
18
|
+
const root = doc.documentElement;
|
|
19
|
+
const insCount = findAllByTagName(root, 'w:ins').length;
|
|
20
|
+
const delCount = findAllByTagName(root, 'w:del').length;
|
|
21
|
+
const engineRuns = insCount + delCount;
|
|
22
|
+
let oracleRuns = null;
|
|
23
|
+
let ratio = null;
|
|
24
|
+
if (oracleDocumentXml) {
|
|
25
|
+
const oracleDoc = parseXml(oracleDocumentXml);
|
|
26
|
+
const oracleRoot = oracleDoc.documentElement;
|
|
27
|
+
const oracleIns = findAllByTagName(oracleRoot, 'w:ins').length;
|
|
28
|
+
const oracleDel = findAllByTagName(oracleRoot, 'w:del').length;
|
|
29
|
+
oracleRuns = oracleIns + oracleDel;
|
|
30
|
+
ratio = oracleRuns > 0 ? engineRuns / oracleRuns : null;
|
|
31
|
+
}
|
|
32
|
+
return { engineRuns, oracleRuns, ratio };
|
|
33
|
+
}
|
|
34
|
+
export async function scoreCompatibility(resultBuffer, libreOfficePath, timeout = 30_000) {
|
|
35
|
+
if (!libreOfficePath) {
|
|
36
|
+
return { opensClean: false, skipReason: 'binary_missing' };
|
|
37
|
+
}
|
|
38
|
+
// Verify binary exists
|
|
39
|
+
try {
|
|
40
|
+
await access(libreOfficePath);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return { opensClean: false, skipReason: 'binary_missing' };
|
|
44
|
+
}
|
|
45
|
+
let tempDir;
|
|
46
|
+
let inputPath;
|
|
47
|
+
try {
|
|
48
|
+
tempDir = await mkdtemp(join(tmpdir(), 'benchmark-q2-'));
|
|
49
|
+
inputPath = join(tempDir, 'input.docx');
|
|
50
|
+
await writeFile(inputPath, resultBuffer);
|
|
51
|
+
await execFileAsync(libreOfficePath, ['--headless', '--convert-to', 'docx', '--outdir', tempDir, inputPath], { timeout });
|
|
52
|
+
return { opensClean: true };
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
56
|
+
if (msg.includes('TIMEOUT') || msg.includes('timed out')) {
|
|
57
|
+
return { opensClean: false, skipReason: 'timeout' };
|
|
58
|
+
}
|
|
59
|
+
return { opensClean: false, skipReason: 'conversion_error' };
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
// Cleanup temp files
|
|
63
|
+
if (inputPath) {
|
|
64
|
+
try {
|
|
65
|
+
await unlink(inputPath);
|
|
66
|
+
}
|
|
67
|
+
catch { /* ignore */ }
|
|
68
|
+
}
|
|
69
|
+
if (tempDir) {
|
|
70
|
+
const outputPath = join(tempDir, 'input.docx');
|
|
71
|
+
try {
|
|
72
|
+
await unlink(outputPath);
|
|
73
|
+
}
|
|
74
|
+
catch { /* ignore */ }
|
|
75
|
+
try {
|
|
76
|
+
const { rmdir } = await import('fs/promises');
|
|
77
|
+
await rmdir(tempDir);
|
|
78
|
+
}
|
|
79
|
+
catch { /* ignore */ }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function scoreExtras(resultDocumentXml) {
|
|
84
|
+
const doc = parseXml(resultDocumentXml);
|
|
85
|
+
const root = doc.documentElement;
|
|
86
|
+
// Move detection: w:moveFrom or w:moveTo present
|
|
87
|
+
const moveFrom = findAllByTagName(root, 'w:moveFrom');
|
|
88
|
+
const moveTo = findAllByTagName(root, 'w:moveTo');
|
|
89
|
+
const moveDetection = moveFrom.length > 0 || moveTo.length > 0;
|
|
90
|
+
// Table cell diff: track changes inside w:tc elements
|
|
91
|
+
const tableCells = findAllByTagName(root, 'w:tc');
|
|
92
|
+
let tableCellDiff = false;
|
|
93
|
+
for (const tc of tableCells) {
|
|
94
|
+
const ins = findAllByTagName(tc, 'w:ins');
|
|
95
|
+
const del = findAllByTagName(tc, 'w:del');
|
|
96
|
+
if (ins.length > 0 || del.length > 0) {
|
|
97
|
+
tableCellDiff = true;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { moveDetection, tableCellDiff };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=scores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scores.js","sourceRoot":"","sources":["../../src/benchmark/scores.ts"],"names":[],"mappings":"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"}
|