docrev 0.9.15 → 0.9.16

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.
Files changed (41) hide show
  1. package/README.md +41 -46
  2. package/dist/lib/wordcomments.d.ts.map +1 -1
  3. package/dist/lib/wordcomments.js +25 -2
  4. package/dist/lib/wordcomments.js.map +1 -1
  5. package/docs-src/build.py +113 -0
  6. package/docs-src/extra.css +208 -0
  7. package/docs-src/md-to-html.lua +6 -0
  8. package/docs-src/template.html +116 -0
  9. package/lib/wordcomments.ts +25 -2
  10. package/mkdocs.yml +64 -0
  11. package/package.json +1 -1
  12. package/site/assets/extra.css +208 -0
  13. package/site/commands.html +926 -0
  14. package/site/configuration.html +469 -0
  15. package/site/index.html +288 -0
  16. package/site/troubleshooting.html +461 -0
  17. package/site/workflow.html +518 -0
  18. package/dev_notes/bug_repro_comment_parser.md +0 -71
  19. package/dev_notes/stress2/adversarial.docx +0 -0
  20. package/dev_notes/stress2/build_adversarial.ts +0 -186
  21. package/dev_notes/stress2/drift_matcher.ts +0 -62
  22. package/dev_notes/stress2/probe_anchors.ts +0 -35
  23. package/dev_notes/stress2/project/adversarial.docx +0 -0
  24. package/dev_notes/stress2/project/discussion.before.md +0 -3
  25. package/dev_notes/stress2/project/discussion.md +0 -3
  26. package/dev_notes/stress2/project/methods.before.md +0 -20
  27. package/dev_notes/stress2/project/methods.md +0 -20
  28. package/dev_notes/stress2/project/rev.yaml +0 -5
  29. package/dev_notes/stress2/project/sections.yaml +0 -4
  30. package/dev_notes/stress2/sections.yaml +0 -5
  31. package/dev_notes/stress2/trace_placement.ts +0 -50
  32. package/dev_notes/stresstest_boundaries.ts +0 -27
  33. package/dev_notes/stresstest_drift_apply.ts +0 -43
  34. package/dev_notes/stresstest_drift_compare.ts +0 -43
  35. package/dev_notes/stresstest_drift_v2.ts +0 -54
  36. package/dev_notes/stresstest_inspect.ts +0 -54
  37. package/dev_notes/stresstest_pstyle.ts +0 -55
  38. package/dev_notes/stresstest_section_debug.ts +0 -23
  39. package/dev_notes/stresstest_split.ts +0 -70
  40. package/dev_notes/stresstest_trace.ts +0 -19
  41. package/dev_notes/stresstest_verify_no_overwrite.ts +0 -40
@@ -1,55 +0,0 @@
1
- // Inspect the document.xml paragraph styles to find true headings.
2
- import AdmZip from 'adm-zip';
3
- import * as fs from 'fs';
4
-
5
- const docx = 'C:/GillesC/tmp/docrev-stress/reviewed.docx';
6
- const zip = new AdmZip(docx);
7
- const xml = zip.getEntry('word/document.xml')!.getData().toString('utf8');
8
-
9
- // Build text-position map from <w:t> runs the same way extractCommentAnchors does
10
- const textNodePattern = /<w:t[^>]*>([^<]*)<\/w:t>/g;
11
- const textNodes: Array<{ xmlStart: number; xmlEnd: number; textStart: number; textEnd: number; text: string }> = [];
12
- let textPosition = 0;
13
- let m;
14
- function decode(s: string): string {
15
- return s.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&apos;/g, "'");
16
- }
17
- while ((m = textNodePattern.exec(xml)) !== null) {
18
- const decoded = decode(m[1]);
19
- textNodes.push({ xmlStart: m.index, xmlEnd: m.index + m[0].length, textStart: textPosition, textEnd: textPosition + decoded.length, text: decoded });
20
- textPosition += decoded.length;
21
- }
22
-
23
- function xmlToText(xmlPos: number): number {
24
- for (const n of textNodes) {
25
- if (xmlPos >= n.xmlStart && xmlPos < n.xmlEnd) return n.textStart;
26
- if (xmlPos < n.xmlStart) return n.textStart;
27
- }
28
- return textNodes.length ? textNodes[textNodes.length - 1].textEnd : 0;
29
- }
30
-
31
- // Now walk paragraphs; each <w:p ...>...</w:p>. Inside, find <w:pStyle w:val="..."/> if present, and concatenate text runs.
32
- const paraPattern = /<w:p\b[^>]*>([\s\S]*?)<\/w:p>/g;
33
- const headings: Array<{ style: string; text: string; xmlStart: number; textPos: number }> = [];
34
- let pm;
35
- while ((pm = paraPattern.exec(xml)) !== null) {
36
- const inner = pm[1];
37
- const styleMatch = inner.match(/<w:pStyle[^>]*w:val="([^"]+)"/);
38
- if (!styleMatch) continue;
39
- const style = styleMatch[1];
40
- if (!/heading/i.test(style)) continue;
41
- // Extract text from runs
42
- const textInRange = /<w:t[^>]*>([^<]*)<\/w:t>/g;
43
- let txt = '';
44
- let tm;
45
- while ((tm = textInRange.exec(inner)) !== null) txt += decode(tm[1]);
46
- if (!txt.trim()) continue;
47
- const xmlStart = pm.index;
48
- const textPos = xmlToText(xmlStart);
49
- headings.push({ style, text: txt.trim(), xmlStart, textPos });
50
- }
51
-
52
- console.log(`Found ${headings.length} heading paragraphs:`);
53
- for (const h of headings) {
54
- console.log(` [${h.style.padEnd(8)}] textPos=${String(h.textPos).padStart(6)} "${h.text.slice(0, 60)}"`);
55
- }
@@ -1,23 +0,0 @@
1
- import { extractCommentAnchors } from '../lib/import.js';
2
-
3
- const docx = 'C:/GillesC/tmp/docrev-stress/reviewed.docx';
4
- const { fullDocText } = await extractCommentAnchors(docx);
5
-
6
- const keywords = ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion', 'Conclusion', 'References'];
7
- for (const kw of keywords) {
8
- const lower = fullDocText.toLowerCase();
9
- const needle = kw.toLowerCase();
10
- const occ: Array<{ idx: number; ctx: string; afterChar: string }> = [];
11
- let idx = 0;
12
- while ((idx = lower.indexOf(needle, idx)) !== -1) {
13
- const ctx = fullDocText.slice(Math.max(0, idx - 20), idx + needle.length + 20).replace(/\s+/g, ' ');
14
- const afterChar = fullDocText.slice(idx + needle.length, idx + needle.length + 1);
15
- occ.push({ idx, ctx, afterChar });
16
- idx++;
17
- }
18
- console.log(`\n--- ${kw} (${occ.length} occurrences) ---`);
19
- for (const o of occ.slice(0, 6)) {
20
- console.log(` @${o.idx} after="${o.afterChar}" ctx: ...${o.ctx}...`);
21
- }
22
- if (occ.length > 6) console.log(` ... and ${occ.length - 6} more`);
23
- }
@@ -1,70 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
-
4
- const ROOT = 'C:/GillesC/tmp/docrev-stress/project';
5
- fs.mkdirSync(ROOT, { recursive: true });
6
-
7
- const full = fs.readFileSync('C:/GillesC/tmp/docrev-stress/full.md', 'utf-8');
8
- const lines = full.split(/\r?\n/);
9
-
10
- interface Section { file: string; header: string; lines: string[]; }
11
-
12
- const sections: Section[] = [];
13
-
14
- // Map H1 heading text to section file
15
- const headerToFile: Record<string, string> = {
16
- 'Abstract': 'abstract.md',
17
- 'Introduction': 'introduction.md',
18
- 'Methods': 'methods.md',
19
- 'Results': 'results.md',
20
- 'Discussion': 'discussion.md',
21
- 'Conclusion': 'conclusion.md',
22
- 'References': 'references.md',
23
- 'Supplementary Materials': 'supplement.md',
24
- };
25
-
26
- let current: Section | null = null;
27
- const preambleLines: string[] = [];
28
-
29
- for (const line of lines) {
30
- const m = line.match(/^# (.+)$/);
31
- if (m && headerToFile[m[1].trim()]) {
32
- if (current) sections.push(current);
33
- current = { file: headerToFile[m[1].trim()], header: m[1].trim(), lines: [line] };
34
- } else if (current) {
35
- current.lines.push(line);
36
- } else {
37
- preambleLines.push(line);
38
- }
39
- }
40
- if (current) sections.push(current);
41
-
42
- // Write sections
43
- for (const s of sections) {
44
- const out = path.join(ROOT, s.file);
45
- fs.writeFileSync(out, s.lines.join('\n'), 'utf-8');
46
- console.log(`wrote ${out} (${s.lines.length} lines)`);
47
- }
48
-
49
- // Write sections.yaml
50
- const yaml: string[] = ['version: 1', 'sections:'];
51
- for (const s of sections) {
52
- yaml.push(` ${s.file}:`);
53
- yaml.push(` header: "${s.header}"`);
54
- yaml.push(` aliases: []`);
55
- }
56
- fs.writeFileSync(path.join(ROOT, 'sections.yaml'), yaml.join('\n') + '\n', 'utf-8');
57
- console.log(`wrote sections.yaml`);
58
-
59
- // Minimal rev.yaml so commands that look for project root don't choke
60
- const revYaml = `title: "Stress Test"
61
- authors:
62
- - name: Gilles Colling
63
- output:
64
- docx: {}
65
- pdf: {}
66
- `;
67
- fs.writeFileSync(path.join(ROOT, 'rev.yaml'), revYaml, 'utf-8');
68
-
69
- console.log();
70
- console.log(`section files: ${sections.length}`);
@@ -1,19 +0,0 @@
1
- import { extractCommentAnchors } from '../lib/import.js';
2
-
3
- const docx = 'C:/GillesC/tmp/docrev-stress/reviewed.docx';
4
- const { fullDocText } = await extractCommentAnchors(docx);
5
-
6
- const needle = 'methods';
7
- const lower = fullDocText.toLowerCase();
8
- let idx = 0;
9
- const trace: Array<{idx:number, after:string, skipped:boolean}> = [];
10
- while ((idx = lower.indexOf(needle, idx)) !== -1 && trace.length < 10) {
11
- const after = fullDocText.slice(idx + needle.length, idx + needle.length + 5);
12
- const skip = after.startsWith(':') || after.startsWith(' :');
13
- trace.push({ idx, after, skipped: skip });
14
- if (!skip) break;
15
- idx++;
16
- }
17
- for (const t of trace) console.log(`idx=${t.idx} after="${t.after}" skipped=${t.skipped}`);
18
- console.log();
19
- console.log(`first non-:-prefixed Methods idx = ${trace.find(t => !t.skipped)?.idx ?? -1}`);
@@ -1,40 +0,0 @@
1
- // Verify sync --comments-only didn't touch existing prose, only inserted comments.
2
- import * as fs from 'fs';
3
- import { stripCriticMarkup } from '../lib/anchor-match.js';
4
-
5
- const original = 'C:/GillesC/tmp/docrev-stress/project';
6
- const synced = 'C:/GillesC/tmp/docrev-stress/project-sync';
7
- const files = ['abstract.md', 'introduction.md', 'methods.md', 'results.md', 'discussion.md', 'conclusion.md', 'references.md', 'supplement.md'];
8
-
9
- let totalComments = 0;
10
- let mismatches = 0;
11
- for (const f of files) {
12
- const orig = fs.readFileSync(`${original}/${f}`, 'utf-8');
13
- const synd = fs.readFileSync(`${synced}/${f}`, 'utf-8');
14
-
15
- // Count comments inserted
16
- const commentMatches = synd.match(/\{>>.*?<<\}/gs) || [];
17
- totalComments += commentMatches.length;
18
-
19
- // The originals may already contain CriticMarkup (Word highlights -> [X]{.mark}),
20
- // so strip both sides to compare just the underlying prose.
21
- const synStripped = stripCriticMarkup(synd);
22
- const origNorm = stripCriticMarkup(orig);
23
-
24
- if (synStripped !== origNorm) {
25
- // Find first difference
26
- let i = 0;
27
- while (i < origNorm.length && i < synStripped.length && origNorm[i] === synStripped[i]) i++;
28
- const ctxOrig = origNorm.slice(Math.max(0, i - 30), i + 50).replace(/\n/g, '\\n');
29
- const ctxSyn = synStripped.slice(Math.max(0, i - 30), i + 50).replace(/\n/g, '\\n');
30
- console.log(`✗ ${f}: prose differs at byte ${i} (lengths orig=${origNorm.length} stripped=${synStripped.length})`);
31
- console.log(` orig: ${ctxOrig}`);
32
- console.log(` syn: ${ctxSyn}`);
33
- mismatches++;
34
- } else {
35
- console.log(`✓ ${f}: prose preserved (${commentMatches.length} comments inserted)`);
36
- }
37
- }
38
- console.log();
39
- console.log(`total comments inserted: ${totalComments}`);
40
- console.log(`prose mismatches: ${mismatches}/${files.length}`);