WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
# Help
|
||||
|
||||
* [Log rotation](#rotate)
|
||||
* [Reopening log files](#reopening)
|
||||
* [Saving to multiple files](#multiple)
|
||||
* [Log filtering](#filter-logs)
|
||||
* [Transports and systemd](#transport-systemd)
|
||||
* [Log to different streams](#multi-stream)
|
||||
* [Duplicate keys](#dupe-keys)
|
||||
* [Log levels as labels instead of numbers](#level-string)
|
||||
* [Pino with `debug`](#debug)
|
||||
* [Unicode and Windows terminal](#windows)
|
||||
* [Mapping Pino Log Levels to Google Cloud Logging (Stackdriver) Severity Levels](#stackdriver)
|
||||
* [Using Grafana Loki to evaluate pino logs in a kubernetes cluster](#grafana-loki)
|
||||
* [Avoid Message Conflict](#avoid-message-conflict)
|
||||
* [Best performance for logging to `stdout`](#best-performance-for-stdout)
|
||||
* [Testing](#testing)
|
||||
|
||||
<a id="rotate"></a>
|
||||
## Log rotation
|
||||
|
||||
Use a separate tool for log rotation:
|
||||
We recommend [logrotate](https://github.com/logrotate/logrotate).
|
||||
Consider we output our logs to `/var/log/myapp.log` like so:
|
||||
|
||||
```
|
||||
$ node server.js > /var/log/myapp.log
|
||||
```
|
||||
|
||||
We would rotate our log files with logrotate, by adding the following to `/etc/logrotate.d/myapp`:
|
||||
|
||||
```
|
||||
/var/log/myapp.log {
|
||||
su root
|
||||
daily
|
||||
rotate 7
|
||||
delaycompress
|
||||
compress
|
||||
notifempty
|
||||
missingok
|
||||
copytruncate
|
||||
}
|
||||
```
|
||||
|
||||
The `copytruncate` configuration has a very slight possibility of lost log lines due
|
||||
to a gap between copying and truncating - the truncate may occur after additional lines
|
||||
have been written. To perform log rotation without `copytruncate`, see the [Reopening log files](#reopening)
|
||||
help.
|
||||
|
||||
<a id="reopening"></a>
|
||||
## Reopening log files
|
||||
|
||||
In cases where a log rotation tool doesn't offer copy-truncate capabilities,
|
||||
or where using them is deemed inappropriate, `pino.destination`
|
||||
can reopen file paths after a file has been moved away.
|
||||
|
||||
One way to use this is to set up a `SIGUSR2` or `SIGHUP` signal handler that
|
||||
reopens the log file destination, making sure to write the process PID out
|
||||
somewhere so the log rotation tool knows where to send the signal.
|
||||
|
||||
```js
|
||||
// write the process pid to a well known location for later
|
||||
const fs = require('node:fs')
|
||||
fs.writeFileSync('/var/run/myapp.pid', process.pid)
|
||||
|
||||
const dest = pino.destination('/log/file')
|
||||
const logger = require('pino')(dest)
|
||||
process.on('SIGHUP', () => dest.reopen())
|
||||
```
|
||||
|
||||
The log rotation tool can then be configured to send this signal to the process
|
||||
after a log rotation event has occurred.
|
||||
|
||||
Given a similar scenario as in the [Log rotation](#rotate) section a basic
|
||||
`logrotate` config that aligns with this strategy would look similar to the following:
|
||||
|
||||
```
|
||||
/var/log/myapp.log {
|
||||
su root
|
||||
daily
|
||||
rotate 7
|
||||
delaycompress
|
||||
compress
|
||||
notifempty
|
||||
missingok
|
||||
postrotate
|
||||
kill -HUP `cat /var/run/myapp.pid`
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
<a id="multiple"></a>
|
||||
## Saving to multiple files
|
||||
|
||||
See [`pino.multistream`](/docs/api.md#pino-multistream).
|
||||
|
||||
<a id="filter-logs"></a>
|
||||
## Log Filtering
|
||||
The Pino philosophy advocates common, preexisting, system utilities.
|
||||
|
||||
Some recommendations in line with this philosophy are:
|
||||
|
||||
1. Use [`grep`](https://linux.die.net/man/1/grep):
|
||||
```sh
|
||||
$ # View all "INFO" level logs
|
||||
$ node app.js | grep '"level":30'
|
||||
```
|
||||
1. Use [`jq`](https://stedolan.github.io/jq/):
|
||||
```sh
|
||||
$ # View all "ERROR" level logs
|
||||
$ node app.js | jq 'select(.level == 50)'
|
||||
```
|
||||
|
||||
<a id="transport-systemd"></a>
|
||||
## Transports and systemd
|
||||
`systemd` makes it complicated to use pipes in services. One method for overcoming
|
||||
this challenge is to use a subshell:
|
||||
|
||||
```
|
||||
ExecStart=/bin/sh -c '/path/to/node app.js | pino-transport'
|
||||
```
|
||||
|
||||
<a id="multi-stream"></a>
|
||||
## Log to different streams
|
||||
|
||||
Pino's default log destination is the singular destination of `stdout`. While
|
||||
not recommended for performance reasons, multiple destinations can be targeted
|
||||
by using [`pino.multistream`](/docs/api.md#pino-multistream).
|
||||
|
||||
In this example, we use `stderr` for `error` level logs and `stdout` as default
|
||||
for all other levels (e.g. `debug`, `info`, and `warn`).
|
||||
|
||||
```js
|
||||
const pino = require('pino')
|
||||
var streams = [
|
||||
{level: 'debug', stream: process.stdout},
|
||||
{level: 'error', stream: process.stderr},
|
||||
{level: 'fatal', stream: process.stderr}
|
||||
]
|
||||
|
||||
const logger = pino({
|
||||
name: 'my-app',
|
||||
level: 'debug', // must be the lowest level of all streams
|
||||
}, pino.multistream(streams))
|
||||
```
|
||||
|
||||
<a id="dupe-keys"></a>
|
||||
## How Pino handles duplicate keys
|
||||
|
||||
Duplicate keys are possibly when a child logger logs an object with a key that
|
||||
collides with a key in the child loggers bindings.
|
||||
|
||||
See the [child logger duplicate keys caveat](/docs/child-loggers.md#duplicate-keys-caveat)
|
||||
for information on this is handled.
|
||||
|
||||
<a id="level-string"></a>
|
||||
## Log levels as labels instead of numbers
|
||||
Pino log lines are meant to be parsable. Thus, Pino's default mode of operation
|
||||
is to print the level value instead of the string name.
|
||||
However, you can use the [`formatters`](/docs/api.md#formatters-object) option
|
||||
with a [`level`](/docs/api.md#level) function to print the string name instead of the level value :
|
||||
|
||||
```js
|
||||
const pino = require('pino')
|
||||
|
||||
const log = pino({
|
||||
formatters: {
|
||||
level: (label) => {
|
||||
return {
|
||||
level: label
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
log.info('message')
|
||||
|
||||
// {"level":"info","time":1661632832200,"pid":18188,"hostname":"foo","msg":"message"}
|
||||
```
|
||||
|
||||
Although it works, we recommend using one of these options instead if you are able:
|
||||
|
||||
1. If the only change desired is the name then a transport can be used. One such
|
||||
transport is [`pino-text-level-transport`](https://npm.im/pino-text-level-transport).
|
||||
1. Use a prettifier like [`pino-pretty`](https://npm.im/pino-pretty) to make
|
||||
the logs human friendly.
|
||||
|
||||
<a id="debug"></a>
|
||||
## Pino with `debug`
|
||||
|
||||
The popular [`debug`](https://npm.im/debug) is used in many modules across the ecosystem.
|
||||
|
||||
The [`pino-debug`](https://github.com/pinojs/pino-debug) module
|
||||
can capture calls to `debug` loggers and run them
|
||||
through `pino` instead. This results in a 10x (20x in asynchronous mode)
|
||||
performance improvement - even though `pino-debug` is logging additional
|
||||
data and wrapping it in JSON.
|
||||
|
||||
To quickly enable this install [`pino-debug`](https://github.com/pinojs/pino-debug)
|
||||
and preload it with the `-r` flag, enabling any `debug` logs with the
|
||||
`DEBUG` environment variable:
|
||||
|
||||
```sh
|
||||
$ npm i pino-debug
|
||||
$ DEBUG=* node -r pino-debug app.js
|
||||
```
|
||||
|
||||
[`pino-debug`](https://github.com/pinojs/pino-debug) also offers fine-grain control to map specific `debug`
|
||||
namespaces to `pino` log levels. See [`pino-debug`](https://github.com/pinojs/pino-debug)
|
||||
for more.
|
||||
|
||||
<a id="windows"></a>
|
||||
## Unicode and Windows terminal
|
||||
|
||||
Pino uses [sonic-boom](https://github.com/mcollina/sonic-boom) to speed
|
||||
up logging. Internally, it uses [`fs.write`](https://nodejs.org/dist/latest-v10.x/docs/api/fs.html#fs_fs_write_fd_string_position_encoding_callback) to write log lines directly to a file
|
||||
descriptor. On Windows, Unicode output is not handled properly in the
|
||||
terminal (both `cmd.exe` and PowerShell), and as such the output could
|
||||
be visualized incorrectly if the log lines include utf8 characters. It
|
||||
is possible to configure the terminal to visualize those characters
|
||||
correctly with the use of [`chcp`](https://ss64.com/nt/chcp.html) by
|
||||
executing in the terminal `chcp 65001`. This is a known limitation of
|
||||
Node.js.
|
||||
|
||||
<a id="stackdriver"></a>
|
||||
## Mapping Pino Log Levels to Google Cloud Logging (Stackdriver) Severity Levels
|
||||
|
||||
Google Cloud Logging uses `severity` levels instead of log levels. As a result, all logs may show as INFO
|
||||
level logs while completely ignoring the level set in the pino log. Google Cloud Logging also prefers that
|
||||
log data is present inside a `message` key instead of the default `msg` key that Pino uses. Use a technique
|
||||
similar to the one below to retain log levels in Google Cloud Logging
|
||||
|
||||
```js
|
||||
const pino = require('pino')
|
||||
|
||||
// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity
|
||||
const PinoLevelToSeverityLookup = {
|
||||
trace: 'DEBUG',
|
||||
debug: 'DEBUG',
|
||||
info: 'INFO',
|
||||
warn: 'WARNING',
|
||||
error: 'ERROR',
|
||||
fatal: 'CRITICAL',
|
||||
};
|
||||
|
||||
const defaultPinoConf = {
|
||||
messageKey: 'message',
|
||||
formatters: {
|
||||
level(label, number) {
|
||||
return {
|
||||
severity: PinoLevelToSeverityLookup[label] || PinoLevelToSeverityLookup['info'],
|
||||
level: number,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = function createLogger(options) {
|
||||
return pino(Object.assign({}, options, defaultPinoConf))
|
||||
}
|
||||
```
|
||||
|
||||
A library that configures Pino for
|
||||
[Google Cloud Structured Logging](https://cloud.google.com/logging/docs/structured-logging)
|
||||
is available at:
|
||||
[@google-cloud/pino-logging-gcp-config](https://www.npmjs.com/package/@google-cloud/pino-logging-gcp-config)
|
||||
|
||||
This library has the following features:
|
||||
|
||||
+ Converts Pino log levels to Google Cloud Logging log levels, as above
|
||||
+ Uses `message` instead of `msg` for the message key, as above
|
||||
+ Adds a millisecond-granularity timestamp in the
|
||||
[structure](https://cloud.google.com/logging/docs/agent/logging/configuration#timestamp-processing)
|
||||
recognised by Google Cloud Logging eg: \
|
||||
`"timestamp":{"seconds":1445470140,"nanos":123000000}`
|
||||
+ Adds a sequential
|
||||
[`insertId`](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#FIELDS.insert_id)
|
||||
to ensure log messages with identical timestamps are ordered correctly.
|
||||
+ Logs including an `Error` object have the
|
||||
[`stack_trace`](https://cloud.google.com/error-reporting/docs/formatting-error-messages#log-error)
|
||||
property set so that the error is forwarded to Google Cloud Error Reporting.
|
||||
+ Includes a
|
||||
[`ServiceContext`](https://cloud.google.com/error-reporting/reference/rest/v1beta1/ServiceContext)
|
||||
object in the logs for Google Cloud Error Reporting, auto detected from the
|
||||
environment if not specified
|
||||
+ Maps the OpenTelemetry properties `span_id`, `trace_id`, and `trace_flags`
|
||||
to the equivalent Google Cloud Logging fields.
|
||||
|
||||
<a id="grafana-loki"></a>
|
||||
## Using Grafana Loki to evaluate pino logs in a kubernetes cluster
|
||||
|
||||
To get pino logs into Grafana Loki there are two options:
|
||||
|
||||
1. **Push:** Use [pino-loki](https://github.com/Julien-R44/pino-loki) to send logs directly to Loki.
|
||||
1. **Pull:** Configure Grafana Promtail to read and properly parse the logs before sending them to Loki.
|
||||
Similar to Google Cloud logging, this involves remapping the log levels. See this [article](https://medium.com/@janpaepke/structured-logging-in-the-grafana-monitoring-stack-8aff0a5af2f5) for details.
|
||||
|
||||
<a id="avoid-message-conflict"></a>
|
||||
## Avoid Message Conflict
|
||||
|
||||
As described in the [`message` documentation](/docs/api.md#message), when a log
|
||||
is written like `log.info({ msg: 'a message' }, 'another message')` then the
|
||||
final output JSON will have `"msg":"another message"` and the `'a message'`
|
||||
string will be lost. To overcome this, the [`logMethod` hook](/docs/api.md#logmethod)
|
||||
can be used:
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
|
||||
const log = require('pino')({
|
||||
level: 'debug',
|
||||
hooks: {
|
||||
logMethod (inputArgs, method) {
|
||||
if (inputArgs.length === 2 && inputArgs[0].msg) {
|
||||
inputArgs[0].originalMsg = inputArgs[0].msg
|
||||
}
|
||||
return method.apply(this, inputArgs)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
log.info('no original message')
|
||||
log.info({ msg: 'mapped to originalMsg' }, 'a message')
|
||||
|
||||
// {"level":30,"time":1596313323106,"pid":63739,"hostname":"foo","msg":"no original message"}
|
||||
// {"level":30,"time":1596313323107,"pid":63739,"hostname":"foo","msg":"a message","originalMsg":"mapped to originalMsg"}
|
||||
```
|
||||
|
||||
<a id="best-performance-for-stdout"></a>
|
||||
## Best performance for logging to `stdout`
|
||||
|
||||
The best performance for logging directly to stdout is _usually_ achieved by using the
|
||||
default configuration:
|
||||
|
||||
```js
|
||||
const log = require('pino')();
|
||||
```
|
||||
|
||||
You should only have to configure custom transports or other settings
|
||||
if you have broader logging requirements.
|
||||
|
||||
<a id="testing"></a>
|
||||
## Testing
|
||||
|
||||
See [`pino-test`](https://github.com/pinojs/pino-test).
|
||||
@@ -0,0 +1,659 @@
|
||||
import type * as JSONSchema from "../core/json-schema.js";
|
||||
import { type $ZodRegistry, globalRegistry } from "../core/registries.js";
|
||||
import * as _checks from "./checks.js";
|
||||
import * as _iso from "./iso.js";
|
||||
import * as _schemas from "./schemas.js";
|
||||
import type { ZodNumber, ZodString, ZodType } from "./schemas.js";
|
||||
|
||||
// Local z object to avoid circular dependency with ../index.js
|
||||
const z = {
|
||||
..._schemas,
|
||||
..._checks,
|
||||
iso: _iso,
|
||||
};
|
||||
|
||||
type JSONSchemaVersion = "draft-2020-12" | "draft-7" | "draft-4" | "openapi-3.0";
|
||||
|
||||
interface FromJSONSchemaParams {
|
||||
defaultTarget?: JSONSchemaVersion;
|
||||
registry?: $ZodRegistry<any>;
|
||||
}
|
||||
|
||||
interface ConversionContext {
|
||||
version: JSONSchemaVersion;
|
||||
defs: Record<string, JSONSchema.JSONSchema>;
|
||||
refs: Map<string, ZodType>;
|
||||
processing: Set<string>;
|
||||
rootSchema: JSONSchema.JSONSchema;
|
||||
registry: $ZodRegistry<any>;
|
||||
}
|
||||
|
||||
// Keys that are recognized and handled by the conversion logic
|
||||
const RECOGNIZED_KEYS = /*@__PURE__*/ new Set([
|
||||
// Schema identification
|
||||
"$schema",
|
||||
"$ref",
|
||||
"$defs",
|
||||
"definitions",
|
||||
// Core schema keywords
|
||||
"$id",
|
||||
"id",
|
||||
"$comment",
|
||||
"$anchor",
|
||||
"$vocabulary",
|
||||
"$dynamicRef",
|
||||
"$dynamicAnchor",
|
||||
// Type
|
||||
"type",
|
||||
"enum",
|
||||
"const",
|
||||
// Composition
|
||||
"anyOf",
|
||||
"oneOf",
|
||||
"allOf",
|
||||
"not",
|
||||
// Object
|
||||
"properties",
|
||||
"required",
|
||||
"additionalProperties",
|
||||
"patternProperties",
|
||||
"propertyNames",
|
||||
"minProperties",
|
||||
"maxProperties",
|
||||
// Array
|
||||
"items",
|
||||
"prefixItems",
|
||||
"additionalItems",
|
||||
"minItems",
|
||||
"maxItems",
|
||||
"uniqueItems",
|
||||
"contains",
|
||||
"minContains",
|
||||
"maxContains",
|
||||
// String
|
||||
"minLength",
|
||||
"maxLength",
|
||||
"pattern",
|
||||
"format",
|
||||
// Number
|
||||
"minimum",
|
||||
"maximum",
|
||||
"exclusiveMinimum",
|
||||
"exclusiveMaximum",
|
||||
"multipleOf",
|
||||
// Already handled metadata
|
||||
"description",
|
||||
"default",
|
||||
// Content
|
||||
"contentEncoding",
|
||||
"contentMediaType",
|
||||
"contentSchema",
|
||||
// Unsupported (error-throwing)
|
||||
"unevaluatedItems",
|
||||
"unevaluatedProperties",
|
||||
"if",
|
||||
"then",
|
||||
"else",
|
||||
"dependentSchemas",
|
||||
"dependentRequired",
|
||||
// OpenAPI
|
||||
"nullable",
|
||||
"readOnly",
|
||||
]);
|
||||
|
||||
function detectVersion(schema: JSONSchema.JSONSchema, defaultTarget?: JSONSchemaVersion): JSONSchemaVersion {
|
||||
const $schema = schema.$schema;
|
||||
|
||||
if ($schema === "https://json-schema.org/draft/2020-12/schema") {
|
||||
return "draft-2020-12";
|
||||
}
|
||||
if ($schema === "http://json-schema.org/draft-07/schema#") {
|
||||
return "draft-7";
|
||||
}
|
||||
if ($schema === "http://json-schema.org/draft-04/schema#") {
|
||||
return "draft-4";
|
||||
}
|
||||
|
||||
// Use defaultTarget if provided, otherwise default to draft-2020-12
|
||||
return defaultTarget ?? "draft-2020-12";
|
||||
}
|
||||
|
||||
function resolveRef(ref: string, ctx: ConversionContext): JSONSchema.JSONSchema {
|
||||
if (!ref.startsWith("#")) {
|
||||
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
||||
}
|
||||
|
||||
const path = ref.slice(1).split("/").filter(Boolean);
|
||||
|
||||
// Handle root reference "#"
|
||||
if (path.length === 0) {
|
||||
return ctx.rootSchema;
|
||||
}
|
||||
|
||||
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
||||
|
||||
if (path[0] === defsKey) {
|
||||
const key = path[1];
|
||||
if (!key || !ctx.defs[key]) {
|
||||
throw new Error(`Reference not found: ${ref}`);
|
||||
}
|
||||
return ctx.defs[key]!;
|
||||
}
|
||||
|
||||
throw new Error(`Reference not found: ${ref}`);
|
||||
}
|
||||
|
||||
function convertBaseSchema(schema: JSONSchema.JSONSchema, ctx: ConversionContext): ZodType {
|
||||
// Handle unsupported features
|
||||
if (schema.not !== undefined) {
|
||||
// Special case: { not: {} } represents never
|
||||
if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) {
|
||||
return z.never();
|
||||
}
|
||||
throw new Error("not is not supported in Zod (except { not: {} } for never)");
|
||||
}
|
||||
if (schema.unevaluatedItems !== undefined) {
|
||||
throw new Error("unevaluatedItems is not supported");
|
||||
}
|
||||
if (schema.unevaluatedProperties !== undefined) {
|
||||
throw new Error("unevaluatedProperties is not supported");
|
||||
}
|
||||
if (schema.if !== undefined || schema.then !== undefined || schema.else !== undefined) {
|
||||
throw new Error("Conditional schemas (if/then/else) are not supported");
|
||||
}
|
||||
if (schema.dependentSchemas !== undefined || schema.dependentRequired !== undefined) {
|
||||
throw new Error("dependentSchemas and dependentRequired are not supported");
|
||||
}
|
||||
|
||||
// Handle $ref
|
||||
if (schema.$ref) {
|
||||
const refPath = schema.$ref;
|
||||
if (ctx.refs.has(refPath)) {
|
||||
return ctx.refs.get(refPath)!;
|
||||
}
|
||||
|
||||
if (ctx.processing.has(refPath)) {
|
||||
// Circular reference - use lazy
|
||||
return z.lazy(() => {
|
||||
if (!ctx.refs.has(refPath)) {
|
||||
throw new Error(`Circular reference not resolved: ${refPath}`);
|
||||
}
|
||||
return ctx.refs.get(refPath)!;
|
||||
});
|
||||
}
|
||||
|
||||
ctx.processing.add(refPath);
|
||||
const resolved = resolveRef(refPath, ctx);
|
||||
const zodSchema = convertSchema(resolved, ctx);
|
||||
ctx.refs.set(refPath, zodSchema);
|
||||
ctx.processing.delete(refPath);
|
||||
return zodSchema;
|
||||
}
|
||||
|
||||
// Handle enum
|
||||
if (schema.enum !== undefined) {
|
||||
const enumValues = schema.enum;
|
||||
|
||||
// Special case: OpenAPI 3.0 null representation { type: "string", nullable: true, enum: [null] }
|
||||
if (
|
||||
ctx.version === "openapi-3.0" &&
|
||||
schema.nullable === true &&
|
||||
enumValues.length === 1 &&
|
||||
enumValues[0] === null
|
||||
) {
|
||||
return z.null();
|
||||
}
|
||||
|
||||
if (enumValues.length === 0) {
|
||||
return z.never();
|
||||
}
|
||||
if (enumValues.length === 1) {
|
||||
return z.literal(enumValues[0]!);
|
||||
}
|
||||
// Check if all values are strings
|
||||
if (enumValues.every((v) => typeof v === "string")) {
|
||||
return z.enum(enumValues as [string, ...string[]]);
|
||||
}
|
||||
// Mixed types - use union of literals
|
||||
const literalSchemas = enumValues.map((v) => z.literal(v));
|
||||
if (literalSchemas.length < 2) {
|
||||
return literalSchemas[0]!;
|
||||
}
|
||||
return z.union([literalSchemas[0]!, literalSchemas[1]!, ...literalSchemas.slice(2)] as [
|
||||
ZodType,
|
||||
ZodType,
|
||||
...ZodType[],
|
||||
]);
|
||||
}
|
||||
|
||||
// Handle const
|
||||
if (schema.const !== undefined) {
|
||||
return z.literal(schema.const);
|
||||
}
|
||||
|
||||
// Handle type
|
||||
const type = schema.type;
|
||||
|
||||
if (Array.isArray(type)) {
|
||||
// Expand type array into anyOf union
|
||||
const typeSchemas = type.map((t) => {
|
||||
const typeSchema: JSONSchema.JSONSchema = { ...schema, type: t };
|
||||
return convertBaseSchema(typeSchema, ctx);
|
||||
});
|
||||
if (typeSchemas.length === 0) {
|
||||
return z.never();
|
||||
}
|
||||
if (typeSchemas.length === 1) {
|
||||
return typeSchemas[0]!;
|
||||
}
|
||||
return z.union(typeSchemas as [ZodType, ZodType, ...ZodType[]]);
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
// No type specified - empty schema (any)
|
||||
return z.any();
|
||||
}
|
||||
|
||||
let zodSchema: ZodType;
|
||||
|
||||
switch (type) {
|
||||
case "string": {
|
||||
let stringSchema: ZodString = z.string();
|
||||
|
||||
// Apply format using .check() with Zod format functions
|
||||
if (schema.format) {
|
||||
const format = schema.format;
|
||||
// Map common formats to Zod check functions
|
||||
if (format === "email") {
|
||||
stringSchema = stringSchema.check(z.email());
|
||||
} else if (format === "uri" || format === "uri-reference") {
|
||||
stringSchema = stringSchema.check(z.url());
|
||||
} else if (format === "uuid" || format === "guid") {
|
||||
stringSchema = stringSchema.check(z.uuid());
|
||||
} else if (format === "date-time") {
|
||||
stringSchema = stringSchema.check(z.iso.datetime());
|
||||
} else if (format === "date") {
|
||||
stringSchema = stringSchema.check(z.iso.date());
|
||||
} else if (format === "time") {
|
||||
stringSchema = stringSchema.check(z.iso.time());
|
||||
} else if (format === "duration") {
|
||||
stringSchema = stringSchema.check(z.iso.duration());
|
||||
} else if (format === "ipv4") {
|
||||
stringSchema = stringSchema.check(z.ipv4());
|
||||
} else if (format === "ipv6") {
|
||||
stringSchema = stringSchema.check(z.ipv6());
|
||||
} else if (format === "mac") {
|
||||
stringSchema = stringSchema.check(z.mac());
|
||||
} else if (format === "cidr") {
|
||||
stringSchema = stringSchema.check(z.cidrv4());
|
||||
} else if (format === "cidr-v6") {
|
||||
stringSchema = stringSchema.check(z.cidrv6());
|
||||
} else if (format === "base64") {
|
||||
stringSchema = stringSchema.check(z.base64());
|
||||
} else if (format === "base64url") {
|
||||
stringSchema = stringSchema.check(z.base64url());
|
||||
} else if (format === "e164") {
|
||||
stringSchema = stringSchema.check(z.e164());
|
||||
} else if (format === "jwt") {
|
||||
stringSchema = stringSchema.check(z.jwt());
|
||||
} else if (format === "emoji") {
|
||||
stringSchema = stringSchema.check(z.emoji());
|
||||
} else if (format === "nanoid") {
|
||||
stringSchema = stringSchema.check(z.nanoid());
|
||||
} else if (format === "cuid") {
|
||||
stringSchema = stringSchema.check(z.cuid());
|
||||
} else if (format === "cuid2") {
|
||||
stringSchema = stringSchema.check(z.cuid2());
|
||||
} else if (format === "ulid") {
|
||||
stringSchema = stringSchema.check(z.ulid());
|
||||
} else if (format === "xid") {
|
||||
stringSchema = stringSchema.check(z.xid());
|
||||
} else if (format === "ksuid") {
|
||||
stringSchema = stringSchema.check(z.ksuid());
|
||||
}
|
||||
// Note: json-string format is not currently supported by Zod
|
||||
// Custom formats are ignored - keep as plain string
|
||||
}
|
||||
|
||||
// Apply constraints
|
||||
if (typeof schema.minLength === "number") {
|
||||
stringSchema = stringSchema.min(schema.minLength);
|
||||
}
|
||||
if (typeof schema.maxLength === "number") {
|
||||
stringSchema = stringSchema.max(schema.maxLength);
|
||||
}
|
||||
if (schema.pattern) {
|
||||
// JSON Schema patterns are not implicitly anchored (match anywhere in string)
|
||||
stringSchema = stringSchema.regex(new RegExp(schema.pattern));
|
||||
}
|
||||
|
||||
zodSchema = stringSchema;
|
||||
break;
|
||||
}
|
||||
|
||||
case "number":
|
||||
case "integer": {
|
||||
let numberSchema: ZodNumber = type === "integer" ? z.number().int() : z.number();
|
||||
|
||||
// Apply constraints
|
||||
if (typeof schema.minimum === "number") {
|
||||
numberSchema = numberSchema.min(schema.minimum);
|
||||
}
|
||||
if (typeof schema.maximum === "number") {
|
||||
numberSchema = numberSchema.max(schema.maximum);
|
||||
}
|
||||
if (typeof schema.exclusiveMinimum === "number") {
|
||||
numberSchema = numberSchema.gt(schema.exclusiveMinimum);
|
||||
} else if (schema.exclusiveMinimum === true && typeof schema.minimum === "number") {
|
||||
numberSchema = numberSchema.gt(schema.minimum);
|
||||
}
|
||||
if (typeof schema.exclusiveMaximum === "number") {
|
||||
numberSchema = numberSchema.lt(schema.exclusiveMaximum);
|
||||
} else if (schema.exclusiveMaximum === true && typeof schema.maximum === "number") {
|
||||
numberSchema = numberSchema.lt(schema.maximum);
|
||||
}
|
||||
if (typeof schema.multipleOf === "number") {
|
||||
numberSchema = numberSchema.multipleOf(schema.multipleOf);
|
||||
}
|
||||
|
||||
zodSchema = numberSchema;
|
||||
break;
|
||||
}
|
||||
|
||||
case "boolean": {
|
||||
zodSchema = z.boolean();
|
||||
break;
|
||||
}
|
||||
|
||||
case "null": {
|
||||
zodSchema = z.null();
|
||||
break;
|
||||
}
|
||||
|
||||
case "object": {
|
||||
const shape: Record<string, ZodType> = {};
|
||||
const properties = schema.properties || {};
|
||||
const requiredSet = new Set(schema.required || []);
|
||||
|
||||
// Convert properties - mark optional ones
|
||||
for (const [key, propSchema] of Object.entries(properties)) {
|
||||
const propZodSchema = convertSchema(propSchema as JSONSchema.JSONSchema, ctx);
|
||||
// If not in required array, make it optional
|
||||
shape[key] = requiredSet.has(key) ? propZodSchema : propZodSchema.optional();
|
||||
}
|
||||
|
||||
// Handle propertyNames
|
||||
if (schema.propertyNames) {
|
||||
const keySchema = convertSchema(schema.propertyNames, ctx) as ZodString;
|
||||
const valueSchema =
|
||||
schema.additionalProperties && typeof schema.additionalProperties === "object"
|
||||
? convertSchema(schema.additionalProperties as JSONSchema.JSONSchema, ctx)
|
||||
: z.any();
|
||||
|
||||
// Case A: No properties (pure record)
|
||||
if (Object.keys(shape).length === 0) {
|
||||
zodSchema = z.record(keySchema, valueSchema);
|
||||
break;
|
||||
}
|
||||
|
||||
// Case B: With properties (intersection of object and looseRecord)
|
||||
const objectSchema = z.object(shape).passthrough();
|
||||
const recordSchema = z.looseRecord(keySchema, valueSchema);
|
||||
zodSchema = z.intersection(objectSchema, recordSchema);
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle patternProperties
|
||||
if (schema.patternProperties) {
|
||||
// patternProperties: keys matching pattern must satisfy corresponding schema
|
||||
// Use loose records so non-matching keys pass through
|
||||
const patternProps = schema.patternProperties;
|
||||
const patternKeys = Object.keys(patternProps);
|
||||
const looseRecords: ZodType[] = [];
|
||||
|
||||
for (const pattern of patternKeys) {
|
||||
const patternValue = convertSchema(patternProps[pattern] as JSONSchema.JSONSchema, ctx);
|
||||
const keySchema = z.string().regex(new RegExp(pattern));
|
||||
looseRecords.push(z.looseRecord(keySchema, patternValue));
|
||||
}
|
||||
|
||||
// Build intersection: object schema + all pattern property records
|
||||
const schemasToIntersect: ZodType[] = [];
|
||||
if (Object.keys(shape).length > 0) {
|
||||
// Use passthrough so patternProperties can validate additional keys
|
||||
schemasToIntersect.push(z.object(shape).passthrough());
|
||||
}
|
||||
schemasToIntersect.push(...looseRecords);
|
||||
|
||||
if (schemasToIntersect.length === 0) {
|
||||
zodSchema = z.object({}).passthrough();
|
||||
} else if (schemasToIntersect.length === 1) {
|
||||
zodSchema = schemasToIntersect[0]!;
|
||||
} else {
|
||||
// Chain intersections: (A & B) & C & D ...
|
||||
let result = z.intersection(schemasToIntersect[0]!, schemasToIntersect[1]!);
|
||||
for (let i = 2; i < schemasToIntersect.length; i++) {
|
||||
result = z.intersection(result, schemasToIntersect[i]!);
|
||||
}
|
||||
zodSchema = result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle additionalProperties
|
||||
// In JSON Schema, additionalProperties defaults to true (allow any extra properties)
|
||||
// In Zod, objects strip unknown keys by default, so we need to handle this explicitly
|
||||
const objectSchema = z.object(shape);
|
||||
if (schema.additionalProperties === false) {
|
||||
// Strict mode - no extra properties allowed
|
||||
zodSchema = objectSchema.strict();
|
||||
} else if (typeof schema.additionalProperties === "object") {
|
||||
// Extra properties must match the specified schema
|
||||
zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties as JSONSchema.JSONSchema, ctx));
|
||||
} else {
|
||||
// additionalProperties is true or undefined - allow any extra properties (passthrough)
|
||||
zodSchema = objectSchema.passthrough();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "array": {
|
||||
// TODO: uniqueItems is not supported
|
||||
// TODO: contains/minContains/maxContains are not supported
|
||||
// Check if this is a tuple (prefixItems or items as array)
|
||||
const prefixItems = schema.prefixItems;
|
||||
const items = schema.items;
|
||||
|
||||
if (prefixItems && Array.isArray(prefixItems)) {
|
||||
// Tuple with prefixItems (draft-2020-12)
|
||||
const tupleItems = prefixItems.map((item) => convertSchema(item as JSONSchema.JSONSchema, ctx));
|
||||
const rest =
|
||||
items && typeof items === "object" && !Array.isArray(items)
|
||||
? convertSchema(items as JSONSchema.JSONSchema, ctx)
|
||||
: undefined;
|
||||
if (rest) {
|
||||
zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]).rest(rest);
|
||||
} else {
|
||||
zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]);
|
||||
}
|
||||
// Apply minItems/maxItems constraints to tuples
|
||||
if (typeof schema.minItems === "number") {
|
||||
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
||||
}
|
||||
if (typeof schema.maxItems === "number") {
|
||||
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
||||
}
|
||||
} else if (Array.isArray(items)) {
|
||||
// Tuple with items array (draft-7)
|
||||
const tupleItems = items.map((item) => convertSchema(item as JSONSchema.JSONSchema, ctx));
|
||||
const rest =
|
||||
schema.additionalItems && typeof schema.additionalItems === "object"
|
||||
? convertSchema(schema.additionalItems as JSONSchema.JSONSchema, ctx)
|
||||
: undefined; // additionalItems: false means no rest, handled by default tuple behavior
|
||||
if (rest) {
|
||||
zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]).rest(rest);
|
||||
} else {
|
||||
zodSchema = z.tuple(tupleItems as [ZodType, ...ZodType[]]);
|
||||
}
|
||||
// Apply minItems/maxItems constraints to tuples
|
||||
if (typeof schema.minItems === "number") {
|
||||
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
||||
}
|
||||
if (typeof schema.maxItems === "number") {
|
||||
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
||||
}
|
||||
} else if (items !== undefined) {
|
||||
// Regular array
|
||||
const element = convertSchema(items as JSONSchema.JSONSchema, ctx);
|
||||
let arraySchema = z.array(element);
|
||||
|
||||
// Apply constraints
|
||||
if (typeof schema.minItems === "number") {
|
||||
arraySchema = arraySchema.min(schema.minItems);
|
||||
}
|
||||
if (typeof schema.maxItems === "number") {
|
||||
arraySchema = arraySchema.max(schema.maxItems);
|
||||
}
|
||||
|
||||
zodSchema = arraySchema;
|
||||
} else {
|
||||
// No items specified - array of any
|
||||
zodSchema = z.array(z.any());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported type: ${type}`);
|
||||
}
|
||||
|
||||
return zodSchema;
|
||||
}
|
||||
|
||||
function convertSchema(schema: JSONSchema.JSONSchema | boolean, ctx: ConversionContext): ZodType {
|
||||
if (typeof schema === "boolean") {
|
||||
return schema ? z.any() : z.never();
|
||||
}
|
||||
|
||||
// Convert base schema first (ignoring composition keywords)
|
||||
let baseSchema = convertBaseSchema(schema, ctx);
|
||||
const hasExplicitType = schema.type || schema.enum !== undefined || schema.const !== undefined;
|
||||
|
||||
// Process composition keywords LAST (they can appear together)
|
||||
// Handle anyOf - wrap base schema with union
|
||||
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
||||
const options = schema.anyOf.map((s) => convertSchema(s, ctx));
|
||||
const anyOfUnion = z.union(options as [ZodType, ZodType, ...ZodType[]]);
|
||||
baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion;
|
||||
}
|
||||
|
||||
// Handle oneOf - exclusive union (exactly one must match)
|
||||
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
||||
const options = schema.oneOf.map((s) => convertSchema(s, ctx));
|
||||
const oneOfUnion = z.xor(options as [ZodType, ZodType, ...ZodType[]]);
|
||||
baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
|
||||
}
|
||||
|
||||
// Handle allOf - wrap base schema with intersection
|
||||
if (schema.allOf && Array.isArray(schema.allOf)) {
|
||||
if (schema.allOf.length === 0) {
|
||||
baseSchema = hasExplicitType ? baseSchema : z.any();
|
||||
} else {
|
||||
let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0]!, ctx);
|
||||
const startIdx = hasExplicitType ? 0 : 1;
|
||||
for (let i = startIdx; i < schema.allOf.length; i++) {
|
||||
result = z.intersection(result, convertSchema(schema.allOf[i]!, ctx));
|
||||
}
|
||||
baseSchema = result;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle nullable (OpenAPI 3.0)
|
||||
if (schema.nullable === true && ctx.version === "openapi-3.0") {
|
||||
baseSchema = z.nullable(baseSchema);
|
||||
}
|
||||
|
||||
// Handle readOnly
|
||||
if (schema.readOnly === true) {
|
||||
baseSchema = z.readonly(baseSchema);
|
||||
}
|
||||
|
||||
// Apply `default` so it wraps the fully-composed schema. This ensures
|
||||
// `parse(undefined) -> default` works regardless of which branch of
|
||||
// `convertBaseSchema` produced the inner schema (enum/const/not/typed/etc.).
|
||||
if (schema.default !== undefined) {
|
||||
baseSchema = baseSchema.default(schema.default);
|
||||
}
|
||||
|
||||
// Collect non-description annotation metadata into the user-supplied
|
||||
// registry. Description is handled separately below via `.describe()` to
|
||||
// preserve the contract that `schema.description` reads from globalRegistry.
|
||||
const extraMeta: Record<string, unknown> = {};
|
||||
|
||||
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
||||
for (const key of coreMetadataKeys) {
|
||||
if (key in schema) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
|
||||
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
||||
for (const key of contentMetadataKeys) {
|
||||
if (key in schema) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(schema)) {
|
||||
if (!RECOGNIZED_KEYS.has(key)) {
|
||||
extraMeta[key] = schema[key];
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(extraMeta).length > 0) {
|
||||
ctx.registry.add(baseSchema, extraMeta);
|
||||
}
|
||||
|
||||
// Apply description last. `.describe()` clones the schema and sets
|
||||
// `_zod.parent` on the clone, so registry lookups on the returned reference
|
||||
// still resolve `extraMeta` via parent inheritance.
|
||||
if (schema.description) {
|
||||
baseSchema = baseSchema.describe(schema.description);
|
||||
}
|
||||
|
||||
return baseSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JSON Schema to a Zod schema. This function should be considered semi-experimental. It's behavior is liable to change. */
|
||||
export function fromJSONSchema(schema: JSONSchema.JSONSchema | boolean, params?: FromJSONSchemaParams): ZodType {
|
||||
// Handle boolean schemas
|
||||
if (typeof schema === "boolean") {
|
||||
return schema ? z.any() : z.never();
|
||||
}
|
||||
|
||||
// Normalize input via a JSON round-trip. This guarantees the converter
|
||||
// walks a plain, finite, JSON-valid object graph: cyclic inputs fail here,
|
||||
// getter/Proxy-based properties are materialized into static values, and
|
||||
// class instances collapse to plain objects.
|
||||
let normalized: JSONSchema.JSONSchema;
|
||||
try {
|
||||
normalized = JSON.parse(JSON.stringify(schema));
|
||||
} catch {
|
||||
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
||||
}
|
||||
|
||||
const version = detectVersion(normalized, params?.defaultTarget);
|
||||
const defs = (normalized.$defs || normalized.definitions || {}) as Record<string, JSONSchema.JSONSchema>;
|
||||
|
||||
const ctx: ConversionContext = {
|
||||
version,
|
||||
defs,
|
||||
refs: new Map(),
|
||||
processing: new Set(),
|
||||
rootSchema: normalized,
|
||||
registry: params?.registry ?? globalRegistry,
|
||||
};
|
||||
|
||||
return convertSchema(normalized, ctx);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
function _apply_decorated_descriptor(target, property, decorators, descriptor, context) {
|
||||
var desc = {};
|
||||
|
||||
Object["ke" + "ys"](descriptor).forEach(function(key) {
|
||||
desc[key] = descriptor[key];
|
||||
});
|
||||
desc.enumerable = !!desc.enumerable;
|
||||
desc.configurable = !!desc.configurable;
|
||||
|
||||
if ("value" in desc || desc.initializer) desc.writable = true;
|
||||
desc = decorators.slice().reverse().reduce(function(desc, decorator) {
|
||||
return decorator ? decorator(target, property, desc) || desc : desc;
|
||||
}, desc);
|
||||
|
||||
var hasAccessor = Object.prototype.hasOwnProperty.call(desc, "get") || Object.prototype.hasOwnProperty.call(desc, "set");
|
||||
|
||||
if (context && desc.initializer !== void 0 && !hasAccessor) {
|
||||
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
|
||||
desc.initializer = undefined;
|
||||
}
|
||||
if (hasAccessor) {
|
||||
delete desc.writable;
|
||||
delete desc.initializer;
|
||||
delete desc.value;
|
||||
}
|
||||
if (desc.initializer === void 0) {
|
||||
Object["define" + "Property"](target, property, desc);
|
||||
desc = null;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
export { _apply_decorated_descriptor as _ };
|
||||
@@ -0,0 +1,104 @@
|
||||
[](https://prettier.io)
|
||||
|
||||
<h2 align="center">Opinionated Code Formatter</h2>
|
||||
|
||||
<p align="center">
|
||||
<em>
|
||||
JavaScript
|
||||
· TypeScript
|
||||
· Flow
|
||||
· JSX
|
||||
· JSON
|
||||
</em>
|
||||
<br />
|
||||
<em>
|
||||
CSS
|
||||
· SCSS
|
||||
· Less
|
||||
</em>
|
||||
<br />
|
||||
<em>
|
||||
HTML
|
||||
· Vue
|
||||
· Angular
|
||||
</em>
|
||||
<br />
|
||||
<em>
|
||||
GraphQL
|
||||
· Markdown
|
||||
· YAML
|
||||
</em>
|
||||
<br />
|
||||
<em>
|
||||
<a href="https://prettier.io/docs/plugins">
|
||||
Your favorite language?
|
||||
</a>
|
||||
</em>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/prettier/prettier/actions?query=branch%3Amain">
|
||||
<img alt="CI Status" src="https://img.shields.io/github/check-runs/prettier/prettier/main?style=flat-square&label=CI"></a>
|
||||
<a href="https://codecov.io/gh/prettier/prettier">
|
||||
<img alt="Coverage Status" src="https://img.shields.io/codecov/c/github/prettier/prettier.svg?style=flat-square"></a>
|
||||
<a href="https://x.com/acdlite/status/974390255393505280">
|
||||
<img alt="Blazing Fast" src="https://img.shields.io/badge/speed-blazing%20%F0%9F%94%A5-brightgreen.svg?style=flat-square"></a>
|
||||
<br/>
|
||||
<a href="https://www.npmjs.com/package/prettier">
|
||||
<img alt="npm version" src="https://img.shields.io/npm/v/prettier.svg?style=flat-square"></a>
|
||||
<a href="https://www.npmjs.com/package/prettier">
|
||||
<img alt="weekly downloads from npm" src="https://img.shields.io/npm/dw/prettier.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/prettier/prettier#badge">
|
||||
<img alt="code style: prettier" src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square"></a>
|
||||
<a href="https://x.com/intent/follow?screen_name=PrettierCode">
|
||||
<img alt="Follow Prettier on X" src="https://img.shields.io/badge/%40PrettierCode-9f9f9f?style=flat-square&logo=x&labelColor=555"></a>
|
||||
</p>
|
||||
|
||||
## Intro
|
||||
|
||||
Prettier is an opinionated code formatter. It enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary.
|
||||
|
||||
### Input
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
foo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne());
|
||||
```
|
||||
|
||||
### Output
|
||||
|
||||
```js
|
||||
foo(
|
||||
reallyLongArg(),
|
||||
omgSoManyParameters(),
|
||||
IShouldRefactorThis(),
|
||||
isThereSeriouslyAnotherOne(),
|
||||
);
|
||||
```
|
||||
|
||||
Prettier can be run [in your editor](https://prettier.io/docs/editors) on-save, in a [pre-commit hook](https://prettier.io/docs/precommit), or in [CI environments](https://prettier.io/docs/cli#list-different) to ensure your codebase has a consistent style without devs ever having to post a nit-picky comment on a code review ever again!
|
||||
|
||||
---
|
||||
|
||||
**[Documentation](https://prettier.io/docs/)**
|
||||
|
||||
[Install](https://prettier.io/docs/install) ·
|
||||
[Options](https://prettier.io/docs/options) ·
|
||||
[CLI](https://prettier.io/docs/cli) ·
|
||||
[API](https://prettier.io/docs/api)
|
||||
|
||||
**[Playground](https://prettier.io/playground/)**
|
||||
|
||||
---
|
||||
|
||||
## Badge
|
||||
|
||||
Show the world you're using _Prettier_ → [](https://github.com/prettier/prettier)
|
||||
|
||||
```md
|
||||
[](https://github.com/prettier/prettier)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
@@ -0,0 +1,4 @@
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"bannedFunctionType", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const util_1 = require("../util");
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'prefer-enum-initializers',
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Require each enum member value to be explicitly initialized',
|
||||
},
|
||||
hasSuggestions: true,
|
||||
messages: {
|
||||
defineInitializer: "The value of the member '{{ name }}' should be explicitly defined.",
|
||||
defineInitializerSuggestion: 'Can be fixed to {{ name }} = {{ suggested }}',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
function TSEnumDeclaration(node) {
|
||||
const { members } = node.body;
|
||||
members.forEach((member, index) => {
|
||||
if (member.initializer == null) {
|
||||
const name = context.sourceCode.getText(member);
|
||||
context.report({
|
||||
node: member,
|
||||
messageId: 'defineInitializer',
|
||||
data: {
|
||||
name,
|
||||
},
|
||||
suggest: [
|
||||
{
|
||||
messageId: 'defineInitializerSuggestion',
|
||||
data: { name, suggested: index },
|
||||
fix: (fixer) => {
|
||||
return fixer.replaceText(member, `${name} = ${index}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
messageId: 'defineInitializerSuggestion',
|
||||
data: { name, suggested: index + 1 },
|
||||
fix: (fixer) => {
|
||||
return fixer.replaceText(member, `${name} = ${index + 1}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
messageId: 'defineInitializerSuggestion',
|
||||
data: { name, suggested: `'${name}'` },
|
||||
fix: (fixer) => {
|
||||
return fixer.replaceText(member, `${name} = '${name}'`);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
TSEnumDeclaration,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
function _defaults(e, r) {
|
||||
for (var t = Object.getOwnPropertyNames(r), o = 0; o < t.length; o++) {
|
||||
var n = t[o],
|
||||
a = Object.getOwnPropertyDescriptor(r, n);
|
||||
a && a.configurable && void 0 === e[n] && Object.defineProperty(e, n, a);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
export { _defaults as default };
|
||||
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2015_collection: LibDefinition;
|
||||
@@ -0,0 +1,187 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const assert = require('node:assert')
|
||||
const serializer = require('../lib/err-with-cause')
|
||||
const { wrapErrorSerializer } = require('../')
|
||||
|
||||
test('serializes Error objects', () => {
|
||||
const serialized = serializer(Error('foo'))
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
})
|
||||
|
||||
test('serializes Error objects with extra properties', () => {
|
||||
const err = Error('foo')
|
||||
err.statusCode = 500
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.ok(serialized.statusCode)
|
||||
assert.strictEqual(serialized.statusCode, 500)
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
})
|
||||
|
||||
test('serializes Error objects with subclass "type"', () => {
|
||||
class MyError extends Error {}
|
||||
|
||||
const err = new MyError('foo')
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.type, 'MyError')
|
||||
})
|
||||
|
||||
test('serializes nested errors', () => {
|
||||
const err = Error('foo')
|
||||
err.inner = Error('bar')
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
assert.strictEqual(serialized.inner.type, 'Error')
|
||||
assert.strictEqual(serialized.inner.message, 'bar')
|
||||
assert.match(serialized.inner.stack, /Error: bar/)
|
||||
assert.match(serialized.inner.stack, /err-with-cause\.test\.js:/)
|
||||
})
|
||||
|
||||
test('serializes error causes', () => {
|
||||
const innerErr = Error('inner')
|
||||
const middleErr = Error('middle')
|
||||
middleErr.cause = innerErr
|
||||
const outerErr = Error('outer')
|
||||
outerErr.cause = middleErr
|
||||
|
||||
const serialized = serializer(outerErr)
|
||||
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'outer')
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
|
||||
assert.strictEqual(serialized.cause.type, 'Error')
|
||||
assert.strictEqual(serialized.cause.message, 'middle')
|
||||
assert.match(serialized.cause.stack, /err-with-cause\.test\.js:/)
|
||||
|
||||
assert.strictEqual(serialized.cause.cause.type, 'Error')
|
||||
assert.strictEqual(serialized.cause.cause.message, 'inner')
|
||||
assert.match(serialized.cause.cause.stack, /err-with-cause\.test\.js:/)
|
||||
})
|
||||
|
||||
test('keeps non-error cause', () => {
|
||||
const err = Error('foo')
|
||||
err.cause = 'abc'
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.strictEqual(serialized.cause, 'abc')
|
||||
})
|
||||
|
||||
test('prevents infinite recursion', () => {
|
||||
const err = Error('foo')
|
||||
err.inner = err
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
assert.ok(!serialized.inner)
|
||||
})
|
||||
|
||||
test('cleans up infinite recursion tracking', () => {
|
||||
const err = Error('foo')
|
||||
const bar = Error('bar')
|
||||
err.inner = bar
|
||||
bar.inner = err
|
||||
|
||||
serializer(err)
|
||||
const serialized = serializer(err)
|
||||
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
assert.ok(serialized.inner)
|
||||
assert.strictEqual(serialized.inner.type, 'Error')
|
||||
assert.strictEqual(serialized.inner.message, 'bar')
|
||||
assert.match(serialized.inner.stack, /Error: bar/)
|
||||
assert.ok(!serialized.inner.inner)
|
||||
})
|
||||
|
||||
test('err.raw is available', () => {
|
||||
const err = Error('foo')
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.raw, err)
|
||||
})
|
||||
|
||||
test('redefined err.constructor doesnt crash serializer', () => {
|
||||
function check (a, name) {
|
||||
assert.strictEqual(a.type, name)
|
||||
assert.strictEqual(a.message, 'foo')
|
||||
}
|
||||
|
||||
const err1 = TypeError('foo')
|
||||
err1.constructor = '10'
|
||||
|
||||
const err2 = TypeError('foo')
|
||||
err2.constructor = undefined
|
||||
|
||||
const err3 = Error('foo')
|
||||
err3.constructor = null
|
||||
|
||||
const err4 = Error('foo')
|
||||
err4.constructor = 10
|
||||
|
||||
class MyError extends Error {}
|
||||
|
||||
const err5 = new MyError('foo')
|
||||
err5.constructor = undefined
|
||||
|
||||
check(serializer(err1), 'TypeError')
|
||||
check(serializer(err2), 'TypeError')
|
||||
check(serializer(err3), 'Error')
|
||||
check(serializer(err4), 'Error')
|
||||
// We do not expect 'MyError' because err5.constructor has been blown away.
|
||||
// `err5.name` is 'Error' from the base class prototype.
|
||||
check(serializer(err5), 'Error')
|
||||
})
|
||||
|
||||
test('pass through anything that does not look like an Error', () => {
|
||||
function check (a) {
|
||||
assert.strictEqual(serializer(a), a)
|
||||
}
|
||||
|
||||
check('foo')
|
||||
check({ hello: 'world' })
|
||||
check([1, 2])
|
||||
})
|
||||
|
||||
test('can wrap err serializers', () => {
|
||||
const err = Error('foo')
|
||||
err.foo = 'foo'
|
||||
const serializer = wrapErrorSerializer(function (err) {
|
||||
delete err.foo
|
||||
err.bar = 'bar'
|
||||
return err
|
||||
})
|
||||
const serialized = serializer(err)
|
||||
assert.strictEqual(serialized.type, 'Error')
|
||||
assert.strictEqual(serialized.message, 'foo')
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
assert.ok(!serialized.foo)
|
||||
assert.strictEqual(serialized.bar, 'bar')
|
||||
})
|
||||
|
||||
test('serializes aggregate errors', { skip: !global.AggregateError }, () => {
|
||||
const foo = new Error('foo')
|
||||
const bar = new Error('bar')
|
||||
for (const aggregate of [
|
||||
new AggregateError([foo, bar], 'aggregated message'),
|
||||
{ errors: [foo, bar], message: 'aggregated message', stack: 'err-with-cause.test.js:' }
|
||||
]) {
|
||||
const serialized = serializer(aggregate)
|
||||
assert.strictEqual(serialized.message, 'aggregated message')
|
||||
assert.strictEqual(serialized.aggregateErrors.length, 2)
|
||||
assert.strictEqual(serialized.aggregateErrors[0].message, 'foo')
|
||||
assert.strictEqual(serialized.aggregateErrors[1].message, 'bar')
|
||||
assert.match(serialized.aggregateErrors[0].stack, /^Error: foo/)
|
||||
assert.match(serialized.aggregateErrors[1].stack, /^Error: bar/)
|
||||
assert.match(serialized.stack, /err-with-cause\.test\.js:/)
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2024_promise: LibDefinition;
|
||||
@@ -0,0 +1,94 @@
|
||||
import { expectTypeOf, test } from "vitest";
|
||||
import * as z from "../index.js";
|
||||
|
||||
test("branded types", () => {
|
||||
const mySchema = z
|
||||
.object({
|
||||
name: z.string(),
|
||||
})
|
||||
.brand<"superschema">();
|
||||
|
||||
// simple branding
|
||||
type MySchema = z.infer<typeof mySchema>;
|
||||
// Using true for type equality assertion
|
||||
expectTypeOf<MySchema>().toEqualTypeOf<{ name: string } & z.$brand<"superschema">>();
|
||||
|
||||
const doStuff = (arg: MySchema) => arg;
|
||||
doStuff(z.parse(mySchema, { name: "hello there" }));
|
||||
|
||||
// inheritance
|
||||
const extendedSchema = mySchema.brand<"subschema">();
|
||||
type ExtendedSchema = z.infer<typeof extendedSchema>;
|
||||
expectTypeOf<ExtendedSchema>().toEqualTypeOf<{ name: string } & z.$brand<"superschema"> & z.$brand<"subschema">>();
|
||||
|
||||
doStuff(z.parse(extendedSchema, { name: "hello again" }));
|
||||
|
||||
// number branding
|
||||
const numberSchema = z.number().brand<42>();
|
||||
type NumberSchema = z.infer<typeof numberSchema>;
|
||||
expectTypeOf<NumberSchema>().toEqualTypeOf<number & { [z.$brand]: { 42: true } }>();
|
||||
|
||||
// symbol branding
|
||||
const MyBrand: unique symbol = Symbol("hello");
|
||||
type MyBrand = typeof MyBrand;
|
||||
const symbolBrand = z.number().brand<"sup">().brand<typeof MyBrand>();
|
||||
type SymbolBrand = z.infer<typeof symbolBrand>;
|
||||
// number & { [z.$brand]: { sup: true, [MyBrand]: true } }
|
||||
expectTypeOf<SymbolBrand>().toEqualTypeOf<number & z.$brand<"sup"> & z.$brand<MyBrand>>();
|
||||
|
||||
// keeping brands out of input types
|
||||
const age = z.number().brand<"age">();
|
||||
type Age1 = z.infer<typeof age>;
|
||||
type AgeInput1 = z.input<typeof age>;
|
||||
|
||||
// Using not for type inequality assertion
|
||||
expectTypeOf<AgeInput1>().not.toEqualTypeOf<Age1>();
|
||||
expectTypeOf<number>().toEqualTypeOf<AgeInput1>();
|
||||
expectTypeOf<number & z.$brand<"age">>().toEqualTypeOf<Age1>();
|
||||
|
||||
// @ts-expect-error
|
||||
doStuff({ name: "hello there!" });
|
||||
});
|
||||
|
||||
test("brand direction: out (default)", () => {
|
||||
const schema = z.string().brand<"A">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// output is branded
|
||||
expectTypeOf<Output>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
// input is NOT branded (default behavior)
|
||||
expectTypeOf<Input>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
test("brand direction: out (explicit)", () => {
|
||||
const schema = z.string().brand<"A", "out">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// output is branded
|
||||
expectTypeOf<Output>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
// input is NOT branded
|
||||
expectTypeOf<Input>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
test("brand direction: in", () => {
|
||||
const schema = z.string().brand<"A", "in">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// input is branded
|
||||
expectTypeOf<Input>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
// output is NOT branded
|
||||
expectTypeOf<Output>().toEqualTypeOf<string>();
|
||||
});
|
||||
|
||||
test("brand direction: inout", () => {
|
||||
const schema = z.string().brand<"A", "inout">();
|
||||
type Input = z.input<typeof schema>;
|
||||
type Output = z.output<typeof schema>;
|
||||
|
||||
// both are branded
|
||||
expectTypeOf<Input>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
expectTypeOf<Output>().toEqualTypeOf<string & z.$brand<"A">>();
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export { _ as default } from "../esm/_array_with_holes.js";
|
||||
@@ -0,0 +1,62 @@
|
||||
export interface Options {
|
||||
/* a list of files to search */
|
||||
files?: string[]
|
||||
/* the directory to search from */
|
||||
cwd?: string
|
||||
/* the directory to stop searching */
|
||||
stopDir?: string
|
||||
/* the key in package.json to read data at */
|
||||
packageKey?: string
|
||||
/* the function used to parse json */
|
||||
parseJSON?: (str: string) => any
|
||||
}
|
||||
|
||||
export interface LoadResult {
|
||||
/* file path */
|
||||
path?: string
|
||||
/* file data */
|
||||
data?: any
|
||||
}
|
||||
|
||||
export interface AsyncLoader {
|
||||
/** Optional loader name */
|
||||
name?: string
|
||||
test: RegExp
|
||||
load(filepath: string): Promise<any>
|
||||
}
|
||||
|
||||
export interface SyncLoader {
|
||||
/** Optional loader name */
|
||||
name?: string
|
||||
test: RegExp
|
||||
loadSync(filepath: string): any
|
||||
}
|
||||
|
||||
export interface MultiLoader {
|
||||
/** Optional loader name */
|
||||
name?: string
|
||||
test: RegExp
|
||||
load(filepath: string): Promise<any>
|
||||
loadSync(filepath: string): any
|
||||
}
|
||||
|
||||
declare class JoyCon {
|
||||
constructor(options?: Options)
|
||||
|
||||
options: Options
|
||||
|
||||
resolve(files?: string[] | Options, cwd?: string, stopDir?: string): Promise<string | null>
|
||||
resolveSync(files?: string[] | Options, cwd?: string, stopDir?: string): string | null
|
||||
|
||||
load(files?: string[] | Options, cwd?: string, stopDir?: string): Promise<LoadResult>
|
||||
loadSync(files?: string[] | Options, cwd?: string, stopDir?: string): LoadResult
|
||||
|
||||
addLoader(loader: AsyncLoader | SyncLoader | MultiLoader): this
|
||||
removeLoader(name: string): this
|
||||
|
||||
/** Clear internal cache */
|
||||
clearCache(): this
|
||||
}
|
||||
|
||||
|
||||
export default JoyCon
|
||||
@@ -0,0 +1,4 @@
|
||||
const rnds8 = new Uint8Array(16);
|
||||
export default function rng() {
|
||||
return crypto.getRandomValues(rnds8);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "json-schema-traverse",
|
||||
"version": "0.4.1",
|
||||
"description": "Traverse JSON Schema passing each schema object to callback",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"eslint": "eslint index.js spec",
|
||||
"test-spec": "mocha spec -R spec",
|
||||
"test": "npm run eslint && nyc npm run test-spec"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/epoberezkin/json-schema-traverse.git"
|
||||
},
|
||||
"keywords": [
|
||||
"JSON-Schema",
|
||||
"traverse",
|
||||
"iterate"
|
||||
],
|
||||
"author": "Evgeny Poberezkin",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/epoberezkin/json-schema-traverse/issues"
|
||||
},
|
||||
"homepage": "https://github.com/epoberezkin/json-schema-traverse#readme",
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.13.1",
|
||||
"eslint": "^3.19.0",
|
||||
"mocha": "^3.4.2",
|
||||
"nyc": "^11.0.2",
|
||||
"pre-commit": "^1.2.2"
|
||||
},
|
||||
"nyc": {
|
||||
"exclude": [
|
||||
"**/spec/**",
|
||||
"node_modules"
|
||||
],
|
||||
"reporter": [
|
||||
"lcov",
|
||||
"text-summary"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_define_property.cjs",
|
||||
"module": "../../esm/_define_property.js"
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
function md5(bytes) {
|
||||
const words = uint8ToUint32(bytes);
|
||||
const md5Bytes = wordsToMd5(words, bytes.length * 8);
|
||||
return uint32ToUint8(md5Bytes);
|
||||
}
|
||||
function uint32ToUint8(input) {
|
||||
const bytes = new Uint8Array(input.length * 4);
|
||||
for (let i = 0; i < input.length * 4; i++) {
|
||||
bytes[i] = (input[i >> 2] >>> ((i % 4) * 8)) & 0xff;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
function getOutputLength(inputLength8) {
|
||||
return (((inputLength8 + 64) >>> 9) << 4) + 14 + 1;
|
||||
}
|
||||
function wordsToMd5(x, len) {
|
||||
const xpad = new Uint32Array(getOutputLength(len)).fill(0);
|
||||
xpad.set(x);
|
||||
xpad[len >> 5] |= 0x80 << (len % 32);
|
||||
xpad[xpad.length - 1] = len;
|
||||
x = xpad;
|
||||
let a = 1732584193;
|
||||
let b = -271733879;
|
||||
let c = -1732584194;
|
||||
let d = 271733878;
|
||||
for (let i = 0; i < x.length; i += 16) {
|
||||
const olda = a;
|
||||
const oldb = b;
|
||||
const oldc = c;
|
||||
const oldd = d;
|
||||
a = md5ff(a, b, c, d, x[i], 7, -680876936);
|
||||
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
|
||||
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
|
||||
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
||||
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
|
||||
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
||||
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
||||
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
|
||||
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
||||
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
||||
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
|
||||
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
||||
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
||||
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
|
||||
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
||||
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
||||
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
|
||||
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
||||
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
|
||||
b = md5gg(b, c, d, a, x[i], 20, -373897302);
|
||||
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
|
||||
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
|
||||
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
|
||||
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
|
||||
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
|
||||
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
||||
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
|
||||
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
||||
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
||||
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
|
||||
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
||||
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
||||
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
|
||||
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
||||
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
||||
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
|
||||
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
||||
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
||||
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
|
||||
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
||||
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
|
||||
d = md5hh(d, a, b, c, x[i], 11, -358537222);
|
||||
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
|
||||
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
|
||||
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
|
||||
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
|
||||
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
|
||||
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
|
||||
a = md5ii(a, b, c, d, x[i], 6, -198630844);
|
||||
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
||||
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
||||
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
|
||||
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
||||
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
||||
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
|
||||
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
||||
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
||||
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
|
||||
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
||||
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
||||
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
|
||||
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
||||
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
|
||||
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
|
||||
a = safeAdd(a, olda);
|
||||
b = safeAdd(b, oldb);
|
||||
c = safeAdd(c, oldc);
|
||||
d = safeAdd(d, oldd);
|
||||
}
|
||||
return Uint32Array.of(a, b, c, d);
|
||||
}
|
||||
function uint8ToUint32(input) {
|
||||
if (input.length === 0) {
|
||||
return new Uint32Array();
|
||||
}
|
||||
const output = new Uint32Array(getOutputLength(input.length * 8)).fill(0);
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
output[i >> 2] |= (input[i] & 0xff) << ((i % 4) * 8);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
function safeAdd(x, y) {
|
||||
const lsw = (x & 0xffff) + (y & 0xffff);
|
||||
const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||
return (msw << 16) | (lsw & 0xffff);
|
||||
}
|
||||
function bitRotateLeft(num, cnt) {
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
function md5cmn(q, a, b, x, s, t) {
|
||||
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
|
||||
}
|
||||
function md5ff(a, b, c, d, x, s, t) {
|
||||
return md5cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
function md5gg(a, b, c, d, x, s, t) {
|
||||
return md5cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
function md5hh(a, b, c, d, x, s, t) {
|
||||
return md5cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
function md5ii(a, b, c, d, x, s, t) {
|
||||
return md5cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
export default md5;
|
||||
@@ -0,0 +1,18 @@
|
||||
function _defineProperties(target, props) {
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var descriptor = props[i];
|
||||
descriptor.enumerable = descriptor.enumerable || false;
|
||||
descriptor.configurable = true;
|
||||
|
||||
if ("value" in descriptor) descriptor.writable = true;
|
||||
|
||||
Object.defineProperty(target, descriptor.key, descriptor);
|
||||
}
|
||||
}
|
||||
function _create_class(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||||
|
||||
return Constructor;
|
||||
}
|
||||
export { _create_class as _ };
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pbkdf2.d.ts","sourceRoot":"","sources":["src/pbkdf2.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,SAAS,GAAG;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAkCF;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,GACd,UAAU,CAsBZ;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,UAAU,CAAC,CAsBrB"}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Code generated by Herebyfile.mjs generate:enums from internal/ast/modifierflags.go. DO NOT EDIT.
|
||||
export var ModifierFlags;
|
||||
(function (ModifierFlags) {
|
||||
ModifierFlags[ModifierFlags["None"] = 0] = "None";
|
||||
ModifierFlags[ModifierFlags["Public"] = 1] = "Public";
|
||||
ModifierFlags[ModifierFlags["Private"] = 2] = "Private";
|
||||
ModifierFlags[ModifierFlags["Protected"] = 4] = "Protected";
|
||||
ModifierFlags[ModifierFlags["Readonly"] = 8] = "Readonly";
|
||||
ModifierFlags[ModifierFlags["Override"] = 16] = "Override";
|
||||
ModifierFlags[ModifierFlags["Export"] = 32] = "Export";
|
||||
ModifierFlags[ModifierFlags["Abstract"] = 64] = "Abstract";
|
||||
ModifierFlags[ModifierFlags["Ambient"] = 128] = "Ambient";
|
||||
ModifierFlags[ModifierFlags["Static"] = 256] = "Static";
|
||||
ModifierFlags[ModifierFlags["Accessor"] = 512] = "Accessor";
|
||||
ModifierFlags[ModifierFlags["Async"] = 1024] = "Async";
|
||||
ModifierFlags[ModifierFlags["Default"] = 2048] = "Default";
|
||||
ModifierFlags[ModifierFlags["Const"] = 4096] = "Const";
|
||||
ModifierFlags[ModifierFlags["In"] = 8192] = "In";
|
||||
ModifierFlags[ModifierFlags["Out"] = 16384] = "Out";
|
||||
ModifierFlags[ModifierFlags["Decorator"] = 32768] = "Decorator";
|
||||
ModifierFlags[ModifierFlags["Deprecated"] = 65536] = "Deprecated";
|
||||
ModifierFlags[ModifierFlags["JSDocPublic"] = 8388608] = "JSDocPublic";
|
||||
ModifierFlags[ModifierFlags["JSDocPrivate"] = 16777216] = "JSDocPrivate";
|
||||
ModifierFlags[ModifierFlags["JSDocProtected"] = 33554432] = "JSDocProtected";
|
||||
ModifierFlags[ModifierFlags["JSDocReadonly"] = 67108864] = "JSDocReadonly";
|
||||
ModifierFlags[ModifierFlags["JSDocOverride"] = 134217728] = "JSDocOverride";
|
||||
ModifierFlags[ModifierFlags["HasComputedJSDocModifiers"] = 268435456] = "HasComputedJSDocModifiers";
|
||||
ModifierFlags[ModifierFlags["HasComputedFlags"] = 536870912] = "HasComputedFlags";
|
||||
ModifierFlags[ModifierFlags["SyntacticOrJSDocModifiers"] = 31] = "SyntacticOrJSDocModifiers";
|
||||
ModifierFlags[ModifierFlags["SyntacticOnlyModifiers"] = 65504] = "SyntacticOnlyModifiers";
|
||||
ModifierFlags[ModifierFlags["SyntacticModifiers"] = 65535] = "SyntacticModifiers";
|
||||
ModifierFlags[ModifierFlags["JSDocCacheOnlyModifiers"] = 260046848] = "JSDocCacheOnlyModifiers";
|
||||
ModifierFlags[ModifierFlags["JSDocOnlyModifiers"] = 65536] = "JSDocOnlyModifiers";
|
||||
ModifierFlags[ModifierFlags["NonCacheOnlyModifiers"] = 131071] = "NonCacheOnlyModifiers";
|
||||
ModifierFlags[ModifierFlags["AccessibilityModifier"] = 7] = "AccessibilityModifier";
|
||||
ModifierFlags[ModifierFlags["ParameterPropertyModifier"] = 31] = "ParameterPropertyModifier";
|
||||
ModifierFlags[ModifierFlags["NonPublicAccessibilityModifier"] = 6] = "NonPublicAccessibilityModifier";
|
||||
ModifierFlags[ModifierFlags["TypeScriptModifier"] = 28895] = "TypeScriptModifier";
|
||||
ModifierFlags[ModifierFlags["ExportDefault"] = 2080] = "ExportDefault";
|
||||
ModifierFlags[ModifierFlags["All"] = 131071] = "All";
|
||||
ModifierFlags[ModifierFlags["Modifier"] = 98303] = "Modifier";
|
||||
ModifierFlags[ModifierFlags["JavaScript"] = 3872] = "JavaScript";
|
||||
})(ModifierFlags || (ModifierFlags = {}));
|
||||
//# sourceMappingURL=modifierFlags.enum.js.map
|
||||
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ImportVisitor = void 0;
|
||||
const definition_1 = require("../definition");
|
||||
const Visitor_1 = require("./Visitor");
|
||||
class ImportVisitor extends Visitor_1.Visitor {
|
||||
#declaration;
|
||||
#referencer;
|
||||
constructor(declaration, referencer) {
|
||||
super(referencer);
|
||||
this.#declaration = declaration;
|
||||
this.#referencer = referencer;
|
||||
}
|
||||
static visit(referencer, declaration) {
|
||||
const importReferencer = new ImportVisitor(declaration, referencer);
|
||||
importReferencer.visit(declaration);
|
||||
}
|
||||
ImportDefaultSpecifier(node) {
|
||||
const local = node.local;
|
||||
this.visitImport(local, node);
|
||||
}
|
||||
ImportNamespaceSpecifier(node) {
|
||||
const local = node.local;
|
||||
this.visitImport(local, node);
|
||||
}
|
||||
ImportSpecifier(node) {
|
||||
const local = node.local;
|
||||
this.visitImport(local, node);
|
||||
}
|
||||
visitImport(id, specifier) {
|
||||
this.#referencer
|
||||
.currentScope()
|
||||
.defineIdentifier(id, new definition_1.ImportBindingDefinition(id, specifier, this.#declaration));
|
||||
}
|
||||
}
|
||||
exports.ImportVisitor = ImportVisitor;
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "on-exit-leak-free",
|
||||
"version": "2.1.2",
|
||||
"description": "Execute a function on exit without leaking memory, allowing all objects to be garbage collected",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "standard | snazzy && tap test/*.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/mcollina/on-exit-or-gc.git"
|
||||
},
|
||||
"keywords": [
|
||||
"weak",
|
||||
"reference",
|
||||
"finalization",
|
||||
"registry",
|
||||
"process",
|
||||
"exit",
|
||||
"garbage",
|
||||
"collector"
|
||||
],
|
||||
"author": "Matteo Collina <hello@matteocollina.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mcollina/on-exit-or-gc/issues"
|
||||
},
|
||||
"homepage": "https://github.com/mcollina/on-exit-or-gc#readme",
|
||||
"devDependencies": {
|
||||
"snazzy": "^9.0.0",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "^16.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
# pgpass
|
||||
|
||||
[](https://github.com/hoegaarden/pgpass/actions?query=workflow%3ACI+branch%3Amaster)
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install pgpass
|
||||
```
|
||||
|
||||
## Usage
|
||||
```js
|
||||
var pgPass = require('pgpass');
|
||||
|
||||
var connInfo = {
|
||||
'host' : 'pgserver' ,
|
||||
'user' : 'the_user_name' ,
|
||||
};
|
||||
|
||||
pgPass(connInfo, function(pass){
|
||||
conn_info.password = pass;
|
||||
// connect to postgresql server
|
||||
});
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
This module tries to read the `~/.pgpass` file (or the equivalent for windows systems). If the environment variable `PGPASSFILE` is set, this file is used instead. If everything goes right, the password from said file is passed to the callback; if the password cannot be read `undefined` is passed to the callback.
|
||||
|
||||
Cases where `undefined` is returned:
|
||||
|
||||
- the environment variable `PGPASSWORD` is set
|
||||
- the file cannot be read (wrong permissions, no such file, ...)
|
||||
- for non windows systems: the file is write-/readable by the group or by other users
|
||||
- there is no matching line for the given connection info
|
||||
|
||||
There should be no need to use this module directly; it is already included in `node-postgres`.
|
||||
|
||||
## Configuration
|
||||
|
||||
The module reads the environment variable `PGPASS_NO_DEESCAPE` to decide if the the read tokens from the password file should be de-escaped or not. Default is to do de-escaping. For further information on this see [this commit](https://github.com/postgres/postgres/commit/8d15e3ec4fcb735875a8a70a09ec0c62153c3329).
|
||||
|
||||
|
||||
## Tests
|
||||
|
||||
There are tests in `./test/`; including linting and coverage testing. Running `npm test` runs:
|
||||
|
||||
- `jshint`
|
||||
- `mocha` tests
|
||||
- `jscoverage` and `mocha -R html-cov`
|
||||
|
||||
You can see the coverage report in `coverage.html`.
|
||||
|
||||
|
||||
## Development, Patches, Bugs, ...
|
||||
|
||||
If you find Bugs or have improvements, please feel free to open a issue on GitHub. If you provide a pull request, I'm more than happy to merge them, just make sure to add tests for your changes.
|
||||
|
||||
## Links
|
||||
|
||||
- https://github.com/hoegaarden/node-pgpass
|
||||
- http://www.postgresql.org/docs/current/static/libpq-pgpass.html
|
||||
- https://wiki.postgresql.org/wiki/Pgpass
|
||||
- https://github.com/postgres/postgres/blob/master/src/interfaces/libpq/fe-connect.c
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2013-2016 Hannes Hörl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user