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,85 @@
/**
* @fileoverview Rule to disallow an empty pattern
* @author Alberto Rodríguez
*/
"use strict";
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
defaultOptions: [
{
allowObjectPatternsAsParameters: false,
},
],
docs: {
description: "Disallow empty destructuring patterns",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-empty-pattern",
},
schema: [
{
type: "object",
properties: {
allowObjectPatternsAsParameters: {
type: "boolean",
},
},
additionalProperties: false,
},
],
messages: {
unexpected: "Unexpected empty {{type}} pattern.",
},
},
create(context) {
const [{ allowObjectPatternsAsParameters }] = context.options;
return {
ObjectPattern(node) {
if (node.properties.length > 0) {
return;
}
// Allow {} and {} = {} empty object patterns as parameters when allowObjectPatternsAsParameters is true
if (
allowObjectPatternsAsParameters &&
(astUtils.isFunction(node.parent) ||
(node.parent.type === "AssignmentPattern" &&
astUtils.isFunction(node.parent.parent) &&
node.parent.right.type === "ObjectExpression" &&
node.parent.right.properties.length === 0))
) {
return;
}
context.report({
node,
messageId: "unexpected",
data: { type: "object" },
});
},
ArrayPattern(node) {
if (node.elements.length === 0) {
context.report({
node,
messageId: "unexpected",
data: { type: "array" },
});
}
},
};
},
};

View File

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

View File

@@ -0,0 +1,110 @@
import * as util from "../core/util.js";
const error = () => {
const Sizable = {
string: { unit: "எழுத்துக்கள்", verb: "கொண்டிருக்க வேண்டும்" },
file: { unit: "பைட்டுகள்", verb: "கொண்டிருக்க வேண்டும்" },
array: { unit: "உறுப்புகள்", verb: "கொண்டிருக்க வேண்டும்" },
set: { unit: "உறுப்புகள்", verb: "கொண்டிருக்க வேண்டும்" },
};
function getSizing(origin) {
return Sizable[origin] ?? null;
}
const FormatDictionary = {
regex: "உள்ளீடு",
email: "மின்னஞ்சல் முகவரி",
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: "ISO தேதி நேரம்",
date: "ISO தேதி",
time: "ISO நேரம்",
duration: "ISO கால அளவு",
ipv4: "IPv4 முகவரி",
ipv6: "IPv6 முகவரி",
cidrv4: "IPv4 வரம்பு",
cidrv6: "IPv6 வரம்பு",
base64: "base64-encoded சரம்",
base64url: "base64url-encoded சரம்",
json_string: "JSON சரம்",
e164: "E.164 எண்",
jwt: "JWT",
template_literal: "input",
};
const TypeDictionary = {
nan: "NaN",
number: "எண்",
array: "அணி",
null: "வெறுமை",
};
return (issue) => {
switch (issue.code) {
case "invalid_type": {
const expected = TypeDictionary[issue.expected] ?? issue.expected;
const receivedType = util.parsedType(issue.input);
const received = TypeDictionary[receivedType] ?? receivedType;
if (/^[A-Z]/.test(issue.expected)) {
return `தவறான உள்ளீடு: எதிர்பார்க்கப்பட்டது instanceof ${issue.expected}, பெறப்பட்டது ${received}`;
}
return `தவறான உள்ளீடு: எதிர்பார்க்கப்பட்டது ${expected}, பெறப்பட்டது ${received}`;
}
case "invalid_value":
if (issue.values.length === 1)
return `தவறான உள்ளீடு: எதிர்பார்க்கப்பட்டது ${util.stringifyPrimitive(issue.values[0])}`;
return `தவறான விருப்பம்: எதிர்பார்க்கப்பட்டது ${util.joinValues(issue.values, "|")} இல் ஒன்று`;
case "too_big": {
const adj = issue.inclusive ? "<=" : "<";
const sizing = getSizing(issue.origin);
if (sizing) {
return `மிக பெரியது: எதிர்பார்க்கப்பட்டது ${issue.origin ?? "மதிப்பு"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "உறுப்புகள்"} ஆக இருக்க வேண்டும்`;
}
return `மிக பெரியது: எதிர்பார்க்கப்பட்டது ${issue.origin ?? "மதிப்பு"} ${adj}${issue.maximum.toString()} ஆக இருக்க வேண்டும்`;
}
case "too_small": {
const adj = issue.inclusive ? ">=" : ">";
const sizing = getSizing(issue.origin);
if (sizing) {
return `மிகச் சிறியது: எதிர்பார்க்கப்பட்டது ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit} ஆக இருக்க வேண்டும்`; //
}
return `மிகச் சிறியது: எதிர்பார்க்கப்பட்டது ${issue.origin} ${adj}${issue.minimum.toString()} ஆக இருக்க வேண்டும்`;
}
case "invalid_format": {
const _issue = issue;
if (_issue.format === "starts_with")
return `தவறான சரம்: "${_issue.prefix}" இல் தொடங்க வேண்டும்`;
if (_issue.format === "ends_with")
return `தவறான சரம்: "${_issue.suffix}" இல் முடிவடைய வேண்டும்`;
if (_issue.format === "includes")
return `தவறான சரம்: "${_issue.includes}" ஐ உள்ளடக்க வேண்டும்`;
if (_issue.format === "regex")
return `தவறான சரம்: ${_issue.pattern} முறைபாட்டுடன் பொருந்த வேண்டும்`;
return `தவறான ${FormatDictionary[_issue.format] ?? issue.format}`;
}
case "not_multiple_of":
return `தவறான எண்: ${issue.divisor} இன் பலமாக இருக்க வேண்டும்`;
case "unrecognized_keys":
return `அடையாளம் தெரியாத விசை${issue.keys.length > 1 ? "கள்" : ""}: ${util.joinValues(issue.keys, ", ")}`;
case "invalid_key":
return `${issue.origin} இல் தவறான விசை`;
case "invalid_union":
return "தவறான உள்ளீடு";
case "invalid_element":
return `${issue.origin} இல் தவறான மதிப்பு`;
default:
return `தவறான உள்ளீடு`;
}
};
};
export default function () {
return {
localeError: error(),
};
}

View File

@@ -0,0 +1,214 @@
const path = require('path');
const fs = require('fs');
const Keyv = require('keyv');
const { writeJSON, tryParse } = require('./utils');
const { del } = require('./del');
const cache = {
/**
* Load a cache identified by the given Id. If the element does not exists, then initialize an empty
* cache storage. If specified `cacheDir` will be used as the directory to persist the data to. If omitted
* then the cache module directory `./cache` will be used instead
*
* @method load
* @param docId {String} the id of the cache, would also be used as the name of the file cache
* @param [cacheDir] {String} directory for the cache entry
*/
load: function (docId, cacheDir) {
const me = this;
me.keyv = new Keyv();
me.__visited = {};
me.__persisted = {};
me._pathToFile = cacheDir ? path.resolve(cacheDir, docId) : path.resolve(__dirname, '../.cache/', docId);
if (fs.existsSync(me._pathToFile)) {
me._persisted = tryParse(me._pathToFile, {});
}
},
get _persisted() {
return this.__persisted;
},
set _persisted(value) {
this.__persisted = value;
},
get _visited() {
return this.__visited;
},
set _visited(value) {
this.__visited = value;
},
/**
* Load the cache from the provided file
* @method loadFile
* @param {String} pathToFile the path to the file containing the info for the cache
*/
loadFile: function (pathToFile) {
const me = this;
const dir = path.dirname(pathToFile);
const fName = path.basename(pathToFile);
me.load(fName, dir);
},
/**
* Returns the entire persisted object
* @method all
* @returns {*}
*/
all: function () {
return this._persisted;
},
keys: function () {
return Object.keys(this._persisted);
},
/**
* sets a key to a given value
* @method setKey
* @param key {string} the key to set
* @param value {object} the value of the key. Could be any object that can be serialized with JSON.stringify
*/
setKey: function (key, value) {
this._visited[key] = true;
this._persisted[key] = value;
},
/**
* remove a given key from the cache
* @method removeKey
* @param key {String} the key to remove from the object
*/
removeKey: function (key) {
delete this._visited[key]; // esfmt-ignore-line
delete this._persisted[key]; // esfmt-ignore-line
},
/**
* Return the value of the provided key
* @method getKey
* @param key {String} the name of the key to retrieve
* @returns {*} the value from the key
*/
getKey: function (key) {
this._visited[key] = true;
return this._persisted[key];
},
/**
* Remove keys that were not accessed/set since the
* last time the `prune` method was called.
* @method _prune
* @private
*/
_prune: function () {
const me = this;
const obj = {};
const keys = Object.keys(me._visited);
// no keys visited for either get or set value
if (keys.length === 0) {
return;
}
keys.forEach(function (key) {
obj[key] = me._persisted[key];
});
me._visited = {};
me._persisted = obj;
},
/**
* Save the state of the cache identified by the docId to disk
* as a JSON structure
* @param [noPrune=false] {Boolean} whether to remove from cache the non visited files
* @method save
*/
save: function (noPrune) {
const me = this;
!noPrune && me._prune();
writeJSON(me._pathToFile, me._persisted);
},
/**
* remove the file where the cache is persisted
* @method removeCacheFile
* @return {Boolean} true or false if the file was successfully deleted
*/
removeCacheFile: function () {
return del(this._pathToFile);
},
/**
* Destroy the file cache and cache content.
* @method destroy
*/
destroy: function () {
const me = this;
me._visited = {};
me._persisted = {};
me.removeCacheFile();
},
};
module.exports = {
/**
* Alias for create. Should be considered depreacted. Will be removed in next releases
*
* @method load
* @param docId {String} the id of the cache, would also be used as the name of the file cache
* @param [cacheDir] {String} directory for the cache entry
* @returns {cache} cache instance
*/
load: function (docId, cacheDir) {
return this.create(docId, cacheDir);
},
/**
* Load a cache identified by the given Id. If the element does not exists, then initialize an empty
* cache storage.
*
* @method create
* @param docId {String} the id of the cache, would also be used as the name of the file cache
* @param [cacheDir] {String} directory for the cache entry
* @returns {cache} cache instance
*/
create: function (docId, cacheDir) {
const obj = Object.create(cache);
obj.load(docId, cacheDir);
return obj;
},
createFromFile: function (filePath) {
const obj = Object.create(cache);
obj.loadFile(filePath);
return obj;
},
/**
* Clear the cache identified by the given id. Caches stored in a different cache directory can be deleted directly
*
* @method clearCache
* @param docId {String} the id of the cache, would also be used as the name of the file cache
* @param cacheDir {String} the directory where the cache file was written
* @returns {Boolean} true if the cache folder was deleted. False otherwise
*/
clearCacheById: function (docId, cacheDir) {
const filePath = cacheDir ? path.resolve(cacheDir, docId) : path.resolve(__dirname, '../.cache/', docId);
return del(filePath);
},
/**
* Remove all cache stored in the cache directory
* @method clearAll
* @returns {Boolean} true if the cache folder was deleted. False otherwise
*/
clearAll: function (cacheDir) {
const filePath = cacheDir ? path.resolve(cacheDir) : path.resolve(__dirname, '../.cache/');
return del(filePath);
},
};

View File

@@ -0,0 +1,134 @@
"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.default = default_1;
const util = __importStar(require("../core/util.cjs"));
const error = () => {
const Sizable = {
string: { unit: "文字", verb: "である" },
file: { unit: "バイト", verb: "である" },
array: { unit: "要素", verb: "である" },
set: { unit: "要素", verb: "である" },
};
function getSizing(origin) {
return Sizable[origin] ?? null;
}
const FormatDictionary = {
regex: "入力値",
email: "メールアドレス",
url: "URL",
emoji: "絵文字",
uuid: "UUID",
uuidv4: "UUIDv4",
uuidv6: "UUIDv6",
nanoid: "nanoid",
guid: "GUID",
cuid: "cuid",
cuid2: "cuid2",
ulid: "ULID",
xid: "XID",
ksuid: "KSUID",
datetime: "ISO日時",
date: "ISO日付",
time: "ISO時刻",
duration: "ISO期間",
ipv4: "IPv4アドレス",
ipv6: "IPv6アドレス",
cidrv4: "IPv4範囲",
cidrv6: "IPv6範囲",
base64: "base64エンコード文字列",
base64url: "base64urlエンコード文字列",
json_string: "JSON文字列",
e164: "E.164番号",
jwt: "JWT",
template_literal: "入力値",
};
const TypeDictionary = {
nan: "NaN",
number: "数値",
array: "配列",
};
return (issue) => {
switch (issue.code) {
case "invalid_type": {
const expected = TypeDictionary[issue.expected] ?? issue.expected;
const receivedType = util.parsedType(issue.input);
const received = TypeDictionary[receivedType] ?? receivedType;
if (/^[A-Z]/.test(issue.expected)) {
return `無効な入力: instanceof ${issue.expected}が期待されましたが、${received}が入力されました`;
}
return `無効な入力: ${expected}が期待されましたが、${received}が入力されました`;
}
case "invalid_value":
if (issue.values.length === 1)
return `無効な入力: ${util.stringifyPrimitive(issue.values[0])}が期待されました`;
return `無効な選択: ${util.joinValues(issue.values, "、")}のいずれかである必要があります`;
case "too_big": {
const adj = issue.inclusive ? "以下である" : "より小さい";
const sizing = getSizing(issue.origin);
if (sizing)
return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${sizing.unit ?? "要素"}${adj}必要があります`;
return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${adj}必要があります`;
}
case "too_small": {
const adj = issue.inclusive ? "以上である" : "より大きい";
const sizing = getSizing(issue.origin);
if (sizing)
return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${sizing.unit}${adj}必要があります`;
return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${adj}必要があります`;
}
case "invalid_format": {
const _issue = issue;
if (_issue.format === "starts_with")
return `無効な文字列: "${_issue.prefix}"で始まる必要があります`;
if (_issue.format === "ends_with")
return `無効な文字列: "${_issue.suffix}"で終わる必要があります`;
if (_issue.format === "includes")
return `無効な文字列: "${_issue.includes}"を含む必要があります`;
if (_issue.format === "regex")
return `無効な文字列: パターン${_issue.pattern}に一致する必要があります`;
return `無効な${FormatDictionary[_issue.format] ?? issue.format}`;
}
case "not_multiple_of":
return `無効な数値: ${issue.divisor}の倍数である必要があります`;
case "unrecognized_keys":
return `認識されていないキー${issue.keys.length > 1 ? "群" : ""}: ${util.joinValues(issue.keys, "、")}`;
case "invalid_key":
return `${issue.origin}内の無効なキー`;
case "invalid_union":
return "無効な入力";
case "invalid_element":
return `${issue.origin}内の無効な値`;
default:
return `無効な入力`;
}
};
};
function default_1() {
return {
localeError: error(),
};
}
module.exports = exports.default;

View File

@@ -0,0 +1,13 @@
export * from './CatchClauseDefinition';
export * from './ClassNameDefinition';
export * from './Definition';
export * from './DefinitionType';
export * from './FunctionNameDefinition';
export * from './ImplicitGlobalVariableDefinition';
export * from './ImportBindingDefinition';
export * from './ParameterDefinition';
export * from './TSEnumMemberDefinition';
export * from './TSEnumNameDefinition';
export * from './TSModuleNameDefinition';
export * from './TypeDefinition';
export * from './VariableDefinition';

View File

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

View File

@@ -0,0 +1,111 @@
/* -*- Mode: js; js-indent-level: 2; -*- */
/*
* Copyright 2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE or:
* http://opensource.org/licenses/BSD-3-Clause
*/
exports.GREATEST_LOWER_BOUND = 1;
exports.LEAST_UPPER_BOUND = 2;
/**
* Recursive implementation of binary search.
*
* @param aLow Indices here and lower do not contain the needle.
* @param aHigh Indices here and higher do not contain the needle.
* @param aNeedle The element being searched for.
* @param aHaystack The non-empty array being searched.
* @param aCompare Function which takes two elements and returns -1, 0, or 1.
* @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or
* 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the
* closest element that is smaller than or greater than the one we are
* searching for, respectively, if the exact element cannot be found.
*/
function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) {
// This function terminates when one of the following is true:
//
// 1. We find the exact element we are looking for.
//
// 2. We did not find the exact element, but we can return the index of
// the next-closest element.
//
// 3. We did not find the exact element, and there is no next-closest
// element than the one we are searching for, so we return -1.
var mid = Math.floor((aHigh - aLow) / 2) + aLow;
var cmp = aCompare(aNeedle, aHaystack[mid], true);
if (cmp === 0) {
// Found the element we are looking for.
return mid;
}
else if (cmp > 0) {
// Our needle is greater than aHaystack[mid].
if (aHigh - mid > 1) {
// The element is in the upper half.
return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias);
}
// The exact needle element was not found in this haystack. Determine if
// we are in termination case (3) or (2) and return the appropriate thing.
if (aBias == exports.LEAST_UPPER_BOUND) {
return aHigh < aHaystack.length ? aHigh : -1;
} else {
return mid;
}
}
else {
// Our needle is less than aHaystack[mid].
if (mid - aLow > 1) {
// The element is in the lower half.
return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias);
}
// we are in termination case (3) or (2) and return the appropriate thing.
if (aBias == exports.LEAST_UPPER_BOUND) {
return mid;
} else {
return aLow < 0 ? -1 : aLow;
}
}
}
/**
* This is an implementation of binary search which will always try and return
* the index of the closest element if there is no exact hit. This is because
* mappings between original and generated line/col pairs are single points,
* and there is an implicit region between each of them, so a miss just means
* that you aren't on the very start of a region.
*
* @param aNeedle The element you are looking for.
* @param aHaystack The array that is being searched.
* @param aCompare A function which takes the needle and an element in the
* array and returns -1, 0, or 1 depending on whether the needle is less
* than, equal to, or greater than the element, respectively.
* @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or
* 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the
* closest element that is smaller than or greater than the one we are
* searching for, respectively, if the exact element cannot be found.
* Defaults to 'binarySearch.GREATEST_LOWER_BOUND'.
*/
exports.search = function search(aNeedle, aHaystack, aCompare, aBias) {
if (aHaystack.length === 0) {
return -1;
}
var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack,
aCompare, aBias || exports.GREATEST_LOWER_BOUND);
if (index < 0) {
return -1;
}
// We have found either the exact element, or the next-closest element than
// the one we are searching for. However, there may be more than one such
// element. Make sure we always return the smallest of these.
while (index - 1 >= 0) {
if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) {
break;
}
--index;
}
return index;
};

View File

@@ -0,0 +1,241 @@
'use strict'
const test = require('node:test')
const assert = require('node:assert')
const os = require('node:os')
const tspl = require('@matteo.collina/tspl')
const { sink, once } = require('./helper')
const pino = require('../')
const { pid } = process
const hostname = os.hostname()
const level = 50
const name = 'error'
test('mixin object is included', async () => {
let n = 0
const stream = sink()
const instance = pino({
mixin () {
return { hello: ++n }
}
}, stream)
instance.level = name
instance[name]('test')
const result = await once(stream, 'data')
assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
assert.deepEqual(result, {
pid,
hostname,
level,
msg: 'test',
hello: 1
})
})
test('mixin object is new every time', async (t) => {
const plan = tspl(t, { plan: 6 })
let n = 0
const stream = sink()
const instance = pino({
mixin () {
return { hello: n }
}
}, stream)
instance.level = name
while (++n < 4) {
const msg = `test #${n}`
stream.pause()
instance[name](msg)
stream.resume()
const result = await once(stream, 'data')
plan.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
plan.deepEqual(result, {
pid,
hostname,
level,
msg,
hello: n
})
}
await plan
})
test('mixin object is not called if below log level', async () => {
const stream = sink()
const instance = pino({
mixin () {
throw Error('should not call mixin function')
}
}, stream)
instance.level = 'error'
instance.info('test')
})
test('mixin object + logged object', async () => {
const stream = sink()
const instance = pino({
mixin () {
return { foo: 1, bar: 2 }
}
}, stream)
instance.level = name
instance[name]({ bar: 3, baz: 4 })
const result = await once(stream, 'data')
assert.ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
delete result.time
assert.deepEqual(result, {
pid,
hostname,
level,
foo: 1,
bar: 3,
baz: 4
})
})
test('mixin not a function', async () => {
const stream = sink()
assert.throws(function () {
pino({ mixin: 'not a function' }, stream)
})
})
test('mixin can use context', async (t) => {
const plan = tspl(t, { plan: 3 })
const stream = sink()
const instance = pino({
mixin (context) {
plan.ok(context !== null, 'context should be defined')
plan.ok(context !== undefined, 'context should be defined')
plan.deepEqual(context, {
message: '123',
stack: 'stack'
})
return Object.assign({
error: context.message,
stack: context.stack
})
}
}, stream)
instance.level = name
instance[name]({
message: '123',
stack: 'stack'
}, 'test')
await plan
})
test('mixin works without context', async (t) => {
const plan = tspl(t, { plan: 3 })
const stream = sink()
const instance = pino({
mixin (context) {
plan.ok(context !== null, 'context is still defined w/o passing mergeObject')
plan.ok(context !== undefined, 'context is still defined w/o passing mergeObject')
plan.deepEqual(context, {})
return {
something: true
}
}
}, stream)
instance.level = name
instance[name]('test')
await plan
})
test('mixin can use level number', async (t) => {
const plan = tspl(t, { plan: 3 })
const stream = sink()
const instance = pino({
mixin (context, num) {
plan.ok(num !== null, 'level should be defined')
plan.ok(num !== undefined, 'level should be defined')
plan.deepEqual(num, level)
return Object.assign({
error: context.message,
stack: context.stack
})
}
}, stream)
instance.level = name
instance[name]({
message: '123',
stack: 'stack'
}, 'test')
await plan
})
test('mixin receives logger as third parameter', async (t) => {
const plan = tspl(t, { plan: 3 })
const stream = sink()
const instance = pino({
mixin (context, num, logger) {
plan.ok(logger !== null, 'logger should be defined')
plan.ok(logger !== undefined, 'logger should be defined')
plan.deepEqual(logger, instance)
return { ...context, num }
}
}, stream)
instance.level = name
instance[name]({
message: '123'
}, 'test')
await plan
})
test('mixin receives child logger', async (t) => {
const plan = tspl(t, { plan: 3 })
const stream = sink()
let child = null
const instance = pino({
mixin (context, num, logger) {
plan.ok(logger !== null, 'logger should be defined')
plan.ok(logger !== undefined, 'logger should be defined')
plan.deepEqual(logger.expected, child.expected)
return { ...context, num }
}
}, stream)
instance.level = name
instance.expected = false
child = instance.child({})
child.expected = true
child[name]({
message: '123'
}, 'test')
await plan
})
test('mixin receives logger even if child exists', async (t) => {
const plan = tspl(t, { plan: 3 })
const stream = sink()
let child = null
const instance = pino({
mixin (context, num, logger) {
plan.ok(logger !== null, 'logger should be defined')
plan.ok(logger !== undefined, 'logger should be defined')
plan.deepEqual(logger.expected, instance.expected)
return { ...context, num }
}
}, stream)
instance.level = name
instance.expected = false
child = instance.child({})
child.expected = true
instance[name]({
message: '123'
}, 'test')
await plan
})

View File

@@ -0,0 +1,21 @@
"use strict";
module.exports = function (it) {
const { pattern } = it;
return `
You are linting "${pattern}", but all of the files matching the glob pattern "${pattern}" are ignored.
If you don't want to lint these files, remove the pattern "${pattern}" from the list of arguments passed to ESLint.
If you do want to lint these files, explicitly list one or more of the files from this glob that you'd like to lint to see more details about why they are ignored.
* If the file is ignored because of a matching ignore pattern, check global ignores in your config file.
https://eslint.org/docs/latest/use/configure/ignore
* If the file is ignored because no matching configuration was supplied, check file patterns in your config file.
https://eslint.org/docs/latest/use/configure/configuration-files#specify-files-with-arbitrary-extensions
* If the file is ignored because it is located outside of the base path, change the location of your config file to be in a parent directory.
`.trimStart();
};

View File

@@ -0,0 +1,17 @@
import type * as ts from 'typescript';
import type { ParserServices, TSESTreeOptions } from './parser-options';
import type { TSESTree } from './ts-estree';
export declare function clearProgramCache(): void;
export declare function clearDefaultProjectMatchedFiles(): void;
export type AST<T extends TSESTreeOptions> = (T['comment'] extends true ? {
comments: TSESTree.Comment[];
} : {}) & (T['tokens'] extends true ? {
tokens: TSESTree.Token[];
} : {}) & TSESTree.Program;
export interface ParseAndGenerateServicesResult<T extends TSESTreeOptions> {
ast: AST<T>;
services: ParserServices;
}
export declare function parse<T extends TSESTreeOptions = TSESTreeOptions>(code: string, options?: T): AST<T>;
export declare function clearParseAndGenerateServicesCalls(): void;
export declare function parseAndGenerateServices<T extends TSESTreeOptions = TSESTreeOptions>(code: string | ts.SourceFile, tsestreeOptions: T): ParseAndGenerateServicesResult<T>;

View File

@@ -0,0 +1,5 @@
import type { TSESTree } from '@typescript-eslint/utils';
/**
* Recursively checks whether a given reference has a type query declaration among its parents
*/
export declare function referenceContainsTypeQuery(node: TSESTree.Node): boolean;

View File

@@ -0,0 +1,2 @@
export declare var TokenFlags: any;
//# sourceMappingURL=tokenFlags.d.ts.map

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlockScope = void 0;
const ScopeBase_1 = require("./ScopeBase");
const ScopeType_1 = require("./ScopeType");
class BlockScope extends ScopeBase_1.ScopeBase {
constructor(scopeManager, upperScope, block) {
super(scopeManager, ScopeType_1.ScopeType.block, upperScope, block, false);
}
}
exports.BlockScope = BlockScope;

View File

@@ -0,0 +1,2 @@
export declare const crypto: any;
//# sourceMappingURL=cryptoNode.d.ts.map

View File

@@ -0,0 +1,225 @@
declare module "node:tty" {
import * as net from "node:net";
/**
* The `tty.isatty()` method returns `true` if the given `fd` is associated with
* a TTY and `false` if it is not, including whenever `fd` is not a non-negative
* integer.
* @since v0.5.8
* @param fd A numeric file descriptor
*/
function isatty(fd: number): boolean;
/**
* Represents the readable side of a TTY. In normal circumstances `process.stdin` will be the only `tty.ReadStream` instance in a Node.js
* process and there should be no reason to create additional instances.
* @since v0.5.8
*/
class ReadStream extends net.Socket {
constructor(fd: number, options?: net.SocketConstructorOpts);
/**
* A `boolean` that is `true` if the TTY is currently configured to operate as a
* raw device.
*
* This flag is always `false` when a process starts, even if the terminal is
* operating in raw mode. Its value will change with subsequent calls to `setRawMode`.
* @since v0.7.7
*/
isRaw: boolean;
/**
* Allows configuration of `tty.ReadStream` so that it operates as a raw device.
*
* When in raw mode, input is always available character-by-character, not
* including modifiers. Additionally, all special processing of characters by the
* terminal is disabled, including echoing input
* characters. Ctrl+C will no longer cause a `SIGINT` when
* in this mode.
* @since v0.7.7
* @param mode If `true`, configures the `tty.ReadStream` to operate as a raw device. If `false`, configures the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw`
* property will be set to the resulting mode.
* @return The read stream instance.
*/
setRawMode(mode: boolean): this;
/**
* A `boolean` that is always `true` for `tty.ReadStream` instances.
* @since v0.5.8
*/
isTTY: boolean;
}
/**
* -1 - to the left from cursor
* 0 - the entire line
* 1 - to the right from cursor
*/
type Direction = -1 | 0 | 1;
interface WriteStreamEventMap extends net.SocketEventMap {
"resize": [];
}
/**
* Represents the writable side of a TTY. In normal circumstances, `process.stdout` and `process.stderr` will be the only`tty.WriteStream` instances created for a Node.js process and there
* should be no reason to create additional instances.
* @since v0.5.8
*/
class WriteStream extends net.Socket {
constructor(fd: number);
/**
* `writeStream.clearLine()` clears the current line of this `WriteStream` in a
* direction identified by `dir`.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
clearLine(dir: Direction, callback?: () => void): boolean;
/**
* `writeStream.clearScreenDown()` clears this `WriteStream` from the current
* cursor down.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
clearScreenDown(callback?: () => void): boolean;
/**
* `writeStream.cursorTo()` moves this `WriteStream`'s cursor to the specified
* position.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
cursorTo(x: number, y?: number, callback?: () => void): boolean;
cursorTo(x: number, callback: () => void): boolean;
/**
* `writeStream.moveCursor()` moves this `WriteStream`'s cursor _relative_ to its
* current position.
* @since v0.7.7
* @param callback Invoked once the operation completes.
* @return `false` if the stream wishes for the calling code to wait for the `'drain'` event to be emitted before continuing to write additional data; otherwise `true`.
*/
moveCursor(dx: number, dy: number, callback?: () => void): boolean;
/**
* Returns:
*
* * `1` for 2,
* * `4` for 16,
* * `8` for 256,
* * `24` for 16,777,216 colors supported.
*
* Use this to determine what colors the terminal supports. Due to the nature of
* colors in terminals it is possible to either have false positives or false
* negatives. It depends on process information and the environment variables that
* may lie about what terminal is used.
* It is possible to pass in an `env` object to simulate the usage of a specific
* terminal. This can be useful to check how specific environment settings behave.
*
* To enforce a specific color support, use one of the below environment settings.
*
* * 2 colors: `FORCE_COLOR = 0` (Disables colors)
* * 16 colors: `FORCE_COLOR = 1`
* * 256 colors: `FORCE_COLOR = 2`
* * 16,777,216 colors: `FORCE_COLOR = 3`
*
* Disabling color support is also possible by using the `NO_COLOR` and `NODE_DISABLE_COLORS` environment variables.
* @since v9.9.0
* @param [env=process.env] An object containing the environment variables to check. This enables simulating the usage of a specific terminal.
*/
getColorDepth(env?: object): number;
/**
* Returns `true` if the `writeStream` supports at least as many colors as provided
* in `count`. Minimum support is 2 (black and white).
*
* This has the same false positives and negatives as described in `writeStream.getColorDepth()`.
*
* ```js
* process.stdout.hasColors();
* // Returns true or false depending on if `stdout` supports at least 16 colors.
* process.stdout.hasColors(256);
* // Returns true or false depending on if `stdout` supports at least 256 colors.
* process.stdout.hasColors({ TMUX: '1' });
* // Returns true.
* process.stdout.hasColors(2 ** 24, { TMUX: '1' });
* // Returns false (the environment setting pretends to support 2 ** 8 colors).
* ```
* @since v11.13.0, v10.16.0
* @param [count=16] The number of colors that are requested (minimum 2).
* @param [env=process.env] An object containing the environment variables to check. This enables simulating the usage of a specific terminal.
*/
hasColors(count?: number): boolean;
hasColors(env?: object): boolean;
hasColors(count: number, env?: object): boolean;
/**
* `writeStream.getWindowSize()` returns the size of the TTY
* corresponding to this `WriteStream`. The array is of the type `[numColumns, numRows]` where `numColumns` and `numRows` represent the number
* of columns and rows in the corresponding TTY.
* @since v0.7.7
*/
getWindowSize(): [number, number];
/**
* A `number` specifying the number of columns the TTY currently has. This property
* is updated whenever the `'resize'` event is emitted.
* @since v0.7.7
*/
columns: number;
/**
* A `number` specifying the number of rows the TTY currently has. This property
* is updated whenever the `'resize'` event is emitted.
* @since v0.7.7
*/
rows: number;
/**
* A `boolean` that is always `true`.
* @since v0.5.8
*/
isTTY: boolean;
// #region InternalEventEmitter
addListener<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
addListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
emit<E extends keyof WriteStreamEventMap>(eventName: E, ...args: WriteStreamEventMap[E]): boolean;
emit(eventName: string | symbol, ...args: any[]): boolean;
listenerCount<E extends keyof WriteStreamEventMap>(
eventName: E,
listener?: (...args: WriteStreamEventMap[E]) => void,
): number;
listenerCount(eventName: string | symbol, listener?: (...args: any[]) => void): number;
listeners<E extends keyof WriteStreamEventMap>(eventName: E): ((...args: WriteStreamEventMap[E]) => void)[];
listeners(eventName: string | symbol): ((...args: any[]) => void)[];
off<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
off(eventName: string | symbol, listener: (...args: any[]) => void): this;
on<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
on(eventName: string | symbol, listener: (...args: any[]) => void): this;
once<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
once(eventName: string | symbol, listener: (...args: any[]) => void): this;
prependListener<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
prependListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
prependOnceListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
rawListeners<E extends keyof WriteStreamEventMap>(eventName: E): ((...args: WriteStreamEventMap[E]) => void)[];
rawListeners(eventName: string | symbol): ((...args: any[]) => void)[];
// eslint-disable-next-line @definitelytyped/no-unnecessary-generics
removeAllListeners<E extends keyof WriteStreamEventMap>(eventName?: E): this;
removeAllListeners(eventName?: string | symbol): this;
removeListener<E extends keyof WriteStreamEventMap>(
eventName: E,
listener: (...args: WriteStreamEventMap[E]) => void,
): this;
removeListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
// #endregion
}
}
declare module "tty" {
export * from "node:tty";
}

View File

@@ -0,0 +1,508 @@
/**
* Pure JS replacement for @typescript/libsyncrpc.
*
* Spawns a child process and communicates with it synchronously over
* stdin/stdout pipes using the same MessagePack-based tuple protocol:
* [MessageType (u8), method (bin), payload (bin)]
*
* Synchronous I/O is achieved by calling fs.readSync / fs.writeSync
* directly on the pipe file descriptors obtained from the spawned
* ChildProcess.
*/
import { spawn, } from "node:child_process";
import { closeSync, openSync, readSync, writeSync, } from "node:fs";
import { binHeaderSize, MSGPACK_BIN16, MSGPACK_BIN32, MSGPACK_BIN8, MSGPACK_FIXARRAY3, MSGPACK_UINT8, writeBinHeader, } from "./node/msgpack.js";
// ── MessageType constants ────────────────────────────────────────────
// Sent by channel (parent → child)
const MSG_REQUEST = 1;
const MSG_CALL_RESPONSE = 2;
const MSG_CALL_ERROR = 3;
// Sent by child (child → parent)
const MSG_RESPONSE = 4;
const MSG_ERROR = 5;
const MSG_CALL = 6;
// Pre-allocated buffer used by Atomics.wait for tiny sleeps when a
// non-blocking fd returns EAGAIN.
const sleepBuf = new Int32Array(new SharedArrayBuffer(4));
// Shared empty buffer avoids allocating Buffer.alloc(0) on every
// zero-length bin field.
const EMPTY_BUF = Buffer.alloc(0);
// ── Global cleanup tracking ─────────────────────────────────────────
// Track all live child processes so they can be killed on process exit.
// This mimics the auto-cleanup behavior of the native libsyncrpc module,
// whose Rust/C++ destructors would kill children automatically.
const liveChildren = new Set();
process.on("exit", () => {
for (const child of liveChildren) {
try {
child.kill();
}
catch {
// swallow process may already be dead
}
}
liveChildren.clear();
});
/**
* SyncRpcChannel drop-in replacement for the native libsyncrpc class.
*
* API surface intentionally matches the original:
* - constructor(exe, args)
* - requestSync(method, payload): string
* - requestBinarySync(method, payload): Uint8Array
* - registerCallback(name, cb)
* - close()
*
* The protocol is unversioned; both sides (this JS channel and the Go
* child process) must be built from the same tree.
*
* This class is **not** thread-safe. All calls must originate from a
* single thread — do not share an instance across worker threads.
*/
export class SyncRpcChannel {
child;
readFd;
writeFd;
pipeFd;
callbacks = new Map();
methodBufCache = new Map();
// When true, the payload byte lengths of each request/response are recorded
// and exposed via the `last*` fields below. These count only the JSON/binary
// payload bytes, not the MessagePack tuple framing (message type, method
// name, and length headers).
collectTiming;
// Per-request payload byte measurements for the most recently completed
// request. Only meaningful when `collectTiming` is true. Callers read these
// immediately after a request returns (the channel is strictly serial).
lastBytesSent = 0;
lastBytesReceived = 0;
_msgType = 0;
_msgName = EMPTY_BUF;
_msgPayload = EMPTY_BUF;
headerBuf = Buffer.allocUnsafe(4);
// Read-ahead buffer reduces readSync syscalls by buffering data from the pipe.
readBuf = Buffer.allocUnsafe(65536);
readBufPos = 0;
readBufLen = 0;
// Write buffer assembles entire tuples for a single writeSync.
writeBuf = Buffer.allocUnsafe(65536);
constructor(exe, args, collectTiming = false) {
this.collectTiming = collectTiming;
const isWindows = process.platform === "win32";
if (isWindows) {
// On Windows, libuv pipe handles don't expose POSIX fds, so
// readSync/writeSync can't be used on stdio pipes. Instead,
// we create a Windows named pipe path, pass it to the child
// via --pipe, and open it with fs.openSync which returns a
// real C-runtime fd backed by a proper HANDLE.
const pipePath = `\\\\.\\pipe\\tsgo-sync-${process.pid}-${Date.now()}`;
this.child = spawn(exe, [...args, "--pipe", pipePath], {
stdio: ["ignore", "ignore", "inherit"],
});
// Retry openSync until the child creates the named pipe.
let fd;
for (let i = 0; i < 500; i++) {
try {
fd = openSync(pipePath, "r+");
break;
}
catch {
if (this.child.exitCode !== null) {
throw new Error(`Child process exited with code ${this.child.exitCode} before pipe was ready`);
}
Atomics.wait(sleepBuf, 0, 0, 10);
}
}
if (fd === undefined) {
this.child.kill();
throw new Error("SyncRpcChannel: timed out connecting to named pipe");
}
this.readFd = fd;
this.writeFd = fd;
this.pipeFd = fd;
}
else {
// POSIX: use stdio pipe file descriptors directly.
this.child = spawn(exe, args, {
stdio: ["pipe", "pipe", "inherit"],
});
const stdout = this.child.stdout;
const stdin = this.child.stdin;
this.readFd = stdout._handle.fd;
this.writeFd = stdin._handle.fd;
if (typeof this.readFd !== "number" || this.readFd < 0 || typeof this.writeFd !== "number" || this.writeFd < 0) {
stdout.destroy();
stdin.destroy();
this.child.kill();
throw new Error("SyncRpcChannel: could not obtain pipe file descriptors.");
}
// Set the pipe handles to blocking mode. Under node --test's
// process isolation, pipes are created in non-blocking mode
// (for the IPC channel). This causes readSync/writeSync to get
// EAGAIN, requiring costly 1ms sleeps per retry. Setting
// blocking mode ensures readSync blocks properly until data
// arrives, matching the behavior of the native libsyncrpc.
stdout._handle.setBlocking?.(true);
stdin._handle.setBlocking?.(true);
// Prevent Node's event-loop from reading stdout or keeping the
// process alive we will use fs.readSync exclusively.
stdout.pause();
stdout.unref();
stdin.unref();
}
// Track for auto-cleanup on process exit.
liveChildren.add(this.child);
this.child.unref();
}
// ── Public API ──────────────────────────────────────────────────
/**
* Send a request and synchronously wait for the response (string).
* Handles Call (callback) messages from the child inline.
*/
requestSync(method, payload) {
this.ensureOpen();
const result = this.requestBytesSync(method, payload);
return result.toString("utf-8");
}
/**
* Send a request and synchronously wait for the response (binary).
* Handles Call (callback) messages from the child inline.
*/
requestBinarySync(method, payload) {
this.ensureOpen();
return this.requestBytesSync(method, payload);
}
/** Register a string→string callback that the child may invoke. */
registerCallback(name, callback) {
this.callbacks.set(name, callback);
}
/** Kill the child process and release resources. */
close() {
try {
liveChildren.delete(this.child);
if (this.pipeFd !== undefined) {
closeSync(this.pipeFd);
this.pipeFd = undefined;
}
// Destroy the stdio streams so that their pipe handles are closed
// and no longer prevent the event loop from draining.
this.child.stdout?.destroy();
this.child.stdin?.destroy();
this.child.kill();
this.readFd = -1;
this.writeFd = -1;
}
catch {
// swallow process may already be dead
}
}
// ── Core request loop ───────────────────────────────────────────
ensureOpen() {
if (this.readFd < 0) {
throw new Error("SyncRpcChannel is closed");
}
}
getMethodBuf(method) {
let buf = this.methodBufCache.get(method);
if (buf === undefined) {
buf = Buffer.from(method, "utf-8");
this.methodBufCache.set(method, buf);
}
return buf;
}
requestBytesSync(method, payload) {
const methodBuf = this.getMethodBuf(method);
if (this.collectTiming) {
this.lastBytesSent = typeof payload === "string"
? Buffer.byteLength(payload, "utf-8")
: payload.length;
this.lastBytesReceived = 0;
}
this.writeTuple(MSG_REQUEST, methodBuf, payload);
for (;;) {
this.readTuple();
switch (this._msgType) {
case MSG_RESPONSE: {
// Compare raw bytes instead of decoding to string.
if (!methodBuf.equals(this._msgName)) {
throw new Error(`name mismatch for response: expected \`${method}\`, got \`${this._msgName.toString("utf-8")}\``);
}
if (this.collectTiming) {
this.lastBytesReceived = this._msgPayload.length;
}
return this._msgPayload;
}
case MSG_ERROR: {
if (methodBuf.equals(this._msgName)) {
throw new Error(this._msgPayload.toString("utf-8"));
}
throw new Error(`name mismatch for response: expected \`${method}\`, got \`${this._msgName.toString("utf-8")}\``);
}
case MSG_CALL: {
this.handleCall(this._msgName.toString("utf-8"), this._msgPayload);
break;
}
default:
throw new Error(`Invalid message type from child: ${this._msgType}`);
}
}
}
// ── Callback handling ───────────────────────────────────────────
/**
* Handle an incoming MSG_CALL from the child process.
*
* After sending the error response back to the child, this method
* intentionally re-throws to abort the caller's request loop.
* A failed callback is treated as unrecoverable to match the
* behavior of the native libsyncrpc addon.
*/
handleCall(name, payload) {
const cb = this.callbacks.get(name);
if (!cb) {
const errMsg = `unknown callback: \`${name}\`. Please make sure to register it on the JavaScript side before invoking it.`;
this.writeTuple(MSG_CALL_ERROR, Buffer.from(name, "utf-8"), Buffer.from(errMsg, "utf-8"));
throw new Error(`no callback named \`${name}\` found`);
}
try {
const result = cb(name, payload.toString("utf-8"));
this.writeTuple(MSG_CALL_RESPONSE, Buffer.from(name, "utf-8"), Buffer.from(result, "utf-8"));
}
catch (e) {
const errMsg = String(e instanceof Error ? e.message : e).trim();
this.writeTuple(MSG_CALL_ERROR, Buffer.from(name, "utf-8"), Buffer.from(errMsg, "utf-8"));
throw new Error(`Error calling callback \`${name}\`: ${errMsg}`);
}
}
// ── MessagePack tuple write ─────────────────────────────────────
/**
* Write a complete [type, name, payload] tuple in as few writeSync
* calls as possible. For messages that fit in the pre-allocated
* write buffer (64 KB), everything is assembled and sent in a single
* syscall. Larger messages use two syscalls: one for the header
* portion and one for the payload data.
*/
writeTuple(type, name, payload) {
const nameLen = name.length;
const payloadIsString = typeof payload === "string";
const payloadLen = payloadIsString ? Buffer.byteLength(payload, "utf-8") : payload.length;
const nameHdrSize = binHeaderSize(nameLen);
const payloadHdrSize = binHeaderSize(payloadLen);
const headerSize = 2 + nameHdrSize + nameLen + payloadHdrSize;
const totalSize = headerSize + payloadLen;
if (totalSize <= this.writeBuf.length) {
// Small message: assemble into write buffer, one syscall
let off = 0;
this.writeBuf[off++] = MSGPACK_FIXARRAY3;
this.writeBuf[off++] = type;
off = writeBinHeader(this.writeBuf, off, nameLen);
name.copy(this.writeBuf, off);
off += nameLen;
off = writeBinHeader(this.writeBuf, off, payloadLen);
if (payloadLen > 0) {
if (payloadIsString) {
// Encode string directly into write buffer — avoids
// Buffer.from(string, 'utf-8') allocation entirely.
this.writeBuf.write(payload, off, payloadLen, "utf-8");
}
else if (payload instanceof Buffer) {
payload.copy(this.writeBuf, off);
}
else {
this.writeBuf.set(payload, off);
}
}
this.writeAllBuf(this.writeBuf, totalSize);
}
else {
// Large message: header + name in one call, payload in another
let off = 0;
this.writeBuf[off++] = MSGPACK_FIXARRAY3;
this.writeBuf[off++] = type;
off = writeBinHeader(this.writeBuf, off, nameLen);
name.copy(this.writeBuf, off);
off += nameLen;
off = writeBinHeader(this.writeBuf, off, payloadLen);
this.writeAllBuf(this.writeBuf, off);
if (payloadLen > 0) {
if (payloadIsString) {
// Large string: must allocate (can't stream-encode
// across multiple writeSync calls).
this.writeAllBuf(Buffer.from(payload, "utf-8"));
}
else {
this.writeAllBuf(payload);
}
}
}
}
// ── MessagePack tuple read ──────────────────────────────────────
/**
* Read a [type, name, payload] tuple into instance fields
* (_msgType, _msgName, _msgPayload) to avoid allocating a
* short-lived 3-element array on every call.
*/
readTuple() {
// Fixed 3-element array marker
const marker = this.readByte();
if (marker !== MSGPACK_FIXARRAY3) {
throw new Error(`Expected fixed 3-element array (0x93), received: 0x${marker.toString(16)}`);
}
// Message type positive fixint or uint8
const tb = this.readByte();
if (tb <= 0x7f) {
this._msgType = tb;
}
else if (tb === MSGPACK_UINT8) {
this._msgType = this.readByte();
}
else {
throw new Error(`Expected positive fixint or uint8 marker, received: 0x${tb.toString(16)}`);
}
this._msgName = this.readBin();
this._msgPayload = this.readBin();
}
/**
* Read a MessagePack bin field.
*/
readBin() {
const marker = this.readByte();
let size;
switch (marker) {
case MSGPACK_BIN8:
size = this.readByte();
break;
case MSGPACK_BIN16:
this.readExactInto(this.headerBuf, 2);
size = (this.headerBuf[0] << 8) | this.headerBuf[1];
break;
case MSGPACK_BIN32:
this.readExactInto(this.headerBuf, 4);
size = this.headerBuf.readUInt32BE(0);
break;
default:
throw new Error(`Expected binary data (0xc4-0xc6), received: 0x${marker.toString(16)}`);
}
if (size === 0)
return EMPTY_BUF;
return this.readExact(size);
}
// ── Low-level synchronous I/O ───────────────────────────────────
/** Build an EOF error with the child's exit code/signal if available. */
eofError() {
const code = this.child.exitCode;
const signal = this.child.signalCode;
const detail = signal ? `killed by signal ${signal}` : code !== null ? `exited with code ${code}` : "unknown reason";
return new Error(`Unexpected EOF while reading from child process (${detail})`);
}
/** Read a single byte from the buffered read-ahead. */
readByte() {
if (this.readBufPos >= this.readBufLen) {
this.fillReadBuffer();
}
return this.readBuf[this.readBufPos++];
}
readExact(length) {
// Use allocUnsafeSlow (not allocUnsafe) so the buffer has its own
// backing ArrayBuffer at byteOffset 0. This is critical because
// callers such as RemoteSourceFile create DataView/Uint8Array over
// buffer.buffer with absolute offsets. Buffer.allocUnsafe returns
// slices of a shared pool whose byteOffset is non-zero, corrupting
// those downstream views.
//
// allocUnsafeSlow (vs alloc) skips zero-fill, which matters for
// large transfers — e.g. checker.ts at ~57 MB saves ~5 ms of
// unnecessary memset. The buffer is immediately filled by
// readExactInto so uninitialized memory is never exposed.
const buf = Buffer.allocUnsafeSlow(length);
this.readExactInto(buf, length);
return buf;
}
/**
* Fill the internal read-ahead buffer from the pipe fd.
* Retries on EAGAIN for non-blocking mode compatibility.
*/
fillReadBuffer() {
this.readBufPos = 0;
this.readBufLen = 0;
for (;;) {
try {
const n = readSync(this.readFd, this.readBuf, 0, this.readBuf.length, null);
if (n === 0) {
throw this.eofError();
}
this.readBufLen = n;
return;
}
catch (e) {
if (e instanceof Error && ("code" in e) && (e.code === "EAGAIN" || e.code === "EWOULDBLOCK")) {
Atomics.wait(sleepBuf, 0, 0, 1);
continue;
}
throw e;
}
}
}
/**
* Synchronously read exactly `length` bytes into `buffer`.
* Serves from the internal read-ahead buffer first; for large reads
* that exceed the buffer size, reads directly from the fd to avoid
* an extra copy.
*/
readExactInto(buffer, length) {
let pos = 0;
while (pos < length) {
const avail = this.readBufLen - this.readBufPos;
if (avail > 0) {
// Serve from read-ahead buffer
const toCopy = Math.min(avail, length - pos);
this.readBuf.copy(buffer, pos, this.readBufPos, this.readBufPos + toCopy);
this.readBufPos += toCopy;
pos += toCopy;
}
else if (length - pos >= this.readBuf.length) {
// Remaining data is larger than read buffer; read directly
// into the target to avoid unnecessary copying.
try {
const n = readSync(this.readFd, buffer, pos, length - pos, null);
if (n === 0) {
throw this.eofError();
}
pos += n;
}
catch (e) {
if (e instanceof Error && ("code" in e) && (e.code === "EAGAIN" || e.code === "EWOULDBLOCK")) {
Atomics.wait(sleepBuf, 0, 0, 1);
continue;
}
throw e;
}
}
else {
// Refill the read-ahead buffer
this.fillReadBuffer();
}
}
}
/**
* Synchronously write all bytes from `data` (up to `length`).
* Retries on EAGAIN.
*/
writeAllBuf(data, length) {
const total = length ?? data.length;
let pos = 0;
while (pos < total) {
try {
const n = writeSync(this.writeFd, data, pos, total - pos);
pos += n;
}
catch (e) {
if (e instanceof Error && ("code" in e) && (e.code === "EAGAIN" || e.code === "EWOULDBLOCK")) {
Atomics.wait(sleepBuf, 0, 0, 1);
continue;
}
throw e;
}
}
}
}
//# sourceMappingURL=syncChannel.js.map

View File

@@ -0,0 +1,124 @@
/**
* @fileoverview Rule to disallow calls to the `Object` constructor without an argument
* @author Francesco Trotta
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const {
getVariableByName,
isArrowToken,
isStartOfExpressionStatement,
needsPrecedingSemicolon,
} = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description:
"Disallow calls to the `Object` constructor without an argument",
recommended: false,
url: "https://eslint.org/docs/latest/rules/no-object-constructor",
},
hasSuggestions: true,
schema: [],
messages: {
preferLiteral: "The object literal notation {} is preferable.",
useLiteral: "Replace with '{{replacement}}'.",
useLiteralAfterSemicolon:
"Replace with '{{replacement}}', add preceding semicolon.",
},
},
create(context) {
const sourceCode = context.sourceCode;
/**
* Determines whether or not an object literal that replaces a specified node needs to be enclosed in parentheses.
* @param {ASTNode} node The node to be replaced.
* @returns {boolean} Whether or not parentheses around the object literal are required.
*/
function needsParentheses(node) {
if (isStartOfExpressionStatement(node)) {
return true;
}
const prevToken = sourceCode.getTokenBefore(node);
if (prevToken && isArrowToken(prevToken)) {
return true;
}
return false;
}
/**
* Reports on nodes where the `Object` constructor is called without arguments.
* @param {ASTNode} node The node to evaluate.
* @returns {void}
*/
function check(node) {
if (
node.callee.type !== "Identifier" ||
node.callee.name !== "Object" ||
node.arguments.length
) {
return;
}
const variable = getVariableByName(
sourceCode.getScope(node),
"Object",
);
if (variable && variable.identifiers.length === 0) {
let replacement;
let fixText;
let messageId = "useLiteral";
if (needsParentheses(node)) {
replacement = "({})";
if (needsPrecedingSemicolon(sourceCode, node)) {
fixText = ";({})";
messageId = "useLiteralAfterSemicolon";
} else {
fixText = "({})";
}
} else {
replacement = fixText = "{}";
}
context.report({
node,
messageId: "preferLiteral",
suggest: [
{
messageId,
data: { replacement },
fix: fixer => fixer.replaceText(node, fixText),
},
],
});
}
}
return {
CallExpression: check,
NewExpression: check,
};
},
};

View File

@@ -0,0 +1 @@
{"version":3,"file":"https.js","sourceRoot":"","sources":["../../../src/schemes/https.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,QAAQ,CAAC;AAE1B,MAAM,OAAO,GAAoB;IAChC,MAAM,EAAG,OAAO;IAChB,UAAU,EAAG,IAAI,CAAC,UAAU;IAC5B,KAAK,EAAG,IAAI,CAAC,KAAK;IAClB,SAAS,EAAG,IAAI,CAAC,SAAS;CAC1B,CAAA;AAED,eAAe,OAAO,CAAC"}