WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
import { SonicBoom } from '../../'
|
||||
|
||||
const sonic = new SonicBoom({ fd: process.stdout.fd })
|
||||
sonic.write('hello sonic\n')
|
||||
@@ -0,0 +1,56 @@
|
||||
import OverloadYield from "./OverloadYield.js";
|
||||
function _wrapAsyncGenerator(e) {
|
||||
return function () {
|
||||
return new AsyncGenerator(e.apply(this, arguments));
|
||||
};
|
||||
}
|
||||
function AsyncGenerator(e) {
|
||||
var t, n;
|
||||
function resume(t, n) {
|
||||
try {
|
||||
var r = e[t](n),
|
||||
o = r.value,
|
||||
u = o instanceof OverloadYield;
|
||||
Promise.resolve(u ? o.v : o).then(function (n) {
|
||||
if (u) {
|
||||
var i = "return" === t && o.k ? t : "next";
|
||||
if (!o.k || n.done) return resume(i, n);
|
||||
n = e[i](n).value;
|
||||
}
|
||||
settle(!!r.done, n);
|
||||
}, function (e) {
|
||||
resume("throw", e);
|
||||
});
|
||||
} catch (e) {
|
||||
settle(2, e);
|
||||
}
|
||||
}
|
||||
function settle(e, r) {
|
||||
2 === e ? t.reject(r) : t.resolve({
|
||||
value: r,
|
||||
done: e
|
||||
}), (t = t.next) ? resume(t.key, t.arg) : n = null;
|
||||
}
|
||||
this._invoke = function (e, r) {
|
||||
return new Promise(function (o, u) {
|
||||
var i = {
|
||||
key: e,
|
||||
arg: r,
|
||||
resolve: o,
|
||||
reject: u,
|
||||
next: null
|
||||
};
|
||||
n ? n = n.next = i : (t = n = i, resume(e, r));
|
||||
});
|
||||
}, "function" != typeof e["return"] && (this["return"] = void 0);
|
||||
}
|
||||
AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () {
|
||||
return this;
|
||||
}, AsyncGenerator.prototype.next = function (e) {
|
||||
return this._invoke("next", e);
|
||||
}, AsyncGenerator.prototype["throw"] = function (e) {
|
||||
return this._invoke("throw", e);
|
||||
}, AsyncGenerator.prototype["return"] = function (e) {
|
||||
return this._invoke("return", e);
|
||||
};
|
||||
export { _wrapAsyncGenerator as default };
|
||||
@@ -0,0 +1,711 @@
|
||||
declare module "node:async_hooks" {
|
||||
/**
|
||||
* ```js
|
||||
* import { executionAsyncId } from 'node:async_hooks';
|
||||
* import fs from 'node:fs';
|
||||
*
|
||||
* console.log(executionAsyncId()); // 1 - bootstrap
|
||||
* const path = '.';
|
||||
* fs.open(path, 'r', (err, fd) => {
|
||||
* console.log(executionAsyncId()); // 6 - open()
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The ID returned from `executionAsyncId()` is related to execution timing, not
|
||||
* causality (which is covered by `triggerAsyncId()`):
|
||||
*
|
||||
* ```js
|
||||
* const server = net.createServer((conn) => {
|
||||
* // Returns the ID of the server, not of the new connection, because the
|
||||
* // callback runs in the execution scope of the server's MakeCallback().
|
||||
* async_hooks.executionAsyncId();
|
||||
*
|
||||
* }).listen(port, () => {
|
||||
* // Returns the ID of a TickObject (process.nextTick()) because all
|
||||
* // callbacks passed to .listen() are wrapped in a nextTick().
|
||||
* async_hooks.executionAsyncId();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Promise contexts may not get precise `executionAsyncIds` by default.
|
||||
* See the section on [promise execution tracking](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#promise-execution-tracking).
|
||||
* @since v8.1.0
|
||||
* @return The `asyncId` of the current execution context. Useful to track when something calls.
|
||||
*/
|
||||
function executionAsyncId(): number;
|
||||
/**
|
||||
* Resource objects returned by `executionAsyncResource()` are most often internal
|
||||
* Node.js handle objects with undocumented APIs. Using any functions or properties
|
||||
* on the object is likely to crash your application and should be avoided.
|
||||
*
|
||||
* Using `executionAsyncResource()` in the top-level execution context will
|
||||
* return an empty object as there is no handle or request object to use,
|
||||
* but having an object representing the top-level can be helpful.
|
||||
*
|
||||
* ```js
|
||||
* import { open } from 'node:fs';
|
||||
* import { executionAsyncId, executionAsyncResource } from 'node:async_hooks';
|
||||
*
|
||||
* console.log(executionAsyncId(), executionAsyncResource()); // 1 {}
|
||||
* open(new URL(import.meta.url), 'r', (err, fd) => {
|
||||
* console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* This can be used to implement continuation local storage without the
|
||||
* use of a tracking `Map` to store the metadata:
|
||||
*
|
||||
* ```js
|
||||
* import { createServer } from 'node:http';
|
||||
* import {
|
||||
* executionAsyncId,
|
||||
* executionAsyncResource,
|
||||
* createHook,
|
||||
* } from 'node:async_hooks';
|
||||
* const sym = Symbol('state'); // Private symbol to avoid pollution
|
||||
*
|
||||
* createHook({
|
||||
* init(asyncId, type, triggerAsyncId, resource) {
|
||||
* const cr = executionAsyncResource();
|
||||
* if (cr) {
|
||||
* resource[sym] = cr[sym];
|
||||
* }
|
||||
* },
|
||||
* }).enable();
|
||||
*
|
||||
* const server = createServer((req, res) => {
|
||||
* executionAsyncResource()[sym] = { state: req.url };
|
||||
* setTimeout(function() {
|
||||
* res.end(JSON.stringify(executionAsyncResource()[sym]));
|
||||
* }, 100);
|
||||
* }).listen(3000);
|
||||
* ```
|
||||
* @since v13.9.0, v12.17.0
|
||||
* @return The resource representing the current execution. Useful to store data within the resource.
|
||||
*/
|
||||
function executionAsyncResource(): object;
|
||||
/**
|
||||
* ```js
|
||||
* const server = net.createServer((conn) => {
|
||||
* // The resource that caused (or triggered) this callback to be called
|
||||
* // was that of the new connection. Thus the return value of triggerAsyncId()
|
||||
* // is the asyncId of "conn".
|
||||
* async_hooks.triggerAsyncId();
|
||||
*
|
||||
* }).listen(port, () => {
|
||||
* // Even though all callbacks passed to .listen() are wrapped in a nextTick()
|
||||
* // the callback itself exists because the call to the server's .listen()
|
||||
* // was made. So the return value would be the ID of the server.
|
||||
* async_hooks.triggerAsyncId();
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Promise contexts may not get valid `triggerAsyncId`s by default. See
|
||||
* the section on [promise execution tracking](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#promise-execution-tracking).
|
||||
* @return The ID of the resource responsible for calling the callback that is currently being executed.
|
||||
*/
|
||||
function triggerAsyncId(): number;
|
||||
interface HookCallbacks {
|
||||
/**
|
||||
* The [`init` callback](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#initasyncid-type-triggerasyncid-resource).
|
||||
*/
|
||||
init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
|
||||
/**
|
||||
* The [`before` callback](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#beforeasyncid).
|
||||
*/
|
||||
before?(asyncId: number): void;
|
||||
/**
|
||||
* The [`after` callback](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#afterasyncid).
|
||||
*/
|
||||
after?(asyncId: number): void;
|
||||
/**
|
||||
* The [`promiseResolve` callback](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#promiseresolveasyncid).
|
||||
*/
|
||||
promiseResolve?(asyncId: number): void;
|
||||
/**
|
||||
* The [`destroy` callback](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#destroyasyncid).
|
||||
*/
|
||||
destroy?(asyncId: number): void;
|
||||
/**
|
||||
* Whether the hook should track `Promise`s. Cannot be `false` if
|
||||
* `promiseResolve` is set.
|
||||
* @default true
|
||||
*/
|
||||
trackPromises?: boolean | undefined;
|
||||
}
|
||||
interface AsyncHook {
|
||||
/**
|
||||
* Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
|
||||
*/
|
||||
enable(): this;
|
||||
/**
|
||||
* Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.
|
||||
*/
|
||||
disable(): this;
|
||||
}
|
||||
/**
|
||||
* Registers functions to be called for different lifetime events of each async
|
||||
* operation.
|
||||
*
|
||||
* The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the
|
||||
* respective asynchronous event during a resource's lifetime.
|
||||
*
|
||||
* All callbacks are optional. For example, if only resource cleanup needs to
|
||||
* be tracked, then only the `destroy` callback needs to be passed. The
|
||||
* specifics of all functions that can be passed to `callbacks` is in the
|
||||
* [Hook Callbacks](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#hook-callbacks) section.
|
||||
*
|
||||
* ```js
|
||||
* import { createHook } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncHook = createHook({
|
||||
* init(asyncId, type, triggerAsyncId, resource) { },
|
||||
* destroy(asyncId) { },
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The callbacks will be inherited via the prototype chain:
|
||||
*
|
||||
* ```js
|
||||
* class MyAsyncCallbacks {
|
||||
* init(asyncId, type, triggerAsyncId, resource) { }
|
||||
* destroy(asyncId) {}
|
||||
* }
|
||||
*
|
||||
* class MyAddedCallbacks extends MyAsyncCallbacks {
|
||||
* before(asyncId) { }
|
||||
* after(asyncId) { }
|
||||
* }
|
||||
*
|
||||
* const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
|
||||
* ```
|
||||
*
|
||||
* Because promises are asynchronous resources whose lifecycle is tracked
|
||||
* via the async hooks mechanism, the `init()`, `before()`, `after()`, and
|
||||
* `destroy()` callbacks _must not_ be async functions that return promises.
|
||||
* @since v8.1.0
|
||||
* @param options The [Hook Callbacks](https://nodejs.org/docs/latest-v26.x/api/async_hooks.html#hook-callbacks) to register
|
||||
* @returns Instance used for disabling and enabling hooks
|
||||
*/
|
||||
function createHook(options: HookCallbacks): AsyncHook;
|
||||
interface AsyncResourceOptions {
|
||||
/**
|
||||
* The ID of the execution context that created this async event.
|
||||
* @default executionAsyncId()
|
||||
*/
|
||||
triggerAsyncId?: number | undefined;
|
||||
/**
|
||||
* Disables automatic `emitDestroy` when the object is garbage collected.
|
||||
* This usually does not need to be set (even if `emitDestroy` is called
|
||||
* manually), unless the resource's `asyncId` is retrieved and the
|
||||
* sensitive API's `emitDestroy` is called with it.
|
||||
* @default false
|
||||
*/
|
||||
requireManualDestroy?: boolean | undefined;
|
||||
}
|
||||
/**
|
||||
* The class `AsyncResource` is designed to be extended by the embedder's async
|
||||
* resources. Using this, users can easily trigger the lifetime events of their
|
||||
* own resources.
|
||||
*
|
||||
* The `init` hook will trigger when an `AsyncResource` is instantiated.
|
||||
*
|
||||
* The following is an overview of the `AsyncResource` API.
|
||||
*
|
||||
* ```js
|
||||
* import { AsyncResource, executionAsyncId } from 'node:async_hooks';
|
||||
*
|
||||
* // AsyncResource() is meant to be extended. Instantiating a
|
||||
* // new AsyncResource() also triggers init. If triggerAsyncId is omitted then
|
||||
* // async_hook.executionAsyncId() is used.
|
||||
* const asyncResource = new AsyncResource(
|
||||
* type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
|
||||
* );
|
||||
*
|
||||
* // Run a function in the execution context of the resource. This will
|
||||
* // * establish the context of the resource
|
||||
* // * trigger the AsyncHooks before callbacks
|
||||
* // * call the provided function `fn` with the supplied arguments
|
||||
* // * trigger the AsyncHooks after callbacks
|
||||
* // * restore the original execution context
|
||||
* asyncResource.runInAsyncScope(fn, thisArg, ...args);
|
||||
*
|
||||
* // Call AsyncHooks destroy callbacks.
|
||||
* asyncResource.emitDestroy();
|
||||
*
|
||||
* // Return the unique ID assigned to the AsyncResource instance.
|
||||
* asyncResource.asyncId();
|
||||
*
|
||||
* // Return the trigger ID for the AsyncResource instance.
|
||||
* asyncResource.triggerAsyncId();
|
||||
* ```
|
||||
*/
|
||||
class AsyncResource {
|
||||
/**
|
||||
* AsyncResource() is meant to be extended. Instantiating a
|
||||
* new AsyncResource() also triggers init. If triggerAsyncId is omitted then
|
||||
* async_hook.executionAsyncId() is used.
|
||||
* @param type The type of async event.
|
||||
* @param triggerAsyncId The ID of the execution context that created
|
||||
* this async event (default: `executionAsyncId()`), or an
|
||||
* AsyncResourceOptions object (since v9.3.0)
|
||||
*/
|
||||
constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions);
|
||||
/**
|
||||
* Binds the given function to the current execution context.
|
||||
* @since v14.8.0, v12.19.0
|
||||
* @param fn The function to bind to the current execution context.
|
||||
* @param type An optional name to associate with the underlying `AsyncResource`.
|
||||
*/
|
||||
static bind<Func extends (this: ThisArg, ...args: any[]) => any, ThisArg>(
|
||||
fn: Func,
|
||||
type?: string,
|
||||
thisArg?: ThisArg,
|
||||
): Func;
|
||||
/**
|
||||
* Binds the given function to execute to this `AsyncResource`'s scope.
|
||||
* @since v14.8.0, v12.19.0
|
||||
* @param fn The function to bind to the current `AsyncResource`.
|
||||
*/
|
||||
bind<Func extends (...args: any[]) => any>(fn: Func): Func;
|
||||
/**
|
||||
* Call the provided function with the provided arguments in the execution context
|
||||
* of the async resource. This will establish the context, trigger the AsyncHooks
|
||||
* before callbacks, call the function, trigger the AsyncHooks after callbacks, and
|
||||
* then restore the original execution context.
|
||||
* @since v9.6.0
|
||||
* @param fn The function to call in the execution context of this async resource.
|
||||
* @param thisArg The receiver to be used for the function call.
|
||||
* @param args Optional arguments to pass to the function.
|
||||
*/
|
||||
runInAsyncScope<This, Result>(
|
||||
fn: (this: This, ...args: any[]) => Result,
|
||||
thisArg?: This,
|
||||
...args: any[]
|
||||
): Result;
|
||||
/**
|
||||
* Call all `destroy` hooks. This should only ever be called once. An error will
|
||||
* be thrown if it is called more than once. This **must** be manually called. If
|
||||
* the resource is left to be collected by the GC then the `destroy` hooks will
|
||||
* never be called.
|
||||
* @return A reference to `asyncResource`.
|
||||
*/
|
||||
emitDestroy(): this;
|
||||
/**
|
||||
* @return The unique `asyncId` assigned to the resource.
|
||||
*/
|
||||
asyncId(): number;
|
||||
/**
|
||||
* @return The same `triggerAsyncId` that is passed to the `AsyncResource` constructor.
|
||||
*/
|
||||
triggerAsyncId(): number;
|
||||
}
|
||||
interface AsyncLocalStorageOptions {
|
||||
/**
|
||||
* The default value to be used when no store is provided.
|
||||
*/
|
||||
defaultValue?: any;
|
||||
/**
|
||||
* A name for the `AsyncLocalStorage` value.
|
||||
*/
|
||||
name?: string | undefined;
|
||||
}
|
||||
/**
|
||||
* This class creates stores that stay coherent through asynchronous operations.
|
||||
*
|
||||
* While you can create your own implementation on top of the `node:async_hooks` module, `AsyncLocalStorage` should be preferred as it is a performant and memory
|
||||
* safe implementation that involves significant optimizations that are non-obvious
|
||||
* to implement.
|
||||
*
|
||||
* The following example uses `AsyncLocalStorage` to build a simple logger
|
||||
* that assigns IDs to incoming HTTP requests and includes them in messages
|
||||
* logged within each request.
|
||||
*
|
||||
* ```js
|
||||
* import http from 'node:http';
|
||||
* import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
*
|
||||
* function logWithId(msg) {
|
||||
* const id = asyncLocalStorage.getStore();
|
||||
* console.log(`${id !== undefined ? id : '-'}:`, msg);
|
||||
* }
|
||||
*
|
||||
* let idSeq = 0;
|
||||
* http.createServer((req, res) => {
|
||||
* asyncLocalStorage.run(idSeq++, () => {
|
||||
* logWithId('start');
|
||||
* // Imagine any chain of async operations here
|
||||
* setImmediate(() => {
|
||||
* logWithId('finish');
|
||||
* res.end();
|
||||
* });
|
||||
* });
|
||||
* }).listen(8080);
|
||||
*
|
||||
* http.get('http://localhost:8080');
|
||||
* http.get('http://localhost:8080');
|
||||
* // Prints:
|
||||
* // 0: start
|
||||
* // 0: finish
|
||||
* // 1: start
|
||||
* // 1: finish
|
||||
* ```
|
||||
*
|
||||
* Each instance of `AsyncLocalStorage` maintains an independent storage context.
|
||||
* Multiple instances can safely exist simultaneously without risk of interfering
|
||||
* with each other's data.
|
||||
* @since v13.10.0, v12.17.0
|
||||
*/
|
||||
class AsyncLocalStorage<T> {
|
||||
/**
|
||||
* Creates a new instance of `AsyncLocalStorage`. Store is only provided within a
|
||||
* `run()` call or after an `enterWith()` call.
|
||||
*/
|
||||
constructor(options?: AsyncLocalStorageOptions);
|
||||
/**
|
||||
* Binds the given function to the current execution context.
|
||||
* @since v19.8.0
|
||||
* @param fn The function to bind to the current execution context.
|
||||
* @return A new function that calls `fn` within the captured execution context.
|
||||
*/
|
||||
static bind<Func extends (...args: any[]) => any>(fn: Func): Func;
|
||||
/**
|
||||
* Captures the current execution context and returns a function that accepts a
|
||||
* function as an argument. Whenever the returned function is called, it
|
||||
* calls the function passed to it within the captured context.
|
||||
*
|
||||
* ```js
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
* const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
|
||||
* const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
|
||||
* console.log(result); // returns 123
|
||||
* ```
|
||||
*
|
||||
* AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
|
||||
* async context tracking purposes, for example:
|
||||
*
|
||||
* ```js
|
||||
* class Foo {
|
||||
* #runInAsyncScope = AsyncLocalStorage.snapshot();
|
||||
*
|
||||
* get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
|
||||
* }
|
||||
*
|
||||
* const foo = asyncLocalStorage.run(123, () => new Foo());
|
||||
* console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
|
||||
* ```
|
||||
* @since v19.8.0
|
||||
* @return A new function with the signature `(fn: (...args) : R, ...args) : R`.
|
||||
*/
|
||||
static snapshot(): <R, TArgs extends any[]>(fn: (...args: TArgs) => R, ...args: TArgs) => R;
|
||||
/**
|
||||
* Disables the instance of `AsyncLocalStorage`. All subsequent calls
|
||||
* to `asyncLocalStorage.getStore()` will return `undefined` until `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()` is called again.
|
||||
*
|
||||
* When calling `asyncLocalStorage.disable()`, all current contexts linked to the
|
||||
* instance will be exited.
|
||||
*
|
||||
* Calling `asyncLocalStorage.disable()` is required before the `asyncLocalStorage` can be garbage collected. This does not apply to stores
|
||||
* provided by the `asyncLocalStorage`, as those objects are garbage collected
|
||||
* along with the corresponding async resources.
|
||||
*
|
||||
* Use this method when the `asyncLocalStorage` is not in use anymore
|
||||
* in the current process.
|
||||
* @since v13.10.0, v12.17.0
|
||||
* @experimental
|
||||
*/
|
||||
disable(): void;
|
||||
/**
|
||||
* Returns the current store.
|
||||
* If called outside of an asynchronous context initialized by
|
||||
* calling `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()`, it
|
||||
* returns `undefined`.
|
||||
* @since v13.10.0, v12.17.0
|
||||
*/
|
||||
getStore(): T | undefined;
|
||||
/**
|
||||
* The name of the `AsyncLocalStorage` instance if provided.
|
||||
* @since v24.0.0
|
||||
*/
|
||||
readonly name: string;
|
||||
/**
|
||||
* Runs a function synchronously within a context and returns its
|
||||
* return value. The store is not accessible outside of the callback function.
|
||||
* The store is accessible to any asynchronous operations created within the
|
||||
* callback.
|
||||
*
|
||||
* The optional `args` are passed to the callback function.
|
||||
*
|
||||
* If the callback function throws an error, the error is thrown by `run()` too.
|
||||
* The stacktrace is not impacted by this call and the context is exited.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* const store = { id: 2 };
|
||||
* try {
|
||||
* asyncLocalStorage.run(store, () => {
|
||||
* asyncLocalStorage.getStore(); // Returns the store object
|
||||
* setTimeout(() => {
|
||||
* asyncLocalStorage.getStore(); // Returns the store object
|
||||
* }, 200);
|
||||
* throw new Error();
|
||||
* });
|
||||
* } catch (e) {
|
||||
* asyncLocalStorage.getStore(); // Returns undefined
|
||||
* // The error will be caught here
|
||||
* }
|
||||
* ```
|
||||
* @since v13.10.0, v12.17.0
|
||||
*/
|
||||
run<R>(store: T, callback: () => R): R;
|
||||
run<R, TArgs extends any[]>(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R;
|
||||
/**
|
||||
* Runs a function synchronously outside of a context and returns its
|
||||
* return value. The store is not accessible within the callback function or
|
||||
* the asynchronous operations created within the callback. Any `getStore()` call done within the callback function will always return `undefined`.
|
||||
*
|
||||
* The optional `args` are passed to the callback function.
|
||||
*
|
||||
* If the callback function throws an error, the error is thrown by `exit()` too.
|
||||
* The stacktrace is not impacted by this call and the context is re-entered.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* // Within a call to run
|
||||
* try {
|
||||
* asyncLocalStorage.getStore(); // Returns the store object or value
|
||||
* asyncLocalStorage.exit(() => {
|
||||
* asyncLocalStorage.getStore(); // Returns undefined
|
||||
* throw new Error();
|
||||
* });
|
||||
* } catch (e) {
|
||||
* asyncLocalStorage.getStore(); // Returns the same object or value
|
||||
* // The error will be caught here
|
||||
* }
|
||||
* ```
|
||||
* @since v13.10.0, v12.17.0
|
||||
* @experimental
|
||||
*/
|
||||
exit<R, TArgs extends any[]>(callback: (...args: TArgs) => R, ...args: TArgs): R;
|
||||
/**
|
||||
* Creates a disposable scope that enters the given store and automatically
|
||||
* restores the previous store value when the scope is disposed. This method is
|
||||
* designed to work with JavaScript's explicit resource management (`using` syntax).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
*
|
||||
* {
|
||||
* using _ = asyncLocalStorage.withScope('my-store');
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
|
||||
* }
|
||||
*
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: undefined
|
||||
* ```
|
||||
*
|
||||
* The `withScope()` method is particularly useful for managing context in
|
||||
* synchronous code where you want to ensure the previous store value is restored
|
||||
* when exiting a block, even if an error is thrown.
|
||||
*
|
||||
* ```js
|
||||
* import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
*
|
||||
* try {
|
||||
* using _ = asyncLocalStorage.withScope('my-store');
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
|
||||
* throw new Error('test');
|
||||
* } catch (e) {
|
||||
* // Store is automatically restored even after error
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: undefined
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **Important:** When using `withScope()` in async functions before the first
|
||||
* `await`, be aware that the scope change will affect the caller's context. The
|
||||
* synchronous portion of an async function (before the first `await`) runs
|
||||
* immediately when called, and when it reaches the first `await`, it returns the
|
||||
* promise to the caller. At that point, the scope change becomes visible in the
|
||||
* caller's context and will persist in subsequent synchronous code until something
|
||||
* else changes the scope value. For async operations, prefer using `run()` which
|
||||
* properly isolates context across async boundaries.
|
||||
*
|
||||
* ```js
|
||||
* import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
*
|
||||
* const asyncLocalStorage = new AsyncLocalStorage();
|
||||
*
|
||||
* async function example() {
|
||||
* using _ = asyncLocalStorage.withScope('my-store');
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
|
||||
* await someAsyncOperation(); // Function pauses here and returns promise
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
|
||||
* }
|
||||
*
|
||||
* // Calling without await
|
||||
* example(); // Synchronous portion runs, then pauses at first await
|
||||
* // After the promise is returned, the scope 'my-store' is now active in caller!
|
||||
* console.log(asyncLocalStorage.getStore()); // Prints: my-store (unexpected!)
|
||||
* ```
|
||||
* @since v25.9.0
|
||||
* @experimental
|
||||
*/
|
||||
withScope(store: T): RunScope;
|
||||
/**
|
||||
* Transitions into the context for the remainder of the current
|
||||
* synchronous execution and then persists the store through any following
|
||||
* asynchronous calls.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* const store = { id: 1 };
|
||||
* // Replaces previous store with the given store object
|
||||
* asyncLocalStorage.enterWith(store);
|
||||
* asyncLocalStorage.getStore(); // Returns the store object
|
||||
* someAsyncOperation(() => {
|
||||
* asyncLocalStorage.getStore(); // Returns the same object
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* This transition will continue for the _entire_ synchronous execution.
|
||||
* This means that if, for example, the context is entered within an event
|
||||
* handler subsequent event handlers will also run within that context unless
|
||||
* specifically bound to another context with an `AsyncResource`. That is why `run()` should be preferred over `enterWith()` unless there are strong reasons
|
||||
* to use the latter method.
|
||||
*
|
||||
* ```js
|
||||
* const store = { id: 1 };
|
||||
*
|
||||
* emitter.on('my-event', () => {
|
||||
* asyncLocalStorage.enterWith(store);
|
||||
* });
|
||||
* emitter.on('my-event', () => {
|
||||
* asyncLocalStorage.getStore(); // Returns the same object
|
||||
* });
|
||||
*
|
||||
* asyncLocalStorage.getStore(); // Returns undefined
|
||||
* emitter.emit('my-event');
|
||||
* asyncLocalStorage.getStore(); // Returns the same object
|
||||
* ```
|
||||
* @since v13.11.0, v12.17.0
|
||||
* @experimental
|
||||
*/
|
||||
enterWith(store: T): void;
|
||||
}
|
||||
/**
|
||||
* A disposable scope returned by `asyncLocalStorage.withScope()` that
|
||||
* automatically restores the previous store value when disposed. This class
|
||||
* implements the [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management) protocol and is designed to work
|
||||
* with JavaScript's `using` syntax.
|
||||
*
|
||||
* The scope automatically restores the previous store value when the `using` block
|
||||
* exits, whether through normal completion or by throwing an error.
|
||||
* @since v25.9.0
|
||||
* @experimental
|
||||
*/
|
||||
interface RunScope extends Disposable {
|
||||
/**
|
||||
* Explicitly ends the scope and restores the previous store value. This method
|
||||
* is idempotent: calling it multiple times has the same effect as calling it once.
|
||||
*
|
||||
* The `[Symbol.dispose]()` method defers to `dispose()`.
|
||||
*
|
||||
* If `withScope()` is called without the `using` keyword, `dispose()` must be
|
||||
* called manually to restore the previous store value. Forgetting to call
|
||||
* `dispose()` will cause the store value to persist for the remainder of the
|
||||
* current execution context:
|
||||
*
|
||||
* ```js
|
||||
* import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
*
|
||||
* const storage = new AsyncLocalStorage();
|
||||
*
|
||||
* // Without using, the scope must be disposed manually
|
||||
* const scope = storage.withScope('my-store');
|
||||
* // storage.getStore() === 'my-store' here
|
||||
*
|
||||
* scope.dispose(); // Restore previous value
|
||||
* // storage.getStore() === undefined here
|
||||
* ```
|
||||
* @since v25.9.0
|
||||
*/
|
||||
dispose(): void;
|
||||
}
|
||||
/**
|
||||
* @since v17.2.0, v16.14.0
|
||||
* @return A map of provider types to the corresponding numeric id.
|
||||
* This map contains all the event types that might be emitted by the `async_hooks.init()` event.
|
||||
*/
|
||||
namespace asyncWrapProviders {
|
||||
const NONE: number;
|
||||
const DIRHANDLE: number;
|
||||
const DNSCHANNEL: number;
|
||||
const ELDHISTOGRAM: number;
|
||||
const FILEHANDLE: number;
|
||||
const FILEHANDLECLOSEREQ: number;
|
||||
const FIXEDSIZEBLOBCOPY: number;
|
||||
const FSEVENTWRAP: number;
|
||||
const FSREQCALLBACK: number;
|
||||
const FSREQPROMISE: number;
|
||||
const GETADDRINFOREQWRAP: number;
|
||||
const GETNAMEINFOREQWRAP: number;
|
||||
const HEAPSNAPSHOT: number;
|
||||
const HTTP2SESSION: number;
|
||||
const HTTP2STREAM: number;
|
||||
const HTTP2PING: number;
|
||||
const HTTP2SETTINGS: number;
|
||||
const HTTPINCOMINGMESSAGE: number;
|
||||
const HTTPCLIENTREQUEST: number;
|
||||
const JSSTREAM: number;
|
||||
const JSUDPWRAP: number;
|
||||
const MESSAGEPORT: number;
|
||||
const PIPECONNECTWRAP: number;
|
||||
const PIPESERVERWRAP: number;
|
||||
const PIPEWRAP: number;
|
||||
const PROCESSWRAP: number;
|
||||
const PROMISE: number;
|
||||
const QUERYWRAP: number;
|
||||
const SHUTDOWNWRAP: number;
|
||||
const SIGNALWRAP: number;
|
||||
const STATWATCHER: number;
|
||||
const STREAMPIPE: number;
|
||||
const TCPCONNECTWRAP: number;
|
||||
const TCPSERVERWRAP: number;
|
||||
const TCPWRAP: number;
|
||||
const TTYWRAP: number;
|
||||
const UDPSENDWRAP: number;
|
||||
const UDPWRAP: number;
|
||||
const SIGINTWATCHDOG: number;
|
||||
const WORKER: number;
|
||||
const WORKERHEAPSNAPSHOT: number;
|
||||
const WRITEWRAP: number;
|
||||
const ZLIB: number;
|
||||
const CHECKPRIMEREQUEST: number;
|
||||
const PBKDF2REQUEST: number;
|
||||
const KEYPAIRGENREQUEST: number;
|
||||
const KEYGENREQUEST: number;
|
||||
const KEYEXPORTREQUEST: number;
|
||||
const CIPHERREQUEST: number;
|
||||
const DERIVEBITSREQUEST: number;
|
||||
const HASHREQUEST: number;
|
||||
const RANDOMBYTESREQUEST: number;
|
||||
const RANDOMPRIMEREQUEST: number;
|
||||
const SCRYPTREQUEST: number;
|
||||
const SIGNREQUEST: number;
|
||||
const TLSWRAP: number;
|
||||
const VERIFYREQUEST: number;
|
||||
}
|
||||
}
|
||||
declare module "async_hooks" {
|
||||
export * from "node:async_hooks";
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
import type { Version1Options } from './types.js';
|
||||
type V1State = {
|
||||
node?: Uint8Array;
|
||||
clockseq?: number;
|
||||
msecs?: number;
|
||||
nsecs?: number;
|
||||
};
|
||||
declare function v1(options?: Version1Options, buf?: undefined, offset?: number): string;
|
||||
declare function v1<Buf extends Uint8Array = Uint8Array>(options: Version1Options | undefined, buf: Buf, offset?: number): Buf;
|
||||
export declare function updateV1State(state: V1State, now: number, rnds: Uint8Array): V1State;
|
||||
export default v1;
|
||||
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2017_object = void 0;
|
||||
const base_config_1 = require("./base-config");
|
||||
exports.es2017_object = {
|
||||
libs: [],
|
||||
variables: [['ObjectConstructor', base_config_1.TYPE]],
|
||||
};
|
||||
@@ -0,0 +1,482 @@
|
||||
/**
|
||||
* @fileoverview A rule to disallow the type conversions with shorter notations.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/u;
|
||||
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "- -", "-", "*"];
|
||||
|
||||
/**
|
||||
* Checks whether or not a node is a double logical negating.
|
||||
* @param {ASTNode} node An UnaryExpression node to check.
|
||||
* @returns {boolean} Whether or not the node is a double logical negating.
|
||||
*/
|
||||
function isDoubleLogicalNegating(node) {
|
||||
return (
|
||||
node.operator === "!" &&
|
||||
node.argument.type === "UnaryExpression" &&
|
||||
node.argument.operator === "!"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a node is a binary negating of `.indexOf()` method calling.
|
||||
* @param {ASTNode} node An UnaryExpression node to check.
|
||||
* @returns {boolean} Whether or not the node is a binary negating of `.indexOf()` method calling.
|
||||
*/
|
||||
function isBinaryNegatingOfIndexOf(node) {
|
||||
if (node.operator !== "~") {
|
||||
return false;
|
||||
}
|
||||
const callNode = astUtils.skipChainExpression(node.argument);
|
||||
|
||||
return (
|
||||
callNode.type === "CallExpression" &&
|
||||
astUtils.isSpecificMemberAccess(callNode.callee, null, INDEX_OF_PATTERN)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a node is a multiplying by one.
|
||||
* @param {BinaryExpression} node A BinaryExpression node to check.
|
||||
* @returns {boolean} Whether or not the node is a multiplying by one.
|
||||
*/
|
||||
function isMultiplyByOne(node) {
|
||||
return (
|
||||
node.operator === "*" &&
|
||||
((node.left.type === "Literal" && node.left.value === 1) ||
|
||||
(node.right.type === "Literal" && node.right.value === 1))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node logically represents multiplication by a fraction of `1`.
|
||||
* For example, `a * 1` in `a * 1 / b` is technically multiplication by `1`, but the
|
||||
* whole expression can be logically interpreted as `a * (1 / b)` rather than `(a * 1) / b`.
|
||||
* @param {BinaryExpression} node A BinaryExpression node to check.
|
||||
* @param {SourceCode} sourceCode The source code object.
|
||||
* @returns {boolean} Whether or not the node is a multiplying by a fraction of `1`.
|
||||
*/
|
||||
function isMultiplyByFractionOfOne(node, sourceCode) {
|
||||
return (
|
||||
node.type === "BinaryExpression" &&
|
||||
node.operator === "*" &&
|
||||
node.right.type === "Literal" &&
|
||||
node.right.value === 1 &&
|
||||
node.parent.type === "BinaryExpression" &&
|
||||
node.parent.operator === "/" &&
|
||||
node.parent.left === node &&
|
||||
!astUtils.isParenthesised(sourceCode, node)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the result of a node is numeric or not
|
||||
* @param {ASTNode} node The node to test
|
||||
* @returns {boolean} true if the node is a number literal or a `Number()`, `parseInt` or `parseFloat` call
|
||||
*/
|
||||
function isNumeric(node) {
|
||||
return (
|
||||
(node.type === "Literal" && typeof node.value === "number") ||
|
||||
(node.type === "CallExpression" &&
|
||||
(node.callee.name === "Number" ||
|
||||
node.callee.name === "parseInt" ||
|
||||
node.callee.name === "parseFloat"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first non-numeric operand in a BinaryExpression. Designed to be
|
||||
* used from bottom to up since it walks up the BinaryExpression trees using
|
||||
* node.parent to find the result.
|
||||
* @param {BinaryExpression} node The BinaryExpression node to be walked up on
|
||||
* @returns {ASTNode|null} The first non-numeric item in the BinaryExpression tree or null
|
||||
*/
|
||||
function getNonNumericOperand(node) {
|
||||
const left = node.left,
|
||||
right = node.right;
|
||||
|
||||
if (right.type !== "BinaryExpression" && !isNumeric(right)) {
|
||||
return right;
|
||||
}
|
||||
|
||||
if (left.type !== "BinaryExpression" && !isNumeric(left)) {
|
||||
return left;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an expression evaluates to a string.
|
||||
* @param {ASTNode} node node that represents the expression to check.
|
||||
* @returns {boolean} Whether or not the expression evaluates to a string.
|
||||
*/
|
||||
function isStringType(node) {
|
||||
return (
|
||||
astUtils.isStringLiteral(node) ||
|
||||
(node.type === "CallExpression" &&
|
||||
node.callee.type === "Identifier" &&
|
||||
node.callee.name === "String")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a node is an empty string literal or not.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} Whether or not the passed in node is an
|
||||
* empty string literal or not.
|
||||
*/
|
||||
function isEmptyString(node) {
|
||||
return (
|
||||
astUtils.isStringLiteral(node) &&
|
||||
(node.value === "" ||
|
||||
(node.type === "TemplateLiteral" &&
|
||||
node.quasis.length === 1 &&
|
||||
node.quasis[0].value.cooked === ""))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a node is a concatenating with an empty string.
|
||||
* @param {ASTNode} node A BinaryExpression node to check.
|
||||
* @returns {boolean} Whether or not the node is a concatenating with an empty string.
|
||||
*/
|
||||
function isConcatWithEmptyString(node) {
|
||||
return (
|
||||
node.operator === "+" &&
|
||||
((isEmptyString(node.left) && !isStringType(node.right)) ||
|
||||
(isEmptyString(node.right) && !isStringType(node.left)))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a node is appended with an empty string.
|
||||
* @param {ASTNode} node An AssignmentExpression node to check.
|
||||
* @returns {boolean} Whether or not the node is appended with an empty string.
|
||||
*/
|
||||
function isAppendEmptyString(node) {
|
||||
return node.operator === "+=" && isEmptyString(node.right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operand that is not an empty string from a flagged BinaryExpression.
|
||||
* @param {ASTNode} node The flagged BinaryExpression node to check.
|
||||
* @returns {ASTNode} The operand that is not an empty string from a flagged BinaryExpression.
|
||||
*/
|
||||
function getNonEmptyOperand(node) {
|
||||
return isEmptyString(node.left) ? node.right : node.left;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
hasSuggestions: true,
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Disallow shorthand type conversions",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-implicit-coercion",
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
boolean: {
|
||||
type: "boolean",
|
||||
},
|
||||
number: {
|
||||
type: "boolean",
|
||||
},
|
||||
string: {
|
||||
type: "boolean",
|
||||
},
|
||||
disallowTemplateShorthand: {
|
||||
type: "boolean",
|
||||
},
|
||||
allow: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: ALLOWABLE_OPERATORS,
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allow: [],
|
||||
boolean: true,
|
||||
disallowTemplateShorthand: false,
|
||||
number: true,
|
||||
string: true,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
implicitCoercion:
|
||||
"Unexpected implicit coercion encountered. Use `{{recommendation}}` instead.",
|
||||
useRecommendation: "Use `{{recommendation}}` instead.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [options] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Gets the source text of a node to be used as the argument of a
|
||||
* `Boolean()`, `Number()`, or `String()` call in a recommendation. A
|
||||
* `SequenceExpression` operand must be parenthesized, otherwise its commas
|
||||
* would be parsed as argument separators, which changes the evaluated
|
||||
* operand (for example `!!(a, b)` becomes `Boolean(a, b)`).
|
||||
* @param {ASTNode} node The operand node.
|
||||
* @returns {string} The source text, parenthesized if needed.
|
||||
*/
|
||||
function getOperandText(node) {
|
||||
const text = sourceCode.getText(node);
|
||||
|
||||
return node.type === "SequenceExpression" ? `(${text})` : text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error and autofixes the node
|
||||
* @param {ASTNode} node An ast node to report the error on.
|
||||
* @param {string} recommendation The recommended code for the issue
|
||||
* @param {bool} shouldSuggest Whether this report should offer a suggestion
|
||||
* @param {bool} shouldFix Whether this report should fix the node
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node, recommendation, shouldSuggest, shouldFix) {
|
||||
/**
|
||||
* Fix function
|
||||
* @param {RuleFixer} fixer The fixer to fix.
|
||||
* @returns {Fix} The fix object.
|
||||
*/
|
||||
function fix(fixer) {
|
||||
const tokenBefore = sourceCode.getTokenBefore(node);
|
||||
|
||||
if (
|
||||
tokenBefore?.range[1] === node.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(tokenBefore, recommendation)
|
||||
) {
|
||||
return fixer.replaceText(node, ` ${recommendation}`);
|
||||
}
|
||||
|
||||
return fixer.replaceText(node, recommendation);
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: "implicitCoercion",
|
||||
data: { recommendation },
|
||||
fix(fixer) {
|
||||
if (!shouldFix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fix(fixer);
|
||||
},
|
||||
suggest: [
|
||||
{
|
||||
messageId: "useRecommendation",
|
||||
data: { recommendation },
|
||||
fix(fixer) {
|
||||
if (shouldFix || !shouldSuggest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fix(fixer);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
UnaryExpression(node) {
|
||||
let operatorAllowed;
|
||||
|
||||
// !!foo
|
||||
operatorAllowed = options.allow.includes("!!");
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.boolean &&
|
||||
isDoubleLogicalNegating(node)
|
||||
) {
|
||||
const recommendation = `Boolean(${getOperandText(node.argument.argument)})`;
|
||||
const variable = astUtils.getVariableByName(
|
||||
sourceCode.getScope(node),
|
||||
"Boolean",
|
||||
);
|
||||
const booleanExists = variable?.identifiers.length === 0;
|
||||
|
||||
report(node, recommendation, true, booleanExists);
|
||||
}
|
||||
|
||||
// ~foo.indexOf(bar)
|
||||
operatorAllowed = options.allow.includes("~");
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.boolean &&
|
||||
isBinaryNegatingOfIndexOf(node)
|
||||
) {
|
||||
// `foo?.indexOf(bar) !== -1` will be true (== found) if the `foo` is nullish. So use `>= 0` in that case.
|
||||
const comparison =
|
||||
node.argument.type === "ChainExpression"
|
||||
? ">= 0"
|
||||
: "!== -1";
|
||||
const recommendation = `${sourceCode.getText(node.argument)} ${comparison}`;
|
||||
|
||||
report(node, recommendation, false, false);
|
||||
}
|
||||
|
||||
// +foo
|
||||
operatorAllowed = options.allow.includes("+");
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.number &&
|
||||
node.operator === "+" &&
|
||||
!isNumeric(node.argument)
|
||||
) {
|
||||
const recommendation = `Number(${getOperandText(node.argument)})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
}
|
||||
|
||||
// -(-foo)
|
||||
operatorAllowed = options.allow.includes("- -");
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.number &&
|
||||
node.operator === "-" &&
|
||||
node.argument.type === "UnaryExpression" &&
|
||||
node.argument.operator === "-" &&
|
||||
!isNumeric(node.argument.argument)
|
||||
) {
|
||||
const recommendation = `Number(${getOperandText(node.argument.argument)})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
}
|
||||
},
|
||||
|
||||
// Use `:exit` to prevent double reporting
|
||||
"BinaryExpression:exit"(node) {
|
||||
let operatorAllowed;
|
||||
|
||||
// 1 * foo
|
||||
operatorAllowed = options.allow.includes("*");
|
||||
const nonNumericOperand =
|
||||
!operatorAllowed &&
|
||||
options.number &&
|
||||
isMultiplyByOne(node) &&
|
||||
!isMultiplyByFractionOfOne(node, sourceCode) &&
|
||||
getNonNumericOperand(node);
|
||||
|
||||
if (nonNumericOperand) {
|
||||
const recommendation = `Number(${getOperandText(nonNumericOperand)})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
}
|
||||
|
||||
// foo - 0
|
||||
operatorAllowed = options.allow.includes("-");
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.number &&
|
||||
node.operator === "-" &&
|
||||
node.right.type === "Literal" &&
|
||||
node.right.value === 0 &&
|
||||
!isNumeric(node.left)
|
||||
) {
|
||||
const recommendation = `Number(${getOperandText(node.left)})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
}
|
||||
|
||||
// "" + foo
|
||||
operatorAllowed = options.allow.includes("+");
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.string &&
|
||||
isConcatWithEmptyString(node)
|
||||
) {
|
||||
const recommendation = `String(${getOperandText(getNonEmptyOperand(node))})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression(node) {
|
||||
// foo += ""
|
||||
const operatorAllowed = options.allow.includes("+");
|
||||
|
||||
if (
|
||||
!operatorAllowed &&
|
||||
options.string &&
|
||||
isAppendEmptyString(node)
|
||||
) {
|
||||
const code = sourceCode.getText(getNonEmptyOperand(node));
|
||||
const recommendation = `${code} = String(${code})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
}
|
||||
},
|
||||
|
||||
TemplateLiteral(node) {
|
||||
if (!options.disallowTemplateShorthand) {
|
||||
return;
|
||||
}
|
||||
|
||||
// tag`${foo}`
|
||||
if (node.parent.type === "TaggedTemplateExpression") {
|
||||
return;
|
||||
}
|
||||
|
||||
// `` or `${foo}${bar}`
|
||||
if (node.expressions.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// `prefix${foo}`
|
||||
if (node.quasis[0].value.cooked !== "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// `${foo}postfix`
|
||||
if (node.quasis[1].value.cooked !== "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the expression is already a string, then this isn't a coercion
|
||||
if (isStringType(node.expressions[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recommendation = `String(${getOperandText(node.expressions[0])})`;
|
||||
|
||||
report(node, recommendation, true, false);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"JSON.stringify@native": {
|
||||
"name": "JSON.stringify@native",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "libs",
|
||||
"hz": 21346.248036663714,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.02454137183514576,
|
||||
"rhz": 3.51787999536997,
|
||||
"sampleSize": 171
|
||||
},
|
||||
"fast-stable-stringify@a9f81e8": {
|
||||
"name": "fast-stable-stringify@a9f81e8",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "libs",
|
||||
"hz": 6067.929566886422,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.01636142507497922,
|
||||
"rhz": 1,
|
||||
"sampleSize": 149
|
||||
},
|
||||
"json-stable-stringify@1.0.1": {
|
||||
"name": "json-stable-stringify@1.0.1",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "libs",
|
||||
"hz": 4375.290115410294,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.015137049904064193,
|
||||
"rhz": 0.7210515658070408,
|
||||
"sampleSize": 141
|
||||
},
|
||||
"faster-stable-stringify@1.0.0": {
|
||||
"name": "faster-stable-stringify@1.0.0",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "libs",
|
||||
"hz": 4952.367339646239,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.01379783018004576,
|
||||
"rhz": 0.8161543875973826,
|
||||
"sampleSize": 142
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import { ModifierFlags, type Node, type NodeArray, type SourceFile, SyntaxKind } from "../../ast/index.ts";
|
||||
import { RemoteNodeBase, type SourceFileInfo } from "./node.infrastructure.ts";
|
||||
export declare class RemoteNodeList extends Array<RemoteNode> implements NodeArray<RemoteNode> {
|
||||
static get [Symbol.species](): ArrayConstructor;
|
||||
parent: RemoteNode;
|
||||
hasTrailingComma?: boolean;
|
||||
transformFlags: number;
|
||||
protected view: DataView;
|
||||
protected index: number;
|
||||
private _byteIndex;
|
||||
private _cursorIndex;
|
||||
private _cursorNodeIndex;
|
||||
get pos(): number;
|
||||
get end(): number;
|
||||
get next(): number;
|
||||
private get data();
|
||||
private sourceFile;
|
||||
constructor(view: DataView, index: number, parent: RemoteNode, sourceFile: SourceFileInfo, offsetNodes: number);
|
||||
get 0(): RemoteNode;
|
||||
get 1(): RemoteNode;
|
||||
get 2(): RemoteNode;
|
||||
get 3(): RemoteNode;
|
||||
get 4(): RemoteNode;
|
||||
get 5(): RemoteNode;
|
||||
get 6(): RemoteNode;
|
||||
get 7(): RemoteNode;
|
||||
get 8(): RemoteNode;
|
||||
get 9(): RemoteNode;
|
||||
get 10(): RemoteNode;
|
||||
get 11(): RemoteNode;
|
||||
get 12(): RemoteNode;
|
||||
get 13(): RemoteNode;
|
||||
get 14(): RemoteNode;
|
||||
get 15(): RemoteNode;
|
||||
[Symbol.iterator](): ArrayIterator<RemoteNode>;
|
||||
forEachNode<T>(visitNode: (node: RemoteNode) => T | undefined): T | undefined;
|
||||
at(index: number): RemoteNode;
|
||||
private getOrCreateChildAtNodeIndex;
|
||||
__print(): string;
|
||||
}
|
||||
export declare class RemoteNode extends RemoteNodeBase implements Node {
|
||||
protected static NODE_LEN: number;
|
||||
protected get sourceFile(): SourceFileInfo;
|
||||
protected _sourceFile: SourceFileInfo;
|
||||
get id(): string;
|
||||
constructor(view: DataView, index: number, parent: RemoteNode, sourceFile: SourceFileInfo, offsetNodes: number);
|
||||
forEachChild<T>(visitNode: (node: Node) => T, visitList?: (list: NodeArray<Node>) => T): T | undefined;
|
||||
get jsDoc(): readonly Node[] | undefined;
|
||||
getSourceFile(): SourceFile;
|
||||
getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number;
|
||||
getFullStart(): number;
|
||||
getEnd(): number;
|
||||
getWidth(sourceFile?: SourceFile): number;
|
||||
getFullWidth(): number;
|
||||
getLeadingTriviaWidth(sourceFile?: SourceFile): number;
|
||||
getFullText(sourceFile?: SourceFile): string;
|
||||
getText(sourceFile?: SourceFile): string;
|
||||
protected getString(index: number): string;
|
||||
private getOrCreateChildAtNodeIndex;
|
||||
private hasChildren;
|
||||
private getNamedChild;
|
||||
private getChildAtOrder;
|
||||
__print(): string;
|
||||
__printChildren(): string;
|
||||
__printSubtree(): string;
|
||||
get containsOnlyTriviaWhiteSpaces(): boolean;
|
||||
get isArrayType(): boolean;
|
||||
get isBracketed(): boolean;
|
||||
get isExportEquals(): boolean;
|
||||
get isNameFirst(): boolean;
|
||||
get isTypeOf(): boolean;
|
||||
get isTypeOnly(): boolean;
|
||||
get multiLine(): boolean;
|
||||
get keyword(): SyntaxKind | undefined;
|
||||
get keywordToken(): SyntaxKind | undefined;
|
||||
get operator(): SyntaxKind | undefined;
|
||||
get phaseModifier(): SyntaxKind | undefined;
|
||||
get token(): SyntaxKind | undefined;
|
||||
get templateFlags(): number | undefined;
|
||||
get tokenFlags(): number;
|
||||
get argument(): RemoteNode | undefined;
|
||||
get argumentExpression(): RemoteNode | undefined;
|
||||
get arguments(): RemoteNodeList | undefined;
|
||||
get assertsModifier(): RemoteNode | undefined;
|
||||
get asteriskToken(): RemoteNode | undefined;
|
||||
get attributes(): RemoteNode | RemoteNodeList | undefined;
|
||||
get awaitModifier(): RemoteNode | undefined;
|
||||
get block(): RemoteNode | undefined;
|
||||
get body(): RemoteNode | undefined;
|
||||
get caseBlock(): RemoteNode | undefined;
|
||||
get catchClause(): RemoteNode | undefined;
|
||||
get checkType(): RemoteNode | undefined;
|
||||
get children(): RemoteNode | RemoteNodeList | undefined;
|
||||
get className(): RemoteNode | undefined;
|
||||
get clauses(): RemoteNodeList | undefined;
|
||||
get closingElement(): RemoteNode | undefined;
|
||||
get closingFragment(): RemoteNode | undefined;
|
||||
get colonToken(): RemoteNode | undefined;
|
||||
get comment(): RemoteNodeList | undefined;
|
||||
get condition(): RemoteNode | undefined;
|
||||
get constraint(): RemoteNode | undefined;
|
||||
get declarationList(): RemoteNode | undefined;
|
||||
get declarations(): RemoteNodeList | undefined;
|
||||
get defaultType(): RemoteNode | undefined;
|
||||
get dotDotDotToken(): RemoteNode | undefined;
|
||||
get elements(): RemoteNodeList | undefined;
|
||||
get elementType(): RemoteNode | undefined;
|
||||
get elseStatement(): RemoteNode | undefined;
|
||||
get endOfFileToken(): RemoteNode | undefined;
|
||||
get equalsGreaterThanToken(): RemoteNode | undefined;
|
||||
get equalsToken(): RemoteNode | undefined;
|
||||
get exclamationToken(): RemoteNode | undefined;
|
||||
get exportClause(): RemoteNode | undefined;
|
||||
get expression(): RemoteNode | undefined;
|
||||
get exprName(): RemoteNode | undefined;
|
||||
get extendsType(): RemoteNode | undefined;
|
||||
get falseType(): RemoteNode | undefined;
|
||||
get finallyBlock(): RemoteNode | undefined;
|
||||
get head(): RemoteNode | undefined;
|
||||
get heritageClauses(): RemoteNodeList | undefined;
|
||||
get importClause(): RemoteNode | undefined;
|
||||
get incrementor(): RemoteNode | undefined;
|
||||
get indexType(): RemoteNode | undefined;
|
||||
get initializer(): RemoteNode | undefined;
|
||||
get jsdocPropertyTags(): RemoteNode | undefined;
|
||||
get label(): RemoteNode | undefined;
|
||||
get left(): RemoteNode | undefined;
|
||||
get literal(): RemoteNode | undefined;
|
||||
get members(): RemoteNodeList | undefined;
|
||||
get modifiers(): RemoteNodeList | undefined;
|
||||
get moduleReference(): RemoteNode | undefined;
|
||||
get moduleSpecifier(): RemoteNode | undefined;
|
||||
get name(): RemoteNode | undefined;
|
||||
get namedBindings(): RemoteNode | undefined;
|
||||
get nameExpression(): RemoteNode | undefined;
|
||||
get namespace(): RemoteNode | undefined;
|
||||
get nameType(): RemoteNode | undefined;
|
||||
get objectAssignmentInitializer(): RemoteNode | undefined;
|
||||
get objectType(): RemoteNode | undefined;
|
||||
get openingElement(): RemoteNode | undefined;
|
||||
get openingFragment(): RemoteNode | undefined;
|
||||
get operand(): RemoteNode | undefined;
|
||||
get operatorToken(): RemoteNode | undefined;
|
||||
get parameterName(): RemoteNode | undefined;
|
||||
get parameters(): RemoteNodeList | undefined;
|
||||
get postfixToken(): RemoteNode | undefined;
|
||||
get properties(): RemoteNodeList | undefined;
|
||||
get propertyName(): RemoteNode | undefined;
|
||||
get qualifier(): RemoteNode | undefined;
|
||||
get questionDotToken(): RemoteNode | undefined;
|
||||
get questionToken(): RemoteNode | undefined;
|
||||
get readonlyToken(): RemoteNode | undefined;
|
||||
get right(): RemoteNode | undefined;
|
||||
get statement(): RemoteNode | undefined;
|
||||
get statements(): RemoteNodeList | undefined;
|
||||
get tag(): RemoteNode | undefined;
|
||||
get tagName(): RemoteNode | undefined;
|
||||
get tags(): RemoteNodeList | undefined;
|
||||
get template(): RemoteNode | undefined;
|
||||
get templateSpans(): RemoteNodeList | undefined;
|
||||
get thenStatement(): RemoteNode | undefined;
|
||||
get thisArg(): RemoteNode | undefined;
|
||||
get trueType(): RemoteNode | undefined;
|
||||
get tryBlock(): RemoteNode | undefined;
|
||||
get tupleNameSource(): RemoteNode | undefined;
|
||||
get type(): RemoteNode | undefined;
|
||||
get typeArguments(): RemoteNodeList | undefined;
|
||||
get typeExpression(): RemoteNode | undefined;
|
||||
get typeName(): RemoteNode | undefined;
|
||||
get typeParameter(): RemoteNode | undefined;
|
||||
get typeParameters(): RemoteNodeList | undefined;
|
||||
get types(): RemoteNodeList | undefined;
|
||||
get value(): RemoteNode | undefined;
|
||||
get variableDeclaration(): RemoteNode | undefined;
|
||||
get whenFalse(): RemoteNode | undefined;
|
||||
get whenTrue(): RemoteNode | undefined;
|
||||
get text(): string | undefined;
|
||||
get rawText(): string | undefined;
|
||||
get flags(): number;
|
||||
get modifierFlags(): ModifierFlags;
|
||||
}
|
||||
//# sourceMappingURL=node.generated.d.ts.map
|
||||
@@ -0,0 +1,32 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es6 = void 0;
|
||||
const es5_1 = require("./es5");
|
||||
const es2015_collection_1 = require("./es2015.collection");
|
||||
const es2015_core_1 = require("./es2015.core");
|
||||
const es2015_generator_1 = require("./es2015.generator");
|
||||
const es2015_iterable_1 = require("./es2015.iterable");
|
||||
const es2015_promise_1 = require("./es2015.promise");
|
||||
const es2015_proxy_1 = require("./es2015.proxy");
|
||||
const es2015_reflect_1 = require("./es2015.reflect");
|
||||
const es2015_symbol_1 = require("./es2015.symbol");
|
||||
const es2015_symbol_wellknown_1 = require("./es2015.symbol.wellknown");
|
||||
exports.es6 = {
|
||||
libs: [
|
||||
es5_1.es5,
|
||||
es2015_core_1.es2015_core,
|
||||
es2015_collection_1.es2015_collection,
|
||||
es2015_iterable_1.es2015_iterable,
|
||||
es2015_generator_1.es2015_generator,
|
||||
es2015_promise_1.es2015_promise,
|
||||
es2015_proxy_1.es2015_proxy,
|
||||
es2015_reflect_1.es2015_reflect,
|
||||
es2015_symbol_1.es2015_symbol,
|
||||
es2015_symbol_wellknown_1.es2015_symbol_wellknown,
|
||||
],
|
||||
variables: [],
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { parse, safeParse, parseAsync, safeParseAsync, encode, decode, encodeAsync, decodeAsync, safeEncode, safeDecode, safeEncodeAsync, safeDecodeAsync, } from "../core/index.js";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2016_full = void 0;
|
||||
const dom_1 = require("./dom");
|
||||
const dom_iterable_1 = require("./dom.iterable");
|
||||
const es2016_1 = require("./es2016");
|
||||
const scripthost_1 = require("./scripthost");
|
||||
const webworker_importscripts_1 = require("./webworker.importscripts");
|
||||
exports.es2016_full = {
|
||||
libs: [es2016_1.es2016, dom_1.dom, webworker_importscripts_1.webworker_importscripts, scripthost_1.scripthost, dom_iterable_1.dom_iterable],
|
||||
variables: [],
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "wrappy",
|
||||
"version": "1.0.2",
|
||||
"description": "Callback wrapping utility",
|
||||
"main": "wrappy.js",
|
||||
"files": [
|
||||
"wrappy.js"
|
||||
],
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"tap": "^2.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap --coverage test/*.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/npm/wrappy"
|
||||
},
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/npm/wrappy/issues"
|
||||
},
|
||||
"homepage": "https://github.com/npm/wrappy"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
export type AllowInterfaces = 'always' | 'never' | 'with-single-extends';
|
||||
export type AllowObjectTypes = 'always' | 'never';
|
||||
export type Options = [
|
||||
{
|
||||
allowInterfaces?: AllowInterfaces;
|
||||
allowObjectTypes?: AllowObjectTypes;
|
||||
allowWithName?: string;
|
||||
}
|
||||
];
|
||||
export type MessageIds = 'noEmptyInterface' | 'noEmptyInterfaceWithSuper' | 'noEmptyObject' | 'replaceEmptyInterface' | 'replaceEmptyInterfaceWithSuper' | 'replaceEmptyObjectType';
|
||||
declare const _default: TSESLint.RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "fast-stable-stringify",
|
||||
"version": "1.0.0",
|
||||
"description": "Deterministic stringification for when performance matters",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/.bin/karma start",
|
||||
"travis": "./node_modules/.bin/karma start ./karma.conf.travis.js",
|
||||
"table": "node ./cli/index.js results/libs/*.json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nickyout/fast-stable-stringify.git"
|
||||
},
|
||||
"keywords": [
|
||||
"JSON",
|
||||
"stable",
|
||||
"deterministic",
|
||||
"stringify",
|
||||
"fast"
|
||||
],
|
||||
"author": "Nicky Out",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nickyout/fast-stable-stringify/issues"
|
||||
},
|
||||
"homepage": "https://github.com/nickyout/fast-stable-stringify#readme",
|
||||
"devDependencies": {
|
||||
"faster-stable-stringify": "^1.0.0",
|
||||
"fs-extra": "^4.0.1",
|
||||
"glob": "^7.1.2",
|
||||
"json-stable-stringify": "^1.0.0",
|
||||
"karma": "^1.7.1",
|
||||
"karma-benchmark": "^0.7.1",
|
||||
"karma-benchmark-reporter": "git+https://github.com/nickyout/karma-benchmark-reporter.git#4b570c9",
|
||||
"karma-firefox-launcher": "^1.0.1",
|
||||
"karma-sauce-launcher": "^1.2.0",
|
||||
"karma-webpack": "^2.0.4",
|
||||
"markdown-table": "^1.1.1",
|
||||
"minimist": "^1.2.0",
|
||||
"split": "^1.0.1",
|
||||
"webpack": "^3.5.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import defineProperty from "./defineProperty.js";
|
||||
function ownKeys(e, r) {
|
||||
var t = Object.keys(e);
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
var o = Object.getOwnPropertySymbols(e);
|
||||
r && (o = o.filter(function (r) {
|
||||
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
||||
})), t.push.apply(t, o);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
function _objectSpread2(e) {
|
||||
for (var r = 1; r < arguments.length; r++) {
|
||||
var t = null != arguments[r] ? arguments[r] : {};
|
||||
r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
|
||||
defineProperty(e, r, t[r]);
|
||||
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
|
||||
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
||||
});
|
||||
}
|
||||
return e;
|
||||
}
|
||||
export { _objectSpread2 as default };
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"JSON.stringify@native": {
|
||||
"name": "JSON.stringify@native",
|
||||
"browser": "Safari 10.0.1 (Mac OS X 10.12.1)",
|
||||
"suite": "libs",
|
||||
"hz": 20880.94942943559,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.034431069225489566,
|
||||
"rhz": 6.0500575134602785,
|
||||
"sampleSize": 171
|
||||
},
|
||||
"fast-stable-stringify@a9f81e8": {
|
||||
"name": "fast-stable-stringify@a9f81e8",
|
||||
"browser": "Safari 10.0.1 (Mac OS X 10.12.1)",
|
||||
"suite": "libs",
|
||||
"hz": 3451.36379001014,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.030283351076228322,
|
||||
"rhz": 1,
|
||||
"sampleSize": 136
|
||||
},
|
||||
"json-stable-stringify@1.0.1": {
|
||||
"name": "json-stable-stringify@1.0.1",
|
||||
"browser": "Safari 10.0.1 (Mac OS X 10.12.1)",
|
||||
"suite": "libs",
|
||||
"hz": 2888.328126218209,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.021217425635208887,
|
||||
"rhz": 0.8368657440801751,
|
||||
"sampleSize": 171
|
||||
},
|
||||
"faster-stable-stringify@1.0.0": {
|
||||
"name": "faster-stable-stringify@1.0.0",
|
||||
"browser": "Safari 10.0.1 (Mac OS X 10.12.1)",
|
||||
"suite": "libs",
|
||||
"hz": 3063.3319729455015,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.029382106163122576,
|
||||
"rhz": 0.887571452714494,
|
||||
"sampleSize": 164
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import * as espree from "./espree.js";
|
||||
export = espree;
|
||||
//# sourceMappingURL=espree.d.cts.map
|
||||
@@ -0,0 +1,605 @@
|
||||
/**
|
||||
* Utils for modular division and fields.
|
||||
* Field over 11 is a finite (Galois) field is integer number operations `mod 11`.
|
||||
* There is no division: it is replaced by modular multiplicative inverse.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import {
|
||||
_validateObject,
|
||||
anumber,
|
||||
bitMask,
|
||||
bytesToNumberBE,
|
||||
bytesToNumberLE,
|
||||
ensureBytes,
|
||||
numberToBytesBE,
|
||||
numberToBytesLE,
|
||||
} from '../utils.ts';
|
||||
|
||||
// prettier-ignore
|
||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
||||
// prettier-ignore
|
||||
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _7n = /* @__PURE__ */ BigInt(7);
|
||||
// prettier-ignore
|
||||
const _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
|
||||
|
||||
// Calculates a modulo b
|
||||
export function mod(a: bigint, b: bigint): bigint {
|
||||
const result = a % b;
|
||||
return result >= _0n ? result : b + result;
|
||||
}
|
||||
/**
|
||||
* Efficiently raise num to power and do modular division.
|
||||
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||||
* @example
|
||||
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
||||
*/
|
||||
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
||||
return FpPow(Field(modulo), num, power);
|
||||
}
|
||||
|
||||
/** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
|
||||
export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
||||
let res = x;
|
||||
while (power-- > _0n) {
|
||||
res *= res;
|
||||
res %= modulo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverses number over modulo.
|
||||
* Implemented using [Euclidean GCD](https://brilliant.org/wiki/extended-euclidean-algorithm/).
|
||||
*/
|
||||
export function invert(number: bigint, modulo: bigint): bigint {
|
||||
if (number === _0n) throw new Error('invert: expected non-zero number');
|
||||
if (modulo <= _0n) throw new Error('invert: expected positive modulus, got ' + modulo);
|
||||
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
||||
let a = mod(number, modulo);
|
||||
let b = modulo;
|
||||
// prettier-ignore
|
||||
let x = _0n, y = _1n, u = _1n, v = _0n;
|
||||
while (a !== _0n) {
|
||||
// JIT applies optimization if those two lines follow each other
|
||||
const q = b / a;
|
||||
const r = b % a;
|
||||
const m = x - u * q;
|
||||
const n = y - v * q;
|
||||
// prettier-ignore
|
||||
b = a, a = r, x = u, y = v, u = m, v = n;
|
||||
}
|
||||
const gcd = b;
|
||||
if (gcd !== _1n) throw new Error('invert: does not exist');
|
||||
return mod(x, modulo);
|
||||
}
|
||||
|
||||
function assertIsSquare<T>(Fp: IField<T>, root: T, n: T): void {
|
||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||
}
|
||||
|
||||
// Not all roots are possible! Example which will throw:
|
||||
// const NUM =
|
||||
// n = 72057594037927816n;
|
||||
// Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
|
||||
function sqrt3mod4<T>(Fp: IField<T>, n: T) {
|
||||
const p1div4 = (Fp.ORDER + _1n) / _4n;
|
||||
const root = Fp.pow(n, p1div4);
|
||||
assertIsSquare(Fp, root, n);
|
||||
return root;
|
||||
}
|
||||
|
||||
function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
||||
const p5div8 = (Fp.ORDER - _5n) / _8n;
|
||||
const n2 = Fp.mul(n, _2n);
|
||||
const v = Fp.pow(n2, p5div8);
|
||||
const nv = Fp.mul(n, v);
|
||||
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
||||
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
||||
assertIsSquare(Fp, root, n);
|
||||
return root;
|
||||
}
|
||||
|
||||
// Based on RFC9380, Kong algorithm
|
||||
// prettier-ignore
|
||||
function sqrt9mod16(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
||||
const Fp_ = Field(P);
|
||||
const tn = tonelliShanks(P);
|
||||
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE));// 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
||||
const c2 = tn(Fp_, c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
||||
const c3 = tn(Fp_, Fp_.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
||||
const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
||||
return <T>(Fp: IField<T>, n: T) => {
|
||||
let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
|
||||
let tv2 = Fp.mul(tv1, c1); // 2. tv2 = c1 * tv1
|
||||
const tv3 = Fp.mul(tv1, c2); // 3. tv3 = c2 * tv1
|
||||
const tv4 = Fp.mul(tv1, c3); // 4. tv4 = c3 * tv1
|
||||
const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
|
||||
const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
|
||||
tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
||||
tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
||||
const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
|
||||
const root = Fp.cmov(tv1, tv2, e3);// 10. z = CMOV(tv1, tv2, e3) # Select sqrt from tv1 & tv2
|
||||
assertIsSquare(Fp, root, n);
|
||||
return root;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tonelli-Shanks square root search algorithm.
|
||||
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
||||
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
||||
* @param P field order
|
||||
* @returns function that takes field Fp (created from P) and number n
|
||||
*/
|
||||
export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
||||
// Initialization (precomputation).
|
||||
// Caching initialization could boost perf by 7%.
|
||||
if (P < _3n) throw new Error('sqrt is not defined for small field');
|
||||
// Factor P - 1 = Q * 2^S, where Q is odd
|
||||
let Q = P - _1n;
|
||||
let S = 0;
|
||||
while (Q % _2n === _0n) {
|
||||
Q /= _2n;
|
||||
S++;
|
||||
}
|
||||
|
||||
// Find the first quadratic non-residue Z >= 2
|
||||
let Z = _2n;
|
||||
const _Fp = Field(P);
|
||||
while (FpLegendre(_Fp, Z) === 1) {
|
||||
// Basic primality test for P. After x iterations, chance of
|
||||
// not finding quadratic non-residue is 2^x, so 2^1000.
|
||||
if (Z++ > 1000) throw new Error('Cannot find square root: probably non-prime P');
|
||||
}
|
||||
// Fast-path; usually done before Z, but we do "primality test".
|
||||
if (S === 1) return sqrt3mod4;
|
||||
|
||||
// Slow-path
|
||||
// TODO: test on Fp2 and others
|
||||
let cc = _Fp.pow(Z, Q); // c = z^Q
|
||||
const Q1div2 = (Q + _1n) / _2n;
|
||||
return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
|
||||
if (Fp.is0(n)) return n;
|
||||
// Check if n is a quadratic residue using Legendre symbol
|
||||
if (FpLegendre(Fp, n) !== 1) throw new Error('Cannot find square root');
|
||||
|
||||
// Initialize variables for the main loop
|
||||
let M = S;
|
||||
let c = Fp.mul(Fp.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
|
||||
let t = Fp.pow(n, Q); // t = n^Q, first guess at the fudge factor
|
||||
let R = Fp.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
|
||||
|
||||
// Main loop
|
||||
// while t != 1
|
||||
while (!Fp.eql(t, Fp.ONE)) {
|
||||
if (Fp.is0(t)) return Fp.ZERO; // if t=0 return R=0
|
||||
let i = 1;
|
||||
|
||||
// Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
|
||||
let t_tmp = Fp.sqr(t); // t^(2^1)
|
||||
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
||||
i++;
|
||||
t_tmp = Fp.sqr(t_tmp); // t^(2^2)...
|
||||
if (i === M) throw new Error('Cannot find square root');
|
||||
}
|
||||
|
||||
// Calculate the exponent for b: 2^(M - i - 1)
|
||||
const exponent = _1n << BigInt(M - i - 1); // bigint is important
|
||||
const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
|
||||
|
||||
// Update variables
|
||||
M = i;
|
||||
c = Fp.sqr(b); // c = b^2
|
||||
t = Fp.mul(t, c); // t = (t * b^2)
|
||||
R = Fp.mul(R, b); // R = R*b
|
||||
}
|
||||
return R;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Square root for a finite field. Will try optimized versions first:
|
||||
*
|
||||
* 1. P ≡ 3 (mod 4)
|
||||
* 2. P ≡ 5 (mod 8)
|
||||
* 3. P ≡ 9 (mod 16)
|
||||
* 4. Tonelli-Shanks algorithm
|
||||
*
|
||||
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
||||
* For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
||||
*/
|
||||
export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
||||
// P ≡ 3 (mod 4) => √n = n^((P+1)/4)
|
||||
if (P % _4n === _3n) return sqrt3mod4;
|
||||
// P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
|
||||
if (P % _8n === _5n) return sqrt5mod8;
|
||||
// P ≡ 9 (mod 16) => Kong algorithm, page 11 of https://eprint.iacr.org/2012/685.pdf (algorithm 4)
|
||||
if (P % _16n === _9n) return sqrt9mod16(P);
|
||||
// Tonelli-Shanks algorithm
|
||||
return tonelliShanks(P);
|
||||
}
|
||||
|
||||
// Little-endian check for first LE bit (last BE bit);
|
||||
export const isNegativeLE = (num: bigint, modulo: bigint): boolean =>
|
||||
(mod(num, modulo) & _1n) === _1n;
|
||||
|
||||
/** Field is not always over prime: for example, Fp2 has ORDER(q)=p^m. */
|
||||
export interface IField<T> {
|
||||
ORDER: bigint;
|
||||
isLE: boolean;
|
||||
BYTES: number;
|
||||
BITS: number;
|
||||
MASK: bigint;
|
||||
ZERO: T;
|
||||
ONE: T;
|
||||
// 1-arg
|
||||
create: (num: T) => T;
|
||||
isValid: (num: T) => boolean;
|
||||
is0: (num: T) => boolean;
|
||||
isValidNot0: (num: T) => boolean;
|
||||
neg(num: T): T;
|
||||
inv(num: T): T;
|
||||
sqrt(num: T): T;
|
||||
sqr(num: T): T;
|
||||
// 2-args
|
||||
eql(lhs: T, rhs: T): boolean;
|
||||
add(lhs: T, rhs: T): T;
|
||||
sub(lhs: T, rhs: T): T;
|
||||
mul(lhs: T, rhs: T | bigint): T;
|
||||
pow(lhs: T, power: bigint): T;
|
||||
div(lhs: T, rhs: T | bigint): T;
|
||||
// N for NonNormalized (for now)
|
||||
addN(lhs: T, rhs: T): T;
|
||||
subN(lhs: T, rhs: T): T;
|
||||
mulN(lhs: T, rhs: T | bigint): T;
|
||||
sqrN(num: T): T;
|
||||
|
||||
// Optional
|
||||
// Should be same as sgn0 function in
|
||||
// [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
|
||||
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
||||
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
||||
allowedLengths?: number[];
|
||||
// legendre?(num: T): T;
|
||||
invertBatch: (lst: T[]) => T[];
|
||||
toBytes(num: T): Uint8Array;
|
||||
fromBytes(bytes: Uint8Array, skipValidation?: boolean): T;
|
||||
// If c is False, CMOV returns a, otherwise it returns b.
|
||||
cmov(a: T, b: T, c: boolean): T;
|
||||
}
|
||||
// prettier-ignore
|
||||
const FIELD_FIELDS = [
|
||||
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
||||
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
||||
'addN', 'subN', 'mulN', 'sqrN'
|
||||
] as const;
|
||||
export function validateField<T>(field: IField<T>): IField<T> {
|
||||
const initial = {
|
||||
ORDER: 'bigint',
|
||||
MASK: 'bigint',
|
||||
BYTES: 'number',
|
||||
BITS: 'number',
|
||||
} as Record<string, string>;
|
||||
const opts = FIELD_FIELDS.reduce((map, val: string) => {
|
||||
map[val] = 'function';
|
||||
return map;
|
||||
}, initial);
|
||||
_validateObject(field, opts);
|
||||
// const max = 16384;
|
||||
// if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
|
||||
// if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
|
||||
return field;
|
||||
}
|
||||
|
||||
// Generic field functions
|
||||
|
||||
/**
|
||||
* Same as `pow` but for Fp: non-constant-time.
|
||||
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||||
*/
|
||||
export function FpPow<T>(Fp: IField<T>, num: T, power: bigint): T {
|
||||
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
||||
if (power === _0n) return Fp.ONE;
|
||||
if (power === _1n) return num;
|
||||
let p = Fp.ONE;
|
||||
let d = num;
|
||||
while (power > _0n) {
|
||||
if (power & _1n) p = Fp.mul(p, d);
|
||||
d = Fp.sqr(d);
|
||||
power >>= _1n;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently invert an array of Field elements.
|
||||
* Exception-free. Will return `undefined` for 0 elements.
|
||||
* @param passZero map 0 to 0 (instead of undefined)
|
||||
*/
|
||||
export function FpInvertBatch<T>(Fp: IField<T>, nums: T[], passZero = false): T[] {
|
||||
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined);
|
||||
// Walk from first to last, multiply them by each other MOD p
|
||||
const multipliedAcc = nums.reduce((acc, num, i) => {
|
||||
if (Fp.is0(num)) return acc;
|
||||
inverted[i] = acc;
|
||||
return Fp.mul(acc, num);
|
||||
}, Fp.ONE);
|
||||
// Invert last element
|
||||
const invertedAcc = Fp.inv(multipliedAcc);
|
||||
// Walk from last to first, multiply them by inverted each other MOD p
|
||||
nums.reduceRight((acc, num, i) => {
|
||||
if (Fp.is0(num)) return acc;
|
||||
inverted[i] = Fp.mul(acc, inverted[i]);
|
||||
return Fp.mul(acc, num);
|
||||
}, invertedAcc);
|
||||
return inverted;
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
export function FpDiv<T>(Fp: IField<T>, lhs: T, rhs: T | bigint): T {
|
||||
return Fp.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, Fp.ORDER) : Fp.inv(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Legendre symbol.
|
||||
* Legendre constant is used to calculate Legendre symbol (a | p)
|
||||
* which denotes the value of a^((p-1)/2) (mod p).
|
||||
*
|
||||
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
||||
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
||||
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
||||
*/
|
||||
export function FpLegendre<T>(Fp: IField<T>, n: T): -1 | 0 | 1 {
|
||||
// We can use 3rd argument as optional cache of this value
|
||||
// but seems unneeded for now. The operation is very fast.
|
||||
const p1mod2 = (Fp.ORDER - _1n) / _2n;
|
||||
const powered = Fp.pow(n, p1mod2);
|
||||
const yes = Fp.eql(powered, Fp.ONE);
|
||||
const zero = Fp.eql(powered, Fp.ZERO);
|
||||
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
|
||||
if (!yes && !zero && !no) throw new Error('invalid Legendre symbol result');
|
||||
return yes ? 1 : zero ? 0 : -1;
|
||||
}
|
||||
|
||||
// This function returns True whenever the value x is a square in the field F.
|
||||
export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
|
||||
const l = FpLegendre(Fp, n);
|
||||
return l === 1;
|
||||
}
|
||||
|
||||
export type NLength = { nByteLength: number; nBitLength: number };
|
||||
// CURVE.n lengths
|
||||
export function nLength(n: bigint, nBitLength?: number): NLength {
|
||||
// Bit size, byte size of CURVE.n
|
||||
if (nBitLength !== undefined) anumber(nBitLength);
|
||||
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
||||
const nByteLength = Math.ceil(_nBitLength / 8);
|
||||
return { nBitLength: _nBitLength, nByteLength };
|
||||
}
|
||||
|
||||
type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
||||
type SqrtFn = (n: bigint) => bigint;
|
||||
type FieldOpts = Partial<{
|
||||
sqrt: SqrtFn;
|
||||
isLE: boolean;
|
||||
BITS: number;
|
||||
modFromBytes: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
||||
allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes)
|
||||
}>;
|
||||
/**
|
||||
* Creates a finite field. Major performance optimizations:
|
||||
* * 1. Denormalized operations like mulN instead of mul.
|
||||
* * 2. Identical object shape: never add or remove keys.
|
||||
* * 3. `Object.freeze`.
|
||||
* Fragile: always run a benchmark on a change.
|
||||
* Security note: operations don't check 'isValid' for all elements for performance reasons,
|
||||
* it is caller responsibility to check this.
|
||||
* This is low-level code, please make sure you know what you're doing.
|
||||
*
|
||||
* Note about field properties:
|
||||
* * CHARACTERISTIC p = prime number, number of elements in main subgroup.
|
||||
* * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
|
||||
*
|
||||
* @param ORDER field order, probably prime, or could be composite
|
||||
* @param bitLen how many bits the field consumes
|
||||
* @param isLE (default: false) if encoding / decoding should be in little-endian
|
||||
* @param redef optional faster redefinitions of sqrt and other methods
|
||||
*/
|
||||
export function Field(
|
||||
ORDER: bigint,
|
||||
bitLenOrOpts?: number | FieldOpts, // TODO: use opts only in v2?
|
||||
isLE = false,
|
||||
opts: { sqrt?: SqrtFn } = {}
|
||||
): Readonly<FpField> {
|
||||
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
||||
let _nbitLength: number | undefined = undefined;
|
||||
let _sqrt: SqrtFn | undefined = undefined;
|
||||
let modFromBytes: boolean = false;
|
||||
let allowedLengths: undefined | readonly number[] = undefined;
|
||||
if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
|
||||
if (opts.sqrt || isLE) throw new Error('cannot specify opts in two arguments');
|
||||
const _opts = bitLenOrOpts;
|
||||
if (_opts.BITS) _nbitLength = _opts.BITS;
|
||||
if (_opts.sqrt) _sqrt = _opts.sqrt;
|
||||
if (typeof _opts.isLE === 'boolean') isLE = _opts.isLE;
|
||||
if (typeof _opts.modFromBytes === 'boolean') modFromBytes = _opts.modFromBytes;
|
||||
allowedLengths = _opts.allowedLengths;
|
||||
} else {
|
||||
if (typeof bitLenOrOpts === 'number') _nbitLength = bitLenOrOpts;
|
||||
if (opts.sqrt) _sqrt = opts.sqrt;
|
||||
}
|
||||
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
|
||||
if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
||||
let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
|
||||
const f: Readonly<FpField> = Object.freeze({
|
||||
ORDER,
|
||||
isLE,
|
||||
BITS,
|
||||
BYTES,
|
||||
MASK: bitMask(BITS),
|
||||
ZERO: _0n,
|
||||
ONE: _1n,
|
||||
allowedLengths: allowedLengths,
|
||||
create: (num) => mod(num, ORDER),
|
||||
isValid: (num) => {
|
||||
if (typeof num !== 'bigint')
|
||||
throw new Error('invalid field element: expected bigint, got ' + typeof num);
|
||||
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
||||
},
|
||||
is0: (num) => num === _0n,
|
||||
// is valid and invertible
|
||||
isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
|
||||
isOdd: (num) => (num & _1n) === _1n,
|
||||
neg: (num) => mod(-num, ORDER),
|
||||
eql: (lhs, rhs) => lhs === rhs,
|
||||
|
||||
sqr: (num) => mod(num * num, ORDER),
|
||||
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
||||
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
||||
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
||||
pow: (num, power) => FpPow(f, num, power),
|
||||
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
||||
|
||||
// Same as above, but doesn't normalize
|
||||
sqrN: (num) => num * num,
|
||||
addN: (lhs, rhs) => lhs + rhs,
|
||||
subN: (lhs, rhs) => lhs - rhs,
|
||||
mulN: (lhs, rhs) => lhs * rhs,
|
||||
|
||||
inv: (num) => invert(num, ORDER),
|
||||
sqrt:
|
||||
_sqrt ||
|
||||
((n) => {
|
||||
if (!sqrtP) sqrtP = FpSqrt(ORDER);
|
||||
return sqrtP(f, n);
|
||||
}),
|
||||
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
||||
fromBytes: (bytes, skipValidation = true) => {
|
||||
if (allowedLengths) {
|
||||
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
||||
throw new Error(
|
||||
'Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length
|
||||
);
|
||||
}
|
||||
const padded = new Uint8Array(BYTES);
|
||||
// isLE add 0 to right, !isLE to the left.
|
||||
padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
|
||||
bytes = padded;
|
||||
}
|
||||
if (bytes.length !== BYTES)
|
||||
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
||||
let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
||||
if (modFromBytes) scalar = mod(scalar, ORDER);
|
||||
if (!skipValidation)
|
||||
if (!f.isValid(scalar)) throw new Error('invalid field element: outside of range 0..ORDER');
|
||||
// NOTE: we don't validate scalar here, please use isValid. This done such way because some
|
||||
// protocol may allow non-reduced scalar that reduced later or changed some other way.
|
||||
return scalar;
|
||||
},
|
||||
// TODO: we don't need it here, move out to separate fn
|
||||
invertBatch: (lst) => FpInvertBatch(f, lst),
|
||||
// We can't move this out because Fp6, Fp12 implement it
|
||||
// and it's unclear what to return in there.
|
||||
cmov: (a, b, c) => (c ? b : a),
|
||||
} as FpField);
|
||||
return Object.freeze(f);
|
||||
}
|
||||
|
||||
// Generic random scalar, we can do same for other fields if via Fp2.mul(Fp2.ONE, Fp2.random)?
|
||||
// This allows unsafe methods like ignore bias or zero. These unsafe, but often used in different protocols (if deterministic RNG).
|
||||
// which mean we cannot force this via opts.
|
||||
// Not sure what to do with randomBytes, we can accept it inside opts if wanted.
|
||||
// Probably need to export getMinHashLength somewhere?
|
||||
// random(bytes?: Uint8Array, unsafeAllowZero = false, unsafeAllowBias = false) {
|
||||
// const LEN = !unsafeAllowBias ? getMinHashLength(ORDER) : BYTES;
|
||||
// if (bytes === undefined) bytes = randomBytes(LEN); // _opts.randomBytes?
|
||||
// const num = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
||||
// // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
||||
// const reduced = unsafeAllowZero ? mod(num, ORDER) : mod(num, ORDER - _1n) + _1n;
|
||||
// return reduced;
|
||||
// },
|
||||
|
||||
export function FpSqrtOdd<T>(Fp: IField<T>, elm: T): T {
|
||||
if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
|
||||
const root = Fp.sqrt(elm);
|
||||
return Fp.isOdd(root) ? root : Fp.neg(root);
|
||||
}
|
||||
|
||||
export function FpSqrtEven<T>(Fp: IField<T>, elm: T): T {
|
||||
if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
|
||||
const root = Fp.sqrt(elm);
|
||||
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Constant-time" private key generation utility.
|
||||
* Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
|
||||
* Which makes it slightly more biased, less secure.
|
||||
* @deprecated use `mapKeyToField` instead
|
||||
*/
|
||||
export function hashToPrivateScalar(
|
||||
hash: string | Uint8Array,
|
||||
groupOrder: bigint,
|
||||
isLE = false
|
||||
): bigint {
|
||||
hash = ensureBytes('privateHash', hash);
|
||||
const hashLen = hash.length;
|
||||
const minLen = nLength(groupOrder).nByteLength + 8;
|
||||
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
||||
throw new Error(
|
||||
'hashToPrivateScalar: expected ' + minLen + '-1024 bytes of input, got ' + hashLen
|
||||
);
|
||||
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
||||
return mod(num, groupOrder - _1n) + _1n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total number of bytes consumed by the field element.
|
||||
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
||||
* @param fieldOrder number of field elements, usually CURVE.n
|
||||
* @returns byte length of field
|
||||
*/
|
||||
export function getFieldBytesLength(fieldOrder: bigint): number {
|
||||
if (typeof fieldOrder !== 'bigint') throw new Error('field order must be bigint');
|
||||
const bitLength = fieldOrder.toString(2).length;
|
||||
return Math.ceil(bitLength / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns minimal amount of bytes that can be safely reduced
|
||||
* by field order.
|
||||
* Should be 2^-128 for 128-bit curve such as P256.
|
||||
* @param fieldOrder number of field elements, usually CURVE.n
|
||||
* @returns byte length of target hash
|
||||
*/
|
||||
export function getMinHashLength(fieldOrder: bigint): number {
|
||||
const length = getFieldBytesLength(fieldOrder);
|
||||
return length + Math.ceil(length / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Constant-time" private key generation utility.
|
||||
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
||||
* and convert them into private scalar, with the modulo bias being negligible.
|
||||
* Needs at least 48 bytes of input for 32-byte private key.
|
||||
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
||||
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
||||
* RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
|
||||
* @param hash hash output from SHA3 or a similar function
|
||||
* @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
|
||||
* @param isLE interpret hash bytes as LE num
|
||||
* @returns valid private scalar
|
||||
*/
|
||||
export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {
|
||||
const len = key.length;
|
||||
const fieldLen = getFieldBytesLength(fieldOrder);
|
||||
const minLen = getMinHashLength(fieldOrder);
|
||||
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
||||
if (len < 16 || len < minLen || len > 1024)
|
||||
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
||||
const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
||||
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
||||
const reduced = mod(num, fieldOrder - _1n) + _1n;
|
||||
return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isUnsafeAssignment = isUnsafeAssignment;
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const tsutils = __importStar(require("ts-api-utils"));
|
||||
const predicates_1 = require("./predicates");
|
||||
/**
|
||||
* Does a simple check to see if there is an any being assigned to a non-any type.
|
||||
*
|
||||
* This also checks generic positions to ensure there's no unsafe sub-assignments.
|
||||
* Note: in the case of generic positions, it makes the assumption that the two types are the same.
|
||||
*
|
||||
* @example See tests for examples
|
||||
*
|
||||
* @returns false if it's safe, or an object with the two types if it's unsafe
|
||||
*/
|
||||
function isUnsafeAssignment(type, receiver, checker, senderNode) {
|
||||
return isUnsafeAssignmentWorker(type, receiver, checker, senderNode, new Map());
|
||||
}
|
||||
function isUnsafeAssignmentWorker(type, receiver, checker, senderNode, visited) {
|
||||
if ((0, predicates_1.isTypeAnyType)(type)) {
|
||||
// Allow assignment of any ==> unknown.
|
||||
if ((0, predicates_1.isTypeUnknownType)(receiver)) {
|
||||
return false;
|
||||
}
|
||||
if (!(0, predicates_1.isTypeAnyType)(receiver)) {
|
||||
return { receiver, sender: type };
|
||||
}
|
||||
}
|
||||
const typeAlreadyVisited = visited.get(type);
|
||||
if (typeAlreadyVisited) {
|
||||
if (typeAlreadyVisited.has(receiver)) {
|
||||
return false;
|
||||
}
|
||||
typeAlreadyVisited.add(receiver);
|
||||
}
|
||||
else {
|
||||
visited.set(type, new Set([receiver]));
|
||||
}
|
||||
if (tsutils.isTypeReference(type) && tsutils.isTypeReference(receiver)) {
|
||||
// TODO - figure out how to handle cases like this,
|
||||
// where the types are assignable, but not the same type
|
||||
/*
|
||||
function foo(): ReadonlySet<number> { return new Set<any>(); }
|
||||
|
||||
// and
|
||||
|
||||
type Test<T> = { prop: T }
|
||||
type Test2 = { prop: string }
|
||||
declare const a: Test<any>;
|
||||
const b: Test2 = a;
|
||||
*/
|
||||
if (type.target !== receiver.target) {
|
||||
// if the type references are different, assume safe, as we won't know how to compare the two types
|
||||
// the generic positions might not be equivalent for both types
|
||||
return false;
|
||||
}
|
||||
if (senderNode?.type === utils_1.AST_NODE_TYPES.NewExpression &&
|
||||
senderNode.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
||||
senderNode.callee.name === 'Map' &&
|
||||
senderNode.arguments.length === 0 &&
|
||||
senderNode.typeArguments == null) {
|
||||
// special case to handle `new Map()`
|
||||
// unfortunately Map's default empty constructor is typed to return `Map<any, any>` :(
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/2109#issuecomment-634144396
|
||||
return false;
|
||||
}
|
||||
const typeArguments = type.typeArguments ?? [];
|
||||
const receiverTypeArguments = receiver.typeArguments ?? [];
|
||||
for (let i = 0; i < typeArguments.length; i += 1) {
|
||||
const arg = typeArguments[i];
|
||||
const receiverArg = receiverTypeArguments[i];
|
||||
const unsafe = isUnsafeAssignmentWorker(arg, receiverArg, checker, senderNode, visited);
|
||||
if (unsafe) {
|
||||
return { receiver, sender: type };
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { expectAssignable, expectType, expectNotAssignable } from 'tsd'
|
||||
|
||||
import pino from '../../'
|
||||
import type {
|
||||
LevelWithSilent,
|
||||
Logger,
|
||||
LogFn,
|
||||
DestinationStreamWithMetadata,
|
||||
Level,
|
||||
LevelOrString,
|
||||
LevelWithSilentOrString,
|
||||
LoggerExtras,
|
||||
LoggerOptions,
|
||||
} from '../../pino'
|
||||
|
||||
// NB: can also use `import * as pino`, but that form is callable as `pino()`
|
||||
// under `esModuleInterop: false` or `pino.default()` under `esModuleInterop: true`.
|
||||
const log = pino()
|
||||
expectAssignable<LoggerExtras>(log)
|
||||
expectType<Logger>(log)
|
||||
expectType<LogFn>(log.info)
|
||||
|
||||
expectType<Parameters<typeof log.isLevelEnabled>>([log.level])
|
||||
|
||||
const level: Level = 'debug'
|
||||
expectAssignable<string>(level)
|
||||
|
||||
const levelWithSilent: LevelWithSilent = 'silent'
|
||||
expectAssignable<string>(levelWithSilent)
|
||||
|
||||
const levelOrString: LevelOrString = 'myCustomLevel'
|
||||
expectAssignable<string>(levelOrString)
|
||||
expectNotAssignable<pino.Level>(levelOrString)
|
||||
expectNotAssignable<pino.LevelWithSilent>(levelOrString)
|
||||
expectAssignable<pino.LevelWithSilentOrString>(levelOrString)
|
||||
|
||||
const levelWithSilentOrString: LevelWithSilentOrString = 'myCustomLevel'
|
||||
expectAssignable<string>(levelWithSilentOrString)
|
||||
expectNotAssignable<pino.Level>(levelWithSilentOrString)
|
||||
expectNotAssignable<pino.LevelWithSilent>(levelWithSilentOrString)
|
||||
expectAssignable<pino.LevelOrString>(levelWithSilentOrString)
|
||||
|
||||
function createStream (): DestinationStreamWithMetadata {
|
||||
return { write () {} }
|
||||
}
|
||||
|
||||
const stream = createStream()
|
||||
// Argh. TypeScript doesn't seem to narrow unless we assign the symbol like so, and tsd seems to
|
||||
// break without annotating the type explicitly
|
||||
const needsMetadata: typeof pino.symbols.needsMetadataGsym = pino.symbols.needsMetadataGsym
|
||||
if (stream[needsMetadata]) {
|
||||
expectType<number>(stream.lastLevel)
|
||||
}
|
||||
|
||||
const loggerOptions: LoggerOptions = {
|
||||
browser: {
|
||||
formatters: {
|
||||
log (obj) {
|
||||
return obj
|
||||
},
|
||||
level (label, number) {
|
||||
return { label, number }
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectType<LoggerOptions>(loggerOptions)
|
||||
|
||||
// Reference: https://github.com/pinojs/pino/issues/2285
|
||||
const someConst = 'test' as const
|
||||
pino().error({}, someConst)
|
||||
const someFunc = <T extends typeof someConst>(someConst: T) => {
|
||||
pino().error({}, someConst)
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
{
|
||||
"name": "@types/node",
|
||||
"version": "26.2.0",
|
||||
"description": "TypeScript definitions for node",
|
||||
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node",
|
||||
"license": "MIT",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Microsoft TypeScript",
|
||||
"githubUsername": "Microsoft",
|
||||
"url": "https://github.com/Microsoft"
|
||||
},
|
||||
{
|
||||
"name": "Alberto Schiabel",
|
||||
"githubUsername": "jkomyno",
|
||||
"url": "https://github.com/jkomyno"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Makarov",
|
||||
"githubUsername": "r3nya",
|
||||
"url": "https://github.com/r3nya"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Toueg",
|
||||
"githubUsername": "btoueg",
|
||||
"url": "https://github.com/btoueg"
|
||||
},
|
||||
{
|
||||
"name": "David Junger",
|
||||
"githubUsername": "touffy",
|
||||
"url": "https://github.com/touffy"
|
||||
},
|
||||
{
|
||||
"name": "Mohsen Azimi",
|
||||
"githubUsername": "mohsen1",
|
||||
"url": "https://github.com/mohsen1"
|
||||
},
|
||||
{
|
||||
"name": "Nikita Galkin",
|
||||
"githubUsername": "galkin",
|
||||
"url": "https://github.com/galkin"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Silbermann",
|
||||
"githubUsername": "eps1lon",
|
||||
"url": "https://github.com/eps1lon"
|
||||
},
|
||||
{
|
||||
"name": "Wilco Bakker",
|
||||
"githubUsername": "WilcoBakker",
|
||||
"url": "https://github.com/WilcoBakker"
|
||||
},
|
||||
{
|
||||
"name": "Marcin Kopacz",
|
||||
"githubUsername": "chyzwar",
|
||||
"url": "https://github.com/chyzwar"
|
||||
},
|
||||
{
|
||||
"name": "Trivikram Kamat",
|
||||
"githubUsername": "trivikr",
|
||||
"url": "https://github.com/trivikr"
|
||||
},
|
||||
{
|
||||
"name": "Junxiao Shi",
|
||||
"githubUsername": "yoursunny",
|
||||
"url": "https://github.com/yoursunny"
|
||||
},
|
||||
{
|
||||
"name": "Ilia Baryshnikov",
|
||||
"githubUsername": "qwelias",
|
||||
"url": "https://github.com/qwelias"
|
||||
},
|
||||
{
|
||||
"name": "ExE Boss",
|
||||
"githubUsername": "ExE-Boss",
|
||||
"url": "https://github.com/ExE-Boss"
|
||||
},
|
||||
{
|
||||
"name": "Piotr Błażejewicz",
|
||||
"githubUsername": "peterblazejewicz",
|
||||
"url": "https://github.com/peterblazejewicz"
|
||||
},
|
||||
{
|
||||
"name": "Anna Henningsen",
|
||||
"githubUsername": "addaleax",
|
||||
"url": "https://github.com/addaleax"
|
||||
},
|
||||
{
|
||||
"name": "Victor Perin",
|
||||
"githubUsername": "victorperin",
|
||||
"url": "https://github.com/victorperin"
|
||||
},
|
||||
{
|
||||
"name": "NodeJS Contributors",
|
||||
"githubUsername": "NodeJS",
|
||||
"url": "https://github.com/NodeJS"
|
||||
},
|
||||
{
|
||||
"name": "Linus Unnebäck",
|
||||
"githubUsername": "LinusU",
|
||||
"url": "https://github.com/LinusU"
|
||||
},
|
||||
{
|
||||
"name": "wafuwafu13",
|
||||
"githubUsername": "wafuwafu13",
|
||||
"url": "https://github.com/wafuwafu13"
|
||||
},
|
||||
{
|
||||
"name": "Matteo Collina",
|
||||
"githubUsername": "mcollina",
|
||||
"url": "https://github.com/mcollina"
|
||||
},
|
||||
{
|
||||
"name": "Dmitry Semigradsky",
|
||||
"githubUsername": "Semigradsky",
|
||||
"url": "https://github.com/Semigradsky"
|
||||
},
|
||||
{
|
||||
"name": "René",
|
||||
"githubUsername": "Renegade334",
|
||||
"url": "https://github.com/Renegade334"
|
||||
},
|
||||
{
|
||||
"name": "Yagiz Nizipli",
|
||||
"githubUsername": "anonrig",
|
||||
"url": "https://github.com/anonrig"
|
||||
}
|
||||
],
|
||||
"main": "",
|
||||
"types": "index.d.ts",
|
||||
"typesVersions": {
|
||||
"<=5.6": {
|
||||
"*": [
|
||||
"ts5.6/*"
|
||||
]
|
||||
},
|
||||
"<=5.7": {
|
||||
"*": [
|
||||
"ts5.7/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
|
||||
"directory": "types/node"
|
||||
},
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"undici-types": "~8.3.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"typesPublisherContentHash": "e8c7e12bafdd8ff8648e4d416be7af2d4373bffe17a7498d815e251898739e7c",
|
||||
"typeScriptVersion": "5.6"
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FFTCore = void 0;
|
||||
exports.isPowerOfTwo = isPowerOfTwo;
|
||||
exports.nextPowerOfTwo = nextPowerOfTwo;
|
||||
exports.reverseBits = reverseBits;
|
||||
exports.log2 = log2;
|
||||
exports.bitReversalInplace = bitReversalInplace;
|
||||
exports.bitReversalPermutation = bitReversalPermutation;
|
||||
exports.rootsOfUnity = rootsOfUnity;
|
||||
exports.FFT = FFT;
|
||||
exports.poly = poly;
|
||||
function checkU32(n) {
|
||||
// 0xff_ff_ff_ff
|
||||
if (!Number.isSafeInteger(n) || n < 0 || n > 0xffffffff)
|
||||
throw new Error('wrong u32 integer:' + n);
|
||||
return n;
|
||||
}
|
||||
/** Checks if integer is in form of `1 << X` */
|
||||
function isPowerOfTwo(x) {
|
||||
checkU32(x);
|
||||
return (x & (x - 1)) === 0 && x !== 0;
|
||||
}
|
||||
function nextPowerOfTwo(n) {
|
||||
checkU32(n);
|
||||
if (n <= 1)
|
||||
return 1;
|
||||
return (1 << (log2(n - 1) + 1)) >>> 0;
|
||||
}
|
||||
function reverseBits(n, bits) {
|
||||
checkU32(n);
|
||||
let reversed = 0;
|
||||
for (let i = 0; i < bits; i++, n >>>= 1)
|
||||
reversed = (reversed << 1) | (n & 1);
|
||||
return reversed;
|
||||
}
|
||||
/** Similar to `bitLen(x)-1` but much faster for small integers, like indices */
|
||||
function log2(n) {
|
||||
checkU32(n);
|
||||
return 31 - Math.clz32(n);
|
||||
}
|
||||
/**
|
||||
* Moves lowest bit to highest position, which at first step splits
|
||||
* array on even and odd indices, then it applied again to each part,
|
||||
* which is core of fft
|
||||
*/
|
||||
function bitReversalInplace(values) {
|
||||
const n = values.length;
|
||||
if (n < 2 || !isPowerOfTwo(n))
|
||||
throw new Error('n must be a power of 2 and greater than 1. Got ' + n);
|
||||
const bits = log2(n);
|
||||
for (let i = 0; i < n; i++) {
|
||||
const j = reverseBits(i, bits);
|
||||
if (i < j) {
|
||||
const tmp = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = tmp;
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
function bitReversalPermutation(values) {
|
||||
return bitReversalInplace(values.slice());
|
||||
}
|
||||
const _1n = /** @__PURE__ */ BigInt(1);
|
||||
function findGenerator(field) {
|
||||
let G = BigInt(2);
|
||||
for (; field.eql(field.pow(G, field.ORDER >> _1n), field.ONE); G++)
|
||||
;
|
||||
return G;
|
||||
}
|
||||
/** We limit roots up to 2**31, which is a lot: 2-billion polynomimal should be rare. */
|
||||
function rootsOfUnity(field, generator) {
|
||||
// Factor field.ORDER-1 as oddFactor * 2^powerOfTwo
|
||||
let oddFactor = field.ORDER - _1n;
|
||||
let powerOfTwo = 0;
|
||||
for (; (oddFactor & _1n) !== _1n; powerOfTwo++, oddFactor >>= _1n)
|
||||
;
|
||||
// Find non quadratic residue
|
||||
let G = generator !== undefined ? BigInt(generator) : findGenerator(field);
|
||||
// Powers of generator
|
||||
const omegas = new Array(powerOfTwo + 1);
|
||||
omegas[powerOfTwo] = field.pow(G, oddFactor);
|
||||
for (let i = powerOfTwo; i > 0; i--)
|
||||
omegas[i - 1] = field.sqr(omegas[i]);
|
||||
// Compute all roots of unity for powers up to maxPower
|
||||
const rootsCache = [];
|
||||
const checkBits = (bits) => {
|
||||
checkU32(bits);
|
||||
if (bits > 31 || bits > powerOfTwo)
|
||||
throw new Error('rootsOfUnity: wrong bits ' + bits + ' powerOfTwo=' + powerOfTwo);
|
||||
return bits;
|
||||
};
|
||||
const precomputeRoots = (maxPower) => {
|
||||
checkBits(maxPower);
|
||||
for (let power = maxPower; power >= 0; power--) {
|
||||
if (rootsCache[power])
|
||||
continue; // Skip if we've already computed roots for this power
|
||||
const rootsAtPower = [];
|
||||
for (let j = 0, cur = field.ONE; j < 2 ** power; j++, cur = field.mul(cur, omegas[power]))
|
||||
rootsAtPower.push(cur);
|
||||
rootsCache[power] = rootsAtPower;
|
||||
}
|
||||
return rootsCache[maxPower];
|
||||
};
|
||||
const brpCache = new Map();
|
||||
const inverseCache = new Map();
|
||||
// NOTE: we use bits instead of power, because power = 2**bits,
|
||||
// but power is not neccesary isPowerOfTwo(power)!
|
||||
return {
|
||||
roots: (bits) => {
|
||||
const b = checkBits(bits);
|
||||
return precomputeRoots(b);
|
||||
},
|
||||
brp(bits) {
|
||||
const b = checkBits(bits);
|
||||
if (brpCache.has(b))
|
||||
return brpCache.get(b);
|
||||
else {
|
||||
const res = bitReversalPermutation(this.roots(b));
|
||||
brpCache.set(b, res);
|
||||
return res;
|
||||
}
|
||||
},
|
||||
inverse(bits) {
|
||||
const b = checkBits(bits);
|
||||
if (inverseCache.has(b))
|
||||
return inverseCache.get(b);
|
||||
else {
|
||||
const res = field.invertBatch(this.roots(b));
|
||||
inverseCache.set(b, res);
|
||||
return res;
|
||||
}
|
||||
},
|
||||
omega: (bits) => omegas[checkBits(bits)],
|
||||
clear: () => {
|
||||
rootsCache.splice(0, rootsCache.length);
|
||||
brpCache.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Constructs different flavors of FFT. radix2 implementation of low level mutating API. Flavors:
|
||||
*
|
||||
* - DIT (Decimation-in-Time): Bottom-Up (leaves -> root), Cool-Turkey
|
||||
* - DIF (Decimation-in-Frequency): Top-Down (root -> leaves), Gentleman–Sande
|
||||
*
|
||||
* DIT takes brp input, returns natural output.
|
||||
* DIF takes natural input, returns brp output.
|
||||
*
|
||||
* The output is actually identical. Time / frequence distinction is not meaningful
|
||||
* for Polynomial multiplication in fields.
|
||||
* Which means if protocol supports/needs brp output/inputs, then we can skip this step.
|
||||
*
|
||||
* Cyclic NTT: Rq = Zq[x]/(x^n-1). butterfly_DIT+loop_DIT OR butterfly_DIF+loop_DIT, roots are omega
|
||||
* Negacyclic NTT: Rq = Zq[x]/(x^n+1). butterfly_DIT+loop_DIF, at least for mlkem / mldsa
|
||||
*/
|
||||
const FFTCore = (F, coreOpts) => {
|
||||
const { N, roots, dit, invertButterflies = false, skipStages = 0, brp = true } = coreOpts;
|
||||
const bits = log2(N);
|
||||
if (!isPowerOfTwo(N))
|
||||
throw new Error('FFT: Polynomial size should be power of two');
|
||||
const isDit = dit !== invertButterflies;
|
||||
isDit;
|
||||
return (values) => {
|
||||
if (values.length !== N)
|
||||
throw new Error('FFT: wrong Polynomial length');
|
||||
if (dit && brp)
|
||||
bitReversalInplace(values);
|
||||
for (let i = 0, g = 1; i < bits - skipStages; i++) {
|
||||
// For each stage s (sub-FFT length m = 2^s)
|
||||
const s = dit ? i + 1 + skipStages : bits - i;
|
||||
const m = 1 << s;
|
||||
const m2 = m >> 1;
|
||||
const stride = N >> s;
|
||||
// Loop over each subarray of length m
|
||||
for (let k = 0; k < N; k += m) {
|
||||
// Loop over each butterfly within the subarray
|
||||
for (let j = 0, grp = g++; j < m2; j++) {
|
||||
const rootPos = invertButterflies ? (dit ? N - grp : grp) : j * stride;
|
||||
const i0 = k + j;
|
||||
const i1 = k + j + m2;
|
||||
const omega = roots[rootPos];
|
||||
const b = values[i1];
|
||||
const a = values[i0];
|
||||
// Inlining gives us 10% perf in kyber vs functions
|
||||
if (isDit) {
|
||||
const t = F.mul(b, omega); // Standard DIT butterfly
|
||||
values[i0] = F.add(a, t);
|
||||
values[i1] = F.sub(a, t);
|
||||
}
|
||||
else if (invertButterflies) {
|
||||
values[i0] = F.add(b, a); // DIT loop + inverted butterflies (Kyber decode)
|
||||
values[i1] = F.mul(F.sub(b, a), omega);
|
||||
}
|
||||
else {
|
||||
values[i0] = F.add(a, b); // Standard DIF butterfly
|
||||
values[i1] = F.mul(F.sub(a, b), omega);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dit && brp)
|
||||
bitReversalInplace(values);
|
||||
return values;
|
||||
};
|
||||
};
|
||||
exports.FFTCore = FFTCore;
|
||||
/**
|
||||
* NTT aka FFT over finite field (NOT over complex numbers).
|
||||
* Naming mirrors other libraries.
|
||||
*/
|
||||
function FFT(roots, opts) {
|
||||
const getLoop = (N, roots, brpInput = false, brpOutput = false) => {
|
||||
if (brpInput && brpOutput) {
|
||||
// we cannot optimize this case, but lets support it anyway
|
||||
return (values) => (0, exports.FFTCore)(opts, { N, roots, dit: false, brp: false })(bitReversalInplace(values));
|
||||
}
|
||||
if (brpInput)
|
||||
return (0, exports.FFTCore)(opts, { N, roots, dit: true, brp: false });
|
||||
if (brpOutput)
|
||||
return (0, exports.FFTCore)(opts, { N, roots, dit: false, brp: false });
|
||||
return (0, exports.FFTCore)(opts, { N, roots, dit: true, brp: true }); // all natural
|
||||
};
|
||||
return {
|
||||
direct(values, brpInput = false, brpOutput = false) {
|
||||
const N = values.length;
|
||||
if (!isPowerOfTwo(N))
|
||||
throw new Error('FFT: Polynomial size should be power of two');
|
||||
const bits = log2(N);
|
||||
return getLoop(N, roots.roots(bits), brpInput, brpOutput)(values.slice());
|
||||
},
|
||||
inverse(values, brpInput = false, brpOutput = false) {
|
||||
const N = values.length;
|
||||
const bits = log2(N);
|
||||
const res = getLoop(N, roots.inverse(bits), brpInput, brpOutput)(values.slice());
|
||||
const ivm = opts.inv(BigInt(values.length)); // scale
|
||||
// we can get brp output if we use dif instead of dit!
|
||||
for (let i = 0; i < res.length; i++)
|
||||
res[i] = opts.mul(res[i], ivm);
|
||||
// Allows to re-use non-inverted roots, but is VERY fragile
|
||||
// return [res[0]].concat(res.slice(1).reverse());
|
||||
// inverse calculated as pow(-1), which transforms into ω^{-kn} (-> reverses indices)
|
||||
return res;
|
||||
},
|
||||
};
|
||||
}
|
||||
function poly(field, roots, create, fft, length) {
|
||||
const F = field;
|
||||
const _create = create ||
|
||||
((len, elm) => new Array(len).fill(elm ?? F.ZERO));
|
||||
const isPoly = (x) => Array.isArray(x) || ArrayBuffer.isView(x);
|
||||
const checkLength = (...lst) => {
|
||||
if (!lst.length)
|
||||
return 0;
|
||||
for (const i of lst)
|
||||
if (!isPoly(i))
|
||||
throw new Error('poly: not polynomial: ' + i);
|
||||
const L = lst[0].length;
|
||||
for (let i = 1; i < lst.length; i++)
|
||||
if (lst[i].length !== L)
|
||||
throw new Error(`poly: mismatched lengths ${L} vs ${lst[i].length}`);
|
||||
if (length !== undefined && L !== length)
|
||||
throw new Error(`poly: expected fixed length ${length}, got ${L}`);
|
||||
return L;
|
||||
};
|
||||
function findOmegaIndex(x, n, brp = false) {
|
||||
const bits = log2(n);
|
||||
const omega = brp ? roots.brp(bits) : roots.roots(bits);
|
||||
for (let i = 0; i < n; i++)
|
||||
if (F.eql(x, omega[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
// TODO: mutating versions for mlkem/mldsa
|
||||
return {
|
||||
roots,
|
||||
create: _create,
|
||||
length,
|
||||
extend: (a, len) => {
|
||||
checkLength(a);
|
||||
const out = _create(len, F.ZERO);
|
||||
for (let i = 0; i < a.length; i++)
|
||||
out[i] = a[i];
|
||||
return out;
|
||||
},
|
||||
degree: (a) => {
|
||||
checkLength(a);
|
||||
for (let i = a.length - 1; i >= 0; i--)
|
||||
if (!F.is0(a[i]))
|
||||
return i;
|
||||
return -1;
|
||||
},
|
||||
add: (a, b) => {
|
||||
const len = checkLength(a, b);
|
||||
const out = _create(len);
|
||||
for (let i = 0; i < len; i++)
|
||||
out[i] = F.add(a[i], b[i]);
|
||||
return out;
|
||||
},
|
||||
sub: (a, b) => {
|
||||
const len = checkLength(a, b);
|
||||
const out = _create(len);
|
||||
for (let i = 0; i < len; i++)
|
||||
out[i] = F.sub(a[i], b[i]);
|
||||
return out;
|
||||
},
|
||||
dot: (a, b) => {
|
||||
const len = checkLength(a, b);
|
||||
const out = _create(len);
|
||||
for (let i = 0; i < len; i++)
|
||||
out[i] = F.mul(a[i], b[i]);
|
||||
return out;
|
||||
},
|
||||
mul: (a, b) => {
|
||||
if (isPoly(b)) {
|
||||
const len = checkLength(a, b);
|
||||
if (fft) {
|
||||
const A = fft.direct(a, false, true);
|
||||
const B = fft.direct(b, false, true);
|
||||
for (let i = 0; i < A.length; i++)
|
||||
A[i] = F.mul(A[i], B[i]);
|
||||
return fft.inverse(A, true, false);
|
||||
}
|
||||
else {
|
||||
// NOTE: this is quadratic and mostly for compat tests with FFT
|
||||
const res = _create(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
for (let j = 0; j < len; j++) {
|
||||
const k = (i + j) % len; // wrap mod length
|
||||
res[k] = F.add(res[k], F.mul(a[i], b[j]));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const out = _create(checkLength(a));
|
||||
for (let i = 0; i < out.length; i++)
|
||||
out[i] = F.mul(a[i], b);
|
||||
return out;
|
||||
}
|
||||
},
|
||||
convolve(a, b) {
|
||||
const len = nextPowerOfTwo(a.length + b.length - 1);
|
||||
return this.mul(this.extend(a, len), this.extend(b, len));
|
||||
},
|
||||
shift(p, factor) {
|
||||
const out = _create(checkLength(p));
|
||||
out[0] = p[0];
|
||||
for (let i = 1, power = F.ONE; i < p.length; i++) {
|
||||
power = F.mul(power, factor);
|
||||
out[i] = F.mul(p[i], power);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
clone: (a) => {
|
||||
checkLength(a);
|
||||
const out = _create(a.length);
|
||||
for (let i = 0; i < a.length; i++)
|
||||
out[i] = a[i];
|
||||
return out;
|
||||
},
|
||||
eval: (a, basis) => {
|
||||
checkLength(a);
|
||||
let acc = F.ZERO;
|
||||
for (let i = 0; i < a.length; i++)
|
||||
acc = F.add(acc, F.mul(a[i], basis[i]));
|
||||
return acc;
|
||||
},
|
||||
monomial: {
|
||||
basis: (x, n) => {
|
||||
const out = _create(n);
|
||||
let pow = F.ONE;
|
||||
for (let i = 0; i < n; i++) {
|
||||
out[i] = pow;
|
||||
pow = F.mul(pow, x);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
eval: (a, x) => {
|
||||
checkLength(a);
|
||||
// Same as eval(a, monomialBasis(x, a.length)), but it is faster this way
|
||||
let acc = F.ZERO;
|
||||
for (let i = a.length - 1; i >= 0; i--)
|
||||
acc = F.add(F.mul(acc, x), a[i]);
|
||||
return acc;
|
||||
},
|
||||
},
|
||||
lagrange: {
|
||||
basis: (x, n, brp = false, weights) => {
|
||||
const bits = log2(n);
|
||||
const cache = weights || brp ? roots.brp(bits) : roots.roots(bits); // [ω⁰, ω¹, ..., ωⁿ⁻¹]
|
||||
const out = _create(n);
|
||||
// Fast Kronecker-δ shortcut
|
||||
const idx = findOmegaIndex(x, n, brp);
|
||||
if (idx !== -1) {
|
||||
out[idx] = F.ONE;
|
||||
return out;
|
||||
}
|
||||
const tm = F.pow(x, BigInt(n));
|
||||
const c = F.mul(F.sub(tm, F.ONE), F.inv(BigInt(n))); // c = (xⁿ - 1)/n
|
||||
const denom = _create(n);
|
||||
for (let i = 0; i < n; i++)
|
||||
denom[i] = F.sub(x, cache[i]);
|
||||
const inv = F.invertBatch(denom);
|
||||
for (let i = 0; i < n; i++)
|
||||
out[i] = F.mul(c, F.mul(cache[i], inv[i]));
|
||||
return out;
|
||||
},
|
||||
eval(a, x, brp = false) {
|
||||
checkLength(a);
|
||||
const idx = findOmegaIndex(x, a.length, brp);
|
||||
if (idx !== -1)
|
||||
return a[idx]; // fast path
|
||||
const L = this.basis(x, a.length, brp); // Lᵢ(x)
|
||||
let acc = F.ZERO;
|
||||
for (let i = 0; i < a.length; i++)
|
||||
if (!F.is0(a[i]))
|
||||
acc = F.add(acc, F.mul(a[i], L[i]));
|
||||
return acc;
|
||||
},
|
||||
},
|
||||
vanishing(roots) {
|
||||
checkLength(roots);
|
||||
const out = _create(roots.length + 1, F.ZERO);
|
||||
out[0] = F.ONE;
|
||||
for (const r of roots) {
|
||||
const neg = F.neg(r);
|
||||
for (let j = out.length - 1; j > 0; j--)
|
||||
out[j] = F.add(F.mul(out[j], neg), out[j - 1]);
|
||||
out[0] = F.mul(out[0], neg);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=fft.js.map
|
||||
@@ -0,0 +1,11 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
function md5(bytes) {
|
||||
if (Array.isArray(bytes)) {
|
||||
bytes = Buffer.from(bytes);
|
||||
}
|
||||
else if (typeof bytes === 'string') {
|
||||
bytes = Buffer.from(bytes, 'utf8');
|
||||
}
|
||||
return createHash('md5').update(bytes).digest();
|
||||
}
|
||||
export default md5;
|
||||
@@ -0,0 +1,98 @@
|
||||
'use strict'
|
||||
|
||||
const bench = require('fastbench')
|
||||
const SonicBoom = require('./')
|
||||
const Console = require('console').Console
|
||||
const fs = require('fs')
|
||||
|
||||
const core = fs.createWriteStream('/dev/null')
|
||||
const fd = fs.openSync('/dev/null', 'w')
|
||||
const sonic = new SonicBoom({ fd })
|
||||
const sonic4k = new SonicBoom({ fd, minLength: 4096 })
|
||||
const sonicSync = new SonicBoom({ fd, sync: true })
|
||||
const sonicSync4k = new SonicBoom({ fd, minLength: 4096, sync: true })
|
||||
const sonicBuffer = new SonicBoom({ fd, contentMode: 'buffer' })
|
||||
const sonic4kBuffer = new SonicBoom({ fd, contentMode: 'buffer', minLength: 4096 })
|
||||
const sonicSyncBuffer = new SonicBoom({ fd, contentMode: 'buffer', sync: true })
|
||||
const sonicSync4kBuffer = new SonicBoom({ fd, contentMode: 'buffer', minLength: 4096, sync: true })
|
||||
const dummyConsole = new Console(fs.createWriteStream('/dev/null'))
|
||||
|
||||
const MAX = 10000
|
||||
|
||||
const buf = Buffer.alloc(50, 'hello', 'utf8')
|
||||
const str = buf.toString()
|
||||
|
||||
setTimeout(doBench, 100)
|
||||
|
||||
const run = bench([
|
||||
function benchSonic (cb) {
|
||||
sonic.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonic.write(str)
|
||||
}
|
||||
},
|
||||
function benchSonicSync (cb) {
|
||||
sonicSync.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonicSync.write(str)
|
||||
}
|
||||
},
|
||||
function benchSonic4k (cb) {
|
||||
sonic4k.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonic4k.write(str)
|
||||
}
|
||||
},
|
||||
function benchSonicSync4k (cb) {
|
||||
sonicSync4k.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonicSync4k.write(str)
|
||||
}
|
||||
},
|
||||
function benchCore (cb) {
|
||||
core.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
core.write(str)
|
||||
}
|
||||
},
|
||||
function benchConsole (cb) {
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
dummyConsole.log(str)
|
||||
}
|
||||
setImmediate(cb)
|
||||
},
|
||||
function benchSonicBuf (cb) {
|
||||
sonicBuffer.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonicBuffer.write(buf)
|
||||
}
|
||||
},
|
||||
function benchSonicSyncBuf (cb) {
|
||||
sonicSyncBuffer.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonicSyncBuffer.write(buf)
|
||||
}
|
||||
},
|
||||
function benchSonic4kBuf (cb) {
|
||||
sonic4kBuffer.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonic4kBuffer.write(buf)
|
||||
}
|
||||
},
|
||||
function benchSonicSync4kBuf (cb) {
|
||||
sonicSync4kBuffer.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
sonicSync4kBuffer.write(buf)
|
||||
}
|
||||
},
|
||||
function benchCoreBuf (cb) {
|
||||
core.once('drain', cb)
|
||||
for (let i = 0; i < MAX; i++) {
|
||||
core.write(buf)
|
||||
}
|
||||
}
|
||||
], 1000)
|
||||
|
||||
function doBench () {
|
||||
run(run)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export declare var NodeBuilderFlags: any;
|
||||
//# sourceMappingURL=nodeBuilderFlags.d.ts.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
global.process = { __proto__: process, pid: 123456 }
|
||||
|
||||
const write = process.stdout.write.bind(process.stdout)
|
||||
process.stdout.write = function (chunk) {
|
||||
write('hack ' + chunk)
|
||||
}
|
||||
|
||||
Date.now = function () { return 1459875739796 }
|
||||
require('node:os').hostname = function () { return 'abcdefghijklmnopqr' }
|
||||
const pino = require(require.resolve('../../'))()
|
||||
pino.info('me')
|
||||
@@ -0,0 +1,40 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { createWarning } = require('../')
|
||||
const { withResolvers } = require('./promise')
|
||||
|
||||
test('a limited warning can be re-set', t => {
|
||||
t.plan(7)
|
||||
|
||||
const { promise, resolve } = withResolvers()
|
||||
let count = 0
|
||||
process.on('warning', onWarning)
|
||||
function onWarning () {
|
||||
count++
|
||||
}
|
||||
|
||||
const warn = createWarning({
|
||||
name: 'TestDeprecation',
|
||||
code: 'CODE',
|
||||
message: 'Hello world'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(warn(), true)
|
||||
t.assert.ok(warn.emitted)
|
||||
|
||||
t.assert.strictEqual(warn(), false)
|
||||
t.assert.ok(warn.emitted)
|
||||
|
||||
warn.emitted = false
|
||||
t.assert.strictEqual(warn(), true)
|
||||
t.assert.ok(warn.emitted)
|
||||
|
||||
setImmediate(() => {
|
||||
t.assert.deepStrictEqual(count, 2)
|
||||
process.removeListener('warning', onWarning)
|
||||
resolve()
|
||||
})
|
||||
|
||||
return promise
|
||||
})
|
||||
@@ -0,0 +1,2 @@
|
||||
export declare function createIdGenerator(): () => number;
|
||||
export declare function resetIds(): void;
|
||||
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2017_typedarrays = void 0;
|
||||
const base_config_1 = require("./base-config");
|
||||
exports.es2017_typedarrays = {
|
||||
libs: [],
|
||||
variables: [
|
||||
['Int8ArrayConstructor', base_config_1.TYPE],
|
||||
['Uint8ArrayConstructor', base_config_1.TYPE],
|
||||
['Uint8ClampedArrayConstructor', base_config_1.TYPE],
|
||||
['Int16ArrayConstructor', base_config_1.TYPE],
|
||||
['Uint16ArrayConstructor', base_config_1.TYPE],
|
||||
['Int32ArrayConstructor', base_config_1.TYPE],
|
||||
['Uint32ArrayConstructor', base_config_1.TYPE],
|
||||
['Float32ArrayConstructor', base_config_1.TYPE],
|
||||
['Float64ArrayConstructor', base_config_1.TYPE],
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
const cp = require('child_process');
|
||||
const parse = require('./lib/parse');
|
||||
const enoent = require('./lib/enoent');
|
||||
|
||||
function spawn(command, args, options) {
|
||||
// Parse the arguments
|
||||
const parsed = parse(command, args, options);
|
||||
|
||||
// Spawn the child process
|
||||
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
|
||||
|
||||
// Hook into child process "exit" event to emit an error if the command
|
||||
// does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
|
||||
enoent.hookChildProcess(spawned, parsed);
|
||||
|
||||
return spawned;
|
||||
}
|
||||
|
||||
function spawnSync(command, args, options) {
|
||||
// Parse the arguments
|
||||
const parsed = parse(command, args, options);
|
||||
|
||||
// Spawn the child process
|
||||
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
|
||||
|
||||
// Analyze if the command does not exist, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
|
||||
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = spawn;
|
||||
module.exports.spawn = spawn;
|
||||
module.exports.sync = spawnSync;
|
||||
|
||||
module.exports._parse = parse;
|
||||
module.exports._enoent = enoent;
|
||||
@@ -0,0 +1,67 @@
|
||||
import { CharacterCodes } from "#enums/characterCodes";
|
||||
import { SyntaxKind } from "#enums/syntaxKind";
|
||||
let syntaxKindNames;
|
||||
function getSyntaxKindNames() {
|
||||
if (!syntaxKindNames) {
|
||||
syntaxKindNames = new Map();
|
||||
for (const name of Object.keys(SyntaxKind)) {
|
||||
const val = SyntaxKind[name];
|
||||
if (typeof val === "number" && !syntaxKindNames.has(val)) {
|
||||
syntaxKindNames.set(val, name);
|
||||
}
|
||||
}
|
||||
syntaxKindNames.set(SyntaxKind.EndOfFile, "EndOfFileToken");
|
||||
}
|
||||
return syntaxKindNames;
|
||||
}
|
||||
export function formatSyntaxKind(kind) {
|
||||
return getSyntaxKindNames().get(kind) ?? `Unknown(${kind})`;
|
||||
}
|
||||
/**
|
||||
* Remove one extra leading underscore from an identifier name, recovering the
|
||||
* display form from its escaped {@link __String} key.
|
||||
*/
|
||||
export function unescapeLeadingUnderscores(identifier) {
|
||||
const id = identifier;
|
||||
return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._
|
||||
? id.slice(1)
|
||||
: id;
|
||||
}
|
||||
/**
|
||||
* Add an extra leading underscore to a display name that already begins with
|
||||
* `__`, producing its escaped {@link __String} key.
|
||||
*/
|
||||
export function escapeLeadingUnderscores(identifier) {
|
||||
return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._
|
||||
? "_" + identifier
|
||||
: identifier);
|
||||
}
|
||||
export function tryCast(value, test) {
|
||||
return value !== undefined && test(value) ? value : undefined;
|
||||
}
|
||||
export function cast(value, test) {
|
||||
if (value !== undefined && test(value))
|
||||
return value;
|
||||
throw new Error(`Invalid cast. The supplied value ${value} did not pass the test '${test.name}'.`);
|
||||
}
|
||||
export function cloneSourceFileData(sourceFile) {
|
||||
return {
|
||||
statements: sourceFile.statements,
|
||||
endOfFileToken: sourceFile.endOfFileToken,
|
||||
text: sourceFile.text,
|
||||
fileName: sourceFile.fileName,
|
||||
path: sourceFile.path,
|
||||
languageVariant: sourceFile.languageVariant,
|
||||
scriptKind: sourceFile.scriptKind,
|
||||
isDeclarationFile: sourceFile.isDeclarationFile,
|
||||
referencedFiles: sourceFile.referencedFiles,
|
||||
typeReferenceDirectives: sourceFile.typeReferenceDirectives,
|
||||
libReferenceDirectives: sourceFile.libReferenceDirectives,
|
||||
imports: sourceFile.imports,
|
||||
moduleAugmentations: sourceFile.moduleAugmentations,
|
||||
ambientModuleNames: sourceFile.ambientModuleNames,
|
||||
externalModuleIndicator: sourceFile.externalModuleIndicator,
|
||||
tokenCache: undefined,
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=utils.js.map
|
||||
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
var parse = require('../');
|
||||
var test = require('tape');
|
||||
|
||||
test('-', function (t) {
|
||||
t.plan(6);
|
||||
t.deepEqual(parse(['-n', '-']), { n: '-', _: [] });
|
||||
t.deepEqual(parse(['--nnn', '-']), { nnn: '-', _: [] });
|
||||
t.deepEqual(parse(['-']), { _: ['-'] });
|
||||
t.deepEqual(parse(['-f-']), { f: '-', _: [] });
|
||||
t.deepEqual(
|
||||
parse(['-b', '-'], { boolean: 'b' }),
|
||||
{ b: true, _: ['-'] }
|
||||
);
|
||||
t.deepEqual(
|
||||
parse(['-s', '-'], { string: 's' }),
|
||||
{ s: '-', _: [] }
|
||||
);
|
||||
});
|
||||
|
||||
test('-a -- b', function (t) {
|
||||
t.plan(2);
|
||||
t.deepEqual(parse(['-a', '--', 'b']), { a: true, _: ['b'] });
|
||||
t.deepEqual(parse(['--a', '--', 'b']), { a: true, _: ['b'] });
|
||||
});
|
||||
|
||||
test('move arguments after the -- into their own `--` array', function (t) {
|
||||
t.plan(1);
|
||||
t.deepEqual(
|
||||
parse(['--name', 'John', 'before', '--', 'after'], { '--': true }),
|
||||
{ name: 'John', _: ['before'], '--': ['after'] }
|
||||
);
|
||||
});
|
||||
|
||||
test('--- option value', function (t) {
|
||||
// A multi-dash value is largely an edge case, but check the behaviour is as expected,
|
||||
// and in particular the same for short option and long option (as made consistent in Jan 2023).
|
||||
t.plan(2);
|
||||
t.deepEqual(parse(['-n', '---']), { n: '---', _: [] });
|
||||
t.deepEqual(parse(['--nnn', '---']), { nnn: '---', _: [] });
|
||||
});
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
self.Flatted=function(t){"use strict";const{parse:e,stringify:n}=JSON,{keys:r}=Object,o=String,s="string",c={},l="object",f=(t,e)=>e,i=t=>t instanceof o?o(t):t,a=(t,e)=>typeof e===s?new o(e):e,u=(t,e,n)=>{const r=o(e.push(n)-1);return t.set(n,r),r},p=(t,n)=>{const s=e(t,a).map(i),u=n||f;let p=s[0];if(typeof p===l&&p){const t=[],e=((t,e,n,s)=>f=>{for(let i=r(f),{length:a}=i,u=0;u<a;u++){const r=i[u],a=f[r];if(a instanceof o){const o=t[+a];typeof o!==l||n.has(o)?f[r]=s.call(f,r,o):(n.add(o),f[r]=c,e.push({o:f,k:r,r:o}))}else f[r]!==c&&(f[r]=s.call(f,r,a))}return f})(s,t,new Set,u);p=e(p);let n=0;for(;n<t.length;){const{o:r,k:o,r:s}=t[n++];r[o]=u.call(r,o,e(s))}}return u.call({"":p},"",p)},g=(t,e,r)=>{const o=e&&typeof e===l?(t,n)=>""===t||-1<e.indexOf(t)?n:void 0:e||f,c=new Map,i=[],a=[];let p=+u(c,i,o.call({"":t},"",t)),g=!p;for(;p<i.length;)g=!0,a[p]=n(i[p++],h,r);return"["+a.join(",")+"]";function h(t,e){if(g)return g=!g,e;const n=o.call(this,t,e);switch(typeof n){case l:if(null===n)return n;case s:return c.get(n)||u(c,i,n)}return n}};return t.fromJSON=t=>p(n(t)),t.parse=p,t.stringify=g,t.toJSON=t=>e(g(t)),t}({});
|
||||
Reference in New Issue
Block a user