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,165 @@
'use strict'
const EventEmitter = require('events').EventEmitter
const util = require('util')
const utils = require('../utils')
const NativeQuery = (module.exports = function (config, values, callback) {
EventEmitter.call(this)
config = utils.normalizeQueryConfig(config, values, callback)
this.text = config.text
this.values = config.values
this.name = config.name
this.queryMode = config.queryMode
this.callback = config.callback
this.state = 'new'
this._arrayMode = config.rowMode === 'array'
// if the 'row' event is listened for
// then emit them as they come in
// without setting singleRowMode to true
// this has almost no meaning because libpq
// reads all rows into memory before returning any
this._emitRowEvents = false
this.on(
'newListener',
function (event) {
if (event === 'row') this._emitRowEvents = true
}.bind(this)
)
})
util.inherits(NativeQuery, EventEmitter)
const errorFieldMap = {
sqlState: 'code',
statementPosition: 'position',
messagePrimary: 'message',
context: 'where',
schemaName: 'schema',
tableName: 'table',
columnName: 'column',
dataTypeName: 'dataType',
constraintName: 'constraint',
sourceFile: 'file',
sourceLine: 'line',
sourceFunction: 'routine',
}
NativeQuery.prototype.handleError = function (err) {
// copy pq error fields into the error object
const fields = this.native && this.native.pq.resultErrorFields()
if (fields) {
for (const key in fields) {
const normalizedFieldName = errorFieldMap[key] || key
err[normalizedFieldName] = fields[key]
}
}
if (this.callback) {
this.callback(err)
} else {
this.emit('error', err)
}
this.state = 'error'
}
NativeQuery.prototype.then = function (onSuccess, onFailure) {
return this._getPromise().then(onSuccess, onFailure)
}
NativeQuery.prototype.catch = function (callback) {
return this._getPromise().catch(callback)
}
NativeQuery.prototype._getPromise = function () {
if (this._promise) return this._promise
this._promise = new Promise(
function (resolve, reject) {
this._once('end', resolve)
this._once('error', reject)
}.bind(this)
)
return this._promise
}
NativeQuery.prototype.submit = function (client) {
this.state = 'running'
const self = this
this.native = client.native
client.native.arrayMode = this._arrayMode
let after = function (err, rows, results) {
client.native.arrayMode = false
setImmediate(function () {
self.emit('_done')
})
// handle possible query error
if (err) {
return self.handleError(err)
}
// emit row events for each row in the result
if (self._emitRowEvents) {
if (results.length > 1) {
rows.forEach((rowOfRows, i) => {
rowOfRows.forEach((row) => {
self.emit('row', row, results[i])
})
})
} else {
rows.forEach(function (row) {
self.emit('row', row, results)
})
}
}
// handle successful result
self.state = 'end'
self.emit('end', results)
if (self.callback) {
self.callback(null, results)
}
}
if (process.domain) {
after = process.domain.bind(after)
}
// named query
if (this.name) {
if (this.name.length > 63) {
console.error('Warning! Postgres only supports 63 characters for query names.')
console.error('You supplied %s (%s)', this.name, this.name.length)
console.error('This can cause conflicts and silent errors executing queries')
}
const values = (this.values || []).map(utils.prepareValue)
// check if the client has already executed this named query
// if so...just execute it again - skip the planning phase
if (client.namedQueries[this.name]) {
if (this.text && client.namedQueries[this.name] !== this.text) {
const err = new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`)
return after(err)
}
return client.native.execute(this.name, values, after)
}
// plan the named query the first time, then execute it
return client.native.prepare(this.name, this.text, values.length, function (err) {
if (err) return after(err)
client.namedQueries[self.name] = self.text
return self.native.execute(self.name, values, after)
})
} else if (this.values) {
if (!Array.isArray(this.values)) {
const err = new Error('Query values must be an array')
return after(err)
}
const vals = this.values.map(utils.prepareValue)
client.native.query(this.text, vals, after)
} else if (this.queryMode === 'extended') {
client.native.query(this.text, [], after)
} else {
client.native.query(this.text, after)
}
}

View File

@@ -0,0 +1,508 @@
declare module "node:readline" {
import { Abortable, EventEmitter, InternalEventEmitter } from "node:events";
interface Key {
sequence?: string | undefined;
name?: string | undefined;
ctrl?: boolean | undefined;
meta?: boolean | undefined;
shift?: boolean | undefined;
}
interface InterfaceEventMap {
"close": [];
"error": [error: Error];
"history": [history: string[]];
"line": [input: string];
"pause": [];
"resume": [];
"SIGCONT": [];
"SIGINT": [];
"SIGTSTP": [];
}
/**
* Instances of the `readline.Interface` class are constructed using the `readline.createInterface()` method. Every instance is associated with a
* single `input` [Readable](https://nodejs.org/docs/latest-v26.x/api/stream.html#readable-streams) stream and a single `output` [Writable](https://nodejs.org/docs/latest-v26.x/api/stream.html#writable-streams) stream.
* The `output` stream is used to print prompts for user input that arrives on,
* and is read from, the `input` stream.
* @since v0.1.104
*/
class Interface implements EventEmitter, Disposable {
/**
* NOTE: According to the documentation:
*
* > Instances of the `readline.Interface` class are constructed using the
* > `readline.createInterface()` method.
*
* @see https://nodejs.org/dist/latest-v26.x/docs/api/readline.html#class-interfaceconstructor
*/
protected constructor(
input: NodeJS.ReadableStream,
output?: NodeJS.WritableStream,
completer?: Completer | AsyncCompleter,
terminal?: boolean,
);
/**
* NOTE: According to the documentation:
*
* > Instances of the `readline.Interface` class are constructed using the
* > `readline.createInterface()` method.
*
* @see https://nodejs.org/dist/latest-v26.x/docs/api/readline.html#class-interfaceconstructor
*/
protected constructor(options: ReadLineOptions);
readonly terminal: boolean;
/**
* The current input data being processed by node.
*
* This can be used when collecting input from a TTY stream to retrieve the
* current value that has been processed thus far, prior to the `line` event
* being emitted. Once the `line` event has been emitted, this property will
* be an empty string.
*
* Be aware that modifying the value during the instance runtime may have
* unintended consequences if `rl.cursor` is not also controlled.
*
* **If not using a TTY stream for input, use the `'line'` event.**
*
* One possible use case would be as follows:
*
* ```js
* const values = ['lorem ipsum', 'dolor sit amet'];
* const rl = readline.createInterface(process.stdin);
* const showResults = debounce(() => {
* console.log(
* '\n',
* values.filter((val) => val.startsWith(rl.line)).join(' '),
* );
* }, 300);
* process.stdin.on('keypress', (c, k) => {
* showResults();
* });
* ```
* @since v0.1.98
*/
readonly line: string;
/**
* The cursor position relative to `rl.line`.
*
* This will track where the current cursor lands in the input string, when
* reading input from a TTY stream. The position of cursor determines the
* portion of the input string that will be modified as input is processed,
* as well as the column where the terminal caret will be rendered.
* @since v0.1.98
*/
readonly cursor: number;
/**
* The `rl.getPrompt()` method returns the current prompt used by `rl.prompt()`.
* @since v15.3.0, v14.17.0
* @return the current prompt string
*/
getPrompt(): string;
/**
* The `rl.setPrompt()` method sets the prompt that will be written to `output` whenever `rl.prompt()` is called.
* @since v0.1.98
*/
setPrompt(prompt: string): void;
/**
* The `rl.prompt()` method writes the `Interface` instances configured`prompt` to a new line in `output` in order to provide a user with a new
* location at which to provide input.
*
* When called, `rl.prompt()` will resume the `input` stream if it has been
* paused.
*
* If the `Interface` was created with `output` set to `null` or `undefined` the prompt is not written.
* @since v0.1.98
* @param preserveCursor If `true`, prevents the cursor placement from being reset to `0`.
*/
prompt(preserveCursor?: boolean): void;
/**
* The `rl.question()` method displays the `query` by writing it to the `output`,
* waits for user input to be provided on `input`, then invokes the `callback` function passing the provided input as the first argument.
*
* When called, `rl.question()` will resume the `input` stream if it has been
* paused.
*
* If the `Interface` was created with `output` set to `null` or `undefined` the `query` is not written.
*
* The `callback` function passed to `rl.question()` does not follow the typical
* pattern of accepting an `Error` object or `null` as the first argument.
* The `callback` is called with the provided answer as the only argument.
*
* An error will be thrown if calling `rl.question()` after `rl.close()`.
*
* Example usage:
*
* ```js
* rl.question('What is your favorite food? ', (answer) => {
* console.log(`Oh, so your favorite food is ${answer}`);
* });
* ```
*
* Using an `AbortController` to cancel a question.
*
* ```js
* const ac = new AbortController();
* const signal = ac.signal;
*
* rl.question('What is your favorite food? ', { signal }, (answer) => {
* console.log(`Oh, so your favorite food is ${answer}`);
* });
*
* signal.addEventListener('abort', () => {
* console.log('The food question timed out');
* }, { once: true });
*
* setTimeout(() => ac.abort(), 10000);
* ```
* @since v0.3.3
* @param query A statement or query to write to `output`, prepended to the prompt.
* @param callback A callback function that is invoked with the user's input in response to the `query`.
*/
question(query: string, callback: (answer: string) => void): void;
question(query: string, options: Abortable, callback: (answer: string) => void): void;
/**
* The `rl.pause()` method pauses the `input` stream, allowing it to be resumed
* later if necessary.
*
* Calling `rl.pause()` does not immediately pause other events (including `'line'`) from being emitted by the `Interface` instance.
* @since v0.3.4
*/
pause(): this;
/**
* The `rl.resume()` method resumes the `input` stream if it has been paused.
* @since v0.3.4
*/
resume(): this;
/**
* The `rl.close()` method closes the `Interface` instance and
* relinquishes control over the `input` and `output` streams. When called,
* the `'close'` event will be emitted.
*
* Calling `rl.close()` does not immediately stop other events (including `'line'`)
* from being emitted by the `Interface` instance.
* @since v0.1.98
*/
close(): void;
/**
* Alias for `rl.close()`.
* @since v22.15.0
*/
[Symbol.dispose](): void;
/**
* The `rl.write()` method will write either `data` or a key sequence identified
* by `key` to the `output`. The `key` argument is supported only if `output` is
* a `TTY` text terminal. See `TTY keybindings` for a list of key
* combinations.
*
* If `key` is specified, `data` is ignored.
*
* When called, `rl.write()` will resume the `input` stream if it has been
* paused.
*
* If the `Interface` was created with `output` set to `null` or `undefined` the `data` and `key` are not written.
*
* ```js
* rl.write('Delete this!');
* // Simulate Ctrl+U to delete the line written previously
* rl.write(null, { ctrl: true, name: 'u' });
* ```
*
* The `rl.write()` method will write the data to the `readline` `Interface`'s `input` _as if it were provided by the user_.
* @since v0.1.98
*/
write(data: string | Buffer, key?: Key): void;
write(data: undefined | null | string | Buffer, key: Key): void;
/**
* Returns the real position of the cursor in relation to the input
* prompt + string. Long input (wrapping) strings, as well as multiple
* line prompts are included in the calculations.
* @since v13.5.0, v12.16.0
*/
getCursorPos(): CursorPos;
[Symbol.asyncIterator](): NodeJS.AsyncIterator<string>;
}
interface Interface extends InternalEventEmitter<InterfaceEventMap> {}
type Completer = (line: string) => CompleterResult;
type AsyncCompleter = (
line: string,
callback: (err?: null | Error, result?: CompleterResult) => void,
) => void;
type CompleterResult = [string[], string];
interface ReadLineOptions {
/**
* The [`Readable`](https://nodejs.org/docs/latest-v26.x/api/stream.html#readable-streams) stream to listen to
*/
input: NodeJS.ReadableStream;
/**
* The [`Writable`](https://nodejs.org/docs/latest-v26.x/api/stream.html#writable-streams) stream to write readline data to.
*/
output?: NodeJS.WritableStream | undefined;
/**
* An optional function used for Tab autocompletion.
*/
completer?: Completer | AsyncCompleter | undefined;
/**
* `true` if the `input` and `output` streams should be treated like a TTY,
* and have ANSI/VT100 escape codes written to it.
* Default: checking `isTTY` on the `output` stream upon instantiation.
*/
terminal?: boolean | undefined;
/**
* Initial list of history lines.
* This option makes sense only if `terminal` is set to `true` by the user or by an internal `output` check,
* otherwise the history caching mechanism is not initialized at all.
* @default []
*/
history?: string[] | undefined;
/**
* Maximum number of history lines retained.
* To disable the history set this value to `0`.
* This option makes sense only if `terminal` is set to `true` by the user or by an internal `output` check,
* otherwise the history caching mechanism is not initialized at all.
* @default 30
*/
historySize?: number | undefined;
/**
* If `true`, when a new input line added to the history list duplicates an older one,
* this removes the older line from the list.
* @default false
*/
removeHistoryDuplicates?: boolean | undefined;
/**
* The prompt string to use.
* @default "> "
*/
prompt?: string | undefined;
/**
* If the delay between `\r` and `\n` exceeds `crlfDelay` milliseconds,
* both `\r` and `\n` will be treated as separate end-of-line input.
* `crlfDelay` will be coerced to a number no less than `100`.
* It can be set to `Infinity`, in which case
* `\r` followed by `\n` will always be considered a single newline
* (which may be reasonable for [reading files](https://nodejs.org/docs/latest-v26.x/api/readline.html#example-read-file-stream-line-by-line) with `\r\n` line delimiter).
* @default 100
*/
crlfDelay?: number | undefined;
/**
* The duration `readline` will wait for a character
* (when reading an ambiguous key sequence in milliseconds
* one that can both form a complete key sequence using the input read so far
* and can take additional input to complete a longer key sequence).
* @default 500
*/
escapeCodeTimeout?: number | undefined;
/**
* The number of spaces a tab is equal to (minimum 1).
* @default 8
*/
tabSize?: number | undefined;
/**
* Allows closing the interface using an AbortSignal.
* Aborting the signal will internally call `close` on the interface.
*/
signal?: AbortSignal | undefined;
}
/**
* The `readline.createInterface()` method creates a new `readline.Interface` instance.
*
* ```js
* import readline from 'node:readline';
* const rl = readline.createInterface({
* input: process.stdin,
* output: process.stdout,
* });
* ```
*
* Once the `readline.Interface` instance is created, the most common case is to
* listen for the `'line'` event:
*
* ```js
* rl.on('line', (line) => {
* console.log(`Received: ${line}`);
* });
* ```
*
* If `terminal` is `true` for this instance then the `output` stream will get
* the best compatibility if it defines an `output.columns` property and emits
* a `'resize'` event on the `output` if or when the columns ever change
* (`process.stdout` does this automatically when it is a TTY).
*
* When creating a `readline.Interface` using `stdin` as input, the program
* will not terminate until it receives an [EOF character](https://en.wikipedia.org/wiki/End-of-file#EOF_character). To exit without
* waiting for user input, call `process.stdin.unref()`.
* @since v0.1.98
*/
function createInterface(
input: NodeJS.ReadableStream,
output?: NodeJS.WritableStream,
completer?: Completer | AsyncCompleter,
terminal?: boolean,
): Interface;
function createInterface(options: ReadLineOptions): Interface;
/**
* The `readline.emitKeypressEvents()` method causes the given `Readable` stream to begin emitting `'keypress'` events corresponding to received input.
*
* Optionally, `interface` specifies a `readline.Interface` instance for which
* autocompletion is disabled when copy-pasted input is detected.
*
* If the `stream` is a `TTY`, then it must be in raw mode.
*
* This is automatically called by any readline instance on its `input` if the `input` is a terminal. Closing the `readline` instance does not stop
* the `input` from emitting `'keypress'` events.
*
* ```js
* readline.emitKeypressEvents(process.stdin);
* if (process.stdin.isTTY)
* process.stdin.setRawMode(true);
* ```
*
* ## Example: Tiny CLI
*
* The following example illustrates the use of `readline.Interface` class to
* implement a small command-line interface:
*
* ```js
* import readline from 'node:readline';
* const rl = readline.createInterface({
* input: process.stdin,
* output: process.stdout,
* prompt: 'OHAI> ',
* });
*
* rl.prompt();
*
* rl.on('line', (line) => {
* switch (line.trim()) {
* case 'hello':
* console.log('world!');
* break;
* default:
* console.log(`Say what? I might have heard '${line.trim()}'`);
* break;
* }
* rl.prompt();
* }).on('close', () => {
* console.log('Have a great day!');
* process.exit(0);
* });
* ```
*
* ## Example: Read file stream line-by-Line
*
* A common use case for `readline` is to consume an input file one line at a
* time. The easiest way to do so is leveraging the `fs.ReadStream` API as
* well as a `for await...of` loop:
*
* ```js
* import fs from 'node:fs';
* import readline from 'node:readline';
*
* async function processLineByLine() {
* const fileStream = fs.createReadStream('input.txt');
*
* const rl = readline.createInterface({
* input: fileStream,
* crlfDelay: Infinity,
* });
* // Note: we use the crlfDelay option to recognize all instances of CR LF
* // ('\r\n') in input.txt as a single line break.
*
* for await (const line of rl) {
* // Each line in input.txt will be successively available here as `line`.
* console.log(`Line from file: ${line}`);
* }
* }
*
* processLineByLine();
* ```
*
* Alternatively, one could use the `'line'` event:
*
* ```js
* import fs from 'node:fs';
* import readline from 'node:readline';
*
* const rl = readline.createInterface({
* input: fs.createReadStream('sample.txt'),
* crlfDelay: Infinity,
* });
*
* rl.on('line', (line) => {
* console.log(`Line from file: ${line}`);
* });
* ```
*
* Currently, `for await...of` loop can be a bit slower. If `async` / `await` flow and speed are both essential, a mixed approach can be applied:
*
* ```js
* import { once } from 'node:events';
* import { createReadStream } from 'node:fs';
* import { createInterface } from 'node:readline';
*
* (async function processLineByLine() {
* try {
* const rl = createInterface({
* input: createReadStream('big-file.txt'),
* crlfDelay: Infinity,
* });
*
* rl.on('line', (line) => {
* // Process the line.
* });
*
* await once(rl, 'close');
*
* console.log('File processed.');
* } catch (err) {
* console.error(err);
* }
* })();
* ```
* @since v0.7.7
*/
function emitKeypressEvents(stream: NodeJS.ReadableStream, readlineInterface?: Interface): void;
type Direction = -1 | 0 | 1;
interface CursorPos {
rows: number;
cols: number;
}
/**
* The `readline.clearLine()` method clears current line of given [TTY](https://nodejs.org/docs/latest-v26.x/api/tty.html) stream
* in a specified direction identified by `dir`.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if `stream` wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
function clearLine(stream: NodeJS.WritableStream, dir: Direction, callback?: () => void): boolean;
/**
* The `readline.clearScreenDown()` method clears the given [TTY](https://nodejs.org/docs/latest-v26.x/api/tty.html) stream from
* the current position of the cursor down.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if `stream` wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
function clearScreenDown(stream: NodeJS.WritableStream, callback?: () => void): boolean;
/**
* The `readline.cursorTo()` method moves cursor to the specified position in a
* given [TTY](https://nodejs.org/docs/latest-v26.x/api/tty.html) `stream`.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if `stream` wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
function cursorTo(stream: NodeJS.WritableStream, x: number, y?: number, callback?: () => void): boolean;
/**
* The `readline.moveCursor()` method moves the cursor _relative_ to its current
* position in a given [TTY](https://nodejs.org/docs/latest-v26.x/api/tty.html) `stream`.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if `stream` wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
function moveCursor(stream: NodeJS.WritableStream, dx: number, dy: number, callback?: () => void): boolean;
/** @deprecated This alias will be removed in a future version. Use `import { Interface } from 'node:readline'` instead. */
type ReadLine = Interface;
}
declare module "node:readline" {
export * as promises from "node:readline/promises";
}
declare module "readline" {
export * from "node:readline";
}

View File

@@ -0,0 +1,5 @@
const file2 = require("./file2.js")
module.exports = function () {
file2()
}

View File

@@ -0,0 +1,5 @@
import type { TSESLint } from '@typescript-eslint/utils';
declare const _default: TSESLint.RuleModule<"noNonNullAssertedNullishCoalescing" | "suggestRemovingNonNull", [], import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1,34 @@
import * as core from "../core/index.js";
import * as schemas from "./schemas.js";
export const ZodMiniISODateTime = /*@__PURE__*/ core.$constructor("ZodMiniISODateTime", (inst, def) => {
core.$ZodISODateTime.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
});
// @__NO_SIDE_EFFECTS__
export function datetime(params) {
return core._isoDateTime(ZodMiniISODateTime, params);
}
export const ZodMiniISODate = /*@__PURE__*/ core.$constructor("ZodMiniISODate", (inst, def) => {
core.$ZodISODate.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
});
// @__NO_SIDE_EFFECTS__
export function date(params) {
return core._isoDate(ZodMiniISODate, params);
}
export const ZodMiniISOTime = /*@__PURE__*/ core.$constructor("ZodMiniISOTime", (inst, def) => {
core.$ZodISOTime.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
});
// @__NO_SIDE_EFFECTS__
export function time(params) {
return core._isoTime(ZodMiniISOTime, params);
}
export const ZodMiniISODuration = /*@__PURE__*/ core.$constructor("ZodMiniISODuration", (inst, def) => {
core.$ZodISODuration.init(inst, def);
schemas.ZodMiniStringFormat.init(inst, def);
});
// @__NO_SIDE_EFFECTS__
export function duration(params) {
return core._isoDuration(ZodMiniISODuration, params);
}

View File

@@ -0,0 +1,7 @@
var _typeof = require("./typeof.js")["default"];
var toPrimitive = require("./toPrimitive.js");
function toPropertyKey(t) {
var i = toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
module.exports = toPropertyKey, module.exports.__esModule = true, module.exports["default"] = module.exports;

View File

@@ -0,0 +1,114 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const tsutils = __importStar(require("ts-api-utils"));
const util_1 = require("../util");
exports.default = (0, util_1.createRule)({
name: 'prefer-reduce-type-parameter',
meta: {
type: 'problem',
docs: {
description: 'Enforce using type parameter when calling `Array#reduce` instead of using a type assertion',
recommended: 'strict',
requiresTypeChecking: true,
},
fixable: 'code',
messages: {
preferTypeParameter: 'Unnecessary assertion: Array#reduce accepts a type parameter for the default value.',
},
schema: [],
},
defaultOptions: [],
create(context) {
const services = (0, util_1.getParserServices)(context);
const checker = services.program.getTypeChecker();
function isArrayType(type) {
return tsutils
.unionConstituents(type)
.every(unionPart => tsutils
.intersectionConstituents(unionPart)
.every(t => checker.isArrayType(t) || checker.isTupleType(t)));
}
return {
'CallExpression > MemberExpression.callee'(callee) {
if (!(0, util_1.isStaticMemberAccessOfValue)(callee, context, 'reduce')) {
return;
}
const [, secondArg] = callee.parent.arguments;
if (callee.parent.arguments.length < 2) {
return;
}
if ((0, util_1.isTypeAssertion)(secondArg)) {
const initializerType = services.getTypeAtLocation(secondArg.expression);
const assertedType = services.getTypeAtLocation(secondArg.typeAnnotation);
const isAssertionNecessary = !checker.isTypeAssignableTo(initializerType, assertedType);
// don't report this if the resulting fix will be a type error
if (isAssertionNecessary) {
return;
}
}
else {
return;
}
// Get the symbol of the `reduce` method.
const calleeObjType = (0, util_1.getConstrainedTypeAtLocation)(services, callee.object);
// Check the owner type of the `reduce` method.
if (isArrayType(calleeObjType)) {
context.report({
node: secondArg,
messageId: 'preferTypeParameter',
fix: fixer => {
const fixes = [
fixer.removeRange([
secondArg.range[0],
secondArg.expression.range[0],
]),
fixer.removeRange([
secondArg.expression.range[1],
secondArg.range[1],
]),
];
if (!callee.parent.typeArguments) {
fixes.push(fixer.insertTextAfter(callee, `<${context.sourceCode.getText(secondArg.typeAnnotation)}>`));
}
return fixes;
},
});
return;
}
},
};
},
});

View File

@@ -0,0 +1,14 @@
export declare class BufferReader {
private offset;
private buffer;
private encoding;
constructor(offset?: number);
setBuffer(offset: number, buffer: Buffer): void;
int16(): number;
byte(): number;
int32(): number;
uint32(): number;
string(length: number): string;
cstring(): string;
bytes(length: number): Buffer;
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/ast/ast.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EACR,SAAS,EACT,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,SAAS,EACT,cAAc,EACd,KAAK,EACR,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,cAAc,oBAAoB,CAAC;AAInC,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG;IAAE,WAAW,EAAE,GAAG,CAAC;CAAE,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG;IAAE,mBAAmB,EAAE,IAAI,CAAC;CAAE,CAAC,GAAG,kBAAkB,CAAC;AAEtF,MAAM,WAAW,SAAS;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,IAAI,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC,EAAE,iBAAiB;IAClF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,IAAK,SAAQ,iBAAiB;IAC3C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,IAAI,EAAE,GAAG,SAAS,CAAC;IAC7C,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACvG,aAAa,IAAI,UAAU,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,mBAAmB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzE,YAAY,IAAI,MAAM,CAAC;IACvB,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC1C,YAAY,IAAI,MAAM,CAAC;IACvB,qBAAqB,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACvD,WAAW,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC7C,OAAO,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAC5C;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,UAAW,SAAQ,IAAI;IACpC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC1C,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;IACnD,QAAQ,CAAC,uBAAuB,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3D,QAAQ,CAAC,sBAAsB,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1D,QAAQ,CAAC,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAClC,QAAQ,CAAC,mBAAmB,EAAE,SAAS,IAAI,EAAE,CAAC;IAC9C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,uBAAuB,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1D,qEAAqE;IACrE,aAAa,IAAI,SAAS,MAAM,EAAE,CAAC;IACnC,8EAA8E;IAC9E,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAClE,8EAA8E;IAC9E,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACvE,gBAAgB;IAChB,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAClC;AAID,MAAM,MAAM,gBAAgB,CAAC,KAAK,SAAS,qBAAqB,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;AACjF,MAAM,MAAM,YAAY,CAAC,KAAK,SAAS,iBAAiB,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;AACzE,MAAM,MAAM,aAAa,CAAC,KAAK,SAAS,kBAAkB,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;AAIlF,MAAM,WAAW,kCAAmC,SAAQ,wBAAwB;IAChF,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,kCAAkC,CAAC;AACnF,MAAM,MAAM,gCAAgC,GAAG,UAAU,GAAG,oBAAoB,CAAC;AAEjF,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACtE,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,cAAc,GAAG,wBAAwB,CAAC;CAC/E"}

View File

@@ -0,0 +1,16 @@
"use strict";
// THIS CODE WAS AUTOMATICALLY GENERATED
// DO NOT EDIT THIS CODE BY HAND
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
// npx nx generate-lib repo
Object.defineProperty(exports, "__esModule", { value: true });
exports.es2021 = void 0;
const es2020_1 = require("./es2020");
const es2021_intl_1 = require("./es2021.intl");
const es2021_promise_1 = require("./es2021.promise");
const es2021_string_1 = require("./es2021.string");
const es2021_weakref_1 = require("./es2021.weakref");
exports.es2021 = {
libs: [es2020_1.es2020, es2021_promise_1.es2021_promise, es2021_string_1.es2021_string, es2021_weakref_1.es2021_weakref, es2021_intl_1.es2021_intl],
variables: [],
};

View File

@@ -0,0 +1,4 @@
function _identity(t) {
return t;
}
module.exports = _identity, module.exports.__esModule = true, module.exports["default"] = module.exports;

View File

@@ -0,0 +1,7 @@
import REGEX from './regex.js';
function validate(uuid) {
return typeof uuid === 'string' && REGEX.test(uuid);
}
export default validate;

View File

@@ -0,0 +1,4 @@
{
"main": "../../cjs/_async_generator.cjs",
"module": "../../esm/_async_generator.js"
}

View File

@@ -0,0 +1,59 @@
var test = require('tape');
var stringify = require('../');
test('space parameter', function (t) {
t.plan(1);
var obj = { one: 1, two: 2 };
t.equal(stringify(obj, {space: ' '}), ''
+ '{\n'
+ ' "one": 1,\n'
+ ' "two": 2\n'
+ '}'
);
});
test('space parameter (with tabs)', function (t) {
t.plan(1);
var obj = { one: 1, two: 2 };
t.equal(stringify(obj, {space: '\t'}), ''
+ '{\n'
+ '\t"one": 1,\n'
+ '\t"two": 2\n'
+ '}'
);
});
test('space parameter (with a number)', function (t) {
t.plan(1);
var obj = { one: 1, two: 2 };
t.equal(stringify(obj, {space: 3}), ''
+ '{\n'
+ ' "one": 1,\n'
+ ' "two": 2\n'
+ '}'
);
});
test('space parameter (nested objects)', function (t) {
t.plan(1);
var obj = { one: 1, two: { b: 4, a: [2,3] } };
t.equal(stringify(obj, {space: ' '}), ''
+ '{\n'
+ ' "one": 1,\n'
+ ' "two": {\n'
+ ' "a": [\n'
+ ' 2,\n'
+ ' 3\n'
+ ' ],\n'
+ ' "b": 4\n'
+ ' }\n'
+ '}'
);
});
test('space parameter (same as native)', function (t) {
t.plan(1);
// for this test, properties need to be in alphabetical order
var obj = { one: 1, two: { a: [2,3], b: 4 } };
t.equal(stringify(obj, {space: ' '}), JSON.stringify(obj, null, ' '));
});

View File

@@ -0,0 +1,313 @@
"use strict";
/**
* Utilities for hex, bytes, CSPRNG.
* @module
*/
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapXOFConstructorWithOpts = exports.wrapConstructorWithOpts = exports.wrapConstructor = exports.Hash = exports.nextTick = exports.swap32IfBE = exports.byteSwapIfBE = exports.swap8IfBE = exports.isLE = void 0;
exports.isBytes = isBytes;
exports.anumber = anumber;
exports.abytes = abytes;
exports.ahash = ahash;
exports.aexists = aexists;
exports.aoutput = aoutput;
exports.u8 = u8;
exports.u32 = u32;
exports.clean = clean;
exports.createView = createView;
exports.rotr = rotr;
exports.rotl = rotl;
exports.byteSwap = byteSwap;
exports.byteSwap32 = byteSwap32;
exports.bytesToHex = bytesToHex;
exports.hexToBytes = hexToBytes;
exports.asyncLoop = asyncLoop;
exports.utf8ToBytes = utf8ToBytes;
exports.bytesToUtf8 = bytesToUtf8;
exports.toBytes = toBytes;
exports.kdfInputToBytes = kdfInputToBytes;
exports.concatBytes = concatBytes;
exports.checkOpts = checkOpts;
exports.createHasher = createHasher;
exports.createOptHasher = createOptHasher;
exports.createXOFer = createXOFer;
exports.randomBytes = randomBytes;
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
const crypto_1 = require("@noble/hashes/crypto");
/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */
function isBytes(a) {
return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
}
/** Asserts something is positive integer. */
function anumber(n) {
if (!Number.isSafeInteger(n) || n < 0)
throw new Error('positive integer expected, got ' + n);
}
/** Asserts something is Uint8Array. */
function abytes(b, ...lengths) {
if (!isBytes(b))
throw new Error('Uint8Array expected');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);
}
/** Asserts something is hash */
function ahash(h) {
if (typeof h !== 'function' || typeof h.create !== 'function')
throw new Error('Hash should be wrapped by utils.createHasher');
anumber(h.outputLen);
anumber(h.blockLen);
}
/** Asserts a hash instance has not been destroyed / finished */
function aexists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error('Hash instance has been destroyed');
if (checkFinished && instance.finished)
throw new Error('Hash#digest() has already been called');
}
/** Asserts output is properly-sized byte array */
function aoutput(out, instance) {
abytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error('digestInto() expects output buffer of length at least ' + min);
}
}
/** Cast u8 / u16 / u32 to u8. */
function u8(arr) {
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
}
/** Cast u8 / u16 / u32 to u32. */
function u32(arr) {
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
}
/** Zeroize a byte array. Warning: JS provides no guarantees. */
function clean(...arrays) {
for (let i = 0; i < arrays.length; i++) {
arrays[i].fill(0);
}
}
/** Create DataView of an array for easy byte-level manipulation. */
function createView(arr) {
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
}
/** The rotate right (circular right shift) operation for uint32 */
function rotr(word, shift) {
return (word << (32 - shift)) | (word >>> shift);
}
/** The rotate left (circular left shift) operation for uint32 */
function rotl(word, shift) {
return (word << shift) | ((word >>> (32 - shift)) >>> 0);
}
/** Is current platform little-endian? Most are. Big-Endian platform: IBM */
exports.isLE = (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();
/** The byte swap operation for uint32 */
function byteSwap(word) {
return (((word << 24) & 0xff000000) |
((word << 8) & 0xff0000) |
((word >>> 8) & 0xff00) |
((word >>> 24) & 0xff));
}
/** Conditionally byte swap if on a big-endian platform */
exports.swap8IfBE = exports.isLE
? (n) => n
: (n) => byteSwap(n);
/** @deprecated */
exports.byteSwapIfBE = exports.swap8IfBE;
/** In place byte swap for Uint32Array */
function byteSwap32(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i] = byteSwap(arr[i]);
}
return arr;
}
exports.swap32IfBE = exports.isLE
? (u) => u
: byteSwap32;
// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex
const hasHexBuiltin = /* @__PURE__ */ (() =>
// @ts-ignore
typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();
// Array where index 0xf0 (240) is mapped to string 'f0'
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* Convert byte array to hex string. Uses built-in function, when available.
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
abytes(bytes);
// @ts-ignore
if (hasHexBuiltin)
return bytes.toHex();
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
// We use optimized technique to convert hex string to byte array
const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
function asciiToBase16(ch) {
if (ch >= asciis._0 && ch <= asciis._9)
return ch - asciis._0; // '2' => 50-48
if (ch >= asciis.A && ch <= asciis.F)
return ch - (asciis.A - 10); // 'B' => 66-(65-10)
if (ch >= asciis.a && ch <= asciis.f)
return ch - (asciis.a - 10); // 'b' => 98-(97-10)
return;
}
/**
* Convert hex string to byte array. Uses built-in function, when available.
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
*/
function hexToBytes(hex) {
if (typeof hex !== 'string')
throw new Error('hex string expected, got ' + typeof hex);
// @ts-ignore
if (hasHexBuiltin)
return Uint8Array.fromHex(hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new Error('hex string expected, got unpadded hex of length ' + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === undefined || n2 === undefined) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163
}
return array;
}
/**
* There is no setImmediate in browser and setTimeout is slow.
* Call of async fn will return Promise, which will be fullfiled only on
* next scheduler queue processing step and this is exactly what we need.
*/
const nextTick = async () => { };
exports.nextTick = nextTick;
/** Returns control to thread each 'tick' ms to avoid blocking. */
async function asyncLoop(iters, tick, cb) {
let ts = Date.now();
for (let i = 0; i < iters; i++) {
cb(i);
// Date.now() is not monotonic, so in case if clock goes backwards we return return control too
const diff = Date.now() - ts;
if (diff >= 0 && diff < tick)
continue;
await (0, exports.nextTick)();
ts += diff;
}
}
/**
* Converts string to bytes using UTF8 encoding.
* @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error('string expected');
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Converts bytes to string using UTF8 encoding.
* @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'
*/
function bytesToUtf8(bytes) {
return new TextDecoder().decode(bytes);
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
abytes(data);
return data;
}
/**
* Helper for KDFs: consumes uint8array or string.
* When string is passed, does utf8 decoding, using TextDecoder.
*/
function kdfInputToBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
abytes(data);
return data;
}
/** Copies several Uint8Arrays into one. */
function concatBytes(...arrays) {
let sum = 0;
for (let i = 0; i < arrays.length; i++) {
const a = arrays[i];
abytes(a);
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const a = arrays[i];
res.set(a, pad);
pad += a.length;
}
return res;
}
function checkOpts(defaults, opts) {
if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')
throw new Error('options should be object or undefined');
const merged = Object.assign(defaults, opts);
return merged;
}
/** For runtime check if class implements interface */
class Hash {
}
exports.Hash = Hash;
/** Wraps hash function, creating an interface on top of it */
function createHasher(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
function createOptHasher(hashCons) {
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
const tmp = hashCons({});
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = (opts) => hashCons(opts);
return hashC;
}
function createXOFer(hashCons) {
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
const tmp = hashCons({});
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = (opts) => hashCons(opts);
return hashC;
}
exports.wrapConstructor = createHasher;
exports.wrapConstructorWithOpts = createOptHasher;
exports.wrapXOFConstructorWithOpts = createXOFer;
/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */
function randomBytes(bytesLength = 32) {
if (crypto_1.crypto && typeof crypto_1.crypto.getRandomValues === 'function') {
return crypto_1.crypto.getRandomValues(new Uint8Array(bytesLength));
}
// Legacy Node.js compatibility
if (crypto_1.crypto && typeof crypto_1.crypto.randomBytes === 'function') {
return Uint8Array.from(crypto_1.crypto.randomBytes(bytesLength));
}
throw new Error('crypto.getRandomValues must be defined');
}
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createParserServices = createParserServices;
function createParserServices(astMaps, program) {
if (!program) {
return {
emitDecoratorMetadata: undefined,
experimentalDecorators: undefined,
isolatedDeclarations: undefined,
program,
// we always return the node maps because
// (a) they don't require type info and
// (b) they can be useful when using some of TS's internal non-type-aware AST utils
...astMaps,
};
}
const checker = program.getTypeChecker();
const compilerOptions = program.getCompilerOptions();
return {
program,
// not set in the config is the same as off
emitDecoratorMetadata: compilerOptions.emitDecoratorMetadata ?? false,
experimentalDecorators: compilerOptions.experimentalDecorators ?? false,
isolatedDeclarations: compilerOptions.isolatedDeclarations ?? false,
...astMaps,
getContextualType: node => checker.getContextualType(astMaps.esTreeNodeToTSNodeMap.get(node)),
getResolvedSignature: node => checker.getResolvedSignature(astMaps.esTreeNodeToTSNodeMap.get(node)),
getSymbolAtLocation: node => checker.getSymbolAtLocation(astMaps.esTreeNodeToTSNodeMap.get(node)),
getTypeAtLocation: node => checker.getTypeAtLocation(astMaps.esTreeNodeToTSNodeMap.get(node)),
getTypeFromTypeNode: node => checker.getTypeFromTypeNode(astMaps.esTreeNodeToTSNodeMap.get(node)),
getTypeOfSymbolAtLocation: (symbol, node) => checker.getTypeOfSymbolAtLocation(symbol, astMaps.esTreeNodeToTSNodeMap.get(node)),
};
}

View File

@@ -0,0 +1,698 @@
'use strict'
const test = require('tape')
const fresh = require('import-fresh')
const pinoStdSerializers = require('pino-std-serializers')
const pino = require('../browser')
levelTest('fatal')
levelTest('error')
levelTest('warn')
levelTest('info')
levelTest('debug')
levelTest('trace')
test('silent level', ({ end, fail, pass }) => {
const instance = pino({
level: 'silent',
browser: { write: fail }
})
instance.info('test')
const child = instance.child({ test: 'test' })
child.info('msg-test')
// use setTimeout because setImmediate isn't supported in most browsers
setTimeout(() => {
pass()
end()
}, 0)
})
test('enabled false', ({ end, fail, pass }) => {
const instance = pino({
enabled: false,
browser: { write: fail }
})
instance.info('test')
const child = instance.child({ test: 'test' })
child.info('msg-test')
// use setTimeout because setImmediate isn't supported in most browsers
setTimeout(() => {
pass()
end()
}, 0)
})
test('throw if creating child without bindings', ({ end, throws }) => {
const instance = pino()
throws(() => instance.child())
end()
})
test('stubs write, flush and ee methods on instance', ({ end, ok, is }) => {
const instance = pino()
ok(isFunc(instance.setMaxListeners))
ok(isFunc(instance.getMaxListeners))
ok(isFunc(instance.emit))
ok(isFunc(instance.addListener))
ok(isFunc(instance.on))
ok(isFunc(instance.prependListener))
ok(isFunc(instance.once))
ok(isFunc(instance.prependOnceListener))
ok(isFunc(instance.removeListener))
ok(isFunc(instance.removeAllListeners))
ok(isFunc(instance.listeners))
ok(isFunc(instance.listenerCount))
ok(isFunc(instance.eventNames))
ok(isFunc(instance.write))
ok(isFunc(instance.flush))
is(instance.on(), undefined)
end()
})
test('exposes levels object', ({ end, same }) => {
same(pino.levels, {
values: {
fatal: 60,
error: 50,
warn: 40,
info: 30,
debug: 20,
trace: 10
},
labels: {
10: 'trace',
20: 'debug',
30: 'info',
40: 'warn',
50: 'error',
60: 'fatal'
}
})
end()
})
test('exposes faux stdSerializers', ({ end, ok, same }) => {
ok(pino.stdSerializers)
// make sure faux stdSerializers match pino-std-serializers
for (const serializer in pinoStdSerializers) {
ok(pino.stdSerializers[serializer], `pino.stdSerializers.${serializer}`)
}
// confirm faux methods return empty objects
same(pino.stdSerializers.req(), {})
same(pino.stdSerializers.mapHttpRequest(), {})
same(pino.stdSerializers.mapHttpResponse(), {})
same(pino.stdSerializers.res(), {})
// confirm wrapping function is a passthrough
const noChange = { foo: 'bar', fuz: 42 }
same(pino.stdSerializers.wrapRequestSerializer(noChange), noChange)
same(pino.stdSerializers.wrapResponseSerializer(noChange), noChange)
end()
})
test('exposes err stdSerializer', ({ end, ok }) => {
ok(pino.stdSerializers.err)
ok(pino.stdSerializers.err(Error()))
end()
})
consoleMethodTest('error')
consoleMethodTest('fatal', 'error')
consoleMethodTest('warn')
consoleMethodTest('info')
consoleMethodTest('debug')
consoleMethodTest('trace')
absentConsoleMethodTest('error', 'log')
absentConsoleMethodTest('warn', 'error')
absentConsoleMethodTest('info', 'log')
absentConsoleMethodTest('debug', 'log')
absentConsoleMethodTest('trace', 'log')
// do not run this with airtap
if (process.title !== 'browser') {
test('in absence of console, log methods become noops', ({ end, ok }) => {
const console = global.console
delete global.console
const instance = fresh('../browser')()
global.console = console
ok(fnName(instance.log).match(/noop/))
ok(fnName(instance.fatal).match(/noop/))
ok(fnName(instance.error).match(/noop/))
ok(fnName(instance.warn).match(/noop/))
ok(fnName(instance.info).match(/noop/))
ok(fnName(instance.debug).match(/noop/))
ok(fnName(instance.trace).match(/noop/))
end()
})
}
test('opts.browser.asObject logs pino-like object to console', ({ end, ok, is }) => {
const info = console.info
console.info = function (o) {
is(o.level, 30)
is(o.msg, 'test')
ok(o.time)
console.info = info
}
const instance = require('../browser')({
browser: {
asObject: true
}
})
instance.info('test')
end()
})
test('opts.browser.asObject uses opts.messageKey in logs', ({ end, ok, is }) => {
const messageKey = 'message'
const instance = require('../browser')({
messageKey,
browser: {
asObject: true,
write: function (o) {
is(o.level, 30)
is(o[messageKey], 'test')
ok(o.time)
}
}
})
instance.info('test')
end()
})
test('opts.browser.asObjectBindingsOnly passes the bindings but keep the message unformatted', ({ end, ok, is, deepEqual }) => {
const messageKey = 'message'
const instance = require('../browser')({
messageKey,
browser: {
asObjectBindingsOnly: true,
write: function (o, msg, ...args) {
is(o.level, 30)
ok(o.time)
is(msg, 'test %s')
deepEqual(args, ['foo'])
}
}
})
instance.info('test %s', 'foo')
end()
})
test('opts.browser.formatters (level) logs pino-like object to console', ({ end, ok, is }) => {
const info = console.info
console.info = function (o) {
is(o.level, 30)
is(o.label, 'info')
is(o.msg, 'test')
ok(o.time)
console.info = info
}
const instance = require('../browser')({
browser: {
formatters: {
level (label, number) {
return { label, level: number }
}
}
}
})
instance.info('test')
end()
})
test('opts.browser.formatters (log) logs pino-like object to console', ({ end, ok, is }) => {
const info = console.info
console.info = function (o) {
is(o.level, 30)
is(o.msg, 'test')
is(o.hello, 'world')
is(o.newField, 'test')
ok(o.time, `Logged at ${o.time}`)
console.info = info
}
const instance = require('../browser')({
browser: {
formatters: {
log (o) {
return { ...o, newField: 'test', time: `Logged at ${o.time}` }
}
}
}
})
instance.info({ hello: 'world' }, 'test')
end()
})
test('opts.browser.reportCaller adds caller in asObject mode', ({ end, ok }) => {
const instance = require('../browser')({
browser: {
asObject: true,
reportCaller: true,
write: function (o) {
ok(typeof o.caller === 'string' && o.caller.length > 0, 'has caller string')
ok(/:\\d+:\\d+/.test(o.caller) || /:\d+:\d+/.test(o.caller), `caller has line:col pattern: ${o.caller}`)
}
}
})
instance.info('test')
end()
})
// NOTE: Default (non-object) mode caller string is covered in docs
// and manually verified. Keeping the test minimal to avoid cross-env flakiness.
test('opts.browser.serialize and opts.browser.transmit only serializes log data once', ({ end, ok, is }) => {
const instance = require('../browser')({
serializers: {
extras (data) {
return { serializedExtras: data }
}
},
browser: {
serialize: ['extras'],
transmit: {
level: 'info',
send (level, o) {
is(o.messages[0].extras.serializedExtras, 'world')
}
}
}
})
instance.info({ extras: 'world' }, 'test')
end()
})
test('opts.browser.serialize and opts.asObject only serializes log data once', ({ end, ok, is }) => {
const instance = require('../browser')({
serializers: {
extras (data) {
return { serializedExtras: data }
}
},
browser: {
serialize: ['extras'],
asObject: true,
write: function (o) {
is(o.extras.serializedExtras, 'world')
}
}
})
instance.info({ extras: 'world' }, 'test')
end()
})
test('opts.browser.serialize, opts.asObject and opts.browser.transmit only serializes log data once', ({ end, ok, is }) => {
const instance = require('../browser')({
serializers: {
extras (data) {
return { serializedExtras: data }
}
},
browser: {
serialize: ['extras'],
asObject: true,
transmit: {
send (level, o) {
is(o.messages[0].extras.serializedExtras, 'world')
}
}
}
})
instance.info({ extras: 'world' }, 'test')
end()
})
test('opts.browser.write func log single string', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: function (o) {
is(o.level, 30)
is(o.msg, 'test')
ok(o.time)
}
}
})
instance.info('test')
end()
})
test('opts.browser.write func string joining', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: function (o) {
is(o.level, 30)
is(o.msg, 'test test2 test3')
ok(o.time)
}
}
})
instance.info('test %s %s', 'test2', 'test3')
end()
})
test('opts.browser.write func string joining when asObject is true', ({ end, ok, is }) => {
const instance = pino({
browser: {
asObject: true,
write: function (o) {
is(o.level, 30)
is(o.msg, 'test test2 test3')
ok(o.time)
}
}
})
instance.info('test %s %s', 'test2', 'test3')
end()
})
test('opts.browser.write func string object joining', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: function (o) {
is(o.level, 30)
is(o.msg, 'test {"test":"test2"} {"test":"test3"}')
ok(o.time)
}
}
})
instance.info('test %j %j', { test: 'test2' }, { test: 'test3' })
end()
})
test('opts.browser.write func string object joining when asObject is true', ({ end, ok, is }) => {
const instance = pino({
browser: {
asObject: true,
write: function (o) {
is(o.level, 30)
is(o.msg, 'test {"test":"test2"} {"test":"test3"}')
ok(o.time)
}
}
})
instance.info('test %j %j', { test: 'test2' }, { test: 'test3' })
end()
})
test('opts.browser.write func string interpolation', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: function (o) {
is(o.level, 30)
is(o.msg, 'test2 test ({"test":"test3"})')
ok(o.time)
}
}
})
instance.info('%s test (%j)', 'test2', { test: 'test3' })
end()
})
test('opts.browser.write func number', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: function (o) {
is(o.level, 30)
is(o.msg, 1)
ok(o.time)
}
}
})
instance.info(1)
end()
})
test('opts.browser.write func log single object', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: function (o) {
is(o.level, 30)
is(o.test, 'test')
ok(o.time)
}
}
})
instance.info({ test: 'test' })
end()
})
test('opts.browser.write obj writes to methods corresponding to level', ({ end, ok, is }) => {
const instance = pino({
browser: {
write: {
error: function (o) {
is(o.level, 50)
is(o.test, 'test')
ok(o.time)
}
}
}
})
instance.error({ test: 'test' })
end()
})
test('opts.browser.asObject/write supports child loggers', ({ end, ok, is }) => {
const instance = pino({
browser: {
write (o) {
is(o.level, 30)
is(o.test, 'test')
is(o.msg, 'msg-test')
ok(o.time)
}
}
})
const child = instance.child({ test: 'test' })
child.info('msg-test')
end()
})
test('opts.browser.asObject/write supports child child loggers', ({ end, ok, is }) => {
const instance = pino({
browser: {
write (o) {
is(o.level, 30)
is(o.test, 'test')
is(o.foo, 'bar')
is(o.msg, 'msg-test')
ok(o.time)
}
}
})
const child = instance.child({ test: 'test' }).child({ foo: 'bar' })
child.info('msg-test')
end()
})
test('opts.browser.asObject/write supports child child child loggers', ({ end, ok, is }) => {
const instance = pino({
browser: {
write (o) {
is(o.level, 30)
is(o.test, 'test')
is(o.foo, 'bar')
is(o.baz, 'bop')
is(o.msg, 'msg-test')
ok(o.time)
}
}
})
const child = instance.child({ test: 'test' }).child({ foo: 'bar' }).child({ baz: 'bop' })
child.info('msg-test')
end()
})
test('opts.browser.asObject defensively mitigates naughty numbers', ({ end, pass }) => {
const instance = pino({
browser: { asObject: true, write: () => {} }
})
const child = instance.child({ test: 'test' })
child._childLevel = -10
child.info('test')
pass() // if we reached here, there was no infinite loop, so, .. pass.
end()
})
test('opts.browser.write obj falls back to console where a method is not supplied', ({ end, ok, is }) => {
const info = console.info
console.info = (o) => {
is(o.level, 30)
is(o.msg, 'test')
ok(o.time)
console.info = info
}
const instance = require('../browser')({
browser: {
write: {
error (o) {
is(o.level, 50)
is(o.test, 'test')
ok(o.time)
}
}
}
})
instance.error({ test: 'test' })
instance.info('test')
end()
})
function levelTest (name) {
test(name + ' logs', ({ end, is }) => {
const msg = 'hello world'
sink(name, (args) => {
is(args[0], msg)
end()
})
pino({ level: name })[name](msg)
})
test('passing objects at level ' + name, ({ end, is }) => {
const msg = { hello: 'world' }
sink(name, (args) => {
is(args[0], msg)
end()
})
pino({ level: name })[name](msg)
})
test('passing an object and a string at level ' + name, ({ end, is }) => {
const a = { hello: 'world' }
const b = 'a string'
sink(name, (args) => {
is(args[0], a)
is(args[1], b)
end()
})
pino({ level: name })[name](a, b)
})
test('formatting logs as ' + name, ({ end, is }) => {
sink(name, (args) => {
is(args[0], 'hello %d')
is(args[1], 42)
end()
})
pino({ level: name })[name]('hello %d', 42)
})
test('passing error at level ' + name, ({ end, is }) => {
const err = new Error('myerror')
sink(name, (args) => {
is(args[0], err)
end()
})
pino({ level: name })[name](err)
})
test('passing error with a serializer at level ' + name, ({ end, is }) => {
// in browser - should have no effect (should not crash)
const err = new Error('myerror')
sink(name, (args) => {
is(args[0].err, err)
end()
})
const instance = pino({
level: name,
serializers: {
err: pino.stdSerializers.err
}
})
instance[name]({ err })
})
test('child logger for level ' + name, ({ end, is }) => {
const msg = 'hello world'
const parent = { hello: 'world' }
sink(name, (args) => {
is(args[0], parent)
is(args[1], msg)
end()
})
const instance = pino({ level: name })
const child = instance.child(parent)
child[name](msg)
})
test('child-child logger for level ' + name, ({ end, is }) => {
const msg = 'hello world'
const grandParent = { hello: 'world' }
const parent = { hello: 'you' }
sink(name, (args) => {
is(args[0], grandParent)
is(args[1], parent)
is(args[2], msg)
end()
})
const instance = pino({ level: name })
const child = instance.child(grandParent).child(parent)
child[name](msg)
})
}
function consoleMethodTest (level, method) {
if (!method) method = level
test('pino().' + level + ' uses console.' + method, ({ end, is }) => {
sink(method, (args) => {
is(args[0], 'test')
end()
})
const instance = require('../browser')({ level })
instance[level]('test')
})
}
function absentConsoleMethodTest (method, fallback) {
test('in absence of console.' + method + ', console.' + fallback + ' is used', ({ end, is }) => {
const fn = console[method]
console[method] = undefined
sink(fallback, function (args) {
is(args[0], 'test')
end()
console[method] = fn
})
const instance = require('../browser')({ level: method })
instance[method]('test')
})
}
function isFunc (fn) { return typeof fn === 'function' }
function fnName (fn) {
const rx = /^\s*function\s*([^(]*)/i
const match = rx.exec(fn)
return match && match[1]
}
function sink (method, fn) {
if (method === 'fatal') method = 'error'
const orig = console[method]
console[method] = function () {
console[method] = orig
fn(Array.prototype.slice.call(arguments))
}
}

View File

@@ -0,0 +1,38 @@
/**
* @fileoverview Handle logging for ESLint
* @author Gyandeep Singh
*/
"use strict";
/* eslint no-console: "off" -- Logging util */
/* c8 ignore next */
module.exports = {
/**
* Cover for console.info
* @param {...any} args The elements to log.
* @returns {void}
*/
info(...args) {
console.log(...args);
},
/**
* Cover for console.warn
* @param {...any} args The elements to log.
* @returns {void}
*/
warn(...args) {
console.warn(...args);
},
/**
* Cover for console.error
* @param {...any} args The elements to log.
* @returns {void}
*/
error(...args) {
console.error(...args);
},
};

View File

@@ -0,0 +1,5 @@
var id = 0;
function _classPrivateFieldKey(e) {
return "__private_" + id++ + "_" + e;
}
export { _classPrivateFieldKey as default };

View File

@@ -0,0 +1,13 @@
"use strict";
/**
* This is a compatibility ruleset that:
* - disables rules from eslint:recommended which are already handled by TypeScript.
* - enables rules that make sense due to TS's typechecking / transpilation.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const eslint_recommended_raw_1 = __importDefault(require("../eslint-recommended-raw"));
module.exports = {
overrides: [(0, eslint_recommended_raw_1.default)('glob')],
};

View File

@@ -0,0 +1,124 @@
import type { $ZodStringFormats } from "../core/checks.js";
import type * as errors from "../core/errors.js";
import * as util from "../core/util.js";
const error: () => errors.$ZodErrorMap = () => {
const Sizable: Record<string, { unit: string; verb: string }> = {
string: { unit: "àmi", verb: "ní" },
file: { unit: "bytes", verb: "ní" },
array: { unit: "nkan", verb: "ní" },
set: { unit: "nkan", verb: "ní" },
};
function getSizing(origin: string): { unit: string; verb: string } | null {
return Sizable[origin] ?? null;
}
const FormatDictionary: {
[k in $ZodStringFormats | (string & {})]?: string;
} = {
regex: "ẹ̀rọ ìbáwọlé",
email: "àdírẹ́sì ìmẹ́lì",
url: "URL",
emoji: "emoji",
uuid: "UUID",
uuidv4: "UUIDv4",
uuidv6: "UUIDv6",
nanoid: "nanoid",
guid: "GUID",
cuid: "cuid",
cuid2: "cuid2",
ulid: "ULID",
xid: "XID",
ksuid: "KSUID",
datetime: "àkókò ISO",
date: "ọjọ́ ISO",
time: "àkókò ISO",
duration: "àkókò tó pé ISO",
ipv4: "àdírẹ́sì IPv4",
ipv6: "àdírẹ́sì IPv6",
cidrv4: "àgbègbè IPv4",
cidrv6: "àgbègbè IPv6",
base64: "ọ̀rọ̀ tí a kọ́ ní base64",
base64url: "ọ̀rọ̀ base64url",
json_string: "ọ̀rọ̀ JSON",
e164: "nọ́mbà E.164",
jwt: "JWT",
template_literal: "ẹ̀rọ ìbáwọlé",
};
const TypeDictionary: {
[k in errors.$ZodInvalidTypeExpected | (string & {})]?: string;
} = {
nan: "NaN",
number: "nọ́mbà",
array: "akopọ",
};
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 `Ìbáwọlé aṣìṣe: a ní láti fi instanceof ${issue.expected}, àmọ̀ a rí ${received}`;
}
return `Ìbáwọlé aṣìṣe: a ní láti fi ${expected}, àmọ̀ a rí ${received}`;
}
case "invalid_value":
if (issue.values.length === 1) return `Ìbáwọlé aṣìṣe: a ní láti fi ${util.stringifyPrimitive(issue.values[0])}`;
return `Àṣàyàn aṣìṣe: yan ọ̀kan lára ${util.joinValues(issue.values, "|")}`;
case "too_big": {
const adj = issue.inclusive ? "<=" : "<";
const sizing = getSizing(issue.origin);
if (sizing)
return `Tó pọ̀ jù: a ní láti jẹ́ pé ${issue.origin ?? "iye"} ${sizing.verb} ${adj}${issue.maximum} ${sizing.unit}`;
return `Tó pọ̀ jù: a ní láti jẹ́ ${adj}${issue.maximum}`;
}
case "too_small": {
const adj = issue.inclusive ? ">=" : ">";
const sizing = getSizing(issue.origin);
if (sizing)
return `Kéré ju: a ní láti jẹ́ pé ${issue.origin} ${sizing.verb} ${adj}${issue.minimum} ${sizing.unit}`;
return `Kéré ju: a ní láti jẹ́ ${adj}${issue.minimum}`;
}
case "invalid_format": {
const _issue = issue as errors.$ZodStringFormatIssues;
if (_issue.format === "starts_with") return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ bẹ̀rẹ̀ pẹ̀lú "${_issue.prefix}"`;
if (_issue.format === "ends_with") return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ parí pẹ̀lú "${_issue.suffix}"`;
if (_issue.format === "includes") return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ ní "${_issue.includes}"`;
if (_issue.format === "regex") return `Ọ̀rọ̀ aṣìṣe: gbọ́dọ̀ bá àpẹẹrẹ mu ${_issue.pattern}`;
return `Aṣìṣe: ${FormatDictionary[_issue.format] ?? issue.format}`;
}
case "not_multiple_of":
return `Nọ́mbà aṣìṣe: gbọ́dọ̀ jẹ́ èyà pípín ti ${issue.divisor}`;
case "unrecognized_keys":
return `Bọtìnì àìmọ̀: ${util.joinValues(issue.keys, ", ")}`;
case "invalid_key":
return `Bọtìnì aṣìṣe nínú ${issue.origin}`;
case "invalid_union":
return "Ìbáwọlé aṣìṣe";
case "invalid_element":
return `Iye aṣìṣe nínú ${issue.origin}`;
default:
return "Ìbáwọlé aṣìṣe";
}
};
};
export default function (): { localeError: errors.$ZodErrorMap } {
return {
localeError: error(),
};
}

View File

@@ -0,0 +1,18 @@
type Values = 'always' | 'in-intersections' | 'in-unions' | 'in-unions-and-intersections' | 'never';
export type Options = [
{
allowAliases?: Values;
allowCallbacks?: 'always' | 'never';
allowConditionalTypes?: 'always' | 'never';
allowConstructors?: 'always' | 'never';
allowGenerics?: 'always' | 'never';
allowLiterals?: Values;
allowMappedTypes?: Values;
allowTupleTypes?: Values;
}
];
export type MessageIds = 'noCompositionAlias' | 'noTypeAlias';
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1,216 @@
"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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.$ZodRealError = exports.$ZodError = void 0;
exports.flattenError = flattenError;
exports.formatError = formatError;
exports.treeifyError = treeifyError;
exports.toDotPath = toDotPath;
exports.prettifyError = prettifyError;
const core_js_1 = require("./core.cjs");
const util = __importStar(require("./util.cjs"));
const initializer = (inst, def) => {
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,
});
};
exports.$ZodError = (0, core_js_1.$constructor)("$ZodError", initializer);
exports.$ZodRealError = (0, core_js_1.$constructor)("$ZodError", initializer, { Parent: Error });
function flattenError(error, mapper = (issue) => issue.message) {
const fieldErrors = {};
const formErrors = [];
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 };
}
function formatError(error, mapper = (issue) => issue.message) {
const fieldErrors = { _errors: [] };
const processError = (error, path = []) => {
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._errors.push(mapper(issue));
}
else {
let curr = 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;
}
function treeifyError(error, mapper = (issue) => issue.message) {
const result = { errors: [] };
const processError = (error, path = []) => {
var _a, _b;
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 = 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 = {});
(_a = curr.properties)[el] ?? (_a[el] = { errors: [] });
curr = curr.properties[el];
}
else {
curr.items ?? (curr.items = []);
(_b = curr.items)[el] ?? (_b[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
* ```
*/
function toDotPath(_path) {
const segs = [];
const path = _path.map((seg) => (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("");
}
function prettifyError(error) {
const lines = [];
// 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,654 @@
/**
* @fileoverview Rule to enforce concise object methods and properties.
* @author Jamund Ferguson
*/
"use strict";
const OPTIONS = {
always: "always",
never: "never",
methods: "methods",
properties: "properties",
consistent: "consistent",
consistentAsNeeded: "consistent-as-needed",
};
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
const CTOR_PREFIX_REGEX = /[^_$0-9]/u;
const JSDOC_COMMENT_REGEX = /^\s*\*/u;
/**
* Determines if the first character of the name is a capital letter.
* @param {string} name The name of the node to evaluate.
* @returns {boolean} True if the first character of the property name is a capital letter, false if not.
* @private
*/
function isConstructor(name) {
const match = CTOR_PREFIX_REGEX.exec(name);
// Not a constructor if name has no characters apart from '_', '$' and digits e.g. '_', '$$', '_8'
if (!match) {
return false;
}
const firstChar = name.charAt(match.index);
return firstChar === firstChar.toUpperCase();
}
/**
* Determines if the property can have a shorthand form.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the property can have a shorthand form
* @private
*/
function canHaveShorthand(property) {
return (
property.kind !== "set" &&
property.kind !== "get" &&
property.type !== "SpreadElement" &&
property.type !== "SpreadProperty" &&
property.type !== "ExperimentalSpreadProperty"
);
}
/**
* Checks whether a node is a string literal.
* @param {ASTNode} node Any AST node.
* @returns {boolean} `true` if it is a string literal.
*/
function isStringLiteral(node) {
return node.type === "Literal" && typeof node.value === "string";
}
/**
* Determines if the property is a shorthand or not.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the property is considered shorthand, false if not.
* @private
*/
function isShorthand(property) {
// property.method is true when `{a(){}}`.
return property.shorthand || property.method;
}
/**
* Determines if the property's key and method or value are named equally.
* @param {ASTNode} property Property AST node
* @returns {boolean} True if the key and value are named equally, false if not.
* @private
*/
function isRedundant(property) {
const value = property.value;
if (value.type === "FunctionExpression") {
return !value.id; // Only anonymous should be shorthand method.
}
if (value.type === "Identifier") {
return astUtils.getStaticPropertyName(property) === value.name;
}
return false;
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description:
"Require or disallow method and property shorthand syntax for object literals",
recommended: false,
frozen: true,
url: "https://eslint.org/docs/latest/rules/object-shorthand",
},
fixable: "code",
schema: {
anyOf: [
{
type: "array",
items: [
{
enum: [
"always",
"methods",
"properties",
"never",
"consistent",
"consistent-as-needed",
],
},
],
minItems: 0,
maxItems: 1,
},
{
type: "array",
items: [
{
enum: ["always", "methods", "properties"],
},
{
type: "object",
properties: {
avoidQuotes: {
type: "boolean",
},
},
additionalProperties: false,
},
],
minItems: 0,
maxItems: 2,
},
{
type: "array",
items: [
{
enum: ["always", "methods"],
},
{
type: "object",
properties: {
ignoreConstructors: {
type: "boolean",
},
methodsIgnorePattern: {
type: "string",
},
avoidQuotes: {
type: "boolean",
},
avoidExplicitReturnArrows: {
type: "boolean",
},
},
additionalProperties: false,
},
],
minItems: 0,
maxItems: 2,
},
],
},
defaultOptions: ["always"],
messages: {
expectedAllPropertiesShorthanded:
"Expected shorthand for all properties.",
expectedLiteralMethodLongform:
"Expected longform method syntax for string literal keys.",
expectedPropertyShorthand: "Expected property shorthand.",
expectedPropertyLongform: "Expected longform property syntax.",
expectedMethodShorthand: "Expected method shorthand.",
expectedMethodLongform: "Expected longform method syntax.",
unexpectedMix:
"Unexpected mix of shorthand and non-shorthand properties.",
},
},
create(context) {
const APPLY = context.options[0];
const APPLY_TO_METHODS =
APPLY === OPTIONS.methods || APPLY === OPTIONS.always;
const APPLY_TO_PROPS =
APPLY === OPTIONS.properties || APPLY === OPTIONS.always;
const APPLY_NEVER = APPLY === OPTIONS.never;
const APPLY_CONSISTENT = APPLY === OPTIONS.consistent;
const APPLY_CONSISTENT_AS_NEEDED = APPLY === OPTIONS.consistentAsNeeded;
const PARAMS = context.options[1] || {};
const IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors;
const METHODS_IGNORE_PATTERN = PARAMS.methodsIgnorePattern
? new RegExp(PARAMS.methodsIgnorePattern, "u")
: null;
const AVOID_QUOTES = PARAMS.avoidQuotes;
const AVOID_EXPLICIT_RETURN_ARROWS = !!PARAMS.avoidExplicitReturnArrows;
const sourceCode = context.sourceCode;
/**
* Ensures that an object's properties are consistently shorthand, or not shorthand at all.
* @param {ASTNode} node Property AST node
* @param {boolean} checkRedundancy Whether to check longform redundancy
* @returns {void}
*/
function checkConsistency(node, checkRedundancy) {
// We are excluding getters/setters and spread properties as they are considered neither longform nor shorthand.
const properties = node.properties.filter(canHaveShorthand);
// Do we still have properties left after filtering the getters and setters?
if (properties.length > 0) {
const shorthandProperties = properties.filter(isShorthand);
/*
* If we do not have an equal number of longform properties as
* shorthand properties, we are using the annotations inconsistently
*/
if (shorthandProperties.length !== properties.length) {
// We have at least 1 shorthand property
if (shorthandProperties.length > 0) {
context.report({ node, messageId: "unexpectedMix" });
} else if (checkRedundancy) {
/*
* If all properties of the object contain a method or value with a name matching it's key,
* all the keys are redundant.
*/
const canAlwaysUseShorthand =
properties.every(isRedundant);
if (canAlwaysUseShorthand) {
context.report({
node,
messageId: "expectedAllPropertiesShorthanded",
});
}
}
}
}
}
/**
* Fixes a FunctionExpression node by making it into a shorthand property.
* @param {SourceCodeFixer} fixer The fixer object
* @param {ASTNode} node A `Property` node that has a `FunctionExpression` or `ArrowFunctionExpression` as its value
* @returns {Object} A fix for this node
*/
function makeFunctionShorthand(fixer, node) {
const firstKeyToken = node.computed
? sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken)
: sourceCode.getFirstToken(node.key);
const lastKeyToken = node.computed
? sourceCode.getFirstTokenBetween(
node.key,
node.value,
astUtils.isClosingBracketToken,
)
: sourceCode.getLastToken(node.key);
const keyText = sourceCode.text.slice(
firstKeyToken.range[0],
lastKeyToken.range[1],
);
let keyPrefix = "";
// key: /* */ () => {}
if (sourceCode.commentsExistBetween(lastKeyToken, node.value)) {
return null;
}
if (node.value.async) {
keyPrefix += "async ";
}
if (node.value.generator) {
keyPrefix += "*";
}
const fixRange = [firstKeyToken.range[0], node.range[1]];
const methodPrefix = keyPrefix + keyText;
if (node.value.type === "FunctionExpression") {
const functionToken = sourceCode
.getTokens(node.value)
.find(
token =>
token.type === "Keyword" &&
token.value === "function",
);
const tokenBeforeParams = node.value.generator
? sourceCode.getTokenAfter(functionToken)
: functionToken;
return fixer.replaceTextRange(
fixRange,
methodPrefix +
sourceCode.text.slice(
tokenBeforeParams.range[1],
node.value.range[1],
),
);
}
const arrowToken = sourceCode.getTokenBefore(
node.value.body,
astUtils.isArrowToken,
);
const fnBody = sourceCode.text.slice(
arrowToken.range[1],
node.value.range[1],
);
// First token should not be `async`
const firstValueToken = sourceCode.getFirstToken(node.value, {
skip: node.value.async ? 1 : 0,
});
const sliceStart = firstValueToken.range[0];
const sliceEnd = sourceCode.getTokenBefore(arrowToken).range[1];
const shouldAddParens =
node.value.params.length === 1 &&
node.value.params[0].range[0] === sliceStart;
const oldParamText = sourceCode.text.slice(sliceStart, sliceEnd);
const newParamText = shouldAddParens
? `(${oldParamText})`
: oldParamText;
return fixer.replaceTextRange(
fixRange,
methodPrefix + newParamText + fnBody,
);
}
/**
* Fixes a FunctionExpression node by making it into a longform property.
* @param {SourceCodeFixer} fixer The fixer object
* @param {ASTNode} node A `Property` node that has a `FunctionExpression` as its value
* @returns {Object} A fix for this node
*/
function makeFunctionLongform(fixer, node) {
const firstKeyToken = node.computed
? sourceCode.getTokens(node).find(token => token.value === "[")
: sourceCode.getFirstToken(node.key);
const lastKeyToken = node.computed
? sourceCode
.getTokensBetween(node.key, node.value)
.find(token => token.value === "]")
: sourceCode.getLastToken(node.key);
const keyText = sourceCode.text.slice(
firstKeyToken.range[0],
lastKeyToken.range[1],
);
let functionHeader = "function";
if (node.value.async) {
functionHeader = `async ${functionHeader}`;
}
if (node.value.generator) {
functionHeader = `${functionHeader}*`;
}
return fixer.replaceTextRange(
[node.range[0], lastKeyToken.range[1]],
`${keyText}: ${functionHeader}`,
);
}
/*
* To determine whether a given arrow function has a lexical identifier (`this`, `arguments`, `super`, or `new.target`),
* create a stack of functions that define these identifiers (i.e. all functions except arrow functions) as the AST is
* traversed. Whenever a new function is encountered, create a new entry on the stack (corresponding to a different lexical
* scope of `this`), and whenever a function is exited, pop that entry off the stack. When an arrow function is entered,
* keep a reference to it on the current stack entry, and remove that reference when the arrow function is exited.
* When a lexical identifier is encountered, mark all the arrow functions on the current stack entry by adding them
* to an `arrowsWithLexicalIdentifiers` set. Any arrow function in that set will not be reported by this rule,
* because converting it into a method would change the value of one of the lexical identifiers.
*/
const lexicalScopeStack = [];
const arrowsWithLexicalIdentifiers = new WeakSet();
const argumentsIdentifiers = new WeakSet();
/**
* Enters a function. This creates a new lexical identifier scope, so a new Set of arrow functions is pushed onto the stack.
* Also, this marks all `arguments` identifiers so that they can be detected later.
* @param {ASTNode} node The node representing the function.
* @returns {void}
*/
function enterFunction(node) {
lexicalScopeStack.unshift(new Set());
sourceCode
.getScope(node)
.variables.filter(variable => variable.name === "arguments")
.forEach(variable => {
variable.references
.map(ref => ref.identifier)
.forEach(identifier =>
argumentsIdentifiers.add(identifier),
);
});
}
/**
* Exits a function. This pops the current set of arrow functions off the lexical scope stack.
* @returns {void}
*/
function exitFunction() {
lexicalScopeStack.shift();
}
/**
* Marks the current function as having a lexical keyword. This implies that all arrow functions
* in the current lexical scope contain a reference to this lexical keyword.
* @returns {void}
*/
function reportLexicalIdentifier() {
lexicalScopeStack[0].forEach(arrowFunction =>
arrowsWithLexicalIdentifiers.add(arrowFunction),
);
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {
Program: enterFunction,
FunctionDeclaration: enterFunction,
FunctionExpression: enterFunction,
"Program:exit": exitFunction,
"FunctionDeclaration:exit": exitFunction,
"FunctionExpression:exit": exitFunction,
ArrowFunctionExpression(node) {
lexicalScopeStack[0].add(node);
},
"ArrowFunctionExpression:exit"(node) {
lexicalScopeStack[0].delete(node);
},
ThisExpression: reportLexicalIdentifier,
Super: reportLexicalIdentifier,
MetaProperty(node) {
if (
node.meta.name === "new" &&
node.property.name === "target"
) {
reportLexicalIdentifier();
}
},
Identifier(node) {
if (argumentsIdentifiers.has(node)) {
reportLexicalIdentifier();
}
},
ObjectExpression(node) {
if (APPLY_CONSISTENT) {
checkConsistency(node, false);
} else if (APPLY_CONSISTENT_AS_NEEDED) {
checkConsistency(node, true);
}
},
"Property:exit"(node) {
const isConciseProperty = node.method || node.shorthand;
// Ignore destructuring assignment
if (node.parent.type === "ObjectPattern") {
return;
}
// getters and setters are ignored
if (node.kind === "get" || node.kind === "set") {
return;
}
// only computed methods can fail the following checks
if (
node.computed &&
node.value.type !== "FunctionExpression" &&
node.value.type !== "ArrowFunctionExpression"
) {
return;
}
//--------------------------------------------------------------
// Checks for property/method shorthand.
if (isConciseProperty) {
if (
node.method &&
(APPLY_NEVER ||
(AVOID_QUOTES && isStringLiteral(node.key)))
) {
const messageId = APPLY_NEVER
? "expectedMethodLongform"
: "expectedLiteralMethodLongform";
// { x() {} } should be written as { x: function() {} }
context.report({
node,
messageId,
fix: fixer => makeFunctionLongform(fixer, node),
});
} else if (APPLY_NEVER) {
// { x } should be written as { x: x }
context.report({
node,
messageId: "expectedPropertyLongform",
fix: fixer =>
fixer.insertTextAfter(
node.key,
`: ${node.key.name}`,
),
});
}
} else if (
APPLY_TO_METHODS &&
!node.value.id &&
(node.value.type === "FunctionExpression" ||
node.value.type === "ArrowFunctionExpression")
) {
if (
IGNORE_CONSTRUCTORS &&
node.key.type === "Identifier" &&
isConstructor(node.key.name)
) {
return;
}
if (METHODS_IGNORE_PATTERN) {
const propertyName =
astUtils.getStaticPropertyName(node);
if (
propertyName !== null &&
METHODS_IGNORE_PATTERN.test(propertyName)
) {
return;
}
}
if (AVOID_QUOTES && isStringLiteral(node.key)) {
return;
}
// {[x]: function(){}} should be written as {[x]() {}}
if (
node.value.type === "FunctionExpression" ||
(node.value.type === "ArrowFunctionExpression" &&
node.value.body.type === "BlockStatement" &&
AVOID_EXPLICIT_RETURN_ARROWS &&
!arrowsWithLexicalIdentifiers.has(node.value))
) {
context.report({
node,
messageId: "expectedMethodShorthand",
fix: fixer => makeFunctionShorthand(fixer, node),
});
}
} else if (
node.value.type === "Identifier" &&
node.key.name === node.value.name &&
APPLY_TO_PROPS
) {
// Skip if there are JSDoc comments inside the property (e.g., JSDoc type annotations)
const comments = sourceCode.getCommentsInside(node);
if (
comments.some(
comment =>
comment.type === "Block" &&
JSDOC_COMMENT_REGEX.test(comment.value) &&
comment.value.includes("@type"),
)
) {
return;
}
// {x: x} should be written as {x}
context.report({
node,
messageId: "expectedPropertyShorthand",
fix(fixer) {
// x: /* */ x
// x: (/* */ x)
if (sourceCode.getCommentsInside(node).length > 0) {
return null;
}
return fixer.replaceText(node, node.value.name);
},
});
} else if (
node.value.type === "Identifier" &&
node.key.type === "Literal" &&
node.key.value === node.value.name &&
APPLY_TO_PROPS
) {
if (AVOID_QUOTES) {
return;
}
const comments = sourceCode.getCommentsInside(node);
if (
comments.some(
comment =>
comment.type === "Block" &&
comment.value.startsWith("*") &&
comment.value.includes("@type"),
)
) {
return;
}
// {"x": x} should be written as {x}
context.report({
node,
messageId: "expectedPropertyShorthand",
fix(fixer) {
// "x": /* */ x
// "x": (/* */ x)
if (sourceCode.getCommentsInside(node).length > 0) {
return null;
}
return fixer.replaceText(node, node.value.name);
},
});
}
},
};
},
};

View File

@@ -0,0 +1,6 @@
import * as ts from 'typescript';
/**
* @deprecated
* Gets the source file for a given node
*/
export declare function getSourceFileOfNode(node: ts.Node): ts.SourceFile;

View File

@@ -0,0 +1,306 @@
/**
* @fileoverview Translates tokens between Acorn format and Esprima format.
* @author Nicholas C. Zakas
*/
/**
* @import * as acorn from "acorn";
* @import { EnhancedTokTypes } from "./espree.js"
* @import { NormalizedEcmaVersion } from "./options.js";
* @import { EspreeToken as EsprimaToken } from "../espree.js";
*/
/**
* Based on the `acorn.Token` class, but without a fixed `type` (since we need
* it to be a string). Avoiding `type` lets us make one extending interface
* more strict and another more lax.
*
* We could make `value` more strict to `string` even though the original is
* `any`.
*
* `start` and `end` are required in `acorn.Token`
*
* `loc` and `range` are from `acorn.Token`
*
* Adds `regex`.
*/
/**
* @typedef {{
* jsxAttrValueToken: boolean;
* ecmaVersion: NormalizedEcmaVersion;
* }} ExtraNoTokens
* @typedef {{
* tokens: EsprimaToken[]
* } & ExtraNoTokens} Extra
*/
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
// Esprima Token Types
const Token = {
Boolean: "Boolean",
EOF: "<end>",
Identifier: "Identifier",
PrivateIdentifier: "PrivateIdentifier",
Keyword: "Keyword",
Null: "Null",
Numeric: "Numeric",
Punctuator: "Punctuator",
String: "String",
RegularExpression: "RegularExpression",
Template: "Template",
JSXIdentifier: "JSXIdentifier",
JSXText: "JSXText",
};
/**
* Converts part of a template into an Esprima token.
* @param {acorn.Token[]} tokens The Acorn tokens representing the template.
* @param {string} code The source code.
* @returns {EsprimaToken} The Esprima equivalent of the template token.
* @private
*/
function convertTemplatePart(tokens, code) {
const firstToken = tokens[0],
lastTemplateToken =
/** @type {acorn.Token & { loc: acorn.SourceLocation, range: [number, number] }} */ (
tokens.at(-1)
);
/** @type {EsprimaToken} */
const token = {
type: Token.Template,
value: code.slice(firstToken.start, lastTemplateToken.end),
};
if (firstToken.loc) {
token.loc = {
start: firstToken.loc.start,
end: lastTemplateToken.loc.end,
};
}
if (firstToken.range) {
token.start = firstToken.range[0];
token.end = lastTemplateToken.range[1];
token.range = [token.start, token.end];
}
return token;
}
/* eslint-disable jsdoc/check-types -- The API allows either */
/**
* Contains logic to translate Acorn tokens into Esprima tokens.
*/
class TokenTranslator {
/**
* Contains logic to translate Acorn tokens into Esprima tokens.
* @param {EnhancedTokTypes} acornTokTypes The Acorn token types.
* @param {string|String} code The source code Acorn is parsing. This is necessary
* to correct the "value" property of some tokens.
*/
constructor(acornTokTypes, code) {
/* eslint-enable jsdoc/check-types -- The API allows either */
// token types
this._acornTokTypes = acornTokTypes;
// token buffer for templates
/** @type {acorn.Token[]} */
this._tokens = [];
// track the last curly brace
this._curlyBrace = null;
// the source code
this._code = code;
}
/**
* Translates a single Esprima token to a single Acorn token. This may be
* inaccurate due to how templates are handled differently in Esprima and
* Acorn, but should be accurate for all other tokens.
* @param {acorn.Token} token The Acorn token to translate.
* @param {ExtraNoTokens} extra Espree extra object.
* @returns {EsprimaToken} The Esprima version of the token.
*/
translate(token, extra) {
const type = token.type,
tt = this._acornTokTypes,
// We use an unknown type because `acorn.Token` is a class whose
// `type` property we cannot override to our desired `string`;
// this also allows us to define a stricter `EsprimaToken` with
// a string-only `type` property
unknownTokenType = /** @type {unknown} */ (token),
newToken = /** @type {EsprimaToken} */ (unknownTokenType);
if (type === tt.name) {
newToken.type = Token.Identifier;
// TODO: See if this is an Acorn bug
if ("value" in token && token.value === "static") {
newToken.type = Token.Keyword;
}
if (
extra.ecmaVersion > 5 &&
"value" in token &&
(token.value === "yield" || token.value === "let")
) {
newToken.type = Token.Keyword;
}
} else if (type === tt.privateId) {
newToken.type = Token.PrivateIdentifier;
} else if (
type === tt.semi ||
type === tt.comma ||
type === tt.parenL ||
type === tt.parenR ||
type === tt.braceL ||
type === tt.braceR ||
type === tt.dot ||
type === tt.bracketL ||
type === tt.colon ||
type === tt.question ||
type === tt.bracketR ||
type === tt.ellipsis ||
type === tt.arrow ||
type === tt.jsxTagStart ||
type === tt.incDec ||
type === tt.starstar ||
type === tt.jsxTagEnd ||
type === tt.prefix ||
type === tt.questionDot ||
("binop" in type && type.binop && !type.keyword) ||
("isAssign" in type && type.isAssign)
) {
newToken.type = Token.Punctuator;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.jsxName) {
newToken.type = Token.JSXIdentifier;
} else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
newToken.type = Token.JSXText;
} else if (type.keyword) {
if (type.keyword === "true" || type.keyword === "false") {
newToken.type = Token.Boolean;
} else if (type.keyword === "null") {
newToken.type = Token.Null;
} else {
newToken.type = Token.Keyword;
}
} else if (type === tt.num) {
newToken.type = Token.Numeric;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.string) {
if (extra.jsxAttrValueToken) {
extra.jsxAttrValueToken = false;
newToken.type = Token.JSXText;
} else {
newToken.type = Token.String;
}
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.regexp) {
newToken.type = Token.RegularExpression;
const value = /** @type {{flags: string, pattern: string}} */ (
"value" in token && token.value
);
newToken.regex = {
flags: value.flags,
pattern: value.pattern,
};
newToken.value = `/${value.pattern}/${value.flags}`;
}
return newToken;
}
/**
* Function to call during Acorn's onToken handler.
* @param {acorn.Token} token The Acorn token.
* @param {Extra} extra The Espree extra object.
* @returns {void}
*/
onToken(token, extra) {
const tt = this._acornTokTypes,
tokens = extra.tokens,
templateTokens = this._tokens;
/**
* Flushes the buffered template tokens and resets the template
* tracking.
* @returns {void}
* @private
*/
const translateTemplateTokens = () => {
tokens.push(convertTemplatePart(this._tokens, this._code));
this._tokens = [];
};
if (token.type === tt.eof) {
// might be one last curlyBrace
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
return;
}
if (token.type === tt.backQuote) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
templateTokens.push(token);
// it's the end
if (templateTokens.length > 1) {
translateTemplateTokens();
}
return;
}
if (token.type === tt.dollarBraceL) {
templateTokens.push(token);
translateTemplateTokens();
return;
}
if (token.type === tt.braceR) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
// store new curly for later
this._curlyBrace = token;
return;
}
if (token.type === tt.template || token.type === tt.invalidTemplate) {
if (this._curlyBrace) {
templateTokens.push(this._curlyBrace);
this._curlyBrace = null;
}
templateTokens.push(token);
return;
}
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
tokens.push(this.translate(token, extra));
}
}
//------------------------------------------------------------------------------
// Public
//------------------------------------------------------------------------------
export default TokenTranslator;

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,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/// <reference no-default-lib="true"/>
/// <reference lib="es2016" />
/// <reference lib="dom" />
/// <reference lib="webworker.importscripts" />
/// <reference lib="scripthost" />
/// <reference lib="dom.iterable" />

View File

@@ -0,0 +1 @@
{"version":3,"file":"pasta.js","sourceRoot":"","sources":["../src/pasta.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,IAAI,EAAE,EAAE,KAAK,IAAI,EAAE,EAAE,MAAM,WAAW,CAAC;AACtD,kBAAkB;AAClB,MAAM,CAAC,MAAM,MAAM,GAAc,EAAE,CAAC;AACpC,kBAAkB;AAClB,MAAM,CAAC,MAAM,KAAK,GAAc,EAAE,CAAC"}