@remotion/gif 4.0.0-webhook.27 → 4.1.0-alpha2
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/LICENSE.md +8 -8
- package/dist/cjs/Gif.d.ts +7 -0
- package/dist/{Gif.js → cjs/Gif.js} +11 -6
- package/dist/{GifForDevelopment.d.ts → cjs/GifForDevelopment.d.ts} +0 -0
- package/dist/{GifForDevelopment.js → cjs/GifForDevelopment.js} +10 -5
- package/dist/{GifForRendering.d.ts → cjs/GifForRendering.d.ts} +0 -0
- package/dist/{GifForRendering.js → cjs/GifForRendering.js} +14 -5
- package/dist/{canvas.d.ts → cjs/canvas.d.ts} +1 -1
- package/dist/{canvas.js → cjs/canvas.js} +3 -0
- package/dist/cjs/get-gif-duration-in-seconds.d.ts +5 -0
- package/dist/{get-gif-duration-in-seconds.js → cjs/get-gif-duration-in-seconds.js} +8 -3
- package/dist/cjs/gif-cache.d.ts +4 -0
- package/dist/cjs/gif-cache.js +6 -0
- package/dist/cjs/gifuct/deinterlace.d.ts +4 -0
- package/dist/cjs/gifuct/deinterlace.js +26 -0
- package/dist/cjs/gifuct/index.d.ts +4 -0
- package/dist/cjs/gifuct/index.js +54 -0
- package/dist/cjs/gifuct/lzw.d.ts +5 -0
- package/dist/cjs/gifuct/lzw.js +119 -0
- package/dist/cjs/gifuct/types.d.ts +96 -0
- package/dist/{props.js → cjs/gifuct/types.js} +0 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +1 -0
- package/dist/{index.js → cjs/index.js} +3 -1
- package/dist/{is-cors-error.d.ts → cjs/is-cors-error.d.ts} +0 -0
- package/dist/{is-cors-error.js → cjs/is-cors-error.js} +0 -0
- package/dist/cjs/js-binary-schema-parser/gif.d.ts +51 -0
- package/dist/cjs/js-binary-schema-parser/gif.js +158 -0
- package/dist/cjs/js-binary-schema-parser/parser.d.ts +9 -0
- package/dist/cjs/js-binary-schema-parser/parser.js +54 -0
- package/dist/cjs/js-binary-schema-parser/uint8-parser.d.ts +17 -0
- package/dist/cjs/js-binary-schema-parser/uint8-parser.js +79 -0
- package/dist/cjs/lru/index.d.ts +101 -0
- package/dist/cjs/lru/index.js +258 -0
- package/dist/{parse-generate.d.ts → cjs/parse-generate.d.ts} +1 -1
- package/dist/{parse-generate.js → cjs/parse-generate.js} +27 -9
- package/dist/cjs/parser/decompress-frames.d.ts +2 -0
- package/dist/cjs/parser/decompress-frames.js +19 -0
- package/dist/cjs/preload-gif.d.ts +8 -0
- package/dist/cjs/preload-gif.js +41 -0
- package/dist/{props.d.ts → cjs/props.d.ts} +6 -3
- package/dist/cjs/props.js +2 -0
- package/dist/{react-tools.d.ts → cjs/react-tools.d.ts} +0 -0
- package/dist/{react-tools.js → cjs/react-tools.js} +1 -0
- package/dist/cjs/resolve-gif-source.d.ts +1 -0
- package/dist/cjs/resolve-gif-source.js +7 -0
- package/dist/{use-element-size.d.ts → cjs/use-element-size.d.ts} +1 -1
- package/dist/{use-element-size.js → cjs/use-element-size.js} +1 -1
- package/dist/cjs/useCurrentGifIndex.d.ts +2 -0
- package/dist/cjs/useCurrentGifIndex.js +35 -0
- package/dist/{worker → cjs/worker}/index.d.ts +0 -0
- package/dist/{worker → cjs/worker}/index.js +0 -0
- package/dist/cjs/worker/source.d.ts +1 -0
- package/dist/cjs/worker/source.js +7 -0
- package/dist/{worker → cjs/worker}/worker.d.ts +0 -0
- package/dist/{worker → cjs/worker}/worker.js +0 -0
- package/dist/esm/Gif.d.ts +7 -0
- package/dist/esm/GifForDevelopment.d.ts +3 -0
- package/dist/esm/GifForRendering.d.ts +3 -0
- package/dist/esm/canvas.d.ts +13 -0
- package/dist/esm/get-gif-duration-in-seconds.d.ts +5 -0
- package/dist/esm/gif-cache.d.ts +4 -0
- package/dist/esm/gifuct/deinterlace.d.ts +4 -0
- package/dist/esm/gifuct/index.d.ts +4 -0
- package/dist/esm/gifuct/lzw.d.ts +5 -0
- package/dist/esm/gifuct/types.d.ts +96 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.mjs +1281 -0
- package/dist/esm/is-cors-error.d.ts +1 -0
- package/dist/esm/js-binary-schema-parser/gif.d.ts +51 -0
- package/dist/esm/js-binary-schema-parser/parser.d.ts +9 -0
- package/dist/esm/js-binary-schema-parser/uint8-parser.d.ts +17 -0
- package/dist/esm/lru/index.d.ts +101 -0
- package/dist/esm/parse-generate.d.ts +18 -0
- package/dist/esm/parser/decompress-frames.d.ts +2 -0
- package/dist/esm/preload-gif.d.ts +8 -0
- package/dist/esm/props.d.ts +25 -0
- package/dist/esm/react-tools.d.ts +9 -0
- package/dist/esm/resolve-gif-source.d.ts +1 -0
- package/dist/esm/use-element-size.d.ts +6 -0
- package/dist/esm/useCurrentGifIndex.d.ts +2 -0
- package/dist/esm/worker/index.d.ts +1 -0
- package/dist/esm/worker/source.d.ts +1 -0
- package/dist/esm/worker/worker.d.ts +1 -0
- package/dist/tsconfig-esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +67 -57
- package/dist/Gif.d.ts +0 -3
- package/dist/get-gif-duration-in-seconds.d.ts +0 -1
- package/dist/gif-cache.d.ts +0 -3
- package/dist/gif-cache.js +0 -5
- package/dist/useCurrentGifIndex.d.ts +0 -1
- package/dist/useCurrentGifIndex.js +0 -28
- package/dist/worker/source.d.ts +0 -1
- package/dist/worker/source.js +0 -5
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GIF = void 0;
|
|
4
|
+
const parser_1 = require("./parser");
|
|
5
|
+
const uint8_parser_1 = require("./uint8-parser");
|
|
6
|
+
// a set of 0x00 terminated subblocks
|
|
7
|
+
const subBlocksSchema = {
|
|
8
|
+
blocks: (stream) => {
|
|
9
|
+
const terminator = 0x00;
|
|
10
|
+
const chunks = [];
|
|
11
|
+
const streamSize = stream.data.length;
|
|
12
|
+
let total = 0;
|
|
13
|
+
for (let size = (0, uint8_parser_1.readByte)()(stream); size !== terminator; size = (0, uint8_parser_1.readByte)()(stream)) {
|
|
14
|
+
// size becomes undefined for some case when file is corrupted and terminator is not proper
|
|
15
|
+
// null check to avoid recursion
|
|
16
|
+
if (!size)
|
|
17
|
+
break;
|
|
18
|
+
// catch corrupted files with no terminator
|
|
19
|
+
if (stream.pos + size >= streamSize) {
|
|
20
|
+
const availableSize = streamSize - stream.pos;
|
|
21
|
+
chunks.push((0, uint8_parser_1.readBytes)(availableSize)(stream));
|
|
22
|
+
total += availableSize;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
chunks.push((0, uint8_parser_1.readBytes)(size)(stream));
|
|
26
|
+
total += size;
|
|
27
|
+
}
|
|
28
|
+
const result = new Uint8Array(total);
|
|
29
|
+
let offset = 0;
|
|
30
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
31
|
+
result.set(chunks[i], offset);
|
|
32
|
+
offset += chunks[i].length;
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
// global control extension
|
|
38
|
+
const gceSchema = (0, parser_1.conditional)({
|
|
39
|
+
gce: [
|
|
40
|
+
{ codes: (0, uint8_parser_1.readBytes)(2) },
|
|
41
|
+
{ byteSize: (0, uint8_parser_1.readByte)() },
|
|
42
|
+
{
|
|
43
|
+
extras: (0, uint8_parser_1.readBits)({
|
|
44
|
+
future: { index: 0, length: 3 },
|
|
45
|
+
disposal: { index: 3, length: 3 },
|
|
46
|
+
userInput: { index: 6 },
|
|
47
|
+
transparentColorGiven: { index: 7 },
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
{ delay: (0, uint8_parser_1.readUnsigned)(true) },
|
|
51
|
+
{ transparentColorIndex: (0, uint8_parser_1.readByte)() },
|
|
52
|
+
{ terminator: (0, uint8_parser_1.readByte)() },
|
|
53
|
+
],
|
|
54
|
+
}, (stream) => {
|
|
55
|
+
const codes = (0, uint8_parser_1.peekBytes)(2)(stream);
|
|
56
|
+
return codes[0] === 0x21 && codes[1] === 0xf9;
|
|
57
|
+
});
|
|
58
|
+
// image pipeline block
|
|
59
|
+
const imageSchema = (0, parser_1.conditional)({
|
|
60
|
+
image: [
|
|
61
|
+
{ code: (0, uint8_parser_1.readByte)() },
|
|
62
|
+
{
|
|
63
|
+
descriptor: [
|
|
64
|
+
{ left: (0, uint8_parser_1.readUnsigned)(true) },
|
|
65
|
+
{ top: (0, uint8_parser_1.readUnsigned)(true) },
|
|
66
|
+
{ width: (0, uint8_parser_1.readUnsigned)(true) },
|
|
67
|
+
{ height: (0, uint8_parser_1.readUnsigned)(true) },
|
|
68
|
+
{
|
|
69
|
+
lct: (0, uint8_parser_1.readBits)({
|
|
70
|
+
exists: { index: 0 },
|
|
71
|
+
interlaced: { index: 1 },
|
|
72
|
+
sort: { index: 2 },
|
|
73
|
+
future: { index: 3, length: 2 },
|
|
74
|
+
size: { index: 5, length: 3 },
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
(0, parser_1.conditional)({
|
|
80
|
+
lct: (0, uint8_parser_1.readArray)(3, (_stream, _result, parent) => {
|
|
81
|
+
return 2 ** (parent.descriptor.lct.size + 1);
|
|
82
|
+
}),
|
|
83
|
+
}, (_stream, _result, parent) => {
|
|
84
|
+
return parent.descriptor.lct.exists;
|
|
85
|
+
}),
|
|
86
|
+
{ data: [{ minCodeSize: (0, uint8_parser_1.readByte)() }, subBlocksSchema] },
|
|
87
|
+
],
|
|
88
|
+
}, (stream) => {
|
|
89
|
+
return (0, uint8_parser_1.peekByte)()(stream) === 0x2c;
|
|
90
|
+
});
|
|
91
|
+
// plain text block
|
|
92
|
+
const textSchema = (0, parser_1.conditional)({
|
|
93
|
+
text: [
|
|
94
|
+
{ codes: (0, uint8_parser_1.readBytes)(2) },
|
|
95
|
+
{ blockSize: (0, uint8_parser_1.readByte)() },
|
|
96
|
+
{
|
|
97
|
+
preData: (stream, _result, parent) => (0, uint8_parser_1.readBytes)(parent.text.blockSize)(stream),
|
|
98
|
+
},
|
|
99
|
+
subBlocksSchema,
|
|
100
|
+
],
|
|
101
|
+
}, (stream) => {
|
|
102
|
+
const codes = (0, uint8_parser_1.peekBytes)(2)(stream);
|
|
103
|
+
return codes[0] === 0x21 && codes[1] === 0x01;
|
|
104
|
+
});
|
|
105
|
+
// application block
|
|
106
|
+
const applicationSchema = (0, parser_1.conditional)({
|
|
107
|
+
application: [
|
|
108
|
+
{ codes: (0, uint8_parser_1.readBytes)(2) },
|
|
109
|
+
{ blockSize: (0, uint8_parser_1.readByte)() },
|
|
110
|
+
{
|
|
111
|
+
id: (stream, _result, parent) => (0, uint8_parser_1.readString)(parent.blockSize)(stream),
|
|
112
|
+
},
|
|
113
|
+
subBlocksSchema,
|
|
114
|
+
],
|
|
115
|
+
}, (stream) => {
|
|
116
|
+
const codes = (0, uint8_parser_1.peekBytes)(2)(stream);
|
|
117
|
+
return codes[0] === 0x21 && codes[1] === 0xff;
|
|
118
|
+
});
|
|
119
|
+
// comment block
|
|
120
|
+
const commentSchema = (0, parser_1.conditional)({
|
|
121
|
+
comment: [{ codes: (0, uint8_parser_1.readBytes)(2) }, subBlocksSchema],
|
|
122
|
+
}, (stream) => {
|
|
123
|
+
const codes = (0, uint8_parser_1.peekBytes)(2)(stream);
|
|
124
|
+
return codes[0] === 0x21 && codes[1] === 0xfe;
|
|
125
|
+
});
|
|
126
|
+
exports.GIF = [
|
|
127
|
+
{ header: [{ signature: (0, uint8_parser_1.readString)(3) }, { version: (0, uint8_parser_1.readString)(3) }] },
|
|
128
|
+
{
|
|
129
|
+
lsd: [
|
|
130
|
+
{ width: (0, uint8_parser_1.readUnsigned)(true) },
|
|
131
|
+
{ height: (0, uint8_parser_1.readUnsigned)(true) },
|
|
132
|
+
{
|
|
133
|
+
gct: (0, uint8_parser_1.readBits)({
|
|
134
|
+
exists: { index: 0 },
|
|
135
|
+
resolution: { index: 1, length: 3 },
|
|
136
|
+
sort: { index: 4 },
|
|
137
|
+
size: { index: 5, length: 3 },
|
|
138
|
+
}),
|
|
139
|
+
},
|
|
140
|
+
{ backgroundColorIndex: (0, uint8_parser_1.readByte)() },
|
|
141
|
+
{ pixelAspectRatio: (0, uint8_parser_1.readByte)() },
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
(0, parser_1.conditional)({
|
|
145
|
+
gct: (0, uint8_parser_1.readArray)(3, (_stream, result) => 2 ** (result.lsd.gct.size + 1)),
|
|
146
|
+
}, (_stream, result) => result.lsd.gct.exists),
|
|
147
|
+
// content frames
|
|
148
|
+
{
|
|
149
|
+
frames: (0, parser_1.loop)([gceSchema, applicationSchema, commentSchema, imageSchema, textSchema], (stream) => {
|
|
150
|
+
const nextCode = (0, uint8_parser_1.peekByte)()(stream);
|
|
151
|
+
// rather than check for a terminator, we should check for the existence
|
|
152
|
+
// of an ext or image block to avoid infinite loops
|
|
153
|
+
// var terminator = 0x3B;
|
|
154
|
+
// return nextCode !== terminator;
|
|
155
|
+
return nextCode === 0x21 || nextCode === 0x2c;
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedGif } from '../gifuct/types';
|
|
2
|
+
import type { Stream } from './uint8-parser';
|
|
3
|
+
export declare const parse: <T extends Record<string, T>>(stream: Stream, schema: GifSchema, result?: T, parent?: T) => GifSchema;
|
|
4
|
+
export declare const loop: <R>(schema: GifSchema, continueFunc: (st: Stream, r: R, p: R) => boolean) => (stream: Stream, result: R, parent: R, _parse: ParseFn<R>) => R[];
|
|
5
|
+
type ConditionalFunction<T> = (st: Stream, result: T, parent: T) => boolean;
|
|
6
|
+
type ParseFn<T> = (st: Stream, schema: GifSchema, result: T, parent: T) => void;
|
|
7
|
+
export type GifSchema = unknown | ParsedGif;
|
|
8
|
+
export declare const conditional: <T>(schema: GifSchema, conditionFunc: ConditionalFunction<T>) => (stream: Stream, result: T, parent: T, parseFn: ParseFn<T>) => void;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.conditional = exports.loop = exports.parse = void 0;
|
|
4
|
+
const parse = (stream, schema, result = {}, parent = result) => {
|
|
5
|
+
if (Array.isArray(schema)) {
|
|
6
|
+
schema.forEach((partSchema) => {
|
|
7
|
+
return (0, exports.parse)(stream, partSchema, result, parent);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
else if (typeof schema === 'function') {
|
|
11
|
+
schema(stream, result, parent, exports.parse);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
// @ts-expect-error
|
|
15
|
+
const key = Object.keys(schema)[0];
|
|
16
|
+
// @ts-expect-error
|
|
17
|
+
if (Array.isArray(schema[key])) {
|
|
18
|
+
// @ts-expect-error
|
|
19
|
+
parent[key] = {};
|
|
20
|
+
// @ts-expect-error
|
|
21
|
+
(0, exports.parse)(stream, schema[key], result, parent[key]);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
// @ts-expect-error
|
|
25
|
+
parent[key] = schema[key](stream, result, parent, exports.parse);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
30
|
+
exports.parse = parse;
|
|
31
|
+
const loop = (schema, continueFunc) => {
|
|
32
|
+
return function (stream, result, parent, _parse) {
|
|
33
|
+
const arr = [];
|
|
34
|
+
let lastStreamPos = stream.pos;
|
|
35
|
+
while (continueFunc(stream, result, parent)) {
|
|
36
|
+
const newParent = {};
|
|
37
|
+
_parse(stream, schema, result, newParent); // cases when whole file is parsed but no termination is there and stream position is not getting updated as well
|
|
38
|
+
// it falls into infinite recursion, null check to avoid the same
|
|
39
|
+
if (stream.pos === lastStreamPos) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
lastStreamPos = stream.pos;
|
|
43
|
+
arr.push(newParent);
|
|
44
|
+
}
|
|
45
|
+
return arr;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
exports.loop = loop;
|
|
49
|
+
const conditional = (schema, conditionFunc) => (stream, result, parent, parseFn) => {
|
|
50
|
+
if (conditionFunc(stream, result, parent)) {
|
|
51
|
+
parseFn(stream, schema, result, parent);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
exports.conditional = conditional;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GifSchema } from './parser';
|
|
2
|
+
export type Stream = {
|
|
3
|
+
data: Uint8Array;
|
|
4
|
+
pos: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const buildStream: (uint8Data: Uint8Array) => {
|
|
7
|
+
data: Uint8Array;
|
|
8
|
+
pos: number;
|
|
9
|
+
};
|
|
10
|
+
export declare const readByte: () => (stream: Stream) => number;
|
|
11
|
+
export declare const peekByte: (offset?: number) => (stream: Stream) => number;
|
|
12
|
+
export declare const readBytes: (length: number) => (stream: Stream) => Uint8Array;
|
|
13
|
+
export declare const peekBytes: (length: number) => (stream: Stream) => Uint8Array;
|
|
14
|
+
export declare const readString: (length: number) => (stream: Stream) => string;
|
|
15
|
+
export declare const readUnsigned: (littleEndian: boolean) => (stream: Stream) => number;
|
|
16
|
+
export declare const readArray: <T>(byteSize: number, totalOrFunc: number | ((st: Stream, r: T, p: T) => number)) => (stream: Stream, result: T, parent: T) => any[];
|
|
17
|
+
export declare const readBits: (schema: GifSchema) => (stream: Stream) => Record<string, number | boolean>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-bitwise */
|
|
3
|
+
// Default stream and parsers for Uint8TypedArray data type
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.readBits = exports.readArray = exports.readUnsigned = exports.readString = exports.peekBytes = exports.readBytes = exports.peekByte = exports.readByte = exports.buildStream = void 0;
|
|
6
|
+
const buildStream = (uint8Data) => ({
|
|
7
|
+
data: uint8Data,
|
|
8
|
+
pos: 0,
|
|
9
|
+
});
|
|
10
|
+
exports.buildStream = buildStream;
|
|
11
|
+
const readByte = () => (stream) => {
|
|
12
|
+
return stream.data[stream.pos++];
|
|
13
|
+
};
|
|
14
|
+
exports.readByte = readByte;
|
|
15
|
+
const peekByte = (offset = 0) => (stream) => {
|
|
16
|
+
return stream.data[stream.pos + offset];
|
|
17
|
+
};
|
|
18
|
+
exports.peekByte = peekByte;
|
|
19
|
+
const readBytes = (length) => (stream) => {
|
|
20
|
+
// eslint-disable-next-line no-return-assign
|
|
21
|
+
return stream.data.subarray(stream.pos, (stream.pos += length));
|
|
22
|
+
};
|
|
23
|
+
exports.readBytes = readBytes;
|
|
24
|
+
const peekBytes = (length) => (stream) => {
|
|
25
|
+
return stream.data.subarray(stream.pos, stream.pos + length);
|
|
26
|
+
};
|
|
27
|
+
exports.peekBytes = peekBytes;
|
|
28
|
+
const readString = (length) => (stream) => {
|
|
29
|
+
return Array.from((0, exports.readBytes)(length)(stream))
|
|
30
|
+
.map((value) => String.fromCharCode(value))
|
|
31
|
+
.join('');
|
|
32
|
+
};
|
|
33
|
+
exports.readString = readString;
|
|
34
|
+
const readUnsigned = (littleEndian) => (stream) => {
|
|
35
|
+
const bytes = (0, exports.readBytes)(2)(stream);
|
|
36
|
+
return littleEndian ? (bytes[1] << 8) + bytes[0] : (bytes[0] << 8) + bytes[1];
|
|
37
|
+
};
|
|
38
|
+
exports.readUnsigned = readUnsigned;
|
|
39
|
+
const readArray = (byteSize, totalOrFunc) => (stream, result, parent) => {
|
|
40
|
+
const total = typeof totalOrFunc === 'function'
|
|
41
|
+
? totalOrFunc(stream, result, parent)
|
|
42
|
+
: totalOrFunc;
|
|
43
|
+
const parser = (0, exports.readBytes)(byteSize);
|
|
44
|
+
const arr = new Array(total);
|
|
45
|
+
for (let i = 0; i < total; i++) {
|
|
46
|
+
arr[i] = parser(stream);
|
|
47
|
+
}
|
|
48
|
+
return arr;
|
|
49
|
+
};
|
|
50
|
+
exports.readArray = readArray;
|
|
51
|
+
const subBitsTotal = (bits, startIndex, length) => {
|
|
52
|
+
let result = 0;
|
|
53
|
+
for (let i = 0; i < length; i++) {
|
|
54
|
+
result += Number(bits[startIndex + i] && 2 ** (length - i - 1));
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
const readBits = (schema) => (stream) => {
|
|
59
|
+
const byte = (0, exports.readByte)()(stream);
|
|
60
|
+
// convert the byte to bit array
|
|
61
|
+
const bits = new Array(8);
|
|
62
|
+
for (let i = 0; i < 8; i++) {
|
|
63
|
+
bits[7 - i] = Boolean(byte & (1 << i));
|
|
64
|
+
}
|
|
65
|
+
// convert the bit array to values based on the schema
|
|
66
|
+
// @ts-expect-error
|
|
67
|
+
return Object.keys(schema).reduce((res, key) => {
|
|
68
|
+
// @ts-expect-error
|
|
69
|
+
const def = schema[key];
|
|
70
|
+
if (def.length) {
|
|
71
|
+
res[key] = subBitsTotal(bits, def.index, def.length);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
res[key] = bits[def.index];
|
|
75
|
+
}
|
|
76
|
+
return res;
|
|
77
|
+
}, {});
|
|
78
|
+
};
|
|
79
|
+
exports.readBits = readBits;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export interface Options<KeyType, ValueType> {
|
|
2
|
+
/**
|
|
3
|
+
The maximum number of milliseconds an item should remain in the cache.
|
|
4
|
+
|
|
5
|
+
@default Infinity
|
|
6
|
+
|
|
7
|
+
By default, `maxAge` will be `Infinity`, which means that items will never expire.
|
|
8
|
+
Lazy expiration upon the next write or read call.
|
|
9
|
+
|
|
10
|
+
Individual expiration of an item can be specified by the `set(key, value, maxAge)` method.
|
|
11
|
+
*/
|
|
12
|
+
readonly maxAge?: number;
|
|
13
|
+
/**
|
|
14
|
+
The maximum number of items before evicting the least recently used items.
|
|
15
|
+
*/
|
|
16
|
+
readonly maxSize: number;
|
|
17
|
+
/**
|
|
18
|
+
Called right before an item is evicted from the cache.
|
|
19
|
+
|
|
20
|
+
Useful for side effects or for items like object URLs that need explicit cleanup (`revokeObjectURL`).
|
|
21
|
+
*/
|
|
22
|
+
onEviction?: (key: KeyType, value: ValueType) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare class QuickLRU<KeyType, ValueType> implements Iterable<[KeyType, ValueType]> {
|
|
25
|
+
/**
|
|
26
|
+
The maximum number of milliseconds an item should remain in the cache.
|
|
27
|
+
|
|
28
|
+
@default Infinity
|
|
29
|
+
|
|
30
|
+
By default, `maxAge` will be `Infinity`, which means that items will never expire.
|
|
31
|
+
Lazy expiration upon the next write or read call.
|
|
32
|
+
|
|
33
|
+
Individual expiration of an item can be specified by the `set(key, value, maxAge)` method.
|
|
34
|
+
*/
|
|
35
|
+
maxAge: number;
|
|
36
|
+
/**
|
|
37
|
+
The maximum number of items before evicting the least recently used items.
|
|
38
|
+
*/
|
|
39
|
+
maxSize: number;
|
|
40
|
+
/**
|
|
41
|
+
Called right before an item is evicted from the cache.
|
|
42
|
+
|
|
43
|
+
Useful for side effects or for items like object URLs that need explicit cleanup (`revokeObjectURL`).
|
|
44
|
+
*/
|
|
45
|
+
onEviction?: (key: KeyType, value: ValueType) => void;
|
|
46
|
+
private _size;
|
|
47
|
+
private cache;
|
|
48
|
+
private oldCache;
|
|
49
|
+
/**
|
|
50
|
+
Simple ["Least Recently Used" (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29).
|
|
51
|
+
|
|
52
|
+
The instance is an [`Iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) of `[key, value]` pairs so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
|
|
53
|
+
|
|
54
|
+
@example
|
|
55
|
+
```
|
|
56
|
+
import { QuickLRU } from 'quick-lru-ts';
|
|
57
|
+
|
|
58
|
+
const lru = new QuickLRU({maxSize: 1000});
|
|
59
|
+
|
|
60
|
+
lru.set('🦄', '🌈');
|
|
61
|
+
|
|
62
|
+
lru.has('🦄');
|
|
63
|
+
//=> true
|
|
64
|
+
|
|
65
|
+
lru.get('🦄');
|
|
66
|
+
//=> '🌈'
|
|
67
|
+
```
|
|
68
|
+
*/
|
|
69
|
+
constructor(options: Options<KeyType, ValueType>);
|
|
70
|
+
private _emitEvictions;
|
|
71
|
+
private _deleteIfExpired;
|
|
72
|
+
private _getOrDeleteIfExpired;
|
|
73
|
+
private _getItemValue;
|
|
74
|
+
private _peek;
|
|
75
|
+
private _set;
|
|
76
|
+
private _moveToRecent;
|
|
77
|
+
private _entriesAscending;
|
|
78
|
+
/**
|
|
79
|
+
Get an item.
|
|
80
|
+
|
|
81
|
+
@returns The stored item or `undefined`.
|
|
82
|
+
*/
|
|
83
|
+
get(key: KeyType): ValueType | undefined;
|
|
84
|
+
set(key: KeyType, value: ValueType, { maxAge }?: {
|
|
85
|
+
maxAge?: number;
|
|
86
|
+
}): void;
|
|
87
|
+
has(key: KeyType): boolean;
|
|
88
|
+
peek(key: KeyType): ValueType | undefined;
|
|
89
|
+
delete(key: KeyType): boolean;
|
|
90
|
+
clear(): void;
|
|
91
|
+
resize(maxSize: number): void;
|
|
92
|
+
keys(): Generator<KeyType, void, unknown>;
|
|
93
|
+
values(): Generator<ValueType, void, unknown>;
|
|
94
|
+
[Symbol.iterator](): IterableIterator<[KeyType, ValueType]>;
|
|
95
|
+
/**
|
|
96
|
+
Iterable for all entries, starting with the newest (descending in recency).
|
|
97
|
+
*/
|
|
98
|
+
entriesDescending(): IterableIterator<[KeyType, ValueType]>;
|
|
99
|
+
entriesAscending(): Generator<(KeyType | ValueType)[], void, unknown>;
|
|
100
|
+
get size(): number;
|
|
101
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QuickLRU = void 0;
|
|
4
|
+
class QuickLRU {
|
|
5
|
+
/**
|
|
6
|
+
Simple ["Least Recently Used" (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29).
|
|
7
|
+
|
|
8
|
+
The instance is an [`Iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) of `[key, value]` pairs so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
|
|
9
|
+
|
|
10
|
+
@example
|
|
11
|
+
```
|
|
12
|
+
import { QuickLRU } from 'quick-lru-ts';
|
|
13
|
+
|
|
14
|
+
const lru = new QuickLRU({maxSize: 1000});
|
|
15
|
+
|
|
16
|
+
lru.set('🦄', '🌈');
|
|
17
|
+
|
|
18
|
+
lru.has('🦄');
|
|
19
|
+
//=> true
|
|
20
|
+
|
|
21
|
+
lru.get('🦄');
|
|
22
|
+
//=> '🌈'
|
|
23
|
+
```
|
|
24
|
+
*/
|
|
25
|
+
constructor(options) {
|
|
26
|
+
if (!(options.maxSize && options.maxSize > 0)) {
|
|
27
|
+
throw new TypeError('`maxSize` must be a number greater than 0');
|
|
28
|
+
}
|
|
29
|
+
if (typeof options.maxAge === 'number' && options.maxAge === 0) {
|
|
30
|
+
throw new TypeError('`maxAge` must be a number greater than 0');
|
|
31
|
+
}
|
|
32
|
+
this.maxSize = options.maxSize;
|
|
33
|
+
this.maxAge = options.maxAge || Number.POSITIVE_INFINITY;
|
|
34
|
+
this.onEviction = options.onEviction;
|
|
35
|
+
this.cache = new Map();
|
|
36
|
+
this.oldCache = new Map();
|
|
37
|
+
this._size = 0;
|
|
38
|
+
}
|
|
39
|
+
_emitEvictions(cache) {
|
|
40
|
+
if (typeof this.onEviction !== 'function') {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
for (const [key, item] of cache) {
|
|
44
|
+
this.onEviction(key, item.value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
_deleteIfExpired(key, item) {
|
|
48
|
+
if (item === undefined)
|
|
49
|
+
return true;
|
|
50
|
+
if (typeof item.expiry === 'number' && item.expiry <= Date.now()) {
|
|
51
|
+
if (typeof this.onEviction === 'function') {
|
|
52
|
+
this.onEviction(key, item.value);
|
|
53
|
+
}
|
|
54
|
+
return this.delete(key);
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
_getOrDeleteIfExpired(key, item) {
|
|
59
|
+
const deleted = this._deleteIfExpired(key, item);
|
|
60
|
+
if (deleted === false) {
|
|
61
|
+
return item.value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
_getItemValue(key, item) {
|
|
65
|
+
if (item === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value;
|
|
68
|
+
}
|
|
69
|
+
_peek(key, cache) {
|
|
70
|
+
const item = cache.get(key);
|
|
71
|
+
return this._getItemValue(key, item);
|
|
72
|
+
}
|
|
73
|
+
_set(key, value) {
|
|
74
|
+
this.cache.set(key, value);
|
|
75
|
+
this._size++;
|
|
76
|
+
if (this._size >= this.maxSize) {
|
|
77
|
+
this._size = 0;
|
|
78
|
+
this._emitEvictions(this.oldCache);
|
|
79
|
+
this.oldCache = this.cache;
|
|
80
|
+
this.cache = new Map();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
_moveToRecent(key, item) {
|
|
84
|
+
this.oldCache.delete(key);
|
|
85
|
+
this._set(key, item);
|
|
86
|
+
}
|
|
87
|
+
*_entriesAscending() {
|
|
88
|
+
for (const item of this.oldCache) {
|
|
89
|
+
const [key, value] = item;
|
|
90
|
+
if (!this.cache.has(key)) {
|
|
91
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
92
|
+
if (deleted === false) {
|
|
93
|
+
yield item;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const item of this.cache) {
|
|
98
|
+
const [key, value] = item;
|
|
99
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
100
|
+
if (deleted === false) {
|
|
101
|
+
yield item;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
Get an item.
|
|
107
|
+
|
|
108
|
+
@returns The stored item or `undefined`.
|
|
109
|
+
*/
|
|
110
|
+
get(key) {
|
|
111
|
+
if (this.cache.has(key)) {
|
|
112
|
+
const item = this.cache.get(key);
|
|
113
|
+
return this._getItemValue(key, item);
|
|
114
|
+
}
|
|
115
|
+
if (this.oldCache.has(key)) {
|
|
116
|
+
const item = this.oldCache.get(key);
|
|
117
|
+
if (this._deleteIfExpired(key, item) === false) {
|
|
118
|
+
this._moveToRecent(key, item);
|
|
119
|
+
return item.value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
set(key, value, { maxAge = this.maxAge } = {}) {
|
|
124
|
+
const expiry = typeof maxAge === 'number' && maxAge !== Number.POSITIVE_INFINITY
|
|
125
|
+
? Date.now() + maxAge
|
|
126
|
+
: undefined;
|
|
127
|
+
if (this.cache.has(key)) {
|
|
128
|
+
this.cache.set(key, {
|
|
129
|
+
value,
|
|
130
|
+
expiry,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this._set(key, { value, expiry });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
has(key) {
|
|
138
|
+
if (this.cache.has(key)) {
|
|
139
|
+
return !this._deleteIfExpired(key, this.cache.get(key));
|
|
140
|
+
}
|
|
141
|
+
if (this.oldCache.has(key)) {
|
|
142
|
+
return !this._deleteIfExpired(key, this.oldCache.get(key));
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
peek(key) {
|
|
147
|
+
if (this.cache.has(key)) {
|
|
148
|
+
return this._peek(key, this.cache);
|
|
149
|
+
}
|
|
150
|
+
if (this.oldCache.has(key)) {
|
|
151
|
+
return this._peek(key, this.oldCache);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
delete(key) {
|
|
155
|
+
const deleted = this.cache.delete(key);
|
|
156
|
+
if (deleted) {
|
|
157
|
+
this._size--;
|
|
158
|
+
}
|
|
159
|
+
return this.oldCache.delete(key) || deleted;
|
|
160
|
+
}
|
|
161
|
+
clear() {
|
|
162
|
+
this.cache.clear();
|
|
163
|
+
this.oldCache.clear();
|
|
164
|
+
this._size = 0;
|
|
165
|
+
}
|
|
166
|
+
resize(maxSize) {
|
|
167
|
+
if (!(maxSize && maxSize > 0)) {
|
|
168
|
+
throw new TypeError('`maxSize` must be a number greater than 0');
|
|
169
|
+
}
|
|
170
|
+
const items = [...this._entriesAscending()];
|
|
171
|
+
const removeCount = items.length - maxSize;
|
|
172
|
+
if (removeCount < 0) {
|
|
173
|
+
this.cache = new Map(items);
|
|
174
|
+
this.oldCache = new Map();
|
|
175
|
+
this._size = items.length;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
if (removeCount > 0) {
|
|
179
|
+
this._emitEvictions(items.slice(0, removeCount));
|
|
180
|
+
}
|
|
181
|
+
this.oldCache = new Map(items.slice(removeCount));
|
|
182
|
+
this.cache = new Map();
|
|
183
|
+
this._size = 0;
|
|
184
|
+
}
|
|
185
|
+
this.maxSize = maxSize;
|
|
186
|
+
}
|
|
187
|
+
*keys() {
|
|
188
|
+
for (const [key] of this) {
|
|
189
|
+
yield key;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
*values() {
|
|
193
|
+
for (const [, value] of this) {
|
|
194
|
+
yield value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
*[Symbol.iterator]() {
|
|
198
|
+
for (const item of this.cache) {
|
|
199
|
+
const [key, value] = item;
|
|
200
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
201
|
+
if (deleted === false) {
|
|
202
|
+
yield [key, value.value];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const item of this.oldCache) {
|
|
206
|
+
const [key, value] = item;
|
|
207
|
+
if (!this.cache.has(key)) {
|
|
208
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
209
|
+
if (deleted === false) {
|
|
210
|
+
yield [key, value.value];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
Iterable for all entries, starting with the newest (descending in recency).
|
|
217
|
+
*/
|
|
218
|
+
*entriesDescending() {
|
|
219
|
+
let items = [...this.cache];
|
|
220
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
221
|
+
const item = items[i];
|
|
222
|
+
const [key, value] = item;
|
|
223
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
224
|
+
if (deleted === false) {
|
|
225
|
+
yield [key, value.value];
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
items = [...this.oldCache];
|
|
229
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
230
|
+
const item = items[i];
|
|
231
|
+
const [key, value] = item;
|
|
232
|
+
if (!this.cache.has(key)) {
|
|
233
|
+
const deleted = this._deleteIfExpired(key, value);
|
|
234
|
+
if (deleted === false) {
|
|
235
|
+
yield [key, value.value];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
*entriesAscending() {
|
|
241
|
+
for (const [key, value] of this._entriesAscending()) {
|
|
242
|
+
yield [key, value.value];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
get size() {
|
|
246
|
+
if (!this._size) {
|
|
247
|
+
return this.oldCache.size;
|
|
248
|
+
}
|
|
249
|
+
let oldCacheSize = 0;
|
|
250
|
+
for (const key of this.oldCache.keys()) {
|
|
251
|
+
if (!this.cache.has(key)) {
|
|
252
|
+
oldCacheSize++;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return Math.min(this._size + oldCacheSize, this.maxSize);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
exports.QuickLRU = QuickLRU;
|