@futpib/parser 1.0.0 → 1.0.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 (171) hide show
  1. package/build/apk.d.ts +29 -3
  2. package/build/apkParser.d.ts +15 -2
  3. package/build/apkParser.js +70 -41
  4. package/build/apkParser.test.js +2 -2
  5. package/build/apkUnparser.d.ts +4 -0
  6. package/build/apkUnparser.js +90 -0
  7. package/build/apkUnparser.test.d.ts +1 -0
  8. package/build/apkUnparser.test.js +26 -0
  9. package/build/arbitraryFileSystemEntry.js +1 -1
  10. package/build/arbitraryZip.d.ts +1 -1
  11. package/build/arbitraryZip.js +13 -19
  12. package/build/arbitraryZipPermissions.d.ts +1 -8
  13. package/build/arbitraryZipPermissions.js +1 -16
  14. package/build/arbitraryZipStream.d.ts +1 -1
  15. package/build/arbitraryZipStream.js +3 -3
  16. package/build/arrayParser.d.ts +1 -1
  17. package/build/arrayParser.js +2 -2
  18. package/build/arrayParser.test.js +2 -2
  19. package/build/arrayUnparser.d.ts +2 -0
  20. package/build/arrayUnparser.js +8 -0
  21. package/build/bsonParser.test.js +2 -2
  22. package/build/customInvariant.d.ts +4 -0
  23. package/build/customInvariant.js +11 -0
  24. package/build/debugLogParser.d.ts +1 -1
  25. package/build/debugLogParser.js +1 -1
  26. package/build/elementParser.d.ts +2 -2
  27. package/build/elementParser.js +1 -1
  28. package/build/endOfInputParser.d.ts +2 -2
  29. package/build/exactElementParser.d.ts +1 -1
  30. package/build/exactSequenceParser.js +1 -1
  31. package/build/index.d.ts +5 -2
  32. package/build/index.js +3 -0
  33. package/build/inputReader.d.ts +3 -3
  34. package/build/inputReader.js +6 -6
  35. package/build/inputReader.test.js +7 -7
  36. package/build/javaKeyStore.d.ts +1 -0
  37. package/build/javaKeyStore.js +1 -0
  38. package/build/javaKeyStoreParser.d.ts +2 -0
  39. package/build/javaKeyStoreParser.js +67 -0
  40. package/build/javaKeyStoreParser.test.d.ts +1 -0
  41. package/build/javaKeyStoreParser.test.js +16 -0
  42. package/build/javaKeystoreParser.d.ts +2 -0
  43. package/build/javaKeystoreParser.js +7 -0
  44. package/build/jsonParser.js +3 -2
  45. package/build/jsonParser.test.js +2 -2
  46. package/build/listParser.d.ts +1 -1
  47. package/build/listParser.js +5 -5
  48. package/build/negativeLookahead.d.ts +1 -1
  49. package/build/negativeLookahead.js +16 -18
  50. package/build/negativeLookaheadParser.d.ts +2 -0
  51. package/build/negativeLookaheadParser.js +18 -0
  52. package/build/optionalParser.d.ts +1 -1
  53. package/build/optionalParser.js +2 -2
  54. package/build/parser.d.ts +3 -3
  55. package/build/parser.js +3 -3
  56. package/build/parser.test.js +16 -16
  57. package/build/parserAccessorParser.d.ts +1 -1
  58. package/build/parserConsumedSequenceParser.d.ts +2 -0
  59. package/build/parserConsumedSequenceParser.js +17 -0
  60. package/build/parserContext.d.ts +6 -6
  61. package/build/parserContext.js +15 -14
  62. package/build/parserContext.test.js +7 -7
  63. package/build/parserCreatorCompose.d.ts +3 -3
  64. package/build/parserCreatorCompose.js +2 -2
  65. package/build/parserImplementationInvariant.d.ts +1 -1
  66. package/build/parserImplementationInvariant.js +2 -2
  67. package/build/parserInputCompanion.d.ts +20 -0
  68. package/build/parserInputCompanion.js +30 -0
  69. package/build/parserInvariant.d.ts +1 -1
  70. package/build/parserInvariant.js +1 -1
  71. package/build/quantifierParser.d.ts +2 -0
  72. package/build/quantifierParser.js +17 -0
  73. package/build/sequenceBuffer.d.ts +3 -3
  74. package/build/sequenceBuffer.js +6 -6
  75. package/build/sequenceBuffer.test.js +2 -2
  76. package/build/sequenceUnparser.d.ts +2 -0
  77. package/build/sequenceUnparser.js +6 -0
  78. package/build/sliceBoundedParser.d.ts +1 -1
  79. package/build/sliceBoundedParser.js +1 -1
  80. package/build/sliceBoundedParser.test.js +2 -2
  81. package/build/terminatedArrayParser.d.ts +1 -1
  82. package/build/terminatedArrayParser.js +3 -3
  83. package/build/uint8Array.d.ts +1 -0
  84. package/build/uint8Array.js +7 -0
  85. package/build/unparser.d.ts +8 -0
  86. package/build/unparser.js +104 -0
  87. package/build/unparser.test.d.ts +1 -0
  88. package/build/unparser.test.js +150 -0
  89. package/build/unparserContext.d.ts +31 -0
  90. package/build/unparserContext.js +74 -0
  91. package/build/unparserError.d.ts +9 -0
  92. package/build/unparserError.js +9 -0
  93. package/build/unparserImplementationInvariant.d.ts +2 -0
  94. package/build/unparserImplementationInvariant.js +5 -0
  95. package/build/unparserInputCompanion.d.ts +15 -0
  96. package/build/unparserInputCompanion.js +13 -0
  97. package/build/unparserOutputCompanion.d.ts +15 -0
  98. package/build/unparserOutputCompanion.js +13 -0
  99. package/build/zip.d.ts +9 -17
  100. package/build/zipParser.d.ts +13 -10
  101. package/build/zipParser.js +48 -60
  102. package/build/zipParser.test.js +2 -7
  103. package/build/zipUnparser.d.ts +5 -0
  104. package/build/zipUnparser.js +171 -0
  105. package/build/zipUnparser.test.d.ts +1 -0
  106. package/build/zipUnparser.test.js +80 -0
  107. package/package.json +4 -2
  108. package/src/apk.ts +35 -3
  109. package/src/apkParser.test.ts +2 -2
  110. package/src/apkParser.test.ts.md +114 -111
  111. package/src/apkParser.test.ts.snap +0 -0
  112. package/src/apkParser.ts +150 -85
  113. package/src/apkUnparser.test.ts +37 -0
  114. package/src/apkUnparser.ts +120 -0
  115. package/src/arbitraryFileSystemEntry.ts +2 -4
  116. package/src/arbitraryZip.ts +20 -27
  117. package/src/arbitraryZipPermissions.ts +0 -25
  118. package/src/arbitraryZipStream.ts +4 -4
  119. package/src/arrayParser.test.ts +3 -3
  120. package/src/arrayParser.ts +3 -2
  121. package/src/arrayUnparser.ts +13 -0
  122. package/src/bsonParser.test.ts +2 -2
  123. package/src/bsonParser.ts +3 -3
  124. package/src/{parserInvariant.ts → customInvariant.ts} +1 -1
  125. package/src/debugLogParser.ts +1 -1
  126. package/src/elementParser.ts +3 -3
  127. package/src/endOfInputParser.ts +4 -4
  128. package/src/exactElementParser.ts +1 -1
  129. package/src/exactSequenceParser.ts +2 -2
  130. package/src/index.ts +15 -2
  131. package/src/inputReader.test.ts +7 -7
  132. package/src/inputReader.ts +5 -5
  133. package/src/javaKeyStore.ts +0 -0
  134. package/src/javaKeyStoreParser.test.ts +23 -0
  135. package/src/javaKeyStoreParser.test.ts.md +103 -0
  136. package/src/javaKeyStoreParser.test.ts.snap +0 -0
  137. package/src/javaKeyStoreParser.ts +136 -0
  138. package/src/jsonParser.test.ts +2 -2
  139. package/src/jsonParser.ts +13 -12
  140. package/src/listParser.ts +6 -6
  141. package/src/negativeLookaheadParser.ts +24 -0
  142. package/src/optionalParser.ts +3 -3
  143. package/src/parser.test.ts +19 -17
  144. package/src/parser.ts +7 -7
  145. package/src/parserAccessorParser.ts +1 -1
  146. package/src/parserConsumedSequenceParser.ts +20 -0
  147. package/src/parserContext.test.ts +7 -7
  148. package/src/parserContext.ts +18 -14
  149. package/src/parserCreatorCompose.ts +6 -6
  150. package/src/parserImplementationInvariant.ts +2 -2
  151. package/src/{inputCompanion.ts → parserInputCompanion.ts} +10 -6
  152. package/src/quantifierParser.ts +25 -0
  153. package/src/sequenceBuffer.test.ts +2 -2
  154. package/src/sequenceBuffer.ts +5 -5
  155. package/src/sequenceUnparser.ts +9 -0
  156. package/src/sliceBoundedParser.test.ts +2 -2
  157. package/src/sliceBoundedParser.ts +2 -2
  158. package/src/terminatedArrayParser.ts +3 -3
  159. package/src/uint8Array.ts +10 -0
  160. package/src/unparser.test.ts +221 -0
  161. package/src/unparser.ts +209 -0
  162. package/src/unparserContext.ts +127 -0
  163. package/src/unparserError.ts +12 -0
  164. package/src/unparserImplementationInvariant.ts +6 -0
  165. package/src/unparserOutputCompanion.ts +24 -0
  166. package/src/zip.ts +10 -22
  167. package/src/zipParser.test.ts +2 -8
  168. package/src/zipParser.ts +147 -129
  169. package/src/zipUnparser.test.ts +119 -0
  170. package/src/zipUnparser.ts +239 -0
  171. package/src/negativeLookahead.ts +0 -26
@@ -0,0 +1,150 @@
1
+ import test from 'ava';
2
+ import * as fc from 'fast-check';
3
+ import { runUnparser } from './unparser.js';
4
+ import { stringUnparserOutputCompanion } from './unparserOutputCompanion.js';
5
+ import { testProp } from '@fast-check/ava';
6
+ test('writeLater', async (t) => {
7
+ const stringToBeWrittenBefore = 'before writeLater\n';
8
+ const stringToBeWrittenLater = 'written later\n';
9
+ const stringToBeWrittenAfter = 'after writeLater\n';
10
+ let expectedPositionA;
11
+ let expectedPositionB;
12
+ let actualPositionAFromWithinWriteLater;
13
+ let actualPositionBFromWithinWriteLater;
14
+ const unparser = async function* (_input, unparserContext) {
15
+ yield stringToBeWrittenBefore;
16
+ expectedPositionA = unparserContext.position;
17
+ const writeLater = yield* unparserContext.writeLater(stringToBeWrittenLater.length);
18
+ expectedPositionB = unparserContext.position;
19
+ yield stringToBeWrittenAfter;
20
+ yield* unparserContext.writeEarlier(writeLater, async function* (_input, unparserContext) {
21
+ actualPositionAFromWithinWriteLater = unparserContext.position;
22
+ yield stringToBeWrittenLater;
23
+ actualPositionBFromWithinWriteLater = unparserContext.position;
24
+ }, undefined);
25
+ };
26
+ const stringsAsyncIterable = runUnparser(unparser, undefined, stringUnparserOutputCompanion);
27
+ const strings = [];
28
+ for await (const string of stringsAsyncIterable) {
29
+ strings.push(string);
30
+ }
31
+ const string = strings.join('');
32
+ t.is(string, stringToBeWrittenBefore + stringToBeWrittenLater + stringToBeWrittenAfter);
33
+ t.is(actualPositionAFromWithinWriteLater, expectedPositionA, 'position a');
34
+ t.is(actualPositionBFromWithinWriteLater, expectedPositionB, 'position b');
35
+ t.is(expectedPositionA, stringToBeWrittenBefore.length);
36
+ t.is(expectedPositionB, stringToBeWrittenBefore.length + stringToBeWrittenLater.length);
37
+ });
38
+ test('writeLater one deep', async (t) => {
39
+ const unparser = async function* (_input, unparserContext) {
40
+ yield '(';
41
+ const writeLaterA = yield* unparserContext.writeLater(3);
42
+ yield ')';
43
+ yield* unparserContext.writeEarlier(writeLaterA, async function* (_input, unparserContext) {
44
+ yield '[';
45
+ const writeLaterB = yield* unparserContext.writeLater(1);
46
+ yield ']';
47
+ yield* unparserContext.writeEarlier(writeLaterB, async function* (_input, unparserContext) {
48
+ yield 'a';
49
+ }, undefined);
50
+ }, undefined);
51
+ };
52
+ const stringsAsyncIterable = runUnparser(unparser, undefined, stringUnparserOutputCompanion);
53
+ const strings = [];
54
+ for await (const string of stringsAsyncIterable) {
55
+ strings.push(string);
56
+ }
57
+ const string = strings.join('');
58
+ t.is(string, '([a])');
59
+ });
60
+ test('writeLater deep', async (t) => {
61
+ const unparser = async function* (_input, unparserContext) {
62
+ yield '(';
63
+ const writeLaterA = yield* unparserContext.writeLater(5);
64
+ yield ')';
65
+ let writeLaterC;
66
+ yield* unparserContext.writeEarlier(writeLaterA, async function* (_input, unparserContext) {
67
+ yield '[';
68
+ const writeLaterB = yield* unparserContext.writeLater(3);
69
+ yield ']';
70
+ yield* unparserContext.writeEarlier(writeLaterB, async function* (_input, unparserContext) {
71
+ yield '{';
72
+ writeLaterC = yield* unparserContext.writeLater(1);
73
+ yield '}';
74
+ }, undefined);
75
+ }, undefined);
76
+ yield* unparserContext.writeEarlier(writeLaterC, async function* (_input, unparserContext) {
77
+ yield 'a';
78
+ }, undefined);
79
+ yield 'z';
80
+ };
81
+ const stringsAsyncIterable = runUnparser(unparser, undefined, stringUnparserOutputCompanion);
82
+ const strings = [];
83
+ for await (const string of stringsAsyncIterable) {
84
+ strings.push(string);
85
+ }
86
+ const string = strings.join('');
87
+ t.is(string, '([{a}])z');
88
+ });
89
+ testProp('writeLater positions and lengths', [
90
+ fc.array(fc.oneof(fc.array(fc.oneof(fc.array(fc.string()), fc.string())), fc.string())),
91
+ ], async (t, stringArray3) => {
92
+ const numberUnparser = async function* (input, unparserContext) {
93
+ yield input.toString().padStart(8, '0');
94
+ };
95
+ const createLengthPrefixedUnparser = (unparser) => {
96
+ return async function* (input, unparserContext) {
97
+ const length = yield* unparserContext.writeLater(8);
98
+ yield* unparser(input, unparserContext);
99
+ yield* unparserContext.writeEarlier(length, numberUnparser, unparserContext.position - length.positionEnd);
100
+ };
101
+ };
102
+ const unparser0 = createLengthPrefixedUnparser(async function* (input, unparserContext) {
103
+ yield input;
104
+ });
105
+ const unparser1 = createLengthPrefixedUnparser(async function* (input, unparserContext) {
106
+ for (const string of input) {
107
+ yield* unparser0(string, unparserContext);
108
+ }
109
+ });
110
+ const unparser2 = createLengthPrefixedUnparser(async function* (input, unparserContext) {
111
+ for (const stringArray2 of input) {
112
+ if (typeof stringArray2 === 'string') {
113
+ yield* unparser0(stringArray2, unparserContext);
114
+ }
115
+ else {
116
+ yield* unparser1(stringArray2, unparserContext);
117
+ }
118
+ }
119
+ });
120
+ const unparser3 = createLengthPrefixedUnparser(async function* (input, unparserContext) {
121
+ for (const stringArray3 of input) {
122
+ if (typeof stringArray3 === 'string') {
123
+ yield* unparser0(stringArray3, unparserContext);
124
+ }
125
+ else {
126
+ yield* unparser2(stringArray3, unparserContext);
127
+ }
128
+ }
129
+ });
130
+ const stringsAsyncIterable = runUnparser(unparser3, stringArray3, stringUnparserOutputCompanion);
131
+ const strings = [];
132
+ for await (const string of stringsAsyncIterable) {
133
+ strings.push(string);
134
+ }
135
+ const actualString = strings.join('');
136
+ function getExpectedString(stringArray) {
137
+ let expectedString = stringArray;
138
+ if (typeof stringArray !== 'string') {
139
+ expectedString = stringArray.map(getExpectedString).join('');
140
+ }
141
+ return [
142
+ expectedString.length.toString().padStart(8, '0'),
143
+ expectedString,
144
+ ].join('');
145
+ }
146
+ const expectedString = getExpectedString(stringArray3);
147
+ t.deepEqual(actualString, expectedString);
148
+ }, {
149
+ verbose: true,
150
+ });
@@ -0,0 +1,31 @@
1
+ import { Unparser, UnparserResult } from "./unparser.js";
2
+ import { UnparserOutputCompanion } from "./unparserOutputCompanion.js";
3
+ export type UnparserContext<Sequence, Element> = {
4
+ get position(): number;
5
+ writeLater(length: number): AsyncIterable<WriteLater<Sequence, Element>, WriteLater<Sequence, Element>>;
6
+ writeEarlier<Input>(writeLater: WriteLater<Sequence, Element>, unparser: Unparser<Input, Sequence, Element>, input: Input): AsyncIterable<WriteEarlier<Sequence, Element>, void>;
7
+ };
8
+ export declare class WriteLater<Sequence, Element> extends Error {
9
+ private readonly _position;
10
+ private readonly _length;
11
+ name: string;
12
+ constructor(_position: number, _length: number);
13
+ get position(): number;
14
+ get positionEnd(): number;
15
+ get length(): number;
16
+ }
17
+ export declare class WriteEarlier<Sequence, Element> {
18
+ readonly writeLater: WriteLater<Sequence, Element>;
19
+ readonly unparserResult: UnparserResult<Sequence, Element>;
20
+ readonly unparserContext: UnparserContext<Sequence, Element>;
21
+ constructor(writeLater: WriteLater<Sequence, Element>, unparserResult: UnparserResult<Sequence, Element>, unparserContext: UnparserContext<Sequence, Element>);
22
+ }
23
+ export declare class UnparserContextImplementation<Sequence, Element> implements UnparserContext<Sequence, Element> {
24
+ private readonly _outputCompanion;
25
+ private _position;
26
+ constructor(_outputCompanion: UnparserOutputCompanion<Sequence, Element>, position?: number);
27
+ get position(): number;
28
+ writeLater(length: number): AsyncIterable<WriteLater<Sequence, Element>, WriteLater<Sequence, Element>>;
29
+ writeEarlier<Input>(writeLater: WriteLater<Sequence, Element>, unparser: Unparser<Input, Sequence, Element>, input: Input): AsyncIterable<WriteEarlier<Sequence, Element>, void>;
30
+ handleYield(value: Sequence | WriteLater<Sequence, Element> | WriteEarlier<Sequence, Element>): void;
31
+ }
@@ -0,0 +1,74 @@
1
+ /* eslint-disable prefer-arrow-callback */
2
+ import { unparserImplementationInvariant } from "./unparserImplementationInvariant.js";
3
+ import { parserImplementationInvariant } from "./parserImplementationInvariant.js";
4
+ export class WriteLater extends Error {
5
+ _position;
6
+ _length;
7
+ name = 'WriteLater';
8
+ constructor(_position, _length) {
9
+ super(`(position: ${_position}, length: ${_length})`);
10
+ this._position = _position;
11
+ this._length = _length;
12
+ }
13
+ get position() {
14
+ return this._position;
15
+ }
16
+ get positionEnd() {
17
+ return this._position + this._length;
18
+ }
19
+ get length() {
20
+ return this._length;
21
+ }
22
+ }
23
+ export class WriteEarlier {
24
+ writeLater;
25
+ unparserResult;
26
+ unparserContext;
27
+ constructor(writeLater, unparserResult, unparserContext) {
28
+ this.writeLater = writeLater;
29
+ this.unparserResult = unparserResult;
30
+ this.unparserContext = unparserContext;
31
+ }
32
+ }
33
+ export class UnparserContextImplementation {
34
+ _outputCompanion;
35
+ _position;
36
+ constructor(_outputCompanion, position = 0) {
37
+ this._outputCompanion = _outputCompanion;
38
+ this._position = position;
39
+ }
40
+ get position() {
41
+ return this._position;
42
+ }
43
+ async *writeLater(length) {
44
+ parserImplementationInvariant(length >= 0, 'Length of WriteLater must be non-negative, got %s.', length);
45
+ const writeLater = new WriteLater(this._position, length);
46
+ yield writeLater;
47
+ return writeLater;
48
+ }
49
+ async *writeEarlier(writeLater, unparser, input) {
50
+ const unparserContext = new UnparserContextImplementation(this._outputCompanion, writeLater.position);
51
+ yield new WriteEarlier(writeLater, (async function* () {
52
+ const startPosition = unparserContext.position;
53
+ yield* unparser(input, unparserContext);
54
+ const endPosition = unparserContext.position;
55
+ const writtenLength = endPosition - startPosition;
56
+ unparserImplementationInvariant(writtenLength === writeLater.length, [
57
+ 'WriteEarlier was supposed to write %s elements but wrote %s elements instead.',
58
+ 'Corresponding WriteLater stack (this is where it was created): %s',
59
+ 'End of corresponding WriteEarlier stack.',
60
+ ], writeLater.length, writtenLength, writeLater.stack);
61
+ })(), unparserContext);
62
+ }
63
+ handleYield(value) {
64
+ if (value instanceof WriteEarlier) {
65
+ return;
66
+ }
67
+ if (value instanceof WriteLater) {
68
+ this._position += value.length;
69
+ return;
70
+ }
71
+ const length = this._outputCompanion.length(value);
72
+ this._position += length;
73
+ }
74
+ }
@@ -0,0 +1,9 @@
1
+ export declare class UnparserError extends Error {
2
+ name: string;
3
+ }
4
+ export declare class UnparserImplementationError extends UnparserError {
5
+ name: string;
6
+ }
7
+ export declare class UnparserImplementationInvariantError extends UnparserImplementationError {
8
+ name: string;
9
+ }
@@ -0,0 +1,9 @@
1
+ export class UnparserError extends Error {
2
+ name = 'UnparserError';
3
+ }
4
+ export class UnparserImplementationError extends UnparserError {
5
+ name = 'UnparserImplementationError';
6
+ }
7
+ export class UnparserImplementationInvariantError extends UnparserImplementationError {
8
+ name = 'UnparserImplementationInvariantError';
9
+ }
@@ -0,0 +1,2 @@
1
+ import { type Falsy, type ValueOrAccessor } from './customInvariant.js';
2
+ export declare function unparserImplementationInvariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy>;
@@ -0,0 +1,5 @@
1
+ import { UnparserImplementationInvariantError } from './unparserError.js';
2
+ import { customInvariant } from './customInvariant.js';
3
+ export function unparserImplementationInvariant(value, format, ...formatArguments) {
4
+ return customInvariant(UnparserImplementationInvariantError, value, format, ...formatArguments);
5
+ }
@@ -0,0 +1,15 @@
1
+ import { StringParserInputCompanion, Uint8ArrayParserInputCompanion } from "./parserInputCompanion.js";
2
+ export type UnparserOutputCompanion<Sequence, Element> = {
3
+ is(value: unknown): value is Sequence;
4
+ from(elements: Element[]): Sequence;
5
+ concat(sequences: Sequence[]): Sequence;
6
+ length(sequence: Sequence): number;
7
+ };
8
+ export declare class StringUnparserOutputCompanion extends StringParserInputCompanion implements UnparserOutputCompanion<string, string> {
9
+ concat(sequences: string[]): string;
10
+ }
11
+ export declare const stringUnparserOutputCompanion: StringUnparserOutputCompanion;
12
+ export declare class Uint8ArrayUnparserOutputCompanion extends Uint8ArrayParserInputCompanion implements UnparserOutputCompanion<Uint8Array, number> {
13
+ concat(sequences: Uint8Array[]): Uint8Array;
14
+ }
15
+ export declare const uint8ArrayUnparserOutputCompanion: Uint8ArrayUnparserOutputCompanion;
@@ -0,0 +1,13 @@
1
+ import { StringParserInputCompanion, Uint8ArrayParserInputCompanion } from "./parserInputCompanion.js";
2
+ export class StringUnparserOutputCompanion extends StringParserInputCompanion {
3
+ concat(sequences) {
4
+ return sequences.join('');
5
+ }
6
+ }
7
+ export const stringUnparserOutputCompanion = new StringUnparserOutputCompanion();
8
+ export class Uint8ArrayUnparserOutputCompanion extends Uint8ArrayParserInputCompanion {
9
+ concat(sequences) {
10
+ return Buffer.concat(sequences);
11
+ }
12
+ }
13
+ export const uint8ArrayUnparserOutputCompanion = new Uint8ArrayUnparserOutputCompanion();
@@ -0,0 +1,15 @@
1
+ import { StringParserInputCompanion, Uint8ArrayParserInputCompanion } from "./parserInputCompanion.js";
2
+ export type UnparserOutputCompanion<Sequence, Element> = {
3
+ is(value: unknown): value is Sequence;
4
+ from(elements: Element[]): Sequence;
5
+ concat(sequences: Sequence[]): Sequence;
6
+ length(sequence: Sequence): number;
7
+ };
8
+ export declare class StringUnparserOutputCompanion extends StringParserInputCompanion implements UnparserOutputCompanion<string, string> {
9
+ concat(sequences: string[]): string;
10
+ }
11
+ export declare const stringUnparserOutputCompanion: StringUnparserOutputCompanion;
12
+ export declare class Uint8ArrayUnparserOutputCompanion extends Uint8ArrayParserInputCompanion implements UnparserOutputCompanion<Uint8Array, number> {
13
+ concat(sequences: Uint8Array[]): Uint8Array;
14
+ }
15
+ export declare const uint8ArrayUnparserOutputCompanion: Uint8ArrayUnparserOutputCompanion;
@@ -0,0 +1,13 @@
1
+ import { StringParserInputCompanion, Uint8ArrayParserInputCompanion } from "./parserInputCompanion.js";
2
+ export class StringUnparserOutputCompanion extends StringParserInputCompanion {
3
+ concat(sequences) {
4
+ return sequences.join('');
5
+ }
6
+ }
7
+ export const stringUnparserOutputCompanion = new StringUnparserOutputCompanion();
8
+ export class Uint8ArrayUnparserOutputCompanion extends Uint8ArrayParserInputCompanion {
9
+ concat(sequences) {
10
+ return Buffer.concat(sequences);
11
+ }
12
+ }
13
+ export const uint8ArrayUnparserOutputCompanion = new Uint8ArrayUnparserOutputCompanion();
package/build/zip.d.ts CHANGED
@@ -1,31 +1,23 @@
1
1
  export type ZipCompression = 'store' | 'deflate';
2
- export type ZipUnixPermissions = {
3
- type: 'unix';
4
- unixPermissions: number;
5
- };
6
- export type ZipDosPermissions = {
7
- type: 'dos';
8
- dosPermissions: number;
9
- };
10
- export type ZipPermissions = ZipUnixPermissions | ZipDosPermissions;
11
- export type ZipFileEntry = {
12
- type: 'file';
2
+ export type ZipEntryAttributes = {};
3
+ type ZipEntryCommon = {
13
4
  path: string;
14
5
  date: Date;
15
6
  comment: string;
16
- permissions: ZipPermissions;
7
+ hostSystem: 'unix' | 'dos';
8
+ attributes: ZipEntryAttributes;
9
+ };
10
+ export type ZipFileEntry = ZipEntryCommon & {
11
+ type: 'file';
17
12
  compression: ZipCompression;
18
13
  content: Uint8Array;
19
14
  };
20
- export type ZipDirectoryEntry = {
15
+ export type ZipDirectoryEntry = ZipEntryCommon & {
21
16
  type: 'directory';
22
- path: string;
23
- date: Date;
24
- comment: string;
25
- permissions: ZipPermissions;
26
17
  };
27
18
  export type ZipEntry = ZipFileEntry | ZipDirectoryEntry;
28
19
  export type Zip = {
29
20
  comment: string;
30
21
  entries: ZipEntry[];
31
22
  };
23
+ export {};
@@ -1,17 +1,17 @@
1
- import { Parser } from "./parser.js";
2
- import { Zip, ZipCompression, ZipEntry } from "./zip.js";
1
+ import { type Parser } from './parser.js';
2
+ import { type Zip, type ZipCompression, type ZipEntry } from './zip.js';
3
3
  type ZipLocalFileHeader = {
4
4
  versionNeededToExtract: number;
5
5
  generalPurposeBitFlag: number;
6
6
  compressionMethod: ZipCompression;
7
- lastModFile: Date;
7
+ lastModifiedFile: Date;
8
8
  crc32: number;
9
9
  compressedSize: number;
10
10
  uncompressedSize: number;
11
- fileName: string;
11
+ filePath: string;
12
12
  extraField: Uint8Array;
13
13
  };
14
- type ZipLocalFile = {
14
+ export type ZipLocalFile = {
15
15
  zipLocalFileHeader: ZipLocalFileHeader;
16
16
  zipEncryptionHeader: unknown;
17
17
  compressedData: Uint8Array;
@@ -24,27 +24,30 @@ type ZipVersionMadeBy = {
24
24
  hostSystem: number;
25
25
  zipSpecificationVersion: number;
26
26
  };
27
- type ZipCentralDirectoryHeader = {
27
+ type ZipExternalFileAttributes = {
28
+ directory: boolean;
29
+ };
30
+ export type ZipCentralDirectoryHeader = {
28
31
  versionMadeBy: ZipVersionMadeBy;
29
32
  versionNeededToExtract: number;
30
33
  generalPurposeBitFlag: number;
31
34
  compressionMethod: ZipCompression;
32
- lastModFile: Date;
35
+ lastModifiedFile: Date;
33
36
  crc32: number;
34
37
  compressedSize: number;
35
38
  uncompressedSize: number;
36
39
  diskNumberStart: number;
37
40
  internalFileAttributes: number;
38
- externalFileAttributes: number;
41
+ externalFileAttributes: ZipExternalFileAttributes;
39
42
  relativeOffsetOfLocalHeader: number;
40
- fileName: string;
43
+ filePath: string;
41
44
  extraField: Uint8Array;
42
45
  fileComment: string;
43
46
  };
44
47
  export declare const zipCentralDirectoryHeaderParser: Parser<ZipCentralDirectoryHeader, Uint8Array>;
45
48
  export declare const zip64EndOfCentralDirectoryRecordParser: Parser<unknown, Uint8Array>;
46
49
  export declare const zip64EndOfCentralDirectoryLocatorParser: Parser<unknown, Uint8Array>;
47
- type ZipEndOfCentralDirectoryRecord = {
50
+ export type ZipEndOfCentralDirectoryRecord = {
48
51
  numberOfThisDisk: number;
49
52
  numberOfTheDiskWithTheStartOfTheCentralDirectory: number;
50
53
  totalNumberOfEntriesInTheCentralDirectoryOnThisDisk: number;
@@ -1,15 +1,16 @@
1
- import invariant from "invariant";
2
- import zlib from "node:zlib";
3
- import { createArrayParser } from "./arrayParser.js";
4
- import { createExactSequenceParser } from "./exactSequenceParser.js";
5
- import { setParserName } from "./parser.js";
6
- import { createTupleParser } from "./tupleParser.js";
7
- import { promiseCompose } from "./promiseCompose.js";
8
- import { createFixedLengthSequenceParser } from "./fixedLengthSequenceParser.js";
9
- import { createOptionalParser } from "./optionalParser.js";
10
- import { parserCreatorCompose } from "./parserCreatorCompose.js";
11
- import { Readable } from "node:stream";
12
- import { pipeline } from "node:stream/promises";
1
+ import zlib from 'node:zlib';
2
+ import { Readable } from 'node:stream';
3
+ import { pipeline } from 'node:stream/promises';
4
+ import invariant from 'invariant';
5
+ import { createArrayParser } from './arrayParser.js';
6
+ import { createExactSequenceParser } from './exactSequenceParser.js';
7
+ import { setParserName } from './parser.js';
8
+ import { createTupleParser } from './tupleParser.js';
9
+ import { promiseCompose } from './promiseCompose.js';
10
+ import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
11
+ import { createOptionalParser } from './optionalParser.js';
12
+ import { parserCreatorCompose } from './parserCreatorCompose.js';
13
+ import { uint8ArrayAsyncIterableToUint8Array } from './uint8Array.js';
13
14
  // https://pkwaredownloads.blob.core.windows.net/pem/APPNOTE.txt
14
15
  const uint16LEParser = promiseCompose(createFixedLengthSequenceParser(2), array => Buffer.from(array).readUInt16LE());
15
16
  setParserName(uint16LEParser, 'uint16LEParser');
@@ -18,7 +19,7 @@ setParserName(uint32LEParser, 'uint32LEParser');
18
19
  const dosDateTimeParser = promiseCompose(createTupleParser([
19
20
  uint16LEParser,
20
21
  uint16LEParser,
21
- ]), ([time, date]) => new Date(Date.UTC(1980 + ((date >> 9) & 0x7f), ((date >> 5) & 0xf) - 1, date & 0x1f, (time >> 11) & 0x1f, (time >> 5) & 0x3f, (time & 0x1f) * 2)));
22
+ ]), ([time, date]) => new Date(Date.UTC(1980 + ((date >> 9) & 0x7F), ((date >> 5) & 0xF) - 1, date & 0x1F, (time >> 11) & 0x1F, (time >> 5) & 0x3F, (time & 0x1F) * 2)));
22
23
  const zipCompressionMethodParser = promiseCompose(uint16LEParser, compressionMethod => {
23
24
  if (compressionMethod === 0) {
24
25
  return 'store';
@@ -40,21 +41,21 @@ const zipLocalFileHeaderParser_ = createTupleParser([
40
41
  parserCreatorCompose(() => createTupleParser([
41
42
  uint16LEParser,
42
43
  uint16LEParser,
43
- ]), ([fileNameLength, extraFieldLength,]) => createTupleParser([
44
- createFixedLengthSequenceParser(fileNameLength),
44
+ ]), ([filePathLength, extraFieldLength,]) => createTupleParser([
45
+ createFixedLengthSequenceParser(filePathLength),
45
46
  createFixedLengthSequenceParser(extraFieldLength),
46
47
  ]))(),
47
48
  ]);
48
49
  setParserName(zipLocalFileHeaderParser_, 'zipLocalFileHeaderParser_');
49
- const zipLocalFileHeaderParser = promiseCompose(zipLocalFileHeaderParser_, ([_zipLocalFileHeaderSignature, versionNeededToExtract, generalPurposeBitFlag, compressionMethod, lastModFile, crc32, compressedSize, uncompressedSize, [fileName, extraField],]) => ({
50
+ const zipLocalFileHeaderParser = promiseCompose(zipLocalFileHeaderParser_, ([_zipLocalFileHeaderSignature, versionNeededToExtract, generalPurposeBitFlag, compressionMethod, lastModifiedFile, crc32, compressedSize, uncompressedSize, [filePath, extraField],]) => ({
50
51
  versionNeededToExtract,
51
52
  generalPurposeBitFlag,
52
53
  compressionMethod,
53
- lastModFile,
54
+ lastModifiedFile,
54
55
  crc32,
55
56
  compressedSize,
56
57
  uncompressedSize,
57
- fileName: Buffer.from(fileName).toString('utf8'),
58
+ filePath: Buffer.from(filePath).toString('utf8'),
58
59
  extraField,
59
60
  }));
60
61
  const zipEncryptionHeaderParser = async (parserContext) => {
@@ -68,7 +69,7 @@ const zipDataDescriptorParser = createTupleParser([
68
69
  uint32LEParser,
69
70
  uint32LEParser,
70
71
  ]);
71
- export const zipLocalFileParser = promiseCompose(parserCreatorCompose(() => zipLocalFileHeaderParser, (zipLocalFileHeader) => createTupleParser([
72
+ export const zipLocalFileParser = promiseCompose(parserCreatorCompose(() => zipLocalFileHeaderParser, zipLocalFileHeader => createTupleParser([
72
73
  async () => zipLocalFileHeader,
73
74
  createOptionalParser(zipEncryptionHeaderParser),
74
75
  createFixedLengthSequenceParser(zipLocalFileHeader.compressedSize),
@@ -90,9 +91,18 @@ const zipVersionMadeByParser = promiseCompose(createFixedLengthSequenceParser(2)
90
91
  hostSystem,
91
92
  zipSpecificationVersion,
92
93
  }));
93
- const zipCentralDirectoryHeaderParser_ = createTupleParser([
94
+ const dosExternalFileAttributesParser = promiseCompose(uint32LEParser, externalFileAttributes => ({
95
+ directory: (externalFileAttributes & 0b0001_0000) !== 0,
96
+ }));
97
+ const unixExternalFileAttributesParser = promiseCompose(uint32LEParser, externalFileAttributes => ({
98
+ directory: (externalFileAttributes & (0b0100_0000_0000_0000 << 16)) !== 0,
99
+ }));
100
+ const createExternalFileAttributesParser = (hostSystem) => promiseCompose(hostSystem === 0 ? dosExternalFileAttributesParser : unixExternalFileAttributesParser, externalFileAttributes => externalFileAttributes);
101
+ const zipCentralDirectoryHeaderParser_ = parserCreatorCompose(() => createTupleParser([
94
102
  createExactSequenceParser(Buffer.from('504b0102', 'hex')),
95
103
  zipVersionMadeByParser,
104
+ ]), ([_centralDirectoryHeaderSignature, versionMadeBy,]) => createTupleParser([
105
+ async () => versionMadeBy,
96
106
  uint16LEParser,
97
107
  uint16LEParser,
98
108
  zipCompressionMethodParser,
@@ -106,10 +116,10 @@ const zipCentralDirectoryHeaderParser_ = createTupleParser([
106
116
  uint16LEParser,
107
117
  uint16LEParser,
108
118
  uint16LEParser,
119
+ createExternalFileAttributesParser(versionMadeBy.hostSystem),
109
120
  uint32LEParser,
110
- uint32LEParser,
111
- ]), ([fileNameLength, extraFieldLength, fileCommentLength, diskNumberStart, internalFileAttributes, externalFileAttributes, relativeOffsetOfLocalHeader,]) => createTupleParser([
112
- createFixedLengthSequenceParser(fileNameLength),
121
+ ]), ([filePathLength, extraFieldLength, fileCommentLength, diskNumberStart, internalFileAttributes, externalFileAttributes, relativeOffsetOfLocalHeader,]) => createTupleParser([
122
+ createFixedLengthSequenceParser(filePathLength),
113
123
  createFixedLengthSequenceParser(extraFieldLength),
114
124
  createFixedLengthSequenceParser(fileCommentLength),
115
125
  async () => diskNumberStart,
@@ -117,14 +127,14 @@ const zipCentralDirectoryHeaderParser_ = createTupleParser([
117
127
  async () => externalFileAttributes,
118
128
  async () => relativeOffsetOfLocalHeader,
119
129
  ]))(),
120
- ]);
130
+ ]))();
121
131
  setParserName(zipCentralDirectoryHeaderParser_, 'centralDirectoryHeaderParser_');
122
- export const zipCentralDirectoryHeaderParser = promiseCompose(zipCentralDirectoryHeaderParser_, ([_centralDirectoryHeaderSignature, versionMadeBy, versionNeededToExtract, generalPurposeBitFlag, compressionMethod, lastModFile, crc32, compressedSize, uncompressedSize, [fileName, extraField, fileComment, diskNumberStart, internalFileAttributes, externalFileAttributes, relativeOffsetOfLocalHeader,],]) => ({
132
+ export const zipCentralDirectoryHeaderParser = promiseCompose(zipCentralDirectoryHeaderParser_, ([versionMadeBy, versionNeededToExtract, generalPurposeBitFlag, compressionMethod, lastModifiedFile, crc32, compressedSize, uncompressedSize, [filePath, extraField, fileComment, diskNumberStart, internalFileAttributes, externalFileAttributes, relativeOffsetOfLocalHeader,],]) => ({
123
133
  versionMadeBy,
124
134
  versionNeededToExtract,
125
135
  generalPurposeBitFlag,
126
136
  compressionMethod,
127
- lastModFile,
137
+ lastModifiedFile,
128
138
  crc32,
129
139
  compressedSize,
130
140
  uncompressedSize,
@@ -132,7 +142,7 @@ export const zipCentralDirectoryHeaderParser = promiseCompose(zipCentralDirector
132
142
  internalFileAttributes,
133
143
  externalFileAttributes,
134
144
  relativeOffsetOfLocalHeader,
135
- fileName: Buffer.from(fileName).toString('utf8'),
145
+ filePath: Buffer.from(filePath).toString('utf8'),
136
146
  extraField,
137
147
  fileComment: Buffer.from(fileComment).toString('utf8'),
138
148
  }));
@@ -179,36 +189,20 @@ export async function zipEntriesFromZipSegments({ zipLocalFiles, zipCentralDirec
179
189
  const { zipLocalFileHeader, compressedData, zipDataDescriptor, zipEncryptionHeader, } = zipLocalFile;
180
190
  const centralDirectoryHeader = zipCentralDirectoryHeaders.at(index);
181
191
  invariant(centralDirectoryHeader, 'Central directory header not found for local file %s', index);
182
- let isDosDirectory = false;
183
- let permissions = {
184
- type: 'unix',
185
- unixPermissions: 0,
186
- };
187
- if (centralDirectoryHeader.versionMadeBy.hostSystem === 0) {
188
- isDosDirectory = (centralDirectoryHeader.externalFileAttributes & 0b00010000) !== 0;
189
- permissions = {
190
- type: 'dos',
191
- dosPermissions: centralDirectoryHeader.externalFileAttributes & 0b00111111,
192
- };
193
- }
194
- if (centralDirectoryHeader.versionMadeBy.hostSystem === 3) {
195
- permissions = {
196
- type: 'unix',
197
- unixPermissions: (centralDirectoryHeader.externalFileAttributes >> 16) & 0b111111111,
198
- };
199
- }
200
192
  const commonFields = {
201
- path: zipLocalFileHeader.fileName,
193
+ path: zipLocalFileHeader.filePath,
202
194
  comment: centralDirectoryHeader.fileComment,
203
- date: zipLocalFileHeader.lastModFile,
204
- permissions,
195
+ date: zipLocalFileHeader.lastModifiedFile,
196
+ hostSystem: centralDirectoryHeader.versionMadeBy.hostSystem === 0 ? 'dos' : 'unix',
197
+ attributes: centralDirectoryHeader.externalFileAttributes,
205
198
  };
206
- const isDirectory = isDosDirectory || commonFields.path.endsWith('/');
199
+ const isDirectory = (centralDirectoryHeader.externalFileAttributes.directory
200
+ || commonFields.path.endsWith('/'));
207
201
  if (isDirectory) {
208
202
  return {
209
203
  ...commonFields,
210
204
  type: 'directory',
211
- path: commonFields.path.slice(0, -1),
205
+ path: commonFields.path.replace(/\/$/, ''),
212
206
  };
213
207
  }
214
208
  const fileEntry = {
@@ -217,18 +211,12 @@ export async function zipEntriesFromZipSegments({ zipLocalFiles, zipCentralDirec
217
211
  content: compressedData,
218
212
  compression: zipLocalFileHeader.compressionMethod,
219
213
  };
220
- if (fileEntry.content.length && fileEntry.compression === 'deflate') {
221
- const deflate = zlib.createInflateRaw();
214
+ if (fileEntry.content.length > 0 && fileEntry.compression === 'deflate') {
215
+ const inflate = zlib.createInflateRaw();
222
216
  const input = Readable.from(Buffer.from(compressedData));
223
217
  const [_, buffer] = await Promise.all([
224
- pipeline(input, deflate),
225
- (async () => {
226
- const chunks = [];
227
- for await (const chunk of deflate) {
228
- chunks.push(chunk);
229
- }
230
- return Buffer.concat(chunks);
231
- })(),
218
+ pipeline(input, inflate),
219
+ uint8ArrayAsyncIterableToUint8Array(inflate),
232
220
  ]);
233
221
  fileEntry.content = Uint8Array.from(buffer);
234
222
  }