This commit is contained in:
2026-03-18 20:54:43 +01:00
parent b3c8b77f12
commit 9fe656b34c
8058 changed files with 912898 additions and 23 deletions
+9
View File
@@ -0,0 +1,9 @@
(The MIT License)
Copyright (c) 2011-2013 Jake Luer jake@alogicalparadox.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+63
View File
@@ -0,0 +1,63 @@
![npm](https://img.shields.io/npm/v/loupe?logo=npm)
![Build](https://github.com/chaijs/loupe/workflows/Build/badge.svg?branch=master)
![Codecov branch](https://img.shields.io/codecov/c/github/chaijs/loupe/master?logo=codecov)
# What is loupe?
Loupe turns the object you give it into a string. It's similar to Node.js' `util.inspect()` function, but it works cross platform, in most modern browsers as well as Node.
## Installation
### Node.js
`loupe` is available on [npm](http://npmjs.org). To install it, type:
$ npm install loupe
### Browsers
You can also use it within the browser; install via npm and use the `loupe.js` file found within the download. For example:
```html
<script src="./node_modules/loupe/loupe.js"></script>
```
## Usage
``` js
const { inspect } = require('loupe');
```
```js
inspect({ foo: 'bar' }); // => "{ foo: 'bar' }"
inspect(1); // => '1'
inspect('foo'); // => "'foo'"
inspect([ 1, 2, 3 ]); // => '[ 1, 2, 3 ]'
inspect(/Test/g); // => '/Test/g'
// ...
```
## Tests
```bash
$ npm test
```
Coverage:
```bash
$ npm run upload-coverage
```
## License
(The MIT License)
Copyright (c) 2011-2013 Jake Luer jake@alogicalparadox.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+622
View File
@@ -0,0 +1,622 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
custom: () => custom,
default: () => index_default,
inspect: () => inspect,
registerConstructor: () => registerConstructor,
registerStringTag: () => registerStringTag
});
module.exports = __toCommonJS(index_exports);
// src/helpers.ts
var ansiColors = {
bold: ["1", "22"],
dim: ["2", "22"],
italic: ["3", "23"],
underline: ["4", "24"],
// 5 & 6 are blinking
inverse: ["7", "27"],
hidden: ["8", "28"],
strike: ["9", "29"],
// 10-20 are fonts
// 21-29 are resets for 1-9
black: ["30", "39"],
red: ["31", "39"],
green: ["32", "39"],
yellow: ["33", "39"],
blue: ["34", "39"],
magenta: ["35", "39"],
cyan: ["36", "39"],
white: ["37", "39"],
brightblack: ["30;1", "39"],
brightred: ["31;1", "39"],
brightgreen: ["32;1", "39"],
brightyellow: ["33;1", "39"],
brightblue: ["34;1", "39"],
brightmagenta: ["35;1", "39"],
brightcyan: ["36;1", "39"],
brightwhite: ["37;1", "39"],
grey: ["90", "39"]
};
var styles = {
special: "cyan",
number: "yellow",
bigint: "yellow",
boolean: "yellow",
undefined: "grey",
null: "bold",
string: "green",
symbol: "green",
date: "magenta",
regexp: "red"
};
var truncator = "\u2026";
function colorise(value, styleType) {
const color = ansiColors[styles[styleType]] || ansiColors[styleType] || "";
if (!color) {
return String(value);
}
return `\x1B[${color[0]}m${String(value)}\x1B[${color[1]}m`;
}
function normaliseOptions({
showHidden = false,
depth = 2,
colors = false,
customInspect = true,
showProxy = false,
maxArrayLength = Infinity,
breakLength = Infinity,
seen = [],
// eslint-disable-next-line no-shadow
truncate: truncate2 = Infinity,
stylize = String
} = {}, inspect2) {
const options = {
showHidden: Boolean(showHidden),
depth: Number(depth),
colors: Boolean(colors),
customInspect: Boolean(customInspect),
showProxy: Boolean(showProxy),
maxArrayLength: Number(maxArrayLength),
breakLength: Number(breakLength),
truncate: Number(truncate2),
seen,
inspect: inspect2,
stylize
};
if (options.colors) {
options.stylize = colorise;
}
return options;
}
function isHighSurrogate(char) {
return char >= "\uD800" && char <= "\uDBFF";
}
function truncate(string, length, tail = truncator) {
string = String(string);
const tailLength = tail.length;
const stringLength = string.length;
if (tailLength > length && stringLength > tailLength) {
return tail;
}
if (stringLength > length && stringLength > tailLength) {
let end = length - tailLength;
if (end > 0 && isHighSurrogate(string[end - 1])) {
end = end - 1;
}
return `${string.slice(0, end)}${tail}`;
}
return string;
}
function inspectList(list, options, inspectItem, separator = ", ") {
inspectItem = inspectItem || options.inspect;
const size = list.length;
if (size === 0) return "";
const originalLength = options.truncate;
let output = "";
let peek = "";
let truncated = "";
for (let i = 0; i < size; i += 1) {
const last = i + 1 === list.length;
const secondToLast = i + 2 === list.length;
truncated = `${truncator}(${list.length - i})`;
const value = list[i];
options.truncate = originalLength - output.length - (last ? 0 : separator.length);
const string = peek || inspectItem(value, options) + (last ? "" : separator);
const nextLength = output.length + string.length;
const truncatedLength = nextLength + truncated.length;
if (last && nextLength > originalLength && output.length + truncated.length <= originalLength) {
break;
}
if (!last && !secondToLast && truncatedLength > originalLength) {
break;
}
peek = last ? "" : inspectItem(list[i + 1], options) + (secondToLast ? "" : separator);
if (!last && secondToLast && truncatedLength > originalLength && nextLength + peek.length > originalLength) {
break;
}
output += string;
if (!last && !secondToLast && nextLength + peek.length >= originalLength) {
truncated = `${truncator}(${list.length - i - 1})`;
break;
}
truncated = "";
}
return `${output}${truncated}`;
}
function quoteComplexKey(key) {
if (key.match(/^[a-zA-Z_][a-zA-Z_0-9]*$/)) {
return key;
}
return JSON.stringify(key).replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
}
function inspectProperty([key, value], options) {
options.truncate -= 2;
if (typeof key === "string") {
key = quoteComplexKey(key);
} else if (typeof key !== "number") {
key = `[${options.inspect(key, options)}]`;
}
options.truncate -= key.length;
value = options.inspect(value, options);
return `${key}: ${value}`;
}
// src/array.ts
function inspectArray(array, options) {
const nonIndexProperties = Object.keys(array).slice(array.length);
if (!array.length && !nonIndexProperties.length) return "[]";
options.truncate -= 4;
const listContents = inspectList(array, options);
options.truncate -= listContents.length;
let propertyContents = "";
if (nonIndexProperties.length) {
propertyContents = inspectList(
nonIndexProperties.map((key) => [key, array[key]]),
options,
inspectProperty
);
}
return `[ ${listContents}${propertyContents ? `, ${propertyContents}` : ""} ]`;
}
// src/typedarray.ts
var getArrayName = (array) => {
if (typeof Buffer === "function" && array instanceof Buffer) {
return "Buffer";
}
if (array[Symbol.toStringTag]) {
return array[Symbol.toStringTag];
}
return array.constructor.name;
};
function inspectTypedArray(array, options) {
const name = getArrayName(array);
options.truncate -= name.length + 4;
const nonIndexProperties = Object.keys(array).slice(array.length);
if (!array.length && !nonIndexProperties.length) return `${name}[]`;
let output = "";
for (let i = 0; i < array.length; i++) {
const string = `${options.stylize(truncate(array[i], options.truncate), "number")}${i === array.length - 1 ? "" : ", "}`;
options.truncate -= string.length;
if (array[i] !== array.length && options.truncate <= 3) {
output += `${truncator}(${array.length - array[i] + 1})`;
break;
}
output += string;
}
let propertyContents = "";
if (nonIndexProperties.length) {
propertyContents = inspectList(
nonIndexProperties.map((key) => [key, array[key]]),
options,
inspectProperty
);
}
return `${name}[ ${output}${propertyContents ? `, ${propertyContents}` : ""} ]`;
}
// src/date.ts
function inspectDate(dateObject, options) {
const stringRepresentation = dateObject.toJSON();
if (stringRepresentation === null) {
return "Invalid Date";
}
const split = stringRepresentation.split("T");
const date = split[0];
return options.stylize(`${date}T${truncate(split[1], options.truncate - date.length - 1)}`, "date");
}
// src/function.ts
function inspectFunction(func, options) {
const functionType = func[Symbol.toStringTag] || "Function";
const name = func.name;
if (!name) {
return options.stylize(`[${functionType}]`, "special");
}
return options.stylize(`[${functionType} ${truncate(name, options.truncate - 11)}]`, "special");
}
// src/map.ts
function inspectMapEntry([key, value], options) {
options.truncate -= 4;
key = options.inspect(key, options);
options.truncate -= key.length;
value = options.inspect(value, options);
return `${key} => ${value}`;
}
function mapToEntries(map) {
const entries = [];
map.forEach((value, key) => {
entries.push([key, value]);
});
return entries;
}
function inspectMap(map, options) {
if (map.size === 0) return "Map{}";
options.truncate -= 7;
return `Map{ ${inspectList(mapToEntries(map), options, inspectMapEntry)} }`;
}
// src/number.ts
var isNaN = Number.isNaN || ((i) => i !== i);
function inspectNumber(number, options) {
if (isNaN(number)) {
return options.stylize("NaN", "number");
}
if (number === Infinity) {
return options.stylize("Infinity", "number");
}
if (number === -Infinity) {
return options.stylize("-Infinity", "number");
}
if (number === 0) {
return options.stylize(1 / number === Infinity ? "+0" : "-0", "number");
}
return options.stylize(truncate(String(number), options.truncate), "number");
}
// src/bigint.ts
function inspectBigInt(number, options) {
let nums = truncate(number.toString(), options.truncate - 1);
if (nums !== truncator) nums += "n";
return options.stylize(nums, "bigint");
}
// src/regexp.ts
function inspectRegExp(value, options) {
const flags = value.toString().split("/")[2];
const sourceLength = options.truncate - (2 + flags.length);
const source = value.source;
return options.stylize(`/${truncate(source, sourceLength)}/${flags}`, "regexp");
}
// src/set.ts
function arrayFromSet(set) {
const values = [];
set.forEach((value) => {
values.push(value);
});
return values;
}
function inspectSet(set, options) {
if (set.size === 0) return "Set{}";
options.truncate -= 7;
return `Set{ ${inspectList(arrayFromSet(set), options)} }`;
}
// src/string.ts
var stringEscapeChars = new RegExp(
"['\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]",
"g"
);
var escapeCharacters = {
"\b": "\\b",
" ": "\\t",
"\n": "\\n",
"\f": "\\f",
"\r": "\\r",
"'": "\\'",
"\\": "\\\\"
};
var hex = 16;
var unicodeLength = 4;
function escape(char) {
return escapeCharacters[char] || `\\u${`0000${char.charCodeAt(0).toString(hex)}`.slice(-unicodeLength)}`;
}
function inspectString(string, options) {
if (stringEscapeChars.test(string)) {
string = string.replace(stringEscapeChars, escape);
}
return options.stylize(`'${truncate(string, options.truncate - 2)}'`, "string");
}
// src/symbol.ts
function inspectSymbol(value) {
if ("description" in Symbol.prototype) {
return value.description ? `Symbol(${value.description})` : "Symbol()";
}
return value.toString();
}
// src/promise.ts
var getPromiseValue = () => "Promise{\u2026}";
var promise_default = getPromiseValue;
// src/object.ts
function inspectObject(object, options) {
const properties = Object.getOwnPropertyNames(object);
const symbols = Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(object) : [];
if (properties.length === 0 && symbols.length === 0) {
return "{}";
}
options.truncate -= 4;
options.seen = options.seen || [];
if (options.seen.includes(object)) {
return "[Circular]";
}
options.seen.push(object);
const propertyContents = inspectList(
properties.map((key) => [key, object[key]]),
options,
inspectProperty
);
const symbolContents = inspectList(
symbols.map((key) => [key, object[key]]),
options,
inspectProperty
);
options.seen.pop();
let sep = "";
if (propertyContents && symbolContents) {
sep = ", ";
}
return `{ ${propertyContents}${sep}${symbolContents} }`;
}
// src/class.ts
var toStringTag = typeof Symbol !== "undefined" && Symbol.toStringTag ? Symbol.toStringTag : false;
function inspectClass(value, options) {
let name = "";
if (toStringTag && toStringTag in value) {
name = value[toStringTag];
}
name = name || value.constructor.name;
if (!name || name === "_class") {
name = "<Anonymous Class>";
}
options.truncate -= name.length;
return `${name}${inspectObject(value, options)}`;
}
// src/arguments.ts
function inspectArguments(args, options) {
if (args.length === 0) return "Arguments[]";
options.truncate -= 13;
return `Arguments[ ${inspectList(args, options)} ]`;
}
// src/error.ts
var errorKeys = [
"stack",
"line",
"column",
"name",
"message",
"fileName",
"lineNumber",
"columnNumber",
"number",
"description",
"cause"
];
function inspectObject2(error, options) {
const properties = Object.getOwnPropertyNames(error).filter((key) => errorKeys.indexOf(key) === -1);
const name = error.name;
options.truncate -= name.length;
let message = "";
if (typeof error.message === "string") {
message = truncate(error.message, options.truncate);
} else {
properties.unshift("message");
}
message = message ? `: ${message}` : "";
options.truncate -= message.length + 5;
options.seen = options.seen || [];
if (options.seen.includes(error)) {
return "[Circular]";
}
options.seen.push(error);
const propertyContents = inspectList(
properties.map((key) => [key, error[key]]),
options,
inspectProperty
);
return `${name}${message}${propertyContents ? ` { ${propertyContents} }` : ""}`;
}
// src/html.ts
function inspectAttribute([key, value], options) {
options.truncate -= 3;
if (!value) {
return `${options.stylize(String(key), "yellow")}`;
}
return `${options.stylize(String(key), "yellow")}=${options.stylize(`"${value}"`, "string")}`;
}
function inspectNodeCollection(collection, options) {
return inspectList(collection, options, inspectNode, "\n");
}
function inspectNode(node, options) {
switch (node.nodeType) {
case 1:
return inspectHTML(node, options);
case 3:
return options.inspect(node.data, options);
default:
return options.inspect(node, options);
}
}
function inspectHTML(element, options) {
const properties = element.getAttributeNames();
const name = element.tagName.toLowerCase();
const head = options.stylize(`<${name}`, "special");
const headClose = options.stylize(`>`, "special");
const tail = options.stylize(`</${name}>`, "special");
options.truncate -= name.length * 2 + 5;
let propertyContents = "";
if (properties.length > 0) {
propertyContents += " ";
propertyContents += inspectList(
properties.map((key) => [key, element.getAttribute(key)]),
options,
inspectAttribute,
" "
);
}
options.truncate -= propertyContents.length;
const truncate2 = options.truncate;
let children = inspectNodeCollection(element.children, options);
if (children && children.length > truncate2) {
children = `${truncator}(${element.children.length})`;
}
return `${head}${propertyContents}${headClose}${children}${tail}`;
}
// src/index.ts
var symbolsSupported = typeof Symbol === "function" && typeof Symbol.for === "function";
var chaiInspect = symbolsSupported ? Symbol.for("chai/inspect") : "@@chai/inspect";
var nodeInspect = Symbol.for("nodejs.util.inspect.custom");
var constructorMap = /* @__PURE__ */ new WeakMap();
var stringTagMap = {};
var baseTypesMap = {
undefined: (value, options) => options.stylize("undefined", "undefined"),
null: (value, options) => options.stylize("null", "null"),
boolean: (value, options) => options.stylize(String(value), "boolean"),
Boolean: (value, options) => options.stylize(String(value), "boolean"),
number: inspectNumber,
Number: inspectNumber,
bigint: inspectBigInt,
BigInt: inspectBigInt,
string: inspectString,
String: inspectString,
function: inspectFunction,
Function: inspectFunction,
symbol: inspectSymbol,
// A Symbol polyfill will return `Symbol` not `symbol` from typedetect
Symbol: inspectSymbol,
Array: inspectArray,
Date: inspectDate,
Map: inspectMap,
Set: inspectSet,
RegExp: inspectRegExp,
Promise: promise_default,
// WeakSet, WeakMap are totally opaque to us
WeakSet: (value, options) => options.stylize("WeakSet{\u2026}", "special"),
WeakMap: (value, options) => options.stylize("WeakMap{\u2026}", "special"),
Arguments: inspectArguments,
Int8Array: inspectTypedArray,
Uint8Array: inspectTypedArray,
Uint8ClampedArray: inspectTypedArray,
Int16Array: inspectTypedArray,
Uint16Array: inspectTypedArray,
Int32Array: inspectTypedArray,
Uint32Array: inspectTypedArray,
Float32Array: inspectTypedArray,
Float64Array: inspectTypedArray,
Generator: () => "",
DataView: () => "",
ArrayBuffer: () => "",
Error: inspectObject2,
HTMLCollection: inspectNodeCollection,
NodeList: inspectNodeCollection
};
var inspectCustom = (value, options, type, inspectFn) => {
if (chaiInspect in value && typeof value[chaiInspect] === "function") {
return value[chaiInspect](options);
}
if (nodeInspect in value && typeof value[nodeInspect] === "function") {
return value[nodeInspect](options.depth, options, inspectFn);
}
if ("inspect" in value && typeof value.inspect === "function") {
return value.inspect(options.depth, options);
}
if ("constructor" in value && constructorMap.has(value.constructor)) {
return constructorMap.get(value.constructor)(value, options);
}
if (stringTagMap[type]) {
return stringTagMap[type](value, options);
}
return "";
};
var toString = Object.prototype.toString;
function inspect(value, opts = {}) {
const options = normaliseOptions(opts, inspect);
const { customInspect } = options;
let type = value === null ? "null" : typeof value;
if (type === "object") {
type = toString.call(value).slice(8, -1);
}
if (type in baseTypesMap) {
return baseTypesMap[type](value, options);
}
if (customInspect && value) {
const output = inspectCustom(value, options, type, inspect);
if (output) {
if (typeof output === "string") return output;
return inspect(output, options);
}
}
const proto = value ? Object.getPrototypeOf(value) : false;
if (proto === Object.prototype || proto === null) {
return inspectObject(value, options);
}
if (value && typeof HTMLElement === "function" && value instanceof HTMLElement) {
return inspectHTML(value, options);
}
if ("constructor" in value) {
if (value.constructor !== Object) {
return inspectClass(value, options);
}
return inspectObject(value, options);
}
if (value === Object(value)) {
return inspectObject(value, options);
}
return options.stylize(String(value), type);
}
function registerConstructor(constructor, inspector) {
if (constructorMap.has(constructor)) {
return false;
}
constructorMap.set(constructor, inspector);
return true;
}
function registerStringTag(stringTag, inspector) {
if (stringTag in stringTagMap) {
return false;
}
stringTagMap[stringTag] = inspector;
return true;
}
var custom = chaiInspect;
var index_default = inspect;
+73
View File
@@ -0,0 +1,73 @@
{
"name": "loupe",
"version": "3.2.1",
"description": "Inspect utility for Node.js and browsers",
"homepage": "https://github.com/chaijs/loupe",
"license": "MIT",
"author": "Veselin Todorov <hi@vesln.com>",
"contributors": [
"Keith Cirkel (https://github.com/keithamus)"
],
"type": "module",
"main": "./lib/index.js",
"module": "./lib/index.js",
"browser": {
"./index.js": "./loupe.js",
"util": false
},
"repository": {
"type": "git",
"url": "https://github.com/chaijs/loupe"
},
"files": [
"loupe.js",
"lib/*"
],
"scripts": {
"bench": "node bench",
"lint": "eslint .",
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
"test": "npm run test:node && npm run test:browser",
"pretest:browser": "npx playwright install-deps && npx playwright install && npm run build",
"test:browser": "wtr",
"pretest:node": "npm run build",
"test:node": "mocha",
"build": "npm run build:lib && npm run build:esm-bundle && npm run build:cjs-bundle",
"build:lib": "tsc",
"build:esm-bundle": "esbuild --bundle src/index.ts --outfile=loupe.js --format=esm",
"build:cjs-bundle": "esbuild --bundle src/index.ts --outfile=loupe.js --format=cjs",
"upload-coverage": "codecov"
},
"prettier": {
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"arrowParens": "avoid",
"bracketSpacing": true
},
"devDependencies": {
"@web/dev-server-esbuild": "^1.0.3",
"@web/test-runner": "^0.19.0",
"@web/test-runner-playwright": "^0.11.0",
"benchmark": "^2.1.4",
"chai": "^5.0.0-alpha.0",
"codecov": "^3.8.3",
"core-js": "^3.8.3",
"cross-env": "^7.0.3",
"esbuild": "^0.24.2",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"eslint-config-strict": "^14.0.1",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-prettier": "^5.2.3",
"husky": "^9.1.7",
"mocha": "^11.1.0",
"nyc": "^17.1.0",
"prettier": "^3.0.0",
"simple-assert": "^2.0.0",
"typescript": "^5.0.0-beta"
}
}