WIP: bootstrap and partial real Solana watcher implementation

This commit is contained in:
2026-08-16 09:17:45 +00:00
commit dc23412c3f
7232 changed files with 1687637 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
{
"name": "chalk",
"version": "5.6.2",
"description": "Terminal string styling done right",
"license": "MIT",
"repository": "chalk/chalk",
"funding": "https://github.com/chalk/chalk?sponsor=1",
"type": "module",
"main": "./source/index.js",
"exports": "./source/index.js",
"imports": {
"#ansi-styles": "./source/vendor/ansi-styles/index.js",
"#supports-color": {
"node": "./source/vendor/supports-color/index.js",
"default": "./source/vendor/supports-color/browser.js"
}
},
"types": "./source/index.d.ts",
"sideEffects": false,
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
"scripts": {
"test": "xo && c8 ava && tsd",
"bench": "matcha benchmark.js"
},
"files": [
"source",
"!source/index.test-d.ts"
],
"keywords": [
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"ansi",
"style",
"styles",
"tty",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"log",
"logging",
"command-line",
"text"
],
"devDependencies": {
"@types/node": "^16.11.10",
"ava": "^3.15.0",
"c8": "^7.10.0",
"color-convert": "^2.0.1",
"execa": "^6.0.0",
"log-update": "^5.0.0",
"matcha": "^0.7.0",
"tsd": "^0.19.0",
"xo": "^0.57.0",
"yoctodelay": "^2.0.0"
},
"xo": {
"rules": {
"unicorn/prefer-string-slice": "off",
"@typescript-eslint/consistent-type-imports": "off",
"@typescript-eslint/consistent-type-exports": "off",
"@typescript-eslint/consistent-type-definitions": "off",
"unicorn/expiring-todo-comments": "off"
}
},
"c8": {
"reporter": [
"text",
"lcov"
],
"exclude": [
"source/vendor"
]
}
}

View File

@@ -0,0 +1,375 @@
import { readFileSync } from 'node:fs';
import { isBuiltin } from 'node:module';
import { pathToFileURL } from 'node:url';
import { resolve } from 'pathe';
import { ModuleRunner, EvaluatedModules } from 'vite/module-runner';
import { b as VitestTransport } from './startVitestModuleRunner.DB-7oCpn.js';
import { e as environments } from './index.DC7d2Pf8.js';
import { serializeValue } from '@vitest/utils/serialize';
import { serializeError } from '@vitest/utils/error';
import { disableDefaultColors } from 'tinyrainbow';
import { T as Traces } from './traces.DT5aQ62U.js';
import { o as onCancel, a as rpcDone, c as createRuntimeRpc } from './rpc.MzXet3jl.js';
import { createStackString, parseStacktrace } from '@vitest/utils/source-map';
import { s as setupInspect } from './inspector.CvyFGlXm.js';
import { V as VitestEvaluatedModules } from './evaluatedModules.Dg1zASAC.js';
import { E as EnvironmentTeardownError } from './utils.BX5Fg8C4.js';
function isBuiltinEnvironment(env) {
return env in environments;
}
const isWindows = process.platform === "win32";
const _loaders = /* @__PURE__ */ new Map();
function createEnvironmentLoader(root, rpc) {
const cachedLoader = _loaders.get(root);
if (!cachedLoader || cachedLoader.isClosed()) {
_loaders.delete(root);
const moduleRunner = new ModuleRunner({
hmr: false,
sourcemapInterceptor: "prepareStackTrace",
transport: new VitestTransport({
async fetchModule(id, importer, options) {
const result = await rpc.fetch(id, importer, "__vitest__", options);
if ("cached" in result) return {
code: readFileSync(result.tmp, "utf-8"),
...result
};
if (isWindows && "externalize" in result)
// TODO: vitest returns paths for external modules, but Vite returns file://
// https://github.com/vitejs/vite/pull/20449
result.externalize = isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id) ? result.externalize : pathToFileURL(result.externalize).toString();
return result;
},
async resolveId(id, importer) {
return rpc.resolve(id, importer, "__vitest__");
}
}, new EvaluatedModules(), /* @__PURE__ */ new WeakMap())
});
_loaders.set(root, moduleRunner);
}
return _loaders.get(root);
}
async function loadNativeEnvironment(name, root, traces) {
const packageId = name[0] === "." || name[0] === "/" ? pathToFileURL(resolve(root, name)).toString() : import.meta.resolve(`vitest-environment-${name}`, pathToFileURL(root).toString());
return resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => import(packageId)));
}
function resolveEnvironmentFromModule(name, packageId, pkg) {
if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`);
const environment = pkg.default;
if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`);
if (environment.transformMode) {
console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`);
// keep for backwards compat
environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client";
}
return environment;
}
async function loadEnvironment(name, root, rpc, traces, viteModuleRunner) {
if (isBuiltinEnvironment(name)) return { environment: environments[name] };
if (!viteModuleRunner) return { environment: await loadNativeEnvironment(name, root, traces) };
const loader = createEnvironmentLoader(root, rpc);
const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await traces.$("vitest.runtime.environment.resolve", () => rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__")))?.id ?? resolve(root, name);
return {
environment: resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => loader.import(packageId))),
loader
};
}
const cleanupListeners = /* @__PURE__ */ new Set();
const moduleRunnerListeners = /* @__PURE__ */ new Set();
function onCleanup(cb) {
cleanupListeners.add(cb);
}
async function cleanup() {
await Promise.all([...cleanupListeners].map((l) => l()));
}
function onModuleRunner(cb) {
moduleRunnerListeners.add(cb);
}
function emitModuleRunner(moduleRunner) {
moduleRunnerListeners.forEach((l) => l(moduleRunner));
}
// Store globals in case tests overwrite them
const processListeners = process.listeners.bind(process);
const processOn = process.on.bind(process);
const processOff = process.off.bind(process);
const dispose = [];
function listenForErrors(state) {
dispose.forEach((fn) => fn());
dispose.length = 0;
function catchError(err, type, event) {
const worker = state();
// if there is another listener, assume that it's handled by user code
// one is Vitest's own listener
if (processListeners(event).length > 1) return;
const error = serializeValue(err);
if (typeof error === "object" && error != null) {
error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0;
if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath;
}
state().rpc.onUnhandledError(error, type);
}
const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException");
const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection");
processOn("uncaughtException", uncaughtException);
processOn("unhandledRejection", unhandledRejection);
dispose.push(() => {
processOff("uncaughtException", uncaughtException);
processOff("unhandledRejection", unhandledRejection);
});
}
const resolvingModules = /* @__PURE__ */ new Set();
async function execute(method, ctx, worker, traces) {
const prepareStart = performance.now();
const cleanups = [setupInspect(ctx)];
// RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread
const rpc = ctx.rpc;
try {
// do not close the RPC channel so that we can get the error messages sent to the main thread
cleanups.push(async () => {
await Promise.all(rpc.$rejectPendingCalls(({ method, reject }) => {
reject(new EnvironmentTeardownError(`[vitest-worker]: Closing rpc while "${method}" was pending`));
}));
});
const state = {
ctx,
evaluatedModules: new VitestEvaluatedModules(),
resolvingModules,
moduleExecutionInfo: /* @__PURE__ */ new Map(),
config: ctx.config,
environment: null,
durations: {
environment: 0,
prepare: prepareStart
},
rpc,
onCancel,
onCleanup: onCleanup,
providedContext: ctx.providedContext,
onFilterStackTrace(stack) {
return createStackString(parseStacktrace(stack));
},
metaEnv: createImportMetaEnvProxy()
};
const methodName = method === "collect" ? "collectTests" : "runTests";
if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`);
await worker[methodName](state, traces);
} finally {
await rpcDone().catch(() => {});
await Promise.all(cleanups.map((fn) => fn())).catch(() => {});
}
}
function run(ctx, worker, traces) {
return execute("run", ctx, worker, traces);
}
function collect(ctx, worker, traces) {
return execute("collect", ctx, worker, traces);
}
async function teardown() {
await cleanup();
}
const env = process.env;
function createImportMetaEnvProxy() {
// packages/vitest/src/node/plugins/index.ts:146
const booleanKeys = [
"DEV",
"PROD",
"SSR"
];
return new Proxy(env, {
get(_, key) {
if (typeof key !== "string") return;
if (booleanKeys.includes(key)) return !!process.env[key];
return process.env[key];
},
set(_, key, value) {
if (typeof key !== "string") return true;
if (booleanKeys.includes(key)) process.env[key] = value ? "1" : "";
else process.env[key] = value;
return true;
}
});
}
const __vitest_worker_response__ = true;
const memoryUsage = process.memoryUsage.bind(process);
let reportMemory = false;
let traces;
/** @experimental */
function init(worker) {
worker.on(onMessage);
if (worker.onModuleRunner) onModuleRunner(worker.onModuleRunner);
let runPromise;
let isRunning = false;
let workerTeardown;
let setupContext;
function send(response) {
worker.post(worker.serialize ? worker.serialize(response) : response);
}
async function onMessage(rawMessage) {
const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage;
if (message?.__vitest_worker_request__ !== true) return;
switch (message.type) {
case "start": {
process.env.VITEST_POOL_ID = String(message.poolId);
process.env.VITEST_WORKER_ID = String(message.workerId);
reportMemory = message.options.reportMemory;
if (message.context.config.isAgent) disableDefaultColors();
traces ??= await new Traces({
enabled: message.traces.enabled,
sdkPath: message.traces.sdkPath
}).waitInit();
const { environment, config, pool } = message.context;
const context = traces.getContextFromCarrier(message.traces.otelCarrier);
// record telemetry as part of "start"
traces.recordInitSpan(context);
try {
setupContext = {
environment,
config,
pool,
rpc: createRuntimeRpc(worker),
projectName: config.name || "",
traces
};
workerTeardown = await traces.$("vitest.runtime.setup", { context }, () => worker.setup?.(setupContext));
send({
type: "started",
__vitest_worker_response__
});
} catch (error) {
send({
type: "started",
__vitest_worker_response__,
error: serializeError(error)
});
}
break;
}
case "run":
// Prevent concurrent execution if worker is already running
if (isRunning) {
send({
type: "testfileFinished",
__vitest_worker_response__,
error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests"))
});
return;
}
try {
process.env.VITEST_WORKER_ID = String(message.context.workerId);
} catch (error) {
return send({
type: "testfileFinished",
__vitest_worker_response__,
error: serializeError(error),
usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
});
}
isRunning = true;
try {
const tracesContext = traces.getContextFromCarrier(message.otelCarrier);
runPromise = traces.$("vitest.runtime.run", {
context: tracesContext,
attributes: {
"vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [],
"vitest.worker.id": message.context.workerId
}
}, () => run({
...setupContext,
...message.context
}, worker, traces).catch((error) => serializeError(error)));
send({
type: "testfileFinished",
__vitest_worker_response__,
error: await runPromise,
usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
});
} finally {
runPromise = void 0;
isRunning = false;
}
break;
case "collect":
// Prevent concurrent execution if worker is already running
if (isRunning) {
send({
type: "testfileFinished",
__vitest_worker_response__,
error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests"))
});
return;
}
try {
process.env.VITEST_WORKER_ID = String(message.context.workerId);
} catch (error) {
return send({
type: "testfileFinished",
__vitest_worker_response__,
error: serializeError(error),
usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
});
}
isRunning = true;
try {
const tracesContext = traces.getContextFromCarrier(message.otelCarrier);
runPromise = traces.$("vitest.runtime.collect", {
context: tracesContext,
attributes: {
"vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [],
"vitest.worker.id": message.context.workerId
}
}, () => collect({
...setupContext,
...message.context
}, worker, traces).catch((error) => serializeError(error)));
send({
type: "testfileFinished",
__vitest_worker_response__,
error: await runPromise,
usedMemory: reportMemory ? memoryUsage().heapUsed : void 0
});
} finally {
runPromise = void 0;
isRunning = false;
}
break;
case "stop":
await runPromise;
try {
const context = traces.getContextFromCarrier(message.otelCarrier);
const error = await traces.$("vitest.runtime.teardown", { context }, async () => {
const error = await teardown().catch((error) => serializeError(error));
await workerTeardown?.();
return error;
});
await traces.finish();
send({
type: "stopped",
error,
__vitest_worker_response__
});
} catch (error) {
send({
type: "stopped",
error: serializeError(error),
__vitest_worker_response__
});
}
worker.teardown?.();
break;
}
}
}
function getFilesWithLocations(files) {
return files.flatMap((file) => {
if (!file.testLocations) return file.filepath;
return file.testLocations.map((location) => {
return `${file}:${location}`;
});
});
}
export { listenForErrors as a, emitModuleRunner as e, init as i, loadEnvironment as l };

View File

@@ -0,0 +1,403 @@
# ES Module Lexer
[![Build Status][actions-image]][actions-url]
A JS module syntax lexer used in [es-module-shims](https://github.com/guybedford/es-module-shims).
Outputs the list of exports and locations of import specifiers, including dynamic import and import meta handling.
Supports new syntax features including import attributes and source phase imports.
A very small single JS file (~7KiB gzipped) that includes inlined Web Assembly for very fast source analysis of ECMAScript module syntax only.
For an example of the performance, Angular 1 (720KiB) is fully parsed in 5ms, in comparison to the fastest JS parser, Acorn which takes over 100ms.
_Comprehensively handles the JS language grammar while remaining small and fast. - ~10ms per MB of JS cold and ~5ms per MB of JS warm, [see benchmarks](#benchmarks) for more info._
> [Built with](https://github.com/guybedford/es-module-lexer/blob/main/chompfile.toml) [Chomp](https://chompbuild.com/)
### Usage
```
npm install es-module-lexer
```
See [src/lexer.ts](src/lexer.ts) for the type definitions.
For use in CommonJS:
```js
const { init, parse } = require('es-module-lexer');
(async () => {
// either await init, or call parse asynchronously
// this is necessary for the Web Assembly boot
await init;
const source = 'export var p = 5';
const [imports, exports] = parse(source);
// Returns "p"
source.slice(exports[0].s, exports[0].e);
// Returns "p"
source.slice(exports[0].ls, exports[0].le);
})();
```
An ES module version is also available:
```js
import { init, parse } from 'es-module-lexer';
(async () => {
await init;
const source = `
import { name } from 'mod\\u1011';
import json from './json.json' with { type: 'json' }
export var p = 5;
export function q () {
};
export { x as 'external name' } from 'external';
// Comments provided to demonstrate edge cases
import /*comment!*/ ( 'asdf', { with: { type: 'json' }});
import /*comment!*/.meta.asdf;
// Source phase imports:
import source mod from './mod.wasm';
import.source('./mod.wasm');
`;
const [imports, exports] = parse(source, 'optional-sourcename');
// Returns "modထ"
imports[0].n
// Returns "mod\u1011"
source.slice(imports[0].s, imports[0].e);
// "s" = start
// "e" = end
// Returns "import { name } from 'mod'"
source.slice(imports[0].ss, imports[0].se);
// "ss" = statement start
// "se" = statement end
// Returns "{ type: 'json' }"
source.slice(imports[1].a, imports[1].se);
// "a" = attribute start, -1 for no import attributes
// Parsed import attributes are available in `at`
// Returns [['type', 'json']]
imports[1].at;
// Returns 'json'
imports[1].at[0][1];
// Returns null (no attributes)
imports[0].at;
// Returns "external"
source.slice(imports[2].s, imports[2].e);
// Returns "p"
source.slice(exports[0].s, exports[0].e);
// Returns "p"
source.slice(exports[0].ls, exports[0].le);
// Returns "q"
source.slice(exports[1].s, exports[1].e);
// Returns "q"
source.slice(exports[1].ls, exports[1].le);
// "ss" = export statement start (only the start is tracked, not the end)
// Returns "export"
source.slice(exports[0].ss, exports[0].ss + 6);
// Returns "'external name'"
source.slice(exports[2].s, exports[2].e);
// Returns -1
exports[2].ls;
// Returns -1
exports[2].le;
// Import type is provided by `t` value
// (1 for static, 2, for dynamic)
// Returns true
imports[2].t == 2;
// Returns "asdf" (only for string literal dynamic imports)
imports[2].n
// Returns "import /*comment!*/ ( 'asdf', { with: { type: 'json' } })"
source.slice(imports[3].ss, imports[3].se);
// Returns "'asdf'"
source.slice(imports[3].s, imports[3].e);
// Returns "( 'asdf', { with: { type: 'json' } })"
source.slice(imports[3].d, imports[3].se);
// Returns "{ with: { type: 'json' } }"
source.slice(imports[3].a, imports[3].se - 1);
// For non-string dynamic import expressions:
// - n will be undefined
// - a is currently -1 even if there is an import attribute
// - e is currently the character before the closing )
// For nested dynamic imports, the se value of the outer import is -1 as end tracking does not
// currently support nested dynamic immports
// import.meta is indicated by imports[3].d === -2
// Returns true
imports[4].d === -2;
// Returns "import /*comment!*/.meta"
source.slice(imports[4].s, imports[4].e);
// ss and se are the same for import meta
// Returns "'./mod.wasm'"
source.slice(imports[5].s, imports[5].e);
// Import type 4 and 5 for static and dynamic source phase
imports[5].t === 4;
imports[6].t === 5;
})();
```
### CSP asm.js Build
The default version of the library uses Wasm and (safe) eval usage for performance and a minimal footprint.
Neither of these represent security escalation possibilities since there are no execution string injection vectors, but that can still violate existing CSP policies for applications.
For a version that works with CSP eval disabled, use the `es-module-lexer/js` build:
```js
import { parse } from 'es-module-lexer/js';
```
Instead of Web Assembly, this uses an asm.js build which is almost as fast as the Wasm version ([see benchmarks below](#benchmarks)).
### Minimal Build
For size-sensitive embedders, the `es-module-lexer/minimal` build drops certain features to reduce the binary size. This is used for example by [es-module-shims](https://github.com/guybedford/es-module-shims):
```js
import { parse } from 'es-module-lexer/minimal';
```
Compared to the full build:
* `parse` returns a two-element `[imports, exports]` tuple only - the third and fourth facade and `hasModuleSyntax` booleans are dropped.
* Imports drop the parsed attribute list `at` (the attribute source remains recoverable via the `a` attributes index).
* Exports drop the statement start `ss`.
All other fields are identical to the full build. For CSP eval disabled support, the equivalent asm.js build is available as `es-module-lexer/minimal/js`.
### Import Attributes
The `a` field provides the index of the start of the `{` attributes bracket, or -1 for no attributes.
The list of attribute key and value pairs are provided on the `at` field (full build only):
```js
const [imports] = parse(`
import json from './foo.json' with { type: 'json' };
import './foo.css' with { type: 'css' };
import pkg from 'pkg' with { type: 'json', integrity: 'sha384-...' };
`);
// Returns [['type', 'json']]
imports[0].at;
// Returns [['type', 'css']]
imports[1].at;
// Multiple attributes
// Returns [['type', 'json'], ['integrity', 'sha384-...']]
imports[2].at;
```
The `at` field is an array of `[key, value]` tuples, or `null` if there are no attributes.
Both keys and values support escape sequences:
```js
const [imports] = parse(`
import foo from './foo.js' with { "custom-key": "value" };
import bar from './bar.js' with { "key\\nwith\\nnewlines": "value\\twith\\ttabs" };
`);
// Quoted keys are unquoted
// Returns [['custom-key', 'value']]
imports[0].at;
// Escape sequences are processed
// Returns [['key\nwith\nnewlines', 'value\twith\ttabs']]
imports[1].at;
```
### Escape Sequences
To handle escape sequences in specifier strings, the `.n` field of imported specifiers will be provided where possible.
For dynamic import expressions, this field will be empty if not a valid JS string.
### Facade Detection
Facade modules that only use import / export syntax can be detected via the third return value (full build only):
```js
const [,, facade] = parse(`
export * from 'external';
import * as ns from 'external2';
export { a as b } from 'external3';
export { ns };
`);
facade === true;
```
### ESM Detection
Modules that uses ESM syntaxes can be detected via the fourth return value (full build only):
```js
const [,,, hasModuleSyntax] = parse(`
export {}
`);
hasModuleSyntax === true;
```
Dynamic imports are ignored since they can be used in Non-ESM files.
```js
const [,,, hasModuleSyntax] = parse(`
import('./foo.js')
`);
hasModuleSyntax === false;
```
### Environment Support
Node.js 10+, and [all browsers with Web Assembly support](https://caniuse.com/#feat=wasm).
### Grammar Support
* Token state parses all line comments, block comments, strings, template strings, blocks, parens and punctuators.
* Division operator / regex token ambiguity is handled via backtracking checks against punctuator prefixes, including closing brace or paren backtracking.
* Always correctly parses valid JS source, but may parse invalid JS source without errors.
### Limitations
The lexing approach is designed to deal with the full language grammar including RegEx / division operator ambiguity through backtracking and paren / brace tracking.
Because it lexes rather than fully parses, the analysis is not a validation pass: valid JS source is always analyzed correctly, but some invalid source is accepted without an error rather than rejected. For example `export const = 1` lexes to an empty exports list instead of throwing. Callers that need to reject invalid source should run a validating parser separately.
Multiple exports per declaration (`export var a = 'asdf', q = z`) and renamed destructured exports (`export var { a: b } = asdf`) are detected correctly; earlier versions missed `q` and `b` in these forms.
### Benchmarks
Benchmarks can be run with `npm run bench`.
Current results on a standard desktop machine:
#### Wasm Build
```
Module load time
> 1ms
Cold Run, All Samples
test/samples/*.js (3057 KiB)
> 13ms
Warm Runs (average of 25 runs)
test/samples/angular.js (719 KiB)
> 1ms
test/samples/angular.min.js (188 KiB)
> 1ms
test/samples/d3.js (491 KiB)
> 2ms
test/samples/d3.min.js (274 KiB)
> 1.04ms
test/samples/magic-string.js (34 KiB)
> 0ms
test/samples/magic-string.min.js (20 KiB)
> 0ms
test/samples/rollup.js (902 KiB)
> 3ms
test/samples/rollup.min.js (429 KiB)
> 2ms
Warm Runs, All Samples (average of 25 runs)
test/samples/*.js (3057 KiB)
> 10m
```
### JS Build (asm.js)
```
Module load time
> 1ms
Cold Run, All Samples
test/samples/*.js (3057 KiB)
> 92ms
Warm Runs (average of 25 runs)
test/samples/angular.js (719 KiB)
> 3.6ms
test/samples/angular.min.js (188 KiB)
> 2ms
test/samples/d3.js (491 KiB)
> 4ms
test/samples/d3.min.js (274 KiB)
> 2.52ms
test/samples/magic-string.js (34 KiB)
> 0ms
test/samples/magic-string.min.js (20 KiB)
> 0ms
test/samples/rollup.js (902 KiB)
> 6ms
test/samples/rollup.min.js (429 KiB)
> 3.2ms
Warm Runs, All Samples (average of 25 runs)
test/samples/*.js (3057 KiB)
> 20.88ms
```
### Building
This project uses [Chomp](https://chompbuild.com) for building.
With Chomp installed, download the WASI SDK 12.0 from https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-12.
- [Linux](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz)
- [Windows (MinGW)](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-mingw.tar.gz)
- [macOS](https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz)
Locate the WASI-SDK as a sibling folder, or customize the path via the `WASI_PATH` environment variable.
Emscripten emsdk is also assumed to be a sibling folder or via the `EMSDK_PATH` environment variable.
Example setup:
```
git clone https://github.com:guybedford/es-module-lexer
git clone https://github.com/emscripten-core/emsdk
cd emsdk
git checkout 1.40.1-fastcomp
./emsdk install 1.40.1-fastcomp
cd ..
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
gunzip wasi-sdk-12.0-linux.tar.gz
tar -xf wasi-sdk-12.0-linux.tar
mv wasi-sdk-12.0-linux.tar wasi-sdk-12.0
cargo install chompbuild
cd es-module-lexer
chomp test
```
For the `asm.js` build, git clone `emsdk` from is assumed to be a sibling folder as well.
### License
MIT
[actions-image]: https://github.com/guybedford/es-module-lexer/actions/workflows/build.yml/badge.svg
[actions-url]: https://github.com/guybedford/es-module-lexer/actions/workflows/build.yml

View File

@@ -0,0 +1,212 @@
"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.valueMatchesSomeSpecifier = exports.typeMatchesSomeSpecifier = exports.typeOrValueSpecifiersSchema = void 0;
exports.typeMatchesSpecifier = typeMatchesSpecifier;
exports.valueMatchesSpecifier = valueMatchesSpecifier;
const types_1 = require("@typescript-eslint/types");
const tsutils = __importStar(require("ts-api-utils"));
const specifierNameMatches_1 = require("./typeOrValueSpecifiers/specifierNameMatches");
const typeDeclaredInFile_1 = require("./typeOrValueSpecifiers/typeDeclaredInFile");
const typeDeclaredInLib_1 = require("./typeOrValueSpecifiers/typeDeclaredInLib");
const typeDeclaredInPackageDeclarationFile_1 = require("./typeOrValueSpecifiers/typeDeclaredInPackageDeclarationFile");
exports.typeOrValueSpecifiersSchema = {
items: {
oneOf: [
{
type: 'string',
},
{
additionalProperties: false,
properties: {
from: {
enum: ['file'],
type: 'string',
},
name: {
oneOf: [
{
type: 'string',
},
{
items: {
type: 'string',
},
minItems: 1,
type: 'array',
uniqueItems: true,
},
],
},
path: {
type: 'string',
},
},
required: ['from', 'name'],
type: 'object',
},
{
additionalProperties: false,
properties: {
from: {
enum: ['lib'],
type: 'string',
},
name: {
oneOf: [
{
type: 'string',
},
{
items: {
type: 'string',
},
minItems: 1,
type: 'array',
uniqueItems: true,
},
],
},
},
required: ['from', 'name'],
type: 'object',
},
{
additionalProperties: false,
properties: {
from: {
enum: ['package'],
type: 'string',
},
name: {
oneOf: [
{
type: 'string',
},
{
items: {
type: 'string',
},
minItems: 1,
type: 'array',
uniqueItems: true,
},
],
},
package: {
type: 'string',
},
},
required: ['from', 'name', 'package'],
type: 'object',
},
],
},
type: 'array',
};
function typeMatchesSpecifier(type, specifier, program) {
if (tsutils.isUnionType(type)) {
return type.types.every(t => typeMatchesSpecifier(t, specifier, program));
}
const wholeTypeMatches = (() => {
if (tsutils.isIntrinsicErrorType(type)) {
return false;
}
if (typeof specifier === 'string') {
return (0, specifierNameMatches_1.specifierNameMatches)(type, specifier);
}
if (!(0, specifierNameMatches_1.specifierNameMatches)(type, specifier.name)) {
return false;
}
const symbol = type.getSymbol() ?? type.aliasSymbol;
const declarations = symbol?.getDeclarations() ?? [];
const declarationFiles = declarations.map(declaration => declaration.getSourceFile());
switch (specifier.from) {
case 'file':
return (0, typeDeclaredInFile_1.typeDeclaredInFile)(specifier.path, declarationFiles, program);
case 'lib':
return (0, typeDeclaredInLib_1.typeDeclaredInLib)(declarationFiles, program);
case 'package':
return (0, typeDeclaredInPackageDeclarationFile_1.typeDeclaredInPackageDeclarationFile)(specifier.package, declarations, declarationFiles, program);
}
})();
if (wholeTypeMatches) {
return true;
}
if (tsutils.isIntersectionType(type) &&
tsutils
.intersectionConstituents(type)
.some(part => typeMatchesSpecifier(part, specifier, program))) {
return true;
}
return false;
}
const typeMatchesSomeSpecifier = (type, specifiers = [], program) => specifiers.some(specifier => typeMatchesSpecifier(type, specifier, program));
exports.typeMatchesSomeSpecifier = typeMatchesSomeSpecifier;
const getSpecifierNames = (specifierName) => {
return typeof specifierName === 'string' ? [specifierName] : specifierName;
};
const getStaticName = (node) => {
if (node.type === types_1.AST_NODE_TYPES.Identifier ||
node.type === types_1.AST_NODE_TYPES.JSXIdentifier ||
node.type === types_1.AST_NODE_TYPES.PrivateIdentifier) {
return node.name;
}
if (node.type === types_1.AST_NODE_TYPES.Literal && typeof node.value === 'string') {
return node.value;
}
return undefined;
};
function valueMatchesSpecifier(node, specifier, program, type) {
const staticName = getStaticName(node);
if (!staticName) {
return false;
}
if (typeof specifier === 'string') {
return specifier === staticName;
}
if (!getSpecifierNames(specifier.name).includes(staticName)) {
return false;
}
if (specifier.from === 'package') {
const symbol = type.getSymbol() ?? type.aliasSymbol;
const declarations = symbol?.getDeclarations() ?? [];
const declarationFiles = declarations.map(declaration => declaration.getSourceFile());
return (0, typeDeclaredInPackageDeclarationFile_1.typeDeclaredInPackageDeclarationFile)(specifier.package, declarations, declarationFiles, program);
}
return true;
}
const valueMatchesSomeSpecifier = (node, specifiers = [], program, type) => specifiers.some(specifier => valueMatchesSpecifier(node, specifier, program, type));
exports.valueMatchesSomeSpecifier = valueMatchesSomeSpecifier;

View File

@@ -0,0 +1,179 @@
import { Readable, Writable } from 'node:stream'
export default CacheHandler
declare namespace CacheHandler {
export type CacheMethods = 'GET' | 'HEAD' | 'OPTIONS' | 'TRACE'
export interface CacheHandlerOptions {
store: CacheStore
cacheByDefault?: number
type?: CacheOptions['type']
}
export interface CacheOptions {
store?: CacheStore
/**
* The methods to cache
* Note we can only cache safe methods. Unsafe methods (i.e. PUT, POST)
* invalidate the cache for a origin.
* @see https://www.rfc-editor.org/rfc/rfc9111.html#name-invalidating-stored-respons
* @see https://www.rfc-editor.org/rfc/rfc9110#section-9.2.1
*/
methods?: CacheMethods[]
/**
* RFC9111 allows for caching responses that we aren't explicitly told to
* cache or to not cache.
* @see https://www.rfc-editor.org/rfc/rfc9111.html#section-3-5
* @default undefined
*/
cacheByDefault?: number
/**
* TODO docs
* @default 'shared'
*/
type?: 'shared' | 'private'
/**
* Array of origins to cache. Only requests to these origins will be cached.
* Supports strings (case insensitive) and RegExp patterns.
* @default undefined (cache all origins)
*/
origins?: (string | RegExp)[]
}
export interface CacheControlDirectives {
'max-stale'?: number;
'min-fresh'?: number;
'max-age'?: number;
's-maxage'?: number;
'stale-while-revalidate'?: number;
'stale-if-error'?: number;
public?: true;
private?: true | string[];
'no-store'?: true;
'no-cache'?: true | string[];
'must-revalidate'?: true;
'proxy-revalidate'?: true;
immutable?: true;
'no-transform'?: true;
'must-understand'?: true;
'only-if-cached'?: true;
}
export interface CacheKey {
origin: string
method: string
path: string
headers?: Record<string, string | string[]>
}
export interface CacheValue {
statusCode: number
statusMessage: string
headers: Record<string, string | string[]>
vary?: Record<string, string | string[] | null>
etag?: string
cacheControlDirectives?: CacheControlDirectives
cachedAt: number
staleAt: number
deleteAt: number
}
export interface DeleteByUri {
origin: string
method: string
path: string
}
type GetResult = {
statusCode: number
statusMessage: string
headers: Record<string, string | string[]>
vary?: Record<string, string | string[] | null>
etag?: string
body?: Readable | Iterable<Buffer> | AsyncIterable<Buffer> | Buffer | Iterable<string> | AsyncIterable<string> | string
cacheControlDirectives: CacheControlDirectives,
cachedAt: number
staleAt: number
deleteAt: number
}
/**
* Underlying storage provider for cached responses
*/
export interface CacheStore {
get(key: CacheKey): GetResult | Promise<GetResult | undefined> | undefined
createWriteStream(key: CacheKey, val: CacheValue): Writable | undefined
delete(key: CacheKey): void | Promise<void>
}
export interface MemoryCacheStoreOpts {
/**
* @default Infinity
*/
maxCount?: number
/**
* @default Infinity
*/
maxSize?: number
/**
* @default Infinity
*/
maxEntrySize?: number
errorCallback?: (err: Error) => void
}
export class MemoryCacheStore implements CacheStore {
constructor (opts?: MemoryCacheStoreOpts)
get (key: CacheKey): GetResult | Promise<GetResult | undefined> | undefined
createWriteStream (key: CacheKey, value: CacheValue): Writable | undefined
delete (key: CacheKey): void | Promise<void>
}
export interface SqliteCacheStoreOpts {
/**
* Location of the database
* @default ':memory:'
*/
location?: string
/**
* @default Infinity
*/
maxCount?: number
/**
* @default Infinity
*/
maxEntrySize?: number
}
export class SqliteCacheStore implements CacheStore {
constructor (opts?: SqliteCacheStoreOpts)
/**
* Closes the connection to the database
*/
close (): void
get (key: CacheKey): GetResult | Promise<GetResult | undefined> | undefined
createWriteStream (key: CacheKey, value: CacheValue): Writable | undefined
delete (key: CacheKey): void | Promise<void>
}
}

View File

@@ -0,0 +1,9 @@
import type { UUIDTypes } from './types.js';
export { DNS, URL } from './v35.js';
declare function v5(value: string | Uint8Array, namespace: UUIDTypes, buf?: undefined, offset?: number): string;
declare function v5<TBuf extends Uint8Array = Uint8Array>(value: string | Uint8Array, namespace: UUIDTypes, buf: TBuf, offset?: number): TBuf;
declare namespace v5 {
var DNS: string;
var URL: string;
}
export default v5;

View File

@@ -0,0 +1 @@
{"version":3,"file":"typePredicateKind.enum.d.ts","sourceRoot":"","sources":["../../src/enums/typePredicateKind.enum.ts"],"names":[],"mappings":"AAEA,oBAAY,iBAAiB;IACzB,IAAI,IAAI;IACR,UAAU,IAAI;IACd,WAAW,IAAI;IACf,iBAAiB,IAAI;CACxB"}

View File

@@ -0,0 +1,31 @@
// Zod 3 compat layer
import * as core from "../core/index.js";
/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
export const ZodIssueCode = {
invalid_type: "invalid_type",
too_big: "too_big",
too_small: "too_small",
invalid_format: "invalid_format",
not_multiple_of: "not_multiple_of",
unrecognized_keys: "unrecognized_keys",
invalid_union: "invalid_union",
invalid_key: "invalid_key",
invalid_element: "invalid_element",
invalid_value: "invalid_value",
custom: "custom",
};
export { $brand, config } from "../core/index.js";
/** @deprecated Use `z.config(params)` instead. */
export function setErrorMap(map) {
core.config({
customError: map,
});
}
/** @deprecated Use `z.config()` instead. */
export function getErrorMap() {
return core.config().customError;
}
/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
export var ZodFirstPartyTypeKind;
(function (ZodFirstPartyTypeKind) {
})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));

View File

@@ -0,0 +1,27 @@
const postfixRE = /[?#].*$/;
function cleanUrl(url) {
return url.replace(postfixRE, "");
}
function createManualModuleSource(moduleUrl, exports$1, globalAccessor = "\"__vitest_mocker__\"") {
const source = `
const __factoryModule__ = await globalThis[${globalAccessor}].getFactoryModule("${moduleUrl}");
`;
const keys = exports$1.map((name, index) => {
return `let __${index} = __factoryModule__["${name}"]
export { __${index} as "${name}" }`;
}).join("\n");
let code = `${source}\n${keys}`;
// this prevents recursion
code += `
if (__factoryModule__.__factoryPromise != null) {
__factoryModule__.__factoryPromise.then((resolvedModule) => {
${exports$1.map((name, index) => {
return `__${index} = resolvedModule["${name}"];`;
}).join("\n")}
})
}
`;
return code;
}
export { cleanUrl as a, createManualModuleSource as c };

View File

@@ -0,0 +1,4 @@
import type * as ts from 'typescript';
import type { ASTMaps } from './convert';
import type { ParserServices } from './parser-options';
export declare function createParserServices(astMaps: ASTMaps, program: ts.Program | null): ParserServices;

View File

@@ -0,0 +1,8 @@
import type * as ts from 'typescript/lib/tsserverlibrary';
/**
* Parses a TSConfig file using the same logic as tsserver.
*
* @param configFile the path to the tsconfig.json file, relative to `projectDirectory`
* @param projectDirectory the project directory to use as the CWD, defaults to `process.cwd()`
*/
export declare function getParsedConfigFile(tsserver: typeof ts, configFile: string, projectDirectory?: string): ts.ParsedCommandLine;

View File

@@ -0,0 +1,29 @@
function _ts_generator(thisArg, body) {
var f, y, t, _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
return d(g, "next", { value: verb(0) }), d(g, "throw", { value: verb(1) }), d(g, "return", { value: verb(2) }), typeof Symbol === "function" && d(g, Symbol.iterator, { value: function () { return this; } }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
export { _ts_generator as _ };

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeToCurve = exports.hashToCurve = exports.secp256r1 = exports.p256 = void 0;
const nist_ts_1 = require("./nist.js");
/** @deprecated use `import { p256 } from '@noble/curves/nist.js';` */
exports.p256 = nist_ts_1.p256;
/** @deprecated use `import { p256 } from '@noble/curves/nist.js';` */
exports.secp256r1 = nist_ts_1.p256;
/** @deprecated use `import { p256_hasher } from '@noble/curves/nist.js';` */
exports.hashToCurve = (() => nist_ts_1.p256_hasher.hashToCurve)();
/** @deprecated use `import { p256_hasher } from '@noble/curves/nist.js';` */
exports.encodeToCurve = (() => nist_ts_1.p256_hasher.encodeToCurve)();
//# sourceMappingURL=p256.js.map

View File

@@ -0,0 +1,168 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://json-schema.org/draft-07/schema#",
"title": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"nonNegativeInteger": {
"type": "integer",
"minimum": 0
},
"nonNegativeIntegerDefault0": {
"allOf": [
{ "$ref": "#/definitions/nonNegativeInteger" },
{ "default": 0 }
]
},
"simpleTypes": {
"enum": [
"array",
"boolean",
"integer",
"null",
"number",
"object",
"string"
]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true,
"default": []
}
},
"type": ["object", "boolean"],
"properties": {
"$id": {
"type": "string",
"format": "uri-reference"
},
"$schema": {
"type": "string",
"format": "uri"
},
"$ref": {
"type": "string",
"format": "uri-reference"
},
"$comment": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": true,
"readOnly": {
"type": "boolean",
"default": false
},
"examples": {
"type": "array",
"items": true
},
"multipleOf": {
"type": "number",
"exclusiveMinimum": 0
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "number"
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "number"
},
"maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
"minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": { "$ref": "#" },
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": true
},
"maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
"minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
"uniqueItems": {
"type": "boolean",
"default": false
},
"contains": { "$ref": "#" },
"maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
"minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": { "$ref": "#" },
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"propertyNames": { "format": "regex" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"propertyNames": { "$ref": "#" },
"const": true,
"enum": {
"type": "array",
"items": true,
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"format": { "type": "string" },
"contentMediaType": { "type": "string" },
"contentEncoding": { "type": "string" },
"if": {"$ref": "#"},
"then": {"$ref": "#"},
"else": {"$ref": "#"},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" }
},
"default": true
}

View File

@@ -0,0 +1,114 @@
{
"name": "uuid",
"version": "14.0.1",
"description": "RFC9562 UUIDs",
"type": "module",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"keywords": [
"uuid",
"guid",
"rfc4122",
"rfc9562"
],
"license": "MIT",
"bin": {
"uuid": "./dist-node/bin/uuid"
},
"sideEffects": false,
"types": "./dist/index.d.ts",
"exports": {
".": {
"node": {
"types": "./dist/index.d.ts",
"default": "./dist-node/index.js"
},
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"files": [
"dist",
"dist-node",
"!**/test"
],
"devDependencies": {
"@biomejs/biome": "2.4.10",
"@commitlint/cli": "20.5.0",
"@commitlint/config-conventional": "20.5.0",
"bundlewatch": "0.4.1",
"commander": "14.0.3",
"globals": "17.4.0",
"jest": "30.3.0",
"lefthook": "1.11.13",
"lint-staged": "16.4.0",
"neostandard": "0.13.0",
"npm-run-all2": "8.0.4",
"prettier": "3.8.3",
"release-please": "17.3.0",
"runmd": "2.1.1",
"standard-version": "9.5.0",
"typescript": "5.4.3"
},
"optionalDevDependencies": {
"@wdio/browserstack-service": "9.27.0",
"@wdio/cli": "9.27.0",
"@wdio/jasmine-framework": "9.27.0",
"@wdio/local-runner": "9.27.0",
"@wdio/spec-reporter": "9.27.0",
"@wdio/static-server-service": "9.27.0"
},
"scripts": {
"build": "./scripts/build.sh",
"build:watch": "tsc --watch -p tsconfig.json",
"bundlewatch": "npm run pretest:browser && bundlewatch --config bundlewatch.config.json",
"docs:diff": "npm run docs && git diff README.md",
"docs": "npm run build && npx runmd --output=README.md README_js.md",
"biome:check": "biome check .",
"biome:fix": "biome check --write .",
"examples:browser:rollup:build": "cd examples/browser-rollup && npm run build",
"examples:browser:webpack:build": "cd examples/browser-webpack && npm run build",
"examples:node:esmodules:test": "cd examples/node-esmodules && npm test",
"examples:node:jest:test": "cd examples/node-jest && npm test",
"examples:node:typescript:test": "cd examples/typescript && npm test",
"lint": "npm run biome:check",
"md": "runmd --watch --output=README.md README_js.md",
"prepack": "npm run build -- --no-pack",
"prepare": "lefthook install",
"prepublishOnly": "npm run build",
"pretest:benchmark": "npm run build",
"pretest:browser": "./scripts/iodd && npm run build && npm-run-all --parallel examples:browser:**",
"pretest:node": "npm run build",
"pretest": "npm run build",
"format": "biome format --write .",
"format:check": "biome format --check .",
"release": "standard-version --no-verify",
"test:benchmark": "cd examples/benchmark && npm test",
"test:browser": "wdio run ./wdio.conf.js",
"test:node": "npm-run-all --parallel examples:node:**",
"test:watch": "node --test --enable-source-maps --watch dist-node/test/*.js",
"test": "node --test --enable-source-maps dist-node/test/*.js"
},
"repository": {
"type": "git",
"url": "https://github.com/uuidjs/uuid.git"
},
"lint-staged": {
"*": [
"biome check --write --no-errors-on-unmatched"
]
},
"standard-version": {
"scripts": {
"postchangelog": "biome format --write CHANGELOG.md"
}
},
"packageManager": "npm@11.12.1"
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"encoder.generated.d.ts","sourceRoot":"","sources":["../../../src/api/node/encoder.generated.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAiBR,IAAI,EAMP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAOhD,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAuBxD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CA6CpD"}

View File

@@ -0,0 +1,11 @@
'use strict'
const { createWarning } = require('..')
const CUSTDEP001 = createWarning({
name: 'DeprecationWarning',
code: 'CUSTDEP001',
message: 'This is a deprecation warning'
})
CUSTDEP001()

View File

@@ -0,0 +1,27 @@
import type { TSESTree } from '@typescript-eslint/utils';
import type { RuleContext } from '@typescript-eslint/utils/ts-eslint';
/**
* Parses a syntactically possible `Promise.then()` call. Does not check the
* type of the callee.
*/
export declare function parseThenCall(node: TSESTree.CallExpression, context: RuleContext<string, unknown[]>): {
onFulfilled?: TSESTree.Expression | undefined;
onRejected?: TSESTree.Expression | undefined;
object: TSESTree.Expression;
} | undefined;
/**
* Parses a syntactically possible `Promise.catch()` call. Does not check the
* type of the callee.
*/
export declare function parseCatchCall(node: TSESTree.CallExpression, context: RuleContext<string, unknown[]>): {
onRejected?: TSESTree.Expression | undefined;
object: TSESTree.Expression;
} | undefined;
/**
* Parses a syntactically possible `Promise.finally()` call. Does not check the
* type of the callee.
*/
export declare function parseFinallyCall(node: TSESTree.CallExpression, context: RuleContext<string, unknown[]>): {
object: TSESTree.Expression;
onFinally?: TSESTree.Expression | undefined;
} | undefined;

View File

@@ -0,0 +1,40 @@
import { expect, test } from "vitest";
import * as z from "zod/v4";
test("passing validations", () => {
const example1 = z.custom<number>((x) => typeof x === "number");
example1.parse(1234);
expect(() => example1.parse({})).toThrow();
});
test("string params", () => {
const example1 = z.custom<number>((x) => typeof x !== "number", "customerr");
const result = example1.safeParse(1234);
expect(result.success).toEqual(false);
expect(JSON.stringify(result.error).includes("customerr")).toEqual(true);
});
test("instanceof", () => {
const fn = (value: string) => Uint8Array.from(Buffer.from(value, "base64"));
// Argument of type 'ZodCustom<Uint8Array<ArrayBuffer>, unknown>' is not assignable to parameter of type '$ZodType<any, Uint8Array<ArrayBuffer>>'.
z.string().transform(fn).pipe(z.instanceof(Uint8Array));
});
test("non-continuable by default", () => {
const A = z
.custom<string>((val) => typeof val === "string")
.transform((_) => {
throw new Error("Invalid input");
});
expect(A.safeParse(123).error!).toMatchInlineSnapshot(`
[ZodError: [
{
"code": "custom",
"path": [],
"message": "Invalid input"
}
]]
`);
});

View File

@@ -0,0 +1,74 @@
/**
* @fileoverview Rule to disallow use of the new operator with the `Symbol` object
* @author Alberto Rodríguez
* @deprecated in ESLint v9.0.0
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "Disallow `new` operators with the `Symbol` object",
recommended: false,
url: "https://eslint.org/docs/latest/rules/no-new-symbol",
},
deprecated: {
message: "The rule was replaced with a more general rule.",
url: "https://eslint.org/docs/latest/use/migrate-to-9.0.0#eslint-recommended",
deprecatedSince: "9.0.0",
availableUntil: "11.0.0",
replacedBy: [
{
rule: {
name: "no-new-native-nonconstructor",
url: "https://eslint.org/docs/latest/rules/no-new-native-nonconstructor",
},
},
],
},
schema: [],
messages: {
noNewSymbol: "`Symbol` cannot be called as a constructor.",
},
},
create(context) {
const sourceCode = context.sourceCode;
return {
"Program:exit"(node) {
const globalScope = sourceCode.getScope(node);
const variable = globalScope.set.get("Symbol");
if (variable && variable.defs.length === 0) {
variable.references.forEach(ref => {
const idNode = ref.identifier;
const parent = idNode.parent;
if (
parent &&
parent.type === "NewExpression" &&
parent.callee === idNode
) {
context.report({
node: idNode,
messageId: "noNewSymbol",
});
}
});
}
},
};
},
};

View File

@@ -0,0 +1,18 @@
// Code generated by Herebyfile.mjs generate:enums from internal/ast/utilities.go. DO NOT EDIT.
export var OuterExpressionKinds;
(function (OuterExpressionKinds) {
OuterExpressionKinds[OuterExpressionKinds["Parentheses"] = 1] = "Parentheses";
OuterExpressionKinds[OuterExpressionKinds["TypeAssertions"] = 2] = "TypeAssertions";
OuterExpressionKinds[OuterExpressionKinds["NonNullAssertions"] = 4] = "NonNullAssertions";
OuterExpressionKinds[OuterExpressionKinds["PartiallyEmittedExpressions"] = 8] = "PartiallyEmittedExpressions";
OuterExpressionKinds[OuterExpressionKinds["ExpressionsWithTypeArguments"] = 16] = "ExpressionsWithTypeArguments";
OuterExpressionKinds[OuterExpressionKinds["Satisfies"] = 32] = "Satisfies";
OuterExpressionKinds[OuterExpressionKinds["ExcludeJSDocTypeAssertion"] = 64] = "ExcludeJSDocTypeAssertion";
OuterExpressionKinds[OuterExpressionKinds["Assignments"] = 128] = "Assignments";
OuterExpressionKinds[OuterExpressionKinds["Comma"] = 256] = "Comma";
OuterExpressionKinds[OuterExpressionKinds["Assertions"] = 38] = "Assertions";
OuterExpressionKinds[OuterExpressionKinds["All"] = 63] = "All";
OuterExpressionKinds[OuterExpressionKinds["AllExceptAssertionsOrExpressionsWithTypeArguments"] = 9] = "AllExceptAssertionsOrExpressionsWithTypeArguments";
OuterExpressionKinds[OuterExpressionKinds["ExpressionTypePassthrough"] = 385] = "ExpressionTypePassthrough";
})(OuterExpressionKinds || (OuterExpressionKinds = {}));
//# sourceMappingURL=outerExpressionKinds.js.map

View File

@@ -0,0 +1,13 @@
Copyright (c) 2017, Emil Bay <github@tixz.dk>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,517 @@
'use strict';
const StreamValues = require('stream-json/streamers/StreamValues');
const Verifier = require('stream-json/utils/Verifier');
const JSONstringify = require('json-stringify-safe');
const uuid = require('uuid').v4;
const generateRequest = require('./generateRequest');
/** * @namespace */
const Utils = module.exports;
// same reference as other files use, for tidyness
const utils = Utils;
Utils.request = generateRequest;
/**
* Generates a JSON-RPC 1.0 or 2.0 response
* @param {Object} error Error member
* @param {Object} result Result member
* @param {String|Number|null} id Id of request
* @param {Number} version JSON-RPC version to use
* @return {Object} A JSON-RPC 1.0 or 2.0 response
*/
Utils.response = function(error, result, id, version) {
id = typeof(id) === 'undefined' || id === null ? null : id;
error = typeof(error) === 'undefined' || error === null ? null : error;
version = typeof(version) === 'undefined' || version === null ? 2 : version;
result = typeof(result) === 'undefined' || result === null ? null : result;
const response = (version === 2) ? { jsonrpc: "2.0", id: id } : { id: id };
// errors are always included in version 1
if(version === 1) {
response.error = error;
}
// one or the other with precedence for errors
if(error) {
response.error = error;
} else {
response.result = result;
}
return response;
};
/**
* Generates a random UUID
* @return {String}
*/
Utils.generateId = function() {
return uuid();
};
/**
* Merges properties of object b into object a
* @param {...Object} args Objects to be merged
* @return {Object}
* @private
*/
Utils.merge = function(...args) {
return args.reduce(function (out, obj) {
return {...out, ...obj};
}, {});
};
/**
* Parses an incoming stream for requests using stream-json
* @param {Stream} stream
* @param {Object} options
* @param {Function} onRequest Called once for stream errors and an unlimited amount of times for valid requests
*/
Utils.parseStream = function(stream, options, onRequest) {
const onError = Utils.once(onRequest);
const onSuccess = (...args) => onRequest(null, ...args);
const verifier = new Verifier({jsonStreaming: true});
const parser = StreamValues.withParser();
parser.on('data', function(obj) {
let data = obj.value;
// apply reviver walk function to prevent stringify/parse again
if(typeof options.reviver === 'function') {
data = Utils.walk({'': data}, '', options.reviver);
}
onSuccess(data);
});
parser.on('error', onError);
verifier.on('error', onError);
stream.on('error', onError);
stream.pipe(verifier);
stream.pipe(parser);
};
/**
* Returns a function that can only be called once
* @param {Function} fn
* @return {Function}
*/
Utils.once = function (fn) {
let called = false;
let lastRetval;
return function (...args) {
if (called) return lastRetval;
called = true;
lastRetval = fn.call(this, ...args);
};
};
/**
* Returns true if obj is a plain object (not null)
* @param {*} obj
* @return {Boolean}
*/
Utils.isPlainObject = function (obj) {
return typeof obj === 'object' && obj !== null;
};
/**
* Converts an object to an array
* @param {*} obj
* @return {Array}
*/
Utils.toArray = function (obj) {
if (Array.isArray(obj)) return obj;
if (Utils.isPlainObject(obj)) return Object.keys(obj).map(function (key) {
return obj[key];
});
if (!obj) return [];
return Array.prototype.slice.call(obj);
};
/**
* Converts an object to a plain object
* @param {*} obj
* @return {Object}
*/
Utils.toPlainObject = function (value) {
value = Object(value);
const result = {};
for (const key in value) {
result[key] = value[key];
}
return result;
};
/**
* Picks keys from obj
* @param {Object} obj
* @param {String[]} keys
* @return {Object}
*/
Utils.pick = function (obj, keys) {
return keys.reduce(function (out, key) {
out[key] = obj[key];
return out;
}, {});
};
/**
* Helper to parse a stream and interpret it as JSON
* @param {Stream} stream Stream instance
* @param {Function} [options] Optional options for JSON.parse
* @param {Function} callback
*/
Utils.parseBody = function(stream, options, callback) {
callback = Utils.once(callback);
let data = '';
stream.setEncoding('utf8');
stream.on('data', function(str) {
data += str;
});
stream.on('error', function(err) {
callback(err);
});
stream.on('end', function() {
utils.JSON.parse(data, options, function(err, request) {
if(err) {
callback(err);
return;
}
callback(null, request);
});
});
};
/**
* Returns a HTTP request listener bound to the server in the argument.
* @param {http.Server} self Instance of a HTTP server
* @param {JaysonServer} server Instance of JaysonServer (typically jayson.Server)
* @return {Function}
* @private
*/
Utils.getHttpListener = function(self, server) {
return function(req, res) {
const options = self.options || {};
server.emit('http request', req);
// 405 method not allowed if not POST
if(!Utils.isMethod(req, 'POST')) {
return respond('Method Not Allowed', 405, {'allow': 'POST'});
}
// 415 unsupported media type if Content-Type is not correct
if(!Utils.isContentType(req, 'application/json')) {
return respond('Unsupported Media Type', 415);
}
Utils.parseBody(req, options, function(err, request) {
if(err) {
return respond(err, 400);
}
server.call(request, function(error, success) {
const response = error || success;
if(!response) {
// no response received at all, must be a notification
return respond('', 204);
}
utils.JSON.stringify(response, options, function(err, body) {
if(err) {
return respond(err, 500);
}
const headers = {
'content-length': Buffer.byteLength(body, options.encoding),
'content-type': 'application/json; charset=utf-8'
};
respond(body, 200, headers);
});
});
});
function respond(response, code, headers) {
const body = response instanceof Error ? response.toString() : response;
server.emit('http response', res, req);
res.writeHead(code, headers || {});
res.end(body);
}
};
};
/**
* Determines if a HTTP Request comes with a specific Content-Type
* @param {ServerRequest} request
* @param {String} type
* @return {Boolean}
* @private
*/
Utils.isContentType = function(request, type) {
request = request || {headers: {}};
const contentType = request.headers['content-type'] || '';
return RegExp(type, 'i').test(contentType);
};
/**
* Determines if a HTTP Request is of a specific method
* @param {ServerRequest} request
* @param {String} method
* @return {Boolean}
* @private
*/
Utils.isMethod = function(request, method) {
method = (method || '').toUpperCase();
return (request.method || '') === method;
};
/**
* Recursively walk an object and apply a function on its members
* @param {Object} holder The object to walk
* @param {String} key The key to look at
* @param {Function} fn The function to apply to members
* @return {Object}
*/
Utils.walk = function(holder, key, fn) {
let k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = Utils.walk(value, k, fn);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return fn.call(holder, key, value);
};
/** * @namespace */
Utils.JSON = {};
/**
* Parses a JSON string and then invokes the given callback
* @param {String} str The string to parse
* @param {Object} options Object with options, possibly holding a "reviver" function
* @param {Function} callback
*/
Utils.JSON.parse = function(str, options, callback) {
let reviver = null;
let obj = null;
options = options || {};
if(typeof options.reviver === 'function') {
reviver = options.reviver;
}
try {
obj = JSON.parse.apply(JSON, [str, reviver].filter(v => v));
} catch(err) {
callback(err);
return;
}
callback(null, obj);
};
/**
* Stringifies JSON and then invokes the given callback
* @param {Object} obj The object to stringify
* @param {Object} options Object with options, possibly holding a "replacer" function
* @param {Function} callback
*/
Utils.JSON.stringify = function(obj, options, callback) {
let replacer = null;
let str = null;
options = options || {};
if(typeof options.replacer === 'function') {
replacer = options.replacer;
}
try {
str = JSONstringify.apply(JSON, [obj, replacer].filter(v => v));
} catch(err) {
callback(err);
return;
}
callback(null, str);
};
/** * @namespace */
Utils.Request = {};
/**
* Determines if the passed request is a batch request
* @param {Object} request The request
* @return {Boolean}
*/
Utils.Request.isBatch = function(request) {
return Array.isArray(request);
};
/**
* Determines if the passed request is a notification request
* @param {Object} request The request
* @return {Boolean}
*/
Utils.Request.isNotification = function(request) {
return Boolean(
request
&& !Utils.Request.isBatch(request)
&& (typeof(request.id) === 'undefined'
|| request.id === null)
);
};
/**
* Determines if the passed request is a valid JSON-RPC 2.0 Request
* @param {Object} request The request
* @return {Boolean}
*/
Utils.Request.isValidVersionTwoRequest = function(request) {
return Boolean(
request
&& typeof(request) === 'object'
&& request.jsonrpc === '2.0'
&& typeof(request.method) === 'string'
&& (
typeof(request.params) === 'undefined'
|| Array.isArray(request.params)
|| (request.params && typeof(request.params) === 'object')
)
&& (
typeof(request.id) === 'undefined'
|| typeof(request.id) === 'string'
|| typeof(request.id) === 'number'
|| request.id === null
)
);
};
/**
* Determines if the passed request is a valid JSON-RPC 1.0 Request
* @param {Object} request The request
* @return {Boolean}
*/
Utils.Request.isValidVersionOneRequest = function(request) {
return Boolean(
request
&& typeof(request) === 'object'
&& typeof(request.method) === 'string'
&& Array.isArray(request.params)
&& typeof(request.id) !== 'undefined'
);
};
/**
* Determines if the passed request is a valid JSON-RPC Request
* @param {Object} request The request
* @param {Number} [version=2] JSON-RPC version 1 or 2
* @return {Boolean}
*/
Utils.Request.isValidRequest = function(request, version) {
version = version === 1 ? 1 : 2;
return Boolean(
request
&& (
(version === 1 && Utils.Request.isValidVersionOneRequest(request)) ||
(version === 2 && Utils.Request.isValidVersionTwoRequest(request))
)
);
};
/** * @namespace */
Utils.Response = {};
/**
* Determines if the passed error is a valid JSON-RPC error response
* @param {Object} error The error
* @param {Number} [version=2] JSON-RPC version 1 or 2
* @return {Boolean}
*/
Utils.Response.isValidError = function(error, version) {
version = version === 1 ? 1 : 2;
return Boolean(
version === 1 && (
typeof(error) !== 'undefined'
&& error !== null
)
|| version === 2 && (
error
&& typeof(error.code) === 'number'
&& parseInt(error.code, 10) === error.code
&& typeof(error.message) === 'string'
)
);
};
/**
* Determines if the passed object is a valid JSON-RPC response
* @param {Object} response The response
* @param {Number} [version=2] JSON-RPC version 1 or 2
* @return {Boolean}
*/
Utils.Response.isValidResponse = function(response, version) {
version = version === 1 ? 1 : 2;
return Boolean(
response !== null
&& typeof response === 'object'
&& (version === 2 && (
// check version
response.jsonrpc === '2.0'
&& (
// check id
response.id === null
|| typeof response.id === 'string'
|| typeof response.id === 'number'
)
&& (
// result and error do not exist at the same time
(typeof response.result === 'undefined' && typeof response.error !== 'undefined')
|| (typeof response.result !== 'undefined' && typeof response.error === 'undefined')
)
&& (
// check result
(typeof response.result !== 'undefined')
// check error object
|| (
response.error !== null
&& typeof response.error === 'object'
&& typeof response.error.code === 'number'
// check error.code is integer
&& ((response.error.code | 0) === response.error.code)
&& typeof response.error.message === 'string'
)
)
)
|| version === 1 && (
typeof response.id !== 'undefined'
&& (
// result and error relation (the other null if one is not)
(typeof response.result !== 'undefined' && response.error === null)
|| (typeof response.error !== 'undefined' && response.result === null)
)
))
);
};

View File

@@ -0,0 +1,9 @@
import type { ArrayOfStringOrObject, RuleListener } from 'eslint/lib/rules/no-restricted-imports';
import type { InferMessageIdsTypeFromRule, InferOptionsTypeFromRule } from '../util';
declare const baseRule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"everything" | "everythingWithCustomMessage" | "importName" | "importNameWithCustomMessage" | "path" | "pathWithCustomMessage" | "patternWithCustomMessage" | "patterns", ArrayOfStringOrObject | [import("eslint/lib/rules/no-restricted-imports").ObjectOfPathsAndPatterns], unknown, RuleListener>;
export type Options = InferOptionsTypeFromRule<typeof baseRule>;
export type MessageIds = InferMessageIdsTypeFromRule<typeof baseRule>;
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"everything" | "everythingWithCustomMessage" | "importName" | "importNameWithCustomMessage" | "path" | "pathWithCustomMessage" | "patternWithCustomMessage" | "patterns", ArrayOfStringOrObject | [import("eslint/lib/rules/no-restricted-imports").ObjectOfPathsAndPatterns], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1,267 @@
'use strict'
/* eslint no-prototype-builtins: 0 */
const test = require('node:test')
const assert = require('node:assert')
const { sink, once } = require('./helper')
const pino = require('../')
// Silence all warnings for this test
process.removeAllListeners('warning')
process.on('warning', () => {})
test('adds additional levels', async () => {
const stream = sink()
const logger = pino({
customLevels: {
foo: 35,
bar: 45
}
}, stream)
logger.foo('test')
const { level } = await once(stream, 'data')
assert.equal(level, 35)
})
test('custom levels does not override default levels', async () => {
const stream = sink()
const logger = pino({
customLevels: {
foo: 35
}
}, stream)
logger.info('test')
const { level } = await once(stream, 'data')
assert.equal(level, 30)
})
test('default levels can be redefined using custom levels', async () => {
const stream = sink()
const logger = pino({
customLevels: {
info: 35,
debug: 45
},
useOnlyCustomLevels: true
}, stream)
assert.equal(logger.hasOwnProperty('info'), true)
logger.info('test')
const { level } = await once(stream, 'data')
assert.equal(level, 35)
})
test('custom levels overrides default level label if use useOnlyCustomLevels', async () => {
const stream = sink()
const logger = pino({
customLevels: {
foo: 35
},
useOnlyCustomLevels: true,
level: 'foo'
}, stream)
assert.equal(logger.hasOwnProperty('info'), false)
})
test('custom levels overrides default level value if use useOnlyCustomLevels', async () => {
const stream = sink()
const logger = pino({
customLevels: {
foo: 35
},
useOnlyCustomLevels: true,
level: 35
}, stream)
assert.equal(logger.hasOwnProperty('info'), false)
})
test('custom levels are inherited by children', async () => {
const stream = sink()
const logger = pino({
customLevels: {
foo: 35
}
}, stream)
logger.child({ childMsg: 'ok' }).foo('test')
const { msg, childMsg, level } = await once(stream, 'data')
assert.equal(level, 35)
assert.equal(childMsg, 'ok')
assert.equal(msg, 'test')
})
test('custom levels can be specified on child bindings', async () => {
const stream = sink()
const logger = pino(stream).child({
childMsg: 'ok'
}, {
customLevels: {
foo: 35
}
})
logger.foo('test')
const { msg, childMsg, level } = await once(stream, 'data')
assert.equal(level, 35)
assert.equal(childMsg, 'ok')
assert.equal(msg, 'test')
})
test('customLevels property child bindings does not get logged', async () => {
const stream = sink()
const logger = pino(stream).child({
childMsg: 'ok'
}, {
customLevels: {
foo: 35
}
})
logger.foo('test')
const { customLevels } = await once(stream, 'data')
assert.equal(customLevels, undefined)
})
test('throws when specifying pre-existing parent labels via child bindings', async () => {
const stream = sink()
assert.throws(
() => pino({
customLevels: {
foo: 35
}
}, stream).child({}, {
customLevels: {
foo: 45
}
}),
/levels cannot be overridden/
)
})
test('throws when specifying pre-existing parent values via child bindings', async () => {
const stream = sink()
assert.throws(
() => pino({
customLevels: {
foo: 35
}
}, stream).child({}, {
customLevels: {
bar: 35
}
}),
/pre-existing level values cannot be used for new levels/
)
})
test('throws when specifying core values via child bindings', async () => {
const stream = sink()
assert.throws(
() => pino(stream).child({}, {
customLevels: {
foo: 30
}
}),
/pre-existing level values cannot be used for new levels/
)
})
test('throws when useOnlyCustomLevels is set true without customLevels', async () => {
const stream = sink()
assert.throws(
() => pino({
useOnlyCustomLevels: true
}, stream),
/customLevels is required if useOnlyCustomLevels is set true/
)
})
test('custom level on one instance does not affect other instances', async () => {
pino({
customLevels: {
foo: 37
}
})
assert.equal(typeof pino().foo, 'undefined')
})
test('setting level below or at custom level will successfully log', async () => {
const stream = sink()
const instance = pino({ customLevels: { foo: 35 } }, stream)
instance.level = 'foo'
instance.info('nope')
instance.foo('bar')
const { msg } = await once(stream, 'data')
assert.equal(msg, 'bar')
})
test('custom level below level threshold will not log', async () => {
const stream = sink()
const instance = pino({ customLevels: { foo: 15 } }, stream)
instance.level = 'info'
instance.info('bar')
instance.foo('nope')
const { msg } = await once(stream, 'data')
assert.equal(msg, 'bar')
})
test('does not share custom level state across siblings', async () => {
const stream = sink()
const logger = pino(stream)
logger.child({}, {
customLevels: { foo: 35 }
})
assert.doesNotThrow(() => {
logger.child({}, {
customLevels: { foo: 35 }
})
})
})
test('custom level does not affect the levels serializer', async () => {
const stream = sink()
const logger = pino({
customLevels: {
foo: 35,
bar: 45
},
formatters: {
level (label, number) {
return { priority: number }
}
}
}, stream)
logger.foo('test')
const { priority } = await once(stream, 'data')
assert.equal(priority, 35)
})
test('When useOnlyCustomLevels is set to true, the level formatter should only get custom levels', async () => {
const stream = sink()
const logger = pino({
customLevels: {
answer: 42
},
useOnlyCustomLevels: true,
level: 42,
formatters: {
level (label, number) {
assert.equal(label, 'answer')
assert.equal(number, 42)
return { level: number }
}
}
}, stream)
logger.answer('test')
const { level } = await once(stream, 'data')
assert.equal(level, 42)
})