utilium 2.0.0-pre.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/buffer.d.ts +1 -1
- package/dist/buffer.js +4 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -2
- package/eslint.shared.js +66 -0
- package/package.json +4 -10
- package/readme.md +0 -1
- package/dist/internal/primitives.d.ts +0 -99
- package/dist/internal/primitives.js +0 -98
- package/dist/internal/struct.d.ts +0 -78
- package/dist/internal/struct.js +0 -44
- package/dist/struct.d.ts +0 -42
- package/dist/struct.js +0 -204
- package/src/buffer.ts +0 -419
- package/src/cache.ts +0 -241
- package/src/checksum.ts +0 -22
- package/src/debugging.ts +0 -113
- package/src/dom.ts +0 -43
- package/src/fs.ts +0 -213
- package/src/index.ts +0 -12
- package/src/internal/primitives.ts +0 -135
- package/src/internal/struct.ts +0 -154
- package/src/list.ts +0 -150
- package/src/misc.ts +0 -80
- package/src/numbers.ts +0 -19
- package/src/objects.ts +0 -145
- package/src/random.ts +0 -36
- package/src/requests.ts +0 -225
- package/src/shell.ts +0 -133
- package/src/string.ts +0 -62
- package/src/struct.ts +0 -295
- package/src/types.ts +0 -277
- package/src/version.ts +0 -54
- package/tsconfig.json +0 -21
package/src/cache.ts
DELETED
@@ -1,241 +0,0 @@
|
|
1
|
-
/** A ranged cache */
|
2
|
-
import { extendBuffer } from './buffer.js';
|
3
|
-
|
4
|
-
export interface Options {
|
5
|
-
/**
|
6
|
-
* If true, use multiple buffers to cache a file.
|
7
|
-
* This is useful when working with small parts of large files,
|
8
|
-
* since we don't need to allocate a large buffer that is mostly unused
|
9
|
-
* @default true
|
10
|
-
*/
|
11
|
-
sparse?: boolean;
|
12
|
-
|
13
|
-
/**
|
14
|
-
* The threshold for whether to combine regions or not
|
15
|
-
* @see Region
|
16
|
-
* @default 0xfff // 4 KiB
|
17
|
-
*/
|
18
|
-
regionGapThreshold?: number;
|
19
|
-
|
20
|
-
/**
|
21
|
-
* Whether to only update the cache when changing or deleting resources
|
22
|
-
* @default false
|
23
|
-
*/
|
24
|
-
cacheOnly?: boolean;
|
25
|
-
}
|
26
|
-
|
27
|
-
export type Range = { start: number; end: number };
|
28
|
-
|
29
|
-
export interface Region {
|
30
|
-
/** The region's offset from the start of the resource */
|
31
|
-
offset: number;
|
32
|
-
|
33
|
-
/** Ranges cached in this region. These are absolute! */
|
34
|
-
ranges: Range[];
|
35
|
-
|
36
|
-
/** Data for this region */
|
37
|
-
data: Uint8Array;
|
38
|
-
}
|
39
|
-
|
40
|
-
/**
|
41
|
-
* The cache for a specific resource
|
42
|
-
* @internal
|
43
|
-
*/
|
44
|
-
export class Resource<ID> {
|
45
|
-
/** Regions used to reduce unneeded allocations. Think of sparse arrays. */
|
46
|
-
public readonly regions: Region[] = [];
|
47
|
-
|
48
|
-
/** The full size of the resource */
|
49
|
-
public get size() {
|
50
|
-
return this._size;
|
51
|
-
}
|
52
|
-
|
53
|
-
public set size(value: number) {
|
54
|
-
if (value >= this._size) {
|
55
|
-
this._size = value;
|
56
|
-
return;
|
57
|
-
}
|
58
|
-
|
59
|
-
this._size = value;
|
60
|
-
|
61
|
-
for (let i = this.regions.length - 1; i >= 0; i--) {
|
62
|
-
const region = this.regions[i];
|
63
|
-
|
64
|
-
if (region.offset >= value) {
|
65
|
-
this.regions.splice(i, 1);
|
66
|
-
continue;
|
67
|
-
}
|
68
|
-
|
69
|
-
const maxLength = value - region.offset;
|
70
|
-
if (region.data.byteLength > maxLength) {
|
71
|
-
region.data = region.data.subarray(0, maxLength);
|
72
|
-
}
|
73
|
-
|
74
|
-
region.ranges = region.ranges
|
75
|
-
.filter(range => range.start < value)
|
76
|
-
.map(range => {
|
77
|
-
if (range.end > value) {
|
78
|
-
return { start: range.start, end: value };
|
79
|
-
}
|
80
|
-
return range;
|
81
|
-
});
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
public constructor(
|
86
|
-
/** The resource ID */
|
87
|
-
public readonly id: ID,
|
88
|
-
protected _size: number,
|
89
|
-
protected readonly options: Options,
|
90
|
-
resources?: Map<ID, Resource<ID> | undefined>
|
91
|
-
) {
|
92
|
-
options.sparse ??= true;
|
93
|
-
if (!options.sparse) this.regions.push({ offset: 0, data: new Uint8Array(_size), ranges: [] });
|
94
|
-
|
95
|
-
resources?.set(id, this);
|
96
|
-
}
|
97
|
-
|
98
|
-
/** Combines adjacent regions and combines adjacent ranges within a region */
|
99
|
-
public collect(): void {
|
100
|
-
if (!this.options.sparse) return;
|
101
|
-
const { regionGapThreshold = 0xfff } = this.options;
|
102
|
-
|
103
|
-
for (let i = 0; i < this.regions.length - 1; ) {
|
104
|
-
const current = this.regions[i];
|
105
|
-
const next = this.regions[i + 1];
|
106
|
-
|
107
|
-
if (next.offset - (current.offset + current.data.byteLength) > regionGapThreshold) {
|
108
|
-
i++;
|
109
|
-
continue;
|
110
|
-
}
|
111
|
-
|
112
|
-
// Combine ranges
|
113
|
-
current.ranges.push(...next.ranges);
|
114
|
-
current.ranges.sort((a, b) => a.start - b.start);
|
115
|
-
|
116
|
-
// Combine overlapping/adjacent ranges
|
117
|
-
current.ranges = current.ranges.reduce((acc: Range[], range) => {
|
118
|
-
if (!acc.length || acc.at(-1)!.end < range.start) {
|
119
|
-
acc.push(range);
|
120
|
-
} else {
|
121
|
-
acc.at(-1)!.end = Math.max(acc.at(-1)!.end, range.end);
|
122
|
-
}
|
123
|
-
return acc;
|
124
|
-
}, []);
|
125
|
-
|
126
|
-
// Extend buffer to include the new region
|
127
|
-
current.data = extendBuffer(current.data, next.offset + next.data.byteLength);
|
128
|
-
current.data.set(next.data, next.offset - current.offset);
|
129
|
-
|
130
|
-
// Remove the next region after merging
|
131
|
-
this.regions.splice(i + 1, 1);
|
132
|
-
}
|
133
|
-
}
|
134
|
-
|
135
|
-
/** Takes an initial range and finds the sub-ranges that are not in the cache */
|
136
|
-
public missing(start: number, end: number): Range[] {
|
137
|
-
const missingRanges: Range[] = [];
|
138
|
-
|
139
|
-
for (const region of this.regions) {
|
140
|
-
if (region.offset >= end) break;
|
141
|
-
|
142
|
-
for (const range of region.ranges) {
|
143
|
-
if (range.end <= start) continue;
|
144
|
-
if (range.start >= end) break;
|
145
|
-
|
146
|
-
if (range.start > start) {
|
147
|
-
missingRanges.push({ start, end: Math.min(range.start, end) });
|
148
|
-
}
|
149
|
-
|
150
|
-
// Adjust the current start if the region overlaps
|
151
|
-
if (range.end > start) start = Math.max(start, range.end);
|
152
|
-
|
153
|
-
if (start >= end) break;
|
154
|
-
}
|
155
|
-
|
156
|
-
if (start >= end) break;
|
157
|
-
}
|
158
|
-
|
159
|
-
// If there are still missing parts at the end
|
160
|
-
if (start < end) missingRanges.push({ start, end });
|
161
|
-
|
162
|
-
return missingRanges;
|
163
|
-
}
|
164
|
-
|
165
|
-
/**
|
166
|
-
* Get the cached sub-ranges of an initial range.
|
167
|
-
* This is conceptually the inverse of `missing`.
|
168
|
-
*/
|
169
|
-
public cached(start: number, end: number): Range[] {
|
170
|
-
const cachedRanges: Range[] = [];
|
171
|
-
|
172
|
-
for (const region of this.regions) {
|
173
|
-
if (region.offset >= end) break;
|
174
|
-
|
175
|
-
for (const range of region.ranges) {
|
176
|
-
if (range.end <= start) continue;
|
177
|
-
if (range.start >= end) break;
|
178
|
-
|
179
|
-
cachedRanges.push({
|
180
|
-
start: Math.max(start, range.start),
|
181
|
-
end: Math.min(end, range.end),
|
182
|
-
});
|
183
|
-
}
|
184
|
-
}
|
185
|
-
|
186
|
-
cachedRanges.sort((a, b) => a.start - b.start);
|
187
|
-
const merged: Range[] = [];
|
188
|
-
for (const curr of cachedRanges) {
|
189
|
-
const last = merged.at(-1);
|
190
|
-
if (last && curr.start <= last.end) {
|
191
|
-
last.end = Math.max(last.end, curr.end);
|
192
|
-
} else {
|
193
|
-
merged.push(curr);
|
194
|
-
}
|
195
|
-
}
|
196
|
-
|
197
|
-
return merged;
|
198
|
-
}
|
199
|
-
|
200
|
-
/** Get the region who's ranges include an offset */
|
201
|
-
public regionAt(offset: number): Region | undefined {
|
202
|
-
if (!this.regions.length) return;
|
203
|
-
|
204
|
-
for (const region of this.regions) {
|
205
|
-
if (region.offset > offset) break;
|
206
|
-
|
207
|
-
// Check if the offset is within this region
|
208
|
-
if (offset >= region.offset && offset < region.offset + region.data.byteLength) return region;
|
209
|
-
}
|
210
|
-
}
|
211
|
-
|
212
|
-
/** Add new data to the cache at given specified offset */
|
213
|
-
public add(data: Uint8Array, offset: number): this {
|
214
|
-
const end = offset + data.byteLength;
|
215
|
-
const region = this.regionAt(offset);
|
216
|
-
|
217
|
-
if (region) {
|
218
|
-
region.data = extendBuffer(region.data, end);
|
219
|
-
region.data.set(data, offset);
|
220
|
-
region.ranges.push({ start: offset, end });
|
221
|
-
region.ranges.sort((a, b) => a.start - b.start);
|
222
|
-
|
223
|
-
this.collect();
|
224
|
-
return this;
|
225
|
-
}
|
226
|
-
|
227
|
-
// Find the correct index to insert the new region
|
228
|
-
const newRegion: Region = { data, offset: offset, ranges: [{ start: offset, end }] };
|
229
|
-
const insertIndex = this.regions.findIndex(region => region.offset > offset);
|
230
|
-
|
231
|
-
// Insert at the right index to keep regions sorted
|
232
|
-
if (insertIndex == -1) {
|
233
|
-
this.regions.push(newRegion); // Append if no later region exists
|
234
|
-
} else {
|
235
|
-
this.regions.splice(insertIndex, 0, newRegion); // Insert before the first region with a greater offset
|
236
|
-
}
|
237
|
-
|
238
|
-
this.collect();
|
239
|
-
return this;
|
240
|
-
}
|
241
|
-
}
|
package/src/checksum.ts
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
/** Utilities for computing checksums */
|
2
|
-
|
3
|
-
// Precompute CRC32C table
|
4
|
-
const crc32cTable = new Uint32Array(256);
|
5
|
-
for (let i = 0; i < 256; i++) {
|
6
|
-
let value = i;
|
7
|
-
for (let j = 0; j < 8; j++) {
|
8
|
-
value = value & 1 ? 0x82f63b78 ^ (value >>> 1) : value >>> 1;
|
9
|
-
}
|
10
|
-
crc32cTable[i] = value;
|
11
|
-
}
|
12
|
-
|
13
|
-
/**
|
14
|
-
* Computes the CRC32C checksum of a Uint8Array.
|
15
|
-
*/
|
16
|
-
export function crc32c(data: Uint8Array): number {
|
17
|
-
let crc = 0xffffffff;
|
18
|
-
for (let i = 0; i < data.length; i++) {
|
19
|
-
crc = (crc >>> 8) ^ crc32cTable[(crc ^ data[i]) & 0xff];
|
20
|
-
}
|
21
|
-
return (crc ^ 0xffffffff) >>> 0;
|
22
|
-
}
|
package/src/debugging.ts
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-base-to-string */
|
2
|
-
export interface CreateLoggerOptions {
|
3
|
-
/**
|
4
|
-
* The function used to output
|
5
|
-
* @default console.log
|
6
|
-
*/
|
7
|
-
output?: (...args: any[]) => void;
|
8
|
-
stringify?: (value: unknown) => string;
|
9
|
-
/**
|
10
|
-
* Whether to output the class name when logging methods
|
11
|
-
* @default true
|
12
|
-
*/
|
13
|
-
className?: boolean;
|
14
|
-
/**
|
15
|
-
* The separator used to separate the class name and method.
|
16
|
-
* Ignored if `className` is `false`
|
17
|
-
* @default '#'
|
18
|
-
*/
|
19
|
-
separator?: string;
|
20
|
-
/**
|
21
|
-
* Whether to log the return value
|
22
|
-
* @default false
|
23
|
-
*/
|
24
|
-
returnValue?: boolean;
|
25
|
-
}
|
26
|
-
|
27
|
-
function defaultStringify(value: unknown): string {
|
28
|
-
switch (typeof value) {
|
29
|
-
case 'undefined':
|
30
|
-
return 'undefined';
|
31
|
-
case 'string':
|
32
|
-
case 'number':
|
33
|
-
case 'boolean':
|
34
|
-
return JSON.stringify(value);
|
35
|
-
case 'bigint':
|
36
|
-
case 'symbol':
|
37
|
-
return value.toString();
|
38
|
-
case 'function':
|
39
|
-
return value.name + '()';
|
40
|
-
case 'object':
|
41
|
-
if (value === null) return 'null';
|
42
|
-
if (ArrayBuffer.isView(value)) {
|
43
|
-
const length =
|
44
|
-
'length' in value
|
45
|
-
? (value.length as number)
|
46
|
-
: value.byteLength / (value.constructor as any).BYTES_PER_ELEMENT;
|
47
|
-
return `${value.constructor.name.replaceAll('Array', '').toLowerCase()}[${length}]`;
|
48
|
-
}
|
49
|
-
if (Array.isArray(value)) return `unknown[${value.length}]`;
|
50
|
-
try {
|
51
|
-
const json = JSON.stringify(value);
|
52
|
-
|
53
|
-
return json.length < 100 ? json : value.toString();
|
54
|
-
} catch {
|
55
|
-
return value.toString();
|
56
|
-
}
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
type LoggableDecoratorContext = Exclude<DecoratorContext, ClassFieldDecoratorContext>;
|
61
|
-
|
62
|
-
/**
|
63
|
-
* Create a function that can be used to decorate classes and non-field members.
|
64
|
-
*/
|
65
|
-
export function createLogDecorator(options: CreateLoggerOptions) {
|
66
|
-
const {
|
67
|
-
output = console.log,
|
68
|
-
separator = '#',
|
69
|
-
returnValue = false,
|
70
|
-
stringify = defaultStringify,
|
71
|
-
className = true,
|
72
|
-
} = options;
|
73
|
-
|
74
|
-
return function log<T extends (...args: any[]) => any>(value: T, context: LoggableDecoratorContext): T {
|
75
|
-
if (context.kind == 'class') {
|
76
|
-
return function (...args: any[]) {
|
77
|
-
output(`new ${value.name} (${args.map(stringify).join(', ')})`);
|
78
|
-
return Reflect.construct(value, args);
|
79
|
-
} as T;
|
80
|
-
}
|
81
|
-
|
82
|
-
return function (this: any, ...args: any[]) {
|
83
|
-
const prefix = (className ? this.constructor.name + separator : '') + context.name.toString();
|
84
|
-
|
85
|
-
output(`${prefix}(${args.map(stringify).join(', ')})`);
|
86
|
-
|
87
|
-
const result = value.call(this, ...args);
|
88
|
-
|
89
|
-
if (returnValue) output(' => ' + stringify(result));
|
90
|
-
|
91
|
-
return result;
|
92
|
-
} as T;
|
93
|
-
};
|
94
|
-
}
|
95
|
-
|
96
|
-
/**
|
97
|
-
* @internal @hidden
|
98
|
-
*/
|
99
|
-
export let U_DEBUG = 'process' in globalThis && 'env' in globalThis.process && globalThis.process.env.U_DEBUG == 'true';
|
100
|
-
|
101
|
-
/**
|
102
|
-
* @internal @hidden
|
103
|
-
*/
|
104
|
-
export function _setDebug(value: boolean) {
|
105
|
-
U_DEBUG = value;
|
106
|
-
}
|
107
|
-
|
108
|
-
/**
|
109
|
-
* @internal @hidden
|
110
|
-
*/
|
111
|
-
export function _debugLog(...text: any[]) {
|
112
|
-
if (U_DEBUG) console.debug('[U]', ...text);
|
113
|
-
}
|
package/src/dom.ts
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
2
|
-
|
3
|
-
/**
|
4
|
-
* Upload a file
|
5
|
-
* @todo use Promise.withResolvers
|
6
|
-
*/
|
7
|
-
export function upload(type?: string, multiple = false): Promise<File> {
|
8
|
-
return new Promise<File>((resolve, reject) => {
|
9
|
-
const input = document.createElement('input');
|
10
|
-
input.type = 'file';
|
11
|
-
if (type) input.accept = type;
|
12
|
-
|
13
|
-
if (multiple) input.multiple = true;
|
14
|
-
|
15
|
-
input.addEventListener('change', e => {
|
16
|
-
const file = input.files?.[0];
|
17
|
-
file ? resolve(file) : reject(new ReferenceError('No files uploaded'));
|
18
|
-
});
|
19
|
-
|
20
|
-
input.click();
|
21
|
-
});
|
22
|
-
}
|
23
|
-
|
24
|
-
/**
|
25
|
-
* Downloads some data
|
26
|
-
*/
|
27
|
-
export function download(data: BlobPart, name: string): void {
|
28
|
-
const link = document.createElement('a');
|
29
|
-
link.href = URL.createObjectURL(new Blob([data]));
|
30
|
-
link.download = name;
|
31
|
-
link.click();
|
32
|
-
}
|
33
|
-
|
34
|
-
/**
|
35
|
-
* Create an instance of a `<template>`
|
36
|
-
*/
|
37
|
-
export function cloneTemplate(selector: string): DocumentFragment {
|
38
|
-
const template = document.querySelector<HTMLTemplateElement>(selector);
|
39
|
-
if (!template) {
|
40
|
-
throw new ReferenceError('Template does not exist: ' + selector);
|
41
|
-
}
|
42
|
-
return template.content.cloneNode(true) as DocumentFragment;
|
43
|
-
}
|
package/src/fs.ts
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
import { isJSON, type JSONValue } from './objects.js';
|
2
|
-
import * as fs from 'fs';
|
3
|
-
|
4
|
-
export abstract class FileMap<V> implements Map<string, V> {
|
5
|
-
public get [Symbol.toStringTag](): string {
|
6
|
-
return 'FileMap';
|
7
|
-
}
|
8
|
-
|
9
|
-
public constructor(protected readonly path: string) {
|
10
|
-
if (!path) {
|
11
|
-
throw new ReferenceError('No path specified');
|
12
|
-
}
|
13
|
-
}
|
14
|
-
|
15
|
-
protected abstract readonly _map: Map<string, V>;
|
16
|
-
|
17
|
-
public abstract clear(): void;
|
18
|
-
|
19
|
-
public abstract delete(key: string): boolean;
|
20
|
-
|
21
|
-
public abstract get(key: string): V;
|
22
|
-
|
23
|
-
public abstract has(key: string): boolean;
|
24
|
-
|
25
|
-
public abstract set(key: string, value: V): this;
|
26
|
-
|
27
|
-
public get size() {
|
28
|
-
return this._map.size;
|
29
|
-
}
|
30
|
-
|
31
|
-
public get [Symbol.iterator]() {
|
32
|
-
return this._map[Symbol.iterator].bind(this._map);
|
33
|
-
}
|
34
|
-
|
35
|
-
public get keys(): typeof this._map.keys {
|
36
|
-
return this._map.keys.bind(this._map);
|
37
|
-
}
|
38
|
-
|
39
|
-
public get values(): typeof this._map.values {
|
40
|
-
return this._map.values.bind(this._map);
|
41
|
-
}
|
42
|
-
|
43
|
-
public get entries(): typeof this._map.entries {
|
44
|
-
return this._map.entries.bind(this._map);
|
45
|
-
}
|
46
|
-
|
47
|
-
public get forEach(): typeof this._map.forEach {
|
48
|
-
return this._map.forEach.bind(this._map);
|
49
|
-
}
|
50
|
-
}
|
51
|
-
|
52
|
-
export interface JSONFileMapOptions {
|
53
|
-
/**
|
54
|
-
* Should an invalid JSON file be overwritten
|
55
|
-
*/
|
56
|
-
overwrite_invalid: boolean;
|
57
|
-
}
|
58
|
-
|
59
|
-
/**
|
60
|
-
* A Map overlaying a JSON file
|
61
|
-
*/
|
62
|
-
export class JSONFileMap<T extends JSONValue = JSONValue> extends FileMap<T> {
|
63
|
-
public get [Symbol.toStringTag](): 'JSONFileMap' {
|
64
|
-
return 'JSONFileMap';
|
65
|
-
}
|
66
|
-
|
67
|
-
public constructor(
|
68
|
-
path: string,
|
69
|
-
public readonly options: JSONFileMapOptions
|
70
|
-
) {
|
71
|
-
super(path);
|
72
|
-
if (!fs.existsSync(path)) {
|
73
|
-
fs.writeFileSync(path, '{}');
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
public get _map(): Map<string, T> {
|
78
|
-
const content = fs.readFileSync(this.path, 'utf8');
|
79
|
-
if (!isJSON(content)) {
|
80
|
-
if (!this.options.overwrite_invalid) {
|
81
|
-
throw new SyntaxError('Invalid JSON file: ' + this.path);
|
82
|
-
}
|
83
|
-
console.warn('Invalid JSON file (overwriting): ' + this.path);
|
84
|
-
this.clear();
|
85
|
-
return new Map();
|
86
|
-
}
|
87
|
-
return new Map(Object.entries(JSON.parse(content)));
|
88
|
-
}
|
89
|
-
|
90
|
-
public _write(map: Map<string, T>) {
|
91
|
-
if (!fs.existsSync(this.path)) {
|
92
|
-
fs.writeFileSync(this.path, '{}');
|
93
|
-
}
|
94
|
-
const content = JSON.stringify(Object.fromEntries(map));
|
95
|
-
fs.writeFileSync(this.path, content);
|
96
|
-
}
|
97
|
-
|
98
|
-
public clear() {
|
99
|
-
fs.writeFileSync(this.path, '{}');
|
100
|
-
}
|
101
|
-
|
102
|
-
public delete(key: string): boolean {
|
103
|
-
const map = this._map;
|
104
|
-
const rt = map.delete(key);
|
105
|
-
this._write(map);
|
106
|
-
return rt;
|
107
|
-
}
|
108
|
-
|
109
|
-
public get<U extends T>(key: string): U {
|
110
|
-
return this._map.get(key) as U;
|
111
|
-
}
|
112
|
-
|
113
|
-
public has(key: string): boolean {
|
114
|
-
return this._map.has(key);
|
115
|
-
}
|
116
|
-
|
117
|
-
public set(key: string, value: T): this {
|
118
|
-
const map = this._map;
|
119
|
-
map.set(key, value);
|
120
|
-
this._write(map);
|
121
|
-
return this;
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
export interface FolderMapOptions {
|
126
|
-
/**
|
127
|
-
* Suffix to append to keys to resolve file names
|
128
|
-
*/
|
129
|
-
suffix: string;
|
130
|
-
}
|
131
|
-
|
132
|
-
/**
|
133
|
-
* A Map overlaying a folder
|
134
|
-
*/
|
135
|
-
export class FolderMap extends FileMap<string> {
|
136
|
-
public get [Symbol.toStringTag](): 'FolderMap' {
|
137
|
-
return 'FolderMap';
|
138
|
-
}
|
139
|
-
|
140
|
-
public constructor(
|
141
|
-
path: string,
|
142
|
-
public readonly options: Partial<FolderMapOptions>
|
143
|
-
) {
|
144
|
-
super(path);
|
145
|
-
}
|
146
|
-
|
147
|
-
protected get _names(): string[] {
|
148
|
-
return fs
|
149
|
-
.readdirSync(this.path)
|
150
|
-
.filter(p => p.endsWith(this.options.suffix || ''))
|
151
|
-
.map(p => p.slice(0, -this.options.suffix!.length));
|
152
|
-
}
|
153
|
-
|
154
|
-
protected _join(path: string): string {
|
155
|
-
return `${this.path}/${path}${this.options.suffix}`;
|
156
|
-
}
|
157
|
-
|
158
|
-
protected get _map(): Map<string, string> {
|
159
|
-
const entries: [string, string][] = [];
|
160
|
-
for (const name of this._names) {
|
161
|
-
const content = fs.readFileSync(this._join(name), 'utf8');
|
162
|
-
entries.push([name, content]);
|
163
|
-
}
|
164
|
-
return new Map(entries);
|
165
|
-
}
|
166
|
-
|
167
|
-
public clear(): void {
|
168
|
-
for (const name of this._names) {
|
169
|
-
fs.unlinkSync(this._join(name));
|
170
|
-
}
|
171
|
-
}
|
172
|
-
|
173
|
-
public delete(key: string): boolean {
|
174
|
-
if (!this.has(key)) {
|
175
|
-
return false;
|
176
|
-
}
|
177
|
-
|
178
|
-
fs.unlinkSync(this._join(key));
|
179
|
-
return true;
|
180
|
-
}
|
181
|
-
|
182
|
-
public get(key: string): string {
|
183
|
-
if (!this.has(key)) {
|
184
|
-
throw new ReferenceError('Key not found');
|
185
|
-
}
|
186
|
-
return fs.readFileSync(this._join(key), 'utf8');
|
187
|
-
}
|
188
|
-
|
189
|
-
public has(key: string): boolean {
|
190
|
-
return this._names.includes(key);
|
191
|
-
}
|
192
|
-
|
193
|
-
public set(key: string, value: string): this {
|
194
|
-
fs.writeFileSync(this._join(key), value);
|
195
|
-
return this;
|
196
|
-
}
|
197
|
-
}
|
198
|
-
|
199
|
-
export function gitCommitHash(repo: string = '.'): string {
|
200
|
-
repo = repo.replaceAll(/\/+/g, '/').replaceAll(/\/$/g, '');
|
201
|
-
const rev = fs
|
202
|
-
.readFileSync(repo + '/.git/HEAD')
|
203
|
-
.toString()
|
204
|
-
.trim();
|
205
|
-
if (rev.indexOf(':') === -1) {
|
206
|
-
return rev;
|
207
|
-
} else {
|
208
|
-
return fs
|
209
|
-
.readFileSync(repo + '/.git/' + rev.substring(5))
|
210
|
-
.toString()
|
211
|
-
.trim();
|
212
|
-
}
|
213
|
-
}
|
package/src/index.ts
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
// This file should not be added to
|
2
|
-
// For better tree shaking, import from whichever file is actually needed
|
3
|
-
|
4
|
-
export * from './list.js';
|
5
|
-
export * from './misc.js';
|
6
|
-
export * from './numbers.js';
|
7
|
-
export * from './objects.js';
|
8
|
-
export * from './random.js';
|
9
|
-
export * from './string.js';
|
10
|
-
export * from './struct.js';
|
11
|
-
export * from './types.js';
|
12
|
-
export * as version from './version.js';
|