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,495 @@
# ws: a Node.js WebSocket library
[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws)
[![CI](https://img.shields.io/github/workflow/status/websockets/ws/CI/master?label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster)
[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws)
ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and
server implementation.
Passes the quite extensive Autobahn test suite: [server][server-report],
[client][client-report].
**Note**: This module does not work in the browser. The client in the docs is a
reference to a back end with the role of a client in the WebSocket
communication. Browser clients must use the native
[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
object. To make the same code work seamlessly on Node.js and the browser, you
can use one of the many wrappers available on npm, like
[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
## Table of Contents
- [Protocol support](#protocol-support)
- [Installing](#installing)
- [Opt-in for performance](#opt-in-for-performance)
- [API docs](#api-docs)
- [WebSocket compression](#websocket-compression)
- [Usage examples](#usage-examples)
- [Sending and receiving text data](#sending-and-receiving-text-data)
- [Sending binary data](#sending-binary-data)
- [Simple server](#simple-server)
- [External HTTP/S server](#external-https-server)
- [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server)
- [Client authentication](#client-authentication)
- [Server broadcast](#server-broadcast)
- [echo.websocket.org demo](#echowebsocketorg-demo)
- [Use the Node.js streams API](#use-the-nodejs-streams-api)
- [Other examples](#other-examples)
- [FAQ](#faq)
- [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
- [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
- [How to connect via a proxy?](#how-to-connect-via-a-proxy)
- [Changelog](#changelog)
- [License](#license)
## Protocol support
- **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
- **HyBi drafts 13-17** (Current default, alternatively option
`protocolVersion: 13`)
## Installing
```
npm install ws
```
### Opt-in for performance
There are 2 optional modules that can be installed along side with the ws
module. These modules are binary addons which improve certain operations.
Prebuilt binaries are available for the most popular platforms so you don't
necessarily need to have a C++ compiler installed on your machine.
- `npm install --save-optional bufferutil`: Allows to efficiently perform
operations such as masking and unmasking the data payload of the WebSocket
frames.
- `npm install --save-optional utf-8-validate`: Allows to efficiently check if a
message contains valid UTF-8.
## API docs
See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and
utility functions.
## WebSocket compression
ws supports the [permessage-deflate extension][permessage-deflate] which enables
the client and server to negotiate a compression algorithm and its parameters,
and then selectively apply it to the data payloads of each WebSocket message.
The extension is disabled by default on the server and enabled by default on the
client. It adds a significant overhead in terms of performance and memory
consumption so we suggest to enable it only if it is really needed.
Note that Node.js has a variety of issues with high-performance compression,
where increased concurrency, especially on Linux, can lead to [catastrophic
memory fragmentation][node-zlib-bug] and slow performance. If you intend to use
permessage-deflate in production, it is worthwhile to set up a test
representative of your workload and ensure Node.js/zlib will handle it with
acceptable performance and memory usage.
Tuning of permessage-deflate can be done via the options defined below. You can
also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
See [the docs][ws-server-options] for more options.
```js
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 8080,
perMessageDeflate: {
zlibDeflateOptions: {
// See zlib defaults.
chunkSize: 1024,
memLevel: 7,
level: 3
},
zlibInflateOptions: {
chunkSize: 10 * 1024
},
// Other options settable:
clientNoContextTakeover: true, // Defaults to negotiated value.
serverNoContextTakeover: true, // Defaults to negotiated value.
serverMaxWindowBits: 10, // Defaults to negotiated value.
// Below options specified as default values.
concurrencyLimit: 10, // Limits zlib concurrency for perf.
threshold: 1024 // Size (in bytes) below which messages
// should not be compressed.
}
});
```
The client will only use the extension if it is supported and enabled on the
server. To always disable the extension on the client set the
`perMessageDeflate` option to `false`.
```js
const WebSocket = require('ws');
const ws = new WebSocket('ws://www.host.com/path', {
perMessageDeflate: false
});
```
## Usage examples
### Sending and receiving text data
```js
const WebSocket = require('ws');
const ws = new WebSocket('ws://www.host.com/path');
ws.on('open', function open() {
ws.send('something');
});
ws.on('message', function incoming(data) {
console.log(data);
});
```
### Sending binary data
```js
const WebSocket = require('ws');
const ws = new WebSocket('ws://www.host.com/path');
ws.on('open', function open() {
const array = new Float32Array(5);
for (var i = 0; i < array.length; ++i) {
array[i] = i / 2;
}
ws.send(array);
});
```
### Simple server
```js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
```
### External HTTP/S server
```js
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
const server = https.createServer({
cert: fs.readFileSync('/path/to/cert.pem'),
key: fs.readFileSync('/path/to/key.pem')
});
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
server.listen(8080);
```
### Multiple servers sharing a single HTTP/S server
```js
const http = require('http');
const WebSocket = require('ws');
const url = require('url');
const server = http.createServer();
const wss1 = new WebSocket.Server({ noServer: true });
const wss2 = new WebSocket.Server({ noServer: true });
wss1.on('connection', function connection(ws) {
// ...
});
wss2.on('connection', function connection(ws) {
// ...
});
server.on('upgrade', function upgrade(request, socket, head) {
const pathname = url.parse(request.url).pathname;
if (pathname === '/foo') {
wss1.handleUpgrade(request, socket, head, function done(ws) {
wss1.emit('connection', ws, request);
});
} else if (pathname === '/bar') {
wss2.handleUpgrade(request, socket, head, function done(ws) {
wss2.emit('connection', ws, request);
});
} else {
socket.destroy();
}
});
server.listen(8080);
```
### Client authentication
```js
const http = require('http');
const WebSocket = require('ws');
const server = http.createServer();
const wss = new WebSocket.Server({ noServer: true });
wss.on('connection', function connection(ws, request, client) {
ws.on('message', function message(msg) {
console.log(`Received message ${msg} from user ${client}`);
});
});
server.on('upgrade', function upgrade(request, socket, head) {
// This function is not defined on purpose. Implement it with your own logic.
authenticate(request, (err, client) => {
if (err || !client) {
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
socket.destroy();
return;
}
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit('connection', ws, request, client);
});
});
});
server.listen(8080);
```
Also see the provided [example][session-parse-example] using `express-session`.
### Server broadcast
A client WebSocket broadcasting to all connected WebSocket clients, including
itself.
```js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(data) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
});
});
```
A client WebSocket broadcasting to every other connected WebSocket clients,
excluding itself.
```js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(data) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
});
});
```
### echo.websocket.org demo
```js
const WebSocket = require('ws');
const ws = new WebSocket('wss://echo.websocket.org/', {
origin: 'https://websocket.org'
});
ws.on('open', function open() {
console.log('connected');
ws.send(Date.now());
});
ws.on('close', function close() {
console.log('disconnected');
});
ws.on('message', function incoming(data) {
console.log(`Roundtrip time: ${Date.now() - data} ms`);
setTimeout(function timeout() {
ws.send(Date.now());
}, 500);
});
```
### Use the Node.js streams API
```js
const WebSocket = require('ws');
const ws = new WebSocket('wss://echo.websocket.org/', {
origin: 'https://websocket.org'
});
const duplex = WebSocket.createWebSocketStream(ws, { encoding: 'utf8' });
duplex.pipe(process.stdout);
process.stdin.pipe(duplex);
```
### Other examples
For a full example with a browser client communicating with a ws server, see the
examples folder.
Otherwise, see the test cases.
## FAQ
### How to get the IP address of the client?
The remote IP address can be obtained from the raw socket.
```js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws, req) {
const ip = req.socket.remoteAddress;
});
```
When the server runs behind a proxy like NGINX, the de-facto standard is to use
the `X-Forwarded-For` header.
```js
wss.on('connection', function connection(ws, req) {
const ip = req.headers['x-forwarded-for'].split(',')[0].trim();
});
```
### How to detect and close broken connections?
Sometimes the link between the server and the client can be interrupted in a way
that keeps both the server and the client unaware of the broken state of the
connection (e.g. when pulling the cord).
In these cases ping messages can be used as a means to verify that the remote
endpoint is still responsive.
```js
const WebSocket = require('ws');
function noop() {}
function heartbeat() {
this.isAlive = true;
}
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.isAlive = true;
ws.on('pong', heartbeat);
});
const interval = setInterval(function ping() {
wss.clients.forEach(function each(ws) {
if (ws.isAlive === false) return ws.terminate();
ws.isAlive = false;
ws.ping(noop);
});
}, 30000);
wss.on('close', function close() {
clearInterval(interval);
});
```
Pong messages are automatically sent in response to ping messages as required by
the spec.
Just like the server example above your clients might as well lose connection
without knowing it. You might want to add a ping listener on your clients to
prevent that. A simple implementation would be:
```js
const WebSocket = require('ws');
function heartbeat() {
clearTimeout(this.pingTimeout);
// Use `WebSocket#terminate()`, which immediately destroys the connection,
// instead of `WebSocket#close()`, which waits for the close timer.
// Delay should be equal to the interval at which your server
// sends out pings plus a conservative assumption of the latency.
this.pingTimeout = setTimeout(() => {
this.terminate();
}, 30000 + 1000);
}
const client = new WebSocket('wss://echo.websocket.org/');
client.on('open', heartbeat);
client.on('ping', heartbeat);
client.on('close', function clear() {
clearTimeout(this.pingTimeout);
});
```
### How to connect via a proxy?
Use a custom `http.Agent` implementation like [https-proxy-agent][] or
[socks-proxy-agent][].
## Changelog
We're using the GitHub [releases][changelog] for changelog entries.
## License
[MIT](LICENSE)
[changelog]: https://github.com/websockets/ws/releases
[client-report]: http://websockets.github.io/ws/autobahn/clients/
[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
[node-zlib-bug]: https://github.com/nodejs/node/issues/8871
[node-zlib-deflaterawdocs]:
https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
[permessage-deflate]: https://tools.ietf.org/html/rfc7692
[server-report]: http://websockets.github.io/ws/autobahn/servers/
[session-parse-example]: ./examples/express-session-parse
[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
[ws-server-options]:
https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback

View File

@@ -0,0 +1,455 @@
import type { $ZodCheck, $ZodStringFormats } from "./checks.js";
import { $constructor } from "./core.js";
import type { $ZodType } from "./schemas.js";
import type { StandardSchemaV1 } from "./standard-schema.js";
import * as util from "./util.js";
///////////////////////////
//// base type ////
///////////////////////////
export interface $ZodIssueBase {
readonly code?: string;
readonly input?: unknown;
readonly path: PropertyKey[];
readonly message: string;
}
////////////////////////////////
//// issue subtypes ////
////////////////////////////////
export type $ZodInvalidTypeExpected =
| "string"
| "number"
| "int"
| "boolean"
| "bigint"
| "symbol"
| "undefined"
| "null"
| "never"
| "void"
| "date"
| "array"
| "object"
| "tuple"
| "record"
| "map"
| "set"
| "file"
| "nonoptional"
| "nan"
| "function"
| (string & {}); // class names for instanceof
export interface $ZodIssueInvalidType<Input = unknown> extends $ZodIssueBase {
readonly code: "invalid_type";
readonly expected: $ZodInvalidTypeExpected;
readonly input?: Input;
}
export interface $ZodIssueTooBig<Input = unknown> extends $ZodIssueBase {
readonly code: "too_big";
readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
readonly maximum: number | bigint;
readonly inclusive?: boolean;
readonly exact?: boolean;
readonly input?: Input;
}
export interface $ZodIssueTooSmall<Input = unknown> extends $ZodIssueBase {
readonly code: "too_small";
readonly origin: "number" | "int" | "bigint" | "date" | "string" | "array" | "set" | "file" | (string & {});
readonly minimum: number | bigint;
/** True if the allowable range includes the minimum */
readonly inclusive?: boolean;
/** True if the allowed value is fixed (e.g.` z.length(5)`), not a range (`z.minLength(5)`) */
readonly exact?: boolean;
readonly input?: Input;
}
export interface $ZodIssueInvalidStringFormat extends $ZodIssueBase {
readonly code: "invalid_format";
readonly format: $ZodStringFormats | (string & {});
readonly pattern?: string;
readonly input?: string;
}
export interface $ZodIssueNotMultipleOf<Input extends number | bigint = number | bigint> extends $ZodIssueBase {
readonly code: "not_multiple_of";
readonly divisor: number;
readonly input?: Input;
}
export interface $ZodIssueUnrecognizedKeys extends $ZodIssueBase {
readonly code: "unrecognized_keys";
readonly keys: string[];
readonly input?: Record<string, unknown>;
}
interface $ZodIssueInvalidUnionNoMatch extends $ZodIssueBase {
readonly code: "invalid_union";
readonly errors: $ZodIssue[][];
readonly input?: unknown;
readonly discriminator?: string | undefined;
readonly options?: util.Primitive[];
readonly inclusive?: true;
}
interface $ZodIssueInvalidUnionMultipleMatch extends $ZodIssueBase {
readonly code: "invalid_union";
readonly errors: [];
readonly input?: unknown;
readonly discriminator?: string | undefined;
readonly inclusive: false;
}
export type $ZodIssueInvalidUnion = $ZodIssueInvalidUnionNoMatch | $ZodIssueInvalidUnionMultipleMatch;
export interface $ZodIssueInvalidKey<Input = unknown> extends $ZodIssueBase {
readonly code: "invalid_key";
readonly origin: "map" | "record";
readonly issues: $ZodIssue[];
readonly input?: Input;
}
export interface $ZodIssueInvalidElement<Input = unknown> extends $ZodIssueBase {
readonly code: "invalid_element";
readonly origin: "map" | "set";
readonly key: unknown;
readonly issues: $ZodIssue[];
readonly input?: Input;
}
export interface $ZodIssueInvalidValue<Input = unknown> extends $ZodIssueBase {
readonly code: "invalid_value";
readonly values: util.Primitive[];
readonly input?: Input;
}
export interface $ZodIssueCustom extends $ZodIssueBase {
readonly code: "custom";
readonly params?: Record<string, any> | undefined;
readonly input?: unknown;
}
////////////////////////////////////////////
//// first-party string formats ////
////////////////////////////////////////////
export interface $ZodIssueStringCommonFormats extends $ZodIssueInvalidStringFormat {
format: Exclude<$ZodStringFormats, "regex" | "jwt" | "starts_with" | "ends_with" | "includes">;
}
export interface $ZodIssueStringInvalidRegex extends $ZodIssueInvalidStringFormat {
format: "regex";
pattern: string;
}
export interface $ZodIssueStringInvalidJWT extends $ZodIssueInvalidStringFormat {
format: "jwt";
algorithm?: string;
}
export interface $ZodIssueStringStartsWith extends $ZodIssueInvalidStringFormat {
format: "starts_with";
prefix: string;
}
export interface $ZodIssueStringEndsWith extends $ZodIssueInvalidStringFormat {
format: "ends_with";
suffix: string;
}
export interface $ZodIssueStringIncludes extends $ZodIssueInvalidStringFormat {
format: "includes";
includes: string;
}
export type $ZodStringFormatIssues =
| $ZodIssueStringCommonFormats
| $ZodIssueStringInvalidRegex
| $ZodIssueStringInvalidJWT
| $ZodIssueStringStartsWith
| $ZodIssueStringEndsWith
| $ZodIssueStringIncludes;
////////////////////////
//// utils /////
////////////////////////
export type $ZodIssue =
| $ZodIssueInvalidType
| $ZodIssueTooBig
| $ZodIssueTooSmall
| $ZodIssueInvalidStringFormat
| $ZodIssueNotMultipleOf
| $ZodIssueUnrecognizedKeys
| $ZodIssueInvalidUnion
| $ZodIssueInvalidKey
| $ZodIssueInvalidElement
| $ZodIssueInvalidValue
| $ZodIssueCustom;
export type $ZodIssueCode = $ZodIssue["code"];
export type $ZodInternalIssue<T extends $ZodIssueBase = $ZodIssue> = T extends any ? RawIssue<T> : never;
type RawIssue<T extends $ZodIssueBase> = T extends any
? util.Flatten<
util.MakePartial<T, "message" | "path"> & {
/** The input data */
readonly input: unknown;
/** The schema or check that originated this issue. */
readonly inst?: $ZodType | $ZodCheck;
/** If `true`, Zod will continue executing checks/refinements after this issue. */
readonly continue?: boolean | undefined;
} & Record<string, unknown>
>
: never;
export type $ZodRawIssue<T extends $ZodIssueBase = $ZodIssue> = $ZodInternalIssue<T>;
export interface $ZodErrorMap<T extends $ZodIssueBase = $ZodIssue> {
// biome-ignore lint:
(issue: $ZodRawIssue<T>): { message: string } | string | undefined | null;
}
//////////////////////// ERROR CLASS ////////////////////////
// const ZOD_ERROR: symbol = Symbol.for("{{zod.error}}");
export interface $ZodError<T = unknown> extends Error {
type: T;
issues: $ZodIssue[];
_zod: {
output: T;
def: $ZodIssue[];
};
stack?: string;
name: string;
}
const initializer = (inst: $ZodError, def: $ZodIssue[]): void => {
inst.name = "$ZodError";
Object.defineProperty(inst, "_zod", {
value: inst._zod,
enumerable: false,
});
Object.defineProperty(inst, "issues", {
value: def,
enumerable: false,
});
inst.message = JSON.stringify(def, util.jsonStringifyReplacer, 2);
Object.defineProperty(inst, "toString", {
value: () => inst.message,
enumerable: false,
});
};
export const $ZodError: $constructor<$ZodError> = $constructor("$ZodError", initializer);
interface $ZodRealError<T = any> extends $ZodError<T> {}
export const $ZodRealError: $constructor<$ZodRealError> = $constructor("$ZodError", initializer, { Parent: Error });
/////////////////// ERROR UTILITIES ////////////////////////
// flatten
export type $ZodFlattenedError<T, U = string> = _FlattenedError<T, U>;
type _FlattenedError<T, U = string> = {
formErrors: U[];
fieldErrors: {
[P in keyof T]?: U[];
};
};
export function flattenError<T>(error: $ZodError<T>): _FlattenedError<T>;
export function flattenError<T, U>(error: $ZodError<T>, mapper?: (issue: $ZodIssue) => U): _FlattenedError<T, U>;
export function flattenError<T, U>(error: $ZodError<T>, mapper = (issue: $ZodIssue) => issue.message as U) {
const fieldErrors: Record<PropertyKey, any> = {};
const formErrors: U[] = [];
for (const sub of error.issues) {
if (sub.path.length > 0) {
fieldErrors[sub.path[0]!] = fieldErrors[sub.path[0]!] || [];
fieldErrors[sub.path[0]!].push(mapper(sub));
} else {
formErrors.push(mapper(sub));
}
}
return { formErrors, fieldErrors };
}
type _ZodFormattedError<T, U = string> = T extends [any, ...any[]]
? { [K in keyof T]?: $ZodFormattedError<T[K], U> }
: T extends any[]
? { [k: number]: $ZodFormattedError<T[number], U> }
: T extends object
? util.Flatten<{ [K in keyof T]?: $ZodFormattedError<T[K], U> }>
: any;
export type $ZodFormattedError<T, U = string> = {
_errors: U[];
} & util.Flatten<_ZodFormattedError<T, U>>;
export function formatError<T>(error: $ZodError<T>): $ZodFormattedError<T>;
export function formatError<T, U>(error: $ZodError<T>, mapper?: (issue: $ZodIssue) => U): $ZodFormattedError<T, U>;
export function formatError<T, U>(error: $ZodError<T>, mapper = (issue: $ZodIssue) => issue.message as U) {
const fieldErrors: $ZodFormattedError<T> = { _errors: [] } as any;
const processError = (error: { issues: $ZodIssue[] }, path: PropertyKey[] = []) => {
for (const issue of error.issues) {
if (issue.code === "invalid_union" && issue.errors.length) {
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
} else if (issue.code === "invalid_key") {
processError({ issues: issue.issues }, [...path, ...issue.path]);
} else if (issue.code === "invalid_element") {
processError({ issues: issue.issues }, [...path, ...issue.path]);
} else {
const fullpath = [...path, ...issue.path];
if (fullpath.length === 0) {
(fieldErrors as any)._errors.push(mapper(issue));
} else {
let curr: any = fieldErrors;
let i = 0;
while (i < fullpath.length) {
const el = fullpath[i]!;
const terminal = i === fullpath.length - 1;
if (!terminal) {
curr[el] = curr[el] || { _errors: [] };
} else {
curr[el] = curr[el] || { _errors: [] };
curr[el]._errors.push(mapper(issue));
}
curr = curr[el];
i++;
}
}
}
}
};
processError(error);
return fieldErrors;
}
export type $ZodErrorTree<T, U = string> = T extends util.Primitive
? { errors: U[] }
: T extends [any, ...any[]]
? { errors: U[]; items?: { [K in keyof T]?: $ZodErrorTree<T[K], U> } }
: T extends any[]
? { errors: U[]; items?: Array<$ZodErrorTree<T[number], U>> }
: T extends object
? {
errors: U[];
properties?: { [K in keyof T]?: $ZodErrorTree<T[K], U> };
}
: { errors: U[] };
export function treeifyError<T>(error: $ZodError<T>): $ZodErrorTree<T>;
export function treeifyError<T, U>(error: $ZodError<T>, mapper?: (issue: $ZodIssue) => U): $ZodErrorTree<T, U>;
export function treeifyError<T, U>(error: $ZodError<T>, mapper = (issue: $ZodIssue) => issue.message as U) {
const result: $ZodErrorTree<T, U> = { errors: [] } as any;
const processError = (error: { issues: $ZodIssue[] }, path: PropertyKey[] = []) => {
for (const issue of error.issues) {
if (issue.code === "invalid_union" && issue.errors.length) {
// regular union error
issue.errors.map((issues) => processError({ issues }, [...path, ...issue.path]));
} else if (issue.code === "invalid_key") {
processError({ issues: issue.issues }, [...path, ...issue.path]);
} else if (issue.code === "invalid_element") {
processError({ issues: issue.issues }, [...path, ...issue.path]);
} else {
const fullpath = [...path, ...issue.path];
if (fullpath.length === 0) {
result.errors.push(mapper(issue));
continue;
}
let curr: any = result;
let i = 0;
while (i < fullpath.length) {
const el = fullpath[i]!;
const terminal = i === fullpath.length - 1;
if (typeof el === "string") {
curr.properties ??= {};
curr.properties[el] ??= { errors: [] };
curr = curr.properties[el];
} else {
curr.items ??= [];
curr.items[el] ??= { errors: [] };
curr = curr.items[el];
}
if (terminal) {
curr.errors.push(mapper(issue));
}
i++;
}
}
}
};
processError(error);
return result;
}
/** Format a ZodError as a human-readable string in the following form.
*
* From
*
* ```ts
* ZodError {
* issues: [
* {
* expected: 'string',
* code: 'invalid_type',
* path: [ 'username' ],
* message: 'Invalid input: expected string'
* },
* {
* expected: 'number',
* code: 'invalid_type',
* path: [ 'favoriteNumbers', 1 ],
* message: 'Invalid input: expected number'
* }
* ];
* }
* ```
*
* to
*
* ```
* username
* ✖ Expected number, received string at "username
* favoriteNumbers[0]
* ✖ Invalid input: expected number
* ```
*/
export function toDotPath(_path: readonly (string | number | symbol | StandardSchemaV1.PathSegment)[]): string {
const segs: string[] = [];
const path: PropertyKey[] = _path.map((seg: any) => (typeof seg === "object" ? seg.key : seg));
for (const seg of path) {
if (typeof seg === "number") segs.push(`[${seg}]`);
else if (typeof seg === "symbol") segs.push(`[${JSON.stringify(String(seg))}]`);
else if (/[^\w$]/.test(seg)) segs.push(`[${JSON.stringify(seg)}]`);
else {
if (segs.length) segs.push(".");
segs.push(seg);
}
}
return segs.join("");
}
export function prettifyError(error: StandardSchemaV1.FailureResult): string {
const lines: string[] = [];
// sort by path length
const issues = [...error.issues].sort((a, b) => (a.path ?? []).length - (b.path ?? []).length);
// Process each issue
for (const issue of issues) {
lines.push(`✖ ${issue.message}`);
if (issue.path?.length) lines.push(` → at ${toDotPath(issue.path)}`);
}
// Convert Map to formatted string
return lines.join("\n");
}

View File

@@ -0,0 +1,196 @@
/**
* @fileoverview The schema to validate language options
* @author Nicholas C. Zakas
*/
"use strict";
//-----------------------------------------------------------------------------
// Data
//-----------------------------------------------------------------------------
const globalVariablesValues = new Set([
true,
"true",
"writable",
"writeable",
false,
"false",
"readonly",
"readable",
null,
"off",
]);
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Check if a value is a non-null object.
* @param {any} value The value to check.
* @returns {boolean} `true` if the value is a non-null object.
*/
function isNonNullObject(value) {
return typeof value === "object" && value !== null;
}
/**
* Check if a value is a non-null non-array object.
* @param {any} value The value to check.
* @returns {boolean} `true` if the value is a non-null non-array object.
*/
function isNonArrayObject(value) {
return isNonNullObject(value) && !Array.isArray(value);
}
/**
* Check if a value is undefined.
* @param {any} value The value to check.
* @returns {boolean} `true` if the value is undefined.
*/
function isUndefined(value) {
return typeof value === "undefined";
}
//-----------------------------------------------------------------------------
// Schemas
//-----------------------------------------------------------------------------
/**
* Validates the ecmaVersion property.
* @param {string|number} ecmaVersion The value to check.
* @returns {void}
* @throws {TypeError} If the value is invalid.
*/
function validateEcmaVersion(ecmaVersion) {
if (isUndefined(ecmaVersion)) {
throw new TypeError(
'Key "ecmaVersion": Expected an "ecmaVersion" property.',
);
}
if (typeof ecmaVersion !== "number" && ecmaVersion !== "latest") {
throw new TypeError(
'Key "ecmaVersion": Expected a number or "latest".',
);
}
}
/**
* Validates the sourceType property.
* @param {string} sourceType The value to check.
* @returns {void}
* @throws {TypeError} If the value is invalid.
*/
function validateSourceType(sourceType) {
if (
typeof sourceType !== "string" ||
!/^(?:script|module|commonjs)$/u.test(sourceType)
) {
throw new TypeError(
'Key "sourceType": Expected "script", "module", or "commonjs".',
);
}
}
/**
* Validates the globals property.
* @param {Object} globals The value to check.
* @returns {void}
* @throws {TypeError} If the value is invalid.
*/
function validateGlobals(globals) {
if (!isNonArrayObject(globals)) {
throw new TypeError('Key "globals": Expected an object.');
}
for (const key of Object.keys(globals)) {
// avoid hairy edge case
if (key === "__proto__") {
continue;
}
if (key !== key.trim()) {
throw new TypeError(
`Key "globals": Global "${key}" has leading or trailing whitespace.`,
);
}
if (!globalVariablesValues.has(globals[key])) {
throw new TypeError(
`Key "globals": Key "${key}": Expected "readonly", "writable", or "off".`,
);
}
}
}
/**
* Validates the parser property.
* @param {Object} parser The value to check.
* @returns {void}
* @throws {TypeError} If the value is invalid.
*/
function validateParser(parser) {
if (
!parser ||
typeof parser !== "object" ||
(typeof parser.parse !== "function" &&
typeof parser.parseForESLint !== "function")
) {
throw new TypeError(
'Key "parser": Expected object with parse() or parseForESLint() method.',
);
}
}
/**
* Validates the language options.
* @param {Object} languageOptions The language options to validate.
* @returns {void}
* @throws {TypeError} If the language options are invalid.
*/
function validateLanguageOptions(languageOptions) {
if (!isNonArrayObject(languageOptions)) {
throw new TypeError("Expected an object.");
}
const {
ecmaVersion,
sourceType,
globals,
parser,
parserOptions,
...otherOptions
} = languageOptions;
if ("ecmaVersion" in languageOptions) {
validateEcmaVersion(ecmaVersion);
}
if ("sourceType" in languageOptions) {
validateSourceType(sourceType);
}
if ("globals" in languageOptions) {
validateGlobals(globals);
}
if ("parser" in languageOptions) {
validateParser(parser);
}
if ("parserOptions" in languageOptions) {
if (!isNonArrayObject(parserOptions)) {
throw new TypeError('Key "parserOptions": Expected an object.');
}
}
const otherOptionKeys = Object.keys(otherOptions);
if (otherOptionKeys.length > 0) {
throw new TypeError(`Unexpected key "${otherOptionKeys[0]}" found.`);
}
}
module.exports = { validateLanguageOptions };

View File

@@ -0,0 +1,101 @@
import { expect, test } from "vitest";
import * as z from "zod/v4";
test("string to number pipe", () => {
const schema = z.string().transform(Number).pipe(z.number());
expect(schema.parse("1234")).toEqual(1234);
});
test("string to number pipe async", async () => {
const schema = z
.string()
.transform(async (val) => Number(val))
.pipe(z.number());
expect(await schema.parseAsync("1234")).toEqual(1234);
});
test("string with default fallback", () => {
const stringWithDefault = z
.pipe(
z.transform((v) => (v === "none" ? undefined : v)),
z.string()
)
.catch("default");
expect(stringWithDefault.parse("ok")).toBe("ok");
expect(stringWithDefault.parse(undefined)).toBe("default");
expect(stringWithDefault.parse("none")).toBe("default");
expect(stringWithDefault.parse(15)).toBe("default");
});
test("continue on non-fatal errors", () => {
const schema = z
.string()
.refine((c) => c === "1234", "A")
.transform((val) => Number(val))
.refine((c) => c === 1234, "B");
schema.parse("1234");
expect(schema.safeParse("4321")).toMatchInlineSnapshot(`
{
"error": [ZodError: [
{
"code": "custom",
"path": [],
"message": "A"
}
]],
"success": false,
}
`);
});
test("break on fatal errors", () => {
const schema = z
.string()
.refine((c) => c === "1234", { message: "A", abort: true })
.transform((val) => Number(val))
.refine((c) => c === 1234, "B");
schema.parse("1234");
expect(schema.safeParse("4321")).toMatchInlineSnapshot(`
{
"error": [ZodError: [
{
"code": "custom",
"path": [],
"message": "A"
}
]],
"success": false,
}
`);
});
test("reverse parsing with pipe", () => {
const schema = z.string().pipe(z.string());
// Reverse direction: default should NOT be applied
expect(z.safeDecode(schema, "asdf")).toMatchInlineSnapshot(`
{
"data": "asdf",
"success": true,
}
`);
expect(z.safeEncode(schema, "asdf")).toMatchInlineSnapshot(`
{
"data": "asdf",
"success": true,
}
`);
});
test("reverse parsing with pipe", () => {
const schema = z.string().transform((val) => val.length);
// should throw
expect(() => z.encode(schema, 1234)).toThrow();
});

View File

@@ -0,0 +1 @@
{"version":3,"file":"nodeBuilderFlags.d.ts","sourceRoot":"","sources":["../../src/enums/nodeBuilderFlags.ts"],"names":[],"mappings":"AACA,eAAO,IAAI,gBAAgB,EAAE,GAAG,CAAC"}

View File

@@ -0,0 +1,4 @@
import * as z from "./v4/classic/external.js";
export * from "./v4/classic/external.js";
export { z };
export default z;

View File

@@ -0,0 +1,40 @@
{
"name": "@rolldown/binding-linux-x64-gnu",
"version": "1.2.4",
"cpu": [
"x64"
],
"main": "rolldown-binding.linux-x64-gnu.node",
"files": [
"rolldown-binding.linux-x64-gnu.node"
],
"description": "Fast JavaScript/TypeScript bundler in Rust with Rollup-compatible API.",
"keywords": [
"bundler",
"esbuild",
"parcel",
"rolldown",
"rollup",
"webpack"
],
"homepage": "https://rolldown.rs/",
"license": "MIT",
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rolldown/rolldown.git",
"directory": "packages/rolldown"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"os": [
"linux"
],
"libc": [
"glibc"
]
}

View File

@@ -0,0 +1 @@
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).uuidParse=n()}(this,(function(){"use strict";var e=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;return function(n){if(!function(n){return"string"==typeof n&&e.test(n)}(n))throw TypeError("Invalid UUID");var t,i=new Uint8Array(16);return i[0]=(t=parseInt(n.slice(0,8),16))>>>24,i[1]=t>>>16&255,i[2]=t>>>8&255,i[3]=255&t,i[4]=(t=parseInt(n.slice(9,13),16))>>>8,i[5]=255&t,i[6]=(t=parseInt(n.slice(14,18),16))>>>8,i[7]=255&t,i[8]=(t=parseInt(n.slice(19,23),16))>>>8,i[9]=255&t,i[10]=(t=parseInt(n.slice(24,36),16))/1099511627776&255,i[11]=t/4294967296&255,i[12]=t>>>24&255,i[13]=t>>>16&255,i[14]=t>>>8&255,i[15]=255&t,i}}));

View File

@@ -0,0 +1,23 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABILITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/// <reference lib="es2021" />
/// <reference lib="es2022.array" />
/// <reference lib="es2022.error" />
/// <reference lib="es2022.intl" />
/// <reference lib="es2022.object" />
/// <reference lib="es2022.regexp" />
/// <reference lib="es2022.string" />

View File

@@ -0,0 +1,112 @@
import {EventEmitter} from 'events';
type WithRequiredProperties<T, K extends keyof T> = T & Required<Pick<T, K>>;
declare class Keyv<Value = any, Options extends Record<string, any> = Record<string, unknown>> extends EventEmitter {
/**
* `this.opts` is an object containing at least the properties listed
* below. However, `Keyv.Options` allows arbitrary properties as well.
* These properties can be specified as the second type parameter to `Keyv`.
*/
opts: WithRequiredProperties<
Keyv.Options<Value>,
'deserialize' | 'namespace' | 'serialize' | 'store' | 'uri'
> &
Options;
/**
* @param opts The options object is also passed through to the storage adapter. Check your storage adapter docs for any extra options.
*/
constructor(options?: Keyv.Options<Value> & Options);
/**
* @param uri The connection string URI.
*
* Merged into the options object as options.uri.
* @param opts The options object is also passed through to the storage adapter. Check your storage adapter docs for any extra options.
*/
constructor(uri?: string, options?: Keyv.Options<Value> & Options);
/** Returns the value. */
get(key: string, options?: {raw?: false}): Promise<Value | undefined>;
/** Returns the raw value. */
get(key: string, options: {raw: true}): Promise<Keyv.DeserializedData<Value> | undefined>;
/** Returns an array of values. Uses `store.getMany` if it exists, otherwise uses parallel calls to `store.get`. */
get(key: string[], options?: {raw?: false}): Promise<Array<Value | undefined>>;
/** Returns an array of raw values. Uses `store.getMany` if it exists, otherwise uses parallel calls to `store.get`. */
get(key: string[], options: {raw: true}): Promise<Array<Keyv.DeserializedData<Value> | undefined>>;
/**
* Set a value.
*
* By default keys are persistent. You can set an expiry TTL in milliseconds.
*/
set(key: string, value: Value, ttl?: number): Promise<true>;
/**
* Deletes an entry.
*
* Returns `true` if the key existed, `false` if not.
*/
delete(key: string | string[]): Promise<boolean>;
/** Delete all entries in the current namespace. */
clear(): Promise<void>;
/** Check if key exists in current namespace. */
has(key: string): Promise<boolean>;
/** Iterator */
iterator(namespace?: string): AsyncGenerator<any, void, any>;
/**
* Closes the connection.
*
* Returns `undefined` when the connection closes.
*/
disconnect(): Promise<void>;
}
declare namespace Keyv {
interface Options<Value> {
[key: string]: any;
/** Namespace for the current instance. */
namespace?: string | undefined;
/** A custom serialization function. */
serialize?: ((data: DeserializedData<Value>) => string) | undefined;
/** A custom deserialization function. */
deserialize?: ((data: string) => DeserializedData<Value> | undefined) | undefined;
/** The connection string URI. */
uri?: string | undefined;
/** The storage adapter instance to be used by Keyv. */
store?: Store<string | undefined> | undefined;
/** Default TTL. Can be overridden by specififying a TTL on `.set()`. */
ttl?: number | undefined;
/** Specify an adapter to use. e.g `'redis'` or `'mongodb'`. */
adapter?: 'redis' | 'mongodb' | 'mongo' | 'sqlite' | 'postgresql' | 'postgres' | 'mysql' | undefined;
/** Enable compression option **/
compression?: CompressionAdapter | undefined;
}
interface CompressionAdapter {
compress(value: any, options?: any): Promise<any>;
decompress(value: any, options?: any): Promise<any>;
serialize(value: any): Promise<any>;
deserialize(value: any): Promise<any>;
}
interface DeserializedData<Value> {
value: Value; expires: number | undefined;
}
type StoredData<Value> = DeserializedData<Value> | string | undefined;
interface Store<Value> {
get(key: string): Value | Promise<Value | undefined> | undefined;
set(key: string, value: Value, ttl?: number): any;
delete(key: string): boolean | Promise<boolean>;
clear(): void | Promise<void>;
has?(key: string): boolean | Promise<boolean>;
getMany?(
keys: string[]
): Array<StoredData<Value>> | Promise<Array<StoredData<Value>>> | undefined;
}
}
export = Keyv;

View File

@@ -0,0 +1,378 @@
import { expect, expectTypeOf, test } from "vitest";
import * as z from "zod/v4";
test("transform ctx.addIssue with parse", () => {
const strs = ["foo", "bar"];
const schema = z.string().transform((data, ctx) => {
const i = strs.indexOf(data);
if (i === -1) {
ctx.addIssue({
input: data,
code: "custom",
message: `${data} is not one of our allowed strings`,
});
}
return data.length;
});
const result = schema.safeParse("asdf");
expect(result.success).toEqual(false);
expect(result.error!).toMatchInlineSnapshot(`
[ZodError: [
{
"code": "custom",
"message": "asdf is not one of our allowed strings",
"path": []
}
]]
`);
});
test("transform ctx.addIssue with parseAsync", async () => {
const strs = ["foo", "bar"];
const result = await z
.string()
.transform(async (data, ctx) => {
const i = strs.indexOf(data);
if (i === -1) {
ctx.addIssue({
input: data,
code: "custom",
message: `${data} is not one of our allowed strings`,
});
}
return data.length;
})
.safeParseAsync("asdf");
expect(result).toMatchInlineSnapshot(`
{
"error": [ZodError: [
{
"code": "custom",
"message": "asdf is not one of our allowed strings",
"path": []
}
]],
"success": false,
}
`);
});
test("z.NEVER in transform", () => {
const foo = z
.number()
.optional()
.transform((val, ctx) => {
if (!val) {
ctx.addIssue({
input: val,
code: z.ZodIssueCode.custom,
message: "bad",
});
return z.NEVER;
}
return val;
});
type foo = z.infer<typeof foo>;
expectTypeOf<foo>().toEqualTypeOf<number>();
const arg = foo.safeParse(undefined);
if (!arg.success) {
expect(arg.error.issues[0].message).toEqual("bad");
}
});
test("basic transformations", () => {
const r1 = z
.string()
.transform((data) => data.length)
.parse("asdf");
expect(r1).toEqual(4);
});
test("coercion", () => {
const numToString = z.number().transform((n) => String(n));
const data = z
.object({
id: numToString,
})
.parse({ id: 5 });
expect(data).toEqual({ id: "5" });
});
test("async coercion", async () => {
const numToString = z.number().transform(async (n) => String(n));
const data = await z
.object({
id: numToString,
})
.parseAsync({ id: 5 });
expect(data).toEqual({ id: "5" });
});
test("sync coercion async error", async () => {
const asyncNumberToString = z.number().transform(async (n) => String(n));
expect(() =>
z
.object({
id: asyncNumberToString,
})
.parse({ id: 5 })
).toThrow();
// expect(data).toEqual({ id: '5' });
});
test("default", () => {
const data = z.string().default("asdf").parse(undefined); // => "asdf"
expect(data).toEqual("asdf");
});
test("dynamic default", () => {
const data = z
.string()
.default(() => "string")
.parse(undefined); // => "asdf"
expect(data).toEqual("string");
});
test("default when property is null or undefined", () => {
const data = z
.object({
foo: z.boolean().nullable().default(true),
bar: z.boolean().default(true),
})
.parse({ foo: null });
expect(data).toEqual({ foo: null, bar: true });
});
test("default with falsy values", () => {
const schema = z.object({
emptyStr: z.string().default("def"),
zero: z.number().default(5),
falseBoolean: z.boolean().default(true),
});
const input = { emptyStr: "", zero: 0, falseBoolean: true };
const output = schema.parse(input);
// defaults are not supposed to be used
expect(output).toEqual(input);
});
test("object typing", () => {
const stringToNumber = z.string().transform((arg) => Number.parseFloat(arg));
const t1 = z.object({
stringToNumber,
});
type t1 = z.input<typeof t1>;
type t2 = z.output<typeof t1>;
expectTypeOf<t1>().toEqualTypeOf<{ stringToNumber: string }>();
expectTypeOf<t2>().toEqualTypeOf<{ stringToNumber: number }>();
});
test("transform method overloads", () => {
const t1 = z.string().transform((val) => val.toUpperCase());
expect(t1.parse("asdf")).toEqual("ASDF");
const t2 = z.string().transform((val) => val.length);
expect(t2.parse("asdf")).toEqual(4);
});
test("multiple transformers", () => {
const stringToNumber = z.string().transform((arg) => Number.parseFloat(arg));
const doubler = stringToNumber.transform((val) => {
return val * 2;
});
expect(doubler.parse("5")).toEqual(10);
});
test("short circuit on dirty", () => {
const schema = z
.string()
.refine(() => false)
.transform((val) => val.toUpperCase());
const result = schema.safeParse("asdf");
expect(result.success).toEqual(false);
expect(result.error).toMatchInlineSnapshot(`
[ZodError: [
{
"code": "custom",
"path": [],
"message": "Invalid input"
}
]]
`);
const result2 = schema.safeParse(1234);
expect(result2.success).toEqual(false);
if (!result2.success) {
expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type);
}
});
test("async short circuit on dirty", async () => {
const schema = z
.string()
.refine(() => false)
.transform((val) => val.toUpperCase());
const result = await schema.spa("asdf");
expect(result.success).toEqual(false);
expect(result.error).toMatchInlineSnapshot(`
[ZodError: [
{
"code": "custom",
"path": [],
"message": "Invalid input"
}
]]
`);
const result2 = await schema.spa(1234);
expect(result2.success).toEqual(false);
expect(result2.error).toMatchInlineSnapshot(`
[ZodError: [
{
"expected": "string",
"code": "invalid_type",
"path": [],
"message": "Invalid input: expected string, received number"
}
]]
`);
});
test("do not continue by default", () => {
const A = z
.string()
.transform((val, ctx) => {
ctx.addIssue({
code: "custom",
message: `custom error`,
});
ctx.addIssue({
code: "custom",
message: `custom error`,
});
return val;
})
.pipe(z.number() as any);
expect(A.safeParse("asdf")).toMatchInlineSnapshot(`
{
"error": [ZodError: [
{
"code": "custom",
"message": "custom error",
"path": []
},
{
"code": "custom",
"message": "custom error",
"path": []
}
]],
"success": false,
}
`);
const B = z
.string()
.transform((val, ctx) => {
ctx.issues.push({
code: "custom",
message: `custom error`,
input: val,
});
ctx.issues.push({
code: "custom",
message: `custom error`,
input: val,
});
return val;
})
.pipe(z.number() as any);
expect(B.safeParse("asdf")).toMatchInlineSnapshot(`
{
"error": [ZodError: [
{
"code": "custom",
"message": "custom error",
"path": []
},
{
"code": "custom",
"message": "custom error",
"path": []
}
]],
"success": false,
}
`);
const C = z
.string()
.transform((val, ctx) => {
ctx.issues.push({
code: "custom",
message: `custom error`,
input: val,
continue: true,
});
ctx.issues.push({
code: "custom",
message: `custom error`,
input: val,
continue: true,
});
return val;
})
.pipe(z.number() as any);
expect(C.safeParse("asdf")).toMatchInlineSnapshot(`
{
"error": [ZodError: [
{
"code": "custom",
"message": "custom error",
"path": []
},
{
"code": "custom",
"message": "custom error",
"path": []
}
]],
"success": false,
}
`);
});
test("encode error", () => {
const schema = z.string().transform((val) => val.length);
expect(() => z.encode(schema, 1234)).toThrowErrorMatchingInlineSnapshot(
`[ZodEncodeError: Encountered unidirectional transform during encode: ZodTransform]`
);
});
test("transform context should have addIssue", () => {
const schema = z.transform((val, ctx) => {
ctx.addIssue({
code: "custom",
message: "Not valid",
});
return val;
});
const result = schema.safeParse("test");
expect(result.success).toBe(false);
if (!result.success) {
expect(result.error.issues[0].message).toBe("Not valid");
}
});

View File

@@ -0,0 +1,4 @@
function _identity(t) {
return t;
}
export { _identity as default };

View File

@@ -0,0 +1 @@
export { _ as default } from "../esm/_class_name_tdz_error.js";

View File

@@ -0,0 +1,120 @@
'use strict'
const test = require('node:test')
const os = require('node:os')
const tspl = require('@matteo.collina/tspl')
const pino = require('../')
const { pid } = process
const hostname = os.hostname()
test('metadata works', async (t) => {
const plan = tspl(t, { plan: 7 })
const now = Date.now()
const instance = pino({}, {
[Symbol.for('pino.metadata')]: true,
write (chunk) {
plan.equal(instance, this.lastLogger)
plan.equal(30, this.lastLevel)
plan.equal('a msg', this.lastMsg)
plan.ok(Number(this.lastTime) >= now)
plan.deepEqual(this.lastObj, { hello: 'world' })
const result = JSON.parse(chunk)
plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
plan.deepEqual(result, {
pid,
hostname,
level: 30,
hello: 'world',
msg: 'a msg'
})
}
})
instance.info({ hello: 'world' }, 'a msg')
await plan
})
test('child loggers works', async (t) => {
const plan = tspl(t, { plan: 6 })
const instance = pino({}, {
[Symbol.for('pino.metadata')]: true,
write (chunk) {
plan.equal(child, this.lastLogger)
plan.equal(30, this.lastLevel)
plan.equal('a msg', this.lastMsg)
plan.deepEqual(this.lastObj, { from: 'child' })
const result = JSON.parse(chunk)
plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
plan.deepEqual(result, {
pid,
hostname,
level: 30,
hello: 'world',
from: 'child',
msg: 'a msg'
})
}
})
const child = instance.child({ hello: 'world' })
child.info({ from: 'child' }, 'a msg')
await plan
})
test('without object', async (t) => {
const plan = tspl(t, { plan: 6 })
const instance = pino({}, {
[Symbol.for('pino.metadata')]: true,
write (chunk) {
plan.equal(instance, this.lastLogger)
plan.equal(30, this.lastLevel)
plan.equal('a msg', this.lastMsg)
plan.deepEqual({ }, this.lastObj)
const result = JSON.parse(chunk)
plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
plan.deepEqual(result, {
pid,
hostname,
level: 30,
msg: 'a msg'
})
}
})
instance.info('a msg')
await plan
})
test('without msg', async (t) => {
const plan = tspl(t, { plan: 6 })
const instance = pino({}, {
[Symbol.for('pino.metadata')]: true,
write (chunk) {
plan.equal(instance, this.lastLogger)
plan.equal(30, this.lastLevel)
plan.equal(undefined, this.lastMsg)
plan.deepEqual({ hello: 'world' }, this.lastObj)
const result = JSON.parse(chunk)
plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
plan.deepEqual(result, {
pid,
hostname,
level: 30,
hello: 'world'
})
}
})
instance.info({ hello: 'world' })
await plan
})

View File

@@ -0,0 +1,156 @@
import * as util from "../core/util.js";
function getRussianPlural(count, one, few, many) {
const absCount = Math.abs(count);
const lastDigit = absCount % 10;
const lastTwoDigits = absCount % 100;
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
return many;
}
if (lastDigit === 1) {
return one;
}
if (lastDigit >= 2 && lastDigit <= 4) {
return few;
}
return many;
}
const error = () => {
const Sizable = {
string: {
unit: {
one: "символ",
few: "символа",
many: "символов",
},
verb: "иметь",
},
file: {
unit: {
one: "байт",
few: "байта",
many: "байт",
},
verb: "иметь",
},
array: {
unit: {
one: "элемент",
few: "элемента",
many: "элементов",
},
verb: "иметь",
},
set: {
unit: {
one: "элемент",
few: "элемента",
many: "элементов",
},
verb: "иметь",
},
};
function getSizing(origin) {
return Sizable[origin] ?? null;
}
const FormatDictionary = {
regex: "ввод",
email: "email адрес",
url: "URL",
emoji: "эмодзи",
uuid: "UUID",
uuidv4: "UUIDv4",
uuidv6: "UUIDv6",
nanoid: "nanoid",
guid: "GUID",
cuid: "cuid",
cuid2: "cuid2",
ulid: "ULID",
xid: "XID",
ksuid: "KSUID",
datetime: "ISO дата и время",
date: "ISO дата",
time: "ISO время",
duration: "ISO длительность",
ipv4: "IPv4 адрес",
ipv6: "IPv6 адрес",
cidrv4: "IPv4 диапазон",
cidrv6: "IPv6 диапазон",
base64: "строка в формате base64",
base64url: "строка в формате base64url",
json_string: "JSON строка",
e164: "номер E.164",
jwt: "JWT",
template_literal: "ввод",
};
const TypeDictionary = {
nan: "NaN",
number: "число",
array: "массив",
};
return (issue) => {
switch (issue.code) {
case "invalid_type": {
const expected = TypeDictionary[issue.expected] ?? issue.expected;
const receivedType = util.parsedType(issue.input);
const received = TypeDictionary[receivedType] ?? receivedType;
if (/^[A-Z]/.test(issue.expected)) {
return `Неверный ввод: ожидалось instanceof ${issue.expected}, получено ${received}`;
}
return `Неверный ввод: ожидалось ${expected}, получено ${received}`;
}
case "invalid_value":
if (issue.values.length === 1)
return `Неверный ввод: ожидалось ${util.stringifyPrimitive(issue.values[0])}`;
return `Неверный вариант: ожидалось одно из ${util.joinValues(issue.values, "|")}`;
case "too_big": {
const adj = issue.inclusive ? "<=" : "<";
const sizing = getSizing(issue.origin);
if (sizing) {
const maxValue = Number(issue.maximum);
const unit = getRussianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
return `Слишком большое значение: ожидалось, что ${issue.origin ?? "значение"} будет иметь ${adj}${issue.maximum.toString()} ${unit}`;
}
return `Слишком большое значение: ожидалось, что ${issue.origin ?? "значение"} будет ${adj}${issue.maximum.toString()}`;
}
case "too_small": {
const adj = issue.inclusive ? ">=" : ">";
const sizing = getSizing(issue.origin);
if (sizing) {
const minValue = Number(issue.minimum);
const unit = getRussianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
return `Слишком маленькое значение: ожидалось, что ${issue.origin} будет иметь ${adj}${issue.minimum.toString()} ${unit}`;
}
return `Слишком маленькое значение: ожидалось, что ${issue.origin} будет ${adj}${issue.minimum.toString()}`;
}
case "invalid_format": {
const _issue = issue;
if (_issue.format === "starts_with")
return `Неверная строка: должна начинаться с "${_issue.prefix}"`;
if (_issue.format === "ends_with")
return `Неверная строка: должна заканчиваться на "${_issue.suffix}"`;
if (_issue.format === "includes")
return `Неверная строка: должна содержать "${_issue.includes}"`;
if (_issue.format === "regex")
return `Неверная строка: должна соответствовать шаблону ${_issue.pattern}`;
return `Неверный ${FormatDictionary[_issue.format] ?? issue.format}`;
}
case "not_multiple_of":
return `Неверное число: должно быть кратным ${issue.divisor}`;
case "unrecognized_keys":
return `Нераспознанн${issue.keys.length > 1 ? "ые" : "ый"} ключ${issue.keys.length > 1 ? "и" : ""}: ${util.joinValues(issue.keys, ", ")}`;
case "invalid_key":
return `Неверный ключ в ${issue.origin}`;
case "invalid_union":
return "Неверные входные данные";
case "invalid_element":
return `Неверное значение в ${issue.origin}`;
default:
return `Неверные входные данные`;
}
};
};
export default function () {
return {
localeError: error(),
};
}

View File

@@ -0,0 +1,8 @@
import type { TSESTree } from '@typescript-eslint/types';
import type { ScopeManager } from '../ScopeManager';
import type { Scope } from './Scope';
import { ScopeBase } from './ScopeBase';
import { ScopeType } from './ScopeType';
export declare class ModuleScope extends ScopeBase<ScopeType.module, TSESTree.Program, Scope> {
constructor(scopeManager: ScopeManager, upperScope: ModuleScope['upper'], block: ModuleScope['block']);
}

View File

@@ -0,0 +1,25 @@
{
"name": "@types/deep-eql",
"version": "4.0.2",
"description": "TypeScript definitions for deep-eql",
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/deep-eql",
"license": "MIT",
"contributors": [
{
"name": "Rodrigo Pietnechuk",
"githubUsername": "ghnoob",
"url": "https://github.com/ghnoob"
}
],
"main": "",
"types": "index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
"directory": "types/deep-eql"
},
"scripts": {},
"dependencies": {},
"typesPublisherContentHash": "3b8981ce557947fc00ca08cbd93b4206bfc0943360956867381a0a3f6b1eabf5",
"typeScriptVersion": "4.5"
}

View File

@@ -0,0 +1,297 @@
/**
* @fileoverview Validates spacing before and after semicolon
* @author Mathias Schreck
* @deprecated in ESLint v8.53.0
*/
"use strict";
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
deprecated: {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
replacedBy: [
{
message:
"ESLint Stylistic now maintains deprecated stylistic core rules.",
url: "https://eslint.style/guide/migration",
plugin: {
name: "@stylistic/eslint-plugin",
url: "https://eslint.style",
},
rule: {
name: "semi-spacing",
url: "https://eslint.style/rules/semi-spacing",
},
},
],
},
type: "layout",
docs: {
description:
"Enforce consistent spacing before and after semicolons",
recommended: false,
url: "https://eslint.org/docs/latest/rules/semi-spacing",
},
fixable: "whitespace",
schema: [
{
type: "object",
properties: {
before: {
type: "boolean",
default: false,
},
after: {
type: "boolean",
default: true,
},
},
additionalProperties: false,
},
],
messages: {
unexpectedWhitespaceBefore:
"Unexpected whitespace before semicolon.",
unexpectedWhitespaceAfter: "Unexpected whitespace after semicolon.",
missingWhitespaceBefore: "Missing whitespace before semicolon.",
missingWhitespaceAfter: "Missing whitespace after semicolon.",
},
},
create(context) {
const config = context.options[0],
sourceCode = context.sourceCode;
let requireSpaceBefore = false,
requireSpaceAfter = true;
if (typeof config === "object") {
requireSpaceBefore = config.before;
requireSpaceAfter = config.after;
}
/**
* Checks if a given token has leading whitespace.
* @param {Object} token The token to check.
* @returns {boolean} True if the given token has leading space, false if not.
*/
function hasLeadingSpace(token) {
const tokenBefore = sourceCode.getTokenBefore(token);
return (
tokenBefore &&
astUtils.isTokenOnSameLine(tokenBefore, token) &&
sourceCode.isSpaceBetween(tokenBefore, token)
);
}
/**
* Checks if a given token has trailing whitespace.
* @param {Object} token The token to check.
* @returns {boolean} True if the given token has trailing space, false if not.
*/
function hasTrailingSpace(token) {
const tokenAfter = sourceCode.getTokenAfter(token);
return (
tokenAfter &&
astUtils.isTokenOnSameLine(token, tokenAfter) &&
sourceCode.isSpaceBetween(token, tokenAfter)
);
}
/**
* Checks if the given token is the last token in its line.
* @param {Token} token The token to check.
* @returns {boolean} Whether or not the token is the last in its line.
*/
function isLastTokenInCurrentLine(token) {
const tokenAfter = sourceCode.getTokenAfter(token);
return !(
tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter)
);
}
/**
* Checks if the given token is the first token in its line
* @param {Token} token The token to check.
* @returns {boolean} Whether or not the token is the first in its line.
*/
function isFirstTokenInCurrentLine(token) {
const tokenBefore = sourceCode.getTokenBefore(token);
return !(
tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore)
);
}
/**
* Checks if the next token of a given token is a closing parenthesis.
* @param {Token} token The token to check.
* @returns {boolean} Whether or not the next token of a given token is a closing parenthesis.
*/
function isBeforeClosingParen(token) {
const nextToken = sourceCode.getTokenAfter(token);
return (
(nextToken && astUtils.isClosingBraceToken(nextToken)) ||
astUtils.isClosingParenToken(nextToken)
);
}
/**
* Report location example :
*
* for unexpected space `before`
*
* var a = 'b' ;
* ^^^
*
* for unexpected space `after`
*
* var a = 'b'; c = 10;
* ^^
*
* Reports if the given token has invalid spacing.
* @param {Token} token The semicolon token to check.
* @param {ASTNode} node The corresponding node of the token.
* @returns {void}
*/
function checkSemicolonSpacing(token, node) {
if (astUtils.isSemicolonToken(token)) {
if (hasLeadingSpace(token)) {
if (!requireSpaceBefore) {
const tokenBefore = sourceCode.getTokenBefore(token);
const loc = {
start: tokenBefore.loc.end,
end: token.loc.start,
};
context.report({
node,
loc,
messageId: "unexpectedWhitespaceBefore",
fix(fixer) {
return fixer.removeRange([
tokenBefore.range[1],
token.range[0],
]);
},
});
}
} else {
if (requireSpaceBefore) {
const loc = token.loc;
context.report({
node,
loc,
messageId: "missingWhitespaceBefore",
fix(fixer) {
return fixer.insertTextBefore(token, " ");
},
});
}
}
if (
!isFirstTokenInCurrentLine(token) &&
!isLastTokenInCurrentLine(token) &&
!isBeforeClosingParen(token)
) {
if (hasTrailingSpace(token)) {
if (!requireSpaceAfter) {
const tokenAfter = sourceCode.getTokenAfter(token);
const loc = {
start: token.loc.end,
end: tokenAfter.loc.start,
};
context.report({
node,
loc,
messageId: "unexpectedWhitespaceAfter",
fix(fixer) {
return fixer.removeRange([
token.range[1],
tokenAfter.range[0],
]);
},
});
}
} else {
if (requireSpaceAfter) {
const loc = token.loc;
context.report({
node,
loc,
messageId: "missingWhitespaceAfter",
fix(fixer) {
return fixer.insertTextAfter(token, " ");
},
});
}
}
}
}
}
/**
* Checks the spacing of the semicolon with the assumption that the last token is the semicolon.
* @param {ASTNode} node The node to check.
* @returns {void}
*/
function checkNode(node) {
const token = sourceCode.getLastToken(node);
checkSemicolonSpacing(token, node);
}
return {
VariableDeclaration: checkNode,
ExpressionStatement: checkNode,
BreakStatement: checkNode,
ContinueStatement: checkNode,
DebuggerStatement: checkNode,
DoWhileStatement: checkNode,
ReturnStatement: checkNode,
ThrowStatement: checkNode,
ImportDeclaration: checkNode,
ExportNamedDeclaration: checkNode,
ExportAllDeclaration: checkNode,
ExportDefaultDeclaration: checkNode,
ForStatement(node) {
if (node.init) {
checkSemicolonSpacing(
sourceCode.getTokenAfter(node.init),
node,
);
}
if (node.test) {
checkSemicolonSpacing(
sourceCode.getTokenAfter(node.test),
node,
);
}
},
PropertyDefinition: checkNode,
};
},
};

View File

@@ -0,0 +1,105 @@
import type * as core from "./core.js";
import type { $ZodType } from "./schemas.js";
export const $output: unique symbol = Symbol("ZodOutput");
export type $output = typeof $output;
export const $input: unique symbol = Symbol("ZodInput");
export type $input = typeof $input;
export type $replace<Meta, S extends $ZodType> = Meta extends $output
? core.output<S>
: Meta extends $input
? core.input<S>
: Meta extends (infer M)[]
? $replace<M, S>[]
: Meta extends (...args: infer P) => infer R
? (
...args: {
[K in keyof P]: $replace<P[K], S>; // tuple
}
) => $replace<R, S>
: // handle objects
Meta extends object
? { [K in keyof Meta]: $replace<Meta[K], S> }
: Meta;
type MetadataType = object | undefined;
export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema extends $ZodType = $ZodType> {
_meta!: Meta;
_schema!: Schema;
_map: WeakMap<Schema, $replace<Meta, Schema>> = new WeakMap();
_idmap: Map<string, Schema> = new Map();
add<S extends Schema>(
schema: S,
..._meta: undefined extends Meta ? [$replace<Meta, S>?] : [$replace<Meta, S>]
): this {
const meta: any = _meta[0];
this._map.set(schema, meta!);
if (meta && typeof meta === "object" && "id" in meta) {
this._idmap.set(meta.id!, schema);
}
return this as any;
}
clear(): this {
this._map = new WeakMap();
this._idmap = new Map();
return this;
}
remove(schema: Schema): this {
const meta: any = this._map.get(schema);
if (meta && typeof meta === "object" && "id" in meta) {
this._idmap.delete(meta.id!);
}
this._map.delete(schema);
return this;
}
get<S extends Schema>(schema: S): $replace<Meta, S> | undefined {
// return this._map.get(schema) as any;
// inherit metadata
const p = schema._zod.parent as Schema;
if (p) {
const pm: any = { ...(this.get(p) ?? {}) };
delete pm.id; // do not inherit id
const f = { ...pm, ...this._map.get(schema) } as any;
return Object.keys(f).length ? f : undefined;
}
return this._map.get(schema) as any;
}
has(schema: Schema): boolean {
return this._map.has(schema);
}
}
export interface JSONSchemaMeta {
id?: string | undefined;
title?: string | undefined;
description?: string | undefined;
deprecated?: boolean | undefined;
[k: string]: unknown;
}
export interface GlobalMeta extends JSONSchemaMeta {}
// registries
export function registry<T extends MetadataType = MetadataType, S extends $ZodType = $ZodType>(): $ZodRegistry<T, S> {
return new $ZodRegistry<T, S>();
}
interface GlobalThisWithRegistry {
/**
* The globalRegistry instance shared across both CommonJS and ESM builds.
* By attaching the registry to `globalThis`, this property ensures a single, deduplicated instance
* is used regardless of whether the package is loaded via `require` (CJS) or `import` (ESM).
* This prevents dual package hazards and keeps registry state consistent.
*/
__zod_globalRegistry?: $ZodRegistry<GlobalMeta>;
}
(globalThis as GlobalThisWithRegistry).__zod_globalRegistry ??= registry<GlobalMeta>();
export const globalRegistry: $ZodRegistry<GlobalMeta> = (globalThis as GlobalThisWithRegistry).__zod_globalRegistry!;

View File

@@ -0,0 +1,73 @@
{
"name": "@typescript-eslint/tsconfig-utils",
"version": "8.67.0",
"description": "Utilities for collecting TSConfigs for linting scenarios.",
"files": [
"dist",
"!**/*.tsbuildinfo"
],
"type": "commonjs",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/typescript-eslint/typescript-eslint.git",
"directory": "packages/tsconfig-utils"
},
"bugs": {
"url": "https://github.com/typescript-eslint/typescript-eslint/issues"
},
"homepage": "https://typescript-eslint.io",
"license": "MIT",
"keywords": [
"eslint",
"typescript",
"estree"
],
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
},
"devDependencies": {
"@typescript/native": "npm:typescript@^7.0.2",
"@vitest/coverage-v8": "^4.0.18",
"rimraf": "^5.0.10",
"typescript": ">=4.8.4 <6.1.0",
"vitest": "^4.0.18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"publishConfig": {
"access": "public"
},
"nx": {
"name": "tsconfig-utils",
"includedScripts": [
"clean"
],
"targets": {
"typecheck:tsgo": {},
"attw-check": {}
}
},
"scripts": {
"//": "These package scripts are mostly here for convenience. Task running is handled by Nx at the root level.",
"build": "pnpm exec nx build",
"clean": "rimraf dist/ coverage/",
"format": "pnpm -w exec format",
"lint": "pnpm -w exec nx lint",
"test": "pnpm -w exec nx test",
"typecheck": "pnpm -w exec nx typecheck",
"typecheck:tsgo": "pnpm -w exec nx typecheck:tsgo",
"attw-check": "pnpm -w exec nx attw-check"
}
}

View File

@@ -0,0 +1,122 @@
/**
* @fileoverview Ensure handling of errors when we know they exist.
* @author Jamund Ferguson
* @deprecated in ESLint v7.0.0
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
deprecated: {
message: "Node.js rules were moved out of ESLint core.",
url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
deprecatedSince: "7.0.0",
availableUntil: "11.0.0",
replacedBy: [
{
message:
"eslint-plugin-n now maintains deprecated Node.js-related rules.",
plugin: {
name: "eslint-plugin-n",
url: "https://github.com/eslint-community/eslint-plugin-n",
},
rule: {
name: "handle-callback-err",
url: "https://github.com/eslint-community/eslint-plugin-n/tree/master/docs/rules/handle-callback-err.md",
},
},
],
},
type: "suggestion",
docs: {
description: "Require error handling in callbacks",
recommended: false,
url: "https://eslint.org/docs/latest/rules/handle-callback-err",
},
schema: [
{
type: "string",
},
],
messages: {
expected: "Expected error to be handled.",
},
},
create(context) {
const errorArgument = context.options[0] || "err";
const sourceCode = context.sourceCode;
/**
* Checks if the given argument should be interpreted as a regexp pattern.
* @param {string} stringToCheck The string which should be checked.
* @returns {boolean} Whether or not the string should be interpreted as a pattern.
*/
function isPattern(stringToCheck) {
const firstChar = stringToCheck[0];
return firstChar === "^";
}
/**
* Checks if the given name matches the configured error argument.
* @param {string} name The name which should be compared.
* @returns {boolean} Whether or not the given name matches the configured error variable name.
*/
function matchesConfiguredErrorName(name) {
if (isPattern(errorArgument)) {
const regexp = new RegExp(errorArgument, "u");
return regexp.test(name);
}
return name === errorArgument;
}
/**
* Get the parameters of a given function scope.
* @param {Object} scope The function scope.
* @returns {Array} All parameters of the given scope.
*/
function getParameters(scope) {
return scope.variables.filter(
variable =>
variable.defs[0] && variable.defs[0].type === "Parameter",
);
}
/**
* Check to see if we're handling the error object properly.
* @param {ASTNode} node The AST node to check.
* @returns {void}
*/
function checkForError(node) {
const scope = sourceCode.getScope(node),
parameters = getParameters(scope),
firstParameter = parameters[0];
if (
firstParameter &&
matchesConfiguredErrorName(firstParameter.name)
) {
if (firstParameter.references.length === 0) {
context.report({ node, messageId: "expected" });
}
}
}
return {
FunctionDeclaration: checkForError,
FunctionExpression: checkForError,
ArrowFunctionExpression: checkForError,
};
},
};

View File

@@ -0,0 +1,23 @@
var defineProperty = require("./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;
}
module.exports = _objectSpread2, module.exports.__esModule = true, module.exports["default"] = module.exports;

View File

@@ -0,0 +1,39 @@
/**
* CommanderError class
*/
class CommanderError extends Error {
/**
* Constructs the CommanderError class
* @param {number} exitCode suggested exit code which could be used with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
*/
constructor(exitCode, code, message) {
super(message);
// properly capture stack trace in Node.js
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = code;
this.exitCode = exitCode;
this.nestedError = undefined;
}
}
/**
* InvalidArgumentError class
*/
class InvalidArgumentError extends CommanderError {
/**
* Constructs the InvalidArgumentError class
* @param {string} [message] explanation of why argument is invalid
*/
constructor(message) {
super(1, 'commander.invalidArgument', message);
// properly capture stack trace in Node.js
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}
}
exports.CommanderError = CommanderError;
exports.InvalidArgumentError = InvalidArgumentError;

View File

@@ -0,0 +1,335 @@
"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 });
const utils_1 = require("@typescript-eslint/utils");
const tsutils = __importStar(require("ts-api-utils"));
const ts = __importStar(require("typescript"));
const util_1 = require("../util");
exports.default = (0, util_1.createRule)({
name: 'consistent-type-exports',
meta: {
type: 'suggestion',
docs: {
description: 'Enforce consistent usage of type exports',
requiresTypeChecking: true,
},
fixable: 'code',
messages: {
multipleExportsAreTypes: 'Type exports {{exportNames}} are not values and should be exported using `export type`.',
singleExportIsType: 'Type export {{exportNames}} is not a value and should be exported using `export type`.',
typeOverValue: 'All exports in the declaration are only used as types. Use `export type`.',
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
fixMixedExportsWithInlineTypeSpecifier: {
type: 'boolean',
description: 'Whether the rule will autofix "mixed" export cases using TS inline type specifiers.',
},
},
},
],
},
defaultOptions: [
{
fixMixedExportsWithInlineTypeSpecifier: false,
},
],
create(context, [{ fixMixedExportsWithInlineTypeSpecifier }]) {
const sourceExportsMap = {};
const services = (0, util_1.getParserServices)(context);
const checker = services.program.getTypeChecker();
/**
* Helper for identifying if a symbol resolves to a
* JavaScript value or a TypeScript type.
*
* @returns True/false if is a type or not, or undefined if the specifier
* can't be resolved.
*/
function isSymbolTypeBased(symbol) {
if (!symbol || checker.isUnknownSymbol(symbol)) {
return undefined;
}
if (symbol.getDeclarations()?.some(ts.isTypeOnlyImportOrExportDeclaration)) {
return true;
}
if (tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Value)) {
return false;
}
return tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)
? isSymbolTypeBased(checker.getImmediateAliasedSymbol(symbol))
: true;
}
return {
ExportAllDeclaration(node) {
if (node.exportKind === 'type') {
return;
}
const sourceModule = ts.resolveModuleName(node.source.value, context.filename, services.program.getCompilerOptions(), ts.sys);
if (sourceModule.resolvedModule == null) {
return;
}
const sourceFile = services.program.getSourceFile(sourceModule.resolvedModule.resolvedFileName);
if (sourceFile == null) {
return;
}
const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile);
if (sourceFileSymbol == null) {
return;
}
const sourceFileType = checker.getTypeOfSymbol(sourceFileSymbol);
// Module can explicitly export types or values, and it's not difficult
// to distinguish one from the other, since we can get the flags of
// the exported symbols or check if symbol export declaration has
// the "type" keyword in it.
//
// Things get a lot more complicated when we're dealing with
// export * from './module-with-type-only-exports'
// export type * from './module-with-type-and-value-exports'
//
// TS checker has an internal function getExportsOfModuleWorker that
// recursively visits all module exports, including "export *". It then
// puts type-only-star-exported symbols into the typeOnlyExportStarMap
// property of sourceFile's SymbolLinks. Since symbol links aren't
// exposed outside the checker, we cannot access it directly.
//
// Therefore, to filter out value properties, we use the following hack:
// checker.getPropertiesOfType returns all exports that were originally
// values, but checker.getPropertyOfType returns undefined for
// properties that are mentioned in the typeOnlyExportStarMap.
const isThereAnyExportedValue = checker
.getPropertiesOfType(sourceFileType)
.some(propertyTypeSymbol => checker.getPropertyOfType(sourceFileType, propertyTypeSymbol.escapedName.toString()) != null);
if (isThereAnyExportedValue) {
return;
}
context.report({
node,
messageId: 'typeOverValue',
fix(fixer) {
const asteriskToken = (0, util_1.nullThrows)(context.sourceCode.getFirstToken(node, token => token.type === utils_1.AST_TOKEN_TYPES.Punctuator &&
token.value === '*'), util_1.NullThrowsReasons.MissingToken('asterisk', 'export all declaration'));
return fixer.insertTextBefore(asteriskToken, 'type ');
},
});
},
ExportNamedDeclaration(node) {
// Coerce the source into a string for use as a lookup entry.
const source = getSourceFromExport(node) ?? 'undefined';
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const sourceExports = (sourceExportsMap[source] ||= {
reportValueExports: [],
source,
typeOnlyNamedExport: null,
valueOnlyNamedExport: null,
});
// Cache the first encountered exports for the package. We will need to come
// back to these later when fixing the problems.
if (node.exportKind === 'type') {
// The export is a type export
sourceExports.typeOnlyNamedExport ??= node;
}
else {
// The export is a value export
sourceExports.valueOnlyNamedExport ??= node;
}
// Next for the current export, we will separate type/value specifiers.
const typeBasedSpecifiers = [];
const inlineTypeSpecifiers = [];
const valueSpecifiers = [];
// Note: it is valid to export values as types. We will avoid reporting errors
// when this is encountered.
if (node.exportKind !== 'type') {
for (const specifier of node.specifiers) {
if (specifier.exportKind === 'type') {
inlineTypeSpecifiers.push(specifier);
continue;
}
const isTypeBased = isSymbolTypeBased(services.getSymbolAtLocation(specifier.exported));
if (isTypeBased === true) {
typeBasedSpecifiers.push(specifier);
}
else if (isTypeBased === false) {
// When isTypeBased is undefined, we should avoid reporting them.
valueSpecifiers.push(specifier);
}
}
}
if ((node.exportKind === 'value' && typeBasedSpecifiers.length) ||
(node.exportKind === 'type' && valueSpecifiers.length)) {
sourceExports.reportValueExports.push({
node,
inlineTypeSpecifiers,
typeBasedSpecifiers,
valueSpecifiers,
});
}
},
'Program:exit'() {
for (const sourceExports of Object.values(sourceExportsMap)) {
// If this export has no issues, move on.
if (sourceExports.reportValueExports.length === 0) {
continue;
}
for (const report of sourceExports.reportValueExports) {
if (report.valueSpecifiers.length === 0) {
// Export is all type-only with no type specifiers; convert the entire export to `export type`.
context.report({
node: report.node,
messageId: 'typeOverValue',
*fix(fixer) {
yield* fixExportInsertType(fixer, context.sourceCode, report.node);
},
});
continue;
}
// We have both type and value violations.
const allExportNames = report.typeBasedSpecifiers.map(specifier => specifier.local.type === utils_1.AST_NODE_TYPES.Identifier
? specifier.local.name
: specifier.local.value);
if (allExportNames.length === 1) {
const exportNames = allExportNames[0];
context.report({
node: report.node,
messageId: 'singleExportIsType',
data: { exportNames },
*fix(fixer) {
if (fixMixedExportsWithInlineTypeSpecifier) {
yield* fixAddTypeSpecifierToNamedExports(fixer, report);
}
else {
yield* fixSeparateNamedExports(fixer, context.sourceCode, report);
}
},
});
}
else {
const exportNames = (0, util_1.formatWordList)(allExportNames);
context.report({
node: report.node,
messageId: 'multipleExportsAreTypes',
data: { exportNames },
*fix(fixer) {
if (fixMixedExportsWithInlineTypeSpecifier) {
yield* fixAddTypeSpecifierToNamedExports(fixer, report);
}
else {
yield* fixSeparateNamedExports(fixer, context.sourceCode, report);
}
},
});
}
}
}
},
};
},
});
/**
* Inserts "type" into an export.
*
* Example:
*
* export type { Foo } from 'foo';
* ^^^^
*/
function* fixExportInsertType(fixer, sourceCode, node) {
const exportToken = (0, util_1.nullThrows)(sourceCode.getFirstToken(node), util_1.NullThrowsReasons.MissingToken('export', node.type));
yield fixer.insertTextAfter(exportToken, ' type');
for (const specifier of node.specifiers) {
if (specifier.exportKind === 'type') {
const kindToken = (0, util_1.nullThrows)(sourceCode.getFirstToken(specifier), util_1.NullThrowsReasons.MissingToken('export', specifier.type));
const firstTokenAfter = (0, util_1.nullThrows)(sourceCode.getTokenAfter(kindToken, {
includeComments: true,
}), 'Missing token following the export kind.');
yield fixer.removeRange([kindToken.range[0], firstTokenAfter.range[0]]);
}
}
}
/**
* Separates the exports which mismatch the kind of export the given
* node represents. For example, a type export's named specifiers which
* represent values will be inserted in a separate `export` statement.
*/
function* fixSeparateNamedExports(fixer, sourceCode, report) {
const { node, inlineTypeSpecifiers, typeBasedSpecifiers, valueSpecifiers } = report;
const typeSpecifiers = [...typeBasedSpecifiers, ...inlineTypeSpecifiers];
const source = getSourceFromExport(node);
const specifierNames = typeSpecifiers.map(getSpecifierText).join(', ');
const exportToken = (0, util_1.nullThrows)(sourceCode.getFirstToken(node), util_1.NullThrowsReasons.MissingToken('export', node.type));
// Filter the bad exports from the current line.
const filteredSpecifierNames = valueSpecifiers
.map(getSpecifierText)
.join(', ');
const openToken = (0, util_1.nullThrows)(sourceCode.getFirstToken(node, util_1.isOpeningBraceToken), util_1.NullThrowsReasons.MissingToken('{', node.type));
const closeToken = (0, util_1.nullThrows)(sourceCode.getLastToken(node, util_1.isClosingBraceToken), util_1.NullThrowsReasons.MissingToken('}', node.type));
// Remove exports from the current line which we're going to re-insert.
yield fixer.replaceTextRange([openToken.range[1], closeToken.range[0]], ` ${filteredSpecifierNames} `);
// Insert the bad exports into a new export line above.
yield fixer.insertTextBefore(exportToken, `export type { ${specifierNames} }${source ? ` from '${source}'` : ''};\n`);
}
function* fixAddTypeSpecifierToNamedExports(fixer, report) {
if (report.node.exportKind === 'type') {
return;
}
for (const specifier of report.typeBasedSpecifiers) {
yield fixer.insertTextBefore(specifier, 'type ');
}
}
/**
* Returns the source of the export, or undefined if the named export has no source.
*/
function getSourceFromExport(node) {
if (node.source?.type === utils_1.AST_NODE_TYPES.Literal &&
typeof node.source.value === 'string') {
return node.source.value;
}
return undefined;
}
/**
* Returns the specifier text for the export. If it is aliased, we take care to return
* the proper formatting.
*/
function getSpecifierText(specifier) {
const exportedName = specifier.exported.type === utils_1.AST_NODE_TYPES.Literal
? specifier.exported.raw
: specifier.exported.name;
const localName = specifier.local.type === utils_1.AST_NODE_TYPES.Literal
? specifier.local.raw
: specifier.local.name;
return `${localName}${exportedName !== localName ? ` as ${exportedName}` : ''}`;
}