text-compress 2.0.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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -0
  3. package/dist/api/folder.d.ts +38 -0
  4. package/dist/api/folder.d.ts.map +1 -0
  5. package/dist/api/folder.js +50 -0
  6. package/dist/api/folder.js.map +1 -0
  7. package/dist/api/text.d.ts +30 -0
  8. package/dist/api/text.d.ts.map +1 -0
  9. package/dist/api/text.js +38 -0
  10. package/dist/api/text.js.map +1 -0
  11. package/dist/archive/collect.d.ts +26 -0
  12. package/dist/archive/collect.d.ts.map +1 -0
  13. package/dist/archive/collect.js +38 -0
  14. package/dist/archive/collect.js.map +1 -0
  15. package/dist/archive/format.d.ts +62 -0
  16. package/dist/archive/format.d.ts.map +1 -0
  17. package/dist/archive/format.js +143 -0
  18. package/dist/archive/format.js.map +1 -0
  19. package/dist/archive/types.d.ts +25 -0
  20. package/dist/archive/types.d.ts.map +1 -0
  21. package/dist/archive/types.js +10 -0
  22. package/dist/archive/types.js.map +1 -0
  23. package/dist/archive/unpack.d.ts +21 -0
  24. package/dist/archive/unpack.d.ts.map +1 -0
  25. package/dist/archive/unpack.js +41 -0
  26. package/dist/archive/unpack.js.map +1 -0
  27. package/dist/cli/analytics.d.ts +10 -0
  28. package/dist/cli/analytics.d.ts.map +1 -0
  29. package/dist/cli/analytics.js +22 -0
  30. package/dist/cli/analytics.js.map +1 -0
  31. package/dist/cli/args.d.ts +43 -0
  32. package/dist/cli/args.d.ts.map +1 -0
  33. package/dist/cli/args.js +152 -0
  34. package/dist/cli/args.js.map +1 -0
  35. package/dist/cli/commands/compress.d.ts +9 -0
  36. package/dist/cli/commands/compress.d.ts.map +1 -0
  37. package/dist/cli/commands/compress.js +62 -0
  38. package/dist/cli/commands/compress.js.map +1 -0
  39. package/dist/cli/commands/decompress.d.ts +9 -0
  40. package/dist/cli/commands/decompress.d.ts.map +1 -0
  41. package/dist/cli/commands/decompress.js +69 -0
  42. package/dist/cli/commands/decompress.js.map +1 -0
  43. package/dist/cli/detect.d.ts +25 -0
  44. package/dist/cli/detect.d.ts.map +1 -0
  45. package/dist/cli/detect.js +78 -0
  46. package/dist/cli/detect.js.map +1 -0
  47. package/dist/cli/main.d.ts +8 -0
  48. package/dist/cli/main.d.ts.map +1 -0
  49. package/dist/cli/main.js +74 -0
  50. package/dist/cli/main.js.map +1 -0
  51. package/dist/cli/output.d.ts +13 -0
  52. package/dist/cli/output.d.ts.map +1 -0
  53. package/dist/cli/output.js +26 -0
  54. package/dist/cli/output.js.map +1 -0
  55. package/dist/cli/paths.d.ts +13 -0
  56. package/dist/cli/paths.d.ts.map +1 -0
  57. package/dist/cli/paths.js +24 -0
  58. package/dist/cli/paths.js.map +1 -0
  59. package/dist/cli/usage.d.ts +8 -0
  60. package/dist/cli/usage.d.ts.map +1 -0
  61. package/dist/cli/usage.js +73 -0
  62. package/dist/cli/usage.js.map +1 -0
  63. package/dist/cli.d.ts +3 -0
  64. package/dist/cli.d.ts.map +1 -0
  65. package/dist/cli.js +10 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/compression/brotli.d.ts +43 -0
  68. package/dist/compression/brotli.d.ts.map +1 -0
  69. package/dist/compression/brotli.js +56 -0
  70. package/dist/compression/brotli.js.map +1 -0
  71. package/dist/crypto/password.d.ts +22 -0
  72. package/dist/crypto/password.d.ts.map +1 -0
  73. package/dist/crypto/password.js +62 -0
  74. package/dist/crypto/password.js.map +1 -0
  75. package/dist/encoding/base64.d.ts +17 -0
  76. package/dist/encoding/base64.d.ts.map +1 -0
  77. package/dist/encoding/base64.js +21 -0
  78. package/dist/encoding/base64.js.map +1 -0
  79. package/dist/encoding/index.d.ts +29 -0
  80. package/dist/encoding/index.d.ts.map +1 -0
  81. package/dist/encoding/index.js +47 -0
  82. package/dist/encoding/index.js.map +1 -0
  83. package/dist/encoding/z85.d.ts +64 -0
  84. package/dist/encoding/z85.d.ts.map +1 -0
  85. package/dist/encoding/z85.js +99 -0
  86. package/dist/encoding/z85.js.map +1 -0
  87. package/dist/fs/gitignore.d.ts +30 -0
  88. package/dist/fs/gitignore.d.ts.map +1 -0
  89. package/dist/fs/gitignore.js +104 -0
  90. package/dist/fs/gitignore.js.map +1 -0
  91. package/dist/fs/paths.d.ts +22 -0
  92. package/dist/fs/paths.d.ts.map +1 -0
  93. package/dist/fs/paths.js +55 -0
  94. package/dist/fs/paths.js.map +1 -0
  95. package/dist/fs/walk.d.ts +22 -0
  96. package/dist/fs/walk.d.ts.map +1 -0
  97. package/dist/fs/walk.js +49 -0
  98. package/dist/fs/walk.js.map +1 -0
  99. package/dist/index.d.ts +21 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +25 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/payload/tags.d.ts +60 -0
  104. package/dist/payload/tags.d.ts.map +1 -0
  105. package/dist/payload/tags.js +78 -0
  106. package/dist/payload/tags.js.map +1 -0
  107. package/dist/split/parts.d.ts +130 -0
  108. package/dist/split/parts.d.ts.map +1 -0
  109. package/dist/split/parts.js +290 -0
  110. package/dist/split/parts.js.map +1 -0
  111. package/dist/streaming/folder.d.ts +49 -0
  112. package/dist/streaming/folder.d.ts.map +1 -0
  113. package/dist/streaming/folder.js +220 -0
  114. package/dist/streaming/folder.js.map +1 -0
  115. package/dist/streaming.d.ts +16 -0
  116. package/dist/streaming.d.ts.map +1 -0
  117. package/dist/streaming.js +243 -0
  118. package/dist/streaming.js.map +1 -0
  119. package/dist/types.d.ts +18 -0
  120. package/dist/types.d.ts.map +1 -0
  121. package/dist/types.js +11 -0
  122. package/dist/types.js.map +1 -0
  123. package/package.json +60 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @module encoding
3
+ *
4
+ * Facade that selects Base64 or Z85 encoding based on the {@link Encoding}
5
+ * discriminator. Higher layers (compression API, streaming pipeline) call
6
+ * only `encodeBuffer` / `decodeBuffer` — they never import z85 or base64
7
+ * directly.
8
+ *
9
+ * ## Strategy pattern
10
+ *
11
+ * This is a simple strategy pattern: the `encoding` parameter picks the
12
+ * algorithm at runtime without branching scattered across the codebase.
13
+ */
14
+ import type { Encoding } from "../types.js";
15
+ /** Encode a binary buffer to a pasteable text string. */
16
+ export declare function encodeBuffer(buffer: Buffer, encoding: Encoding): string;
17
+ /** Decode a pasteable text string back to a binary buffer. */
18
+ export declare function decodeBuffer(str: string, encoding: Encoding): Buffer;
19
+ /**
20
+ * Estimate the character length of an encoded string without encoding.
21
+ *
22
+ * Used by the streaming pipeline to pre-calculate split part counts
23
+ * before writing files to disk.
24
+ *
25
+ * - Base64: `ceil(bytes / 3) × 4`
26
+ * - Z85: accounts for the 1-byte pad prefix and block padding
27
+ */
28
+ export declare function estimatedEncodedLength(binaryBytes: number, encoding: Encoding): number;
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/encoding/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAI3C,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAIvE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAIpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAItF"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @module encoding
3
+ *
4
+ * Facade that selects Base64 or Z85 encoding based on the {@link Encoding}
5
+ * discriminator. Higher layers (compression API, streaming pipeline) call
6
+ * only `encodeBuffer` / `decodeBuffer` — they never import z85 or base64
7
+ * directly.
8
+ *
9
+ * ## Strategy pattern
10
+ *
11
+ * This is a simple strategy pattern: the `encoding` parameter picks the
12
+ * algorithm at runtime without branching scattered across the codebase.
13
+ */
14
+ import { decodeBase64, encodeBase64 } from "./base64.js";
15
+ import { decodeBase85, encodeBase85 } from "./z85.js";
16
+ /** Encode a binary buffer to a pasteable text string. */
17
+ export function encodeBuffer(buffer, encoding) {
18
+ if (encoding === 64)
19
+ return encodeBase64(buffer);
20
+ if (encoding === 85)
21
+ return encodeBase85(buffer);
22
+ throw new Error(`Unsupported encoding: ${encoding}`);
23
+ }
24
+ /** Decode a pasteable text string back to a binary buffer. */
25
+ export function decodeBuffer(str, encoding) {
26
+ if (encoding === 64)
27
+ return decodeBase64(str);
28
+ if (encoding === 85)
29
+ return decodeBase85(str);
30
+ throw new Error(`Unsupported encoding: ${encoding}`);
31
+ }
32
+ /**
33
+ * Estimate the character length of an encoded string without encoding.
34
+ *
35
+ * Used by the streaming pipeline to pre-calculate split part counts
36
+ * before writing files to disk.
37
+ *
38
+ * - Base64: `ceil(bytes / 3) × 4`
39
+ * - Z85: accounts for the 1-byte pad prefix and block padding
40
+ */
41
+ export function estimatedEncodedLength(binaryBytes, encoding) {
42
+ if (encoding === 64)
43
+ return Math.ceil(binaryBytes / 3) * 4;
44
+ const padded = 1 + binaryBytes + ((4 - ((binaryBytes + 1) % 4)) % 4);
45
+ return (padded / 4) * 5;
46
+ }
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/encoding/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAErD,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,QAAkB;IAC7D,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,YAAY,CAAC,MAAM,CAAC,CAAA;IAChD,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,YAAY,CAAC,MAAM,CAAC,CAAA;IAChD,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAA;AACtD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,QAAkB;IAC1D,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,YAAY,CAAC,GAAG,CAAC,CAAA;IAC7C,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,YAAY,CAAC,GAAG,CAAC,CAAA;IAC7C,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAA;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAmB,EAAE,QAAkB;IAC5E,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACpE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;AACzB,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @module encoding/z85
3
+ *
4
+ * Z85 (ZeroMQ RFC 32) Base85 encoder and decoder.
5
+ *
6
+ * ## Why Z85 instead of Ascii85?
7
+ *
8
+ * Standard Ascii85 uses `"` and `\` — characters that break when pasted
9
+ * into chat or JSON strings. Z85 picks an alphabet of 85 printable ASCII
10
+ * characters that avoid quotes, backslashes, and backticks, making the
11
+ * output safe to paste verbatim into most code contexts.
12
+ *
13
+ * ## Algorithm (base-85 positional encoding)
14
+ *
15
+ * Z85 groups input into 4-byte blocks and maps each block to 5 printable
16
+ * characters:
17
+ *
18
+ * ```
19
+ * value = b0·256³ + b1·256² + b2·256 + b3 (0 ≤ value < 256⁴)
20
+ * char[j] = alphabet[value mod 85] (j = 4 … 0)
21
+ * value = floor(value / 85)
22
+ * ```
23
+ *
24
+ * Decoding reverses the process: 5 characters → one 32-bit value → 4 bytes.
25
+ *
26
+ * ## Padding scheme
27
+ *
28
+ * Z85 requires input length to be a multiple of 4 bytes. We prefix a
29
+ * 1-byte pad count (`0–3`) so arbitrary-length payloads round-trip exactly:
30
+ *
31
+ * ```
32
+ * [padCount: u8][payload bytes…][zero padding to multiple of 4]
33
+ * ```
34
+ *
35
+ * @see https://rfc.zeromq.org/spec/32/ — Z85 specification
36
+ */
37
+ /** 85-character alphabet defined by the Z85 specification. */
38
+ export declare const Z85_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#";
39
+ /**
40
+ * Encode a buffer whose length is already a multiple of 4 into a Z85 string.
41
+ *
42
+ * @param buffer - Raw bytes; length must be divisible by 4.
43
+ * @returns Z85-encoded string (length = buffer.length / 4 × 5).
44
+ */
45
+ export declare function z85Encode(buffer: Buffer): string;
46
+ /**
47
+ * Decode a Z85 string back to raw bytes.
48
+ *
49
+ * @param str - Z85 string; length must be a multiple of 5.
50
+ * @throws If length is wrong or an unknown character appears.
51
+ */
52
+ export declare function z85Decode(str: string): Buffer;
53
+ /**
54
+ * Encode arbitrary-length bytes to Z85, handling padding automatically.
55
+ *
56
+ * Pattern: length-prefix padding — a common technique when a codec requires
57
+ * fixed block sizes but the payload length is arbitrary.
58
+ */
59
+ export declare function encodeBase85(buffer: Buffer): string;
60
+ /**
61
+ * Decode a Z85 string produced by {@link encodeBase85}, stripping padding.
62
+ */
63
+ export declare function decodeBase85(str: string): Buffer;
64
+ //# sourceMappingURL=z85.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"z85.d.ts","sourceRoot":"","sources":["../../src/encoding/z85.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,YAAY,0FACgE,CAAA;AAEzF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAYhD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkB7C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAInD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIhD"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @module encoding/z85
3
+ *
4
+ * Z85 (ZeroMQ RFC 32) Base85 encoder and decoder.
5
+ *
6
+ * ## Why Z85 instead of Ascii85?
7
+ *
8
+ * Standard Ascii85 uses `"` and `\` — characters that break when pasted
9
+ * into chat or JSON strings. Z85 picks an alphabet of 85 printable ASCII
10
+ * characters that avoid quotes, backslashes, and backticks, making the
11
+ * output safe to paste verbatim into most code contexts.
12
+ *
13
+ * ## Algorithm (base-85 positional encoding)
14
+ *
15
+ * Z85 groups input into 4-byte blocks and maps each block to 5 printable
16
+ * characters:
17
+ *
18
+ * ```
19
+ * value = b0·256³ + b1·256² + b2·256 + b3 (0 ≤ value < 256⁴)
20
+ * char[j] = alphabet[value mod 85] (j = 4 … 0)
21
+ * value = floor(value / 85)
22
+ * ```
23
+ *
24
+ * Decoding reverses the process: 5 characters → one 32-bit value → 4 bytes.
25
+ *
26
+ * ## Padding scheme
27
+ *
28
+ * Z85 requires input length to be a multiple of 4 bytes. We prefix a
29
+ * 1-byte pad count (`0–3`) so arbitrary-length payloads round-trip exactly:
30
+ *
31
+ * ```
32
+ * [padCount: u8][payload bytes…][zero padding to multiple of 4]
33
+ * ```
34
+ *
35
+ * @see https://rfc.zeromq.org/spec/32/ — Z85 specification
36
+ */
37
+ /** 85-character alphabet defined by the Z85 specification. */
38
+ export const Z85_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#";
39
+ /**
40
+ * Encode a buffer whose length is already a multiple of 4 into a Z85 string.
41
+ *
42
+ * @param buffer - Raw bytes; length must be divisible by 4.
43
+ * @returns Z85-encoded string (length = buffer.length / 4 × 5).
44
+ */
45
+ export function z85Encode(buffer) {
46
+ let out = "";
47
+ for (let i = 0; i < buffer.length; i += 4) {
48
+ let value = buffer[i] * 16777216 + buffer[i + 1] * 65536 + buffer[i + 2] * 256 + buffer[i + 3];
49
+ const chars = new Array(5);
50
+ for (let j = 4; j >= 0; j--) {
51
+ chars[j] = Z85_ALPHABET[value % 85];
52
+ value = Math.floor(value / 85);
53
+ }
54
+ out += chars.join("");
55
+ }
56
+ return out;
57
+ }
58
+ /**
59
+ * Decode a Z85 string back to raw bytes.
60
+ *
61
+ * @param str - Z85 string; length must be a multiple of 5.
62
+ * @throws If length is wrong or an unknown character appears.
63
+ */
64
+ export function z85Decode(str) {
65
+ if (str.length % 5 !== 0)
66
+ throw new Error("Invalid base85 (Z85) input length.");
67
+ const bytes = [];
68
+ for (let i = 0; i < str.length; i += 5) {
69
+ let value = 0;
70
+ for (let j = 0; j < 5; j++) {
71
+ const digit = Z85_ALPHABET.indexOf(str[i + j]);
72
+ if (digit === -1)
73
+ throw new Error(`Invalid base85 (Z85) character: "${str[i + j]}"`);
74
+ value = value * 85 + digit;
75
+ }
76
+ bytes.push(Math.floor(value / 16777216) % 256, Math.floor(value / 65536) % 256, Math.floor(value / 256) % 256, value % 256);
77
+ }
78
+ return Buffer.from(bytes);
79
+ }
80
+ /**
81
+ * Encode arbitrary-length bytes to Z85, handling padding automatically.
82
+ *
83
+ * Pattern: length-prefix padding — a common technique when a codec requires
84
+ * fixed block sizes but the payload length is arbitrary.
85
+ */
86
+ export function encodeBase85(buffer) {
87
+ const padLength = (4 - ((buffer.length + 1) % 4)) % 4;
88
+ const padded = Buffer.concat([Buffer.from([padLength]), buffer, Buffer.alloc(padLength)]);
89
+ return z85Encode(padded);
90
+ }
91
+ /**
92
+ * Decode a Z85 string produced by {@link encodeBase85}, stripping padding.
93
+ */
94
+ export function decodeBase85(str) {
95
+ const padded = z85Decode(str);
96
+ const padLength = padded[0];
97
+ return padded.subarray(1, padded.length - padLength);
98
+ }
99
+ //# sourceMappingURL=z85.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"z85.js","sourceRoot":"","sources":["../../src/encoding/z85.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @module fs/gitignore
3
+ *
4
+ * Git-style `.gitignore` filtering for directory walks.
5
+ *
6
+ * Rules are applied **outside → inside**:
7
+ *
8
+ * 1. If the tree is inside a git repo, load every `.gitignore` on the path
9
+ * from the repo root down to (but not including) the compression root.
10
+ * 2. While walking, load each directory's `.gitignore` before visiting
11
+ * children and drop it when leaving the directory.
12
+ *
13
+ * Later rules can negate earlier ones, matching git's behaviour.
14
+ */
15
+ /**
16
+ * Stateful filter that accumulates `.gitignore` rules while descending
17
+ * a directory tree.
18
+ */
19
+ export declare class GitignoreFilter {
20
+ private readonly layers;
21
+ constructor(rootDir: string);
22
+ /** Load `.gitignore` for `absDir` if present. */
23
+ enterDirectory(absDir: string): void;
24
+ /** Remove rules loaded for `absDir`. */
25
+ leaveDirectory(absDir: string): void;
26
+ /** Whether `absPath` should be excluded from the archive. */
27
+ isIgnored(absPath: string, isDirectory: boolean): boolean;
28
+ private pushLayer;
29
+ }
30
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/fs/gitignore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA0CH;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C,YAAY,OAAO,EAAE,MAAM,EAM1B;IAED,iDAAiD;IACjD,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEnC;IAED,wCAAwC;IACxC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAQnC;IAED,6DAA6D;IAC7D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAmBxD;IAED,OAAO,CAAC,SAAS;CAKlB"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @module fs/gitignore
3
+ *
4
+ * Git-style `.gitignore` filtering for directory walks.
5
+ *
6
+ * Rules are applied **outside → inside**:
7
+ *
8
+ * 1. If the tree is inside a git repo, load every `.gitignore` on the path
9
+ * from the repo root down to (but not including) the compression root.
10
+ * 2. While walking, load each directory's `.gitignore` before visiting
11
+ * children and drop it when leaving the directory.
12
+ *
13
+ * Later rules can negate earlier ones, matching git's behaviour.
14
+ */
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
17
+ import ignore from "ignore";
18
+ function readGitignoreFile(absDir) {
19
+ const gitignorePath = join(absDir, ".gitignore");
20
+ if (!existsSync(gitignorePath))
21
+ return null;
22
+ return ignore().add(readFileSync(gitignorePath, "utf-8"));
23
+ }
24
+ /** Walk upward until a `.git` directory is found; return that path or null. */
25
+ function findGitRoot(dir) {
26
+ let current = resolve(dir);
27
+ while (true) {
28
+ if (existsSync(join(current, ".git")))
29
+ return current;
30
+ const parent = dirname(current);
31
+ if (parent === current)
32
+ return null;
33
+ current = parent;
34
+ }
35
+ }
36
+ /** Directories on the path from `from` up to but excluding `to`. */
37
+ function ancestorDirs(from, to) {
38
+ const ancestors = [];
39
+ let current = resolve(from);
40
+ const target = resolve(to);
41
+ while (current !== target) {
42
+ ancestors.push(current);
43
+ const parent = dirname(current);
44
+ if (parent === current)
45
+ break;
46
+ current = parent;
47
+ }
48
+ return ancestors;
49
+ }
50
+ /**
51
+ * Stateful filter that accumulates `.gitignore` rules while descending
52
+ * a directory tree.
53
+ */
54
+ export class GitignoreFilter {
55
+ layers = [];
56
+ constructor(rootDir) {
57
+ const gitRoot = findGitRoot(rootDir);
58
+ const ancestorRoot = gitRoot ?? resolve(rootDir);
59
+ for (const dir of ancestorDirs(ancestorRoot, rootDir)) {
60
+ this.pushLayer(dir);
61
+ }
62
+ }
63
+ /** Load `.gitignore` for `absDir` if present. */
64
+ enterDirectory(absDir) {
65
+ this.pushLayer(absDir);
66
+ }
67
+ /** Remove rules loaded for `absDir`. */
68
+ leaveDirectory(absDir) {
69
+ const resolved = resolve(absDir);
70
+ for (let index = this.layers.length - 1; index >= 0; index--) {
71
+ if (this.layers[index].baseDir === resolved) {
72
+ this.layers.splice(index, 1);
73
+ return;
74
+ }
75
+ }
76
+ }
77
+ /** Whether `absPath` should be excluded from the archive. */
78
+ isIgnored(absPath, isDirectory) {
79
+ const resolved = resolve(absPath);
80
+ let ignored = false;
81
+ for (const { baseDir, matcher } of this.layers) {
82
+ const rel = relative(baseDir, resolved);
83
+ if (rel === "" || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
84
+ continue;
85
+ }
86
+ const candidates = isDirectory ? [`${rel}/`, rel] : [rel];
87
+ for (const candidate of candidates) {
88
+ const result = matcher.test(candidate);
89
+ if (result.unignored)
90
+ ignored = false;
91
+ else if (result.ignored)
92
+ ignored = true;
93
+ }
94
+ }
95
+ return ignored;
96
+ }
97
+ pushLayer(absDir) {
98
+ const matcher = readGitignoreFile(absDir);
99
+ if (!matcher)
100
+ return;
101
+ this.layers.push({ baseDir: resolve(absDir), matcher });
102
+ }
103
+ }
104
+ //# sourceMappingURL=gitignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/fs/gitignore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @module fs/paths
3
+ *
4
+ * Filesystem path validation and safe file reading.
5
+ *
6
+ * Centralises stat/read error handling so CLI and library callers get
7
+ * consistent, actionable error messages (e.g. distinguishing "path is a
8
+ * directory" from "path not found").
9
+ */
10
+ /**
11
+ * Assert that a path exists and is a directory.
12
+ *
13
+ * @throws If the path is a file or does not exist.
14
+ */
15
+ export declare function assertDirectory(path: string): void;
16
+ /**
17
+ * Read a UTF-8 text file with context-aware error messages.
18
+ *
19
+ * @param purpose - `"compress"` vs `"decompress"` changes the directory hint.
20
+ */
21
+ export declare function readTextFile(path: string, purpose?: "compress" | "decompress"): string;
22
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/fs/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmBH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,UAAU,GAAG,YAAyB,GAC9C,MAAM,CAaR"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @module fs/paths
3
+ *
4
+ * Filesystem path validation and safe file reading.
5
+ *
6
+ * Centralises stat/read error handling so CLI and library callers get
7
+ * consistent, actionable error messages (e.g. distinguishing "path is a
8
+ * directory" from "path not found").
9
+ */
10
+ import { readFileSync, statSync } from "node:fs";
11
+ /**
12
+ * Stat a path, translating ENOENT into a friendly error message.
13
+ */
14
+ function statPath(path) {
15
+ try {
16
+ return statSync(path);
17
+ }
18
+ catch (err) {
19
+ const code = err.code;
20
+ if (code === "ENOENT") {
21
+ throw new Error(`Path not found: ${path}`);
22
+ }
23
+ throw err;
24
+ }
25
+ }
26
+ /**
27
+ * Assert that a path exists and is a directory.
28
+ *
29
+ * @throws If the path is a file or does not exist.
30
+ */
31
+ export function assertDirectory(path) {
32
+ const stat = statPath(path);
33
+ if (!stat.isDirectory()) {
34
+ throw new Error(`"${path}" is not a directory. Pass a file path instead.`);
35
+ }
36
+ }
37
+ /**
38
+ * Read a UTF-8 text file with context-aware error messages.
39
+ *
40
+ * @param purpose - `"compress"` vs `"decompress"` changes the directory hint.
41
+ */
42
+ export function readTextFile(path, purpose = "compress") {
43
+ const stat = statPath(path);
44
+ if (stat.isDirectory()) {
45
+ const hint = purpose === "decompress"
46
+ ? "Pass the compressed .txt file, not a decompressed output folder."
47
+ : "Pass a folder path to compress a directory, or a file path for a single file.";
48
+ throw new Error(`"${path}" is a directory, not a file. ${hint}`);
49
+ }
50
+ if (!stat.isFile()) {
51
+ throw new Error(`Cannot read "${path}": not a regular file.`);
52
+ }
53
+ return readFileSync(path, "utf-8");
54
+ }
55
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/fs/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEhD;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAA;IACvB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAA;QAChD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,iDAAiD,CAAC,CAAA;IAC5E,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,OAAO,GAA8B,UAAU;IAE/C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,GACR,OAAO,KAAK,YAAY;YACtB,CAAC,CAAC,kEAAkE;YACpE,CAAC,CAAC,+EAA+E,CAAA;QACrF,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,iCAAiC,IAAI,EAAE,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,wBAAwB,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AACpC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @module fs/walk
3
+ *
4
+ * Shared depth-first directory walker used by in-memory and streaming
5
+ * folder compression. Applies `.gitignore` rules when enabled.
6
+ */
7
+ export interface DirectoryWalkHandlers {
8
+ /** Called for every directory except the compression root (`relDir === ""`). */
9
+ onDirectory?: (absDir: string, relDir: string) => void;
10
+ onFile: (absPath: string, relPath: string) => void;
11
+ }
12
+ /**
13
+ * Walk `rootDir` depth-first with sorted children.
14
+ *
15
+ * @param rootDir - Absolute path to the folder root.
16
+ * @param handlers - Callbacks for directories and files.
17
+ * @param options.useGitignore - Apply `.gitignore` rules (default: true).
18
+ */
19
+ export declare function walkDirectory(rootDir: string, handlers: DirectoryWalkHandlers, options?: {
20
+ useGitignore?: boolean;
21
+ }): void;
22
+ //# sourceMappingURL=walk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../../src/fs/walk.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACtD,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,IAAI,CAiCN"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @module fs/walk
3
+ *
4
+ * Shared depth-first directory walker used by in-memory and streaming
5
+ * folder compression. Applies `.gitignore` rules when enabled.
6
+ */
7
+ import { readdirSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { GitignoreFilter } from "./gitignore.js";
10
+ /**
11
+ * Walk `rootDir` depth-first with sorted children.
12
+ *
13
+ * @param rootDir - Absolute path to the folder root.
14
+ * @param handlers - Callbacks for directories and files.
15
+ * @param options.useGitignore - Apply `.gitignore` rules (default: true).
16
+ */
17
+ export function walkDirectory(rootDir, handlers, options = {}) {
18
+ const useGitignore = options.useGitignore !== false;
19
+ const filter = useGitignore ? new GitignoreFilter(rootDir) : null;
20
+ function walk(absDir, relDir) {
21
+ filter?.enterDirectory(absDir);
22
+ try {
23
+ if (relDir !== "")
24
+ handlers.onDirectory?.(absDir, relDir);
25
+ const dirents = readdirSync(absDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
26
+ for (const dirent of dirents) {
27
+ const abs = join(absDir, dirent.name);
28
+ const rel = relDir ? `${relDir}/${dirent.name}` : dirent.name;
29
+ const isDirectory = dirent.isDirectory();
30
+ const isFile = dirent.isFile();
31
+ if (!isDirectory && !isFile)
32
+ continue;
33
+ if (filter?.isIgnored(abs, isDirectory))
34
+ continue;
35
+ if (isDirectory) {
36
+ walk(abs, rel);
37
+ }
38
+ else {
39
+ handlers.onFile(abs, rel);
40
+ }
41
+ }
42
+ }
43
+ finally {
44
+ filter?.leaveDirectory(absDir);
45
+ }
46
+ }
47
+ walk(rootDir, "");
48
+ }
49
+ //# sourceMappingURL=walk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk.js","sourceRoot":"","sources":["../../src/fs/walk.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAQhD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,QAA+B,EAC/B,OAAO,GAA+B,EAAE;IAExC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,KAAK,KAAK,CAAA;IACnD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEjE,SAAS,IAAI,CAAC,MAAc,EAAE,MAAc;QAC1C,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC;YACH,IAAI,MAAM,KAAK,EAAE;gBAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;YAEzD,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACzE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAC7B,CAAA;YACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;gBACrC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;gBAC7D,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAA;gBACxC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAA;gBAE9B,IAAI,CAAC,WAAW,IAAI,CAAC,MAAM;oBAAE,SAAQ;gBACrC,IAAI,MAAM,EAAE,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC;oBAAE,SAAQ;gBAEjD,IAAI,WAAW,EAAE,CAAC;oBAChB,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;gBAChB,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;gBAC3B,CAAC;YACH,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;AACnB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @module index
3
+ *
4
+ * Public API barrel — re-exports everything consumers import from
5
+ * `@startdoing/tc`. Internal modules (`streaming/`, `cli/`) are not
6
+ * exported here; only this file defines the npm package surface.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { compress, decompress, compressFolder } from "text-compress";
11
+ * ```
12
+ */
13
+ export { compressFolder, decompressToPath } from "./api/folder.js";
14
+ export { compress, decompress } from "./api/text.js";
15
+ export { unpackDirectory } from "./archive/unpack.js";
16
+ export { assertDirectory, readTextFile } from "./fs/paths.js";
17
+ export { decompressPayload, TAG_FOLDER, TAG_TEXT } from "./payload/tags.js";
18
+ export type { SplitChunk } from "./split/parts.js";
19
+ export { AUTO_SPLIT_CHARS, assembleSplitChunks, createSplitChunkHeader, extractFilenamePrefix, formatSplitOutputPath, parseSplitBuffer, parseSplitPartPath, readSplitInput, resolveSplitChunkSize, resolveSplitInputPaths, SPLIT_MAGIC, splitString, tryParseSplitChunks, wrapSplitChunk, } from "./split/parts.js";
20
+ export type { Encoding } from "./types.js";
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGlE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAEpD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAE7D,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC3E,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @module index
3
+ *
4
+ * Public API barrel — re-exports everything consumers import from
5
+ * `@startdoing/tc`. Internal modules (`streaming/`, `cli/`) are not
6
+ * exported here; only this file defines the npm package surface.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { compress, decompress, compressFolder } from "text-compress";
11
+ * ```
12
+ */
13
+ // Folder API
14
+ export { compressFolder, decompressToPath } from "./api/folder.js";
15
+ // Text API
16
+ export { compress, decompress } from "./api/text.js";
17
+ // Archive unpack (exposed for advanced use / tests)
18
+ export { unpackDirectory } from "./archive/unpack.js";
19
+ // Path validation helpers
20
+ export { assertDirectory, readTextFile } from "./fs/paths.js";
21
+ // Low-level payload access
22
+ export { decompressPayload, TAG_FOLDER, TAG_TEXT } from "./payload/tags.js";
23
+ // Split-file helpers
24
+ export { AUTO_SPLIT_CHARS, assembleSplitChunks, createSplitChunkHeader, extractFilenamePrefix, formatSplitOutputPath, parseSplitBuffer, parseSplitPartPath, readSplitInput, resolveSplitChunkSize, resolveSplitInputPaths, SPLIT_MAGIC, splitString, tryParseSplitChunks, wrapSplitChunk, } from "./split/parts.js";
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAElE,WAAW;AACX,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AACpD,oDAAoD;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC7D,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3E,qBAAqB;AACrB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,cAAc,GACf,MAAM,kBAAkB,CAAA"}