@ansonlai/docx-redline-js 0.7.2 → 0.8.1

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 (53) hide show
  1. package/AGENTS.md +15 -10
  2. package/ARCHITECTURE.md +30 -10
  3. package/CHANGELOG.md +539 -431
  4. package/README.md +331 -309
  5. package/adapters/xml-adapter.js +84 -56
  6. package/core/sha256.js +120 -0
  7. package/dist/docx-redline-js.esm.js +8982 -693
  8. package/dist/docx-redline-js.esm.js.map +4 -4
  9. package/dist/docx-redline-js.esm.min.js +102 -89
  10. package/dist/docx-redline-js.esm.min.js.map +4 -4
  11. package/dist/docx-redline.bundle.cjs +28305 -0
  12. package/dist/docx-redline.bundle.cjs.map +7 -0
  13. package/dist/docx-redline.bundle.js +28296 -0
  14. package/dist/docx-redline.bundle.js.map +7 -0
  15. package/docs/AGENT_FAST_START.md +2 -1
  16. package/docs/AGENT_KNOWLEDGE_BASE.md +480 -393
  17. package/docs/SKILL_AUTHORING.md +5 -2
  18. package/docs/TESTING.md +2 -1
  19. package/docs/schemas/document-operations.schema.json +29 -0
  20. package/document/docx-document.d.ts +39 -0
  21. package/document/docx-document.js +1010 -0
  22. package/document/zip-archive.js +258 -0
  23. package/engine/reconstruction-writer.js +18 -0
  24. package/index.d.ts +598 -531
  25. package/index.js +349 -340
  26. package/node/cli-help.js +5 -5
  27. package/node/cli.js +760 -754
  28. package/node/docx-document.js +11 -355
  29. package/node/index.d.ts +1 -1
  30. package/node/zip-archive.js +28 -38
  31. package/package.json +14 -11
  32. package/scripts/build.mjs +40 -5
  33. package/scripts/generate-word-comment-edge-case-fixture.ps1 +58 -0
  34. package/scripts/generate-word-comment-thread-fixture.ps1 +36 -0
  35. package/scripts/generate-word-header-footer-fixture.ps1 +32 -0
  36. package/scripts/generate-word-multi-section-fixture.ps1 +27 -0
  37. package/scripts/generate-word-package-integrity-cases.mjs +141 -0
  38. package/scripts/generate-word-thread-state-fixtures.ps1 +50 -0
  39. package/scripts/word-com-package-integrity.ps1 +98 -0
  40. package/services/batch-operation-orchestrator.js +262 -259
  41. package/services/comment-replies.js +96 -95
  42. package/services/comment-thread-parts.js +280 -0
  43. package/services/document-inspection.js +366 -365
  44. package/services/document-operation-applier.js +230 -202
  45. package/services/document-operation-contract.js +17 -2
  46. package/services/error-recovery.js +6 -0
  47. package/services/headers-footers.js +206 -0
  48. package/services/operation-batch-compiler.js +1 -0
  49. package/services/operation-preflight.js +231 -218
  50. package/services/package-parts.js +80 -0
  51. package/services/revision-token.js +11 -7
  52. package/services/standalone-docx-plumbing.js +631 -569
  53. package/services/standalone-operation-runner.d.ts +19 -3
@@ -1,64 +1,92 @@
1
- /**
2
- * XML adapter for parser/serializer portability.
3
- *
4
- * Default behavior uses browser-provided DOMParser/XMLSerializer.
5
- * Consumers can override these constructors for non-browser runtimes.
1
+ /**
2
+ * XML adapter for parser/serializer portability.
3
+ *
4
+ * Transparently uses browser-provided DOMParser/XMLSerializer when available in
5
+ * standard web runtimes, automatically falling back to pure-JS @xmldom/xmldom in
6
+ * Node.js and sandbox environments. Consumers can also explicitly override these
7
+ * constructors via configureXmlProvider.
6
8
  */
7
9
 
10
+ import { DOMParser as XmlDomParser, XMLSerializer as XmlDomSerializer } from '@xmldom/xmldom';
8
11
  import { warn as logWarning, error as logError } from './logger.js';
9
12
 
10
- let _DOMParser = globalThis.DOMParser;
11
- let _XMLSerializer = globalThis.XMLSerializer;
12
-
13
- /**
14
- * Configures XML provider constructors.
15
- *
16
- * @param {Object} [options={}] - Provider overrides
17
- * @param {typeof DOMParser} [options.DOMParser] - DOMParser constructor
18
- * @param {typeof XMLSerializer} [options.XMLSerializer] - XMLSerializer constructor
19
- */
20
- export function configureXmlProvider(options = {}) {
21
- if (options.DOMParser) _DOMParser = options.DOMParser;
22
- if (options.XMLSerializer) _XMLSerializer = options.XMLSerializer;
23
- }
24
-
25
- /**
26
- * Creates a parser instance.
27
- *
28
- * @returns {DOMParser}
29
- */
13
+ let _DOMParser = null;
14
+ let _XMLSerializer = null;
15
+
16
+ /**
17
+ * Configures XML provider constructors.
18
+ *
19
+ * @param {Object} [options={}] - Provider overrides
20
+ * @param {typeof DOMParser} [options.DOMParser] - DOMParser constructor
21
+ * @param {typeof XMLSerializer} [options.XMLSerializer] - XMLSerializer constructor
22
+ */
23
+ export function configureXmlProvider(options = {}) {
24
+ if ('DOMParser' in options) _DOMParser = options.DOMParser;
25
+ if ('XMLSerializer' in options) _XMLSerializer = options.XMLSerializer;
26
+ }
27
+
28
+ /**
29
+ * Resolves the active DOMParser constructor.
30
+ *
31
+ * Priority order:
32
+ * 1. Explicitly configured constructor (via configureXmlProvider)
33
+ * 2. Host environment native DOMParser (globalThis.DOMParser)
34
+ * 3. Pure-JS @xmldom/xmldom fallback
35
+ *
36
+ * @returns {typeof DOMParser}
37
+ */
38
+ export function resolveDomParserConstructor() {
39
+ return _DOMParser || globalThis.DOMParser || XmlDomParser;
40
+ }
41
+
42
+ /**
43
+ * Resolves the active XMLSerializer constructor.
44
+ *
45
+ * Priority order:
46
+ * 1. Explicitly configured constructor (via configureXmlProvider)
47
+ * 2. Host environment native XMLSerializer (globalThis.XMLSerializer)
48
+ * 3. Pure-JS @xmldom/xmldom fallback
49
+ *
50
+ * @returns {typeof XMLSerializer}
51
+ */
52
+ export function resolveXmlSerializerConstructor() {
53
+ return _XMLSerializer || globalThis.XMLSerializer || XmlDomSerializer;
54
+ }
55
+
56
+ /**
57
+ * Creates a parser instance.
58
+ *
59
+ * @param {Object} [options={}] - Parser options (e.g. { onError } for xmldom)
60
+ * @returns {DOMParser}
61
+ */
30
62
  export function createParser(options = {}) {
31
- if (!_DOMParser && globalThis.DOMParser) {
32
- _DOMParser = globalThis.DOMParser;
33
- }
34
- if (!_DOMParser) {
35
- throw new Error('DOMParser is not configured. Call configureXmlProvider({ DOMParser, XMLSerializer }) first.');
36
- }
37
- return new _DOMParser(options);
38
- }
39
-
40
- /**
41
- * Creates a serializer instance.
42
- *
43
- * @returns {XMLSerializer}
44
- */
45
- export function createSerializer() {
46
- if (!_XMLSerializer && globalThis.XMLSerializer) {
47
- _XMLSerializer = globalThis.XMLSerializer;
48
- }
49
- if (!_XMLSerializer) {
50
- throw new Error('XMLSerializer is not configured. Call configureXmlProvider({ DOMParser, XMLSerializer }) first.');
51
- }
52
- return new _XMLSerializer();
53
- }
54
-
55
- /**
56
- * Parses XML text into a DOM document.
57
- *
58
- * @param {string} xmlString - XML string
59
- * @param {string} [contentType='text/xml'] - MIME type
60
- * @returns {Document}
61
- */
63
+ const ParserCtor = resolveDomParserConstructor();
64
+ if (!ParserCtor) {
65
+ throw new Error('DOMParser is not configured and no fallback XML parser is available.');
66
+ }
67
+ return new ParserCtor(options);
68
+ }
69
+
70
+ /**
71
+ * Creates a serializer instance.
72
+ *
73
+ * @returns {XMLSerializer}
74
+ */
75
+ export function createSerializer() {
76
+ const SerializerCtor = resolveXmlSerializerConstructor();
77
+ if (!SerializerCtor) {
78
+ throw new Error('XMLSerializer is not configured and no fallback XML serializer is available.');
79
+ }
80
+ return new SerializerCtor();
81
+ }
82
+
83
+ /**
84
+ * Parses XML text into a DOM document.
85
+ *
86
+ * @param {string} xmlString - XML string
87
+ * @param {string} [contentType='text/xml'] - MIME type
88
+ * @returns {Document}
89
+ */
62
90
  export function parseXml(xmlString, contentType = 'text/xml') {
63
91
  const result = parseOoxmlSafe(xmlString, contentType);
64
92
  if (result.error) {
package/core/sha256.js ADDED
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Pure-JS synchronous SHA-256 (FIPS 180-4) implementation.
3
+ *
4
+ * Self-contained, deterministic, and free from Node.js or browser crypto built-ins.
5
+ * Accepts string, Uint8Array, Buffer, or ArrayBuffer and returns a 64-character hex string.
6
+ */
7
+
8
+ const K = new Uint32Array([
9
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
10
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
11
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
12
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
13
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
14
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
15
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
16
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
17
+ ]);
18
+
19
+ const textEncoder = new TextEncoder();
20
+
21
+ /**
22
+ * Computes the SHA-256 digest of binary or text data.
23
+ *
24
+ * @param {Uint8Array|ArrayBuffer|ArrayBufferView|string} input - Input data to hash
25
+ * @returns {string} 64-character lowercase hex string
26
+ */
27
+ export function sha256(input) {
28
+ let bytes;
29
+ if (typeof input === 'string') {
30
+ bytes = textEncoder.encode(input);
31
+ } else if (input instanceof Uint8Array) {
32
+ bytes = input;
33
+ } else if (input instanceof ArrayBuffer) {
34
+ bytes = new Uint8Array(input);
35
+ } else if (ArrayBuffer.isView(input)) {
36
+ bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
37
+ } else {
38
+ throw new TypeError('sha256 input must be a string, Uint8Array, Buffer, or ArrayBuffer.');
39
+ }
40
+
41
+ const byteLen = bytes.length;
42
+ const bitLen = byteLen * 8;
43
+
44
+ // Pad length: input + 1 (0x80) + zeros + 8 bytes (64-bit length) to multiple of 64 bytes
45
+ const paddedLen = Math.ceil((byteLen + 9) / 64) * 64;
46
+ const padded = new Uint8Array(paddedLen);
47
+ padded.set(bytes, 0);
48
+ padded[byteLen] = 0x80;
49
+
50
+ const dataView = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
51
+ // Write 64-bit big-endian length in bits
52
+ const highBits = Math.floor(bitLen / 0x100000000);
53
+ const lowBits = (bitLen >>> 0);
54
+ dataView.setUint32(paddedLen - 8, highBits, false);
55
+ dataView.setUint32(paddedLen - 4, lowBits, false);
56
+
57
+ // Initial hash values
58
+ let h0 = 0x6a09e667;
59
+ let h1 = 0xbb67ae85;
60
+ let h2 = 0x3c6ef372;
61
+ let h3 = 0xa54ff53a;
62
+ let h4 = 0x510e527f;
63
+ let h5 = 0x9b05688c;
64
+ let h6 = 0x1f83d9ab;
65
+ let h7 = 0x5be0cd19;
66
+
67
+ const W = new Uint32Array(64);
68
+
69
+ for (let offset = 0; offset < paddedLen; offset += 64) {
70
+ for (let t = 0; t < 16; t++) {
71
+ W[t] = dataView.getUint32(offset + t * 4, false);
72
+ }
73
+ for (let t = 16; t < 64; t++) {
74
+ const w15 = W[t - 15];
75
+ const s0 = ((w15 >>> 7) | (w15 << 25)) ^ ((w15 >>> 18) | (w15 << 14)) ^ (w15 >>> 3);
76
+ const w2 = W[t - 2];
77
+ const s1 = ((w2 >>> 17) | (w2 << 15)) ^ ((w2 >>> 19) | (w2 << 13)) ^ (w2 >>> 10);
78
+ W[t] = (W[t - 16] + s0 + W[t - 7] + s1) | 0;
79
+ }
80
+
81
+ let a = h0;
82
+ let b = h1;
83
+ let c = h2;
84
+ let d = h3;
85
+ let e = h4;
86
+ let f = h5;
87
+ let g = h6;
88
+ let h = h7;
89
+
90
+ for (let t = 0; t < 64; t++) {
91
+ const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));
92
+ const ch = (e & f) ^ (~e & g);
93
+ const temp1 = (h + S1 + ch + K[t] + W[t]) | 0;
94
+ const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));
95
+ const maj = (a & b) ^ (a & c) ^ (b & c);
96
+ const temp2 = (S0 + maj) | 0;
97
+
98
+ h = g;
99
+ g = f;
100
+ f = e;
101
+ e = (d + temp1) | 0;
102
+ d = c;
103
+ c = b;
104
+ b = a;
105
+ a = (temp1 + temp2) | 0;
106
+ }
107
+
108
+ h0 = (h0 + a) | 0;
109
+ h1 = (h1 + b) | 0;
110
+ h2 = (h2 + c) | 0;
111
+ h3 = (h3 + d) | 0;
112
+ h4 = (h4 + e) | 0;
113
+ h5 = (h5 + f) | 0;
114
+ h6 = (h6 + g) | 0;
115
+ h7 = (h7 + h) | 0;
116
+ }
117
+
118
+ const hex = n => (n >>> 0).toString(16).padStart(8, '0');
119
+ return hex(h0) + hex(h1) + hex(h2) + hex(h3) + hex(h4) + hex(h5) + hex(h6) + hex(h7);
120
+ }