@pistonite/pure 0.26.8 → 0.27.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/package.json +2 -2
- package/src/fs/FsFileImpl.ts +3 -9
- package/src/fs/FsFileStandaloneImplHandleAPI.ts +2 -8
- package/src/fs/FsImplEntryAPI.ts +12 -48
- package/src/fs/FsImplFileAPI.ts +3 -12
- package/src/fs/FsImplHandleAPI.ts +12 -47
- package/src/fs/FsOpen.ts +27 -71
- package/src/fs/FsOpenFile.ts +2 -7
- package/src/fs/FsSave.ts +3 -10
- package/src/fs/FsSupportStatus.ts +1 -5
- package/src/fs/index.ts +2 -11
- package/src/log/index.ts +1 -5
- package/src/log/logger.ts +2 -6
- package/src/memory/async_erc.ts +17 -10
- package/src/memory/cell.ts +2 -8
- package/src/memory/emp.ts +88 -0
- package/src/memory/erc.test.ts +123 -126
- package/src/memory/erc.ts +12 -8
- package/src/memory/index.ts +2 -1
- package/src/memory/persist.ts +1 -4
- package/src/pref/device.ts +118 -0
- package/src/pref/index.ts +1 -0
- package/src/pref/locale.ts +6 -18
- package/src/result/index.ts +1 -3
- package/src/sync/RwLock.ts +2 -0
- package/src/sync/batch.test.ts +4 -6
- package/src/sync/batch.ts +4 -21
- package/src/sync/capture.ts +33 -0
- package/src/sync/debounce.ts +1 -6
- package/src/sync/index.ts +1 -0
- package/src/sync/latest.ts +2 -12
- package/src/sync/mutex.ts +21 -0
- package/src/sync/serial.test.ts +1 -2
- package/src/sync/serial.ts +3 -12
- package/src/sync/util.ts +1 -3
package/src/pref/locale.ts
CHANGED
|
@@ -5,9 +5,7 @@ import { serial } from "../sync/serial.ts";
|
|
|
5
5
|
let supportedLocales: readonly string[] = [];
|
|
6
6
|
let defaultLocale: string = "";
|
|
7
7
|
let settingLocale: string = ""; // if locale is being set (setLocale called)
|
|
8
|
-
let onBeforeChangeHook: (
|
|
9
|
-
newLocale: string,
|
|
10
|
-
) => Promise<Result<void, "cancel">> = () => {
|
|
8
|
+
let onBeforeChangeHook: (newLocale: string) => Promise<Result<void, "cancel">> = () => {
|
|
11
9
|
return Promise.resolve({} as Result<void, "cancel">);
|
|
12
10
|
};
|
|
13
11
|
const locale = persist<string>({
|
|
@@ -81,10 +79,7 @@ export type LocaleOptions<TLocale extends string> = {
|
|
|
81
79
|
*
|
|
82
80
|
* Note that this hook will not be called during initialization.
|
|
83
81
|
*/
|
|
84
|
-
onBeforeChange?: (
|
|
85
|
-
newLocale: string,
|
|
86
|
-
checkCancel: () => void,
|
|
87
|
-
) => void | Promise<void>;
|
|
82
|
+
onBeforeChange?: (newLocale: string, checkCancel: () => void) => void | Promise<void>;
|
|
88
83
|
};
|
|
89
84
|
|
|
90
85
|
/**
|
|
@@ -118,9 +113,7 @@ export type LocaleOptions<TLocale extends string> = {
|
|
|
118
113
|
* Changing the locale from React components is the same as from outside React,
|
|
119
114
|
* with `setLocale` or `i18next.changeLanguage`, depending on your setup.
|
|
120
115
|
*/
|
|
121
|
-
export const initLocale = <TLocale extends string>(
|
|
122
|
-
options: LocaleOptions<TLocale>,
|
|
123
|
-
): void => {
|
|
116
|
+
export const initLocale = <TLocale extends string>(options: LocaleOptions<TLocale>): void => {
|
|
124
117
|
if (options.onBeforeChange) {
|
|
125
118
|
const onBeforeChange = options.onBeforeChange;
|
|
126
119
|
onBeforeChangeHook = serial({
|
|
@@ -135,8 +128,7 @@ export const initLocale = <TLocale extends string>(
|
|
|
135
128
|
if (options.initial) {
|
|
136
129
|
_locale = options.initial;
|
|
137
130
|
} else {
|
|
138
|
-
_locale =
|
|
139
|
-
convertToSupportedLocale(getPreferredLocale()) || options.default;
|
|
131
|
+
_locale = convertToSupportedLocale(getPreferredLocale()) || options.default;
|
|
140
132
|
}
|
|
141
133
|
defaultLocale = options.default;
|
|
142
134
|
if (options.persist) {
|
|
@@ -221,9 +213,7 @@ export const setLocale = (newLocale: string): boolean => {
|
|
|
221
213
|
* console.log(convertToSupportedLocale("es")); // undefined
|
|
222
214
|
* ```
|
|
223
215
|
*/
|
|
224
|
-
export const convertToSupportedLocale = (
|
|
225
|
-
newLocale: string,
|
|
226
|
-
): string | undefined => {
|
|
216
|
+
export const convertToSupportedLocale = (newLocale: string): string | undefined => {
|
|
227
217
|
return convertToSupportedLocaleIn(newLocale, supportedLocales);
|
|
228
218
|
};
|
|
229
219
|
|
|
@@ -257,9 +247,7 @@ export const convertToSupportedLocaleIn = (
|
|
|
257
247
|
* This is a thin wrapper for `convertToSupportedLocale`.
|
|
258
248
|
* See that function for more details.
|
|
259
249
|
*/
|
|
260
|
-
export const convertToSupportedLocaleOrDefault = (
|
|
261
|
-
newLocale: string,
|
|
262
|
-
): string => {
|
|
250
|
+
export const convertToSupportedLocaleOrDefault = (newLocale: string): string => {
|
|
263
251
|
return convertToSupportedLocale(newLocale) || defaultLocale;
|
|
264
252
|
};
|
|
265
253
|
|
package/src/result/index.ts
CHANGED
|
@@ -186,9 +186,7 @@ export function tryCatch<T, E = unknown>(fn: () => T): Result<T, E> {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
/** Wrap an async function with try-catch and return a Promise<Result>. */
|
|
189
|
-
export async function tryAsync<T, E = unknown>(
|
|
190
|
-
fn: () => Promise<T>,
|
|
191
|
-
): Promise<Result<T, E>> {
|
|
189
|
+
export async function tryAsync<T, E = unknown>(fn: () => Promise<T>): Promise<Result<T, E>> {
|
|
192
190
|
try {
|
|
193
191
|
return { val: await fn() };
|
|
194
192
|
} catch (e) {
|
package/src/sync/RwLock.ts
CHANGED
|
@@ -6,6 +6,8 @@ import Deque from "denque";
|
|
|
6
6
|
* Only guaranteed if no one else has reference to the inner object
|
|
7
7
|
*
|
|
8
8
|
* It can take a second type parameter to specify interface with write methods
|
|
9
|
+
*
|
|
10
|
+
* @deprecated unstable API
|
|
9
11
|
*/
|
|
10
12
|
export class RwLock<TRead, TWrite extends TRead = TRead> {
|
|
11
13
|
/**
|
package/src/sync/batch.test.ts
CHANGED
|
@@ -81,12 +81,10 @@ describe("batch", () => {
|
|
|
81
81
|
});
|
|
82
82
|
test("unbatch", async () => {
|
|
83
83
|
const fn = vi.fn();
|
|
84
|
-
const unbatch = vi.fn(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
);
|
|
84
|
+
const unbatch = vi.fn((inputs: [number][], output: number): number[] => {
|
|
85
|
+
// not actual meaningful unbatching
|
|
86
|
+
return [output / inputs.length, output / inputs.length];
|
|
87
|
+
});
|
|
90
88
|
const execute = batch({
|
|
91
89
|
fn: (x: number) => {
|
|
92
90
|
fn(x);
|
package/src/sync/batch.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AnyFn,
|
|
3
|
-
makePromise,
|
|
4
|
-
type PromiseHandle,
|
|
5
|
-
type AwaitRet,
|
|
6
|
-
} from "./util.ts";
|
|
1
|
+
import { type AnyFn, makePromise, type PromiseHandle, type AwaitRet } from "./util.ts";
|
|
7
2
|
|
|
8
3
|
/**
|
|
9
4
|
* An async event wrapper that allows multiple calls in an interval
|
|
@@ -99,13 +94,7 @@ export function batch<TFn extends AnyFn>({
|
|
|
99
94
|
interval,
|
|
100
95
|
disregardExecutionTime,
|
|
101
96
|
}: BatchConstructor<TFn>) {
|
|
102
|
-
const impl = new BatchImpl(
|
|
103
|
-
fn,
|
|
104
|
-
batch,
|
|
105
|
-
unbatch,
|
|
106
|
-
interval,
|
|
107
|
-
!!disregardExecutionTime,
|
|
108
|
-
);
|
|
97
|
+
const impl = new BatchImpl(fn, batch, unbatch, interval, !!disregardExecutionTime);
|
|
109
98
|
return (...args: Parameters<TFn>) => impl.invoke(...args);
|
|
110
99
|
}
|
|
111
100
|
|
|
@@ -124,10 +113,7 @@ export type BatchConstructor<TFn extends AnyFn> = {
|
|
|
124
113
|
*
|
|
125
114
|
* By default, each input will receive the same output from the batched call
|
|
126
115
|
*/
|
|
127
|
-
unbatch?: (
|
|
128
|
-
inputs: Parameters<TFn>[],
|
|
129
|
-
output: AwaitRet<TFn>,
|
|
130
|
-
) => AwaitRet<TFn>[];
|
|
116
|
+
unbatch?: (inputs: Parameters<TFn>[], output: AwaitRet<TFn>) => AwaitRet<TFn>[];
|
|
131
117
|
|
|
132
118
|
/**
|
|
133
119
|
* Interval between each batched call
|
|
@@ -148,10 +134,7 @@ class BatchImpl<TFn extends AnyFn> {
|
|
|
148
134
|
private fn: TFn,
|
|
149
135
|
private batch: (inputs: Parameters<TFn>[]) => Parameters<TFn>,
|
|
150
136
|
private unbatch:
|
|
151
|
-
| ((
|
|
152
|
-
input: Parameters<TFn>[],
|
|
153
|
-
output: AwaitRet<TFn>,
|
|
154
|
-
) => AwaitRet<TFn>[])
|
|
137
|
+
| ((input: Parameters<TFn>[], output: AwaitRet<TFn>) => AwaitRet<TFn>[])
|
|
155
138
|
| undefined,
|
|
156
139
|
private interval: number,
|
|
157
140
|
private disregardExecutionTime: boolean,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const captured = new Set<unknown>();
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Execute an async closure `fn`, and guarantee that `obj` will not be
|
|
5
|
+
* garbage-collected, until the promise is resolved.
|
|
6
|
+
*/
|
|
7
|
+
export const scopedCapture = async <T>(fn: () => Promise<T>, obj: unknown): Promise<T> => {
|
|
8
|
+
// captures the object
|
|
9
|
+
// technically, this is not needed, as the delete() call above
|
|
10
|
+
// should make sure the captured object is not GC'ed.
|
|
11
|
+
// However, making it reachable from a global object will definitely
|
|
12
|
+
// prevent GC even with crazy optimization from any runtime
|
|
13
|
+
captured.add(obj);
|
|
14
|
+
try {
|
|
15
|
+
return await fn();
|
|
16
|
+
} finally {
|
|
17
|
+
captured.delete(obj);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Execute a closure `fn`, and guarantee that `obj` will not be
|
|
23
|
+
* garbage-collected during the execution
|
|
24
|
+
*/
|
|
25
|
+
export const scopedCaptureSync = <T>(fn: () => T, obj: unknown): T => {
|
|
26
|
+
// captures the object
|
|
27
|
+
captured.add(obj);
|
|
28
|
+
try {
|
|
29
|
+
return fn();
|
|
30
|
+
} finally {
|
|
31
|
+
captured.delete(obj);
|
|
32
|
+
}
|
|
33
|
+
};
|
package/src/sync/debounce.ts
CHANGED
package/src/sync/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { debounce, type DebounceConstructor } from "./debounce.ts";
|
|
|
15
15
|
export { batch, type BatchConstructor } from "./batch.ts";
|
|
16
16
|
export { once, type OnceConstructor } from "./once.ts";
|
|
17
17
|
export { makePromise, type PromiseHandle } from "./util.ts";
|
|
18
|
+
export { scopedCapture, scopedCaptureSync } from "./capture.ts";
|
|
18
19
|
|
|
19
20
|
// helper types
|
|
20
21
|
export type { AnyFn, AwaitRet } from "./util.ts";
|
package/src/sync/latest.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AnyFn,
|
|
3
|
-
type AwaitRet,
|
|
4
|
-
makePromise,
|
|
5
|
-
type PromiseHandle,
|
|
6
|
-
} from "./util.ts";
|
|
1
|
+
import { type AnyFn, type AwaitRet, makePromise, type PromiseHandle } from "./util.ts";
|
|
7
2
|
|
|
8
3
|
/**
|
|
9
4
|
* An async event wrapper that always resolve to the result of the latest
|
|
@@ -112,12 +107,7 @@ export class LatestImpl<TFn extends AnyFn> {
|
|
|
112
107
|
if (this.pending) {
|
|
113
108
|
// pending means currentArgs is not undefined
|
|
114
109
|
const currentArgs = this.currentArgs as Parameters<TFn>;
|
|
115
|
-
const nextArgs = this.updateArgs(
|
|
116
|
-
currentArgs,
|
|
117
|
-
this.middleArgs,
|
|
118
|
-
args,
|
|
119
|
-
this.nextArgs,
|
|
120
|
-
);
|
|
110
|
+
const nextArgs = this.updateArgs(currentArgs, this.middleArgs, args, this.nextArgs);
|
|
121
111
|
if (this.areArgsEqual(nextArgs, currentArgs)) {
|
|
122
112
|
// do not schedule new call
|
|
123
113
|
this.nextArgs = undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-reentrant mutex
|
|
3
|
+
*
|
|
4
|
+
* This allows only one context to enter a block at a time in a FIFO manner.
|
|
5
|
+
*
|
|
6
|
+
* This mutex is non-reentrant. Trying to lock it again while the same
|
|
7
|
+
* context already owns the lock will cause a dead lock.
|
|
8
|
+
*
|
|
9
|
+
* While a context id can be used to implement reentrant locks,
|
|
10
|
+
* it is very cumbersome to use. https://github.com/tc39/proposal-async-context
|
|
11
|
+
* will allow for a cleaner implementation.
|
|
12
|
+
*/
|
|
13
|
+
// TODO: implement it if needed
|
|
14
|
+
// export class Mutex {
|
|
15
|
+
// private waiters: Deque;
|
|
16
|
+
//
|
|
17
|
+
// constructor() {
|
|
18
|
+
// this.waiters = new
|
|
19
|
+
// }
|
|
20
|
+
//
|
|
21
|
+
// }
|
package/src/sync/serial.test.ts
CHANGED
|
@@ -5,8 +5,7 @@ import type { Result } from "../result/index.ts";
|
|
|
5
5
|
|
|
6
6
|
test("example", async () => {
|
|
7
7
|
// helper function to simulate async work
|
|
8
|
-
const wait = (ms: number) =>
|
|
9
|
-
new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
|
+
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
9
|
// Create the wrapped function
|
|
11
10
|
const doWork = serial({
|
|
12
11
|
fn: (checkCancel) => async () => {
|
package/src/sync/serial.ts
CHANGED
|
@@ -133,10 +133,7 @@ import type { AnyFn } from "./util.ts";
|
|
|
133
133
|
* If the underlying function throws, the exception will be re-thrown to the caller.
|
|
134
134
|
*/
|
|
135
135
|
|
|
136
|
-
export function serial<TFn extends AnyFn>({
|
|
137
|
-
fn,
|
|
138
|
-
onCancel,
|
|
139
|
-
}: SerialConstructor<TFn>) {
|
|
136
|
+
export function serial<TFn extends AnyFn>({ fn, onCancel }: SerialConstructor<TFn>) {
|
|
140
137
|
const impl = new SerialImpl(fn, onCancel);
|
|
141
138
|
return (...args: Parameters<TFn>) => impl.invoke(...args);
|
|
142
139
|
}
|
|
@@ -162,10 +159,7 @@ class SerialImpl<TFn extends AnyFn> {
|
|
|
162
159
|
private fn: SerialFnCreator<TFn>;
|
|
163
160
|
private onCancel: SerialEventCancelCallback;
|
|
164
161
|
|
|
165
|
-
constructor(
|
|
166
|
-
fn: SerialFnCreator<TFn>,
|
|
167
|
-
onCancel?: SerialEventCancelCallback,
|
|
168
|
-
) {
|
|
162
|
+
constructor(fn: SerialFnCreator<TFn>, onCancel?: SerialEventCancelCallback) {
|
|
169
163
|
this.fn = fn;
|
|
170
164
|
this.serial = 0n;
|
|
171
165
|
if (onCancel) {
|
|
@@ -212,10 +206,7 @@ type SerialFnCreator<T> = (checkCancel: CheckCancelFn, serial: SerialId) => T;
|
|
|
212
206
|
* The callback type passed to SerialEvent constructor to be called
|
|
213
207
|
* when the event is cancelled
|
|
214
208
|
*/
|
|
215
|
-
export type SerialEventCancelCallback = (
|
|
216
|
-
current: SerialId,
|
|
217
|
-
latest: SerialId,
|
|
218
|
-
) => void;
|
|
209
|
+
export type SerialEventCancelCallback = (current: SerialId, latest: SerialId) => void;
|
|
219
210
|
|
|
220
211
|
/** The error type received by caller when an event is cancelled */
|
|
221
212
|
export type SerialCancelToken = "cancel";
|
package/src/sync/util.ts
CHANGED
|
@@ -26,9 +26,7 @@ export type PromiseHandle<T> = {
|
|
|
26
26
|
|
|
27
27
|
/** Shorthand for Awaited<ReturnType<T>> */
|
|
28
28
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
-
export type AwaitRet<T> = T extends (...args: any[]) => infer R
|
|
30
|
-
? Awaited<R>
|
|
31
|
-
: never;
|
|
29
|
+
export type AwaitRet<T> = T extends (...args: any[]) => infer R ? Awaited<R> : never;
|
|
32
30
|
|
|
33
31
|
/** Type for any function */
|
|
34
32
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|