feat(frontend): add API client, layout, and routing

- Create Axios-based API client with sources, jobs, and dashboard endpoints
- Add responsive Layout component with navigation sidebar
- Set up React Router with Dashboard, Backups, and Settings routes
- Configure TanStack Query provider with default options
- Use lucide-react for navigation icons
This commit is contained in:
2026-05-11 21:47:20 +02:00
parent 7676438466
commit d3b92593d5
14073 changed files with 2182272 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-Present Vitest Team
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.
+17
View File
@@ -0,0 +1,17 @@
# @vitest/expect
Jest's expect matchers as a Chai plugin.
## Usage
```js
import * as chai from 'chai'
import { JestAsymmetricMatchers, JestChaiExpect, JestExtend } from '@vitest/expect'
// allows using expect.extend instead of chai.use to extend plugins
chai.use(JestExtend)
// adds all jest matchers to expect
chai.use(JestChaiExpect)
// adds asymmetric matchers like stringContaining, objectContaining
chai.use(JestAsymmetricMatchers)
```
File diff suppressed because it is too large Load Diff
+258
View File
@@ -0,0 +1,258 @@
import * as _vitest_utils from '@vitest/utils';
import { stringify, Constructable } from '@vitest/utils';
export { setupColors } from '@vitest/utils';
import { diff } from '@vitest/utils/diff';
export { DiffOptions } from '@vitest/utils/diff';
type Formatter = (input: string | number | null | undefined) => string;
declare function getMatcherUtils(): {
EXPECTED_COLOR: _vitest_utils.ColorMethod;
RECEIVED_COLOR: _vitest_utils.ColorMethod;
INVERTED_COLOR: _vitest_utils.ColorMethod;
BOLD_WEIGHT: _vitest_utils.ColorMethod;
DIM_COLOR: _vitest_utils.ColorMethod;
matcherHint: (matcherName: string, received?: string, expected?: string, options?: MatcherHintOptions) => string;
printReceived: (object: unknown) => string;
printExpected: (value: unknown) => string;
};
declare function addCustomEqualityTesters(newTesters: Array<Tester>): void;
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
type ChaiPlugin = Chai.ChaiPlugin;
type Tester = (this: TesterContext, a: any, b: any, customTesters: Array<Tester>) => boolean | undefined;
interface TesterContext {
equals: (a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean) => boolean;
}
interface MatcherHintOptions {
comment?: string;
expectedColor?: Formatter;
isDirectExpectCall?: boolean;
isNot?: boolean;
promise?: string;
receivedColor?: Formatter;
secondArgument?: string;
secondArgumentColor?: Formatter;
}
interface MatcherState {
customTesters: Array<Tester>;
assertionCalls: number;
currentTestName?: string;
dontThrow?: () => void;
error?: Error;
equals: (a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean) => boolean;
expand?: boolean;
expectedAssertionsNumber?: number | null;
expectedAssertionsNumberErrorGen?: (() => Error) | null;
isExpectingAssertions?: boolean;
isExpectingAssertionsError?: Error | null;
isNot: boolean;
promise: string;
suppressedErrors: Array<Error>;
testPath?: string;
utils: ReturnType<typeof getMatcherUtils> & {
diff: typeof diff;
stringify: typeof stringify;
iterableEquality: Tester;
subsetEquality: Tester;
};
soft?: boolean;
}
interface SyncExpectationResult {
pass: boolean;
message: () => string;
actual?: any;
expected?: any;
}
type AsyncExpectationResult = Promise<SyncExpectationResult>;
type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;
interface RawMatcherFn<T extends MatcherState = MatcherState> {
(this: T, received: any, expected: any, options?: any): ExpectationResult;
}
type MatchersObject<T extends MatcherState = MatcherState> = Record<string, RawMatcherFn<T>>;
interface ExpectStatic extends Chai.ExpectStatic, AsymmetricMatchersContaining {
<T>(actual: T, message?: string): Assertion<T>;
unreachable: (message?: string) => never;
soft: <T>(actual: T, message?: string) => Assertion<T>;
extend: (expects: MatchersObject) => void;
addEqualityTesters: (testers: Array<Tester>) => void;
assertions: (expected: number) => void;
hasAssertions: () => void;
anything: () => any;
any: (constructor: unknown) => any;
getState: () => MatcherState;
setState: (state: Partial<MatcherState>) => void;
not: AsymmetricMatchersContaining;
}
interface AsymmetricMatchersContaining {
stringContaining: (expected: string) => any;
objectContaining: <T = any>(expected: T) => any;
arrayContaining: <T = unknown>(expected: Array<T>) => any;
stringMatching: (expected: string | RegExp) => any;
closeTo: (expected: number, precision?: number) => any;
}
interface JestAssertion<T = any> extends jest.Matchers<void, T> {
toEqual: <E>(expected: E) => void;
toStrictEqual: <E>(expected: E) => void;
toBe: <E>(expected: E) => void;
toMatch: (expected: string | RegExp) => void;
toMatchObject: <E extends {} | any[]>(expected: E) => void;
toContain: <E>(item: E) => void;
toContainEqual: <E>(item: E) => void;
toBeTruthy: () => void;
toBeFalsy: () => void;
toBeGreaterThan: (num: number | bigint) => void;
toBeGreaterThanOrEqual: (num: number | bigint) => void;
toBeLessThan: (num: number | bigint) => void;
toBeLessThanOrEqual: (num: number | bigint) => void;
toBeNaN: () => void;
toBeUndefined: () => void;
toBeNull: () => void;
toBeDefined: () => void;
toBeInstanceOf: <E>(expected: E) => void;
toBeCalledTimes: (times: number) => void;
toHaveLength: (length: number) => void;
toHaveProperty: <E>(property: string | (string | number)[], value?: E) => void;
toBeCloseTo: (number: number, numDigits?: number) => void;
toHaveBeenCalledTimes: (times: number) => void;
toHaveBeenCalled: () => void;
toBeCalled: () => void;
toHaveBeenCalledWith: <E extends any[]>(...args: E) => void;
toBeCalledWith: <E extends any[]>(...args: E) => void;
toHaveBeenNthCalledWith: <E extends any[]>(n: number, ...args: E) => void;
nthCalledWith: <E extends any[]>(nthCall: number, ...args: E) => void;
toHaveBeenLastCalledWith: <E extends any[]>(...args: E) => void;
lastCalledWith: <E extends any[]>(...args: E) => void;
toThrow: (expected?: string | Constructable | RegExp | Error) => void;
toThrowError: (expected?: string | Constructable | RegExp | Error) => void;
toReturn: () => void;
toHaveReturned: () => void;
toReturnTimes: (times: number) => void;
toHaveReturnedTimes: (times: number) => void;
toReturnWith: <E>(value: E) => void;
toHaveReturnedWith: <E>(value: E) => void;
toHaveLastReturnedWith: <E>(value: E) => void;
lastReturnedWith: <E>(value: E) => void;
toHaveNthReturnedWith: <E>(nthCall: number, value: E) => void;
nthReturnedWith: <E>(nthCall: number, value: E) => void;
}
type VitestAssertion<A, T> = {
[K in keyof A]: A[K] extends Chai.Assertion ? Assertion<T> : A[K] extends (...args: any[]) => any ? A[K] : VitestAssertion<A[K], T>;
} & ((type: string, message?: string) => Assertion);
type Promisify<O> = {
[K in keyof O]: O[K] extends (...args: infer A) => infer R ? O extends R ? Promisify<O[K]> : (...args: A) => Promise<R> : O[K];
};
interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAssertion<T> {
toBeTypeOf: (expected: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => void;
toHaveBeenCalledOnce: () => void;
toSatisfy: <E>(matcher: (value: E) => boolean, message?: string) => void;
resolves: Promisify<Assertion<T>>;
rejects: Promisify<Assertion<T>>;
}
declare global {
namespace jest {
interface Matchers<R, T = {}> {
}
}
}
interface AsymmetricMatcherInterface {
asymmetricMatch: (other: unknown) => boolean;
toString: () => string;
getExpectedType?: () => string;
toAsymmetricMatcher?: () => string;
}
declare abstract class AsymmetricMatcher<T, State extends MatcherState = MatcherState> implements AsymmetricMatcherInterface {
protected sample: T;
protected inverse: boolean;
$$typeof: symbol;
constructor(sample: T, inverse?: boolean);
protected getMatcherContext(expect?: Chai.ExpectStatic): State;
abstract asymmetricMatch(other: unknown): boolean;
abstract toString(): string;
getExpectedType?(): string;
toAsymmetricMatcher?(): string;
}
declare class StringContaining extends AsymmetricMatcher<string> {
constructor(sample: string, inverse?: boolean);
asymmetricMatch(other: string): boolean;
toString(): string;
getExpectedType(): string;
}
declare class Anything extends AsymmetricMatcher<void> {
asymmetricMatch(other: unknown): boolean;
toString(): string;
toAsymmetricMatcher(): string;
}
declare class ObjectContaining extends AsymmetricMatcher<Record<string, unknown>> {
constructor(sample: Record<string, unknown>, inverse?: boolean);
getPrototype(obj: object): any;
hasProperty(obj: object | null, property: string): boolean;
asymmetricMatch(other: any): boolean;
toString(): string;
getExpectedType(): string;
}
declare class ArrayContaining<T = unknown> extends AsymmetricMatcher<Array<T>> {
constructor(sample: Array<T>, inverse?: boolean);
asymmetricMatch(other: Array<T>): boolean;
toString(): string;
getExpectedType(): string;
}
declare class Any extends AsymmetricMatcher<any> {
constructor(sample: unknown);
fnNameFor(func: Function): string;
asymmetricMatch(other: unknown): boolean;
toString(): string;
getExpectedType(): string;
toAsymmetricMatcher(): string;
}
declare class StringMatching extends AsymmetricMatcher<RegExp> {
constructor(sample: string | RegExp, inverse?: boolean);
asymmetricMatch(other: string): boolean;
toString(): string;
getExpectedType(): string;
}
declare const JestAsymmetricMatchers: ChaiPlugin;
declare function equals(a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean): boolean;
declare function isAsymmetric(obj: any): boolean;
declare function hasAsymmetric(obj: any, seen?: Set<unknown>): boolean;
declare function isA(typeName: string, value: unknown): boolean;
declare function fnNameFor(func: Function): string;
declare function hasProperty(obj: object | null, property: string): boolean;
declare function isImmutableUnorderedKeyed(maybeKeyed: any): boolean;
declare function isImmutableUnorderedSet(maybeSet: any): boolean;
declare function iterableEquality(a: any, b: any, customTesters?: Array<Tester>, aStack?: Array<any>, bStack?: Array<any>): boolean | undefined;
declare function subsetEquality(object: unknown, subset: unknown, customTesters?: Array<Tester>): boolean | undefined;
declare function typeEquality(a: any, b: any): boolean | undefined;
declare function arrayBufferEquality(a: unknown, b: unknown): boolean | undefined;
declare function sparseArrayEquality(a: unknown, b: unknown, customTesters?: Array<Tester>): boolean | undefined;
declare function generateToBeMessage(deepEqualityName: string, expected?: string, actual?: string): string;
declare function pluralize(word: string, count: number): string;
declare function getObjectKeys(object: object): Array<string | symbol>;
declare function getObjectSubset(object: any, subset: any, customTesters?: Array<Tester>): {
subset: any;
stripped: number;
};
declare const MATCHERS_OBJECT: unique symbol;
declare const JEST_MATCHERS_OBJECT: unique symbol;
declare const GLOBAL_EXPECT: unique symbol;
declare const ASYMMETRIC_MATCHERS_OBJECT: unique symbol;
declare function getState<State extends MatcherState = MatcherState>(expect: ExpectStatic): State;
declare function setState<State extends MatcherState = MatcherState>(state: Partial<State>, expect: ExpectStatic): void;
declare const JestChaiExpect: ChaiPlugin;
declare const JestExtend: ChaiPlugin;
export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, type Assertion, AsymmetricMatcher, type AsymmetricMatcherInterface, type AsymmetricMatchersContaining, type AsyncExpectationResult, type ChaiPlugin, type ExpectStatic, type ExpectationResult, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, type JestAssertion, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, type MatcherHintOptions, type MatcherState, type MatchersObject, ObjectContaining, type RawMatcherFn, StringContaining, StringMatching, type SyncExpectationResult, type Tester, type TesterContext, addCustomEqualityTesters, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
import './dist/chai.cjs'
export * from './dist/index.js'
+47
View File
@@ -0,0 +1,47 @@
{
"name": "@vitest/expect",
"type": "module",
"version": "1.6.1",
"description": "Jest's expect matchers as a Chai plugin",
"license": "MIT",
"funding": "https://opencollective.com/vitest",
"homepage": "https://github.com/vitest-dev/vitest/tree/main/packages/expect#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/vitest-dev/vitest.git",
"directory": "packages/expect"
},
"bugs": {
"url": "https://github.com/vitest-dev/vitest/issues"
},
"sideEffects": false,
"exports": {
".": {
"types": "./index.d.ts",
"default": "./dist/index.js"
},
"./*": "./*"
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./index.d.ts",
"files": [
"*.d.ts",
"dist"
],
"dependencies": {
"chai": "^4.3.10",
"@vitest/utils": "1.6.1",
"@vitest/spy": "1.6.1"
},
"devDependencies": {
"@types/chai": "4.3.6",
"picocolors": "^1.0.0",
"rollup-plugin-copy": "^3.5.0",
"@vitest/runner": "1.6.1"
},
"scripts": {
"build": "rimraf dist && rollup -c",
"dev": "rollup -c --watch"
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-Present Vitest Team
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.
+5
View File
@@ -0,0 +1,5 @@
# @vitest/runner
Vitest mechanism to collect and run tasks.
[GitHub](https://github.com/vitest-dev/vitest) | [Documentation](https://vitest.dev/advanced/runner)
+171
View File
@@ -0,0 +1,171 @@
import { processError } from '@vitest/utils/error';
import { toArray } from '@vitest/utils';
function partitionSuiteChildren(suite) {
let tasksGroup = [];
const tasksGroups = [];
for (const c of suite.tasks) {
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
tasksGroup.push(c);
} else {
tasksGroups.push(tasksGroup);
tasksGroup = [c];
}
}
if (tasksGroup.length > 0)
tasksGroups.push(tasksGroup);
return tasksGroups;
}
function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnly) {
const suiteIsOnly = parentIsOnly || suite.mode === "only";
suite.tasks.forEach((t) => {
const includeTask = suiteIsOnly || t.mode === "only";
if (onlyMode) {
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
if (t.mode === "only") {
checkAllowOnly(t, allowOnly);
t.mode = "run";
}
} else if (t.mode === "run" && !includeTask) {
t.mode = "skip";
} else if (t.mode === "only") {
checkAllowOnly(t, allowOnly);
t.mode = "run";
}
}
if (t.type === "test") {
if (namePattern && !getTaskFullName(t).match(namePattern))
t.mode = "skip";
} else if (t.type === "suite") {
if (t.mode === "skip")
skipAllTasks(t);
else
interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
}
});
if (suite.mode === "run") {
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run"))
suite.mode = "skip";
}
}
function getTaskFullName(task) {
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
}
function someTasksAreOnly(suite) {
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
}
function skipAllTasks(suite) {
suite.tasks.forEach((t) => {
if (t.mode === "run") {
t.mode = "skip";
if (t.type === "suite")
skipAllTasks(t);
}
});
}
function checkAllowOnly(task, allowOnly) {
if (allowOnly)
return;
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
task.result = {
state: "fail",
errors: [error]
};
}
function generateHash(str) {
let hash = 0;
if (str.length === 0)
return `${hash}`;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return `${hash}`;
}
function calculateSuiteHash(parent) {
parent.tasks.forEach((t, idx) => {
t.id = `${parent.id}_${idx}`;
if (t.type === "suite")
calculateSuiteHash(t);
});
}
function createChainable(keys, fn) {
function create(context) {
const chain2 = function(...args) {
return fn.apply(context, args);
};
Object.assign(chain2, fn);
chain2.withContext = () => chain2.bind(context);
chain2.setContext = (key, value) => {
context[key] = value;
};
chain2.mergeContext = (ctx) => {
Object.assign(context, ctx);
};
for (const key of keys) {
Object.defineProperty(chain2, key, {
get() {
return create({ ...context, [key]: true });
}
});
}
return chain2;
}
const chain = create({});
chain.fn = fn;
return chain;
}
function isAtomTest(s) {
return s.type === "test" || s.type === "custom";
}
function getTests(suite) {
const tests = [];
const arraySuites = toArray(suite);
for (const s of arraySuites) {
if (isAtomTest(s)) {
tests.push(s);
} else {
for (const task of s.tasks) {
if (isAtomTest(task)) {
tests.push(task);
} else {
const taskTests = getTests(task);
for (const test of taskTests)
tests.push(test);
}
}
}
}
return tests;
}
function getTasks(tasks = []) {
return toArray(tasks).flatMap((s) => isAtomTest(s) ? [s] : [s, ...getTasks(s.tasks)]);
}
function getSuites(suite) {
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
}
function hasTests(suite) {
return toArray(suite).some((s) => s.tasks.some((c) => isAtomTest(c) || hasTests(c)));
}
function hasFailed(suite) {
return toArray(suite).some((s) => {
var _a;
return ((_a = s.result) == null ? void 0 : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
});
}
function getNames(task) {
const names = [task.name];
let current = task;
while ((current == null ? void 0 : current.suite) || (current == null ? void 0 : current.file)) {
current = current.suite || current.file;
if (current == null ? void 0 : current.name)
names.unshift(current.name);
}
return names;
}
export { getTests as a, getTasks as b, calculateSuiteHash as c, getSuites as d, hasFailed as e, getNames as f, generateHash as g, hasTests as h, interpretTaskModes as i, createChainable as j, partitionSuiteChildren as p, someTasksAreOnly as s };
+33
View File
@@ -0,0 +1,33 @@
import { VitestRunner } from './types.js';
export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
import { T as Task, F as File, d as SuiteAPI, e as TestAPI, f as SuiteCollector, g as CustomAPI, h as SuiteHooks, O as OnTestFailedHandler, i as OnTestFinishedHandler, a as Test, C as Custom, S as Suite } from './tasks-K5XERDtv.js';
export { D as DoneCallback, E as ExtendedContext, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, R as RunMode, y as RuntimeContext, B as SequenceHooks, G as SequenceSetupFiles, x as SuiteFactory, k as TaskBase, A as TaskContext, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, o as TaskResultPack, j as TaskState, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-K5XERDtv.js';
import { Awaitable } from '@vitest/utils';
export { processError } from '@vitest/utils/error';
import '@vitest/utils/diff';
declare function updateTask(task: Task, runner: VitestRunner): void;
declare function startTests(paths: string[], runner: VitestRunner): Promise<File[]>;
declare const suite: SuiteAPI;
declare const test: TestAPI;
declare const describe: SuiteAPI;
declare const it: TestAPI;
declare function getCurrentSuite<ExtraContext = {}>(): SuiteCollector<ExtraContext>;
declare function createTaskCollector(fn: (...args: any[]) => any, context?: Record<string, unknown>): CustomAPI;
declare function beforeAll(fn: SuiteHooks['beforeAll'][0], timeout?: number): void;
declare function afterAll(fn: SuiteHooks['afterAll'][0], timeout?: number): void;
declare function beforeEach<ExtraContext = {}>(fn: SuiteHooks<ExtraContext>['beforeEach'][0], timeout?: number): void;
declare function afterEach<ExtraContext = {}>(fn: SuiteHooks<ExtraContext>['afterEach'][0], timeout?: number): void;
declare const onTestFailed: (fn: OnTestFailedHandler) => void;
declare const onTestFinished: (fn: OnTestFinishedHandler) => void;
declare function setFn(key: Test | Custom, fn: (() => Awaitable<void>)): void;
declare function getFn<Task = Test | Custom>(key: Task): (() => Awaitable<void>);
declare function setHooks(key: Suite, hooks: SuiteHooks): void;
declare function getHooks(key: Suite): SuiteHooks;
declare function getCurrentTest<T extends Test | Custom | undefined>(): T;
export { Custom, CustomAPI, File, OnTestFailedHandler, OnTestFinishedHandler, Suite, SuiteAPI, SuiteCollector, SuiteHooks, Task, Test, TestAPI, VitestRunner, afterAll, afterEach, beforeAll, beforeEach, createTaskCollector, describe, getCurrentSuite, getCurrentTest, getFn, getHooks, it, onTestFailed, onTestFinished, setFn, setHooks, startTests, suite, test, updateTask };
File diff suppressed because it is too large Load Diff
+280
View File
@@ -0,0 +1,280 @@
import { ErrorWithDiff, Awaitable } from '@vitest/utils';
type ChainableFunction<T extends string, F extends (...args: any) => any, C = {}> = F & {
[x in T]: ChainableFunction<T, F, C>;
} & {
fn: (this: Record<T, any>, ...args: Parameters<F>) => ReturnType<F>;
} & C;
declare function createChainable<T extends string, Args extends any[], R = any>(keys: T[], fn: (this: Record<T, any>, ...args: Args) => R): ChainableFunction<T, (...args: Args) => R>;
interface FixtureItem extends FixtureOptions {
prop: string;
value: any;
/**
* Indicates whether the fixture is a function
*/
isFn: boolean;
/**
* The dependencies(fixtures) of current fixture function.
*/
deps?: FixtureItem[];
}
type RunMode = 'run' | 'skip' | 'only' | 'todo';
type TaskState = RunMode | 'pass' | 'fail';
interface TaskBase {
id: string;
name: string;
mode: RunMode;
meta: TaskMeta;
each?: boolean;
concurrent?: boolean;
shuffle?: boolean;
suite?: Suite;
file?: File;
result?: TaskResult;
retry?: number;
repeats?: number;
location?: {
line: number;
column: number;
};
}
interface TaskPopulated extends TaskBase {
suite: Suite;
pending?: boolean;
result?: TaskResult;
fails?: boolean;
onFailed?: OnTestFailedHandler[];
onFinished?: OnTestFinishedHandler[];
/**
* Store promises (from async expects) to wait for them before finishing the test
*/
promises?: Promise<any>[];
}
interface TaskMeta {
}
interface TaskResult {
state: TaskState;
duration?: number;
startTime?: number;
heap?: number;
errors?: ErrorWithDiff[];
htmlError?: string;
hooks?: Partial<Record<keyof SuiteHooks, TaskState>>;
retryCount?: number;
repeatCount?: number;
}
type TaskResultPack = [id: string, result: TaskResult | undefined, meta: TaskMeta];
interface Suite extends TaskBase {
type: 'suite';
tasks: Task[];
filepath?: string;
projectName: string;
}
interface File extends Suite {
filepath: string;
collectDuration?: number;
setupDuration?: number;
}
interface Test<ExtraContext = {}> extends TaskPopulated {
type: 'test';
context: TaskContext<Test> & ExtraContext & TestContext;
}
interface Custom<ExtraContext = {}> extends TaskPopulated {
type: 'custom';
context: TaskContext<Custom> & ExtraContext & TestContext;
}
type Task = Test | Suite | Custom | File;
type DoneCallback = (error?: any) => void;
type TestFunction<ExtraContext = {}> = (context: ExtendedContext<Test> & ExtraContext) => Awaitable<any> | void;
type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
1: [T[0]];
2: [T[0], T[1]];
3: [T[0], T[1], T[2]];
4: [T[0], T[1], T[2], T[3]];
5: [T[0], T[1], T[2], T[3], T[4]];
6: [T[0], T[1], T[2], T[3], T[4], T[5]];
7: [T[0], T[1], T[2], T[3], T[4], T[5], T[6]];
8: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7]];
9: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8]];
10: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]];
fallback: Array<T extends ReadonlyArray<infer U> ? U : any>;
}[T extends Readonly<[any]> ? 1 : T extends Readonly<[any, any]> ? 2 : T extends Readonly<[any, any, any]> ? 3 : T extends Readonly<[any, any, any, any]> ? 4 : T extends Readonly<[any, any, any, any, any]> ? 5 : T extends Readonly<[any, any, any, any, any, any]> ? 6 : T extends Readonly<[any, any, any, any, any, any, any]> ? 7 : T extends Readonly<[any, any, any, any, any, any, any, any]> ? 8 : T extends Readonly<[any, any, any, any, any, any, any, any, any]> ? 9 : T extends Readonly<[any, any, any, any, any, any, any, any, any, any]> ? 10 : 'fallback'];
interface EachFunctionReturn<T extends any[]> {
/**
* @deprecated Use options as the second argument instead
*/
(name: string | Function, fn: (...args: T) => Awaitable<void>, options: TestOptions): void;
(name: string | Function, fn: (...args: T) => Awaitable<void>, options?: number | TestOptions): void;
(name: string | Function, options: TestOptions, fn: (...args: T) => Awaitable<void>): void;
}
interface TestEachFunction {
<T extends any[] | [any]>(cases: ReadonlyArray<T>): EachFunctionReturn<T>;
<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): EachFunctionReturn<ExtractEachCallbackArgs<T>>;
<T>(cases: ReadonlyArray<T>): EachFunctionReturn<T[]>;
(...args: [TemplateStringsArray, ...any]): EachFunctionReturn<any[]>;
}
interface TestCollectorCallable<C = {}> {
/**
* @deprecated Use options as the second argument instead
*/
<ExtraContext extends C>(name: string | Function, fn: TestFunction<ExtraContext>, options: TestOptions): void;
<ExtraContext extends C>(name: string | Function, fn?: TestFunction<ExtraContext>, options?: number | TestOptions): void;
<ExtraContext extends C>(name: string | Function, options?: TestOptions, fn?: TestFunction<ExtraContext>): void;
}
type ChainableTestAPI<ExtraContext = {}> = ChainableFunction<'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'fails', TestCollectorCallable<ExtraContext>, {
each: TestEachFunction;
}>;
interface TestOptions {
/**
* Test timeout.
*/
timeout?: number;
/**
* Times to retry the test if fails. Useful for making flaky tests more stable.
* When retries is up, the last test error will be thrown.
*
* @default 0
*/
retry?: number;
/**
* How many times the test will run.
* Only inner tests will repeat if set on `describe()`, nested `describe()` will inherit parent's repeat by default.
*
* @default 0
*/
repeats?: number;
/**
* Whether tests run concurrently.
* Tests inherit `concurrent` from `describe()` and nested `describe()` will inherit from parent's `concurrent`.
*/
concurrent?: boolean;
/**
* Whether tests run sequentially.
* Tests inherit `sequential` from `describe()` and nested `describe()` will inherit from parent's `sequential`.
*/
sequential?: boolean;
/**
* Whether the test should be skipped.
*/
skip?: boolean;
/**
* Should this test be the only one running in a suite.
*/
only?: boolean;
/**
* Whether the test should be skipped and marked as a todo.
*/
todo?: boolean;
/**
* Whether the test is expected to fail. If it does, the test will pass, otherwise it will fail.
*/
fails?: boolean;
}
interface ExtendedAPI<ExtraContext> {
skipIf: (condition: any) => ChainableTestAPI<ExtraContext>;
runIf: (condition: any) => ChainableTestAPI<ExtraContext>;
}
type CustomAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & ExtendedAPI<ExtraContext> & {
extend: <T extends Record<string, any> = {}>(fixtures: Fixtures<T, ExtraContext>) => CustomAPI<{
[K in keyof T | keyof ExtraContext]: K extends keyof T ? T[K] : K extends keyof ExtraContext ? ExtraContext[K] : never;
}>;
};
type TestAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & ExtendedAPI<ExtraContext> & {
extend: <T extends Record<string, any> = {}>(fixtures: Fixtures<T, ExtraContext>) => TestAPI<{
[K in keyof T | keyof ExtraContext]: K extends keyof T ? T[K] : K extends keyof ExtraContext ? ExtraContext[K] : never;
}>;
};
interface FixtureOptions {
/**
* Whether to automatically set up current fixture, even though it's not being used in tests.
*/
auto?: boolean;
}
type Use<T> = (value: T) => Promise<void>;
type FixtureFn<T, K extends keyof T, ExtraContext> = (context: Omit<T, K> & ExtraContext, use: Use<T[K]>) => Promise<void>;
type Fixture<T, K extends keyof T, ExtraContext = {}> = ((...args: any) => any) extends T[K] ? (T[K] extends any ? FixtureFn<T, K, Omit<ExtraContext, Exclude<keyof T, K>>> : never) : T[K] | (T[K] extends any ? FixtureFn<T, K, Omit<ExtraContext, Exclude<keyof T, K>>> : never);
type Fixtures<T extends Record<string, any>, ExtraContext = {}> = {
[K in keyof T]: Fixture<T, K, ExtraContext & ExtendedContext<Test>> | [Fixture<T, K, ExtraContext & ExtendedContext<Test>>, FixtureOptions?];
};
type InferFixturesTypes<T> = T extends TestAPI<infer C> ? C : T;
interface SuiteCollectorCallable<ExtraContext = {}> {
/**
* @deprecated Use options as the second argument instead
*/
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, fn: SuiteFactory<OverrideExtraContext>, options: TestOptions): SuiteCollector<OverrideExtraContext>;
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, fn?: SuiteFactory<OverrideExtraContext>, options?: number | TestOptions): SuiteCollector<OverrideExtraContext>;
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, options: TestOptions, fn?: SuiteFactory<OverrideExtraContext>): SuiteCollector<OverrideExtraContext>;
}
type ChainableSuiteAPI<ExtraContext = {}> = ChainableFunction<'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'shuffle', SuiteCollectorCallable<ExtraContext>, {
each: TestEachFunction;
}>;
type SuiteAPI<ExtraContext = {}> = ChainableSuiteAPI<ExtraContext> & {
skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
};
type HookListener<T extends any[], Return = void> = (...args: T) => Awaitable<Return>;
type HookCleanupCallback = (() => Awaitable<unknown>) | void;
interface SuiteHooks<ExtraContext = {}> {
beforeAll: HookListener<[Readonly<Suite | File>], HookCleanupCallback>[];
afterAll: HookListener<[Readonly<Suite | File>]>[];
beforeEach: HookListener<[ExtendedContext<Test | Custom> & ExtraContext, Readonly<Suite>], HookCleanupCallback>[];
afterEach: HookListener<[ExtendedContext<Test | Custom> & ExtraContext, Readonly<Suite>]>[];
}
interface TaskCustomOptions extends TestOptions {
concurrent?: boolean;
sequential?: boolean;
skip?: boolean;
only?: boolean;
todo?: boolean;
fails?: boolean;
each?: boolean;
meta?: Record<string, unknown>;
fixtures?: FixtureItem[];
handler?: (context: TaskContext<Custom>) => Awaitable<void>;
}
interface SuiteCollector<ExtraContext = {}> {
readonly name: string;
readonly mode: RunMode;
options?: TestOptions;
type: 'collector';
test: TestAPI<ExtraContext>;
tasks: (Suite | Custom<ExtraContext> | Test<ExtraContext> | SuiteCollector<ExtraContext>)[];
task: (name: string, options?: TaskCustomOptions) => Custom<ExtraContext>;
collect: (file?: File) => Promise<Suite>;
clear: () => void;
on: <T extends keyof SuiteHooks<ExtraContext>>(name: T, ...fn: SuiteHooks<ExtraContext>[T]) => void;
}
type SuiteFactory<ExtraContext = {}> = (test: TestAPI<ExtraContext>) => Awaitable<void>;
interface RuntimeContext {
tasks: (SuiteCollector | Test)[];
currentSuite: SuiteCollector | null;
}
interface TestContext {
}
interface TaskContext<Task extends Custom | Test = Custom | Test> {
/**
* Metadata of the current test
*/
task: Readonly<Task>;
/**
* Extract hooks on test failed
*/
onTestFailed: (fn: OnTestFailedHandler) => void;
/**
* Extract hooks on test failed
*/
onTestFinished: (fn: OnTestFinishedHandler) => void;
/**
* Mark tests as skipped. All execution after this call will be skipped.
*/
skip: () => void;
}
type ExtendedContext<T extends Custom | Test> = TaskContext<T> & TestContext;
type OnTestFailedHandler = (result: TaskResult) => Awaitable<void>;
type OnTestFinishedHandler = (result: TaskResult) => Awaitable<void>;
type SequenceHooks = 'stack' | 'list' | 'parallel';
type SequenceSetupFiles = 'list' | 'parallel';
export { type TaskContext as A, type SequenceHooks as B, type Custom as C, type DoneCallback as D, type ExtendedContext as E, type File as F, type SequenceSetupFiles as G, type HookListener as H, type InferFixturesTypes as I, type OnTestFailedHandler as O, type RunMode as R, type Suite as S, type Task as T, type Use as U, type Test as a, type ChainableFunction as b, createChainable as c, type SuiteAPI as d, type TestAPI as e, type SuiteCollector as f, type CustomAPI as g, type SuiteHooks as h, type OnTestFinishedHandler as i, type TaskState as j, type TaskBase as k, type TaskPopulated as l, type TaskMeta as m, type TaskResult as n, type TaskResultPack as o, type TestFunction as p, type TestOptions as q, type FixtureOptions as r, type FixtureFn as s, type Fixture as t, type Fixtures as u, type HookCleanupCallback as v, type TaskCustomOptions as w, type SuiteFactory as x, type RuntimeContext as y, type TestContext as z };
+121
View File
@@ -0,0 +1,121 @@
import { B as SequenceHooks, G as SequenceSetupFiles, F as File, T as Task, S as Suite, o as TaskResultPack, a as Test, C as Custom, A as TaskContext, E as ExtendedContext } from './tasks-K5XERDtv.js';
export { g as CustomAPI, D as DoneCallback, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, i as OnTestFinishedHandler, R as RunMode, y as RuntimeContext, d as SuiteAPI, f as SuiteCollector, x as SuiteFactory, h as SuiteHooks, k as TaskBase, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, j as TaskState, e as TestAPI, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-K5XERDtv.js';
import { DiffOptions } from '@vitest/utils/diff';
import '@vitest/utils';
interface VitestRunnerConfig {
root: string;
setupFiles: string[] | string;
name: string;
passWithNoTests: boolean;
testNamePattern?: RegExp;
allowOnly?: boolean;
sequence: {
shuffle?: boolean;
concurrent?: boolean;
seed: number;
hooks: SequenceHooks;
setupFiles: SequenceSetupFiles;
};
chaiConfig?: {
truncateThreshold?: number;
};
maxConcurrency: number;
testTimeout: number;
hookTimeout: number;
retry: number;
includeTaskLocation?: boolean;
diffOptions?: DiffOptions;
}
type VitestRunnerImportSource = 'collect' | 'setup';
interface VitestRunnerConstructor {
new (config: VitestRunnerConfig): VitestRunner;
}
type CancelReason = 'keyboard-input' | 'test-failure' | string & Record<string, never>;
interface VitestRunner {
/**
* First thing that's getting called before actually collecting and running tests.
*/
onBeforeCollect?: (paths: string[]) => unknown;
/**
* Called after collecting tests and before "onBeforeRun".
*/
onCollected?: (files: File[]) => unknown;
/**
* Called when test runner should cancel next test runs.
* Runner should listen for this method and mark tests and suites as skipped in
* "onBeforeRunSuite" and "onBeforeRunTask" when called.
*/
onCancel?: (reason: CancelReason) => unknown;
/**
* Called before running a single test. Doesn't have "result" yet.
*/
onBeforeRunTask?: (test: Task) => unknown;
/**
* Called before actually running the test function. Already has "result" with "state" and "startTime".
*/
onBeforeTryTask?: (test: Task, options: {
retry: number;
repeats: number;
}) => unknown;
/**
* Called after result and state are set.
*/
onAfterRunTask?: (test: Task) => unknown;
/**
* Called right after running the test function. Doesn't have new state yet. Will not be called, if the test function throws.
*/
onAfterTryTask?: (test: Task, options: {
retry: number;
repeats: number;
}) => unknown;
/**
* Called before running a single suite. Doesn't have "result" yet.
*/
onBeforeRunSuite?: (suite: Suite) => unknown;
/**
* Called after running a single suite. Has state and result.
*/
onAfterRunSuite?: (suite: Suite) => unknown;
/**
* If defined, will be called instead of usual Vitest suite partition and handling.
* "before" and "after" hooks will not be ignored.
*/
runSuite?: (suite: Suite) => Promise<void>;
/**
* If defined, will be called instead of usual Vitest handling. Useful, if you have your custom test function.
* "before" and "after" hooks will not be ignored.
*/
runTask?: (test: Task) => Promise<void>;
/**
* Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
*/
onTaskUpdate?: (task: TaskResultPack[]) => Promise<void>;
/**
* Called before running all tests in collected paths.
*/
onBeforeRunFiles?: (files: File[]) => unknown;
/**
* Called right after running all tests in collected paths.
*/
onAfterRunFiles?: (files: File[]) => unknown;
/**
* Called when new context for a test is defined. Useful, if you want to add custom properties to the context.
* If you only want to define custom context, consider using "beforeAll" in "setupFiles" instead.
*
* This method is called for both "test" and "custom" handlers.
*
* @see https://vitest.dev/advanced/runner.html#your-task-function
*/
extendTaskContext?: <T extends Test | Custom>(context: TaskContext<T>) => ExtendedContext<T>;
/**
* Called, when files are imported. Can be called in two situations: when collecting tests and when importing setup files.
*/
importFile: (filepath: string, source: VitestRunnerImportSource) => unknown;
/**
* Publicly available configuration.
*/
config: VitestRunnerConfig;
}
export { type CancelReason, Custom, ExtendedContext, File, SequenceHooks, SequenceSetupFiles, Suite, Task, TaskContext, TaskResultPack, Test, type VitestRunner, type VitestRunnerConfig, type VitestRunnerConstructor, type VitestRunnerImportSource };
+1
View File
@@ -0,0 +1 @@
+25
View File
@@ -0,0 +1,25 @@
import { S as Suite, T as Task, a as Test, C as Custom } from './tasks-K5XERDtv.js';
export { b as ChainableFunction, c as createChainable } from './tasks-K5XERDtv.js';
import { Arrayable } from '@vitest/utils';
/**
* If any tasks been marked as `only`, mark all other tasks as `skip`.
*/
declare function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, parentIsOnly?: boolean, allowOnly?: boolean): void;
declare function someTasksAreOnly(suite: Suite): boolean;
declare function generateHash(str: string): string;
declare function calculateSuiteHash(parent: Suite): void;
/**
* Partition in tasks groups by consecutive concurrent
*/
declare function partitionSuiteChildren(suite: Suite): Task[][];
declare function getTests(suite: Arrayable<Task>): (Test | Custom)[];
declare function getTasks(tasks?: Arrayable<Task>): Task[];
declare function getSuites(suite: Arrayable<Task>): Suite[];
declare function hasTests(suite: Arrayable<Suite>): boolean;
declare function hasFailed(suite: Arrayable<Task>): boolean;
declare function getNames(task: Task): string[];
export { calculateSuiteHash, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, partitionSuiteChildren, someTasksAreOnly };
+3
View File
@@ -0,0 +1,3 @@
export { c as calculateSuiteHash, j as createChainable, g as generateHash, f as getNames, d as getSuites, b as getTasks, a as getTests, e as hasFailed, h as hasTests, i as interpretTaskModes, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
import '@vitest/utils/error';
import '@vitest/utils';
+49
View File
@@ -0,0 +1,49 @@
{
"name": "@vitest/runner",
"type": "module",
"version": "1.6.1",
"description": "Vitest test runner",
"license": "MIT",
"funding": "https://opencollective.com/vitest",
"homepage": "https://github.com/vitest-dev/vitest/tree/main/packages/runner#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/vitest-dev/vitest.git",
"directory": "packages/runner"
},
"bugs": {
"url": "https://github.com/vitest-dev/vitest/issues"
},
"sideEffects": true,
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./utils": {
"types": "./dist/utils.d.ts",
"default": "./dist/utils.js"
},
"./types": {
"types": "./dist/types.d.ts",
"default": "./dist/types.js"
},
"./*": "./*"
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"*.d.ts",
"dist"
],
"dependencies": {
"p-limit": "^5.0.0",
"pathe": "^1.1.1",
"@vitest/utils": "1.6.1"
},
"scripts": {
"build": "rimraf dist && rollup -c",
"dev": "rollup -c --watch"
}
}
+1
View File
@@ -0,0 +1 @@
export * from './dist/types.js'
+1
View File
@@ -0,0 +1 @@
export * from './dist/utils.js'
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-Present Vitest Team
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.
+79
View File
@@ -0,0 +1,79 @@
# @vitest/snapshot
Lightweight implementation of Jest's snapshots.
## Usage
```js
import { SnapshotClient } from '@vitest/snapshot'
import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment'
import { SnapshotManager } from '@vitest/snapshot/manager'
const client = new SnapshotClient({
// you need to provide your own equality check implementation if you use it
// this function is called when `.toMatchSnapshot({ property: 1 })` is called
isEqual: (received, expected) => equals(received, expected, [iterableEquality, subsetEquality]),
})
// class that implements snapshot saving and reading
// by default uses fs module, but you can provide your own implementation depending on the environment
const environment = new NodeSnapshotEnvironment()
// you need to implement this yourselves,
// this depends on your runner
function getCurrentFilepath() {
return '/file.spec.js'
}
function getCurrentTestName() {
return 'test1'
}
// example for inline snapshots, nothing is required to support regular snapshots,
// just call `assert` with `isInline: false`
function wrapper(received) {
function __INLINE_SNAPSHOT__(inlineSnapshot, message) {
client.assert({
received,
message,
isInline: true,
inlineSnapshot,
filepath: getCurrentFilepath(),
name: getCurrentTestName(),
})
}
return {
// the name is hard-coded, it should be inside another function, so Vitest can find the actual test file where it was called (parses call stack trace + 2)
// you can override this behaviour in SnapshotState's `_inferInlineSnapshotStack` method by providing your own SnapshotState to SnapshotClient constructor
toMatchInlineSnapshot: (...args) => __INLINE_SNAPSHOT__(...args),
}
}
const options = {
updateSnapshot: 'new',
snapshotEnvironment: environment,
}
await client.startCurrentRun(getCurrentFilepath(), getCurrentTestName(), options)
// this will save snapshot to a file which is returned by "snapshotEnvironment.resolvePath"
client.assert({
received: 'some text',
isInline: false,
})
// uses "pretty-format", so it requires quotes
// also naming is hard-coded when parsing test files
wrapper('text 1').toMatchInlineSnapshot()
wrapper('text 2').toMatchInlineSnapshot('"text 2"')
const result = await client.finishCurrentRun() // this saves files and returns SnapshotResult
// you can use manager to manage several clients
const manager = new SnapshotManager(options)
manager.add(result)
// do something
// and then read the summary
console.log(manager.summary)
```
+14
View File
@@ -0,0 +1,14 @@
interface SnapshotEnvironment {
getVersion: () => string;
getHeader: () => string;
resolvePath: (filepath: string) => Promise<string>;
resolveRawPath: (testPath: string, rawPath: string) => Promise<string>;
saveSnapshotFile: (filepath: string, snapshot: string) => Promise<void>;
readSnapshotFile: (filepath: string) => Promise<string | null>;
removeSnapshotFile: (filepath: string) => Promise<void>;
}
interface SnapshotEnvironmentOptions {
snapshotsDirName?: string;
}
export type { SnapshotEnvironment as S, SnapshotEnvironmentOptions as a };
+16
View File
@@ -0,0 +1,16 @@
import { S as SnapshotEnvironment, a as SnapshotEnvironmentOptions } from './environment-cMiGIVXz.js';
declare class NodeSnapshotEnvironment implements SnapshotEnvironment {
private options;
constructor(options?: SnapshotEnvironmentOptions);
getVersion(): string;
getHeader(): string;
resolveRawPath(testPath: string, rawPath: string): Promise<string>;
resolvePath(filepath: string): Promise<string>;
prepareDirectory(dirPath: string): Promise<void>;
saveSnapshotFile(filepath: string, snapshot: string): Promise<void>;
readSnapshotFile(filepath: string): Promise<string | null>;
removeSnapshotFile(filepath: string): Promise<void>;
}
export { NodeSnapshotEnvironment, SnapshotEnvironment };
+44
View File
@@ -0,0 +1,44 @@
import { promises, existsSync } from 'node:fs';
import { isAbsolute, resolve, dirname, join, basename } from 'pathe';
class NodeSnapshotEnvironment {
constructor(options = {}) {
this.options = options;
}
getVersion() {
return "1";
}
getHeader() {
return `// Snapshot v${this.getVersion()}`;
}
async resolveRawPath(testPath, rawPath) {
return isAbsolute(rawPath) ? rawPath : resolve(dirname(testPath), rawPath);
}
async resolvePath(filepath) {
return join(
join(
dirname(filepath),
this.options.snapshotsDirName ?? "__snapshots__"
),
`${basename(filepath)}.snap`
);
}
async prepareDirectory(dirPath) {
await promises.mkdir(dirPath, { recursive: true });
}
async saveSnapshotFile(filepath, snapshot) {
await promises.mkdir(dirname(filepath), { recursive: true });
await promises.writeFile(filepath, snapshot, "utf-8");
}
async readSnapshotFile(filepath) {
if (!existsSync(filepath))
return null;
return promises.readFile(filepath, "utf-8");
}
async removeSnapshotFile(filepath) {
if (existsSync(filepath))
await promises.unlink(filepath);
}
}
export { NodeSnapshotEnvironment };
+60
View File
@@ -0,0 +1,60 @@
import { Plugin, OptionsReceived } from 'pretty-format';
import { S as SnapshotEnvironment } from './environment-cMiGIVXz.js';
interface RawSnapshotInfo {
file: string;
readonly?: boolean;
content?: string;
}
type SnapshotData = Record<string, string>;
type SnapshotUpdateState = 'all' | 'new' | 'none';
type SnapshotSerializer = Plugin;
interface SnapshotStateOptions {
updateSnapshot: SnapshotUpdateState;
snapshotEnvironment: SnapshotEnvironment;
expand?: boolean;
snapshotFormat?: OptionsReceived;
resolveSnapshotPath?: (path: string, extension: string) => string;
}
interface SnapshotMatchOptions {
testName: string;
received: unknown;
key?: string;
inlineSnapshot?: string;
isInline: boolean;
error?: Error;
rawSnapshot?: RawSnapshotInfo;
}
interface SnapshotResult {
filepath: string;
added: number;
fileDeleted: boolean;
matched: number;
unchecked: number;
uncheckedKeys: Array<string>;
unmatched: number;
updated: number;
}
interface UncheckedSnapshot {
filePath: string;
keys: Array<string>;
}
interface SnapshotSummary {
added: number;
didUpdate: boolean;
failure: boolean;
filesAdded: number;
filesRemoved: number;
filesRemovedList: Array<string>;
filesUnmatched: number;
filesUpdated: number;
matched: number;
total: number;
unchecked: number;
uncheckedKeysByFile: Array<UncheckedSnapshot>;
unmatched: number;
updated: number;
}
export type { RawSnapshotInfo as R, SnapshotStateOptions as S, UncheckedSnapshot as U, SnapshotMatchOptions as a, SnapshotResult as b, SnapshotData as c, SnapshotUpdateState as d, SnapshotSerializer as e, SnapshotSummary as f };
+109
View File
@@ -0,0 +1,109 @@
import { S as SnapshotStateOptions, a as SnapshotMatchOptions, b as SnapshotResult, R as RawSnapshotInfo } from './index-S94ASl6q.js';
export { c as SnapshotData, e as SnapshotSerializer, f as SnapshotSummary, d as SnapshotUpdateState, U as UncheckedSnapshot } from './index-S94ASl6q.js';
import { S as SnapshotEnvironment } from './environment-cMiGIVXz.js';
import { Plugin, Plugins } from 'pretty-format';
interface ParsedStack {
method: string;
file: string;
line: number;
column: number;
}
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
interface SnapshotReturnOptions {
actual: string;
count: number;
expected?: string;
key: string;
pass: boolean;
}
interface SaveStatus {
deleted: boolean;
saved: boolean;
}
declare class SnapshotState {
testFilePath: string;
snapshotPath: string;
private _counters;
private _dirty;
private _updateSnapshot;
private _snapshotData;
private _initialData;
private _inlineSnapshots;
private _rawSnapshots;
private _uncheckedKeys;
private _snapshotFormat;
private _environment;
private _fileExists;
added: number;
expand: boolean;
matched: number;
unmatched: number;
updated: number;
private constructor();
static create(testFilePath: string, options: SnapshotStateOptions): Promise<SnapshotState>;
get environment(): SnapshotEnvironment;
markSnapshotsAsCheckedForTest(testName: string): void;
protected _inferInlineSnapshotStack(stacks: ParsedStack[]): ParsedStack | null;
private _addSnapshot;
clear(): void;
save(): Promise<SaveStatus>;
getUncheckedCount(): number;
getUncheckedKeys(): Array<string>;
removeUncheckedKeys(): void;
match({ testName, received, key, inlineSnapshot, isInline, error, rawSnapshot, }: SnapshotMatchOptions): SnapshotReturnOptions;
pack(): Promise<SnapshotResult>;
}
interface AssertOptions {
received: unknown;
filepath?: string;
name?: string;
message?: string;
isInline?: boolean;
properties?: object;
inlineSnapshot?: string;
error?: Error;
errorMessage?: string;
rawSnapshot?: RawSnapshotInfo;
}
interface SnapshotClientOptions {
isEqual?: (received: unknown, expected: unknown) => boolean;
}
declare class SnapshotClient {
private options;
filepath?: string;
name?: string;
snapshotState: SnapshotState | undefined;
snapshotStateMap: Map<string, SnapshotState>;
constructor(options?: SnapshotClientOptions);
startCurrentRun(filepath: string, name: string, options: SnapshotStateOptions): Promise<void>;
getSnapshotState(filepath: string): SnapshotState;
clearTest(): void;
skipTestSnapshots(name: string): void;
assert(options: AssertOptions): void;
assertRaw(options: AssertOptions): Promise<void>;
finishCurrentRun(): Promise<SnapshotResult | null>;
clear(): void;
}
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
declare function addSerializer(plugin: Plugin): void;
declare function getSerializers(): Plugins;
declare function stripSnapshotIndentation(inlineSnapshot: string): string;
export { SnapshotClient, SnapshotMatchOptions, SnapshotResult, SnapshotState, SnapshotStateOptions, addSerializer, getSerializers, stripSnapshotIndentation };
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
import { S as SnapshotStateOptions, f as SnapshotSummary, b as SnapshotResult } from './index-S94ASl6q.js';
import 'pretty-format';
import './environment-cMiGIVXz.js';
declare class SnapshotManager {
options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>;
summary: SnapshotSummary;
extension: string;
constructor(options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>);
clear(): void;
add(result: SnapshotResult): void;
resolvePath(testPath: string): string;
resolveRawPath(testPath: string, rawPath: string): string;
}
declare function emptySummary(options: Omit<SnapshotStateOptions, 'snapshotEnvironment'>): SnapshotSummary;
declare function addSnapshotResult(summary: SnapshotSummary, result: SnapshotResult): void;
export { SnapshotManager, addSnapshotResult, emptySummary };
+75
View File
@@ -0,0 +1,75 @@
import { join, dirname, basename, isAbsolute, resolve } from 'pathe';
class SnapshotManager {
constructor(options) {
this.options = options;
this.clear();
}
summary = void 0;
extension = ".snap";
clear() {
this.summary = emptySummary(this.options);
}
add(result) {
addSnapshotResult(this.summary, result);
}
resolvePath(testPath) {
const resolver = this.options.resolveSnapshotPath || (() => {
return join(
join(
dirname(testPath),
"__snapshots__"
),
`${basename(testPath)}${this.extension}`
);
});
const path = resolver(testPath, this.extension);
return path;
}
resolveRawPath(testPath, rawPath) {
return isAbsolute(rawPath) ? rawPath : resolve(dirname(testPath), rawPath);
}
}
function emptySummary(options) {
const summary = {
added: 0,
failure: false,
filesAdded: 0,
filesRemoved: 0,
filesRemovedList: [],
filesUnmatched: 0,
filesUpdated: 0,
matched: 0,
total: 0,
unchecked: 0,
uncheckedKeysByFile: [],
unmatched: 0,
updated: 0,
didUpdate: options.updateSnapshot === "all"
};
return summary;
}
function addSnapshotResult(summary, result) {
if (result.added)
summary.filesAdded++;
if (result.fileDeleted)
summary.filesRemoved++;
if (result.unmatched)
summary.filesUnmatched++;
if (result.updated)
summary.filesUpdated++;
summary.added += result.added;
summary.matched += result.matched;
summary.unchecked += result.unchecked;
if (result.uncheckedKeys && result.uncheckedKeys.length > 0) {
summary.uncheckedKeysByFile.push({
filePath: result.filepath,
keys: result.uncheckedKeys
});
}
summary.unmatched += result.unmatched;
summary.updated += result.updated;
summary.total += result.added + result.matched + result.unmatched + result.updated;
}
export { SnapshotManager, addSnapshotResult, emptySummary };
+1
View File
@@ -0,0 +1 @@
export * from './dist/environment.js'
+1
View File
@@ -0,0 +1 @@
export * from './dist/manager.js'
@@ -0,0 +1,167 @@
declare namespace ansiStyles {
interface CSPair {
/**
The ANSI terminal control sequence for starting this style.
*/
readonly open: string;
/**
The ANSI terminal control sequence for ending this style.
*/
readonly close: string;
}
interface ColorBase {
/**
The ANSI terminal control sequence for ending this color.
*/
readonly close: string;
ansi256(code: number): string;
ansi16m(red: number, green: number, blue: number): string;
}
interface Modifier {
/**
Resets the current color chain.
*/
readonly reset: CSPair;
/**
Make text bold.
*/
readonly bold: CSPair;
/**
Emitting only a small amount of light.
*/
readonly dim: CSPair;
/**
Make text italic. (Not widely supported)
*/
readonly italic: CSPair;
/**
Make text underline. (Not widely supported)
*/
readonly underline: CSPair;
/**
Make text overline.
Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.
*/
readonly overline: CSPair;
/**
Inverse background and foreground colors.
*/
readonly inverse: CSPair;
/**
Prints the text, but makes it invisible.
*/
readonly hidden: CSPair;
/**
Puts a horizontal line through the center of the text. (Not widely supported)
*/
readonly strikethrough: CSPair;
}
interface ForegroundColor {
readonly black: CSPair;
readonly red: CSPair;
readonly green: CSPair;
readonly yellow: CSPair;
readonly blue: CSPair;
readonly cyan: CSPair;
readonly magenta: CSPair;
readonly white: CSPair;
/**
Alias for `blackBright`.
*/
readonly gray: CSPair;
/**
Alias for `blackBright`.
*/
readonly grey: CSPair;
readonly blackBright: CSPair;
readonly redBright: CSPair;
readonly greenBright: CSPair;
readonly yellowBright: CSPair;
readonly blueBright: CSPair;
readonly cyanBright: CSPair;
readonly magentaBright: CSPair;
readonly whiteBright: CSPair;
}
interface BackgroundColor {
readonly bgBlack: CSPair;
readonly bgRed: CSPair;
readonly bgGreen: CSPair;
readonly bgYellow: CSPair;
readonly bgBlue: CSPair;
readonly bgCyan: CSPair;
readonly bgMagenta: CSPair;
readonly bgWhite: CSPair;
/**
Alias for `bgBlackBright`.
*/
readonly bgGray: CSPair;
/**
Alias for `bgBlackBright`.
*/
readonly bgGrey: CSPair;
readonly bgBlackBright: CSPair;
readonly bgRedBright: CSPair;
readonly bgGreenBright: CSPair;
readonly bgYellowBright: CSPair;
readonly bgBlueBright: CSPair;
readonly bgCyanBright: CSPair;
readonly bgMagentaBright: CSPair;
readonly bgWhiteBright: CSPair;
}
interface ConvertColor {
/**
Convert from the RGB color space to the ANSI 256 color space.
@param red - (`0...255`)
@param green - (`0...255`)
@param blue - (`0...255`)
*/
rgbToAnsi256(red: number, green: number, blue: number): number;
/**
Convert from the RGB HEX color space to the RGB color space.
@param hex - A hexadecimal string containing RGB data.
*/
hexToRgb(hex: string): [red: number, green: number, blue: number];
/**
Convert from the RGB HEX color space to the ANSI 256 color space.
@param hex - A hexadecimal string containing RGB data.
*/
hexToAnsi256(hex: string): number;
}
}
declare const ansiStyles: {
readonly modifier: ansiStyles.Modifier;
readonly color: ansiStyles.ForegroundColor & ansiStyles.ColorBase;
readonly bgColor: ansiStyles.BackgroundColor & ansiStyles.ColorBase;
readonly codes: ReadonlyMap<number, number>;
} & ansiStyles.BackgroundColor & ansiStyles.ForegroundColor & ansiStyles.Modifier & ansiStyles.ConvertColor;
export = ansiStyles;
@@ -0,0 +1,164 @@
'use strict';
const ANSI_BACKGROUND_OFFSET = 10;
const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
function assembleStyles() {
const codes = new Map();
const styles = {
modifier: {
reset: [0, 0],
// 21 isn't widely supported and 22 does the same thing
bold: [1, 22],
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
overline: [53, 55],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29]
},
color: {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
// Bright color
blackBright: [90, 39],
redBright: [91, 39],
greenBright: [92, 39],
yellowBright: [93, 39],
blueBright: [94, 39],
magentaBright: [95, 39],
cyanBright: [96, 39],
whiteBright: [97, 39]
},
bgColor: {
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49],
// Bright color
bgBlackBright: [100, 49],
bgRedBright: [101, 49],
bgGreenBright: [102, 49],
bgYellowBright: [103, 49],
bgBlueBright: [104, 49],
bgMagentaBright: [105, 49],
bgCyanBright: [106, 49],
bgWhiteBright: [107, 49]
}
};
// Alias bright black as gray (and grey)
styles.color.gray = styles.color.blackBright;
styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
styles.color.grey = styles.color.blackBright;
styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
for (const [groupName, group] of Object.entries(styles)) {
for (const [styleName, style] of Object.entries(group)) {
styles[styleName] = {
open: `\u001B[${style[0]}m`,
close: `\u001B[${style[1]}m`
};
group[styleName] = styles[styleName];
codes.set(style[0], style[1]);
}
Object.defineProperty(styles, groupName, {
value: group,
enumerable: false
});
}
Object.defineProperty(styles, 'codes', {
value: codes,
enumerable: false
});
styles.color.close = '\u001B[39m';
styles.bgColor.close = '\u001B[49m';
styles.color.ansi256 = wrapAnsi256();
styles.color.ansi16m = wrapAnsi16m();
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
Object.defineProperties(styles, {
rgbToAnsi256: {
value: (red, green, blue) => {
// We use the extended greyscale palette here, with the exception of
// black and white. normal palette only has 4 greyscale shades.
if (red === green && green === blue) {
if (red < 8) {
return 16;
}
if (red > 248) {
return 231;
}
return Math.round(((red - 8) / 247) * 24) + 232;
}
return 16 +
(36 * Math.round(red / 255 * 5)) +
(6 * Math.round(green / 255 * 5)) +
Math.round(blue / 255 * 5);
},
enumerable: false
},
hexToRgb: {
value: hex => {
const matches = /(?<colorString>[a-f\d]{6}|[a-f\d]{3})/i.exec(hex.toString(16));
if (!matches) {
return [0, 0, 0];
}
let {colorString} = matches.groups;
if (colorString.length === 3) {
colorString = colorString.split('').map(character => character + character).join('');
}
const integer = Number.parseInt(colorString, 16);
return [
(integer >> 16) & 0xFF,
(integer >> 8) & 0xFF,
integer & 0xFF
];
},
enumerable: false
},
hexToAnsi256: {
value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
enumerable: false
}
});
return styles;
}
// Make the export immutable
Object.defineProperty(module, 'exports', {
enumerable: true,
get: assembleStyles
});
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
@@ -0,0 +1,52 @@
{
"name": "ansi-styles",
"version": "5.2.0",
"description": "ANSI escape codes for styling strings in the terminal",
"license": "MIT",
"repository": "chalk/ansi-styles",
"funding": "https://github.com/chalk/ansi-styles?sponsor=1",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"engines": {
"node": ">=10"
},
"scripts": {
"test": "xo && ava && tsd",
"screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"ansi",
"styles",
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"tty",
"escape",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"log",
"logging",
"command-line",
"text"
],
"devDependencies": {
"ava": "^2.4.0",
"svg-term-cli": "^2.1.1",
"tsd": "^0.14.0",
"xo": "^0.37.1"
}
}
@@ -0,0 +1,144 @@
# ansi-styles
> [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal
You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.
<img src="screenshot.svg" width="900">
## Install
```
$ npm install ansi-styles
```
## Usage
```js
const style = require('ansi-styles');
console.log(`${style.green.open}Hello world!${style.green.close}`);
// Color conversion between 256/truecolor
// NOTE: When converting from truecolor to 256 colors, the original color
// may be degraded to fit the new color palette. This means terminals
// that do not support 16 million colors will best-match the
// original color.
console.log(`${style.color.ansi256(style.rgbToAnsi256(199, 20, 250))}Hello World${style.color.close}`)
console.log(`${style.color.ansi16m(...style.hexToRgb('#abcdef'))}Hello World${style.color.close}`)
```
## API
Each style has an `open` and `close` property.
## Styles
### Modifiers
- `reset`
- `bold`
- `dim`
- `italic` *(Not widely supported)*
- `underline`
- `overline` *Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.*
- `inverse`
- `hidden`
- `strikethrough` *(Not widely supported)*
### Colors
- `black`
- `red`
- `green`
- `yellow`
- `blue`
- `magenta`
- `cyan`
- `white`
- `blackBright` (alias: `gray`, `grey`)
- `redBright`
- `greenBright`
- `yellowBright`
- `blueBright`
- `magentaBright`
- `cyanBright`
- `whiteBright`
### Background colors
- `bgBlack`
- `bgRed`
- `bgGreen`
- `bgYellow`
- `bgBlue`
- `bgMagenta`
- `bgCyan`
- `bgWhite`
- `bgBlackBright` (alias: `bgGray`, `bgGrey`)
- `bgRedBright`
- `bgGreenBright`
- `bgYellowBright`
- `bgBlueBright`
- `bgMagentaBright`
- `bgCyanBright`
- `bgWhiteBright`
## Advanced usage
By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.
- `style.modifier`
- `style.color`
- `style.bgColor`
###### Example
```js
console.log(style.color.green.open);
```
Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values.
###### Example
```js
console.log(style.codes.get(36));
//=> 39
```
## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
`ansi-styles` allows converting between various color formats and ANSI escapes, with support for 256 and 16 million colors.
The following color spaces from `color-convert` are supported:
- `rgb`
- `hex`
- `ansi256`
To use these, call the associated conversion function with the intended output, for example:
```js
style.color.ansi256(style.rgbToAnsi256(100, 200, 15)); // RGB to 256 color ansi foreground code
style.bgColor.ansi256(style.hexToAnsi256('#C0FFEE')); // HEX to 256 color ansi foreground code
style.color.ansi16m(100, 200, 15); // RGB to 16 million color foreground code
style.bgColor.ansi16m(...style.hexToRgb('#C0FFEE')); // Hex (RGB) to 16 million color foreground code
```
## Related
- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal
## Maintainers
- [Sindre Sorhus](https://github.com/sindresorhus)
- [Josh Junon](https://github.com/qix-)
## For enterprise
Available as part of the Tidelift Subscription.
The maintainers of `ansi-styles` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-ansi-styles?utm_source=npm-ansi-styles&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
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.
+463
View File
@@ -0,0 +1,463 @@
# pretty-format
Stringify any JavaScript value.
- Serialize built-in JavaScript types.
- Serialize application-specific data types with built-in or user-defined plugins.
## Installation
```sh
$ yarn add pretty-format
```
## Usage
```js
const {format: prettyFormat} = require('pretty-format'); // CommonJS
```
```js
import {format as prettyFormat} from 'pretty-format'; // ES2015 modules
```
```js
const val = {object: {}};
val.circularReference = val;
val[Symbol('foo')] = 'foo';
val.map = new Map([['prop', 'value']]);
val.array = [-0, Infinity, NaN];
console.log(prettyFormat(val));
/*
Object {
"array": Array [
-0,
Infinity,
NaN,
],
"circularReference": [Circular],
"map": Map {
"prop" => "value",
},
"object": Object {},
Symbol(foo): "foo",
}
*/
```
## Usage with options
```js
function onClick() {}
console.log(prettyFormat(onClick));
/*
[Function onClick]
*/
const options = {
printFunctionName: false,
};
console.log(prettyFormat(onClick, options));
/*
[Function]
*/
```
<!-- prettier-ignore -->
| key | type | default | description |
| :-------------------- | :--------------- | :---------- | :-------------------------------------------------------------------------------------- |
| `callToJSON` | `boolean` | `true` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function\|null` | `undefined` | compare function used when sorting object keys, `null` can be used to skip over sorting |
| `escapeRegex` | `boolean` | `false` | escape special characters in regular expressions |
| `escapeString` | `boolean` | `true` | escape special characters in strings |
| `highlight` | `boolean` | `false` | highlight syntax with colors in terminal (some plugins) |
| `indent` | `number` | `2` | spaces in each level of indentation |
| `maxDepth` | `number` | `Infinity` | levels to print in arrays, objects, elements, and so on |
| `maxWidth` | `number` | `Infinity` | number of elements to print in arrays, sets, and so on |
| `min` | `boolean` | `false` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | `[]` | plugins to serialize application-specific data types |
| `printBasicPrototype` | `boolean` | `false` | print the prototype for plain objects and arrays |
| `printFunctionName` | `boolean` | `true` | include or omit the name of a function |
| `theme` | `object` | | colors to highlight syntax in terminal |
Property values of `theme` are from [ansi-styles colors](https://github.com/chalk/ansi-styles#colors)
```js
const DEFAULT_THEME = {
comment: 'gray',
content: 'reset',
prop: 'yellow',
tag: 'cyan',
value: 'green',
};
```
## Usage with plugins
The `pretty-format` package provides some built-in plugins, including:
- `ReactElement` for elements from `react`
- `ReactTestComponent` for test objects from `react-test-renderer`
```js
// CommonJS
const React = require('react');
const renderer = require('react-test-renderer');
const {format: prettyFormat, plugins} = require('pretty-format');
const {ReactElement, ReactTestComponent} = plugins;
```
```js
// ES2015 modules and destructuring assignment
import React from 'react';
import renderer from 'react-test-renderer';
import {plugins, format as prettyFormat} from 'pretty-format';
const {ReactElement, ReactTestComponent} = plugins;
```
```js
const onClick = () => {};
const element = React.createElement('button', {onClick}, 'Hello World');
const formatted1 = prettyFormat(element, {
plugins: [ReactElement],
printFunctionName: false,
});
const formatted2 = prettyFormat(renderer.create(element).toJSON(), {
plugins: [ReactTestComponent],
printFunctionName: false,
});
/*
<button
onClick=[Function]
>
Hello World
</button>
*/
```
## Usage in Jest
For snapshot tests, Jest uses `pretty-format` with options that include some of its built-in plugins. For this purpose, plugins are also known as **snapshot serializers**.
To serialize application-specific data types, you can add modules to `devDependencies` of a project, and then:
In an **individual** test file, you can add a module as follows. It precedes any modules from Jest configuration.
```js
import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);
// tests which have `expect(value).toMatchSnapshot()` assertions
```
For **all** test files, you can specify modules in Jest configuration. They precede built-in plugins for React, HTML, and Immutable.js data types. For example, in a `package.json` file:
```json
{
"jest": {
"snapshotSerializers": ["my-serializer-module"]
}
}
```
## Writing plugins
A plugin is a JavaScript object.
If `options` has a `plugins` array: for the first plugin whose `test(val)` method returns a truthy value, then `prettyFormat(val, options)` returns the result from either:
- `serialize(val, …)` method of the **improved** interface (available in **version 21** or later)
- `print(val, …)` method of the **original** interface (if plugin does not have `serialize` method)
### test
Write `test` so it can receive `val` argument of any type. To serialize **objects** which have certain properties, then a guarded expression like `val != null && …` or more concise `val && …` prevents the following errors:
- `TypeError: Cannot read property 'whatever' of null`
- `TypeError: Cannot read property 'whatever' of undefined`
For example, `test` method of built-in `ReactElement` plugin:
```js
const elementSymbol = Symbol.for('react.element');
const test = val => val && val.$$typeof === elementSymbol;
```
Pay attention to efficiency in `test` because `pretty-format` calls it often.
### serialize
The **improved** interface is available in **version 21** or later.
Write `serialize` to return a string, given the arguments:
- `val` which “passed the test”
- unchanging `config` object: derived from `options`
- current `indentation` string: concatenate to `indent` from `config`
- current `depth` number: compare to `maxDepth` from `config`
- current `refs` array: find circular references in objects
- `printer` callback function: serialize children
### config
<!-- prettier-ignore -->
| key | type | description |
| :------------------ | :--------------- | :-------------------------------------------------------------------------------------- |
| `callToJSON` | `boolean` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function\|null` | compare function used when sorting object keys, `null` can be used to skip over sorting |
| `colors` | `Object` | escape codes for colors to highlight syntax |
| `escapeRegex` | `boolean` | escape special characters in regular expressions |
| `escapeString` | `boolean` | escape special characters in strings |
| `indent` | `string` | spaces in each level of indentation |
| `maxDepth` | `number` | levels to print in arrays, objects, elements, and so on |
| `min` | `boolean` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | plugins to serialize application-specific data types |
| `printFunctionName` | `boolean` | include or omit the name of a function |
| `spacingInner` | `string` | spacing to separate items in a list |
| `spacingOuter` | `string` | spacing to enclose a list of items |
Each property of `colors` in `config` corresponds to a property of `theme` in `options`:
- the key is the same (for example, `tag`)
- the value in `colors` is a object with `open` and `close` properties whose values are escape codes from [ansi-styles](https://github.com/chalk/ansi-styles) for the color value in `theme` (for example, `'cyan'`)
Some properties in `config` are derived from `min` in `options`:
- `spacingInner` and `spacingOuter` are **newline** if `min` is `false`
- `spacingInner` is **space** and `spacingOuter` is **empty string** if `min` is `true`
### Example of serialize and test
This plugin is a pattern you can apply to serialize composite data types. Side note: `pretty-format` does not need a plugin to serialize arrays.
```js
// We reused more code when we factored out a function for child items
// that is independent of depth, name, and enclosing punctuation (see below).
const SEPARATOR = ',';
function serializeItems(items, config, indentation, depth, refs, printer) {
if (items.length === 0) {
return '';
}
const indentationItems = indentation + config.indent;
return (
config.spacingOuter +
items
.map(
item =>
indentationItems +
printer(item, config, indentationItems, depth, refs), // callback
)
.join(SEPARATOR + config.spacingInner) +
(config.min ? '' : SEPARATOR) + // following the last item
config.spacingOuter +
indentation
);
}
const plugin = {
test(val) {
return Array.isArray(val);
},
serialize(array, config, indentation, depth, refs, printer) {
const name = array.constructor.name;
return ++depth > config.maxDepth
? `[${name}]`
: `${config.min ? '' : `${name} `}[${serializeItems(
array,
config,
indentation,
depth,
refs,
printer,
)}]`;
},
};
```
```js
const val = {
filter: 'completed',
items: [
{
text: 'Write test',
completed: true,
},
{
text: 'Write serialize',
completed: true,
},
],
};
```
```js
console.log(
prettyFormat(val, {
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": Array [
Object {
"completed": true,
"text": "Write test",
},
Object {
"completed": true,
"text": "Write serialize",
},
],
}
*/
```
```js
console.log(
prettyFormat(val, {
indent: 4,
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": Array [
Object {
"completed": true,
"text": "Write test",
},
Object {
"completed": true,
"text": "Write serialize",
},
],
}
*/
```
```js
console.log(
prettyFormat(val, {
maxDepth: 1,
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": [Array],
}
*/
```
```js
console.log(
prettyFormat(val, {
min: true,
plugins: [plugin],
}),
);
/*
{"filter": "completed", "items": [{"completed": true, "text": "Write test"}, {"completed": true, "text": "Write serialize"}]}
*/
```
### print
The **original** interface is adequate for plugins:
- that **do not** depend on options other than `highlight` or `min`
- that **do not** depend on `depth` or `refs` in recursive traversal, and
- if values either
- do **not** require indentation, or
- do **not** occur as children of JavaScript data structures (for example, array)
Write `print` to return a string, given the arguments:
- `val` which “passed the test”
- current `printer(valChild)` callback function: serialize children
- current `indenter(lines)` callback function: indent lines at the next level
- unchanging `config` object: derived from `options`
- unchanging `colors` object: derived from `options`
The 3 properties of `config` are `min` in `options` and:
- `spacing` and `edgeSpacing` are **newline** if `min` is `false`
- `spacing` is **space** and `edgeSpacing` is **empty string** if `min` is `true`
Each property of `colors` corresponds to a property of `theme` in `options`:
- the key is the same (for example, `tag`)
- the value in `colors` is a object with `open` and `close` properties whose values are escape codes from [ansi-styles](https://github.com/chalk/ansi-styles) for the color value in `theme` (for example, `'cyan'`)
### Example of print and test
This plugin prints functions with the **number of named arguments** excluding rest argument.
```js
const plugin = {
print(val) {
return `[Function ${val.name || 'anonymous'} ${val.length}]`;
},
test(val) {
return typeof val === 'function';
},
};
```
```js
const val = {
onClick(event) {},
render() {},
};
prettyFormat(val, {
plugins: [plugin],
});
/*
Object {
"onClick": [Function onClick 1],
"render": [Function render 0],
}
*/
prettyFormat(val);
/*
Object {
"onClick": [Function onClick],
"render": [Function render],
}
*/
```
This plugin **ignores** the `printFunctionName` option. That limitation of the original `print` interface is a reason to use the improved `serialize` interface, described above.
```js
prettyFormat(val, {
plugins: [pluginOld],
printFunctionName: false,
});
/*
Object {
"onClick": [Function onClick 1],
"render": [Function render 0],
}
*/
prettyFormat(val, {
printFunctionName: false,
});
/*
Object {
"onClick": [Function],
"render": [Function],
}
*/
```
@@ -0,0 +1,180 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.printIteratorEntries = printIteratorEntries;
exports.printIteratorValues = printIteratorValues;
exports.printListItems = printListItems;
exports.printObjectProperties = printObjectProperties;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const getKeysOfEnumerableProperties = (object, compareKeys) => {
const rawKeys = Object.keys(object);
const keys = compareKeys !== null ? rawKeys.sort(compareKeys) : rawKeys;
if (Object.getOwnPropertySymbols) {
Object.getOwnPropertySymbols(object).forEach(symbol => {
if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) {
keys.push(symbol);
}
});
}
return keys;
};
/**
* Return entries (for example, of a map)
* with spacing, indentation, and comma
* without surrounding punctuation (for example, braces)
*/
function printIteratorEntries(
iterator,
config,
indentation,
depth,
refs,
printer,
// Too bad, so sad that separator for ECMAScript Map has been ' => '
// What a distracting diff if you change a data structure to/from
// ECMAScript Object or Immutable.Map/OrderedMap which use the default.
separator = ': '
) {
let result = '';
let width = 0;
let current = iterator.next();
if (!current.done) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
while (!current.done) {
result += indentationNext;
if (width++ === config.maxWidth) {
result += '…';
break;
}
const name = printer(
current.value[0],
config,
indentationNext,
depth,
refs
);
const value = printer(
current.value[1],
config,
indentationNext,
depth,
refs
);
result += name + separator + value;
current = iterator.next();
if (!current.done) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
/**
* Return values (for example, of a set)
* with spacing, indentation, and comma
* without surrounding punctuation (braces or brackets)
*/
function printIteratorValues(
iterator,
config,
indentation,
depth,
refs,
printer
) {
let result = '';
let width = 0;
let current = iterator.next();
if (!current.done) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
while (!current.done) {
result += indentationNext;
if (width++ === config.maxWidth) {
result += '…';
break;
}
result += printer(current.value, config, indentationNext, depth, refs);
current = iterator.next();
if (!current.done) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
/**
* Return items (for example, of an array)
* with spacing, indentation, and comma
* without surrounding punctuation (for example, brackets)
**/
function printListItems(list, config, indentation, depth, refs, printer) {
let result = '';
if (list.length) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
for (let i = 0; i < list.length; i++) {
result += indentationNext;
if (i === config.maxWidth) {
result += '…';
break;
}
if (i in list) {
result += printer(list[i], config, indentationNext, depth, refs);
}
if (i < list.length - 1) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
/**
* Return properties of an object
* with spacing, indentation, and comma
* without surrounding punctuation (for example, braces)
*/
function printObjectProperties(val, config, indentation, depth, refs, printer) {
let result = '';
const keys = getKeysOfEnumerableProperties(val, config.compareKeys);
if (keys.length) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const name = printer(key, config, indentationNext, depth, refs);
const value = printer(val[key], config, indentationNext, depth, refs);
result += `${indentationNext + name}: ${value}`;
if (i < keys.length - 1) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
@@ -0,0 +1,163 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type {SnapshotFormat} from '@jest/schemas';
export declare type Colors = {
comment: {
close: string;
open: string;
};
content: {
close: string;
open: string;
};
prop: {
close: string;
open: string;
};
tag: {
close: string;
open: string;
};
value: {
close: string;
open: string;
};
};
export declare type CompareKeys =
| ((a: string, b: string) => number)
| null
| undefined;
export declare type Config = {
callToJSON: boolean;
compareKeys: CompareKeys;
colors: Colors;
escapeRegex: boolean;
escapeString: boolean;
indent: string;
maxDepth: number;
maxWidth: number;
min: boolean;
plugins: Plugins;
printBasicPrototype: boolean;
printFunctionName: boolean;
spacingInner: string;
spacingOuter: string;
};
export declare const DEFAULT_OPTIONS: {
callToJSON: true;
compareKeys: undefined;
escapeRegex: false;
escapeString: true;
highlight: false;
indent: number;
maxDepth: number;
maxWidth: number;
min: false;
plugins: never[];
printBasicPrototype: true;
printFunctionName: true;
theme: Required<{
readonly comment?: string | undefined;
readonly content?: string | undefined;
readonly prop?: string | undefined;
readonly tag?: string | undefined;
readonly value?: string | undefined;
}>;
};
/**
* Returns a presentation string of your `val` object
* @param val any potential JavaScript object
* @param options Custom settings
*/
declare function format(val: unknown, options?: OptionsReceived): string;
export default format;
export {format};
declare type Indent = (arg0: string) => string;
export declare type NewPlugin = {
serialize: (
val: any,
config: Config,
indentation: string,
depth: number,
refs: Refs,
printer: Printer,
) => string;
test: Test;
};
export declare type OldPlugin = {
print: (
val: unknown,
print: Print,
indent: Indent,
options: PluginOptions,
colors: Colors,
) => string;
test: Test;
};
export declare interface Options
extends Omit<RequiredOptions, 'compareKeys' | 'theme'> {
compareKeys: CompareKeys;
theme: Required<RequiredOptions['theme']>;
}
export declare type OptionsReceived = PrettyFormatOptions;
declare type Plugin_2 = NewPlugin | OldPlugin;
export {Plugin_2 as Plugin};
declare type PluginOptions = {
edgeSpacing: string;
min: boolean;
spacing: string;
};
export declare type Plugins = Array<Plugin_2>;
export declare const plugins: {
AsymmetricMatcher: NewPlugin;
DOMCollection: NewPlugin;
DOMElement: NewPlugin;
Immutable: NewPlugin;
ReactElement: NewPlugin;
ReactTestComponent: NewPlugin;
};
export declare interface PrettyFormatOptions
extends Omit<SnapshotFormat, 'compareKeys'> {
compareKeys?: CompareKeys;
plugins?: Plugins;
}
declare type Print = (arg0: unknown) => string;
export declare type Printer = (
val: unknown,
config: Config,
indentation: string,
depth: number,
refs: Refs,
hasCalledToJSON?: boolean,
) => string;
export declare type Refs = Array<unknown>;
declare type RequiredOptions = Required<PrettyFormatOptions>;
declare type Test = (arg0: any) => boolean;
export declare type Theme = Options['theme'];
export {};
@@ -0,0 +1,478 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = exports.DEFAULT_OPTIONS = void 0;
exports.format = format;
exports.plugins = void 0;
var _ansiStyles = _interopRequireDefault(require('ansi-styles'));
var _collections = require('./collections');
var _AsymmetricMatcher = _interopRequireDefault(
require('./plugins/AsymmetricMatcher')
);
var _DOMCollection = _interopRequireDefault(require('./plugins/DOMCollection'));
var _DOMElement = _interopRequireDefault(require('./plugins/DOMElement'));
var _Immutable = _interopRequireDefault(require('./plugins/Immutable'));
var _ReactElement = _interopRequireDefault(require('./plugins/ReactElement'));
var _ReactTestComponent = _interopRequireDefault(
require('./plugins/ReactTestComponent')
);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint-disable local/ban-types-eventually */
const toString = Object.prototype.toString;
const toISOString = Date.prototype.toISOString;
const errorToString = Error.prototype.toString;
const regExpToString = RegExp.prototype.toString;
/**
* Explicitly comparing typeof constructor to function avoids undefined as name
* when mock identity-obj-proxy returns the key as the value for any key.
*/
const getConstructorName = val =>
(typeof val.constructor === 'function' && val.constructor.name) || 'Object';
/* global window */
/** Is val is equal to global window object? Works even if it does not exist :) */
const isWindow = val => typeof window !== 'undefined' && val === window;
const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
const NEWLINE_REGEXP = /\n/gi;
class PrettyFormatPluginError extends Error {
constructor(message, stack) {
super(message);
this.stack = stack;
this.name = this.constructor.name;
}
}
function isToStringedArrayType(toStringed) {
return (
toStringed === '[object Array]' ||
toStringed === '[object ArrayBuffer]' ||
toStringed === '[object DataView]' ||
toStringed === '[object Float32Array]' ||
toStringed === '[object Float64Array]' ||
toStringed === '[object Int8Array]' ||
toStringed === '[object Int16Array]' ||
toStringed === '[object Int32Array]' ||
toStringed === '[object Uint8Array]' ||
toStringed === '[object Uint8ClampedArray]' ||
toStringed === '[object Uint16Array]' ||
toStringed === '[object Uint32Array]'
);
}
function printNumber(val) {
return Object.is(val, -0) ? '-0' : String(val);
}
function printBigInt(val) {
return String(`${val}n`);
}
function printFunction(val, printFunctionName) {
if (!printFunctionName) {
return '[Function]';
}
return `[Function ${val.name || 'anonymous'}]`;
}
function printSymbol(val) {
return String(val).replace(SYMBOL_REGEXP, 'Symbol($1)');
}
function printError(val) {
return `[${errorToString.call(val)}]`;
}
/**
* The first port of call for printing an object, handles most of the
* data-types in JS.
*/
function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
if (val === true || val === false) {
return `${val}`;
}
if (val === undefined) {
return 'undefined';
}
if (val === null) {
return 'null';
}
const typeOf = typeof val;
if (typeOf === 'number') {
return printNumber(val);
}
if (typeOf === 'bigint') {
return printBigInt(val);
}
if (typeOf === 'string') {
if (escapeString) {
return `"${val.replace(/"|\\/g, '\\$&')}"`;
}
return `"${val}"`;
}
if (typeOf === 'function') {
return printFunction(val, printFunctionName);
}
if (typeOf === 'symbol') {
return printSymbol(val);
}
const toStringed = toString.call(val);
if (toStringed === '[object WeakMap]') {
return 'WeakMap {}';
}
if (toStringed === '[object WeakSet]') {
return 'WeakSet {}';
}
if (
toStringed === '[object Function]' ||
toStringed === '[object GeneratorFunction]'
) {
return printFunction(val, printFunctionName);
}
if (toStringed === '[object Symbol]') {
return printSymbol(val);
}
if (toStringed === '[object Date]') {
return isNaN(+val) ? 'Date { NaN }' : toISOString.call(val);
}
if (toStringed === '[object Error]') {
return printError(val);
}
if (toStringed === '[object RegExp]') {
if (escapeRegex) {
// https://github.com/benjamingr/RegExp.escape/blob/main/polyfill.js
return regExpToString.call(val).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
}
return regExpToString.call(val);
}
if (val instanceof Error) {
return printError(val);
}
return null;
}
/**
* Handles more complex objects ( such as objects with circular references.
* maps and sets etc )
*/
function printComplexValue(
val,
config,
indentation,
depth,
refs,
hasCalledToJSON
) {
if (refs.indexOf(val) !== -1) {
return '[Circular]';
}
refs = refs.slice();
refs.push(val);
const hitMaxDepth = ++depth > config.maxDepth;
const min = config.min;
if (
config.callToJSON &&
!hitMaxDepth &&
val.toJSON &&
typeof val.toJSON === 'function' &&
!hasCalledToJSON
) {
return printer(val.toJSON(), config, indentation, depth, refs, true);
}
const toStringed = toString.call(val);
if (toStringed === '[object Arguments]') {
return hitMaxDepth
? '[Arguments]'
: `${min ? '' : 'Arguments '}[${(0, _collections.printListItems)(
val,
config,
indentation,
depth,
refs,
printer
)}]`;
}
if (isToStringedArrayType(toStringed)) {
return hitMaxDepth
? `[${val.constructor.name}]`
: `${
min
? ''
: !config.printBasicPrototype && val.constructor.name === 'Array'
? ''
: `${val.constructor.name} `
}[${(0, _collections.printListItems)(
val,
config,
indentation,
depth,
refs,
printer
)}]`;
}
if (toStringed === '[object Map]') {
return hitMaxDepth
? '[Map]'
: `Map {${(0, _collections.printIteratorEntries)(
val.entries(),
config,
indentation,
depth,
refs,
printer,
' => '
)}}`;
}
if (toStringed === '[object Set]') {
return hitMaxDepth
? '[Set]'
: `Set {${(0, _collections.printIteratorValues)(
val.values(),
config,
indentation,
depth,
refs,
printer
)}}`;
}
// Avoid failure to serialize global window object in jsdom test environment.
// For example, not even relevant if window is prop of React element.
return hitMaxDepth || isWindow(val)
? `[${getConstructorName(val)}]`
: `${
min
? ''
: !config.printBasicPrototype && getConstructorName(val) === 'Object'
? ''
: `${getConstructorName(val)} `
}{${(0, _collections.printObjectProperties)(
val,
config,
indentation,
depth,
refs,
printer
)}}`;
}
function isNewPlugin(plugin) {
return plugin.serialize != null;
}
function printPlugin(plugin, val, config, indentation, depth, refs) {
let printed;
try {
printed = isNewPlugin(plugin)
? plugin.serialize(val, config, indentation, depth, refs, printer)
: plugin.print(
val,
valChild => printer(valChild, config, indentation, depth, refs),
str => {
const indentationNext = indentation + config.indent;
return (
indentationNext +
str.replace(NEWLINE_REGEXP, `\n${indentationNext}`)
);
},
{
edgeSpacing: config.spacingOuter,
min: config.min,
spacing: config.spacingInner
},
config.colors
);
} catch (error) {
throw new PrettyFormatPluginError(error.message, error.stack);
}
if (typeof printed !== 'string') {
throw new Error(
`pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`
);
}
return printed;
}
function findPlugin(plugins, val) {
for (let p = 0; p < plugins.length; p++) {
try {
if (plugins[p].test(val)) {
return plugins[p];
}
} catch (error) {
throw new PrettyFormatPluginError(error.message, error.stack);
}
}
return null;
}
function printer(val, config, indentation, depth, refs, hasCalledToJSON) {
const plugin = findPlugin(config.plugins, val);
if (plugin !== null) {
return printPlugin(plugin, val, config, indentation, depth, refs);
}
const basicResult = printBasicValue(
val,
config.printFunctionName,
config.escapeRegex,
config.escapeString
);
if (basicResult !== null) {
return basicResult;
}
return printComplexValue(
val,
config,
indentation,
depth,
refs,
hasCalledToJSON
);
}
const DEFAULT_THEME = {
comment: 'gray',
content: 'reset',
prop: 'yellow',
tag: 'cyan',
value: 'green'
};
const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME);
// could be replaced by `satisfies` operator in the future: https://github.com/microsoft/TypeScript/issues/47920
const toOptionsSubtype = options => options;
const DEFAULT_OPTIONS = toOptionsSubtype({
callToJSON: true,
compareKeys: undefined,
escapeRegex: false,
escapeString: true,
highlight: false,
indent: 2,
maxDepth: Infinity,
maxWidth: Infinity,
min: false,
plugins: [],
printBasicPrototype: true,
printFunctionName: true,
theme: DEFAULT_THEME
});
exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
function validateOptions(options) {
Object.keys(options).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(DEFAULT_OPTIONS, key)) {
throw new Error(`pretty-format: Unknown option "${key}".`);
}
});
if (options.min && options.indent !== undefined && options.indent !== 0) {
throw new Error(
'pretty-format: Options "min" and "indent" cannot be used together.'
);
}
if (options.theme !== undefined) {
if (options.theme === null) {
throw new Error('pretty-format: Option "theme" must not be null.');
}
if (typeof options.theme !== 'object') {
throw new Error(
`pretty-format: Option "theme" must be of type "object" but instead received "${typeof options.theme}".`
);
}
}
}
const getColorsHighlight = options =>
DEFAULT_THEME_KEYS.reduce((colors, key) => {
const value =
options.theme && options.theme[key] !== undefined
? options.theme[key]
: DEFAULT_THEME[key];
const color = value && _ansiStyles.default[value];
if (
color &&
typeof color.close === 'string' &&
typeof color.open === 'string'
) {
colors[key] = color;
} else {
throw new Error(
`pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.`
);
}
return colors;
}, Object.create(null));
const getColorsEmpty = () =>
DEFAULT_THEME_KEYS.reduce((colors, key) => {
colors[key] = {
close: '',
open: ''
};
return colors;
}, Object.create(null));
const getPrintFunctionName = options =>
options?.printFunctionName ?? DEFAULT_OPTIONS.printFunctionName;
const getEscapeRegex = options =>
options?.escapeRegex ?? DEFAULT_OPTIONS.escapeRegex;
const getEscapeString = options =>
options?.escapeString ?? DEFAULT_OPTIONS.escapeString;
const getConfig = options => ({
callToJSON: options?.callToJSON ?? DEFAULT_OPTIONS.callToJSON,
colors: options?.highlight ? getColorsHighlight(options) : getColorsEmpty(),
compareKeys:
typeof options?.compareKeys === 'function' || options?.compareKeys === null
? options.compareKeys
: DEFAULT_OPTIONS.compareKeys,
escapeRegex: getEscapeRegex(options),
escapeString: getEscapeString(options),
indent: options?.min
? ''
: createIndent(options?.indent ?? DEFAULT_OPTIONS.indent),
maxDepth: options?.maxDepth ?? DEFAULT_OPTIONS.maxDepth,
maxWidth: options?.maxWidth ?? DEFAULT_OPTIONS.maxWidth,
min: options?.min ?? DEFAULT_OPTIONS.min,
plugins: options?.plugins ?? DEFAULT_OPTIONS.plugins,
printBasicPrototype: options?.printBasicPrototype ?? true,
printFunctionName: getPrintFunctionName(options),
spacingInner: options?.min ? ' ' : '\n',
spacingOuter: options?.min ? '' : '\n'
});
function createIndent(indent) {
return new Array(indent + 1).join(' ');
}
/**
* Returns a presentation string of your `val` object
* @param val any potential JavaScript object
* @param options Custom settings
*/
function format(val, options) {
if (options) {
validateOptions(options);
if (options.plugins) {
const plugin = findPlugin(options.plugins, val);
if (plugin !== null) {
return printPlugin(plugin, val, getConfig(options), '', 0, []);
}
}
}
const basicResult = printBasicValue(
val,
getPrintFunctionName(options),
getEscapeRegex(options),
getEscapeString(options)
);
if (basicResult !== null) {
return basicResult;
}
return printComplexValue(val, getConfig(options), '', 0, []);
}
const plugins = {
AsymmetricMatcher: _AsymmetricMatcher.default,
DOMCollection: _DOMCollection.default,
DOMElement: _DOMElement.default,
Immutable: _Immutable.default,
ReactElement: _ReactElement.default,
ReactTestComponent: _ReactTestComponent.default
};
exports.plugins = plugins;
var _default = format;
exports.default = _default;
@@ -0,0 +1,89 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _collections = require('../collections');
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const asymmetricMatcher =
typeof Symbol === 'function' && Symbol.for
? Symbol.for('jest.asymmetricMatcher')
: 0x1357a5;
const SPACE = ' ';
const serialize = (val, config, indentation, depth, refs, printer) => {
const stringedValue = val.toString();
if (
stringedValue === 'ArrayContaining' ||
stringedValue === 'ArrayNotContaining'
) {
if (++depth > config.maxDepth) {
return `[${stringedValue}]`;
}
return `${stringedValue + SPACE}[${(0, _collections.printListItems)(
val.sample,
config,
indentation,
depth,
refs,
printer
)}]`;
}
if (
stringedValue === 'ObjectContaining' ||
stringedValue === 'ObjectNotContaining'
) {
if (++depth > config.maxDepth) {
return `[${stringedValue}]`;
}
return `${stringedValue + SPACE}{${(0, _collections.printObjectProperties)(
val.sample,
config,
indentation,
depth,
refs,
printer
)}}`;
}
if (
stringedValue === 'StringMatching' ||
stringedValue === 'StringNotMatching'
) {
return (
stringedValue +
SPACE +
printer(val.sample, config, indentation, depth, refs)
);
}
if (
stringedValue === 'StringContaining' ||
stringedValue === 'StringNotContaining'
) {
return (
stringedValue +
SPACE +
printer(val.sample, config, indentation, depth, refs)
);
}
if (typeof val.toAsymmetricMatcher !== 'function') {
throw new Error(
`Asymmetric matcher ${val.constructor.name} does not implement toAsymmetricMatcher()`
);
}
return val.toAsymmetricMatcher();
};
exports.serialize = serialize;
const test = val => val && val.$$typeof === asymmetricMatcher;
exports.test = test;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,67 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _collections = require('../collections');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const SPACE = ' ';
const OBJECT_NAMES = ['DOMStringMap', 'NamedNodeMap'];
const ARRAY_REGEXP = /^(HTML\w*Collection|NodeList)$/;
const testName = name =>
OBJECT_NAMES.indexOf(name) !== -1 || ARRAY_REGEXP.test(name);
const test = val =>
val &&
val.constructor &&
!!val.constructor.name &&
testName(val.constructor.name);
exports.test = test;
const isNamedNodeMap = collection =>
collection.constructor.name === 'NamedNodeMap';
const serialize = (collection, config, indentation, depth, refs, printer) => {
const name = collection.constructor.name;
if (++depth > config.maxDepth) {
return `[${name}]`;
}
return (
(config.min ? '' : name + SPACE) +
(OBJECT_NAMES.indexOf(name) !== -1
? `{${(0, _collections.printObjectProperties)(
isNamedNodeMap(collection)
? Array.from(collection).reduce((props, attribute) => {
props[attribute.name] = attribute.value;
return props;
}, {})
: {
...collection
},
config,
indentation,
depth,
refs,
printer
)}}`
: `[${(0, _collections.printListItems)(
Array.from(collection),
config,
indentation,
depth,
refs,
printer
)}]`)
);
};
exports.serialize = serialize;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,101 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _markup = require('./lib/markup');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const ELEMENT_NODE = 1;
const TEXT_NODE = 3;
const COMMENT_NODE = 8;
const FRAGMENT_NODE = 11;
const ELEMENT_REGEXP = /^((HTML|SVG)\w*)?Element$/;
const testHasAttribute = val => {
try {
return typeof val.hasAttribute === 'function' && val.hasAttribute('is');
} catch {
return false;
}
};
const testNode = val => {
const constructorName = val.constructor.name;
const {nodeType, tagName} = val;
const isCustomElement =
(typeof tagName === 'string' && tagName.includes('-')) ||
testHasAttribute(val);
return (
(nodeType === ELEMENT_NODE &&
(ELEMENT_REGEXP.test(constructorName) || isCustomElement)) ||
(nodeType === TEXT_NODE && constructorName === 'Text') ||
(nodeType === COMMENT_NODE && constructorName === 'Comment') ||
(nodeType === FRAGMENT_NODE && constructorName === 'DocumentFragment')
);
};
const test = val => val?.constructor?.name && testNode(val);
exports.test = test;
function nodeIsText(node) {
return node.nodeType === TEXT_NODE;
}
function nodeIsComment(node) {
return node.nodeType === COMMENT_NODE;
}
function nodeIsFragment(node) {
return node.nodeType === FRAGMENT_NODE;
}
const serialize = (node, config, indentation, depth, refs, printer) => {
if (nodeIsText(node)) {
return (0, _markup.printText)(node.data, config);
}
if (nodeIsComment(node)) {
return (0, _markup.printComment)(node.data, config);
}
const type = nodeIsFragment(node)
? 'DocumentFragment'
: node.tagName.toLowerCase();
if (++depth > config.maxDepth) {
return (0, _markup.printElementAsLeaf)(type, config);
}
return (0, _markup.printElement)(
type,
(0, _markup.printProps)(
nodeIsFragment(node)
? []
: Array.from(node.attributes, attr => attr.name).sort(),
nodeIsFragment(node)
? {}
: Array.from(node.attributes).reduce((props, attribute) => {
props[attribute.name] = attribute.value;
return props;
}, {}),
config,
indentation + config.indent,
depth,
refs,
printer
),
(0, _markup.printChildren)(
Array.prototype.slice.call(node.childNodes || node.children),
config,
indentation + config.indent,
depth,
refs,
printer
),
config,
indentation
);
};
exports.serialize = serialize;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,217 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _collections = require('../collections');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// SENTINEL constants are from https://github.com/facebook/immutable-js
const IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';
const IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@';
const IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@';
const IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@';
const IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@';
const IS_RECORD_SENTINEL = '@@__IMMUTABLE_RECORD__@@'; // immutable v4
const IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@';
const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@';
const IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@';
const getImmutableName = name => `Immutable.${name}`;
const printAsLeaf = name => `[${name}]`;
const SPACE = ' ';
const LAZY = '…'; // Seq is lazy if it calls a method like filter
const printImmutableEntries = (
val,
config,
indentation,
depth,
refs,
printer,
type
) =>
++depth > config.maxDepth
? printAsLeaf(getImmutableName(type))
: `${getImmutableName(type) + SPACE}{${(0,
_collections.printIteratorEntries)(
val.entries(),
config,
indentation,
depth,
refs,
printer
)}}`;
// Record has an entries method because it is a collection in immutable v3.
// Return an iterator for Immutable Record from version v3 or v4.
function getRecordEntries(val) {
let i = 0;
return {
next() {
if (i < val._keys.length) {
const key = val._keys[i++];
return {
done: false,
value: [key, val.get(key)]
};
}
return {
done: true,
value: undefined
};
}
};
}
const printImmutableRecord = (
val,
config,
indentation,
depth,
refs,
printer
) => {
// _name property is defined only for an Immutable Record instance
// which was constructed with a second optional descriptive name arg
const name = getImmutableName(val._name || 'Record');
return ++depth > config.maxDepth
? printAsLeaf(name)
: `${name + SPACE}{${(0, _collections.printIteratorEntries)(
getRecordEntries(val),
config,
indentation,
depth,
refs,
printer
)}}`;
};
const printImmutableSeq = (val, config, indentation, depth, refs, printer) => {
const name = getImmutableName('Seq');
if (++depth > config.maxDepth) {
return printAsLeaf(name);
}
if (val[IS_KEYED_SENTINEL]) {
return `${name + SPACE}{${
// from Immutable collection of entries or from ECMAScript object
val._iter || val._object
? (0, _collections.printIteratorEntries)(
val.entries(),
config,
indentation,
depth,
refs,
printer
)
: LAZY
}}`;
}
return `${name + SPACE}[${
val._iter ||
// from Immutable collection of values
val._array ||
// from ECMAScript array
val._collection ||
// from ECMAScript collection in immutable v4
val._iterable // from ECMAScript collection in immutable v3
? (0, _collections.printIteratorValues)(
val.values(),
config,
indentation,
depth,
refs,
printer
)
: LAZY
}]`;
};
const printImmutableValues = (
val,
config,
indentation,
depth,
refs,
printer,
type
) =>
++depth > config.maxDepth
? printAsLeaf(getImmutableName(type))
: `${getImmutableName(type) + SPACE}[${(0,
_collections.printIteratorValues)(
val.values(),
config,
indentation,
depth,
refs,
printer
)}]`;
const serialize = (val, config, indentation, depth, refs, printer) => {
if (val[IS_MAP_SENTINEL]) {
return printImmutableEntries(
val,
config,
indentation,
depth,
refs,
printer,
val[IS_ORDERED_SENTINEL] ? 'OrderedMap' : 'Map'
);
}
if (val[IS_LIST_SENTINEL]) {
return printImmutableValues(
val,
config,
indentation,
depth,
refs,
printer,
'List'
);
}
if (val[IS_SET_SENTINEL]) {
return printImmutableValues(
val,
config,
indentation,
depth,
refs,
printer,
val[IS_ORDERED_SENTINEL] ? 'OrderedSet' : 'Set'
);
}
if (val[IS_STACK_SENTINEL]) {
return printImmutableValues(
val,
config,
indentation,
depth,
refs,
printer,
'Stack'
);
}
if (val[IS_SEQ_SENTINEL]) {
return printImmutableSeq(val, config, indentation, depth, refs, printer);
}
// For compatibility with immutable v3 and v4, let record be the default.
return printImmutableRecord(val, config, indentation, depth, refs, printer);
};
// Explicitly comparing sentinel properties to true avoids false positive
// when mock identity-obj-proxy returns the key as the value for any key.
exports.serialize = serialize;
const test = val =>
val &&
(val[IS_ITERABLE_SENTINEL] === true || val[IS_RECORD_SENTINEL] === true);
exports.test = test;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,143 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var ReactIs = _interopRequireWildcard(require('react-is'));
var _markup = require('./lib/markup');
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// Given element.props.children, or subtree during recursive traversal,
// return flattened array of children.
const getChildren = (arg, children = []) => {
if (Array.isArray(arg)) {
arg.forEach(item => {
getChildren(item, children);
});
} else if (arg != null && arg !== false) {
children.push(arg);
}
return children;
};
const getType = element => {
const type = element.type;
if (typeof type === 'string') {
return type;
}
if (typeof type === 'function') {
return type.displayName || type.name || 'Unknown';
}
if (ReactIs.isFragment(element)) {
return 'React.Fragment';
}
if (ReactIs.isSuspense(element)) {
return 'React.Suspense';
}
if (typeof type === 'object' && type !== null) {
if (ReactIs.isContextProvider(element)) {
return 'Context.Provider';
}
if (ReactIs.isContextConsumer(element)) {
return 'Context.Consumer';
}
if (ReactIs.isForwardRef(element)) {
if (type.displayName) {
return type.displayName;
}
const functionName = type.render.displayName || type.render.name || '';
return functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef';
}
if (ReactIs.isMemo(element)) {
const functionName =
type.displayName || type.type.displayName || type.type.name || '';
return functionName !== '' ? `Memo(${functionName})` : 'Memo';
}
}
return 'UNDEFINED';
};
const getPropKeys = element => {
const {props} = element;
return Object.keys(props)
.filter(key => key !== 'children' && props[key] !== undefined)
.sort();
};
const serialize = (element, config, indentation, depth, refs, printer) =>
++depth > config.maxDepth
? (0, _markup.printElementAsLeaf)(getType(element), config)
: (0, _markup.printElement)(
getType(element),
(0, _markup.printProps)(
getPropKeys(element),
element.props,
config,
indentation + config.indent,
depth,
refs,
printer
),
(0, _markup.printChildren)(
getChildren(element.props.children),
config,
indentation + config.indent,
depth,
refs,
printer
),
config,
indentation
);
exports.serialize = serialize;
const test = val => val != null && ReactIs.isElement(val);
exports.test = test;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,66 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _markup = require('./lib/markup');
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// Child can be `number` in Stack renderer but not in Fiber renderer.
const testSymbol =
typeof Symbol === 'function' && Symbol.for
? Symbol.for('react.test.json')
: 0xea71357;
const getPropKeys = object => {
const {props} = object;
return props
? Object.keys(props)
.filter(key => props[key] !== undefined)
.sort()
: [];
};
const serialize = (object, config, indentation, depth, refs, printer) =>
++depth > config.maxDepth
? (0, _markup.printElementAsLeaf)(object.type, config)
: (0, _markup.printElement)(
object.type,
object.props
? (0, _markup.printProps)(
getPropKeys(object),
object.props,
config,
indentation + config.indent,
depth,
refs,
printer
)
: '',
object.children
? (0, _markup.printChildren)(
object.children,
config,
indentation + config.indent,
depth,
refs,
printer
)
: '',
config,
indentation
);
exports.serialize = serialize;
const test = val => val && val.$$typeof === testSymbol;
exports.test = test;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,16 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = escapeHTML;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
function escapeHTML(str) {
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
@@ -0,0 +1,113 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.printText =
exports.printProps =
exports.printElementAsLeaf =
exports.printElement =
exports.printComment =
exports.printChildren =
void 0;
var _escapeHTML = _interopRequireDefault(require('./escapeHTML'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// Return empty string if keys is empty.
const printProps = (keys, props, config, indentation, depth, refs, printer) => {
const indentationNext = indentation + config.indent;
const colors = config.colors;
return keys
.map(key => {
const value = props[key];
let printed = printer(value, config, indentationNext, depth, refs);
if (typeof value !== 'string') {
if (printed.indexOf('\n') !== -1) {
printed =
config.spacingOuter +
indentationNext +
printed +
config.spacingOuter +
indentation;
}
printed = `{${printed}}`;
}
return `${
config.spacingInner +
indentation +
colors.prop.open +
key +
colors.prop.close
}=${colors.value.open}${printed}${colors.value.close}`;
})
.join('');
};
// Return empty string if children is empty.
exports.printProps = printProps;
const printChildren = (children, config, indentation, depth, refs, printer) =>
children
.map(
child =>
config.spacingOuter +
indentation +
(typeof child === 'string'
? printText(child, config)
: printer(child, config, indentation, depth, refs))
)
.join('');
exports.printChildren = printChildren;
const printText = (text, config) => {
const contentColor = config.colors.content;
return (
contentColor.open + (0, _escapeHTML.default)(text) + contentColor.close
);
};
exports.printText = printText;
const printComment = (comment, config) => {
const commentColor = config.colors.comment;
return `${commentColor.open}<!--${(0, _escapeHTML.default)(comment)}-->${
commentColor.close
}`;
};
// Separate the functions to format props, children, and element,
// so a plugin could override a particular function, if needed.
// Too bad, so sad: the traditional (but unnecessary) space
// in a self-closing tagColor requires a second test of printedProps.
exports.printComment = printComment;
const printElement = (
type,
printedProps,
printedChildren,
config,
indentation
) => {
const tagColor = config.colors.tag;
return `${tagColor.open}<${type}${
printedProps &&
tagColor.close +
printedProps +
config.spacingOuter +
indentation +
tagColor.open
}${
printedChildren
? `>${tagColor.close}${printedChildren}${config.spacingOuter}${indentation}${tagColor.open}</${type}`
: `${printedProps && !config.min ? '' : ' '}/`
}>${tagColor.close}`;
};
exports.printElement = printElement;
const printElementAsLeaf = (type, config) => {
const tagColor = config.colors.tag;
return `${tagColor.open}<${type}${tagColor.close}${tagColor.open} />${tagColor.close}`;
};
exports.printElementAsLeaf = printElementAsLeaf;
@@ -0,0 +1 @@
'use strict';
@@ -0,0 +1,43 @@
{
"name": "pretty-format",
"version": "29.7.0",
"repository": {
"type": "git",
"url": "https://github.com/jestjs/jest.git",
"directory": "packages/pretty-format"
},
"license": "MIT",
"description": "Stringify any JavaScript value.",
"main": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
".": {
"types": "./build/index.d.ts",
"default": "./build/index.js"
},
"./package.json": "./package.json"
},
"author": "James Kyle <me@thejameskyle.com>",
"dependencies": {
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
"react-is": "^18.0.0"
},
"devDependencies": {
"@types/react": "^17.0.3",
"@types/react-is": "^18.0.0",
"@types/react-test-renderer": "17.0.2",
"immutable": "^4.0.0",
"jest-util": "^29.7.0",
"react": "17.0.2",
"react-dom": "^17.0.1",
"react-test-renderer": "17.0.2"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
},
"publishConfig": {
"access": "public"
},
"gitHead": "4e56991693da7cd4c3730dc3579a1dd1403ee630"
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Facebook, Inc. and its affiliates.
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.
+104
View File
@@ -0,0 +1,104 @@
# `react-is`
This package allows you to test arbitrary values and see if they're a particular React element type.
## Installation
```sh
# Yarn
yarn add react-is
# NPM
npm install react-is
```
## Usage
### Determining if a Component is Valid
```js
import React from "react";
import * as ReactIs from "react-is";
class ClassComponent extends React.Component {
render() {
return React.createElement("div");
}
}
const FunctionComponent = () => React.createElement("div");
const ForwardRefComponent = React.forwardRef((props, ref) =>
React.createElement(Component, { forwardedRef: ref, ...props })
);
const Context = React.createContext(false);
ReactIs.isValidElementType("div"); // true
ReactIs.isValidElementType(ClassComponent); // true
ReactIs.isValidElementType(FunctionComponent); // true
ReactIs.isValidElementType(ForwardRefComponent); // true
ReactIs.isValidElementType(Context.Provider); // true
ReactIs.isValidElementType(Context.Consumer); // true
ReactIs.isValidElementType(React.createFactory("div")); // true
```
### Determining an Element's Type
#### Context
```js
import React from "react";
import * as ReactIs from 'react-is';
const ThemeContext = React.createContext("blue");
ReactIs.isContextConsumer(<ThemeContext.Consumer />); // true
ReactIs.isContextProvider(<ThemeContext.Provider />); // true
ReactIs.typeOf(<ThemeContext.Provider />) === ReactIs.ContextProvider; // true
ReactIs.typeOf(<ThemeContext.Consumer />) === ReactIs.ContextConsumer; // true
```
#### Element
```js
import React from "react";
import * as ReactIs from 'react-is';
ReactIs.isElement(<div />); // true
ReactIs.typeOf(<div />) === ReactIs.Element; // true
```
#### Fragment
```js
import React from "react";
import * as ReactIs from 'react-is';
ReactIs.isFragment(<></>); // true
ReactIs.typeOf(<></>) === ReactIs.Fragment; // true
```
#### Portal
```js
import React from "react";
import ReactDOM from "react-dom";
import * as ReactIs from 'react-is';
const div = document.createElement("div");
const portal = ReactDOM.createPortal(<div />, div);
ReactIs.isPortal(portal); // true
ReactIs.typeOf(portal) === ReactIs.Portal; // true
```
#### StrictMode
```js
import React from "react";
import * as ReactIs from 'react-is';
ReactIs.isStrictMode(<React.StrictMode />); // true
ReactIs.typeOf(<React.StrictMode />) === ReactIs.StrictMode; // true
```
@@ -0,0 +1,221 @@
/**
* @license React
* react-is.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
if (process.env.NODE_ENV !== "production") {
(function() {
'use strict';
// ATTENTION
// When adding new symbols to this file,
// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
// The Symbol used to tag the ReactElement-like types.
var REACT_ELEMENT_TYPE = Symbol.for('react.element');
var REACT_PORTAL_TYPE = Symbol.for('react.portal');
var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
var REACT_PROFILER_TYPE = Symbol.for('react.profiler');
var REACT_PROVIDER_TYPE = Symbol.for('react.provider');
var REACT_CONTEXT_TYPE = Symbol.for('react.context');
var REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
var REACT_MEMO_TYPE = Symbol.for('react.memo');
var REACT_LAZY_TYPE = Symbol.for('react.lazy');
var REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
// -----------------------------------------------------------------------------
var enableScopeAPI = false; // Experimental Create Event Handle API.
var enableCacheElement = false;
var enableTransitionTracing = false; // No known bugs, but needs performance testing
var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber
// stuff. Intended to enable React core members to more easily debug scheduling
// issues in DEV builds.
var enableDebugTracing = false; // Track which Fiber(s) schedule render work.
var REACT_MODULE_REFERENCE;
{
REACT_MODULE_REFERENCE = Symbol.for('react.module.reference');
}
function isValidElementType(type) {
if (typeof type === 'string' || typeof type === 'function') {
return true;
} // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableCacheElement || enableTransitionTracing ) {
return true;
}
if (typeof type === 'object' && type !== null) {
if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object
// types supported by any Flight configuration anywhere since
// we don't know which Flight build this will end up being used
// with.
type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== undefined) {
return true;
}
}
return false;
}
function typeOf(object) {
if (typeof object === 'object' && object !== null) {
var $$typeof = object.$$typeof;
switch ($$typeof) {
case REACT_ELEMENT_TYPE:
var type = object.type;
switch (type) {
case REACT_FRAGMENT_TYPE:
case REACT_PROFILER_TYPE:
case REACT_STRICT_MODE_TYPE:
case REACT_SUSPENSE_TYPE:
case REACT_SUSPENSE_LIST_TYPE:
return type;
default:
var $$typeofType = type && type.$$typeof;
switch ($$typeofType) {
case REACT_SERVER_CONTEXT_TYPE:
case REACT_CONTEXT_TYPE:
case REACT_FORWARD_REF_TYPE:
case REACT_LAZY_TYPE:
case REACT_MEMO_TYPE:
case REACT_PROVIDER_TYPE:
return $$typeofType;
default:
return $$typeof;
}
}
case REACT_PORTAL_TYPE:
return $$typeof;
}
}
return undefined;
}
var ContextConsumer = REACT_CONTEXT_TYPE;
var ContextProvider = REACT_PROVIDER_TYPE;
var Element = REACT_ELEMENT_TYPE;
var ForwardRef = REACT_FORWARD_REF_TYPE;
var Fragment = REACT_FRAGMENT_TYPE;
var Lazy = REACT_LAZY_TYPE;
var Memo = REACT_MEMO_TYPE;
var Portal = REACT_PORTAL_TYPE;
var Profiler = REACT_PROFILER_TYPE;
var StrictMode = REACT_STRICT_MODE_TYPE;
var Suspense = REACT_SUSPENSE_TYPE;
var SuspenseList = REACT_SUSPENSE_LIST_TYPE;
var hasWarnedAboutDeprecatedIsAsyncMode = false;
var hasWarnedAboutDeprecatedIsConcurrentMode = false; // AsyncMode should be deprecated
function isAsyncMode(object) {
{
if (!hasWarnedAboutDeprecatedIsAsyncMode) {
hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint
console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 18+.');
}
}
return false;
}
function isConcurrentMode(object) {
{
if (!hasWarnedAboutDeprecatedIsConcurrentMode) {
hasWarnedAboutDeprecatedIsConcurrentMode = true; // Using console['warn'] to evade Babel and ESLint
console['warn']('The ReactIs.isConcurrentMode() alias has been deprecated, ' + 'and will be removed in React 18+.');
}
}
return false;
}
function isContextConsumer(object) {
return typeOf(object) === REACT_CONTEXT_TYPE;
}
function isContextProvider(object) {
return typeOf(object) === REACT_PROVIDER_TYPE;
}
function isElement(object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
function isForwardRef(object) {
return typeOf(object) === REACT_FORWARD_REF_TYPE;
}
function isFragment(object) {
return typeOf(object) === REACT_FRAGMENT_TYPE;
}
function isLazy(object) {
return typeOf(object) === REACT_LAZY_TYPE;
}
function isMemo(object) {
return typeOf(object) === REACT_MEMO_TYPE;
}
function isPortal(object) {
return typeOf(object) === REACT_PORTAL_TYPE;
}
function isProfiler(object) {
return typeOf(object) === REACT_PROFILER_TYPE;
}
function isStrictMode(object) {
return typeOf(object) === REACT_STRICT_MODE_TYPE;
}
function isSuspense(object) {
return typeOf(object) === REACT_SUSPENSE_TYPE;
}
function isSuspenseList(object) {
return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;
}
exports.ContextConsumer = ContextConsumer;
exports.ContextProvider = ContextProvider;
exports.Element = Element;
exports.ForwardRef = ForwardRef;
exports.Fragment = Fragment;
exports.Lazy = Lazy;
exports.Memo = Memo;
exports.Portal = Portal;
exports.Profiler = Profiler;
exports.StrictMode = StrictMode;
exports.Suspense = Suspense;
exports.SuspenseList = SuspenseList;
exports.isAsyncMode = isAsyncMode;
exports.isConcurrentMode = isConcurrentMode;
exports.isContextConsumer = isContextConsumer;
exports.isContextProvider = isContextProvider;
exports.isElement = isElement;
exports.isForwardRef = isForwardRef;
exports.isFragment = isFragment;
exports.isLazy = isLazy;
exports.isMemo = isMemo;
exports.isPortal = isPortal;
exports.isProfiler = isProfiler;
exports.isStrictMode = isStrictMode;
exports.isSuspense = isSuspense;
exports.isSuspenseList = isSuspenseList;
exports.isValidElementType = isValidElementType;
exports.typeOf = typeOf;
})();
}
@@ -0,0 +1,14 @@
/**
* @license React
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';var b=Symbol.for("react.element"),c=Symbol.for("react.portal"),d=Symbol.for("react.fragment"),e=Symbol.for("react.strict_mode"),f=Symbol.for("react.profiler"),g=Symbol.for("react.provider"),h=Symbol.for("react.context"),k=Symbol.for("react.server_context"),l=Symbol.for("react.forward_ref"),m=Symbol.for("react.suspense"),n=Symbol.for("react.suspense_list"),p=Symbol.for("react.memo"),q=Symbol.for("react.lazy"),t=Symbol.for("react.offscreen"),u;u=Symbol.for("react.module.reference");
function v(a){if("object"===typeof a&&null!==a){var r=a.$$typeof;switch(r){case b:switch(a=a.type,a){case d:case f:case e:case m:case n:return a;default:switch(a=a&&a.$$typeof,a){case k:case h:case l:case q:case p:case g:return a;default:return r}}case c:return r}}}exports.ContextConsumer=h;exports.ContextProvider=g;exports.Element=b;exports.ForwardRef=l;exports.Fragment=d;exports.Lazy=q;exports.Memo=p;exports.Portal=c;exports.Profiler=f;exports.StrictMode=e;exports.Suspense=m;
exports.SuspenseList=n;exports.isAsyncMode=function(){return!1};exports.isConcurrentMode=function(){return!1};exports.isContextConsumer=function(a){return v(a)===h};exports.isContextProvider=function(a){return v(a)===g};exports.isElement=function(a){return"object"===typeof a&&null!==a&&a.$$typeof===b};exports.isForwardRef=function(a){return v(a)===l};exports.isFragment=function(a){return v(a)===d};exports.isLazy=function(a){return v(a)===q};exports.isMemo=function(a){return v(a)===p};
exports.isPortal=function(a){return v(a)===c};exports.isProfiler=function(a){return v(a)===f};exports.isStrictMode=function(a){return v(a)===e};exports.isSuspense=function(a){return v(a)===m};exports.isSuspenseList=function(a){return v(a)===n};
exports.isValidElementType=function(a){return"string"===typeof a||"function"===typeof a||a===d||a===f||a===e||a===m||a===n||a===t||"object"===typeof a&&null!==a&&(a.$$typeof===q||a.$$typeof===p||a.$$typeof===g||a.$$typeof===h||a.$$typeof===l||a.$$typeof===u||void 0!==a.getModuleId)?!0:!1};exports.typeOf=v;
@@ -0,0 +1,7 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-is.production.min.js');
} else {
module.exports = require('./cjs/react-is.development.js');
}
@@ -0,0 +1,26 @@
{
"name": "react-is",
"version": "18.3.1",
"description": "Brand checking of React Elements.",
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
"directory": "packages/react-is"
},
"keywords": [
"react"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/facebook/react/issues"
},
"homepage": "https://reactjs.org/",
"files": [
"LICENSE",
"README.md",
"index.js",
"cjs/",
"umd/"
]
}
@@ -0,0 +1,220 @@
/**
* @license React
* react-is.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = global || self, factory(global.ReactIs = {}));
}(this, (function (exports) { 'use strict';
// ATTENTION
// When adding new symbols to this file,
// Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'
// The Symbol used to tag the ReactElement-like types.
var REACT_ELEMENT_TYPE = Symbol.for('react.element');
var REACT_PORTAL_TYPE = Symbol.for('react.portal');
var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');
var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');
var REACT_PROFILER_TYPE = Symbol.for('react.profiler');
var REACT_PROVIDER_TYPE = Symbol.for('react.provider');
var REACT_CONTEXT_TYPE = Symbol.for('react.context');
var REACT_SERVER_CONTEXT_TYPE = Symbol.for('react.server_context');
var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');
var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');
var REACT_MEMO_TYPE = Symbol.for('react.memo');
var REACT_LAZY_TYPE = Symbol.for('react.lazy');
var REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');
// -----------------------------------------------------------------------------
var enableScopeAPI = false; // Experimental Create Event Handle API.
var enableCacheElement = false;
var enableTransitionTracing = false; // No known bugs, but needs performance testing
var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber
// stuff. Intended to enable React core members to more easily debug scheduling
// issues in DEV builds.
var enableDebugTracing = false; // Track which Fiber(s) schedule render work.
var REACT_MODULE_REFERENCE;
{
REACT_MODULE_REFERENCE = Symbol.for('react.module.reference');
}
function isValidElementType(type) {
if (typeof type === 'string' || typeof type === 'function') {
return true;
} // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden || type === REACT_OFFSCREEN_TYPE || enableScopeAPI || enableCacheElement || enableTransitionTracing ) {
return true;
}
if (typeof type === 'object' && type !== null) {
if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object
// types supported by any Flight configuration anywhere since
// we don't know which Flight build this will end up being used
// with.
type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== undefined) {
return true;
}
}
return false;
}
function typeOf(object) {
if (typeof object === 'object' && object !== null) {
var $$typeof = object.$$typeof;
switch ($$typeof) {
case REACT_ELEMENT_TYPE:
var type = object.type;
switch (type) {
case REACT_FRAGMENT_TYPE:
case REACT_PROFILER_TYPE:
case REACT_STRICT_MODE_TYPE:
case REACT_SUSPENSE_TYPE:
case REACT_SUSPENSE_LIST_TYPE:
return type;
default:
var $$typeofType = type && type.$$typeof;
switch ($$typeofType) {
case REACT_SERVER_CONTEXT_TYPE:
case REACT_CONTEXT_TYPE:
case REACT_FORWARD_REF_TYPE:
case REACT_LAZY_TYPE:
case REACT_MEMO_TYPE:
case REACT_PROVIDER_TYPE:
return $$typeofType;
default:
return $$typeof;
}
}
case REACT_PORTAL_TYPE:
return $$typeof;
}
}
return undefined;
}
var ContextConsumer = REACT_CONTEXT_TYPE;
var ContextProvider = REACT_PROVIDER_TYPE;
var Element = REACT_ELEMENT_TYPE;
var ForwardRef = REACT_FORWARD_REF_TYPE;
var Fragment = REACT_FRAGMENT_TYPE;
var Lazy = REACT_LAZY_TYPE;
var Memo = REACT_MEMO_TYPE;
var Portal = REACT_PORTAL_TYPE;
var Profiler = REACT_PROFILER_TYPE;
var StrictMode = REACT_STRICT_MODE_TYPE;
var Suspense = REACT_SUSPENSE_TYPE;
var SuspenseList = REACT_SUSPENSE_LIST_TYPE;
var hasWarnedAboutDeprecatedIsAsyncMode = false;
var hasWarnedAboutDeprecatedIsConcurrentMode = false; // AsyncMode should be deprecated
function isAsyncMode(object) {
{
if (!hasWarnedAboutDeprecatedIsAsyncMode) {
hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint
console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 18+.');
}
}
return false;
}
function isConcurrentMode(object) {
{
if (!hasWarnedAboutDeprecatedIsConcurrentMode) {
hasWarnedAboutDeprecatedIsConcurrentMode = true; // Using console['warn'] to evade Babel and ESLint
console['warn']('The ReactIs.isConcurrentMode() alias has been deprecated, ' + 'and will be removed in React 18+.');
}
}
return false;
}
function isContextConsumer(object) {
return typeOf(object) === REACT_CONTEXT_TYPE;
}
function isContextProvider(object) {
return typeOf(object) === REACT_PROVIDER_TYPE;
}
function isElement(object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
function isForwardRef(object) {
return typeOf(object) === REACT_FORWARD_REF_TYPE;
}
function isFragment(object) {
return typeOf(object) === REACT_FRAGMENT_TYPE;
}
function isLazy(object) {
return typeOf(object) === REACT_LAZY_TYPE;
}
function isMemo(object) {
return typeOf(object) === REACT_MEMO_TYPE;
}
function isPortal(object) {
return typeOf(object) === REACT_PORTAL_TYPE;
}
function isProfiler(object) {
return typeOf(object) === REACT_PROFILER_TYPE;
}
function isStrictMode(object) {
return typeOf(object) === REACT_STRICT_MODE_TYPE;
}
function isSuspense(object) {
return typeOf(object) === REACT_SUSPENSE_TYPE;
}
function isSuspenseList(object) {
return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;
}
exports.ContextConsumer = ContextConsumer;
exports.ContextProvider = ContextProvider;
exports.Element = Element;
exports.ForwardRef = ForwardRef;
exports.Fragment = Fragment;
exports.Lazy = Lazy;
exports.Memo = Memo;
exports.Portal = Portal;
exports.Profiler = Profiler;
exports.StrictMode = StrictMode;
exports.Suspense = Suspense;
exports.SuspenseList = SuspenseList;
exports.isAsyncMode = isAsyncMode;
exports.isConcurrentMode = isConcurrentMode;
exports.isContextConsumer = isContextConsumer;
exports.isContextProvider = isContextProvider;
exports.isElement = isElement;
exports.isForwardRef = isForwardRef;
exports.isFragment = isFragment;
exports.isLazy = isLazy;
exports.isMemo = isMemo;
exports.isPortal = isPortal;
exports.isProfiler = isProfiler;
exports.isStrictMode = isStrictMode;
exports.isSuspense = isSuspense;
exports.isSuspenseList = isSuspenseList;
exports.isValidElementType = isValidElementType;
exports.typeOf = typeOf;
})));
@@ -0,0 +1,15 @@
/**
* @license React
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
(function(){'use strict';(function(b,c){"object"===typeof exports&&"undefined"!==typeof module?c(exports):"function"===typeof define&&define.amd?define(["exports"],c):(b=b||self,c(b.ReactIs={}))})(this,function(b){function c(a){if("object"===typeof a&&null!==a){var b=a.$$typeof;switch(b){case q:switch(a=a.type,a){case d:case e:case f:case g:case h:return a;default:switch(a=a&&a.$$typeof,a){case t:case k:case l:case m:case n:case p:return a;default:return b}}case r:return b}}}var q=Symbol.for("react.element"),
r=Symbol.for("react.portal"),d=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),e=Symbol.for("react.profiler"),p=Symbol.for("react.provider"),k=Symbol.for("react.context"),t=Symbol.for("react.server_context"),l=Symbol.for("react.forward_ref"),g=Symbol.for("react.suspense"),h=Symbol.for("react.suspense_list"),n=Symbol.for("react.memo"),m=Symbol.for("react.lazy"),u=Symbol.for("react.offscreen");var v=Symbol.for("react.module.reference");b.ContextConsumer=k;b.ContextProvider=p;b.Element=
q;b.ForwardRef=l;b.Fragment=d;b.Lazy=m;b.Memo=n;b.Portal=r;b.Profiler=e;b.StrictMode=f;b.Suspense=g;b.SuspenseList=h;b.isAsyncMode=function(a){return!1};b.isConcurrentMode=function(a){return!1};b.isContextConsumer=function(a){return c(a)===k};b.isContextProvider=function(a){return c(a)===p};b.isElement=function(a){return"object"===typeof a&&null!==a&&a.$$typeof===q};b.isForwardRef=function(a){return c(a)===l};b.isFragment=function(a){return c(a)===d};b.isLazy=function(a){return c(a)===m};b.isMemo=
function(a){return c(a)===n};b.isPortal=function(a){return c(a)===r};b.isProfiler=function(a){return c(a)===e};b.isStrictMode=function(a){return c(a)===f};b.isSuspense=function(a){return c(a)===g};b.isSuspenseList=function(a){return c(a)===h};b.isValidElementType=function(a){return"string"===typeof a||"function"===typeof a||a===d||a===e||a===f||a===g||a===h||a===u||"object"===typeof a&&null!==a&&(a.$$typeof===m||a.$$typeof===n||a.$$typeof===p||a.$$typeof===k||a.$$typeof===l||a.$$typeof===v||void 0!==
a.getModuleId)?!0:!1};b.typeOf=c});
})();
+54
View File
@@ -0,0 +1,54 @@
{
"name": "@vitest/snapshot",
"type": "module",
"version": "1.6.1",
"description": "Vitest snapshot manager",
"license": "MIT",
"funding": "https://opencollective.com/vitest",
"homepage": "https://github.com/vitest-dev/vitest/tree/main/packages/snapshot#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/vitest-dev/vitest.git",
"directory": "packages/snapshot"
},
"bugs": {
"url": "https://github.com/vitest-dev/vitest/issues"
},
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./environment": {
"types": "./dist/environment.d.ts",
"default": "./dist/environment.js"
},
"./manager": {
"types": "./dist/manager.d.ts",
"default": "./dist/manager.js"
},
"./*": "./*"
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"*.d.ts",
"dist"
],
"dependencies": {
"magic-string": "^0.30.5",
"pathe": "^1.1.1",
"pretty-format": "^29.7.0"
},
"devDependencies": {
"@types/natural-compare": "^1.4.3",
"natural-compare": "^1.4.0",
"@vitest/utils": "1.6.1"
},
"scripts": {
"build": "rimraf dist && rollup -c",
"dev": "rollup -c --watch"
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-Present Vitest Team
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.
+3
View File
@@ -0,0 +1,3 @@
# @vitest/spy
Lightweight Jest compatible spy implementation.
+285
View File
@@ -0,0 +1,285 @@
interface MockResultReturn<T> {
type: 'return';
/**
* The value that was returned from the function. If function returned a Promise, then this will be a resolved value.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* An error that was thrown during function execution.
*/
value: any;
}
type MockResult<T> = MockResultReturn<T> | MockResultThrow | MockResultIncomplete;
interface MockContext<TArgs, TReturns> {
/**
* This is an array containing all arguments for each call. One item of the array is the arguments of that call.
*
* @example
* const fn = vi.fn()
*
* fn('arg1', 'arg2')
* fn('arg3')
*
* fn.mock.calls === [
* ['arg1', 'arg2'], // first call
* ['arg3'], // second call
* ]
*/
calls: TArgs[];
/**
* This is an array containing all instances that were instantiated when mock was called with a `new` keyword. Note that this is an actual context (`this`) of the function, not a return value.
*/
instances: TReturns[];
/**
* The order of mock's execution. This returns an array of numbers which are shared between all defined mocks.
*
* @example
* const fn1 = vi.fn()
* const fn2 = vi.fn()
*
* fn1()
* fn2()
* fn1()
*
* fn1.mock.invocationCallOrder === [1, 3]
* fn2.mock.invocationCallOrder === [2]
*/
invocationCallOrder: number[];
/**
* This is an array containing all values that were `returned` from the function.
*
* The `value` property contains the returned value or thrown error. If the function returned a promise, the `value` will be the _resolved_ value, not the actual `Promise`, unless it was never resolved.
*
* @example
* const fn = vi.fn()
* .mockReturnValueOnce('result')
* .mockImplementationOnce(() => { throw new Error('thrown error') })
*
* const result = fn()
*
* try {
* fn()
* }
* catch {}
*
* fn.mock.results === [
* {
* type: 'return',
* value: 'result',
* },
* {
* type: 'throw',
* value: Error,
* },
* ]
*/
results: MockResult<TReturns>[];
/**
* This contains the arguments of the last call. If spy wasn't called, will return `undefined`.
*/
lastCall: TArgs | undefined;
}
type Procedure = (...args: any[]) => any;
type Methods<T> = keyof {
[K in keyof T as T[K] extends Procedure ? K : never]: T[K];
};
type Properties<T> = {
[K in keyof T]: T[K] extends Procedure ? never : K;
}[keyof T] & (string | symbol);
type Classes<T> = {
[K in keyof T]: T[K] extends new (...args: any[]) => any ? K : never;
}[keyof T] & (string | symbol);
/**
* @deprecated Use MockInstance<A, R> instead
*/
interface SpyInstance<TArgs extends any[] = any[], TReturns = any> extends MockInstance<TArgs, TReturns> {
}
interface MockInstance<TArgs extends any[] = any[], TReturns = any> {
/**
* Use it to return the name given to mock with method `.mockName(name)`.
*/
getMockName: () => string;
/**
* Sets internal mock name. Useful to see the name of the mock if an assertion fails.
*/
mockName: (n: string) => this;
/**
* Current context of the mock. It stores information about all invocation calls, instances, and results.
*/
mock: MockContext<TArgs, TReturns>;
/**
* Clears all information about every call. After calling it, all properties on `.mock` will return an empty state. This method does not reset implementations.
*
* It is useful if you need to clean up mock between different assertions.
*/
mockClear: () => this;
/**
* Does what `mockClear` does and makes inner implementation an empty function (returning `undefined` when invoked). This also resets all "once" implementations.
*
* This is useful when you want to completely reset a mock to the default state.
*/
mockReset: () => this;
/**
* Does what `mockReset` does and restores inner implementation to the original function.
*
* Note that restoring mock from `vi.fn()` will set implementation to an empty function that returns `undefined`. Restoring a `vi.fn(impl)` will restore implementation to `impl`.
*/
mockRestore: () => void;
/**
* Returns current mock implementation if there is one.
*
* If mock was created with `vi.fn`, it will consider passed down method as a mock implementation.
*
* If mock was created with `vi.spyOn`, it will return `undefined` unless a custom implementation was provided.
*/
getMockImplementation: () => ((...args: TArgs) => TReturns) | undefined;
/**
* Accepts a function that will be used as an implementation of the mock.
* @example
* const increment = vi.fn().mockImplementation(count => count + 1);
* expect(increment(3)).toBe(4);
*/
mockImplementation: (fn: ((...args: TArgs) => TReturns)) => this;
/**
* Accepts a function that will be used as a mock implementation during the next call. Can be chained so that multiple function calls produce different results.
* @example
* const fn = vi.fn(count => count).mockImplementationOnce(count => count + 1);
* expect(fn(3)).toBe(4);
* expect(fn(3)).toBe(3);
*/
mockImplementationOnce: (fn: ((...args: TArgs) => TReturns)) => this;
/**
* Overrides the original mock implementation temporarily while the callback is being executed.
* @example
* const myMockFn = vi.fn(() => 'original')
*
* myMockFn.withImplementation(() => 'temp', () => {
* myMockFn() // 'temp'
* })
*
* myMockFn() // 'original'
*/
withImplementation: <T>(fn: ((...args: TArgs) => TReturns), cb: () => T) => T extends Promise<unknown> ? Promise<this> : this;
/**
* Use this if you need to return `this` context from the method without invoking actual implementation.
*/
mockReturnThis: () => this;
/**
* Accepts a value that will be returned whenever the mock function is called.
*/
mockReturnValue: (obj: TReturns) => this;
/**
* Accepts a value that will be returned during the next function call. If chained, every consecutive call will return the specified value.
*
* When there are no more `mockReturnValueOnce` values to use, mock will fallback to the previously defined implementation if there is one.
* @example
* const myMockFn = vi
* .fn()
* .mockReturnValue('default')
* .mockReturnValueOnce('first call')
* .mockReturnValueOnce('second call')
*
* // 'first call', 'second call', 'default'
* console.log(myMockFn(), myMockFn(), myMockFn())
*/
mockReturnValueOnce: (obj: TReturns) => this;
/**
* Accepts a value that will be resolved when async function is called.
* @example
* const asyncMock = vi.fn().mockResolvedValue(42)
* asyncMock() // Promise<42>
*/
mockResolvedValue: (obj: Awaited<TReturns>) => this;
/**
* Accepts a value that will be resolved during the next function call. If chained, every consecutive call will resolve specified value.
* @example
* const myMockFn = vi
* .fn()
* .mockResolvedValue('default')
* .mockResolvedValueOnce('first call')
* .mockResolvedValueOnce('second call')
*
* // Promise<'first call'>, Promise<'second call'>, Promise<'default'>
* console.log(myMockFn(), myMockFn(), myMockFn())
*/
mockResolvedValueOnce: (obj: Awaited<TReturns>) => this;
/**
* Accepts an error that will be rejected when async function is called.
* @example
* const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
* await asyncMock() // throws 'Async error'
*/
mockRejectedValue: (obj: any) => this;
/**
* Accepts a value that will be rejected during the next function call. If chained, every consecutive call will reject specified value.
* @example
* const asyncMock = vi
* .fn()
* .mockResolvedValueOnce('first call')
* .mockRejectedValueOnce(new Error('Async error'))
*
* await asyncMock() // first call
* await asyncMock() // throws "Async error"
*/
mockRejectedValueOnce: (obj: any) => this;
}
interface Mock<TArgs extends any[] = any, TReturns = any> extends MockInstance<TArgs, TReturns> {
new (...args: TArgs): TReturns;
(...args: TArgs): TReturns;
}
interface PartialMock<TArgs extends any[] = any, TReturns = any> extends MockInstance<TArgs, TReturns extends Promise<Awaited<TReturns>> ? Promise<Partial<Awaited<TReturns>>> : Partial<TReturns>> {
new (...args: TArgs): TReturns;
(...args: TArgs): TReturns;
}
type MaybeMockedConstructor<T> = T extends new (...args: Array<any>) => infer R ? Mock<ConstructorParameters<T>, R> : T;
type MockedFunction<T extends Procedure> = Mock<Parameters<T>, ReturnType<T>> & {
[K in keyof T]: T[K];
};
type PartiallyMockedFunction<T extends Procedure> = PartialMock<Parameters<T>, ReturnType<T>> & {
[K in keyof T]: T[K];
};
type MockedFunctionDeep<T extends Procedure> = Mock<Parameters<T>, ReturnType<T>> & MockedObjectDeep<T>;
type PartiallyMockedFunctionDeep<T extends Procedure> = PartialMock<Parameters<T>, ReturnType<T>> & MockedObjectDeep<T>;
type MockedObject<T> = MaybeMockedConstructor<T> & {
[K in Methods<T>]: T[K] extends Procedure ? MockedFunction<T[K]> : T[K];
} & {
[K in Properties<T>]: T[K];
};
type MockedObjectDeep<T> = MaybeMockedConstructor<T> & {
[K in Methods<T>]: T[K] extends Procedure ? MockedFunctionDeep<T[K]> : T[K];
} & {
[K in Properties<T>]: MaybeMockedDeep<T[K]>;
};
type MaybeMockedDeep<T> = T extends Procedure ? MockedFunctionDeep<T> : T extends object ? MockedObjectDeep<T> : T;
type MaybePartiallyMockedDeep<T> = T extends Procedure ? PartiallyMockedFunctionDeep<T> : T extends object ? MockedObjectDeep<T> : T;
type MaybeMocked<T> = T extends Procedure ? MockedFunction<T> : T extends object ? MockedObject<T> : T;
type MaybePartiallyMocked<T> = T extends Procedure ? PartiallyMockedFunction<T> : T extends object ? MockedObject<T> : T;
interface Constructable {
new (...args: any[]): any;
}
type MockedClass<T extends Constructable> = MockInstance<T extends new (...args: infer P) => any ? P : never, InstanceType<T>> & {
prototype: T extends {
prototype: any;
} ? Mocked<T['prototype']> : never;
} & T;
type Mocked<T> = {
[P in keyof T]: T[P] extends (...args: infer Args) => infer Returns ? MockInstance<Args, Returns> : T[P] extends Constructable ? MockedClass<T[P]> : T[P];
} & T;
declare const mocks: Set<MockInstance<any[], any>>;
declare function isMockFunction(fn: any): fn is MockInstance;
declare function spyOn<T, S extends Properties<Required<T>>>(obj: T, methodName: S, accessType: 'get'): MockInstance<[], T[S]>;
declare function spyOn<T, G extends Properties<Required<T>>>(obj: T, methodName: G, accessType: 'set'): MockInstance<[T[G]], void>;
declare function spyOn<T, M extends (Classes<Required<T>> | Methods<Required<T>>)>(obj: T, methodName: M): Required<T>[M] extends ({
new (...args: infer A): infer R;
}) | ((...args: infer A) => infer R) ? MockInstance<A, R> : never;
declare function fn<TArgs extends any[] = any, R = any>(): Mock<TArgs, R>;
declare function fn<TArgs extends any[] = any[], R = any>(implementation: (...args: TArgs) => R): Mock<TArgs, R>;
export { type MaybeMocked, type MaybeMockedConstructor, type MaybeMockedDeep, type MaybePartiallyMocked, type MaybePartiallyMockedDeep, type Mock, type MockContext, type MockInstance, type Mocked, type MockedClass, type MockedFunction, type MockedFunctionDeep, type MockedObject, type MockedObjectDeep, type PartialMock, type PartiallyMockedFunction, type PartiallyMockedFunctionDeep, type SpyInstance, fn, isMockFunction, mocks, spyOn };
+130
View File
@@ -0,0 +1,130 @@
import * as tinyspy from 'tinyspy';
const mocks = /* @__PURE__ */ new Set();
function isMockFunction(fn2) {
return typeof fn2 === "function" && "_isMockFunction" in fn2 && fn2._isMockFunction;
}
function spyOn(obj, method, accessType) {
const dictionary = {
get: "getter",
set: "setter"
};
const objMethod = accessType ? { [dictionary[accessType]]: method } : method;
const stub = tinyspy.internalSpyOn(obj, objMethod);
return enhanceSpy(stub);
}
let callOrder = 0;
function enhanceSpy(spy) {
const stub = spy;
let implementation;
let instances = [];
let invocations = [];
const state = tinyspy.getInternalState(spy);
const mockContext = {
get calls() {
return state.calls;
},
get instances() {
return instances;
},
get invocationCallOrder() {
return invocations;
},
get results() {
return state.results.map(([callType, value]) => {
const type = callType === "error" ? "throw" : "return";
return { type, value };
});
},
get lastCall() {
return state.calls[state.calls.length - 1];
}
};
let onceImplementations = [];
let implementationChangedTemporarily = false;
function mockCall(...args) {
instances.push(this);
invocations.push(++callOrder);
const impl = implementationChangedTemporarily ? implementation : onceImplementations.shift() || implementation || state.getOriginal() || (() => {
});
return impl.apply(this, args);
}
let name = stub.name;
stub.getMockName = () => name || "vi.fn()";
stub.mockName = (n) => {
name = n;
return stub;
};
stub.mockClear = () => {
state.reset();
instances = [];
invocations = [];
return stub;
};
stub.mockReset = () => {
stub.mockClear();
implementation = () => void 0;
onceImplementations = [];
return stub;
};
stub.mockRestore = () => {
stub.mockReset();
state.restore();
implementation = void 0;
return stub;
};
stub.getMockImplementation = () => implementation;
stub.mockImplementation = (fn2) => {
implementation = fn2;
state.willCall(mockCall);
return stub;
};
stub.mockImplementationOnce = (fn2) => {
onceImplementations.push(fn2);
return stub;
};
function withImplementation(fn2, cb) {
const originalImplementation = implementation;
implementation = fn2;
state.willCall(mockCall);
implementationChangedTemporarily = true;
const reset = () => {
implementation = originalImplementation;
implementationChangedTemporarily = false;
};
const result = cb();
if (result instanceof Promise) {
return result.then(() => {
reset();
return stub;
});
}
reset();
return stub;
}
stub.withImplementation = withImplementation;
stub.mockReturnThis = () => stub.mockImplementation(function() {
return this;
});
stub.mockReturnValue = (val) => stub.mockImplementation(() => val);
stub.mockReturnValueOnce = (val) => stub.mockImplementationOnce(() => val);
stub.mockResolvedValue = (val) => stub.mockImplementation(() => Promise.resolve(val));
stub.mockResolvedValueOnce = (val) => stub.mockImplementationOnce(() => Promise.resolve(val));
stub.mockRejectedValue = (val) => stub.mockImplementation(() => Promise.reject(val));
stub.mockRejectedValueOnce = (val) => stub.mockImplementationOnce(() => Promise.reject(val));
Object.defineProperty(stub, "mock", {
get: () => mockContext
});
state.willCall(mockCall);
mocks.add(stub);
return stub;
}
function fn(implementation) {
const enhancedSpy = enhanceSpy(tinyspy.internalSpyOn({ spy: implementation || (() => {
}) }, "spy"));
if (implementation)
enhancedSpy.mockImplementation(implementation);
return enhancedSpy;
}
export { fn, isMockFunction, mocks, spyOn };
+38
View File
@@ -0,0 +1,38 @@
{
"name": "@vitest/spy",
"type": "module",
"version": "1.6.1",
"description": "Lightweight Jest compatible spy implementation",
"license": "MIT",
"funding": "https://opencollective.com/vitest",
"homepage": "https://github.com/vitest-dev/vitest/tree/main/packages/spy#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/vitest-dev/vitest.git",
"directory": "packages/spy"
},
"bugs": {
"url": "https://github.com/vitest-dev/vitest/issues"
},
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./*": "./*"
},
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"dependencies": {
"tinyspy": "^2.2.0"
},
"scripts": {
"build": "rimraf dist && rollup -c",
"dev": "rollup -c --watch"
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-Present Vitest Team
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.
+1
View File
@@ -0,0 +1 @@
export * from './dist/diff.js'
+723
View File
@@ -0,0 +1,723 @@
// This definition file follows a somewhat unusual format. ESTree allows
// runtime type checks based on the `type` parameter. In order to explain this
// to typescript we want to use discriminated union types:
// https://github.com/Microsoft/TypeScript/pull/9163
//
// For ESTree this is a bit tricky because the high level interfaces like
// Node or Function are pulling double duty. We want to pass common fields down
// to the interfaces that extend them (like Identifier or
// ArrowFunctionExpression), but you can't extend a type union or enforce
// common fields on them. So we've split the high level interfaces into two
// types, a base type which passes down inherited fields, and a type union of
// all types which extend the base type. Only the type union is exported, and
// the union is how other types refer to the collection of inheriting types.
//
// This makes the definitions file here somewhat more difficult to maintain,
// but it has the notable advantage of making ESTree much easier to use as
// an end user.
interface BaseNodeWithoutComments {
// Every leaf interface that extends BaseNode must specify a type property.
// The type property should be a string literal. For example, Identifier
// has: `type: "Identifier"`
type: string;
loc?: SourceLocation | null | undefined;
range?: [number, number] | undefined;
}
interface BaseNode extends BaseNodeWithoutComments {
leadingComments?: Comment[] | undefined;
trailingComments?: Comment[] | undefined;
}
interface NodeMap {
AssignmentProperty: AssignmentProperty;
CatchClause: CatchClause;
Class: Class;
ClassBody: ClassBody;
Expression: Expression;
Function: Function;
Identifier: Identifier;
Literal: Literal;
MethodDefinition: MethodDefinition;
ModuleDeclaration: ModuleDeclaration;
ModuleSpecifier: ModuleSpecifier;
Pattern: Pattern;
PrivateIdentifier: PrivateIdentifier;
Program: Program;
Property: Property;
PropertyDefinition: PropertyDefinition;
SpreadElement: SpreadElement;
Statement: Statement;
Super: Super;
SwitchCase: SwitchCase;
TemplateElement: TemplateElement;
VariableDeclarator: VariableDeclarator;
}
type Node$1 = NodeMap[keyof NodeMap];
interface Comment extends BaseNodeWithoutComments {
type: "Line" | "Block";
value: string;
}
interface SourceLocation {
source?: string | null | undefined;
start: Position;
end: Position;
}
interface Position {
/** >= 1 */
line: number;
/** >= 0 */
column: number;
}
interface Program extends BaseNode {
type: "Program";
sourceType: "script" | "module";
body: Array<Directive | Statement | ModuleDeclaration>;
comments?: Comment[] | undefined;
}
interface Directive extends BaseNode {
type: "ExpressionStatement";
expression: Literal;
directive: string;
}
interface BaseFunction extends BaseNode {
params: Pattern[];
generator?: boolean | undefined;
async?: boolean | undefined;
// The body is either BlockStatement or Expression because arrow functions
// can have a body that's either. FunctionDeclarations and
// FunctionExpressions have only BlockStatement bodies.
body: BlockStatement | Expression;
}
type Function = FunctionDeclaration | FunctionExpression | ArrowFunctionExpression;
type Statement =
| ExpressionStatement
| BlockStatement
| StaticBlock
| EmptyStatement
| DebuggerStatement
| WithStatement
| ReturnStatement
| LabeledStatement
| BreakStatement
| ContinueStatement
| IfStatement
| SwitchStatement
| ThrowStatement
| TryStatement
| WhileStatement
| DoWhileStatement
| ForStatement
| ForInStatement
| ForOfStatement
| Declaration;
interface BaseStatement extends BaseNode {}
interface EmptyStatement extends BaseStatement {
type: "EmptyStatement";
}
interface BlockStatement extends BaseStatement {
type: "BlockStatement";
body: Statement[];
innerComments?: Comment[] | undefined;
}
interface StaticBlock extends Omit<BlockStatement, "type"> {
type: "StaticBlock";
}
interface ExpressionStatement extends BaseStatement {
type: "ExpressionStatement";
expression: Expression;
}
interface IfStatement extends BaseStatement {
type: "IfStatement";
test: Expression;
consequent: Statement;
alternate?: Statement | null | undefined;
}
interface LabeledStatement extends BaseStatement {
type: "LabeledStatement";
label: Identifier;
body: Statement;
}
interface BreakStatement extends BaseStatement {
type: "BreakStatement";
label?: Identifier | null | undefined;
}
interface ContinueStatement extends BaseStatement {
type: "ContinueStatement";
label?: Identifier | null | undefined;
}
interface WithStatement extends BaseStatement {
type: "WithStatement";
object: Expression;
body: Statement;
}
interface SwitchStatement extends BaseStatement {
type: "SwitchStatement";
discriminant: Expression;
cases: SwitchCase[];
}
interface ReturnStatement extends BaseStatement {
type: "ReturnStatement";
argument?: Expression | null | undefined;
}
interface ThrowStatement extends BaseStatement {
type: "ThrowStatement";
argument: Expression;
}
interface TryStatement extends BaseStatement {
type: "TryStatement";
block: BlockStatement;
handler?: CatchClause | null | undefined;
finalizer?: BlockStatement | null | undefined;
}
interface WhileStatement extends BaseStatement {
type: "WhileStatement";
test: Expression;
body: Statement;
}
interface DoWhileStatement extends BaseStatement {
type: "DoWhileStatement";
body: Statement;
test: Expression;
}
interface ForStatement extends BaseStatement {
type: "ForStatement";
init?: VariableDeclaration | Expression | null | undefined;
test?: Expression | null | undefined;
update?: Expression | null | undefined;
body: Statement;
}
interface BaseForXStatement extends BaseStatement {
left: VariableDeclaration | Pattern;
right: Expression;
body: Statement;
}
interface ForInStatement extends BaseForXStatement {
type: "ForInStatement";
}
interface DebuggerStatement extends BaseStatement {
type: "DebuggerStatement";
}
type Declaration = FunctionDeclaration | VariableDeclaration | ClassDeclaration;
interface BaseDeclaration extends BaseStatement {}
interface MaybeNamedFunctionDeclaration extends BaseFunction, BaseDeclaration {
type: "FunctionDeclaration";
/** It is null when a function declaration is a part of the `export default function` statement */
id: Identifier | null;
body: BlockStatement;
}
interface FunctionDeclaration extends MaybeNamedFunctionDeclaration {
id: Identifier;
}
interface VariableDeclaration extends BaseDeclaration {
type: "VariableDeclaration";
declarations: VariableDeclarator[];
kind: "var" | "let" | "const";
}
interface VariableDeclarator extends BaseNode {
type: "VariableDeclarator";
id: Pattern;
init?: Expression | null | undefined;
}
interface ExpressionMap {
ArrayExpression: ArrayExpression;
ArrowFunctionExpression: ArrowFunctionExpression;
AssignmentExpression: AssignmentExpression;
AwaitExpression: AwaitExpression;
BinaryExpression: BinaryExpression;
CallExpression: CallExpression;
ChainExpression: ChainExpression;
ClassExpression: ClassExpression;
ConditionalExpression: ConditionalExpression;
FunctionExpression: FunctionExpression;
Identifier: Identifier;
ImportExpression: ImportExpression;
Literal: Literal;
LogicalExpression: LogicalExpression;
MemberExpression: MemberExpression;
MetaProperty: MetaProperty;
NewExpression: NewExpression;
ObjectExpression: ObjectExpression;
SequenceExpression: SequenceExpression;
TaggedTemplateExpression: TaggedTemplateExpression;
TemplateLiteral: TemplateLiteral;
ThisExpression: ThisExpression;
UnaryExpression: UnaryExpression;
UpdateExpression: UpdateExpression;
YieldExpression: YieldExpression;
}
type Expression = ExpressionMap[keyof ExpressionMap];
interface BaseExpression extends BaseNode {}
type ChainElement = SimpleCallExpression | MemberExpression;
interface ChainExpression extends BaseExpression {
type: "ChainExpression";
expression: ChainElement;
}
interface ThisExpression extends BaseExpression {
type: "ThisExpression";
}
interface ArrayExpression extends BaseExpression {
type: "ArrayExpression";
elements: Array<Expression | SpreadElement | null>;
}
interface ObjectExpression extends BaseExpression {
type: "ObjectExpression";
properties: Array<Property | SpreadElement>;
}
interface PrivateIdentifier extends BaseNode {
type: "PrivateIdentifier";
name: string;
}
interface Property extends BaseNode {
type: "Property";
key: Expression | PrivateIdentifier;
value: Expression | Pattern; // Could be an AssignmentProperty
kind: "init" | "get" | "set";
method: boolean;
shorthand: boolean;
computed: boolean;
}
interface PropertyDefinition extends BaseNode {
type: "PropertyDefinition";
key: Expression | PrivateIdentifier;
value?: Expression | null | undefined;
computed: boolean;
static: boolean;
}
interface FunctionExpression extends BaseFunction, BaseExpression {
id?: Identifier | null | undefined;
type: "FunctionExpression";
body: BlockStatement;
}
interface SequenceExpression extends BaseExpression {
type: "SequenceExpression";
expressions: Expression[];
}
interface UnaryExpression extends BaseExpression {
type: "UnaryExpression";
operator: UnaryOperator;
prefix: true;
argument: Expression;
}
interface BinaryExpression extends BaseExpression {
type: "BinaryExpression";
operator: BinaryOperator;
left: Expression;
right: Expression;
}
interface AssignmentExpression extends BaseExpression {
type: "AssignmentExpression";
operator: AssignmentOperator;
left: Pattern | MemberExpression;
right: Expression;
}
interface UpdateExpression extends BaseExpression {
type: "UpdateExpression";
operator: UpdateOperator;
argument: Expression;
prefix: boolean;
}
interface LogicalExpression extends BaseExpression {
type: "LogicalExpression";
operator: LogicalOperator;
left: Expression;
right: Expression;
}
interface ConditionalExpression extends BaseExpression {
type: "ConditionalExpression";
test: Expression;
alternate: Expression;
consequent: Expression;
}
interface BaseCallExpression extends BaseExpression {
callee: Expression | Super;
arguments: Array<Expression | SpreadElement>;
}
type CallExpression = SimpleCallExpression | NewExpression;
interface SimpleCallExpression extends BaseCallExpression {
type: "CallExpression";
optional: boolean;
}
interface NewExpression extends BaseCallExpression {
type: "NewExpression";
}
interface MemberExpression extends BaseExpression, BasePattern {
type: "MemberExpression";
object: Expression | Super;
property: Expression | PrivateIdentifier;
computed: boolean;
optional: boolean;
}
type Pattern = Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression;
interface BasePattern extends BaseNode {}
interface SwitchCase extends BaseNode {
type: "SwitchCase";
test?: Expression | null | undefined;
consequent: Statement[];
}
interface CatchClause extends BaseNode {
type: "CatchClause";
param: Pattern | null;
body: BlockStatement;
}
interface Identifier extends BaseNode, BaseExpression, BasePattern {
type: "Identifier";
name: string;
}
type Literal = SimpleLiteral | RegExpLiteral | BigIntLiteral;
interface SimpleLiteral extends BaseNode, BaseExpression {
type: "Literal";
value: string | boolean | number | null;
raw?: string | undefined;
}
interface RegExpLiteral extends BaseNode, BaseExpression {
type: "Literal";
value?: RegExp | null | undefined;
regex: {
pattern: string;
flags: string;
};
raw?: string | undefined;
}
interface BigIntLiteral extends BaseNode, BaseExpression {
type: "Literal";
value?: bigint | null | undefined;
bigint: string;
raw?: string | undefined;
}
type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete";
type BinaryOperator =
| "=="
| "!="
| "==="
| "!=="
| "<"
| "<="
| ">"
| ">="
| "<<"
| ">>"
| ">>>"
| "+"
| "-"
| "*"
| "/"
| "%"
| "**"
| "|"
| "^"
| "&"
| "in"
| "instanceof";
type LogicalOperator = "||" | "&&" | "??";
type AssignmentOperator =
| "="
| "+="
| "-="
| "*="
| "/="
| "%="
| "**="
| "<<="
| ">>="
| ">>>="
| "|="
| "^="
| "&="
| "||="
| "&&="
| "??=";
type UpdateOperator = "++" | "--";
interface ForOfStatement extends BaseForXStatement {
type: "ForOfStatement";
await: boolean;
}
interface Super extends BaseNode {
type: "Super";
}
interface SpreadElement extends BaseNode {
type: "SpreadElement";
argument: Expression;
}
interface ArrowFunctionExpression extends BaseExpression, BaseFunction {
type: "ArrowFunctionExpression";
expression: boolean;
body: BlockStatement | Expression;
}
interface YieldExpression extends BaseExpression {
type: "YieldExpression";
argument?: Expression | null | undefined;
delegate: boolean;
}
interface TemplateLiteral extends BaseExpression {
type: "TemplateLiteral";
quasis: TemplateElement[];
expressions: Expression[];
}
interface TaggedTemplateExpression extends BaseExpression {
type: "TaggedTemplateExpression";
tag: Expression;
quasi: TemplateLiteral;
}
interface TemplateElement extends BaseNode {
type: "TemplateElement";
tail: boolean;
value: {
/** It is null when the template literal is tagged and the text has an invalid escape (e.g. - tag`\unicode and \u{55}`) */
cooked?: string | null | undefined;
raw: string;
};
}
interface AssignmentProperty extends Property {
value: Pattern;
kind: "init";
method: boolean; // false
}
interface ObjectPattern extends BasePattern {
type: "ObjectPattern";
properties: Array<AssignmentProperty | RestElement>;
}
interface ArrayPattern extends BasePattern {
type: "ArrayPattern";
elements: Array<Pattern | null>;
}
interface RestElement extends BasePattern {
type: "RestElement";
argument: Pattern;
}
interface AssignmentPattern extends BasePattern {
type: "AssignmentPattern";
left: Pattern;
right: Expression;
}
type Class = ClassDeclaration | ClassExpression;
interface BaseClass extends BaseNode {
superClass?: Expression | null | undefined;
body: ClassBody;
}
interface ClassBody extends BaseNode {
type: "ClassBody";
body: Array<MethodDefinition | PropertyDefinition | StaticBlock>;
}
interface MethodDefinition extends BaseNode {
type: "MethodDefinition";
key: Expression | PrivateIdentifier;
value: FunctionExpression;
kind: "constructor" | "method" | "get" | "set";
computed: boolean;
static: boolean;
}
interface MaybeNamedClassDeclaration extends BaseClass, BaseDeclaration {
type: "ClassDeclaration";
/** It is null when a class declaration is a part of the `export default class` statement */
id: Identifier | null;
}
interface ClassDeclaration extends MaybeNamedClassDeclaration {
id: Identifier;
}
interface ClassExpression extends BaseClass, BaseExpression {
type: "ClassExpression";
id?: Identifier | null | undefined;
}
interface MetaProperty extends BaseExpression {
type: "MetaProperty";
meta: Identifier;
property: Identifier;
}
type ModuleDeclaration =
| ImportDeclaration
| ExportNamedDeclaration
| ExportDefaultDeclaration
| ExportAllDeclaration;
interface BaseModuleDeclaration extends BaseNode {}
type ModuleSpecifier = ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ExportSpecifier;
interface BaseModuleSpecifier extends BaseNode {
local: Identifier;
}
interface ImportDeclaration extends BaseModuleDeclaration {
type: "ImportDeclaration";
specifiers: Array<ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier>;
source: Literal;
}
interface ImportSpecifier extends BaseModuleSpecifier {
type: "ImportSpecifier";
imported: Identifier;
}
interface ImportExpression extends BaseExpression {
type: "ImportExpression";
source: Expression;
}
interface ImportDefaultSpecifier extends BaseModuleSpecifier {
type: "ImportDefaultSpecifier";
}
interface ImportNamespaceSpecifier extends BaseModuleSpecifier {
type: "ImportNamespaceSpecifier";
}
interface ExportNamedDeclaration extends BaseModuleDeclaration {
type: "ExportNamedDeclaration";
declaration?: Declaration | null | undefined;
specifiers: ExportSpecifier[];
source?: Literal | null | undefined;
}
interface ExportSpecifier extends BaseModuleSpecifier {
type: "ExportSpecifier";
exported: Identifier;
}
interface ExportDefaultDeclaration extends BaseModuleDeclaration {
type: "ExportDefaultDeclaration";
declaration: MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration | Expression;
}
interface ExportAllDeclaration extends BaseModuleDeclaration {
type: "ExportAllDeclaration";
exported: Identifier | null;
source: Literal;
}
interface AwaitExpression extends BaseExpression {
type: "AwaitExpression";
argument: Expression;
}
type Positioned<T> = T & {
start: number;
end: number;
};
type Node = Positioned<Node$1>;
interface IdentifierInfo {
/**
* If the identifier is used in a property shorthand
* { foo } -> { foo: __import_x__.foo }
*/
hasBindingShortcut: boolean;
/**
* The identifier is used in a class declaration
*/
classDeclaration: boolean;
/**
* The identifier is a name for a class expression
*/
classExpression: boolean;
}
interface Visitors {
onIdentifier?: (node: Positioned<Identifier>, info: IdentifierInfo, parentStack: Node[]) => void;
onImportMeta?: (node: Node) => void;
onDynamicImport?: (node: Positioned<ImportExpression>) => void;
onCallExpression?: (node: Positioned<CallExpression>) => void;
}
declare function setIsNodeInPattern(node: Property): WeakSet<Node$1>;
declare function isNodeInPattern(node: Node$1): node is Property;
/**
* Same logic from \@vue/compiler-core & \@vue/compiler-sfc
* Except this is using acorn AST
*/
declare function esmWalker(root: Node, { onIdentifier, onImportMeta, onDynamicImport, onCallExpression }: Visitors): void;
declare function isStaticProperty(node: Node$1): node is Property;
declare function isStaticPropertyKey(node: Node$1, parent: Node$1): boolean;
declare function isFunctionNode(node: Node$1): node is Function;
declare function isInDestructuringAssignment(parent: Node$1, parentStack: Node$1[]): boolean;
export { type ArrayExpression, type ArrayPattern, type ArrowFunctionExpression, type AssignmentExpression, type AssignmentOperator, type AssignmentPattern, type AssignmentProperty, type AwaitExpression, type BaseCallExpression, type BaseClass, type BaseDeclaration, type BaseExpression, type BaseForXStatement, type BaseFunction, type BaseModuleDeclaration, type BaseModuleSpecifier, type BaseNode, type BaseNodeWithoutComments, type BasePattern, type BaseStatement, type BigIntLiteral, type BinaryExpression, type BinaryOperator, type BlockStatement, type BreakStatement, type CallExpression, type CatchClause, type ChainElement, type ChainExpression, type Class, type ClassBody, type ClassDeclaration, type ClassExpression, type Comment, type ConditionalExpression, type ContinueStatement, type DebuggerStatement, type Declaration, type Directive, type DoWhileStatement, type EmptyStatement, type ExportAllDeclaration, type ExportDefaultDeclaration, type ExportNamedDeclaration, type ExportSpecifier, type Expression, type ExpressionMap, type ExpressionStatement, type ForInStatement, type ForOfStatement, type ForStatement, type Function, type FunctionDeclaration, type FunctionExpression, type Identifier, type IfStatement, type ImportDeclaration, type ImportDefaultSpecifier, type ImportExpression, type ImportNamespaceSpecifier, type ImportSpecifier, type LabeledStatement, type Literal, type LogicalExpression, type LogicalOperator, type MaybeNamedClassDeclaration, type MaybeNamedFunctionDeclaration, type MemberExpression, type MetaProperty, type MethodDefinition, type ModuleDeclaration, type ModuleSpecifier, type NewExpression, type Node, type NodeMap, type ObjectExpression, type ObjectPattern, type Pattern, type Position, type Positioned, type PrivateIdentifier, type Program, type Property, type PropertyDefinition, type RegExpLiteral, type RestElement, type ReturnStatement, type SequenceExpression, type SimpleCallExpression, type SimpleLiteral, type SourceLocation, type SpreadElement, type Statement, type StaticBlock, type Super, type SwitchCase, type SwitchStatement, type TaggedTemplateExpression, type TemplateElement, type TemplateLiteral, type ThisExpression, type ThrowStatement, type TryStatement, type UnaryExpression, type UnaryOperator, type UpdateExpression, type UpdateOperator, type VariableDeclaration, type VariableDeclarator, type WhileStatement, type WithStatement, type YieldExpression, esmWalker, isFunctionNode, isInDestructuringAssignment, isNodeInPattern, isStaticProperty, isStaticPropertyKey, setIsNodeInPattern };
+180
View File
@@ -0,0 +1,180 @@
import { walk } from 'estree-walker';
const isNodeInPatternWeakSet = /* @__PURE__ */ new WeakSet();
function setIsNodeInPattern(node) {
return isNodeInPatternWeakSet.add(node);
}
function isNodeInPattern(node) {
return isNodeInPatternWeakSet.has(node);
}
function esmWalker(root, { onIdentifier, onImportMeta, onDynamicImport, onCallExpression }) {
const parentStack = [];
const varKindStack = [];
const scopeMap = /* @__PURE__ */ new WeakMap();
const identifiers = [];
const setScope = (node, name) => {
let scopeIds = scopeMap.get(node);
if (scopeIds && scopeIds.has(name))
return;
if (!scopeIds) {
scopeIds = /* @__PURE__ */ new Set();
scopeMap.set(node, scopeIds);
}
scopeIds.add(name);
};
function isInScope(name, parents) {
return parents.some((node) => {
var _a;
return node && ((_a = scopeMap.get(node)) == null ? void 0 : _a.has(name));
});
}
function handlePattern(p, parentScope) {
if (p.type === "Identifier") {
setScope(parentScope, p.name);
} else if (p.type === "RestElement") {
handlePattern(p.argument, parentScope);
} else if (p.type === "ObjectPattern") {
p.properties.forEach((property) => {
if (property.type === "RestElement")
setScope(parentScope, property.argument.name);
else
handlePattern(property.value, parentScope);
});
} else if (p.type === "ArrayPattern") {
p.elements.forEach((element) => {
if (element)
handlePattern(element, parentScope);
});
} else if (p.type === "AssignmentPattern") {
handlePattern(p.left, parentScope);
} else {
setScope(parentScope, p.name);
}
}
walk(root, {
enter(node, parent) {
if (node.type === "ImportDeclaration")
return this.skip();
if (parent && !(parent.type === "IfStatement" && node === parent.alternate))
parentStack.unshift(parent);
if (node.type === "VariableDeclaration")
varKindStack.unshift(node.kind);
if (node.type === "CallExpression")
onCallExpression == null ? void 0 : onCallExpression(node);
if (node.type === "MetaProperty" && node.meta.name === "import")
onImportMeta == null ? void 0 : onImportMeta(node);
else if (node.type === "ImportExpression")
onDynamicImport == null ? void 0 : onDynamicImport(node);
if (node.type === "Identifier") {
if (!isInScope(node.name, parentStack) && isRefIdentifier(node, parent, parentStack)) {
identifiers.push([node, parentStack.slice(0)]);
}
} else if (isFunctionNode(node)) {
if (node.type === "FunctionDeclaration") {
const parentScope = findParentScope(parentStack);
if (parentScope)
setScope(parentScope, node.id.name);
}
node.params.forEach((p) => {
if (p.type === "ObjectPattern" || p.type === "ArrayPattern") {
handlePattern(p, node);
return;
}
walk(p.type === "AssignmentPattern" ? p.left : p, {
enter(child, parent2) {
if ((parent2 == null ? void 0 : parent2.type) === "AssignmentPattern" && (parent2 == null ? void 0 : parent2.right) === child)
return this.skip();
if (child.type !== "Identifier")
return;
if (isStaticPropertyKey(child, parent2))
return;
if ((parent2 == null ? void 0 : parent2.type) === "TemplateLiteral" && (parent2 == null ? void 0 : parent2.expressions.includes(child)) || (parent2 == null ? void 0 : parent2.type) === "CallExpression" && (parent2 == null ? void 0 : parent2.callee) === child)
return;
setScope(node, child.name);
}
});
});
} else if (node.type === "Property" && parent.type === "ObjectPattern") {
setIsNodeInPattern(node);
} else if (node.type === "VariableDeclarator") {
const parentFunction = findParentScope(
parentStack,
varKindStack[0] === "var"
);
if (parentFunction)
handlePattern(node.id, parentFunction);
} else if (node.type === "CatchClause" && node.param) {
handlePattern(node.param, node);
}
},
leave(node, parent) {
if (parent && !(parent.type === "IfStatement" && node === parent.alternate))
parentStack.shift();
if (node.type === "VariableDeclaration")
varKindStack.shift();
}
});
identifiers.forEach(([node, stack]) => {
if (!isInScope(node.name, stack)) {
const parent = stack[0];
const grandparent = stack[1];
const hasBindingShortcut = isStaticProperty(parent) && parent.shorthand && (!isNodeInPattern(parent) || isInDestructuringAssignment(parent, parentStack));
const classDeclaration = parent.type === "PropertyDefinition" && (grandparent == null ? void 0 : grandparent.type) === "ClassBody" || parent.type === "ClassDeclaration" && node === parent.superClass;
const classExpression = parent.type === "ClassExpression" && node === parent.id;
onIdentifier == null ? void 0 : onIdentifier(node, {
hasBindingShortcut,
classDeclaration,
classExpression
}, stack);
}
});
}
function isRefIdentifier(id, parent, parentStack) {
if (parent.type === "CatchClause" || (parent.type === "VariableDeclarator" || parent.type === "ClassDeclaration") && parent.id === id)
return false;
if (isFunctionNode(parent)) {
if (parent.id === id)
return false;
if (parent.params.includes(id))
return false;
}
if (parent.type === "MethodDefinition" && !parent.computed)
return false;
if (isStaticPropertyKey(id, parent))
return false;
if (isNodeInPattern(parent) && parent.value === id)
return false;
if (parent.type === "ArrayPattern" && !isInDestructuringAssignment(parent, parentStack))
return false;
if (parent.type === "MemberExpression" && parent.property === id && !parent.computed)
return false;
if (parent.type === "ExportSpecifier")
return false;
if (id.name === "arguments")
return false;
return true;
}
function isStaticProperty(node) {
return node && node.type === "Property" && !node.computed;
}
function isStaticPropertyKey(node, parent) {
return isStaticProperty(parent) && parent.key === node;
}
const functionNodeTypeRE = /Function(?:Expression|Declaration)$|Method$/;
function isFunctionNode(node) {
return functionNodeTypeRE.test(node.type);
}
const blockNodeTypeRE = /^BlockStatement$|^For(?:In|Of)?Statement$/;
function isBlock(node) {
return blockNodeTypeRE.test(node.type);
}
function findParentScope(parentStack, isVar = false) {
return parentStack.find(isVar ? isFunctionNode : isBlock);
}
function isInDestructuringAssignment(parent, parentStack) {
if (parent && (parent.type === "Property" || parent.type === "ArrayPattern"))
return parentStack.some((i) => i.type === "AssignmentExpression");
return false;
}
export { esmWalker, isFunctionNode, isInDestructuringAssignment, isNodeInPattern, isStaticProperty, isStaticPropertyKey, setIsNodeInPattern };
+77
View File
@@ -0,0 +1,77 @@
const SAFE_TIMERS_SYMBOL = Symbol("vitest:SAFE_TIMERS");
const SAFE_COLORS_SYMBOL = Symbol("vitest:SAFE_COLORS");
const colorsMap = {
bold: ["\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"],
dim: ["\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"],
italic: ["\x1B[3m", "\x1B[23m"],
underline: ["\x1B[4m", "\x1B[24m"],
inverse: ["\x1B[7m", "\x1B[27m"],
hidden: ["\x1B[8m", "\x1B[28m"],
strikethrough: ["\x1B[9m", "\x1B[29m"],
black: ["\x1B[30m", "\x1B[39m"],
red: ["\x1B[31m", "\x1B[39m"],
green: ["\x1B[32m", "\x1B[39m"],
yellow: ["\x1B[33m", "\x1B[39m"],
blue: ["\x1B[34m", "\x1B[39m"],
magenta: ["\x1B[35m", "\x1B[39m"],
cyan: ["\x1B[36m", "\x1B[39m"],
white: ["\x1B[37m", "\x1B[39m"],
gray: ["\x1B[90m", "\x1B[39m"],
bgBlack: ["\x1B[40m", "\x1B[49m"],
bgRed: ["\x1B[41m", "\x1B[49m"],
bgGreen: ["\x1B[42m", "\x1B[49m"],
bgYellow: ["\x1B[43m", "\x1B[49m"],
bgBlue: ["\x1B[44m", "\x1B[49m"],
bgMagenta: ["\x1B[45m", "\x1B[49m"],
bgCyan: ["\x1B[46m", "\x1B[49m"],
bgWhite: ["\x1B[47m", "\x1B[49m"]
};
const colorsEntries = Object.entries(colorsMap);
function string(str) {
return String(str);
}
string.open = "";
string.close = "";
const defaultColors = /* @__PURE__ */ colorsEntries.reduce((acc, [key]) => {
acc[key] = string;
return acc;
}, { isColorSupported: false });
function getDefaultColors() {
return { ...defaultColors };
}
function getColors() {
return globalThis[SAFE_COLORS_SYMBOL] || defaultColors;
}
function createColors(isTTY = false) {
const enabled = typeof process !== "undefined" && !("NO_COLOR" in process.env || process.argv.includes("--no-color")) && !("GITHUB_ACTIONS" in process.env) && ("FORCE_COLOR" in process.env || process.argv.includes("--color") || process.platform === "win32" || isTTY && process.env.TERM !== "dumb" || "CI" in process.env);
const replaceClose = (string2, close, replace, index) => {
const start = string2.substring(0, index) + replace;
const end = string2.substring(index + close.length);
const nextIndex = end.indexOf(close);
return ~nextIndex ? start + replaceClose(end, close, replace, nextIndex) : start + end;
};
const formatter = (open, close, replace = open) => {
const fn = (input) => {
const string2 = String(input);
const index = string2.indexOf(close, open.length);
return ~index ? open + replaceClose(string2, close, replace, index) + close : open + string2 + close;
};
fn.open = open;
fn.close = close;
return fn;
};
const colorsObject = {
isColorSupported: enabled,
reset: enabled ? (s) => `\x1B[0m${s}\x1B[0m` : string
};
for (const [name, formatterArgs] of colorsEntries) {
colorsObject[name] = enabled ? formatter(...formatterArgs) : string;
}
return colorsObject;
}
function setupColors(colors) {
globalThis[SAFE_COLORS_SYMBOL] = colors;
}
export { SAFE_TIMERS_SYMBOL as S, SAFE_COLORS_SYMBOL as a, getDefaultColors as b, createColors as c, getColors as g, setupColors as s };
+144
View File
@@ -0,0 +1,144 @@
import { format as format$1, plugins } from 'pretty-format';
import * as loupe from 'loupe';
const {
AsymmetricMatcher,
DOMCollection,
DOMElement,
Immutable,
ReactElement,
ReactTestComponent
} = plugins;
const PLUGINS = [
ReactTestComponent,
ReactElement,
DOMElement,
DOMCollection,
Immutable,
AsymmetricMatcher
];
function stringify(object, maxDepth = 10, { maxLength, ...options } = {}) {
const MAX_LENGTH = maxLength ?? 1e4;
let result;
try {
result = format$1(object, {
maxDepth,
escapeString: false,
// min: true,
plugins: PLUGINS,
...options
});
} catch {
result = format$1(object, {
callToJSON: false,
maxDepth,
escapeString: false,
// min: true,
plugins: PLUGINS,
...options
});
}
return result.length >= MAX_LENGTH && maxDepth > 1 ? stringify(object, Math.floor(maxDepth / 2)) : result;
}
const formatRegExp = /%[sdjifoOcj%]/g;
function format(...args) {
if (typeof args[0] !== "string") {
const objects = [];
for (let i2 = 0; i2 < args.length; i2++)
objects.push(inspect(args[i2], { depth: 0, colors: false, compact: 3 }));
return objects.join(" ");
}
const len = args.length;
let i = 1;
const template = args[0];
let str = String(template).replace(formatRegExp, (x) => {
if (x === "%%")
return "%";
if (i >= len)
return x;
switch (x) {
case "%s": {
const value = args[i++];
if (typeof value === "bigint")
return `${value.toString()}n`;
if (typeof value === "number" && value === 0 && 1 / value < 0)
return "-0";
if (typeof value === "object" && value !== null)
return inspect(value, { depth: 0, colors: false, compact: 3 });
return String(value);
}
case "%d": {
const value = args[i++];
if (typeof value === "bigint")
return `${value.toString()}n`;
return Number(value).toString();
}
case "%i": {
const value = args[i++];
if (typeof value === "bigint")
return `${value.toString()}n`;
return Number.parseInt(String(value)).toString();
}
case "%f":
return Number.parseFloat(String(args[i++])).toString();
case "%o":
return inspect(args[i++], { showHidden: true, showProxy: true });
case "%O":
return inspect(args[i++]);
case "%c": {
i++;
return "";
}
case "%j":
try {
return JSON.stringify(args[i++]);
} catch (err) {
const m = err.message;
if (
// chromium
m.includes("circular structure") || m.includes("cyclic structures") || m.includes("cyclic object")
)
return "[Circular]";
throw err;
}
default:
return x;
}
});
for (let x = args[i]; i < len; x = args[++i]) {
if (x === null || typeof x !== "object")
str += ` ${x}`;
else
str += ` ${inspect(x)}`;
}
return str;
}
function inspect(obj, options = {}) {
if (options.truncate === 0)
options.truncate = Number.POSITIVE_INFINITY;
return loupe.inspect(obj, options);
}
function objDisplay(obj, options = {}) {
if (typeof options.truncate === "undefined")
options.truncate = 40;
const str = inspect(obj, options);
const type = Object.prototype.toString.call(obj);
if (options.truncate && str.length >= options.truncate) {
if (type === "[object Function]") {
const fn = obj;
return !fn.name ? "[Function]" : `[Function: ${fn.name}]`;
} else if (type === "[object Array]") {
return `[ Array(${obj.length}) ]`;
} else if (type === "[object Object]") {
const keys = Object.keys(obj);
const kstr = keys.length > 2 ? `${keys.splice(0, 2).join(", ")}, ...` : keys.join(", ");
return `{ Object (${kstr}) }`;
} else {
return str;
}
}
return str;
}
export { format as f, inspect as i, objDisplay as o, stringify as s };
+93
View File
@@ -0,0 +1,93 @@
import { D as DiffOptions } from './types-9l4niLY8.js';
export { a as DiffOptionsColor } from './types-9l4niLY8.js';
import 'pretty-format';
/**
* Diff Match and Patch
* Copyright 2018 The diff-match-patch Authors.
* https://github.com/google/diff-match-patch
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Computes the difference between two texts to create a patch.
* Applies the patch onto another text, allowing for errors.
* @author fraser@google.com (Neil Fraser)
*/
/**
* CHANGES by pedrottimark to diff_match_patch_uncompressed.ts file:
*
* 1. Delete anything not needed to use diff_cleanupSemantic method
* 2. Convert from prototype properties to var declarations
* 3. Convert Diff to class from constructor and prototype
* 4. Add type annotations for arguments and return values
* 5. Add exports
*/
/**
* The data structure representing a diff is an array of tuples:
* [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
* which means: delete 'Hello', add 'Goodbye' and keep ' world.'
*/
declare const DIFF_DELETE = -1;
declare const DIFF_INSERT = 1;
declare const DIFF_EQUAL = 0;
/**
* Class representing one diff tuple.
* Attempts to look like a two-element array (which is what this used to be).
* @param {number} op Operation, one of: DIFF_DELETE, DIFF_INSERT, DIFF_EQUAL.
* @param {string} text Text to be deleted, inserted, or retained.
* @constructor
*/
declare class Diff {
0: number;
1: string;
constructor(op: number, text: string);
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
declare function diffLinesUnified(aLines: Array<string>, bLines: Array<string>, options?: DiffOptions): string;
declare function diffLinesUnified2(aLinesDisplay: Array<string>, bLinesDisplay: Array<string>, aLinesCompare: Array<string>, bLinesCompare: Array<string>, options?: DiffOptions): string;
declare function diffLinesRaw(aLines: Array<string>, bLines: Array<string>, options?: DiffOptions): [Array<Diff>, boolean];
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
declare function diffStringsUnified(a: string, b: string, options?: DiffOptions): string;
declare function diffStringsRaw(a: string, b: string, cleanup: boolean, options?: DiffOptions): [Array<Diff>, boolean];
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @param a Expected value
* @param b Received value
* @param options Diff options
* @returns {string | null} a string diff
*/
declare function diff(a: any, b: any, options?: DiffOptions): string | null;
export { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, Diff, DiffOptions, diff, diffLinesRaw, diffLinesUnified, diffLinesUnified2, diffStringsRaw, diffStringsUnified };
+1081
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
import { D as DiffOptions } from './types-9l4niLY8.js';
import 'pretty-format';
declare function serializeError(val: any, seen?: WeakMap<WeakKey, any>): any;
declare function processError(err: any, diffOptions?: DiffOptions): any;
declare function replaceAsymmetricMatcher(actual: any, expected: any, actualReplaced?: WeakSet<WeakKey>, expectedReplaced?: WeakSet<WeakKey>): {
replacedActual: any;
replacedExpected: any;
};
export { processError, replaceAsymmetricMatcher, serializeError };
+150
View File
@@ -0,0 +1,150 @@
import { diff } from './diff.js';
import { f as format, s as stringify } from './chunk-display.js';
import { deepClone, getOwnProperties, getType } from './helpers.js';
import 'pretty-format';
import 'diff-sequences';
import './chunk-colors.js';
import 'loupe';
const IS_RECORD_SYMBOL = "@@__IMMUTABLE_RECORD__@@";
const IS_COLLECTION_SYMBOL = "@@__IMMUTABLE_ITERABLE__@@";
function isImmutable(v) {
return v && (v[IS_COLLECTION_SYMBOL] || v[IS_RECORD_SYMBOL]);
}
const OBJECT_PROTO = Object.getPrototypeOf({});
function getUnserializableMessage(err) {
if (err instanceof Error)
return `<unserializable>: ${err.message}`;
if (typeof err === "string")
return `<unserializable>: ${err}`;
return "<unserializable>";
}
function serializeError(val, seen = /* @__PURE__ */ new WeakMap()) {
if (!val || typeof val === "string")
return val;
if (typeof val === "function")
return `Function<${val.name || "anonymous"}>`;
if (typeof val === "symbol")
return val.toString();
if (typeof val !== "object")
return val;
if (isImmutable(val))
return serializeError(val.toJSON(), seen);
if (val instanceof Promise || val.constructor && val.constructor.prototype === "AsyncFunction")
return "Promise";
if (typeof Element !== "undefined" && val instanceof Element)
return val.tagName;
if (typeof val.asymmetricMatch === "function")
return `${val.toString()} ${format(val.sample)}`;
if (typeof val.toJSON === "function")
return val.toJSON();
if (seen.has(val))
return seen.get(val);
if (Array.isArray(val)) {
const clone = new Array(val.length);
seen.set(val, clone);
val.forEach((e, i) => {
try {
clone[i] = serializeError(e, seen);
} catch (err) {
clone[i] = getUnserializableMessage(err);
}
});
return clone;
} else {
const clone = /* @__PURE__ */ Object.create(null);
seen.set(val, clone);
let obj = val;
while (obj && obj !== OBJECT_PROTO) {
Object.getOwnPropertyNames(obj).forEach((key) => {
if (key in clone)
return;
try {
clone[key] = serializeError(val[key], seen);
} catch (err) {
delete clone[key];
clone[key] = getUnserializableMessage(err);
}
});
obj = Object.getPrototypeOf(obj);
}
return clone;
}
}
function normalizeErrorMessage(message) {
return message.replace(/__(vite_ssr_import|vi_import)_\d+__\./g, "");
}
function processError(err, diffOptions) {
if (!err || typeof err !== "object")
return { message: err };
if (err.stack)
err.stackStr = String(err.stack);
if (err.name)
err.nameStr = String(err.name);
if (err.showDiff || err.showDiff === void 0 && err.expected !== void 0 && err.actual !== void 0) {
const clonedActual = deepClone(err.actual, { forceWritable: true });
const clonedExpected = deepClone(err.expected, { forceWritable: true });
const { replacedActual, replacedExpected } = replaceAsymmetricMatcher(clonedActual, clonedExpected);
err.diff = diff(replacedExpected, replacedActual, { ...diffOptions, ...err.diffOptions });
}
if (typeof err.expected !== "string")
err.expected = stringify(err.expected, 10);
if (typeof err.actual !== "string")
err.actual = stringify(err.actual, 10);
try {
if (typeof err.message === "string")
err.message = normalizeErrorMessage(err.message);
if (typeof err.cause === "object" && typeof err.cause.message === "string")
err.cause.message = normalizeErrorMessage(err.cause.message);
} catch {
}
try {
return serializeError(err);
} catch (e) {
return serializeError(new Error(`Failed to fully serialize error: ${e == null ? void 0 : e.message}
Inner error message: ${err == null ? void 0 : err.message}`));
}
}
function isAsymmetricMatcher(data) {
const type = getType(data);
return type === "Object" && typeof data.asymmetricMatch === "function";
}
function isReplaceable(obj1, obj2) {
const obj1Type = getType(obj1);
const obj2Type = getType(obj2);
return obj1Type === obj2Type && (obj1Type === "Object" || obj1Type === "Array");
}
function replaceAsymmetricMatcher(actual, expected, actualReplaced = /* @__PURE__ */ new WeakSet(), expectedReplaced = /* @__PURE__ */ new WeakSet()) {
if (!isReplaceable(actual, expected))
return { replacedActual: actual, replacedExpected: expected };
if (actualReplaced.has(actual) || expectedReplaced.has(expected))
return { replacedActual: actual, replacedExpected: expected };
actualReplaced.add(actual);
expectedReplaced.add(expected);
getOwnProperties(expected).forEach((key) => {
const expectedValue = expected[key];
const actualValue = actual[key];
if (isAsymmetricMatcher(expectedValue)) {
if (expectedValue.asymmetricMatch(actualValue))
actual[key] = expectedValue;
} else if (isAsymmetricMatcher(actualValue)) {
if (actualValue.asymmetricMatch(expectedValue))
expected[key] = actualValue;
} else if (isReplaceable(actualValue, expectedValue)) {
const replaced = replaceAsymmetricMatcher(
actualValue,
expectedValue,
actualReplaced,
expectedReplaced
);
actual[key] = replaced.replacedActual;
expected[key] = replaced.replacedExpected;
}
});
return {
replacedActual: actual,
replacedExpected: expected
};
}
export { processError, replaceAsymmetricMatcher, serializeError };
+35
View File
@@ -0,0 +1,35 @@
import { Nullable, Arrayable } from './types.js';
interface CloneOptions {
forceWritable?: boolean;
}
declare function notNullish<T>(v: T | null | undefined): v is NonNullable<T>;
declare function assertTypes(value: unknown, name: string, types: string[]): void;
declare function isPrimitive(value: unknown): boolean;
declare function slash(path: string): string;
declare function parseRegexp(input: string): RegExp;
declare function toArray<T>(array?: Nullable<Arrayable<T>>): Array<T>;
declare function isObject(item: unknown): boolean;
declare function getType(value: unknown): string;
declare function getOwnProperties(obj: any): (string | symbol)[];
declare function deepClone<T>(val: T, options?: CloneOptions): T;
declare function clone<T>(val: T, seen: WeakMap<any, any>, options?: CloneOptions): T;
declare function noop(): void;
declare function objectAttr(source: any, path: string, defaultValue?: undefined): any;
type DeferPromise<T> = Promise<T> & {
resolve: (value: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
};
declare function createDefer<T>(): DeferPromise<T>;
/**
* If code starts with a function call, will return its last index, respecting arguments.
* This will return 25 - last ending character of toMatch ")"
* Also works with callbacks
* ```
* toMatch({ test: '123' });
* toBeAliased('123')
* ```
*/
declare function getCallLastIndex(code: string): number | null;
export { type DeferPromise, assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray };
+154
View File
@@ -0,0 +1,154 @@
function notNullish(v) {
return v != null;
}
function assertTypes(value, name, types) {
const receivedType = typeof value;
const pass = types.includes(receivedType);
if (!pass)
throw new TypeError(`${name} value must be ${types.join(" or ")}, received "${receivedType}"`);
}
function isPrimitive(value) {
return value === null || typeof value !== "function" && typeof value !== "object";
}
function slash(path) {
return path.replace(/\\/g, "/");
}
function parseRegexp(input) {
const m = input.match(/(\/?)(.+)\1([a-z]*)/i);
if (!m)
return /$^/;
if (m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3]))
return RegExp(input);
return new RegExp(m[2], m[3]);
}
function toArray(array) {
if (array === null || array === void 0)
array = [];
if (Array.isArray(array))
return array;
return [array];
}
function isObject(item) {
return item != null && typeof item === "object" && !Array.isArray(item);
}
function isFinalObj(obj) {
return obj === Object.prototype || obj === Function.prototype || obj === RegExp.prototype;
}
function getType(value) {
return Object.prototype.toString.apply(value).slice(8, -1);
}
function collectOwnProperties(obj, collector) {
const collect = typeof collector === "function" ? collector : (key) => collector.add(key);
Object.getOwnPropertyNames(obj).forEach(collect);
Object.getOwnPropertySymbols(obj).forEach(collect);
}
function getOwnProperties(obj) {
const ownProps = /* @__PURE__ */ new Set();
if (isFinalObj(obj))
return [];
collectOwnProperties(obj, ownProps);
return Array.from(ownProps);
}
const defaultCloneOptions = { forceWritable: false };
function deepClone(val, options = defaultCloneOptions) {
const seen = /* @__PURE__ */ new WeakMap();
return clone(val, seen, options);
}
function clone(val, seen, options = defaultCloneOptions) {
let k, out;
if (seen.has(val))
return seen.get(val);
if (Array.isArray(val)) {
out = Array(k = val.length);
seen.set(val, out);
while (k--)
out[k] = clone(val[k], seen, options);
return out;
}
if (Object.prototype.toString.call(val) === "[object Object]") {
out = Object.create(Object.getPrototypeOf(val));
seen.set(val, out);
const props = getOwnProperties(val);
for (const k2 of props) {
const descriptor = Object.getOwnPropertyDescriptor(val, k2);
if (!descriptor)
continue;
const cloned = clone(val[k2], seen, options);
if (options.forceWritable) {
Object.defineProperty(out, k2, {
enumerable: descriptor.enumerable,
configurable: true,
writable: true,
value: cloned
});
} else if ("get" in descriptor) {
Object.defineProperty(out, k2, {
...descriptor,
get() {
return cloned;
}
});
} else {
Object.defineProperty(out, k2, {
...descriptor,
value: cloned
});
}
}
return out;
}
return val;
}
function noop() {
}
function objectAttr(source, path, defaultValue = void 0) {
const paths = path.replace(/\[(\d+)\]/g, ".$1").split(".");
let result = source;
for (const p of paths) {
result = Object(result)[p];
if (result === void 0)
return defaultValue;
}
return result;
}
function createDefer() {
let resolve = null;
let reject = null;
const p = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
p.resolve = resolve;
p.reject = reject;
return p;
}
function getCallLastIndex(code) {
let charIndex = -1;
let inString = null;
let startedBracers = 0;
let endedBracers = 0;
let beforeChar = null;
while (charIndex <= code.length) {
beforeChar = code[charIndex];
charIndex++;
const char = code[charIndex];
const isCharString = char === '"' || char === "'" || char === "`";
if (isCharString && beforeChar !== "\\") {
if (inString === char)
inString = null;
else if (!inString)
inString = char;
}
if (!inString) {
if (char === "(")
startedBracers++;
if (char === ")")
endedBracers++;
}
if (startedBracers && endedBracers && startedBracers === endedBracers)
return charIndex;
}
return null;
}
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray };
+110
View File
@@ -0,0 +1,110 @@
export { DeferPromise, assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js';
export { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, ErrorWithDiff, MergeInsertions, MutableArray, Nullable, ParsedStack } from './types.js';
import { PrettyFormatOptions } from 'pretty-format';
declare function stringify(object: unknown, maxDepth?: number, { maxLength, ...options }?: PrettyFormatOptions & {
maxLength?: number;
}): string;
declare function getSafeTimers(): {
nextTick: any;
setTimeout: any;
setInterval: any;
clearInterval: any;
clearTimeout: any;
setImmediate: any;
clearImmediate: any;
};
declare function setSafeTimers(): void;
declare function shuffle<T>(array: T[], seed?: number): T[];
interface LoupeOptions {
showHidden?: boolean | undefined;
depth?: number | null | undefined;
colors?: boolean | undefined;
customInspect?: boolean | undefined;
showProxy?: boolean | undefined;
maxArrayLength?: number | null | undefined;
maxStringLength?: number | null | undefined;
breakLength?: number | undefined;
compact?: boolean | number | undefined;
sorted?: boolean | ((a: string, b: string) => number) | undefined;
getters?: 'get' | 'set' | boolean | undefined;
numericSeparator?: boolean | undefined;
truncate?: number;
}
declare function format(...args: unknown[]): string;
declare function inspect(obj: unknown, options?: LoupeOptions): string;
declare function objDisplay(obj: unknown, options?: LoupeOptions): string;
declare const SAFE_TIMERS_SYMBOL: unique symbol;
declare const SAFE_COLORS_SYMBOL: unique symbol;
declare const colorsMap: {
readonly bold: readonly ["\u001B[1m", "\u001B[22m", "\u001B[22m\u001B[1m"];
readonly dim: readonly ["\u001B[2m", "\u001B[22m", "\u001B[22m\u001B[2m"];
readonly italic: readonly ["\u001B[3m", "\u001B[23m"];
readonly underline: readonly ["\u001B[4m", "\u001B[24m"];
readonly inverse: readonly ["\u001B[7m", "\u001B[27m"];
readonly hidden: readonly ["\u001B[8m", "\u001B[28m"];
readonly strikethrough: readonly ["\u001B[9m", "\u001B[29m"];
readonly black: readonly ["\u001B[30m", "\u001B[39m"];
readonly red: readonly ["\u001B[31m", "\u001B[39m"];
readonly green: readonly ["\u001B[32m", "\u001B[39m"];
readonly yellow: readonly ["\u001B[33m", "\u001B[39m"];
readonly blue: readonly ["\u001B[34m", "\u001B[39m"];
readonly magenta: readonly ["\u001B[35m", "\u001B[39m"];
readonly cyan: readonly ["\u001B[36m", "\u001B[39m"];
readonly white: readonly ["\u001B[37m", "\u001B[39m"];
readonly gray: readonly ["\u001B[90m", "\u001B[39m"];
readonly bgBlack: readonly ["\u001B[40m", "\u001B[49m"];
readonly bgRed: readonly ["\u001B[41m", "\u001B[49m"];
readonly bgGreen: readonly ["\u001B[42m", "\u001B[49m"];
readonly bgYellow: readonly ["\u001B[43m", "\u001B[49m"];
readonly bgBlue: readonly ["\u001B[44m", "\u001B[49m"];
readonly bgMagenta: readonly ["\u001B[45m", "\u001B[49m"];
readonly bgCyan: readonly ["\u001B[46m", "\u001B[49m"];
readonly bgWhite: readonly ["\u001B[47m", "\u001B[49m"];
};
type ColorName = keyof typeof colorsMap;
interface ColorMethod {
(input: unknown): string;
open: string;
close: string;
}
type ColorsMethods = {
[Key in ColorName]: ColorMethod;
};
type Colors$1 = ColorsMethods & {
isColorSupported: boolean;
reset: (input: unknown) => string;
};
declare function getDefaultColors(): Colors$1;
declare function getColors(): Colors$1;
declare function createColors(isTTY?: boolean): Colors$1;
declare function setupColors(colors: Colors$1): void;
interface ErrorOptions {
message?: string;
stackTraceLimit?: number;
}
/**
* Get original stacktrace without source map support the most performant way.
* - Create only 1 stack frame.
* - Rewrite prepareStackTrace to bypass "support-stack-trace" (usually takes ~250ms).
*/
declare function createSimpleStackTrace(options?: ErrorOptions): string;
declare const lineSplitRE: RegExp;
declare function positionToOffset(source: string, lineNumber: number, columnNumber: number): number;
declare function offsetToLineNumber(source: string, offset: number): number;
type Colors = Record<ColorName, (input: string) => string>;
interface HighlightOptions {
jsx?: boolean;
colors?: Colors;
}
declare function highlight(code: string, options?: HighlightOptions): string;
export { type ColorMethod, type ColorName, type Colors$1 as Colors, type ColorsMethods, SAFE_COLORS_SYMBOL, SAFE_TIMERS_SYMBOL, createColors, createSimpleStackTrace, format, getColors, getDefaultColors, getSafeTimers, highlight, inspect, lineSplitRE, objDisplay, offsetToLineNumber, positionToOffset, setSafeTimers, setupColors, shuffle, stringify };
+643
View File
@@ -0,0 +1,643 @@
export { assertTypes, clone, createDefer, deepClone, getCallLastIndex, getOwnProperties, getType, isObject, isPrimitive, noop, notNullish, objectAttr, parseRegexp, slash, toArray } from './helpers.js';
export { f as format, i as inspect, o as objDisplay, s as stringify } from './chunk-display.js';
import { S as SAFE_TIMERS_SYMBOL, g as getColors } from './chunk-colors.js';
export { a as SAFE_COLORS_SYMBOL, c as createColors, b as getDefaultColors, s as setupColors } from './chunk-colors.js';
import 'pretty-format';
import 'loupe';
function getSafeTimers() {
const {
setTimeout: safeSetTimeout,
setInterval: safeSetInterval,
clearInterval: safeClearInterval,
clearTimeout: safeClearTimeout,
setImmediate: safeSetImmediate,
clearImmediate: safeClearImmediate
} = globalThis[SAFE_TIMERS_SYMBOL] || globalThis;
const {
nextTick: safeNextTick
} = globalThis[SAFE_TIMERS_SYMBOL] || globalThis.process || { nextTick: (cb) => cb() };
return {
nextTick: safeNextTick,
setTimeout: safeSetTimeout,
setInterval: safeSetInterval,
clearInterval: safeClearInterval,
clearTimeout: safeClearTimeout,
setImmediate: safeSetImmediate,
clearImmediate: safeClearImmediate
};
}
function setSafeTimers() {
const {
setTimeout: safeSetTimeout,
setInterval: safeSetInterval,
clearInterval: safeClearInterval,
clearTimeout: safeClearTimeout,
setImmediate: safeSetImmediate,
clearImmediate: safeClearImmediate
} = globalThis;
const {
nextTick: safeNextTick
} = globalThis.process || { nextTick: (cb) => cb() };
const timers = {
nextTick: safeNextTick,
setTimeout: safeSetTimeout,
setInterval: safeSetInterval,
clearInterval: safeClearInterval,
clearTimeout: safeClearTimeout,
setImmediate: safeSetImmediate,
clearImmediate: safeClearImmediate
};
globalThis[SAFE_TIMERS_SYMBOL] = timers;
}
const RealDate = Date;
function random(seed) {
const x = Math.sin(seed++) * 1e4;
return x - Math.floor(x);
}
function shuffle(array, seed = RealDate.now()) {
let length = array.length;
while (length) {
const index = Math.floor(random(seed) * length--);
const previous = array[length];
array[length] = array[index];
array[index] = previous;
++seed;
}
return array;
}
function createSimpleStackTrace(options) {
const { message = "error", stackTraceLimit = 1 } = options || {};
const limit = Error.stackTraceLimit;
const prepareStackTrace = Error.prepareStackTrace;
Error.stackTraceLimit = stackTraceLimit;
Error.prepareStackTrace = (e) => e.stack;
const err = new Error(message);
const stackTrace = err.stack || "";
Error.prepareStackTrace = prepareStackTrace;
Error.stackTraceLimit = limit;
return stackTrace;
}
const lineSplitRE = /\r?\n/;
function positionToOffset(source, lineNumber, columnNumber) {
const lines = source.split(lineSplitRE);
const nl = /\r\n/.test(source) ? 2 : 1;
let start = 0;
if (lineNumber > lines.length)
return source.length;
for (let i = 0; i < lineNumber - 1; i++)
start += lines[i].length + nl;
return start + columnNumber;
}
function offsetToLineNumber(source, offset) {
if (offset > source.length) {
throw new Error(
`offset is longer than source length! offset ${offset} > length ${source.length}`
);
}
const lines = source.split(lineSplitRE);
const nl = /\r\n/.test(source) ? 2 : 1;
let counted = 0;
let line = 0;
for (; line < lines.length; line++) {
const lineLength = lines[line].length + nl;
if (counted + lineLength >= offset)
break;
counted += lineLength;
}
return line + 1;
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
// Copyright 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Simon Lydell
// License: MIT.
var Identifier, JSXIdentifier, JSXPunctuator, JSXString, JSXText, KeywordsWithExpressionAfter, KeywordsWithNoLineTerminatorAfter, LineTerminatorSequence, MultiLineComment, Newline, NumericLiteral, Punctuator, RegularExpressionLiteral, SingleLineComment, StringLiteral, Template, TokensNotPrecedingObjectLiteral, TokensPrecedingExpression, WhiteSpace;
RegularExpressionLiteral = /\/(?![*\/])(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\\]).|\\.)*(\/[$_\u200C\u200D\p{ID_Continue}]*|\\)?/yu;
Punctuator = /--|\+\+|=>|\.{3}|\??\.(?!\d)|(?:&&|\|\||\?\?|[+\-%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2}|\/(?![\/*]))=?|[?~,:;[\](){}]/y;
Identifier = /(\x23?)(?=[$_\p{ID_Start}\\])(?:[$_\u200C\u200D\p{ID_Continue}]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+/yu;
StringLiteral = /(['"])(?:(?!\1)[^\\\n\r]|\\(?:\r\n|[^]))*(\1)?/y;
NumericLiteral = /(?:0[xX][\da-fA-F](?:_?[\da-fA-F])*|0[oO][0-7](?:_?[0-7])*|0[bB][01](?:_?[01])*)n?|0n|[1-9](?:_?\d)*n|(?:(?:0(?!\d)|0\d*[89]\d*|[1-9](?:_?\d)*)(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:[eE][+-]?\d(?:_?\d)*)?|0[0-7]+/y;
Template = /[`}](?:[^`\\$]|\\[^]|\$(?!\{))*(`|\$\{)?/y;
WhiteSpace = /[\t\v\f\ufeff\p{Zs}]+/yu;
LineTerminatorSequence = /\r?\n|[\r\u2028\u2029]/y;
MultiLineComment = /\/\*(?:[^*]|\*(?!\/))*(\*\/)?/y;
SingleLineComment = /\/\/.*/y;
JSXPunctuator = /[<>.:={}]|\/(?![\/*])/y;
JSXIdentifier = /[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}-]*/yu;
JSXString = /(['"])(?:(?!\1)[^])*(\1)?/y;
JSXText = /[^<>{}]+/y;
TokensPrecedingExpression = /^(?:[\/+-]|\.{3}|\?(?:InterpolationIn(?:JSX|Template)|NoLineTerminatorHere|NonExpressionParenEnd|UnaryIncDec))?$|[{}([,;<>=*%&|^!~?:]$/;
TokensNotPrecedingObjectLiteral = /^(?:=>|[;\]){}]|else|\?(?:NoLineTerminatorHere|NonExpressionParenEnd))?$/;
KeywordsWithExpressionAfter = /^(?:await|case|default|delete|do|else|instanceof|new|return|throw|typeof|void|yield)$/;
KeywordsWithNoLineTerminatorAfter = /^(?:return|throw|yield)$/;
Newline = RegExp(LineTerminatorSequence.source);
var jsTokens_1 = function*(input, {jsx = false} = {}) {
var braces, firstCodePoint, isExpression, lastIndex, lastSignificantToken, length, match, mode, nextLastIndex, nextLastSignificantToken, parenNesting, postfixIncDec, punctuator, stack;
({length} = input);
lastIndex = 0;
lastSignificantToken = "";
stack = [
{tag: "JS"}
];
braces = [];
parenNesting = 0;
postfixIncDec = false;
while (lastIndex < length) {
mode = stack[stack.length - 1];
switch (mode.tag) {
case "JS":
case "JSNonExpressionParen":
case "InterpolationInTemplate":
case "InterpolationInJSX":
if (input[lastIndex] === "/" && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken))) {
RegularExpressionLiteral.lastIndex = lastIndex;
if (match = RegularExpressionLiteral.exec(input)) {
lastIndex = RegularExpressionLiteral.lastIndex;
lastSignificantToken = match[0];
postfixIncDec = true;
yield ({
type: "RegularExpressionLiteral",
value: match[0],
closed: match[1] !== void 0 && match[1] !== "\\"
});
continue;
}
}
Punctuator.lastIndex = lastIndex;
if (match = Punctuator.exec(input)) {
punctuator = match[0];
nextLastIndex = Punctuator.lastIndex;
nextLastSignificantToken = punctuator;
switch (punctuator) {
case "(":
if (lastSignificantToken === "?NonExpressionParenKeyword") {
stack.push({
tag: "JSNonExpressionParen",
nesting: parenNesting
});
}
parenNesting++;
postfixIncDec = false;
break;
case ")":
parenNesting--;
postfixIncDec = true;
if (mode.tag === "JSNonExpressionParen" && parenNesting === mode.nesting) {
stack.pop();
nextLastSignificantToken = "?NonExpressionParenEnd";
postfixIncDec = false;
}
break;
case "{":
Punctuator.lastIndex = 0;
isExpression = !TokensNotPrecedingObjectLiteral.test(lastSignificantToken) && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken));
braces.push(isExpression);
postfixIncDec = false;
break;
case "}":
switch (mode.tag) {
case "InterpolationInTemplate":
if (braces.length === mode.nesting) {
Template.lastIndex = lastIndex;
match = Template.exec(input);
lastIndex = Template.lastIndex;
lastSignificantToken = match[0];
if (match[1] === "${") {
lastSignificantToken = "?InterpolationInTemplate";
postfixIncDec = false;
yield ({
type: "TemplateMiddle",
value: match[0]
});
} else {
stack.pop();
postfixIncDec = true;
yield ({
type: "TemplateTail",
value: match[0],
closed: match[1] === "`"
});
}
continue;
}
break;
case "InterpolationInJSX":
if (braces.length === mode.nesting) {
stack.pop();
lastIndex += 1;
lastSignificantToken = "}";
yield ({
type: "JSXPunctuator",
value: "}"
});
continue;
}
}
postfixIncDec = braces.pop();
nextLastSignificantToken = postfixIncDec ? "?ExpressionBraceEnd" : "}";
break;
case "]":
postfixIncDec = true;
break;
case "++":
case "--":
nextLastSignificantToken = postfixIncDec ? "?PostfixIncDec" : "?UnaryIncDec";
break;
case "<":
if (jsx && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken))) {
stack.push({tag: "JSXTag"});
lastIndex += 1;
lastSignificantToken = "<";
yield ({
type: "JSXPunctuator",
value: punctuator
});
continue;
}
postfixIncDec = false;
break;
default:
postfixIncDec = false;
}
lastIndex = nextLastIndex;
lastSignificantToken = nextLastSignificantToken;
yield ({
type: "Punctuator",
value: punctuator
});
continue;
}
Identifier.lastIndex = lastIndex;
if (match = Identifier.exec(input)) {
lastIndex = Identifier.lastIndex;
nextLastSignificantToken = match[0];
switch (match[0]) {
case "for":
case "if":
case "while":
case "with":
if (lastSignificantToken !== "." && lastSignificantToken !== "?.") {
nextLastSignificantToken = "?NonExpressionParenKeyword";
}
}
lastSignificantToken = nextLastSignificantToken;
postfixIncDec = !KeywordsWithExpressionAfter.test(match[0]);
yield ({
type: match[1] === "#" ? "PrivateIdentifier" : "IdentifierName",
value: match[0]
});
continue;
}
StringLiteral.lastIndex = lastIndex;
if (match = StringLiteral.exec(input)) {
lastIndex = StringLiteral.lastIndex;
lastSignificantToken = match[0];
postfixIncDec = true;
yield ({
type: "StringLiteral",
value: match[0],
closed: match[2] !== void 0
});
continue;
}
NumericLiteral.lastIndex = lastIndex;
if (match = NumericLiteral.exec(input)) {
lastIndex = NumericLiteral.lastIndex;
lastSignificantToken = match[0];
postfixIncDec = true;
yield ({
type: "NumericLiteral",
value: match[0]
});
continue;
}
Template.lastIndex = lastIndex;
if (match = Template.exec(input)) {
lastIndex = Template.lastIndex;
lastSignificantToken = match[0];
if (match[1] === "${") {
lastSignificantToken = "?InterpolationInTemplate";
stack.push({
tag: "InterpolationInTemplate",
nesting: braces.length
});
postfixIncDec = false;
yield ({
type: "TemplateHead",
value: match[0]
});
} else {
postfixIncDec = true;
yield ({
type: "NoSubstitutionTemplate",
value: match[0],
closed: match[1] === "`"
});
}
continue;
}
break;
case "JSXTag":
case "JSXTagEnd":
JSXPunctuator.lastIndex = lastIndex;
if (match = JSXPunctuator.exec(input)) {
lastIndex = JSXPunctuator.lastIndex;
nextLastSignificantToken = match[0];
switch (match[0]) {
case "<":
stack.push({tag: "JSXTag"});
break;
case ">":
stack.pop();
if (lastSignificantToken === "/" || mode.tag === "JSXTagEnd") {
nextLastSignificantToken = "?JSX";
postfixIncDec = true;
} else {
stack.push({tag: "JSXChildren"});
}
break;
case "{":
stack.push({
tag: "InterpolationInJSX",
nesting: braces.length
});
nextLastSignificantToken = "?InterpolationInJSX";
postfixIncDec = false;
break;
case "/":
if (lastSignificantToken === "<") {
stack.pop();
if (stack[stack.length - 1].tag === "JSXChildren") {
stack.pop();
}
stack.push({tag: "JSXTagEnd"});
}
}
lastSignificantToken = nextLastSignificantToken;
yield ({
type: "JSXPunctuator",
value: match[0]
});
continue;
}
JSXIdentifier.lastIndex = lastIndex;
if (match = JSXIdentifier.exec(input)) {
lastIndex = JSXIdentifier.lastIndex;
lastSignificantToken = match[0];
yield ({
type: "JSXIdentifier",
value: match[0]
});
continue;
}
JSXString.lastIndex = lastIndex;
if (match = JSXString.exec(input)) {
lastIndex = JSXString.lastIndex;
lastSignificantToken = match[0];
yield ({
type: "JSXString",
value: match[0],
closed: match[2] !== void 0
});
continue;
}
break;
case "JSXChildren":
JSXText.lastIndex = lastIndex;
if (match = JSXText.exec(input)) {
lastIndex = JSXText.lastIndex;
lastSignificantToken = match[0];
yield ({
type: "JSXText",
value: match[0]
});
continue;
}
switch (input[lastIndex]) {
case "<":
stack.push({tag: "JSXTag"});
lastIndex++;
lastSignificantToken = "<";
yield ({
type: "JSXPunctuator",
value: "<"
});
continue;
case "{":
stack.push({
tag: "InterpolationInJSX",
nesting: braces.length
});
lastIndex++;
lastSignificantToken = "?InterpolationInJSX";
postfixIncDec = false;
yield ({
type: "JSXPunctuator",
value: "{"
});
continue;
}
}
WhiteSpace.lastIndex = lastIndex;
if (match = WhiteSpace.exec(input)) {
lastIndex = WhiteSpace.lastIndex;
yield ({
type: "WhiteSpace",
value: match[0]
});
continue;
}
LineTerminatorSequence.lastIndex = lastIndex;
if (match = LineTerminatorSequence.exec(input)) {
lastIndex = LineTerminatorSequence.lastIndex;
postfixIncDec = false;
if (KeywordsWithNoLineTerminatorAfter.test(lastSignificantToken)) {
lastSignificantToken = "?NoLineTerminatorHere";
}
yield ({
type: "LineTerminatorSequence",
value: match[0]
});
continue;
}
MultiLineComment.lastIndex = lastIndex;
if (match = MultiLineComment.exec(input)) {
lastIndex = MultiLineComment.lastIndex;
if (Newline.test(match[0])) {
postfixIncDec = false;
if (KeywordsWithNoLineTerminatorAfter.test(lastSignificantToken)) {
lastSignificantToken = "?NoLineTerminatorHere";
}
}
yield ({
type: "MultiLineComment",
value: match[0],
closed: match[1] !== void 0
});
continue;
}
SingleLineComment.lastIndex = lastIndex;
if (match = SingleLineComment.exec(input)) {
lastIndex = SingleLineComment.lastIndex;
postfixIncDec = false;
yield ({
type: "SingleLineComment",
value: match[0]
});
continue;
}
firstCodePoint = String.fromCodePoint(input.codePointAt(lastIndex));
lastIndex += firstCodePoint.length;
lastSignificantToken = firstCodePoint;
postfixIncDec = false;
yield ({
type: mode.tag.startsWith("JSX") ? "JSXInvalid" : "Invalid",
value: firstCodePoint
});
}
return void 0;
};
var jsTokens = /*@__PURE__*/getDefaultExportFromCjs(jsTokens_1);
// src/index.ts
var reservedWords = {
keyword: [
"break",
"case",
"catch",
"continue",
"debugger",
"default",
"do",
"else",
"finally",
"for",
"function",
"if",
"return",
"switch",
"throw",
"try",
"var",
"const",
"while",
"with",
"new",
"this",
"super",
"class",
"extends",
"export",
"import",
"null",
"true",
"false",
"in",
"instanceof",
"typeof",
"void",
"delete"
],
strict: [
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield"
]
}, keywords = new Set(reservedWords.keyword), reservedWordsStrictSet = new Set(reservedWords.strict), sometimesKeywords = /* @__PURE__ */ new Set(["as", "async", "from", "get", "of", "set"]);
function isReservedWord(word) {
return word === "await" || word === "enum";
}
function isStrictReservedWord(word) {
return isReservedWord(word) || reservedWordsStrictSet.has(word);
}
function isKeyword(word) {
return keywords.has(word);
}
var BRACKET = /^[()[\]{}]$/, getTokenType = function(token) {
if (token.type === "IdentifierName") {
if (isKeyword(token.value) || isStrictReservedWord(token.value) || sometimesKeywords.has(token.value))
return "Keyword";
if (token.value[0] && token.value[0] !== token.value[0].toLowerCase())
return "IdentifierCapitalized";
}
return token.type === "Punctuator" && BRACKET.test(token.value) ? "Bracket" : token.type === "Invalid" && (token.value === "@" || token.value === "#") ? "Punctuator" : token.type;
};
function getCallableType(token) {
if (token.type === "IdentifierName")
return "IdentifierCallable";
if (token.type === "PrivateIdentifier")
return "PrivateIdentifierCallable";
throw new Error("Not a callable token");
}
var colorize = (defs, type, value) => {
let colorize2 = defs[type];
return colorize2 ? colorize2(value) : value;
}, highlightTokens = (defs, text, jsx) => {
let highlighted = "", lastPotentialCallable = null, stackedHighlight = "";
for (let token of jsTokens(text, { jsx })) {
let type = getTokenType(token);
if (type === "IdentifierName" || type === "PrivateIdentifier") {
lastPotentialCallable && (highlighted += colorize(defs, getTokenType(lastPotentialCallable), lastPotentialCallable.value) + stackedHighlight, stackedHighlight = ""), lastPotentialCallable = token;
continue;
}
if (lastPotentialCallable && (token.type === "WhiteSpace" || token.type === "LineTerminatorSequence" || token.type === "Punctuator" && (token.value === "?." || token.value === "!"))) {
stackedHighlight += colorize(defs, type, token.value);
continue;
}
if (stackedHighlight && !lastPotentialCallable && (highlighted += stackedHighlight, stackedHighlight = ""), lastPotentialCallable) {
let type2 = token.type === "Punctuator" && token.value === "(" ? getCallableType(lastPotentialCallable) : getTokenType(lastPotentialCallable);
highlighted += colorize(defs, type2, lastPotentialCallable.value) + stackedHighlight, stackedHighlight = "", lastPotentialCallable = null;
}
highlighted += colorize(defs, type, token.value);
}
return highlighted;
};
function highlight$1(code, options = { jsx: !1, colors: {} }) {
return code && highlightTokens(options.colors || {}, code, options.jsx);
}
function getDefs(c) {
const Invalid = (text) => c.white(c.bgRed(c.bold(text)));
return {
Keyword: c.magenta,
IdentifierCapitalized: c.yellow,
Punctuator: c.yellow,
StringLiteral: c.green,
NoSubstitutionTemplate: c.green,
MultiLineComment: c.gray,
SingleLineComment: c.gray,
RegularExpressionLiteral: c.cyan,
NumericLiteral: c.blue,
TemplateHead: (text) => c.green(text.slice(0, text.length - 2)) + c.cyan(text.slice(-2)),
TemplateTail: (text) => c.cyan(text.slice(0, 1)) + c.green(text.slice(1)),
TemplateMiddle: (text) => c.cyan(text.slice(0, 1)) + c.green(text.slice(1, text.length - 2)) + c.cyan(text.slice(-2)),
IdentifierCallable: c.blue,
PrivateIdentifierCallable: (text) => `#${c.blue(text.slice(1))}`,
Invalid,
JSXString: c.green,
JSXIdentifier: c.yellow,
JSXInvalid: Invalid,
JSXPunctuator: c.yellow
};
}
function highlight(code, options = { jsx: false }) {
return highlight$1(code, {
jsx: options.jsx,
colors: getDefs(options.colors || getColors())
});
}
export { SAFE_TIMERS_SYMBOL, createSimpleStackTrace, getColors, getSafeTimers, highlight, lineSplitRE, offsetToLineNumber, positionToOffset, setSafeTimers, shuffle };
+111
View File
@@ -0,0 +1,111 @@
import { ParsedStack, ErrorWithDiff } from './types.js';
type GeneratedColumn = number;
type SourcesIndex = number;
type SourceLine = number;
type SourceColumn = number;
type NamesIndex = number;
type SourceMapSegment = [GeneratedColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
interface SourceMapV3 {
file?: string | null;
names: string[];
sourceRoot?: string;
sources: (string | null)[];
sourcesContent?: (string | null)[];
version: 3;
}
interface EncodedSourceMap extends SourceMapV3 {
mappings: string;
}
interface DecodedSourceMap extends SourceMapV3 {
mappings: SourceMapSegment[][];
}
type OriginalMapping = {
source: string | null;
line: number;
column: number;
name: string | null;
};
type InvalidOriginalMapping = {
source: null;
line: null;
column: null;
name: null;
};
type GeneratedMapping = {
line: number;
column: number;
};
type InvalidGeneratedMapping = {
line: null;
column: null;
};
type Bias = typeof GREATEST_LOWER_BOUND | typeof LEAST_UPPER_BOUND;
type SourceMapInput = string | Ro<EncodedSourceMap> | Ro<DecodedSourceMap> | TraceMap;
type Needle = {
line: number;
column: number;
bias?: Bias;
};
type SourceNeedle = {
source: string;
line: number;
column: number;
bias?: Bias;
};
declare abstract class SourceMap {
version: SourceMapV3['version'];
file: SourceMapV3['file'];
names: SourceMapV3['names'];
sourceRoot: SourceMapV3['sourceRoot'];
sources: SourceMapV3['sources'];
sourcesContent: SourceMapV3['sourcesContent'];
resolvedSources: SourceMapV3['sources'];
}
type Ro<T> = T extends Array<infer V> ? V[] | Readonly<V[]> | RoArray<V> | Readonly<RoArray<V>> : T extends object ? T | Readonly<T> | RoObject<T> | Readonly<RoObject<T>> : T;
type RoArray<T> = Ro<T>[];
type RoObject<T> = {
[K in keyof T]: T[K] | Ro<T[K]>;
};
declare const LEAST_UPPER_BOUND = -1;
declare const GREATEST_LOWER_BOUND = 1;
/**
* A higher-level API to find the source/line/column associated with a generated line/column
* (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
* `source-map` library.
*/
declare let originalPositionFor: (map: TraceMap, needle: Needle) => OriginalMapping | InvalidOriginalMapping;
/**
* Finds the generated line/column position of the provided source/line/column source position.
*/
declare let generatedPositionFor: (map: TraceMap, needle: SourceNeedle) => GeneratedMapping | InvalidGeneratedMapping;
declare class TraceMap implements SourceMap {
version: SourceMapV3['version'];
file: SourceMapV3['file'];
names: SourceMapV3['names'];
sourceRoot: SourceMapV3['sourceRoot'];
sources: SourceMapV3['sources'];
sourcesContent: SourceMapV3['sourcesContent'];
resolvedSources: string[];
private _encoded;
private _decoded;
private _decodedMemo;
private _bySources;
private _bySourceMemos;
constructor(map: SourceMapInput, mapUrl?: string | null);
}
interface StackTraceParserOptions {
ignoreStackEntries?: (RegExp | string)[];
getSourceMap?: (file: string) => unknown;
frameFilter?: (error: Error, frame: ParsedStack) => boolean | void;
}
declare function parseSingleFFOrSafariStack(raw: string): ParsedStack | null;
declare function parseSingleStack(raw: string): ParsedStack | null;
declare function parseSingleV8Stack(raw: string): ParsedStack | null;
declare function parseStacktrace(stack: string, options?: StackTraceParserOptions): ParsedStack[];
declare function parseErrorStacktrace(e: ErrorWithDiff, options?: StackTraceParserOptions): ParsedStack[];
export { type SourceMapInput, type StackTraceParserOptions, TraceMap, generatedPositionFor, originalPositionFor, parseErrorStacktrace, parseSingleFFOrSafariStack, parseSingleStack, parseSingleV8Stack, parseStacktrace };
+878
View File
@@ -0,0 +1,878 @@
import { notNullish, isPrimitive } from './helpers.js';
function normalizeWindowsPath(input = "") {
if (!input || !input.includes("\\")) {
return input;
}
return input.replace(/\\/g, "/");
}
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
function cwd() {
if (typeof process !== "undefined") {
return process.cwd().replace(/\\/g, "/");
}
return "/";
}
const resolve$2 = function(...arguments_) {
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
let resolvedPath = "";
let resolvedAbsolute = false;
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
const path = index >= 0 ? arguments_[index] : cwd();
if (!path || path.length === 0) {
continue;
}
resolvedPath = `${path}/${resolvedPath}`;
resolvedAbsolute = isAbsolute(path);
}
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
return `/${resolvedPath}`;
}
return resolvedPath.length > 0 ? resolvedPath : ".";
};
function normalizeString(path, allowAboveRoot) {
let res = "";
let lastSegmentLength = 0;
let lastSlash = -1;
let dots = 0;
let char = null;
for (let index = 0; index <= path.length; ++index) {
if (index < path.length) {
char = path[index];
} else if (char === "/") {
break;
} else {
char = "/";
}
if (char === "/") {
if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
if (res.length > 2) {
const lastSlashIndex = res.lastIndexOf("/");
if (lastSlashIndex === -1) {
res = "";
lastSegmentLength = 0;
} else {
res = res.slice(0, lastSlashIndex);
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
}
lastSlash = index;
dots = 0;
continue;
} else if (res.length > 0) {
res = "";
lastSegmentLength = 0;
lastSlash = index;
dots = 0;
continue;
}
}
if (allowAboveRoot) {
res += res.length > 0 ? "/.." : "..";
lastSegmentLength = 2;
}
} else {
if (res.length > 0) {
res += `/${path.slice(lastSlash + 1, index)}`;
} else {
res = path.slice(lastSlash + 1, index);
}
lastSegmentLength = index - lastSlash - 1;
}
lastSlash = index;
dots = 0;
} else if (char === "." && dots !== -1) {
++dots;
} else {
dots = -1;
}
}
return res;
}
const isAbsolute = function(p) {
return _IS_ABSOLUTE_RE.test(p);
};
const comma = ','.charCodeAt(0);
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const intToChar = new Uint8Array(64); // 64 possible chars.
const charToInt = new Uint8Array(128); // z is 122 in ASCII
for (let i = 0; i < chars.length; i++) {
const c = chars.charCodeAt(i);
intToChar[i] = c;
charToInt[c] = i;
}
function decode(mappings) {
const state = new Int32Array(5);
const decoded = [];
let index = 0;
do {
const semi = indexOf(mappings, index);
const line = [];
let sorted = true;
let lastCol = 0;
state[0] = 0;
for (let i = index; i < semi; i++) {
let seg;
i = decodeInteger(mappings, i, state, 0); // genColumn
const col = state[0];
if (col < lastCol)
sorted = false;
lastCol = col;
if (hasMoreVlq(mappings, i, semi)) {
i = decodeInteger(mappings, i, state, 1); // sourcesIndex
i = decodeInteger(mappings, i, state, 2); // sourceLine
i = decodeInteger(mappings, i, state, 3); // sourceColumn
if (hasMoreVlq(mappings, i, semi)) {
i = decodeInteger(mappings, i, state, 4); // namesIndex
seg = [col, state[1], state[2], state[3], state[4]];
}
else {
seg = [col, state[1], state[2], state[3]];
}
}
else {
seg = [col];
}
line.push(seg);
}
if (!sorted)
sort(line);
decoded.push(line);
index = semi + 1;
} while (index <= mappings.length);
return decoded;
}
function indexOf(mappings, index) {
const idx = mappings.indexOf(';', index);
return idx === -1 ? mappings.length : idx;
}
function decodeInteger(mappings, pos, state, j) {
let value = 0;
let shift = 0;
let integer = 0;
do {
const c = mappings.charCodeAt(pos++);
integer = charToInt[c];
value |= (integer & 31) << shift;
shift += 5;
} while (integer & 32);
const shouldNegate = value & 1;
value >>>= 1;
if (shouldNegate) {
value = -0x80000000 | -value;
}
state[j] += value;
return pos;
}
function hasMoreVlq(mappings, i, length) {
if (i >= length)
return false;
return mappings.charCodeAt(i) !== comma;
}
function sort(line) {
line.sort(sortComparator$1);
}
function sortComparator$1(a, b) {
return a[0] - b[0];
}
// Matches the scheme of a URL, eg "http://"
const schemeRegex = /^[\w+.-]+:\/\//;
/**
* Matches the parts of a URL:
* 1. Scheme, including ":", guaranteed.
* 2. User/password, including "@", optional.
* 3. Host, guaranteed.
* 4. Port, including ":", optional.
* 5. Path, including "/", optional.
* 6. Query, including "?", optional.
* 7. Hash, including "#", optional.
*/
const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
/**
* File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
* with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
*
* 1. Host, optional.
* 2. Path, which may include "/", guaranteed.
* 3. Query, including "?", optional.
* 4. Hash, including "#", optional.
*/
const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
var UrlType;
(function (UrlType) {
UrlType[UrlType["Empty"] = 1] = "Empty";
UrlType[UrlType["Hash"] = 2] = "Hash";
UrlType[UrlType["Query"] = 3] = "Query";
UrlType[UrlType["RelativePath"] = 4] = "RelativePath";
UrlType[UrlType["AbsolutePath"] = 5] = "AbsolutePath";
UrlType[UrlType["SchemeRelative"] = 6] = "SchemeRelative";
UrlType[UrlType["Absolute"] = 7] = "Absolute";
})(UrlType || (UrlType = {}));
function isAbsoluteUrl(input) {
return schemeRegex.test(input);
}
function isSchemeRelativeUrl(input) {
return input.startsWith('//');
}
function isAbsolutePath(input) {
return input.startsWith('/');
}
function isFileUrl(input) {
return input.startsWith('file:');
}
function isRelative(input) {
return /^[.?#]/.test(input);
}
function parseAbsoluteUrl(input) {
const match = urlRegex.exec(input);
return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
}
function parseFileUrl(input) {
const match = fileRegex.exec(input);
const path = match[2];
return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
}
function makeUrl(scheme, user, host, port, path, query, hash) {
return {
scheme,
user,
host,
port,
path,
query,
hash,
type: UrlType.Absolute,
};
}
function parseUrl(input) {
if (isSchemeRelativeUrl(input)) {
const url = parseAbsoluteUrl('http:' + input);
url.scheme = '';
url.type = UrlType.SchemeRelative;
return url;
}
if (isAbsolutePath(input)) {
const url = parseAbsoluteUrl('http://foo.com' + input);
url.scheme = '';
url.host = '';
url.type = UrlType.AbsolutePath;
return url;
}
if (isFileUrl(input))
return parseFileUrl(input);
if (isAbsoluteUrl(input))
return parseAbsoluteUrl(input);
const url = parseAbsoluteUrl('http://foo.com/' + input);
url.scheme = '';
url.host = '';
url.type = input
? input.startsWith('?')
? UrlType.Query
: input.startsWith('#')
? UrlType.Hash
: UrlType.RelativePath
: UrlType.Empty;
return url;
}
function stripPathFilename(path) {
// If a path ends with a parent directory "..", then it's a relative path with excess parent
// paths. It's not a file, so we can't strip it.
if (path.endsWith('/..'))
return path;
const index = path.lastIndexOf('/');
return path.slice(0, index + 1);
}
function mergePaths(url, base) {
normalizePath(base, base.type);
// If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
// path).
if (url.path === '/') {
url.path = base.path;
}
else {
// Resolution happens relative to the base path's directory, not the file.
url.path = stripPathFilename(base.path) + url.path;
}
}
/**
* The path can have empty directories "//", unneeded parents "foo/..", or current directory
* "foo/.". We need to normalize to a standard representation.
*/
function normalizePath(url, type) {
const rel = type <= UrlType.RelativePath;
const pieces = url.path.split('/');
// We need to preserve the first piece always, so that we output a leading slash. The item at
// pieces[0] is an empty string.
let pointer = 1;
// Positive is the number of real directories we've output, used for popping a parent directory.
// Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
let positive = 0;
// We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
// generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
// real directory, we won't need to append, unless the other conditions happen again.
let addTrailingSlash = false;
for (let i = 1; i < pieces.length; i++) {
const piece = pieces[i];
// An empty directory, could be a trailing slash, or just a double "//" in the path.
if (!piece) {
addTrailingSlash = true;
continue;
}
// If we encounter a real directory, then we don't need to append anymore.
addTrailingSlash = false;
// A current directory, which we can always drop.
if (piece === '.')
continue;
// A parent directory, we need to see if there are any real directories we can pop. Else, we
// have an excess of parents, and we'll need to keep the "..".
if (piece === '..') {
if (positive) {
addTrailingSlash = true;
positive--;
pointer--;
}
else if (rel) {
// If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
// URL, protocol relative URL, or an absolute path, we don't need to keep excess.
pieces[pointer++] = piece;
}
continue;
}
// We've encountered a real directory. Move it to the next insertion pointer, which accounts for
// any popped or dropped directories.
pieces[pointer++] = piece;
positive++;
}
let path = '';
for (let i = 1; i < pointer; i++) {
path += '/' + pieces[i];
}
if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
path += '/';
}
url.path = path;
}
/**
* Attempts to resolve `input` URL/path relative to `base`.
*/
function resolve$1(input, base) {
if (!input && !base)
return '';
const url = parseUrl(input);
let inputType = url.type;
if (base && inputType !== UrlType.Absolute) {
const baseUrl = parseUrl(base);
const baseType = baseUrl.type;
switch (inputType) {
case UrlType.Empty:
url.hash = baseUrl.hash;
// fall through
case UrlType.Hash:
url.query = baseUrl.query;
// fall through
case UrlType.Query:
case UrlType.RelativePath:
mergePaths(url, baseUrl);
// fall through
case UrlType.AbsolutePath:
// The host, user, and port are joined, you can't copy one without the others.
url.user = baseUrl.user;
url.host = baseUrl.host;
url.port = baseUrl.port;
// fall through
case UrlType.SchemeRelative:
// The input doesn't have a schema at least, so we need to copy at least that over.
url.scheme = baseUrl.scheme;
}
if (baseType > inputType)
inputType = baseType;
}
normalizePath(url, inputType);
const queryHash = url.query + url.hash;
switch (inputType) {
// This is impossible, because of the empty checks at the start of the function.
// case UrlType.Empty:
case UrlType.Hash:
case UrlType.Query:
return queryHash;
case UrlType.RelativePath: {
// The first char is always a "/", and we need it to be relative.
const path = url.path.slice(1);
if (!path)
return queryHash || '.';
if (isRelative(base || input) && !isRelative(path)) {
// If base started with a leading ".", or there is no base and input started with a ".",
// then we need to ensure that the relative path starts with a ".". We don't know if
// relative starts with a "..", though, so check before prepending.
return './' + path + queryHash;
}
return path + queryHash;
}
case UrlType.AbsolutePath:
return url.path + queryHash;
default:
return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
}
}
function resolve(input, base) {
// The base is always treated as a directory, if it's not empty.
// https://github.com/mozilla/source-map/blob/8cb3ee57/lib/util.js#L327
// https://github.com/chromium/chromium/blob/da4adbb3/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js#L400-L401
if (base && !base.endsWith('/'))
base += '/';
return resolve$1(input, base);
}
/**
* Removes everything after the last "/", but leaves the slash.
*/
function stripFilename(path) {
if (!path)
return '';
const index = path.lastIndexOf('/');
return path.slice(0, index + 1);
}
const COLUMN = 0;
const SOURCES_INDEX = 1;
const SOURCE_LINE = 2;
const SOURCE_COLUMN = 3;
const NAMES_INDEX = 4;
const REV_GENERATED_LINE = 1;
const REV_GENERATED_COLUMN = 2;
function maybeSort(mappings, owned) {
const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
if (unsortedIndex === mappings.length)
return mappings;
// If we own the array (meaning we parsed it from JSON), then we're free to directly mutate it. If
// not, we do not want to modify the consumer's input array.
if (!owned)
mappings = mappings.slice();
for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
mappings[i] = sortSegments(mappings[i], owned);
}
return mappings;
}
function nextUnsortedSegmentLine(mappings, start) {
for (let i = start; i < mappings.length; i++) {
if (!isSorted(mappings[i]))
return i;
}
return mappings.length;
}
function isSorted(line) {
for (let j = 1; j < line.length; j++) {
if (line[j][COLUMN] < line[j - 1][COLUMN]) {
return false;
}
}
return true;
}
function sortSegments(line, owned) {
if (!owned)
line = line.slice();
return line.sort(sortComparator);
}
function sortComparator(a, b) {
return a[COLUMN] - b[COLUMN];
}
let found = false;
/**
* A binary search implementation that returns the index if a match is found.
* If no match is found, then the left-index (the index associated with the item that comes just
* before the desired index) is returned. To maintain proper sort order, a splice would happen at
* the next index:
*
* ```js
* const array = [1, 3];
* const needle = 2;
* const index = binarySearch(array, needle, (item, needle) => item - needle);
*
* assert.equal(index, 0);
* array.splice(index + 1, 0, needle);
* assert.deepEqual(array, [1, 2, 3]);
* ```
*/
function binarySearch(haystack, needle, low, high) {
while (low <= high) {
const mid = low + ((high - low) >> 1);
const cmp = haystack[mid][COLUMN] - needle;
if (cmp === 0) {
found = true;
return mid;
}
if (cmp < 0) {
low = mid + 1;
}
else {
high = mid - 1;
}
}
found = false;
return low - 1;
}
function upperBound(haystack, needle, index) {
for (let i = index + 1; i < haystack.length; index = i++) {
if (haystack[i][COLUMN] !== needle)
break;
}
return index;
}
function lowerBound(haystack, needle, index) {
for (let i = index - 1; i >= 0; index = i--) {
if (haystack[i][COLUMN] !== needle)
break;
}
return index;
}
function memoizedState() {
return {
lastKey: -1,
lastNeedle: -1,
lastIndex: -1,
};
}
/**
* This overly complicated beast is just to record the last tested line/column and the resulting
* index, allowing us to skip a few tests if mappings are monotonically increasing.
*/
function memoizedBinarySearch(haystack, needle, state, key) {
const { lastKey, lastNeedle, lastIndex } = state;
let low = 0;
let high = haystack.length - 1;
if (key === lastKey) {
if (needle === lastNeedle) {
found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
return lastIndex;
}
if (needle >= lastNeedle) {
// lastIndex may be -1 if the previous needle was not found.
low = lastIndex === -1 ? 0 : lastIndex;
}
else {
high = lastIndex;
}
}
state.lastKey = key;
state.lastNeedle = needle;
return (state.lastIndex = binarySearch(haystack, needle, low, high));
}
// Rebuilds the original source files, with mappings that are ordered by source line/column instead
// of generated line/column.
function buildBySources(decoded, memos) {
const sources = memos.map(buildNullArray);
for (let i = 0; i < decoded.length; i++) {
const line = decoded[i];
for (let j = 0; j < line.length; j++) {
const seg = line[j];
if (seg.length === 1)
continue;
const sourceIndex = seg[SOURCES_INDEX];
const sourceLine = seg[SOURCE_LINE];
const sourceColumn = seg[SOURCE_COLUMN];
const originalSource = sources[sourceIndex];
const originalLine = (originalSource[sourceLine] || (originalSource[sourceLine] = []));
const memo = memos[sourceIndex];
// The binary search either found a match, or it found the left-index just before where the
// segment should go. Either way, we want to insert after that. And there may be multiple
// generated segments associated with an original location, so there may need to move several
// indexes before we find where we need to insert.
const index = upperBound(originalLine, sourceColumn, memoizedBinarySearch(originalLine, sourceColumn, memo, sourceLine));
insert(originalLine, (memo.lastIndex = index + 1), [sourceColumn, i, seg[COLUMN]]);
}
}
return sources;
}
function insert(array, index, value) {
for (let i = array.length; i > index; i--) {
array[i] = array[i - 1];
}
array[index] = value;
}
// Null arrays allow us to use ordered index keys without actually allocating contiguous memory like
// a real array. We use a null-prototype object to avoid prototype pollution and deoptimizations.
// Numeric properties on objects are magically sorted in ascending order by the engine regardless of
// the insertion order. So, by setting any numeric keys, even out of order, we'll get ascending
// order when iterating with for-in.
function buildNullArray() {
return { __proto__: null };
}
const LINE_GTR_ZERO = '`line` must be greater than 0 (lines start at line 1)';
const COL_GTR_EQ_ZERO = '`column` must be greater than or equal to 0 (columns start at column 0)';
const LEAST_UPPER_BOUND = -1;
const GREATEST_LOWER_BOUND = 1;
/**
* Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
*/
let decodedMappings;
/**
* A higher-level API to find the source/line/column associated with a generated line/column
* (think, from a stack trace). Line is 1-based, but column is 0-based, due to legacy behavior in
* `source-map` library.
*/
let originalPositionFor;
/**
* Finds the generated line/column position of the provided source/line/column source position.
*/
let generatedPositionFor;
class TraceMap {
constructor(map, mapUrl) {
const isString = typeof map === 'string';
if (!isString && map._decodedMemo)
return map;
const parsed = (isString ? JSON.parse(map) : map);
const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
this.version = version;
this.file = file;
this.names = names || [];
this.sourceRoot = sourceRoot;
this.sources = sources;
this.sourcesContent = sourcesContent;
const from = resolve(sourceRoot || '', stripFilename(mapUrl));
this.resolvedSources = sources.map((s) => resolve(s || '', from));
const { mappings } = parsed;
if (typeof mappings === 'string') {
this._encoded = mappings;
this._decoded = undefined;
}
else {
this._encoded = undefined;
this._decoded = maybeSort(mappings, isString);
}
this._decodedMemo = memoizedState();
this._bySources = undefined;
this._bySourceMemos = undefined;
}
}
(() => {
decodedMappings = (map) => {
return (map._decoded || (map._decoded = decode(map._encoded)));
};
originalPositionFor = (map, { line, column, bias }) => {
line--;
if (line < 0)
throw new Error(LINE_GTR_ZERO);
if (column < 0)
throw new Error(COL_GTR_EQ_ZERO);
const decoded = decodedMappings(map);
// It's common for parent source maps to have pointers to lines that have no
// mapping (like a "//# sourceMappingURL=") at the end of the child file.
if (line >= decoded.length)
return OMapping(null, null, null, null);
const segments = decoded[line];
const index = traceSegmentInternal(segments, map._decodedMemo, line, column, bias || GREATEST_LOWER_BOUND);
if (index === -1)
return OMapping(null, null, null, null);
const segment = segments[index];
if (segment.length === 1)
return OMapping(null, null, null, null);
const { names, resolvedSources } = map;
return OMapping(resolvedSources[segment[SOURCES_INDEX]], segment[SOURCE_LINE] + 1, segment[SOURCE_COLUMN], segment.length === 5 ? names[segment[NAMES_INDEX]] : null);
};
generatedPositionFor = (map, { source, line, column, bias }) => {
return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
};
function generatedPosition(map, source, line, column, bias, all) {
line--;
if (line < 0)
throw new Error(LINE_GTR_ZERO);
if (column < 0)
throw new Error(COL_GTR_EQ_ZERO);
const { sources, resolvedSources } = map;
let sourceIndex = sources.indexOf(source);
if (sourceIndex === -1)
sourceIndex = resolvedSources.indexOf(source);
if (sourceIndex === -1)
return all ? [] : GMapping(null, null);
const generated = (map._bySources || (map._bySources = buildBySources(decodedMappings(map), (map._bySourceMemos = sources.map(memoizedState)))));
const segments = generated[sourceIndex][line];
if (segments == null)
return all ? [] : GMapping(null, null);
const memo = map._bySourceMemos[sourceIndex];
if (all)
return sliceGeneratedPositions(segments, memo, line, column, bias);
const index = traceSegmentInternal(segments, memo, line, column, bias);
if (index === -1)
return GMapping(null, null);
const segment = segments[index];
return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
}
})();
function OMapping(source, line, column, name) {
return { source, line, column, name };
}
function GMapping(line, column) {
return { line, column };
}
function traceSegmentInternal(segments, memo, line, column, bias) {
let index = memoizedBinarySearch(segments, column, memo, line);
if (found) {
index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
}
else if (bias === LEAST_UPPER_BOUND)
index++;
if (index === -1 || index === segments.length)
return -1;
return index;
}
function sliceGeneratedPositions(segments, memo, line, column, bias) {
let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
// We ignored the bias when tracing the segment so that we're guarnateed to find the first (in
// insertion order) segment that matched. Even if we did respect the bias when tracing, we would
// still need to call `lowerBound()` to find the first segment, which is slower than just looking
// for the GREATEST_LOWER_BOUND to begin with. The only difference that matters for us is when the
// binary search didn't match, in which case GREATEST_LOWER_BOUND just needs to increment to
// match LEAST_UPPER_BOUND.
if (!found && bias === LEAST_UPPER_BOUND)
min++;
if (min === -1 || min === segments.length)
return [];
// We may have found the segment that started at an earlier column. If this is the case, then we
// need to slice all generated segments that match _that_ column, because all such segments span
// to our desired column.
const matchedColumn = found ? column : segments[min][COLUMN];
// The binary search is not guaranteed to find the lower bound when a match wasn't found.
if (!found)
min = lowerBound(segments, matchedColumn, min);
const max = upperBound(segments, matchedColumn, min);
const result = [];
for (; min <= max; min++) {
const segment = segments[min];
result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]));
}
return result;
}
const CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
const SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
const stackIgnorePatterns = [
"node:internal",
/\/packages\/\w+\/dist\//,
/\/@vitest\/\w+\/dist\//,
"/vitest/dist/",
"/vitest/src/",
"/vite-node/dist/",
"/vite-node/src/",
"/node_modules/chai/",
"/node_modules/tinypool/",
"/node_modules/tinyspy/",
"/deps/chai.js",
/__vitest_browser__/
];
function extractLocation(urlLike) {
if (!urlLike.includes(":"))
return [urlLike];
const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, ""));
if (!parts)
return [urlLike];
let url = parts[1];
if (url.startsWith("http:") || url.startsWith("https:")) {
const urlObj = new URL(url);
url = urlObj.pathname;
}
if (url.startsWith("/@fs/")) {
url = url.slice(typeof process !== "undefined" && process.platform === "win32" ? 5 : 4);
}
return [url, parts[2] || void 0, parts[3] || void 0];
}
function parseSingleFFOrSafariStack(raw) {
let line = raw.trim();
if (SAFARI_NATIVE_CODE_REGEXP.test(line))
return null;
if (line.includes(" > eval"))
line = line.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ":$1");
if (!line.includes("@") && !line.includes(":"))
return null;
const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(?:@)/;
const matches = line.match(functionNameRegex);
const functionName = matches && matches[1] ? matches[1] : void 0;
const [url, lineNumber, columnNumber] = extractLocation(line.replace(functionNameRegex, ""));
if (!url || !lineNumber || !columnNumber)
return null;
return {
file: url,
method: functionName || "",
line: Number.parseInt(lineNumber),
column: Number.parseInt(columnNumber)
};
}
function parseSingleStack(raw) {
const line = raw.trim();
if (!CHROME_IE_STACK_REGEXP.test(line))
return parseSingleFFOrSafariStack(line);
return parseSingleV8Stack(line);
}
function parseSingleV8Stack(raw) {
let line = raw.trim();
if (!CHROME_IE_STACK_REGEXP.test(line))
return null;
if (line.includes("(eval "))
line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
const location = sanitizedLine.match(/ (\(.+\)$)/);
sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine);
let method = location && sanitizedLine || "";
let file = url && ["eval", "<anonymous>"].includes(url) ? void 0 : url;
if (!file || !lineNumber || !columnNumber)
return null;
if (method.startsWith("async "))
method = method.slice(6);
if (file.startsWith("file://"))
file = file.slice(7);
file = resolve$2(file);
if (method)
method = method.replace(/__vite_ssr_import_\d+__\./g, "");
return {
method,
file,
line: Number.parseInt(lineNumber),
column: Number.parseInt(columnNumber)
};
}
function parseStacktrace(stack, options = {}) {
const { ignoreStackEntries = stackIgnorePatterns } = options;
let stacks = !CHROME_IE_STACK_REGEXP.test(stack) ? parseFFOrSafariStackTrace(stack) : parseV8Stacktrace(stack);
if (ignoreStackEntries.length)
stacks = stacks.filter((stack2) => !ignoreStackEntries.some((p) => stack2.file.match(p)));
return stacks.map((stack2) => {
var _a;
const map = (_a = options.getSourceMap) == null ? void 0 : _a.call(options, stack2.file);
if (!map || typeof map !== "object" || !map.version)
return stack2;
const traceMap = new TraceMap(map);
const { line, column } = originalPositionFor(traceMap, stack2);
if (line != null && column != null)
return { ...stack2, line, column };
return stack2;
});
}
function parseFFOrSafariStackTrace(stack) {
return stack.split("\n").map((line) => parseSingleFFOrSafariStack(line)).filter(notNullish);
}
function parseV8Stacktrace(stack) {
return stack.split("\n").map((line) => parseSingleV8Stack(line)).filter(notNullish);
}
function parseErrorStacktrace(e, options = {}) {
if (!e || isPrimitive(e))
return [];
if (e.stacks)
return e.stacks;
const stackStr = e.stack || e.stackStr || "";
let stackFrames = parseStacktrace(stackStr, options);
if (options.frameFilter)
stackFrames = stackFrames.filter((f) => options.frameFilter(e, f) !== false);
e.stacks = stackFrames;
return stackFrames;
}
export { TraceMap, generatedPositionFor, originalPositionFor, parseErrorStacktrace, parseSingleFFOrSafariStack, parseSingleStack, parseSingleV8Stack, parseStacktrace };
+35
View File
@@ -0,0 +1,35 @@
import { CompareKeys } from 'pretty-format';
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
type DiffOptionsColor = (arg: string) => string;
interface DiffOptions {
aAnnotation?: string;
aColor?: DiffOptionsColor;
aIndicator?: string;
bAnnotation?: string;
bColor?: DiffOptionsColor;
bIndicator?: string;
changeColor?: DiffOptionsColor;
changeLineTrailingSpaceColor?: DiffOptionsColor;
commonColor?: DiffOptionsColor;
commonIndicator?: string;
commonLineTrailingSpaceColor?: DiffOptionsColor;
contextLines?: number;
emptyFirstOrLastLinePlaceholder?: string;
expand?: boolean;
includeChangeCounts?: boolean;
omitAnnotationLines?: boolean;
patchColor?: DiffOptionsColor;
compareKeys?: CompareKeys;
truncateThreshold?: number;
truncateAnnotation?: string;
truncateAnnotationColor?: DiffOptionsColor;
}
export type { DiffOptions as D, DiffOptionsColor as a };
+39
View File
@@ -0,0 +1,39 @@
type Awaitable<T> = T | PromiseLike<T>;
type Nullable<T> = T | null | undefined;
type Arrayable<T> = T | Array<T>;
type ArgumentsType<T> = T extends (...args: infer U) => any ? U : never;
type MergeInsertions<T> = T extends object ? {
[K in keyof T]: MergeInsertions<T[K]>;
} : T;
type DeepMerge<F, S> = MergeInsertions<{
[K in keyof F | keyof S]: K extends keyof S & keyof F ? DeepMerge<F[K], S[K]> : K extends keyof S ? S[K] : K extends keyof F ? F[K] : never;
}>;
type MutableArray<T extends readonly any[]> = {
-readonly [k in keyof T]: T[k];
};
interface Constructable {
new (...args: any[]): any;
}
interface ParsedStack {
method: string;
file: string;
line: number;
column: number;
}
interface ErrorWithDiff extends Error {
name: string;
nameStr?: string;
stack?: string;
stackStr?: string;
stacks?: ParsedStack[];
showDiff?: boolean;
actual?: any;
expected?: any;
operator?: string;
type?: string;
frame?: string;
diff?: string;
codeFrame?: string;
}
export type { ArgumentsType, Arrayable, Awaitable, Constructable, DeepMerge, ErrorWithDiff, MergeInsertions, MutableArray, Nullable, ParsedStack };
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
export * from './dist/error.js'
+1
View File
@@ -0,0 +1 @@
export * from './dist/helpers.js'
+167
View File
@@ -0,0 +1,167 @@
declare namespace ansiStyles {
interface CSPair {
/**
The ANSI terminal control sequence for starting this style.
*/
readonly open: string;
/**
The ANSI terminal control sequence for ending this style.
*/
readonly close: string;
}
interface ColorBase {
/**
The ANSI terminal control sequence for ending this color.
*/
readonly close: string;
ansi256(code: number): string;
ansi16m(red: number, green: number, blue: number): string;
}
interface Modifier {
/**
Resets the current color chain.
*/
readonly reset: CSPair;
/**
Make text bold.
*/
readonly bold: CSPair;
/**
Emitting only a small amount of light.
*/
readonly dim: CSPair;
/**
Make text italic. (Not widely supported)
*/
readonly italic: CSPair;
/**
Make text underline. (Not widely supported)
*/
readonly underline: CSPair;
/**
Make text overline.
Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.
*/
readonly overline: CSPair;
/**
Inverse background and foreground colors.
*/
readonly inverse: CSPair;
/**
Prints the text, but makes it invisible.
*/
readonly hidden: CSPair;
/**
Puts a horizontal line through the center of the text. (Not widely supported)
*/
readonly strikethrough: CSPair;
}
interface ForegroundColor {
readonly black: CSPair;
readonly red: CSPair;
readonly green: CSPair;
readonly yellow: CSPair;
readonly blue: CSPair;
readonly cyan: CSPair;
readonly magenta: CSPair;
readonly white: CSPair;
/**
Alias for `blackBright`.
*/
readonly gray: CSPair;
/**
Alias for `blackBright`.
*/
readonly grey: CSPair;
readonly blackBright: CSPair;
readonly redBright: CSPair;
readonly greenBright: CSPair;
readonly yellowBright: CSPair;
readonly blueBright: CSPair;
readonly cyanBright: CSPair;
readonly magentaBright: CSPair;
readonly whiteBright: CSPair;
}
interface BackgroundColor {
readonly bgBlack: CSPair;
readonly bgRed: CSPair;
readonly bgGreen: CSPair;
readonly bgYellow: CSPair;
readonly bgBlue: CSPair;
readonly bgCyan: CSPair;
readonly bgMagenta: CSPair;
readonly bgWhite: CSPair;
/**
Alias for `bgBlackBright`.
*/
readonly bgGray: CSPair;
/**
Alias for `bgBlackBright`.
*/
readonly bgGrey: CSPair;
readonly bgBlackBright: CSPair;
readonly bgRedBright: CSPair;
readonly bgGreenBright: CSPair;
readonly bgYellowBright: CSPair;
readonly bgBlueBright: CSPair;
readonly bgCyanBright: CSPair;
readonly bgMagentaBright: CSPair;
readonly bgWhiteBright: CSPair;
}
interface ConvertColor {
/**
Convert from the RGB color space to the ANSI 256 color space.
@param red - (`0...255`)
@param green - (`0...255`)
@param blue - (`0...255`)
*/
rgbToAnsi256(red: number, green: number, blue: number): number;
/**
Convert from the RGB HEX color space to the RGB color space.
@param hex - A hexadecimal string containing RGB data.
*/
hexToRgb(hex: string): [red: number, green: number, blue: number];
/**
Convert from the RGB HEX color space to the ANSI 256 color space.
@param hex - A hexadecimal string containing RGB data.
*/
hexToAnsi256(hex: string): number;
}
}
declare const ansiStyles: {
readonly modifier: ansiStyles.Modifier;
readonly color: ansiStyles.ForegroundColor & ansiStyles.ColorBase;
readonly bgColor: ansiStyles.BackgroundColor & ansiStyles.ColorBase;
readonly codes: ReadonlyMap<number, number>;
} & ansiStyles.BackgroundColor & ansiStyles.ForegroundColor & ansiStyles.Modifier & ansiStyles.ConvertColor;
export = ansiStyles;
+164
View File
@@ -0,0 +1,164 @@
'use strict';
const ANSI_BACKGROUND_OFFSET = 10;
const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
function assembleStyles() {
const codes = new Map();
const styles = {
modifier: {
reset: [0, 0],
// 21 isn't widely supported and 22 does the same thing
bold: [1, 22],
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
overline: [53, 55],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29]
},
color: {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
// Bright color
blackBright: [90, 39],
redBright: [91, 39],
greenBright: [92, 39],
yellowBright: [93, 39],
blueBright: [94, 39],
magentaBright: [95, 39],
cyanBright: [96, 39],
whiteBright: [97, 39]
},
bgColor: {
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49],
// Bright color
bgBlackBright: [100, 49],
bgRedBright: [101, 49],
bgGreenBright: [102, 49],
bgYellowBright: [103, 49],
bgBlueBright: [104, 49],
bgMagentaBright: [105, 49],
bgCyanBright: [106, 49],
bgWhiteBright: [107, 49]
}
};
// Alias bright black as gray (and grey)
styles.color.gray = styles.color.blackBright;
styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
styles.color.grey = styles.color.blackBright;
styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
for (const [groupName, group] of Object.entries(styles)) {
for (const [styleName, style] of Object.entries(group)) {
styles[styleName] = {
open: `\u001B[${style[0]}m`,
close: `\u001B[${style[1]}m`
};
group[styleName] = styles[styleName];
codes.set(style[0], style[1]);
}
Object.defineProperty(styles, groupName, {
value: group,
enumerable: false
});
}
Object.defineProperty(styles, 'codes', {
value: codes,
enumerable: false
});
styles.color.close = '\u001B[39m';
styles.bgColor.close = '\u001B[49m';
styles.color.ansi256 = wrapAnsi256();
styles.color.ansi16m = wrapAnsi16m();
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
Object.defineProperties(styles, {
rgbToAnsi256: {
value: (red, green, blue) => {
// We use the extended greyscale palette here, with the exception of
// black and white. normal palette only has 4 greyscale shades.
if (red === green && green === blue) {
if (red < 8) {
return 16;
}
if (red > 248) {
return 231;
}
return Math.round(((red - 8) / 247) * 24) + 232;
}
return 16 +
(36 * Math.round(red / 255 * 5)) +
(6 * Math.round(green / 255 * 5)) +
Math.round(blue / 255 * 5);
},
enumerable: false
},
hexToRgb: {
value: hex => {
const matches = /(?<colorString>[a-f\d]{6}|[a-f\d]{3})/i.exec(hex.toString(16));
if (!matches) {
return [0, 0, 0];
}
let {colorString} = matches.groups;
if (colorString.length === 3) {
colorString = colorString.split('').map(character => character + character).join('');
}
const integer = Number.parseInt(colorString, 16);
return [
(integer >> 16) & 0xFF,
(integer >> 8) & 0xFF,
integer & 0xFF
];
},
enumerable: false
},
hexToAnsi256: {
value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
enumerable: false
}
});
return styles;
}
// Make the export immutable
Object.defineProperty(module, 'exports', {
enumerable: true,
get: assembleStyles
});
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
@@ -0,0 +1,52 @@
{
"name": "ansi-styles",
"version": "5.2.0",
"description": "ANSI escape codes for styling strings in the terminal",
"license": "MIT",
"repository": "chalk/ansi-styles",
"funding": "https://github.com/chalk/ansi-styles?sponsor=1",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"engines": {
"node": ">=10"
},
"scripts": {
"test": "xo && ava && tsd",
"screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"ansi",
"styles",
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"tty",
"escape",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"log",
"logging",
"command-line",
"text"
],
"devDependencies": {
"ava": "^2.4.0",
"svg-term-cli": "^2.1.1",
"tsd": "^0.14.0",
"xo": "^0.37.1"
}
}
+144
View File
@@ -0,0 +1,144 @@
# ansi-styles
> [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal
You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.
<img src="screenshot.svg" width="900">
## Install
```
$ npm install ansi-styles
```
## Usage
```js
const style = require('ansi-styles');
console.log(`${style.green.open}Hello world!${style.green.close}`);
// Color conversion between 256/truecolor
// NOTE: When converting from truecolor to 256 colors, the original color
// may be degraded to fit the new color palette. This means terminals
// that do not support 16 million colors will best-match the
// original color.
console.log(`${style.color.ansi256(style.rgbToAnsi256(199, 20, 250))}Hello World${style.color.close}`)
console.log(`${style.color.ansi16m(...style.hexToRgb('#abcdef'))}Hello World${style.color.close}`)
```
## API
Each style has an `open` and `close` property.
## Styles
### Modifiers
- `reset`
- `bold`
- `dim`
- `italic` *(Not widely supported)*
- `underline`
- `overline` *Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.*
- `inverse`
- `hidden`
- `strikethrough` *(Not widely supported)*
### Colors
- `black`
- `red`
- `green`
- `yellow`
- `blue`
- `magenta`
- `cyan`
- `white`
- `blackBright` (alias: `gray`, `grey`)
- `redBright`
- `greenBright`
- `yellowBright`
- `blueBright`
- `magentaBright`
- `cyanBright`
- `whiteBright`
### Background colors
- `bgBlack`
- `bgRed`
- `bgGreen`
- `bgYellow`
- `bgBlue`
- `bgMagenta`
- `bgCyan`
- `bgWhite`
- `bgBlackBright` (alias: `bgGray`, `bgGrey`)
- `bgRedBright`
- `bgGreenBright`
- `bgYellowBright`
- `bgBlueBright`
- `bgMagentaBright`
- `bgCyanBright`
- `bgWhiteBright`
## Advanced usage
By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.
- `style.modifier`
- `style.color`
- `style.bgColor`
###### Example
```js
console.log(style.color.green.open);
```
Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values.
###### Example
```js
console.log(style.codes.get(36));
//=> 39
```
## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
`ansi-styles` allows converting between various color formats and ANSI escapes, with support for 256 and 16 million colors.
The following color spaces from `color-convert` are supported:
- `rgb`
- `hex`
- `ansi256`
To use these, call the associated conversion function with the intended output, for example:
```js
style.color.ansi256(style.rgbToAnsi256(100, 200, 15)); // RGB to 256 color ansi foreground code
style.bgColor.ansi256(style.hexToAnsi256('#C0FFEE')); // HEX to 256 color ansi foreground code
style.color.ansi16m(100, 200, 15); // RGB to 16 million color foreground code
style.bgColor.ansi16m(...style.hexToRgb('#C0FFEE')); // Hex (RGB) to 16 million color foreground code
```
## Related
- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal
## Maintainers
- [Sindre Sorhus](https://github.com/sindresorhus)
- [Josh Junon](https://github.com/qix-)
## For enterprise
Available as part of the Tidelift Subscription.
The maintainers of `ansi-styles` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-ansi-styles?utm_source=npm-ansi-styles&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
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.
+463
View File
@@ -0,0 +1,463 @@
# pretty-format
Stringify any JavaScript value.
- Serialize built-in JavaScript types.
- Serialize application-specific data types with built-in or user-defined plugins.
## Installation
```sh
$ yarn add pretty-format
```
## Usage
```js
const {format: prettyFormat} = require('pretty-format'); // CommonJS
```
```js
import {format as prettyFormat} from 'pretty-format'; // ES2015 modules
```
```js
const val = {object: {}};
val.circularReference = val;
val[Symbol('foo')] = 'foo';
val.map = new Map([['prop', 'value']]);
val.array = [-0, Infinity, NaN];
console.log(prettyFormat(val));
/*
Object {
"array": Array [
-0,
Infinity,
NaN,
],
"circularReference": [Circular],
"map": Map {
"prop" => "value",
},
"object": Object {},
Symbol(foo): "foo",
}
*/
```
## Usage with options
```js
function onClick() {}
console.log(prettyFormat(onClick));
/*
[Function onClick]
*/
const options = {
printFunctionName: false,
};
console.log(prettyFormat(onClick, options));
/*
[Function]
*/
```
<!-- prettier-ignore -->
| key | type | default | description |
| :-------------------- | :--------------- | :---------- | :-------------------------------------------------------------------------------------- |
| `callToJSON` | `boolean` | `true` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function\|null` | `undefined` | compare function used when sorting object keys, `null` can be used to skip over sorting |
| `escapeRegex` | `boolean` | `false` | escape special characters in regular expressions |
| `escapeString` | `boolean` | `true` | escape special characters in strings |
| `highlight` | `boolean` | `false` | highlight syntax with colors in terminal (some plugins) |
| `indent` | `number` | `2` | spaces in each level of indentation |
| `maxDepth` | `number` | `Infinity` | levels to print in arrays, objects, elements, and so on |
| `maxWidth` | `number` | `Infinity` | number of elements to print in arrays, sets, and so on |
| `min` | `boolean` | `false` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | `[]` | plugins to serialize application-specific data types |
| `printBasicPrototype` | `boolean` | `false` | print the prototype for plain objects and arrays |
| `printFunctionName` | `boolean` | `true` | include or omit the name of a function |
| `theme` | `object` | | colors to highlight syntax in terminal |
Property values of `theme` are from [ansi-styles colors](https://github.com/chalk/ansi-styles#colors)
```js
const DEFAULT_THEME = {
comment: 'gray',
content: 'reset',
prop: 'yellow',
tag: 'cyan',
value: 'green',
};
```
## Usage with plugins
The `pretty-format` package provides some built-in plugins, including:
- `ReactElement` for elements from `react`
- `ReactTestComponent` for test objects from `react-test-renderer`
```js
// CommonJS
const React = require('react');
const renderer = require('react-test-renderer');
const {format: prettyFormat, plugins} = require('pretty-format');
const {ReactElement, ReactTestComponent} = plugins;
```
```js
// ES2015 modules and destructuring assignment
import React from 'react';
import renderer from 'react-test-renderer';
import {plugins, format as prettyFormat} from 'pretty-format';
const {ReactElement, ReactTestComponent} = plugins;
```
```js
const onClick = () => {};
const element = React.createElement('button', {onClick}, 'Hello World');
const formatted1 = prettyFormat(element, {
plugins: [ReactElement],
printFunctionName: false,
});
const formatted2 = prettyFormat(renderer.create(element).toJSON(), {
plugins: [ReactTestComponent],
printFunctionName: false,
});
/*
<button
onClick=[Function]
>
Hello World
</button>
*/
```
## Usage in Jest
For snapshot tests, Jest uses `pretty-format` with options that include some of its built-in plugins. For this purpose, plugins are also known as **snapshot serializers**.
To serialize application-specific data types, you can add modules to `devDependencies` of a project, and then:
In an **individual** test file, you can add a module as follows. It precedes any modules from Jest configuration.
```js
import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);
// tests which have `expect(value).toMatchSnapshot()` assertions
```
For **all** test files, you can specify modules in Jest configuration. They precede built-in plugins for React, HTML, and Immutable.js data types. For example, in a `package.json` file:
```json
{
"jest": {
"snapshotSerializers": ["my-serializer-module"]
}
}
```
## Writing plugins
A plugin is a JavaScript object.
If `options` has a `plugins` array: for the first plugin whose `test(val)` method returns a truthy value, then `prettyFormat(val, options)` returns the result from either:
- `serialize(val, …)` method of the **improved** interface (available in **version 21** or later)
- `print(val, …)` method of the **original** interface (if plugin does not have `serialize` method)
### test
Write `test` so it can receive `val` argument of any type. To serialize **objects** which have certain properties, then a guarded expression like `val != null && …` or more concise `val && …` prevents the following errors:
- `TypeError: Cannot read property 'whatever' of null`
- `TypeError: Cannot read property 'whatever' of undefined`
For example, `test` method of built-in `ReactElement` plugin:
```js
const elementSymbol = Symbol.for('react.element');
const test = val => val && val.$$typeof === elementSymbol;
```
Pay attention to efficiency in `test` because `pretty-format` calls it often.
### serialize
The **improved** interface is available in **version 21** or later.
Write `serialize` to return a string, given the arguments:
- `val` which “passed the test”
- unchanging `config` object: derived from `options`
- current `indentation` string: concatenate to `indent` from `config`
- current `depth` number: compare to `maxDepth` from `config`
- current `refs` array: find circular references in objects
- `printer` callback function: serialize children
### config
<!-- prettier-ignore -->
| key | type | description |
| :------------------ | :--------------- | :-------------------------------------------------------------------------------------- |
| `callToJSON` | `boolean` | call `toJSON` method (if it exists) on objects |
| `compareKeys` | `function\|null` | compare function used when sorting object keys, `null` can be used to skip over sorting |
| `colors` | `Object` | escape codes for colors to highlight syntax |
| `escapeRegex` | `boolean` | escape special characters in regular expressions |
| `escapeString` | `boolean` | escape special characters in strings |
| `indent` | `string` | spaces in each level of indentation |
| `maxDepth` | `number` | levels to print in arrays, objects, elements, and so on |
| `min` | `boolean` | minimize added space: no indentation nor line breaks |
| `plugins` | `array` | plugins to serialize application-specific data types |
| `printFunctionName` | `boolean` | include or omit the name of a function |
| `spacingInner` | `string` | spacing to separate items in a list |
| `spacingOuter` | `string` | spacing to enclose a list of items |
Each property of `colors` in `config` corresponds to a property of `theme` in `options`:
- the key is the same (for example, `tag`)
- the value in `colors` is a object with `open` and `close` properties whose values are escape codes from [ansi-styles](https://github.com/chalk/ansi-styles) for the color value in `theme` (for example, `'cyan'`)
Some properties in `config` are derived from `min` in `options`:
- `spacingInner` and `spacingOuter` are **newline** if `min` is `false`
- `spacingInner` is **space** and `spacingOuter` is **empty string** if `min` is `true`
### Example of serialize and test
This plugin is a pattern you can apply to serialize composite data types. Side note: `pretty-format` does not need a plugin to serialize arrays.
```js
// We reused more code when we factored out a function for child items
// that is independent of depth, name, and enclosing punctuation (see below).
const SEPARATOR = ',';
function serializeItems(items, config, indentation, depth, refs, printer) {
if (items.length === 0) {
return '';
}
const indentationItems = indentation + config.indent;
return (
config.spacingOuter +
items
.map(
item =>
indentationItems +
printer(item, config, indentationItems, depth, refs), // callback
)
.join(SEPARATOR + config.spacingInner) +
(config.min ? '' : SEPARATOR) + // following the last item
config.spacingOuter +
indentation
);
}
const plugin = {
test(val) {
return Array.isArray(val);
},
serialize(array, config, indentation, depth, refs, printer) {
const name = array.constructor.name;
return ++depth > config.maxDepth
? `[${name}]`
: `${config.min ? '' : `${name} `}[${serializeItems(
array,
config,
indentation,
depth,
refs,
printer,
)}]`;
},
};
```
```js
const val = {
filter: 'completed',
items: [
{
text: 'Write test',
completed: true,
},
{
text: 'Write serialize',
completed: true,
},
],
};
```
```js
console.log(
prettyFormat(val, {
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": Array [
Object {
"completed": true,
"text": "Write test",
},
Object {
"completed": true,
"text": "Write serialize",
},
],
}
*/
```
```js
console.log(
prettyFormat(val, {
indent: 4,
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": Array [
Object {
"completed": true,
"text": "Write test",
},
Object {
"completed": true,
"text": "Write serialize",
},
],
}
*/
```
```js
console.log(
prettyFormat(val, {
maxDepth: 1,
plugins: [plugin],
}),
);
/*
Object {
"filter": "completed",
"items": [Array],
}
*/
```
```js
console.log(
prettyFormat(val, {
min: true,
plugins: [plugin],
}),
);
/*
{"filter": "completed", "items": [{"completed": true, "text": "Write test"}, {"completed": true, "text": "Write serialize"}]}
*/
```
### print
The **original** interface is adequate for plugins:
- that **do not** depend on options other than `highlight` or `min`
- that **do not** depend on `depth` or `refs` in recursive traversal, and
- if values either
- do **not** require indentation, or
- do **not** occur as children of JavaScript data structures (for example, array)
Write `print` to return a string, given the arguments:
- `val` which “passed the test”
- current `printer(valChild)` callback function: serialize children
- current `indenter(lines)` callback function: indent lines at the next level
- unchanging `config` object: derived from `options`
- unchanging `colors` object: derived from `options`
The 3 properties of `config` are `min` in `options` and:
- `spacing` and `edgeSpacing` are **newline** if `min` is `false`
- `spacing` is **space** and `edgeSpacing` is **empty string** if `min` is `true`
Each property of `colors` corresponds to a property of `theme` in `options`:
- the key is the same (for example, `tag`)
- the value in `colors` is a object with `open` and `close` properties whose values are escape codes from [ansi-styles](https://github.com/chalk/ansi-styles) for the color value in `theme` (for example, `'cyan'`)
### Example of print and test
This plugin prints functions with the **number of named arguments** excluding rest argument.
```js
const plugin = {
print(val) {
return `[Function ${val.name || 'anonymous'} ${val.length}]`;
},
test(val) {
return typeof val === 'function';
},
};
```
```js
const val = {
onClick(event) {},
render() {},
};
prettyFormat(val, {
plugins: [plugin],
});
/*
Object {
"onClick": [Function onClick 1],
"render": [Function render 0],
}
*/
prettyFormat(val);
/*
Object {
"onClick": [Function onClick],
"render": [Function render],
}
*/
```
This plugin **ignores** the `printFunctionName` option. That limitation of the original `print` interface is a reason to use the improved `serialize` interface, described above.
```js
prettyFormat(val, {
plugins: [pluginOld],
printFunctionName: false,
});
/*
Object {
"onClick": [Function onClick 1],
"render": [Function render 0],
}
*/
prettyFormat(val, {
printFunctionName: false,
});
/*
Object {
"onClick": [Function],
"render": [Function],
}
*/
```
@@ -0,0 +1,180 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.printIteratorEntries = printIteratorEntries;
exports.printIteratorValues = printIteratorValues;
exports.printListItems = printListItems;
exports.printObjectProperties = printObjectProperties;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const getKeysOfEnumerableProperties = (object, compareKeys) => {
const rawKeys = Object.keys(object);
const keys = compareKeys !== null ? rawKeys.sort(compareKeys) : rawKeys;
if (Object.getOwnPropertySymbols) {
Object.getOwnPropertySymbols(object).forEach(symbol => {
if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) {
keys.push(symbol);
}
});
}
return keys;
};
/**
* Return entries (for example, of a map)
* with spacing, indentation, and comma
* without surrounding punctuation (for example, braces)
*/
function printIteratorEntries(
iterator,
config,
indentation,
depth,
refs,
printer,
// Too bad, so sad that separator for ECMAScript Map has been ' => '
// What a distracting diff if you change a data structure to/from
// ECMAScript Object or Immutable.Map/OrderedMap which use the default.
separator = ': '
) {
let result = '';
let width = 0;
let current = iterator.next();
if (!current.done) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
while (!current.done) {
result += indentationNext;
if (width++ === config.maxWidth) {
result += '…';
break;
}
const name = printer(
current.value[0],
config,
indentationNext,
depth,
refs
);
const value = printer(
current.value[1],
config,
indentationNext,
depth,
refs
);
result += name + separator + value;
current = iterator.next();
if (!current.done) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
/**
* Return values (for example, of a set)
* with spacing, indentation, and comma
* without surrounding punctuation (braces or brackets)
*/
function printIteratorValues(
iterator,
config,
indentation,
depth,
refs,
printer
) {
let result = '';
let width = 0;
let current = iterator.next();
if (!current.done) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
while (!current.done) {
result += indentationNext;
if (width++ === config.maxWidth) {
result += '…';
break;
}
result += printer(current.value, config, indentationNext, depth, refs);
current = iterator.next();
if (!current.done) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
/**
* Return items (for example, of an array)
* with spacing, indentation, and comma
* without surrounding punctuation (for example, brackets)
**/
function printListItems(list, config, indentation, depth, refs, printer) {
let result = '';
if (list.length) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
for (let i = 0; i < list.length; i++) {
result += indentationNext;
if (i === config.maxWidth) {
result += '…';
break;
}
if (i in list) {
result += printer(list[i], config, indentationNext, depth, refs);
}
if (i < list.length - 1) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
/**
* Return properties of an object
* with spacing, indentation, and comma
* without surrounding punctuation (for example, braces)
*/
function printObjectProperties(val, config, indentation, depth, refs, printer) {
let result = '';
const keys = getKeysOfEnumerableProperties(val, config.compareKeys);
if (keys.length) {
result += config.spacingOuter;
const indentationNext = indentation + config.indent;
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const name = printer(key, config, indentationNext, depth, refs);
const value = printer(val[key], config, indentationNext, depth, refs);
result += `${indentationNext + name}: ${value}`;
if (i < keys.length - 1) {
result += `,${config.spacingInner}`;
} else if (!config.min) {
result += ',';
}
}
result += config.spacingOuter + indentation;
}
return result;
}
@@ -0,0 +1,163 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type {SnapshotFormat} from '@jest/schemas';
export declare type Colors = {
comment: {
close: string;
open: string;
};
content: {
close: string;
open: string;
};
prop: {
close: string;
open: string;
};
tag: {
close: string;
open: string;
};
value: {
close: string;
open: string;
};
};
export declare type CompareKeys =
| ((a: string, b: string) => number)
| null
| undefined;
export declare type Config = {
callToJSON: boolean;
compareKeys: CompareKeys;
colors: Colors;
escapeRegex: boolean;
escapeString: boolean;
indent: string;
maxDepth: number;
maxWidth: number;
min: boolean;
plugins: Plugins;
printBasicPrototype: boolean;
printFunctionName: boolean;
spacingInner: string;
spacingOuter: string;
};
export declare const DEFAULT_OPTIONS: {
callToJSON: true;
compareKeys: undefined;
escapeRegex: false;
escapeString: true;
highlight: false;
indent: number;
maxDepth: number;
maxWidth: number;
min: false;
plugins: never[];
printBasicPrototype: true;
printFunctionName: true;
theme: Required<{
readonly comment?: string | undefined;
readonly content?: string | undefined;
readonly prop?: string | undefined;
readonly tag?: string | undefined;
readonly value?: string | undefined;
}>;
};
/**
* Returns a presentation string of your `val` object
* @param val any potential JavaScript object
* @param options Custom settings
*/
declare function format(val: unknown, options?: OptionsReceived): string;
export default format;
export {format};
declare type Indent = (arg0: string) => string;
export declare type NewPlugin = {
serialize: (
val: any,
config: Config,
indentation: string,
depth: number,
refs: Refs,
printer: Printer,
) => string;
test: Test;
};
export declare type OldPlugin = {
print: (
val: unknown,
print: Print,
indent: Indent,
options: PluginOptions,
colors: Colors,
) => string;
test: Test;
};
export declare interface Options
extends Omit<RequiredOptions, 'compareKeys' | 'theme'> {
compareKeys: CompareKeys;
theme: Required<RequiredOptions['theme']>;
}
export declare type OptionsReceived = PrettyFormatOptions;
declare type Plugin_2 = NewPlugin | OldPlugin;
export {Plugin_2 as Plugin};
declare type PluginOptions = {
edgeSpacing: string;
min: boolean;
spacing: string;
};
export declare type Plugins = Array<Plugin_2>;
export declare const plugins: {
AsymmetricMatcher: NewPlugin;
DOMCollection: NewPlugin;
DOMElement: NewPlugin;
Immutable: NewPlugin;
ReactElement: NewPlugin;
ReactTestComponent: NewPlugin;
};
export declare interface PrettyFormatOptions
extends Omit<SnapshotFormat, 'compareKeys'> {
compareKeys?: CompareKeys;
plugins?: Plugins;
}
declare type Print = (arg0: unknown) => string;
export declare type Printer = (
val: unknown,
config: Config,
indentation: string,
depth: number,
refs: Refs,
hasCalledToJSON?: boolean,
) => string;
export declare type Refs = Array<unknown>;
declare type RequiredOptions = Required<PrettyFormatOptions>;
declare type Test = (arg0: any) => boolean;
export declare type Theme = Options['theme'];
export {};
@@ -0,0 +1,478 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = exports.DEFAULT_OPTIONS = void 0;
exports.format = format;
exports.plugins = void 0;
var _ansiStyles = _interopRequireDefault(require('ansi-styles'));
var _collections = require('./collections');
var _AsymmetricMatcher = _interopRequireDefault(
require('./plugins/AsymmetricMatcher')
);
var _DOMCollection = _interopRequireDefault(require('./plugins/DOMCollection'));
var _DOMElement = _interopRequireDefault(require('./plugins/DOMElement'));
var _Immutable = _interopRequireDefault(require('./plugins/Immutable'));
var _ReactElement = _interopRequireDefault(require('./plugins/ReactElement'));
var _ReactTestComponent = _interopRequireDefault(
require('./plugins/ReactTestComponent')
);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* eslint-disable local/ban-types-eventually */
const toString = Object.prototype.toString;
const toISOString = Date.prototype.toISOString;
const errorToString = Error.prototype.toString;
const regExpToString = RegExp.prototype.toString;
/**
* Explicitly comparing typeof constructor to function avoids undefined as name
* when mock identity-obj-proxy returns the key as the value for any key.
*/
const getConstructorName = val =>
(typeof val.constructor === 'function' && val.constructor.name) || 'Object';
/* global window */
/** Is val is equal to global window object? Works even if it does not exist :) */
const isWindow = val => typeof window !== 'undefined' && val === window;
const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/;
const NEWLINE_REGEXP = /\n/gi;
class PrettyFormatPluginError extends Error {
constructor(message, stack) {
super(message);
this.stack = stack;
this.name = this.constructor.name;
}
}
function isToStringedArrayType(toStringed) {
return (
toStringed === '[object Array]' ||
toStringed === '[object ArrayBuffer]' ||
toStringed === '[object DataView]' ||
toStringed === '[object Float32Array]' ||
toStringed === '[object Float64Array]' ||
toStringed === '[object Int8Array]' ||
toStringed === '[object Int16Array]' ||
toStringed === '[object Int32Array]' ||
toStringed === '[object Uint8Array]' ||
toStringed === '[object Uint8ClampedArray]' ||
toStringed === '[object Uint16Array]' ||
toStringed === '[object Uint32Array]'
);
}
function printNumber(val) {
return Object.is(val, -0) ? '-0' : String(val);
}
function printBigInt(val) {
return String(`${val}n`);
}
function printFunction(val, printFunctionName) {
if (!printFunctionName) {
return '[Function]';
}
return `[Function ${val.name || 'anonymous'}]`;
}
function printSymbol(val) {
return String(val).replace(SYMBOL_REGEXP, 'Symbol($1)');
}
function printError(val) {
return `[${errorToString.call(val)}]`;
}
/**
* The first port of call for printing an object, handles most of the
* data-types in JS.
*/
function printBasicValue(val, printFunctionName, escapeRegex, escapeString) {
if (val === true || val === false) {
return `${val}`;
}
if (val === undefined) {
return 'undefined';
}
if (val === null) {
return 'null';
}
const typeOf = typeof val;
if (typeOf === 'number') {
return printNumber(val);
}
if (typeOf === 'bigint') {
return printBigInt(val);
}
if (typeOf === 'string') {
if (escapeString) {
return `"${val.replace(/"|\\/g, '\\$&')}"`;
}
return `"${val}"`;
}
if (typeOf === 'function') {
return printFunction(val, printFunctionName);
}
if (typeOf === 'symbol') {
return printSymbol(val);
}
const toStringed = toString.call(val);
if (toStringed === '[object WeakMap]') {
return 'WeakMap {}';
}
if (toStringed === '[object WeakSet]') {
return 'WeakSet {}';
}
if (
toStringed === '[object Function]' ||
toStringed === '[object GeneratorFunction]'
) {
return printFunction(val, printFunctionName);
}
if (toStringed === '[object Symbol]') {
return printSymbol(val);
}
if (toStringed === '[object Date]') {
return isNaN(+val) ? 'Date { NaN }' : toISOString.call(val);
}
if (toStringed === '[object Error]') {
return printError(val);
}
if (toStringed === '[object RegExp]') {
if (escapeRegex) {
// https://github.com/benjamingr/RegExp.escape/blob/main/polyfill.js
return regExpToString.call(val).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
}
return regExpToString.call(val);
}
if (val instanceof Error) {
return printError(val);
}
return null;
}
/**
* Handles more complex objects ( such as objects with circular references.
* maps and sets etc )
*/
function printComplexValue(
val,
config,
indentation,
depth,
refs,
hasCalledToJSON
) {
if (refs.indexOf(val) !== -1) {
return '[Circular]';
}
refs = refs.slice();
refs.push(val);
const hitMaxDepth = ++depth > config.maxDepth;
const min = config.min;
if (
config.callToJSON &&
!hitMaxDepth &&
val.toJSON &&
typeof val.toJSON === 'function' &&
!hasCalledToJSON
) {
return printer(val.toJSON(), config, indentation, depth, refs, true);
}
const toStringed = toString.call(val);
if (toStringed === '[object Arguments]') {
return hitMaxDepth
? '[Arguments]'
: `${min ? '' : 'Arguments '}[${(0, _collections.printListItems)(
val,
config,
indentation,
depth,
refs,
printer
)}]`;
}
if (isToStringedArrayType(toStringed)) {
return hitMaxDepth
? `[${val.constructor.name}]`
: `${
min
? ''
: !config.printBasicPrototype && val.constructor.name === 'Array'
? ''
: `${val.constructor.name} `
}[${(0, _collections.printListItems)(
val,
config,
indentation,
depth,
refs,
printer
)}]`;
}
if (toStringed === '[object Map]') {
return hitMaxDepth
? '[Map]'
: `Map {${(0, _collections.printIteratorEntries)(
val.entries(),
config,
indentation,
depth,
refs,
printer,
' => '
)}}`;
}
if (toStringed === '[object Set]') {
return hitMaxDepth
? '[Set]'
: `Set {${(0, _collections.printIteratorValues)(
val.values(),
config,
indentation,
depth,
refs,
printer
)}}`;
}
// Avoid failure to serialize global window object in jsdom test environment.
// For example, not even relevant if window is prop of React element.
return hitMaxDepth || isWindow(val)
? `[${getConstructorName(val)}]`
: `${
min
? ''
: !config.printBasicPrototype && getConstructorName(val) === 'Object'
? ''
: `${getConstructorName(val)} `
}{${(0, _collections.printObjectProperties)(
val,
config,
indentation,
depth,
refs,
printer
)}}`;
}
function isNewPlugin(plugin) {
return plugin.serialize != null;
}
function printPlugin(plugin, val, config, indentation, depth, refs) {
let printed;
try {
printed = isNewPlugin(plugin)
? plugin.serialize(val, config, indentation, depth, refs, printer)
: plugin.print(
val,
valChild => printer(valChild, config, indentation, depth, refs),
str => {
const indentationNext = indentation + config.indent;
return (
indentationNext +
str.replace(NEWLINE_REGEXP, `\n${indentationNext}`)
);
},
{
edgeSpacing: config.spacingOuter,
min: config.min,
spacing: config.spacingInner
},
config.colors
);
} catch (error) {
throw new PrettyFormatPluginError(error.message, error.stack);
}
if (typeof printed !== 'string') {
throw new Error(
`pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`
);
}
return printed;
}
function findPlugin(plugins, val) {
for (let p = 0; p < plugins.length; p++) {
try {
if (plugins[p].test(val)) {
return plugins[p];
}
} catch (error) {
throw new PrettyFormatPluginError(error.message, error.stack);
}
}
return null;
}
function printer(val, config, indentation, depth, refs, hasCalledToJSON) {
const plugin = findPlugin(config.plugins, val);
if (plugin !== null) {
return printPlugin(plugin, val, config, indentation, depth, refs);
}
const basicResult = printBasicValue(
val,
config.printFunctionName,
config.escapeRegex,
config.escapeString
);
if (basicResult !== null) {
return basicResult;
}
return printComplexValue(
val,
config,
indentation,
depth,
refs,
hasCalledToJSON
);
}
const DEFAULT_THEME = {
comment: 'gray',
content: 'reset',
prop: 'yellow',
tag: 'cyan',
value: 'green'
};
const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME);
// could be replaced by `satisfies` operator in the future: https://github.com/microsoft/TypeScript/issues/47920
const toOptionsSubtype = options => options;
const DEFAULT_OPTIONS = toOptionsSubtype({
callToJSON: true,
compareKeys: undefined,
escapeRegex: false,
escapeString: true,
highlight: false,
indent: 2,
maxDepth: Infinity,
maxWidth: Infinity,
min: false,
plugins: [],
printBasicPrototype: true,
printFunctionName: true,
theme: DEFAULT_THEME
});
exports.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
function validateOptions(options) {
Object.keys(options).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(DEFAULT_OPTIONS, key)) {
throw new Error(`pretty-format: Unknown option "${key}".`);
}
});
if (options.min && options.indent !== undefined && options.indent !== 0) {
throw new Error(
'pretty-format: Options "min" and "indent" cannot be used together.'
);
}
if (options.theme !== undefined) {
if (options.theme === null) {
throw new Error('pretty-format: Option "theme" must not be null.');
}
if (typeof options.theme !== 'object') {
throw new Error(
`pretty-format: Option "theme" must be of type "object" but instead received "${typeof options.theme}".`
);
}
}
}
const getColorsHighlight = options =>
DEFAULT_THEME_KEYS.reduce((colors, key) => {
const value =
options.theme && options.theme[key] !== undefined
? options.theme[key]
: DEFAULT_THEME[key];
const color = value && _ansiStyles.default[value];
if (
color &&
typeof color.close === 'string' &&
typeof color.open === 'string'
) {
colors[key] = color;
} else {
throw new Error(
`pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.`
);
}
return colors;
}, Object.create(null));
const getColorsEmpty = () =>
DEFAULT_THEME_KEYS.reduce((colors, key) => {
colors[key] = {
close: '',
open: ''
};
return colors;
}, Object.create(null));
const getPrintFunctionName = options =>
options?.printFunctionName ?? DEFAULT_OPTIONS.printFunctionName;
const getEscapeRegex = options =>
options?.escapeRegex ?? DEFAULT_OPTIONS.escapeRegex;
const getEscapeString = options =>
options?.escapeString ?? DEFAULT_OPTIONS.escapeString;
const getConfig = options => ({
callToJSON: options?.callToJSON ?? DEFAULT_OPTIONS.callToJSON,
colors: options?.highlight ? getColorsHighlight(options) : getColorsEmpty(),
compareKeys:
typeof options?.compareKeys === 'function' || options?.compareKeys === null
? options.compareKeys
: DEFAULT_OPTIONS.compareKeys,
escapeRegex: getEscapeRegex(options),
escapeString: getEscapeString(options),
indent: options?.min
? ''
: createIndent(options?.indent ?? DEFAULT_OPTIONS.indent),
maxDepth: options?.maxDepth ?? DEFAULT_OPTIONS.maxDepth,
maxWidth: options?.maxWidth ?? DEFAULT_OPTIONS.maxWidth,
min: options?.min ?? DEFAULT_OPTIONS.min,
plugins: options?.plugins ?? DEFAULT_OPTIONS.plugins,
printBasicPrototype: options?.printBasicPrototype ?? true,
printFunctionName: getPrintFunctionName(options),
spacingInner: options?.min ? ' ' : '\n',
spacingOuter: options?.min ? '' : '\n'
});
function createIndent(indent) {
return new Array(indent + 1).join(' ');
}
/**
* Returns a presentation string of your `val` object
* @param val any potential JavaScript object
* @param options Custom settings
*/
function format(val, options) {
if (options) {
validateOptions(options);
if (options.plugins) {
const plugin = findPlugin(options.plugins, val);
if (plugin !== null) {
return printPlugin(plugin, val, getConfig(options), '', 0, []);
}
}
}
const basicResult = printBasicValue(
val,
getPrintFunctionName(options),
getEscapeRegex(options),
getEscapeString(options)
);
if (basicResult !== null) {
return basicResult;
}
return printComplexValue(val, getConfig(options), '', 0, []);
}
const plugins = {
AsymmetricMatcher: _AsymmetricMatcher.default,
DOMCollection: _DOMCollection.default,
DOMElement: _DOMElement.default,
Immutable: _Immutable.default,
ReactElement: _ReactElement.default,
ReactTestComponent: _ReactTestComponent.default
};
exports.plugins = plugins;
var _default = format;
exports.default = _default;
@@ -0,0 +1,89 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _collections = require('../collections');
var Symbol = globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const asymmetricMatcher =
typeof Symbol === 'function' && Symbol.for
? Symbol.for('jest.asymmetricMatcher')
: 0x1357a5;
const SPACE = ' ';
const serialize = (val, config, indentation, depth, refs, printer) => {
const stringedValue = val.toString();
if (
stringedValue === 'ArrayContaining' ||
stringedValue === 'ArrayNotContaining'
) {
if (++depth > config.maxDepth) {
return `[${stringedValue}]`;
}
return `${stringedValue + SPACE}[${(0, _collections.printListItems)(
val.sample,
config,
indentation,
depth,
refs,
printer
)}]`;
}
if (
stringedValue === 'ObjectContaining' ||
stringedValue === 'ObjectNotContaining'
) {
if (++depth > config.maxDepth) {
return `[${stringedValue}]`;
}
return `${stringedValue + SPACE}{${(0, _collections.printObjectProperties)(
val.sample,
config,
indentation,
depth,
refs,
printer
)}}`;
}
if (
stringedValue === 'StringMatching' ||
stringedValue === 'StringNotMatching'
) {
return (
stringedValue +
SPACE +
printer(val.sample, config, indentation, depth, refs)
);
}
if (
stringedValue === 'StringContaining' ||
stringedValue === 'StringNotContaining'
) {
return (
stringedValue +
SPACE +
printer(val.sample, config, indentation, depth, refs)
);
}
if (typeof val.toAsymmetricMatcher !== 'function') {
throw new Error(
`Asymmetric matcher ${val.constructor.name} does not implement toAsymmetricMatcher()`
);
}
return val.toAsymmetricMatcher();
};
exports.serialize = serialize;
const test = val => val && val.$$typeof === asymmetricMatcher;
exports.test = test;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,67 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _collections = require('../collections');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const SPACE = ' ';
const OBJECT_NAMES = ['DOMStringMap', 'NamedNodeMap'];
const ARRAY_REGEXP = /^(HTML\w*Collection|NodeList)$/;
const testName = name =>
OBJECT_NAMES.indexOf(name) !== -1 || ARRAY_REGEXP.test(name);
const test = val =>
val &&
val.constructor &&
!!val.constructor.name &&
testName(val.constructor.name);
exports.test = test;
const isNamedNodeMap = collection =>
collection.constructor.name === 'NamedNodeMap';
const serialize = (collection, config, indentation, depth, refs, printer) => {
const name = collection.constructor.name;
if (++depth > config.maxDepth) {
return `[${name}]`;
}
return (
(config.min ? '' : name + SPACE) +
(OBJECT_NAMES.indexOf(name) !== -1
? `{${(0, _collections.printObjectProperties)(
isNamedNodeMap(collection)
? Array.from(collection).reduce((props, attribute) => {
props[attribute.name] = attribute.value;
return props;
}, {})
: {
...collection
},
config,
indentation,
depth,
refs,
printer
)}}`
: `[${(0, _collections.printListItems)(
Array.from(collection),
config,
indentation,
depth,
refs,
printer
)}]`)
);
};
exports.serialize = serialize;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;
@@ -0,0 +1,101 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.test = exports.serialize = exports.default = void 0;
var _markup = require('./lib/markup');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const ELEMENT_NODE = 1;
const TEXT_NODE = 3;
const COMMENT_NODE = 8;
const FRAGMENT_NODE = 11;
const ELEMENT_REGEXP = /^((HTML|SVG)\w*)?Element$/;
const testHasAttribute = val => {
try {
return typeof val.hasAttribute === 'function' && val.hasAttribute('is');
} catch {
return false;
}
};
const testNode = val => {
const constructorName = val.constructor.name;
const {nodeType, tagName} = val;
const isCustomElement =
(typeof tagName === 'string' && tagName.includes('-')) ||
testHasAttribute(val);
return (
(nodeType === ELEMENT_NODE &&
(ELEMENT_REGEXP.test(constructorName) || isCustomElement)) ||
(nodeType === TEXT_NODE && constructorName === 'Text') ||
(nodeType === COMMENT_NODE && constructorName === 'Comment') ||
(nodeType === FRAGMENT_NODE && constructorName === 'DocumentFragment')
);
};
const test = val => val?.constructor?.name && testNode(val);
exports.test = test;
function nodeIsText(node) {
return node.nodeType === TEXT_NODE;
}
function nodeIsComment(node) {
return node.nodeType === COMMENT_NODE;
}
function nodeIsFragment(node) {
return node.nodeType === FRAGMENT_NODE;
}
const serialize = (node, config, indentation, depth, refs, printer) => {
if (nodeIsText(node)) {
return (0, _markup.printText)(node.data, config);
}
if (nodeIsComment(node)) {
return (0, _markup.printComment)(node.data, config);
}
const type = nodeIsFragment(node)
? 'DocumentFragment'
: node.tagName.toLowerCase();
if (++depth > config.maxDepth) {
return (0, _markup.printElementAsLeaf)(type, config);
}
return (0, _markup.printElement)(
type,
(0, _markup.printProps)(
nodeIsFragment(node)
? []
: Array.from(node.attributes, attr => attr.name).sort(),
nodeIsFragment(node)
? {}
: Array.from(node.attributes).reduce((props, attribute) => {
props[attribute.name] = attribute.value;
return props;
}, {}),
config,
indentation + config.indent,
depth,
refs,
printer
),
(0, _markup.printChildren)(
Array.prototype.slice.call(node.childNodes || node.children),
config,
indentation + config.indent,
depth,
refs,
printer
),
config,
indentation
);
};
exports.serialize = serialize;
const plugin = {
serialize,
test
};
var _default = plugin;
exports.default = _default;

Some files were not shown because too many files have changed in this diff Show More