@centralping/ergo 0.1.0-beta.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.
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/http/accepts.js +69 -0
- package/http/authorization.js +65 -0
- package/http/body.js +311 -0
- package/http/cache-control.js +123 -0
- package/http/compress.js +157 -0
- package/http/cookie.js +39 -0
- package/http/cors.js +79 -0
- package/http/csrf.js +76 -0
- package/http/handler.js +74 -0
- package/http/index.js +13 -0
- package/http/json-api-query.js +53 -0
- package/http/logger.js +167 -0
- package/http/main.js +140 -0
- package/http/precondition.js +53 -0
- package/http/prefer.js +36 -0
- package/http/rate-limit.js +66 -0
- package/http/security-headers.js +62 -0
- package/http/send.js +399 -0
- package/http/timeout.js +47 -0
- package/http/url.js +47 -0
- package/http/validate.js +84 -0
- package/lib/accepts.js +49 -0
- package/lib/attach-instance.js +23 -0
- package/lib/authorization.js +187 -0
- package/lib/body/multiparse.js +173 -0
- package/lib/body/multipart/headers.js +69 -0
- package/lib/body/writer.js +73 -0
- package/lib/cookie/cookie.js +192 -0
- package/lib/cookie/index.js +14 -0
- package/lib/cookie/jar.js +106 -0
- package/lib/cookie/parse.js +101 -0
- package/lib/cors.js +191 -0
- package/lib/csrf.js +96 -0
- package/lib/from-connect.js +69 -0
- package/lib/json-api-query/index.js +25 -0
- package/lib/json-api-query/schema.json +105 -0
- package/lib/json-api-query/validate.js +56 -0
- package/lib/link.js +96 -0
- package/lib/prefer.js +52 -0
- package/lib/query.js +113 -0
- package/lib/rate-limit.js +115 -0
- package/lib/sanitize-quoted-string.js +28 -0
- package/lib/security-headers.js +125 -0
- package/lib/validate.js +80 -0
- package/lib/vary.js +40 -0
- package/package.json +158 -0
- package/types/http/accepts.d.ts +8 -0
- package/types/http/authorization.d.ts +8 -0
- package/types/http/body.d.ts +20 -0
- package/types/http/cache-control.d.ts +16 -0
- package/types/http/compress.d.ts +5 -0
- package/types/http/cookie.d.ts +2 -0
- package/types/http/cors.d.ts +9 -0
- package/types/http/csrf.d.ts +9 -0
- package/types/http/handler.d.ts +2 -0
- package/types/http/index.d.ts +1 -0
- package/types/http/json-api-query.d.ts +2 -0
- package/types/http/logger.d.ts +9 -0
- package/types/http/main.d.ts +142 -0
- package/types/http/precondition.d.ts +44 -0
- package/types/http/prefer.d.ts +2 -0
- package/types/http/rate-limit.d.ts +17 -0
- package/types/http/security-headers.d.ts +10 -0
- package/types/http/send.d.ts +8 -0
- package/types/http/timeout.d.ts +5 -0
- package/types/http/url.d.ts +2 -0
- package/types/http/validate.d.ts +6 -0
- package/types/lib/accepts.d.ts +7 -0
- package/types/lib/attach-instance.d.ts +19 -0
- package/types/lib/authorization.d.ts +6 -0
- package/types/lib/body/multiparse.d.ts +9 -0
- package/types/lib/body/multipart/headers.d.ts +2 -0
- package/types/lib/body/writer.d.ts +2 -0
- package/types/lib/cookie/cookie.d.ts +32 -0
- package/types/lib/cookie/index.d.ts +2 -0
- package/types/lib/cookie/jar.d.ts +8 -0
- package/types/lib/cookie/parse.d.ts +19 -0
- package/types/lib/cors.d.ts +9 -0
- package/types/lib/csrf.d.ts +32 -0
- package/types/lib/from-connect.d.ts +47 -0
- package/types/lib/json-api-query/index.d.ts +123 -0
- package/types/lib/json-api-query/validate.d.ts +5 -0
- package/types/lib/link.d.ts +37 -0
- package/types/lib/prefer.d.ts +36 -0
- package/types/lib/query.d.ts +6 -0
- package/types/lib/rate-limit.d.ts +76 -0
- package/types/lib/sanitize-quoted-string.d.ts +19 -0
- package/types/lib/security-headers.d.ts +24 -0
- package/types/lib/validate.d.ts +16 -0
- package/types/lib/vary.d.ts +17 -0
- package/types/utils/attempt.d.ts +2 -0
- package/types/utils/buffers/index.d.ts +2 -0
- package/types/utils/buffers/match.d.ts +10 -0
- package/types/utils/buffers/split.d.ts +10 -0
- package/types/utils/compose-with.d.ts +40 -0
- package/types/utils/compose.d.ts +83 -0
- package/types/utils/flat-array.d.ts +2 -0
- package/types/utils/get.d.ts +5 -0
- package/types/utils/http-errors.d.ts +22 -0
- package/types/utils/iterables/buffer-split.d.ts +2 -0
- package/types/utils/iterables/chain.d.ts +2 -0
- package/types/utils/iterables/exec-all.d.ts +2 -0
- package/types/utils/iterables/filter.d.ts +2 -0
- package/types/utils/iterables/for-each.d.ts +2 -0
- package/types/utils/iterables/from-stream.d.ts +2 -0
- package/types/utils/iterables/index.d.ts +10 -0
- package/types/utils/iterables/map.d.ts +2 -0
- package/types/utils/iterables/range.d.ts +24 -0
- package/types/utils/iterables/reduce.d.ts +2 -0
- package/types/utils/iterables/take.d.ts +2 -0
- package/types/utils/observables/buffer-split.d.ts +2 -0
- package/types/utils/observables/chain.d.ts +2 -0
- package/types/utils/observables/index.d.ts +4 -0
- package/types/utils/observables/map.d.ts +2 -0
- package/types/utils/observables/take.d.ts +2 -0
- package/types/utils/pick.d.ts +2 -0
- package/types/utils/set.d.ts +2 -0
- package/types/utils/streams/index.d.ts +2 -0
- package/types/utils/streams/meter.d.ts +5 -0
- package/types/utils/streams/tee.d.ts +2 -0
- package/types/utils/type.d.ts +2 -0
- package/utils/attempt.js +37 -0
- package/utils/buffers/index.js +13 -0
- package/utils/buffers/match.js +96 -0
- package/utils/buffers/split.js +55 -0
- package/utils/compose-with.js +232 -0
- package/utils/compose.js +165 -0
- package/utils/flat-array.js +24 -0
- package/utils/get.js +39 -0
- package/utils/http-errors.js +113 -0
- package/utils/iterables/buffer-split.js +117 -0
- package/utils/iterables/chain.js +32 -0
- package/utils/iterables/exec-all.js +42 -0
- package/utils/iterables/filter.js +35 -0
- package/utils/iterables/for-each.js +33 -0
- package/utils/iterables/from-stream.js +29 -0
- package/utils/iterables/index.js +21 -0
- package/utils/iterables/map.js +47 -0
- package/utils/iterables/range.js +34 -0
- package/utils/iterables/reduce.js +43 -0
- package/utils/iterables/take.js +36 -0
- package/utils/observables/buffer-split.js +109 -0
- package/utils/observables/chain.js +33 -0
- package/utils/observables/index.js +19 -0
- package/utils/observables/map.js +34 -0
- package/utils/observables/take.js +40 -0
- package/utils/pick.js +41 -0
- package/utils/set.js +38 -0
- package/utils/streams/index.js +11 -0
- package/utils/streams/meter.js +98 -0
- package/utils/streams/tee.js +84 -0
- package/utils/type.js +47 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export default compose;
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Async pipeline composition utility.
|
|
4
|
+
*
|
|
5
|
+
* Creates an async pipeline from a list of middleware functions. Each function receives
|
|
6
|
+
* the original arguments plus the accumulated state object from prior middleware.
|
|
7
|
+
*
|
|
8
|
+
* - `compose(...fns)` — runs functions sequentially (`serial`)
|
|
9
|
+
* - `compose.all(...fns)` — runs functions concurrently and merges all results
|
|
10
|
+
* - `compose.withOptions(options, ...fns)` — sequential with options (e.g. `breakWhen`)
|
|
11
|
+
* - `compose.all.withOptions(options, ...fns)` — concurrent with options
|
|
12
|
+
*
|
|
13
|
+
* State is accumulated into a null-prototype accumulator object with an
|
|
14
|
+
* `isAccumulator: true` flag and a `size` getter. If the last argument passed to the
|
|
15
|
+
* composed pipeline is already an accumulator object, it is reused for accumulation.
|
|
16
|
+
*
|
|
17
|
+
* Serial composition uses a sync fast-path: when a middleware returns a non-thenable
|
|
18
|
+
* value, the result is merged immediately without scheduling a microtask. This
|
|
19
|
+
* eliminates unnecessary `await` overhead for synchronous middleware (the majority
|
|
20
|
+
* of ergo's built-in middleware).
|
|
21
|
+
*
|
|
22
|
+
* @module utils/compose
|
|
23
|
+
* @version 0.2.0
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* import compose from 'ergo/utils/compose';
|
|
28
|
+
*
|
|
29
|
+
* const pipeline = compose(
|
|
30
|
+
* async (req, res) => ({user: await getUser(req)}),
|
|
31
|
+
* async (req, res, {user}) => ({role: await getRole(user)})
|
|
32
|
+
* );
|
|
33
|
+
*
|
|
34
|
+
* const result = await pipeline(req, res);
|
|
35
|
+
* // result.user, result.role
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Early termination with breakWhen
|
|
39
|
+
* const pipeline = compose.withOptions(
|
|
40
|
+
* {breakWhen: (acc) => acc.done},
|
|
41
|
+
* () => ({done: true, a: 1}),
|
|
42
|
+
* () => ({b: 2}) // never reached
|
|
43
|
+
* );
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Composes middleware functions into an async pipeline with result accumulation.
|
|
47
|
+
*
|
|
48
|
+
* @param {...function} fns - Middleware functions to compose
|
|
49
|
+
* @returns {function} - Async composed pipeline
|
|
50
|
+
*/
|
|
51
|
+
declare function compose(...fns: Function[]): Function;
|
|
52
|
+
declare namespace compose {
|
|
53
|
+
function all(...fns: any[]): Function;
|
|
54
|
+
namespace all {
|
|
55
|
+
/**
|
|
56
|
+
* Creates a concurrent pipeline with configuration options.
|
|
57
|
+
*
|
|
58
|
+
* @param {object} options - Pipeline options
|
|
59
|
+
* @param {...function} fns - Middleware functions to compose
|
|
60
|
+
* @returns {function} - Async composed pipeline
|
|
61
|
+
*/
|
|
62
|
+
function withOptions(options: object, ...fns: Function[]): Function;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates a sequential pipeline with configuration options.
|
|
66
|
+
*
|
|
67
|
+
* @param {object} options - Pipeline options
|
|
68
|
+
* @param {function} [options.breakWhen] - Predicate `(acc) => boolean`; when truthy,
|
|
69
|
+
* serial iteration stops after the current step's result is merged
|
|
70
|
+
* @param {...function} fns - Middleware functions to compose
|
|
71
|
+
* @returns {function} - Async composed pipeline
|
|
72
|
+
*/
|
|
73
|
+
function withOptions(options: {
|
|
74
|
+
breakWhen?: Function | undefined;
|
|
75
|
+
}, ...fns: Function[]): Function;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Creates a null-prototype accumulator object.
|
|
79
|
+
*
|
|
80
|
+
* @param {object} [defaults={}] - Initial properties to copy into the accumulator
|
|
81
|
+
* @returns {object} - Null-prototype accumulator with `isAccumulator: true` and `size` getter
|
|
82
|
+
*/
|
|
83
|
+
export function accumulator(defaults?: object): object;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {number} [statusCode=500] - HTTP status code
|
|
3
|
+
* @param {object} [options] - RFC 9457 Problem Details fields
|
|
4
|
+
* @param {string} [options.type] - RFC 9457 `type` URI (defaults to MDN docs link)
|
|
5
|
+
* @param {string} [options.detail] - RFC 9457 `detail` (human-readable explanation)
|
|
6
|
+
* @param {string} [options.message] - Alias for `detail` (backward compat)
|
|
7
|
+
* @param {Array<[string, string]>} [options.headers] - Response headers to attach
|
|
8
|
+
* @param {string} [options.instance] - RFC 9457 `instance` URI identifying the specific occurrence
|
|
9
|
+
* @param {number|string} [options.retryAfter] - Retry-After value (seconds or HTTP-date).
|
|
10
|
+
* Auto-appended to `headers` as `['Retry-After', String(value)]` and included in toJSON().
|
|
11
|
+
* @param {Error} [options.originalError] - Underlying error
|
|
12
|
+
* @returns {Error} - Error with RFC 9457 properties and `toJSON()` method
|
|
13
|
+
*/
|
|
14
|
+
export default function httpErrors(statusCode?: number, { type, message, detail: rawDetail, headers, instance, retryAfter, originalError, ...extra }?: {
|
|
15
|
+
type?: string | undefined;
|
|
16
|
+
detail?: string | undefined;
|
|
17
|
+
message?: string | undefined;
|
|
18
|
+
headers?: [string, string][] | undefined;
|
|
19
|
+
instance?: string | undefined;
|
|
20
|
+
retryAfter?: string | number | undefined;
|
|
21
|
+
originalError?: Error | undefined;
|
|
22
|
+
}): Error;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default as bufferSplit } from "./buffer-split.js";
|
|
2
|
+
export { default as chain } from "./chain.js";
|
|
3
|
+
export { default as execAll } from "./exec-all.js";
|
|
4
|
+
export { default as filter } from "./filter.js";
|
|
5
|
+
export { default as forEach } from "./for-each.js";
|
|
6
|
+
export { default as fromStream } from "./from-stream.js";
|
|
7
|
+
export { default as map } from "./map.js";
|
|
8
|
+
export { default as range } from "./range.js";
|
|
9
|
+
export { default as reduce } from "./reduce.js";
|
|
10
|
+
export { default as take } from "./take.js";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Integer range generator.
|
|
3
|
+
*
|
|
4
|
+
* Produces a sequence of integers from `start` (inclusive) to `stop` (exclusive)
|
|
5
|
+
* stepping by `step`. Mirrors Python's `range()` behaviour.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/iterables/range
|
|
8
|
+
* @version 0.1.0
|
|
9
|
+
* @since 0.1.0
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* import range from 'ergo/utils/iterables/range';
|
|
13
|
+
*
|
|
14
|
+
* [...range(5)] // => [0, 1, 2, 3, 4]
|
|
15
|
+
* [...range(1, 5)] // => [1, 2, 3, 4]
|
|
16
|
+
* [...range(0, 10, 2)] // => [0, 2, 4, 6, 8]
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* @param {number} start - Start value (or stop if only one arg)
|
|
20
|
+
* @param {number} [stop] - Exclusive upper bound
|
|
21
|
+
* @param {number} [step=1] - Step increment
|
|
22
|
+
* @returns {Generator<number>} - Sequence of integers
|
|
23
|
+
*/
|
|
24
|
+
export default function _default(start: number, stop?: number, step?: number): Generator<number>;
|
package/utils/attempt.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Try/catch wrapper for async functions.
|
|
3
|
+
*
|
|
4
|
+
* Wraps an async `fn` so that if it throws, the `fail` function is called with
|
|
5
|
+
* the original arguments plus the caught error appended. Both functions are awaited.
|
|
6
|
+
*
|
|
7
|
+
* Used by `http/handler.js` to wrap the try pipeline with an error handler pipeline.
|
|
8
|
+
*
|
|
9
|
+
* @module utils/attempt
|
|
10
|
+
* @version 0.1.0
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* import attempt from 'ergo/utils/attempt';
|
|
15
|
+
*
|
|
16
|
+
* const safe = attempt(
|
|
17
|
+
* async (req, res) => { throw new Error('oops'); },
|
|
18
|
+
* async (req, res, err) => { res.writeHead(500); res.end(err.message); }
|
|
19
|
+
* );
|
|
20
|
+
*
|
|
21
|
+
* await safe(req, res); // calls the fail function with (req, res, err)
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {function} fn - Primary async function to execute
|
|
26
|
+
* @param {function} fail - Error handler called with (...originalArgs, error)
|
|
27
|
+
* @returns {function} - Wrapped async function with try/catch behavior
|
|
28
|
+
*/
|
|
29
|
+
export default (fn, fail) => {
|
|
30
|
+
return async (...args) => {
|
|
31
|
+
try {
|
|
32
|
+
return await fn(...args);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
return await fail(...args, e);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Buffer utilities barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Provides `match` (KMP substring search in Buffers) and `split` (Buffer split by separator).
|
|
5
|
+
*
|
|
6
|
+
* @module utils/buffers
|
|
7
|
+
* @version 0.1.0
|
|
8
|
+
* @since 0.1.0
|
|
9
|
+
* @requires ./match.js
|
|
10
|
+
* @requires ./split.js
|
|
11
|
+
*/
|
|
12
|
+
export {default as match} from './match.js';
|
|
13
|
+
export {default as split} from './split.js';
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview KMP (Knuth-Morris-Pratt) substring search for Node.js Buffers.
|
|
3
|
+
*
|
|
4
|
+
* Finds all occurrences of a byte pattern in a Buffer using the KMP algorithm.
|
|
5
|
+
* Supports incremental/streaming search by accepting and returning a `partial` counter
|
|
6
|
+
* and pre-computed `lookup` table, enabling multi-chunk searches without re-scanning.
|
|
7
|
+
*
|
|
8
|
+
* Returns match start indices, the KMP failure function (`lookup`), and the unfinished
|
|
9
|
+
* match state (`partial`) for the next chunk.
|
|
10
|
+
*
|
|
11
|
+
* @module utils/buffers/match
|
|
12
|
+
* @version 0.1.0
|
|
13
|
+
* @since 0.1.0
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import bufferMatch from 'ergo/utils/buffers/match';
|
|
17
|
+
*
|
|
18
|
+
* const {matches} = bufferMatch(Buffer.from('hello world'), Buffer.from('l'));
|
|
19
|
+
* // matches => [2, 3, 9]
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Searches for all occurrences of `searchBuffer` in `buffer` using KMP.
|
|
23
|
+
*
|
|
24
|
+
* @param {import('node:buffer').Buffer} [buffer=Buffer.from('')] - The buffer to search within
|
|
25
|
+
* @param {import('node:buffer').Buffer} [searchBuffer] - The byte pattern to search for
|
|
26
|
+
* @param {object} [options] - KMP search options
|
|
27
|
+
* @param {number} [options.limit=Infinity] - Maximum matches to return
|
|
28
|
+
* @param {number} [options.partial=0] - KMP partial match state from a prior chunk
|
|
29
|
+
* @param {number[]} [options.lookup] - Pre-computed KMP failure function table
|
|
30
|
+
* @returns {{matches: number[], partial: number, lookup: number[]}} - Match result with indices, partial state, and lookup table
|
|
31
|
+
*/
|
|
32
|
+
export default (
|
|
33
|
+
buffer = Buffer.from(''),
|
|
34
|
+
searchBuffer,
|
|
35
|
+
{limit = Infinity, partial = 0, lookup} = {}
|
|
36
|
+
) => {
|
|
37
|
+
/* eslint-disable no-param-reassign */
|
|
38
|
+
const matches = [];
|
|
39
|
+
|
|
40
|
+
if (lookup === undefined) {
|
|
41
|
+
lookup = makeLookup(searchBuffer);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (lookup.length === 0) {
|
|
45
|
+
return {matches, partial, lookup};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (let i = partial; i < buffer.length; i++) {
|
|
49
|
+
while (partial >= 0 && buffer[i] !== searchBuffer[partial]) {
|
|
50
|
+
if (partial > 0) {
|
|
51
|
+
partial = lookup[partial - 1];
|
|
52
|
+
} else {
|
|
53
|
+
partial = -1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
partial += 1;
|
|
58
|
+
if (partial === searchBuffer.length) {
|
|
59
|
+
matches.push(i - partial + 1);
|
|
60
|
+
partial = 0;
|
|
61
|
+
|
|
62
|
+
if (matches.length >= limit) {
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {matches, partial, lookup};
|
|
69
|
+
/* eslint-enable no-param-reassign */
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Builds the KMP failure function (partial match table) for a byte pattern.
|
|
74
|
+
*
|
|
75
|
+
* @param {import('node:buffer').Buffer|string} [searchBuffer=''] - The pattern to pre-process
|
|
76
|
+
* @returns {number[]} - The KMP failure function table
|
|
77
|
+
*/
|
|
78
|
+
function makeLookup(searchBuffer = '') {
|
|
79
|
+
const lookup = [];
|
|
80
|
+
let pos = -1;
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < searchBuffer.length; i++) {
|
|
83
|
+
while (pos >= 0 && searchBuffer[i] !== searchBuffer[pos]) {
|
|
84
|
+
pos -= 1;
|
|
85
|
+
|
|
86
|
+
if (pos >= 0) {
|
|
87
|
+
pos = lookup[pos];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pos += 1;
|
|
92
|
+
lookup.push(pos);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return lookup;
|
|
96
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Buffer split utility using KMP-based pattern matching.
|
|
3
|
+
*
|
|
4
|
+
* Splits a Buffer by a separator pattern, analogous to `String.prototype.split()`.
|
|
5
|
+
* Supports incremental/streaming operation by threading `partial` and `lookup`
|
|
6
|
+
* state across chunks.
|
|
7
|
+
*
|
|
8
|
+
* Returns `{buffers, partial, lookup}` where `buffers` is the array of Buffer slices.
|
|
9
|
+
*
|
|
10
|
+
* @module utils/buffers/split
|
|
11
|
+
* @version 0.1.0
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
* @requires ./match.js
|
|
14
|
+
* @requires ../get.js
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* import bufferSplit from 'ergo/utils/buffers/split';
|
|
18
|
+
*
|
|
19
|
+
* const {buffers} = bufferSplit(Buffer.from('a--b--c'), Buffer.from('--'));
|
|
20
|
+
* // buffers => [Buffer<'a'>, Buffer<'b'>, Buffer<'c'>]
|
|
21
|
+
*/
|
|
22
|
+
import bufferMatch from './match.js';
|
|
23
|
+
import get from '../get.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Splits a Buffer by a separator pattern.
|
|
27
|
+
*
|
|
28
|
+
* @param {import('node:buffer').Buffer|string} buffer - Source buffer to split
|
|
29
|
+
* @param {import('node:buffer').Buffer} [separator] - Byte pattern to split on
|
|
30
|
+
* @param {object} [options] - KMP split options
|
|
31
|
+
* @param {number} [options.limit=Infinity] - Maximum splits to produce
|
|
32
|
+
* @param {number} [options.partial=0] - Partial KMP match state from prior chunk
|
|
33
|
+
* @param {number[]} [options.lookup] - Pre-computed KMP failure function table
|
|
34
|
+
* @returns {{buffers: import('node:buffer').Buffer[], partial: number, lookup: number[]}} - Split result with buffer slices, partial state, and lookup table
|
|
35
|
+
*/
|
|
36
|
+
export default (buffer = Buffer.from(''), separator, {limit = Infinity, ...options} = {}) => {
|
|
37
|
+
const sepLen = get(separator, 'length', {safe: true}) ?? 0;
|
|
38
|
+
const {matches, ...rest} = bufferMatch(buffer, separator, {limit, ...options});
|
|
39
|
+
|
|
40
|
+
matches.push(buffer.length);
|
|
41
|
+
|
|
42
|
+
const splitsLength = Math.min(limit, matches.length);
|
|
43
|
+
|
|
44
|
+
let start = 0;
|
|
45
|
+
const buffers = Array.from({length: splitsLength}, (v, i) => {
|
|
46
|
+
const offset = matches[i];
|
|
47
|
+
const split = buffer.slice(start, offset);
|
|
48
|
+
|
|
49
|
+
start = offset + sepLen;
|
|
50
|
+
|
|
51
|
+
return split;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return {buffers, ...rest};
|
|
55
|
+
};
|