WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// Interface declaration for Float16Array, required in @types/node v24+.
|
||||
// These definitions are specific to TS <=5.6.
|
||||
|
||||
// This needs all of the "common" properties/methods of the TypedArrays,
|
||||
// otherwise the type unions `TypedArray` and `ArrayBufferView` will be
|
||||
// empty objects.
|
||||
interface Float16Array extends Pick<Float32Array, typeof Symbol.iterator | "entries" | "keys" | "values"> {
|
||||
readonly BYTES_PER_ELEMENT: number;
|
||||
readonly buffer: ArrayBufferLike;
|
||||
readonly byteLength: number;
|
||||
readonly byteOffset: number;
|
||||
readonly length: number;
|
||||
readonly [Symbol.toStringTag]: "Float16Array";
|
||||
at(index: number): number | undefined;
|
||||
copyWithin(target: number, start: number, end?: number): this;
|
||||
every(predicate: (value: number, index: number, array: Float16Array) => unknown, thisArg?: any): boolean;
|
||||
fill(value: number, start?: number, end?: number): this;
|
||||
filter(predicate: (value: number, index: number, array: Float16Array) => any, thisArg?: any): Float16Array;
|
||||
find(predicate: (value: number, index: number, obj: Float16Array) => boolean, thisArg?: any): number | undefined;
|
||||
findIndex(predicate: (value: number, index: number, obj: Float16Array) => boolean, thisArg?: any): number;
|
||||
findLast<S extends number>(
|
||||
predicate: (value: number, index: number, array: Float16Array) => value is S,
|
||||
thisArg?: any,
|
||||
): S | undefined;
|
||||
findLast(
|
||||
predicate: (value: number, index: number, array: Float16Array) => unknown,
|
||||
thisArg?: any,
|
||||
): number | undefined;
|
||||
findLastIndex(predicate: (value: number, index: number, array: Float16Array) => unknown, thisArg?: any): number;
|
||||
forEach(callbackfn: (value: number, index: number, array: Float16Array) => void, thisArg?: any): void;
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
indexOf(searchElement: number, fromIndex?: number): number;
|
||||
join(separator?: string): string;
|
||||
lastIndexOf(searchElement: number, fromIndex?: number): number;
|
||||
map(callbackfn: (value: number, index: number, array: Float16Array) => number, thisArg?: any): Float16Array;
|
||||
reduce(
|
||||
callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float16Array) => number,
|
||||
): number;
|
||||
reduce(
|
||||
callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float16Array) => number,
|
||||
initialValue: number,
|
||||
): number;
|
||||
reduce<U>(
|
||||
callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float16Array) => U,
|
||||
initialValue: U,
|
||||
): U;
|
||||
reduceRight(
|
||||
callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float16Array) => number,
|
||||
): number;
|
||||
reduceRight(
|
||||
callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float16Array) => number,
|
||||
initialValue: number,
|
||||
): number;
|
||||
reduceRight<U>(
|
||||
callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float16Array) => U,
|
||||
initialValue: U,
|
||||
): U;
|
||||
reverse(): Float16Array;
|
||||
set(array: ArrayLike<number>, offset?: number): void;
|
||||
slice(start?: number, end?: number): Float16Array;
|
||||
some(predicate: (value: number, index: number, array: Float16Array) => unknown, thisArg?: any): boolean;
|
||||
sort(compareFn?: (a: number, b: number) => number): this;
|
||||
subarray(begin?: number, end?: number): Float16Array;
|
||||
toLocaleString(locales: string | string[], options?: Intl.NumberFormatOptions): string;
|
||||
toReversed(): Float16Array;
|
||||
toSorted(compareFn?: (a: number, b: number) => number): Float16Array;
|
||||
toString(): string;
|
||||
valueOf(): Float16Array;
|
||||
with(index: number, value: number): Float16Array;
|
||||
[index: number]: number;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
const promisify = require('es6-promisify');
|
||||
const jayson = require('../../../');
|
||||
const promiseUtils = require('../utils');
|
||||
|
||||
/**
|
||||
* Constructor for a Jayson Promise Client Websocket
|
||||
* @see Client
|
||||
* @class PromiseClientWebsocket
|
||||
* @extends ClientWebsocket
|
||||
* @return {PromiseClientWebsocket}
|
||||
*/
|
||||
const PromiseClientWebsocket = function(options) {
|
||||
if(!(this instanceof PromiseClientWebsocket)) {
|
||||
return new PromiseClientWebsocket(options);
|
||||
}
|
||||
jayson.Client.websocket.apply(this, arguments);
|
||||
this.request = promiseUtils.wrapClientRequestMethod(this.request.bind(this));
|
||||
};
|
||||
require('util').inherits(PromiseClientWebsocket, jayson.Client.websocket);
|
||||
|
||||
module.exports = PromiseClientWebsocket;
|
||||
@@ -0,0 +1,6 @@
|
||||
function _class_private_method_get(receiver, privateSet, fn) {
|
||||
if (!privateSet.has(receiver)) throw new TypeError("attempted to get private field on non-instance");
|
||||
|
||||
return fn;
|
||||
}
|
||||
export { _class_private_method_get as _ };
|
||||
@@ -0,0 +1,17 @@
|
||||
export declare enum ScriptTarget {
|
||||
ES2015 = 2,
|
||||
ES2016 = 3,
|
||||
ES2017 = 4,
|
||||
ES2018 = 5,
|
||||
ES2019 = 6,
|
||||
ES2020 = 7,
|
||||
ES2021 = 8,
|
||||
ES2022 = 9,
|
||||
ES2023 = 10,
|
||||
ES2024 = 11,
|
||||
ES2025 = 12,
|
||||
ESNext = 99,
|
||||
JSON = 100,
|
||||
Latest = 99
|
||||
}
|
||||
//# sourceMappingURL=scriptTarget.enum.d.ts.map
|
||||
@@ -0,0 +1,5 @@
|
||||
var assertClassBrand = require("./assertClassBrand.js");
|
||||
function _classPrivateGetter(s, r, a) {
|
||||
return a(assertClassBrand(s, r));
|
||||
}
|
||||
module.exports = _classPrivateGetter, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "@typescript-eslint/scope-manager",
|
||||
"version": "8.67.0",
|
||||
"description": "TypeScript scope analyser for ESLint",
|
||||
"files": [
|
||||
"dist",
|
||||
"!**/*.tsbuildinfo"
|
||||
],
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/typescript-eslint/typescript-eslint.git",
|
||||
"directory": "packages/scope-manager"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/typescript-eslint/typescript-eslint/issues"
|
||||
},
|
||||
"homepage": "https://typescript-eslint.io/packages/scope-manager",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"eslint",
|
||||
"typescript",
|
||||
"estree"
|
||||
],
|
||||
"dependencies": {
|
||||
"@typescript-eslint/visitor-keys": "8.67.0",
|
||||
"@typescript-eslint/types": "8.67.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native": "npm:typescript@^7.0.2",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vitest/pretty-format": "^4.0.18",
|
||||
"eslint": "^10.0.0",
|
||||
"glob": "^11.1.0",
|
||||
"rimraf": "^5.0.10",
|
||||
"typescript": ">=4.8.4 <6.1.0",
|
||||
"vitest": "^4.0.18",
|
||||
"@typescript-eslint/typescript-estree": "8.67.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"nx": {
|
||||
"name": "scope-manager",
|
||||
"includedScripts": [
|
||||
"clean",
|
||||
"clean-fixtures"
|
||||
],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"command": "eslint"
|
||||
},
|
||||
"typecheck:tsgo": {},
|
||||
"attw-check": {}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm exec nx build",
|
||||
"clean": "rimraf dist/ coverage/",
|
||||
"clean-fixtures": "rimraf -g \"./tests/fixtures/**/*.shot\"",
|
||||
"format": "pnpm -w run format",
|
||||
"generate-lib": "pnpm -w exec nx generate-lib repo",
|
||||
"lint": "pnpm -w exec nx lint",
|
||||
"test": "pnpm -w exec nx test",
|
||||
"typecheck": "pnpm -w exec nx typecheck",
|
||||
"typecheck:tsgo": "pnpm -w exec nx typecheck:tsgo",
|
||||
"attw-check": "pnpm -w exec nx attw-check"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"name": "@typescript-eslint/utils",
|
||||
"version": "8.67.0",
|
||||
"description": "Utilities for working with TypeScript + ESLint together",
|
||||
"files": [
|
||||
"dist",
|
||||
"!**/*.tsbuildinfo"
|
||||
],
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./ast-utils": {
|
||||
"types": "./dist/ast-utils/index.d.ts",
|
||||
"default": "./dist/ast-utils/index.js"
|
||||
},
|
||||
"./eslint-utils": {
|
||||
"types": "./dist/eslint-utils/index.d.ts",
|
||||
"default": "./dist/eslint-utils/index.js"
|
||||
},
|
||||
"./json-schema": {
|
||||
"types": "./dist/json-schema.d.ts",
|
||||
"default": "./dist/json-schema.js"
|
||||
},
|
||||
"./ts-eslint": {
|
||||
"types": "./dist/ts-eslint/index.d.ts",
|
||||
"default": "./dist/ts-eslint/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/typescript-eslint/typescript-eslint.git",
|
||||
"directory": "packages/utils"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/typescript-eslint/typescript-eslint/issues"
|
||||
},
|
||||
"homepage": "https://typescript-eslint.io/packages/utils",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"eslint",
|
||||
"typescript",
|
||||
"estree"
|
||||
],
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.67.0",
|
||||
"@typescript-eslint/typescript-estree": "8.67.0",
|
||||
"@typescript-eslint/types": "8.67.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native": "npm:typescript@^7.0.2",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"eslint": "^10.0.0",
|
||||
"rimraf": "^5.0.10",
|
||||
"typescript": ">=4.8.4 <6.1.0",
|
||||
"vitest": "^4.0.18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"nx": {
|
||||
"name": "utils",
|
||||
"includedScripts": [
|
||||
"clean"
|
||||
],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"command": "eslint"
|
||||
},
|
||||
"typecheck": {
|
||||
"outputs": [
|
||||
"{workspaceRoot}/dist",
|
||||
"{projectRoot}/dist"
|
||||
]
|
||||
},
|
||||
"typecheck:tsgo": {
|
||||
"outputs": [
|
||||
"{workspaceRoot}/dist",
|
||||
"{projectRoot}/dist"
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"typecheck"
|
||||
]
|
||||
},
|
||||
"attw-check": {}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm exec nx build",
|
||||
"clean": "rimraf dist/ coverage/",
|
||||
"format": "pnpm -w run format",
|
||||
"lint": "pnpm -w exec nx lint",
|
||||
"test": "pnpm -w exec nx test",
|
||||
"typecheck": "pnpm -w exec nx typecheck",
|
||||
"typecheck:tsgo": "pnpm -w exec nx typecheck:tsgo",
|
||||
"attw-check": "pnpm -w exec nx attw-check"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
'use strict'
|
||||
|
||||
// Run this to see how colouring works
|
||||
|
||||
const _prettyFactory = require('../../')
|
||||
const pino = require('pino')
|
||||
const { Writable } = require('node:stream')
|
||||
|
||||
function prettyFactory () {
|
||||
return _prettyFactory({
|
||||
colorize: true
|
||||
})
|
||||
}
|
||||
|
||||
const pretty = prettyFactory()
|
||||
const formatted = pretty('this is not json\nit\'s just regular output\n')
|
||||
console.log(formatted)
|
||||
|
||||
const opts = {
|
||||
base: {
|
||||
hostname: 'localhost',
|
||||
pid: process.pid
|
||||
}
|
||||
}
|
||||
const log = pino(opts, new Writable({
|
||||
write (chunk, enc, cb) {
|
||||
const formatted = pretty(chunk.toString())
|
||||
console.log(formatted)
|
||||
cb()
|
||||
}
|
||||
}))
|
||||
|
||||
log.info('foobar')
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Hiroki Osame <hiroki.osame@gmail.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,704 @@
|
||||
import { existsSync, writeFileSync, readFileSync } from 'node:fs';
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { resolve, dirname, relative } from 'node:path';
|
||||
import { detectPackageManager, installPackage } from './index.CMESou6r.js';
|
||||
import { p as prompt, a as any } from './index.og1WyBLx.js';
|
||||
import { x } from 'tinyexec';
|
||||
import c from 'tinyrainbow';
|
||||
import { c as configFiles } from './constants.CPYnjOGj.js';
|
||||
import 'node:process';
|
||||
import 'node:module';
|
||||
import 'node:url';
|
||||
import './_commonjsHelpers.D26ty3Ew.js';
|
||||
import 'readline';
|
||||
import 'events';
|
||||
|
||||
const jsxExample = {
|
||||
name: "HelloWorld.jsx",
|
||||
js: `
|
||||
export default function HelloWorld({ name }) {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello {name}!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`,
|
||||
ts: `
|
||||
export default function HelloWorld({ name }: { name: string }) {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello {name}!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from '@testing-library/jsx'
|
||||
import HelloWorld from './HelloWorld.<EXT>x'
|
||||
|
||||
test('renders name', async () => {
|
||||
const { getByText } = await render(<HelloWorld name="Vitest" />)
|
||||
await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const vueExample = {
|
||||
name: "HelloWorld.vue",
|
||||
js: `
|
||||
<script setup>
|
||||
defineProps({
|
||||
name: String
|
||||
})
|
||||
<\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Hello {{ name }}!</h1>
|
||||
</div>
|
||||
</template>
|
||||
`,
|
||||
ts: `
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
name: string
|
||||
}>()
|
||||
<\/script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Hello {{ name }}!</h1>
|
||||
</div>
|
||||
</template>
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from 'vitest-browser-vue'
|
||||
import HelloWorld from './HelloWorld.vue'
|
||||
|
||||
test('renders name', async () => {
|
||||
const { getByText } = render(HelloWorld, {
|
||||
props: { name: 'Vitest' },
|
||||
})
|
||||
await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const svelteExample = {
|
||||
name: "HelloWorld.svelte",
|
||||
js: `
|
||||
<script>
|
||||
export let name
|
||||
<\/script>
|
||||
|
||||
<h1>Hello {name}!</h1>
|
||||
`,
|
||||
ts: `
|
||||
<script lang="ts">
|
||||
export let name: string
|
||||
<\/script>
|
||||
|
||||
<h1>Hello {name}!</h1>
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from 'vitest-browser-svelte'
|
||||
import HelloWorld from './HelloWorld.svelte'
|
||||
|
||||
test('renders name', async () => {
|
||||
const { getByText } = render(HelloWorld, { name: 'Vitest' })
|
||||
await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const markoExample = {
|
||||
name: "HelloWorld.marko",
|
||||
js: `
|
||||
class {
|
||||
onCreate() {
|
||||
this.state = { name: null }
|
||||
}
|
||||
}
|
||||
|
||||
<h1>Hello \${state.name}!</h1>
|
||||
`,
|
||||
ts: `
|
||||
export interface Input {
|
||||
name: string
|
||||
}
|
||||
|
||||
<h1>Hello \${input.name}!</h1>
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from '@marko/testing-library'
|
||||
import HelloWorld from './HelloWorld.svelte'
|
||||
|
||||
test('renders name', async () => {
|
||||
const { getByText } = await render(HelloWorld, { name: 'Vitest' })
|
||||
const element = getByText('Hello Vitest!')
|
||||
expect(element).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const litExample = {
|
||||
name: "HelloWorld.js",
|
||||
js: `
|
||||
import { html, LitElement } from 'lit'
|
||||
|
||||
export class HelloWorld extends LitElement {
|
||||
static properties = {
|
||||
name: { type: String },
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.name = 'World'
|
||||
}
|
||||
|
||||
render() {
|
||||
return html\`<h1>Hello \${this.name}!</h1>\`
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hello-world', HelloWorld)
|
||||
`,
|
||||
ts: `
|
||||
import { html, LitElement } from 'lit'
|
||||
import { customElement, property } from 'lit/decorators.js'
|
||||
|
||||
@customElement('hello-world')
|
||||
export class HelloWorld extends LitElement {
|
||||
@property({ type: String })
|
||||
name = 'World'
|
||||
|
||||
render() {
|
||||
return html\`<h1>Hello \${this.name}!</h1>\`
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'hello-world': HelloWorld
|
||||
}
|
||||
}
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from 'vitest-browser-lit'
|
||||
import { html } from 'lit'
|
||||
import './HelloWorld.js'
|
||||
|
||||
test('renders name', async () => {
|
||||
const screen = render(html\`<hello-world name="Vitest"></hello-world>\`)
|
||||
const element = screen.getByText('Hello Vitest!')
|
||||
await expect.element(element).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const qwikExample = {
|
||||
name: "HelloWorld.jsx",
|
||||
js: `
|
||||
import { component$ } from '@builder.io/qwik'
|
||||
|
||||
export default component$(({ name }) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello {name}!</h1>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
`,
|
||||
ts: `
|
||||
import { component$ } from '@builder.io/qwik'
|
||||
|
||||
export default component$(({ name }: { name: string }) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello {name}!</h1>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from 'vitest-browser-qwik'
|
||||
import HelloWorld from './HelloWorld.tsx'
|
||||
|
||||
test('renders name', async () => {
|
||||
const { getByText } = render(<HelloWorld name="Vitest" />)
|
||||
await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const preactExample = {
|
||||
name: "HelloWorld.jsx",
|
||||
js: `
|
||||
export default function HelloWorld({ name }) {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello {name}!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`,
|
||||
ts: `
|
||||
export default function HelloWorld({ name }: { name: string }) {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello {name}!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { render } from 'vitest-browser-preact'
|
||||
import HelloWorld from './HelloWorld.<EXT>x'
|
||||
|
||||
test('renders name', async () => {
|
||||
const { getByText } = render(<HelloWorld name="Vitest" />)
|
||||
await expect.element(getByText('Hello Vitest!')).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
const vanillaExample = {
|
||||
name: "HelloWorld.js",
|
||||
js: `
|
||||
export default function HelloWorld({ name }) {
|
||||
const parent = document.createElement('div')
|
||||
|
||||
const h1 = document.createElement('h1')
|
||||
h1.textContent = 'Hello ' + name + '!'
|
||||
parent.appendChild(h1)
|
||||
|
||||
return parent
|
||||
}
|
||||
`,
|
||||
ts: `
|
||||
export default function HelloWorld({ name }: { name: string }): HTMLDivElement {
|
||||
const parent = document.createElement('div')
|
||||
|
||||
const h1 = document.createElement('h1')
|
||||
h1.textContent = 'Hello ' + name + '!'
|
||||
parent.appendChild(h1)
|
||||
|
||||
return parent
|
||||
}
|
||||
`,
|
||||
test: `
|
||||
import { expect, test } from 'vitest'
|
||||
import { getByText } from '@testing-library/dom'
|
||||
import HelloWorld from './HelloWorld.js'
|
||||
|
||||
test('renders name', () => {
|
||||
const parent = HelloWorld({ name: 'Vitest' })
|
||||
document.body.appendChild(parent)
|
||||
|
||||
const element = getByText(parent, 'Hello Vitest!')
|
||||
expect(element).toBeInTheDocument()
|
||||
})
|
||||
`
|
||||
};
|
||||
function getExampleTest(framework) {
|
||||
switch (framework) {
|
||||
case "solid": return {
|
||||
...jsxExample,
|
||||
test: jsxExample.test.replace("@testing-library/jsx", `@testing-library/${framework}`)
|
||||
};
|
||||
case "preact": return preactExample;
|
||||
case "react": return {
|
||||
...jsxExample,
|
||||
test: jsxExample.test.replace("@testing-library/jsx", `vitest-browser-${framework}`)
|
||||
};
|
||||
case "vue": return vueExample;
|
||||
case "svelte": return svelteExample;
|
||||
case "lit": return litExample;
|
||||
case "marko": return markoExample;
|
||||
case "qwik": return qwikExample;
|
||||
default: return vanillaExample;
|
||||
}
|
||||
}
|
||||
async function generateExampleFiles(framework, lang) {
|
||||
const example = getExampleTest(framework);
|
||||
let fileName = example.name;
|
||||
const folder = resolve(process.cwd(), "vitest-example");
|
||||
const fileContent = example[lang];
|
||||
if (!existsSync(folder)) await mkdir(folder, { recursive: true });
|
||||
const isJSX = fileName.endsWith(".jsx");
|
||||
if (isJSX && lang === "ts") fileName = fileName.replace(".jsx", ".tsx");
|
||||
else if (fileName.endsWith(".js") && lang === "ts") fileName = fileName.replace(".js", ".ts");
|
||||
example.test = example.test.replace("<EXT>", lang);
|
||||
const filePath = resolve(folder, fileName);
|
||||
const testPath = resolve(folder, `HelloWorld.test.${isJSX ? `${lang}x` : lang}`);
|
||||
writeFileSync(filePath, fileContent.trimStart(), "utf-8");
|
||||
writeFileSync(testPath, example.test.trimStart(), "utf-8");
|
||||
return testPath;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
const log = console.log;
|
||||
function getProviderOptions() {
|
||||
return Object.entries({
|
||||
playwright: "Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev",
|
||||
webdriverio: "WebdriverIO uses WebDriver protocol. Read more: https://webdriver.io",
|
||||
preview: "Preview is useful to quickly run your tests in the browser, but not suitable for CI."
|
||||
}).map(([provider, description]) => {
|
||||
return {
|
||||
title: provider,
|
||||
description,
|
||||
value: provider
|
||||
};
|
||||
});
|
||||
}
|
||||
function getBrowserNames(provider) {
|
||||
switch (provider) {
|
||||
case "webdriverio": return [
|
||||
"chrome",
|
||||
"firefox",
|
||||
"edge",
|
||||
"safari"
|
||||
];
|
||||
case "playwright": return [
|
||||
"chromium",
|
||||
"firefox",
|
||||
"webkit"
|
||||
];
|
||||
case "preview": return [
|
||||
"chrome",
|
||||
"firefox",
|
||||
"safari"
|
||||
];
|
||||
}
|
||||
}
|
||||
function getFramework() {
|
||||
return [
|
||||
{
|
||||
title: "vanilla",
|
||||
value: "vanilla",
|
||||
description: "No framework, just plain JavaScript or TypeScript."
|
||||
},
|
||||
{
|
||||
title: "vue",
|
||||
value: "vue",
|
||||
description: "\"The Progressive JavaScript Framework\""
|
||||
},
|
||||
{
|
||||
title: "svelte",
|
||||
value: "svelte",
|
||||
description: "\"Svelte: cybernetically enhanced web apps\""
|
||||
},
|
||||
{
|
||||
title: "react",
|
||||
value: "react",
|
||||
description: "\"The library for web and native user interfaces\""
|
||||
},
|
||||
{
|
||||
title: "lit",
|
||||
value: "lit",
|
||||
description: "\"A simple library for building fast, lightweight web components.\""
|
||||
},
|
||||
{
|
||||
title: "preact",
|
||||
value: "preact",
|
||||
description: "\"Fast 3kB alternative to React with the same modern API\""
|
||||
},
|
||||
{
|
||||
title: "solid",
|
||||
value: "solid",
|
||||
description: "\"Simple and performant reactivity for building user interfaces\""
|
||||
},
|
||||
{
|
||||
title: "marko",
|
||||
value: "marko",
|
||||
description: "\"A declarative, HTML-based language that makes building web apps fun\""
|
||||
},
|
||||
{
|
||||
title: "qwik",
|
||||
value: "qwik",
|
||||
description: "\"Instantly interactive web apps at scale\""
|
||||
}
|
||||
];
|
||||
}
|
||||
function getFrameworkTestPackage(framework) {
|
||||
switch (framework) {
|
||||
case "vanilla": return null;
|
||||
case "vue": return "vitest-browser-vue";
|
||||
case "svelte": return "vitest-browser-svelte";
|
||||
case "react": return "vitest-browser-react";
|
||||
case "lit": return "vitest-browser-lit";
|
||||
case "preact": return "vitest-browser-preact";
|
||||
case "solid": return "@solidjs/testing-library";
|
||||
case "marko": return "@marko/testing-library";
|
||||
case "qwik": return "vitest-browser-qwik";
|
||||
}
|
||||
throw new Error(`Unsupported framework: ${framework}`);
|
||||
}
|
||||
function getFrameworkPluginPackage(framework) {
|
||||
switch (framework) {
|
||||
case "vue": return "@vitejs/plugin-vue";
|
||||
case "svelte": return "@sveltejs/vite-plugin-svelte";
|
||||
case "react": return "@vitejs/plugin-react";
|
||||
case "preact": return "@preact/preset-vite";
|
||||
case "solid": return "vite-plugin-solid";
|
||||
case "marko": return "@marko/vite";
|
||||
case "qwik": return "@builder.io/qwik/optimizer";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getLanguageOptions() {
|
||||
return [{
|
||||
title: "TypeScript",
|
||||
description: "Use TypeScript.",
|
||||
value: "ts"
|
||||
}, {
|
||||
title: "JavaScript",
|
||||
description: "Use plain JavaScript.",
|
||||
value: "js"
|
||||
}];
|
||||
}
|
||||
async function installPackages(pkgManager, packages) {
|
||||
if (!packages.length) {
|
||||
log(c.green("✔"), c.bold("All packages are already installed."));
|
||||
return;
|
||||
}
|
||||
log(c.cyan("◼"), c.bold("Installing packages..."));
|
||||
log(c.cyan("◼"), packages.join(", "));
|
||||
log();
|
||||
await installPackage(packages, {
|
||||
dev: true,
|
||||
packageManager: pkgManager ?? void 0
|
||||
});
|
||||
}
|
||||
function readPkgJson(path) {
|
||||
if (!existsSync(path)) return null;
|
||||
const content = readFileSync(path, "utf-8");
|
||||
return JSON.parse(content);
|
||||
}
|
||||
function getPossibleDefaults(dependencies) {
|
||||
return {
|
||||
lang: "ts",
|
||||
provider: getPossibleProvider(dependencies),
|
||||
framework: getPossibleFramework(dependencies)
|
||||
};
|
||||
}
|
||||
function getPossibleFramework(dependencies) {
|
||||
if (dependencies.vue || dependencies["vue-tsc"] || dependencies["@vue/reactivity"]) return "vue";
|
||||
if (dependencies.react || dependencies["react-dom"]) return "react";
|
||||
if (dependencies.svelte || dependencies["@sveltejs/kit"]) return "svelte";
|
||||
if (dependencies.lit || dependencies["lit-html"]) return "lit";
|
||||
if (dependencies.preact) return "preact";
|
||||
if (dependencies["solid-js"] || dependencies["@solidjs/start"]) return "solid";
|
||||
if (dependencies.marko) return "marko";
|
||||
if (dependencies["@builder.io/qwik"] || dependencies["@qwik.dev/core"]) return "qwik";
|
||||
return "vanilla";
|
||||
}
|
||||
function getPossibleProvider(dependencies) {
|
||||
if (dependencies.webdriverio || dependencies["@wdio/cli"] || dependencies["@wdio/config"]) return "webdriverio";
|
||||
// playwright is the default recommendation
|
||||
return "playwright";
|
||||
}
|
||||
function getProviderDocsLink(provider) {
|
||||
switch (provider) {
|
||||
case "playwright": return "https://vitest.dev/config/browser/playwright";
|
||||
case "webdriverio": return "https://vitest.dev/config/browser/webdriverio";
|
||||
}
|
||||
}
|
||||
function sort(choices, value) {
|
||||
const index = choices.findIndex((i) => i.value === value);
|
||||
if (index === -1) return choices;
|
||||
return [choices.splice(index, 1)[0], ...choices];
|
||||
}
|
||||
function fail() {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
function getFrameworkImportInfo(framework) {
|
||||
switch (framework) {
|
||||
case "svelte": return {
|
||||
importName: "svelte",
|
||||
isNamedExport: true
|
||||
};
|
||||
case "qwik": return {
|
||||
importName: "qwikVite",
|
||||
isNamedExport: true
|
||||
};
|
||||
default: return {
|
||||
importName: framework,
|
||||
isNamedExport: false
|
||||
};
|
||||
}
|
||||
}
|
||||
async function generateFrameworkConfigFile(options) {
|
||||
const { importName, isNamedExport } = getFrameworkImportInfo(options.framework);
|
||||
const frameworkImport = isNamedExport ? `import { ${importName} } from '${options.frameworkPlugin}'` : `import ${importName} from '${options.frameworkPlugin}'`;
|
||||
const configContent = [
|
||||
`import { defineConfig } from 'vitest/config'`,
|
||||
`import { ${options.provider} } from '@vitest/browser-${options.provider}'`,
|
||||
options.frameworkPlugin ? frameworkImport : null,
|
||||
``,
|
||||
"export default defineConfig({",
|
||||
options.frameworkPlugin ? ` plugins: [${importName}()],` : null,
|
||||
` test: {`,
|
||||
` browser: {`,
|
||||
` enabled: true,`,
|
||||
` provider: ${options.provider}(),`,
|
||||
options.provider !== "preview" && ` // ${getProviderDocsLink(options.provider)}`,
|
||||
` instances: [`,
|
||||
...options.browsers.map((browser) => ` { browser: '${browser}' },`),
|
||||
` ],`,
|
||||
` },`,
|
||||
` },`,
|
||||
`})`,
|
||||
""
|
||||
].filter((t) => typeof t === "string").join("\n");
|
||||
await writeFile(options.configPath, configContent);
|
||||
}
|
||||
async function updatePkgJsonScripts(pkgJsonPath, vitestScript) {
|
||||
if (!existsSync(pkgJsonPath)) {
|
||||
const pkg = { scripts: { "test:browser": vitestScript } };
|
||||
await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8");
|
||||
} else {
|
||||
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
||||
pkg.scripts = pkg.scripts || {};
|
||||
pkg.scripts["test:browser"] = vitestScript;
|
||||
await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8");
|
||||
}
|
||||
log(c.green("✔"), "Added \"test:browser\" script to your package.json.");
|
||||
}
|
||||
function getRunScript(pkgManager) {
|
||||
switch (pkgManager) {
|
||||
case "yarn@berry":
|
||||
case "yarn": return "yarn test:browser";
|
||||
case "pnpm@6":
|
||||
case "pnpm": return "pnpm test:browser";
|
||||
case "bun": return "bun test:browser";
|
||||
default: return "npm run test:browser";
|
||||
}
|
||||
}
|
||||
function getPlaywrightRunArgs(pkgManager) {
|
||||
switch (pkgManager) {
|
||||
case "yarn@berry":
|
||||
case "yarn": return ["yarn", "exec"];
|
||||
case "pnpm@6":
|
||||
case "pnpm": return ["pnpx"];
|
||||
case "bun": return ["bunx"];
|
||||
default: return ["npx"];
|
||||
}
|
||||
}
|
||||
async function create() {
|
||||
log(c.cyan("◼"), "This utility will help you set up a browser testing environment.\n");
|
||||
const pkgJsonPath = resolve(process.cwd(), "package.json");
|
||||
const pkg = readPkgJson(pkgJsonPath) || {};
|
||||
const dependencies = {
|
||||
...pkg.dependencies,
|
||||
...pkg.devDependencies
|
||||
};
|
||||
const defaults = getPossibleDefaults(dependencies);
|
||||
const { lang } = await prompt({
|
||||
type: "select",
|
||||
name: "lang",
|
||||
message: "Choose a language for your tests",
|
||||
choices: sort(getLanguageOptions(), defaults?.lang)
|
||||
});
|
||||
if (!lang) return fail();
|
||||
const { provider } = await prompt({
|
||||
type: "select",
|
||||
name: "provider",
|
||||
message: "Choose a browser provider. Vitest will use its API to control the testing environment",
|
||||
choices: sort(getProviderOptions(), defaults?.provider)
|
||||
});
|
||||
if (!provider) return fail();
|
||||
const { browsers } = await prompt({
|
||||
type: "multiselect",
|
||||
name: "browsers",
|
||||
message: "Choose a browser",
|
||||
choices: getBrowserNames(provider).map((browser) => ({
|
||||
title: browser,
|
||||
value: browser
|
||||
}))
|
||||
});
|
||||
if (!provider) return fail();
|
||||
const { framework } = await prompt({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: "Choose your framework",
|
||||
choices: sort(getFramework(), defaults?.framework)
|
||||
});
|
||||
if (!framework) return fail();
|
||||
let installPlaywright = false;
|
||||
if (provider === "playwright") ({installPlaywright} = await prompt({
|
||||
type: "confirm",
|
||||
name: "installPlaywright",
|
||||
message: `Install Playwright browsers (can be done manually via 'pnpm exec playwright install')?`
|
||||
}));
|
||||
if (installPlaywright == null) return fail();
|
||||
const dependenciesToInstall = [`@vitest/browser-${provider}`];
|
||||
const frameworkPackage = getFrameworkTestPackage(framework);
|
||||
if (frameworkPackage) dependenciesToInstall.push(frameworkPackage);
|
||||
const frameworkPlugin = getFrameworkPluginPackage(framework);
|
||||
if (frameworkPlugin) dependenciesToInstall.push(frameworkPlugin);
|
||||
const pkgManager = await detectPackageManager();
|
||||
log();
|
||||
await installPackages(pkgManager, dependenciesToInstall.filter((pkg) => !dependencies[pkg]));
|
||||
const rootConfig = any(configFiles, { cwd: process.cwd() });
|
||||
let scriptCommand = "vitest";
|
||||
log();
|
||||
if (rootConfig) {
|
||||
const configPath = resolve(dirname(rootConfig), `vitest.browser.config.${lang}`);
|
||||
scriptCommand = `vitest --config=${relative(process.cwd(), configPath)}`;
|
||||
await generateFrameworkConfigFile({
|
||||
configPath,
|
||||
framework,
|
||||
frameworkPlugin,
|
||||
provider,
|
||||
browsers
|
||||
});
|
||||
log(
|
||||
c.green("✔"),
|
||||
"Created a new config file for browser tests:",
|
||||
c.bold(relative(process.cwd(), configPath)),
|
||||
// TODO: Can we modify the config ourselves?
|
||||
"\nSince you already have a Vitest config file, it is recommended to copy the contents of the new file ",
|
||||
"into your existing config located at ",
|
||||
c.bold(relative(process.cwd(), rootConfig))
|
||||
);
|
||||
} else {
|
||||
const configPath = resolve(process.cwd(), `vitest.config.${lang}`);
|
||||
await generateFrameworkConfigFile({
|
||||
configPath,
|
||||
framework,
|
||||
frameworkPlugin,
|
||||
provider,
|
||||
browsers
|
||||
});
|
||||
log(c.green("✔"), "Created a config file for browser tests:", c.bold(relative(process.cwd(), configPath)));
|
||||
}
|
||||
log();
|
||||
await updatePkgJsonScripts(pkgJsonPath, scriptCommand);
|
||||
if (installPlaywright) {
|
||||
log();
|
||||
const [command, ...args] = getPlaywrightRunArgs(pkgManager);
|
||||
const allArgs = [
|
||||
...args,
|
||||
"playwright",
|
||||
"install",
|
||||
"--with-deps"
|
||||
];
|
||||
log(c.cyan("◼"), `Installing Playwright dependencies with \`${c.bold(command)} ${c.bold(allArgs.join(" "))}\`...`);
|
||||
log();
|
||||
await x(command, allArgs, { nodeOptions: { stdio: [
|
||||
"pipe",
|
||||
"inherit",
|
||||
"inherit"
|
||||
] } });
|
||||
}
|
||||
log();
|
||||
const exampleTestFile = await generateExampleFiles(framework, lang);
|
||||
log(c.green("✔"), "Created example test file in", c.bold(relative(process.cwd(), exampleTestFile)));
|
||||
log(c.dim(" You can safely delete this file once you have written your own tests."));
|
||||
log();
|
||||
log(c.cyan("◼"), "All done! Run your tests with", c.bold(getRunScript(pkgManager)));
|
||||
}
|
||||
|
||||
export { create };
|
||||
@@ -0,0 +1,195 @@
|
||||
import { chai } from '@vitest/expect';
|
||||
import { createHook } from 'node:async_hooks';
|
||||
import { l as loadDiffConfig, a as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.DYx3LtFI.js';
|
||||
import { r as rpc } from './rpc.MzXet3jl.js';
|
||||
import { g as getWorkerState } from './utils.BX5Fg8C4.js';
|
||||
import { T as TestRunner, N as NodeBenchmarkRunner } from './test.DNmyFkvJ.js';
|
||||
|
||||
function setupChaiConfig(config) {
|
||||
Object.assign(chai.config, config);
|
||||
}
|
||||
|
||||
async function resolveSnapshotEnvironment(config, moduleRunner) {
|
||||
if (!config.snapshotEnvironment) {
|
||||
const { VitestNodeSnapshotEnvironment } = await import('./node.COQbm6gK.js');
|
||||
return new VitestNodeSnapshotEnvironment();
|
||||
}
|
||||
const mod = await moduleRunner.import(config.snapshotEnvironment);
|
||||
if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`");
|
||||
return mod.default;
|
||||
}
|
||||
|
||||
const IGNORED_TYPES = new Set([
|
||||
"DNSCHANNEL",
|
||||
"ELDHISTOGRAM",
|
||||
"PerformanceObserver",
|
||||
"RANDOMBYTESREQUEST",
|
||||
"SIGNREQUEST",
|
||||
"STREAM_END_OF_STREAM",
|
||||
"TCPWRAP",
|
||||
"TIMERWRAP",
|
||||
"TLSWRAP",
|
||||
"ZLIB"
|
||||
]);
|
||||
function detectAsyncLeaks(testFile, projectName) {
|
||||
const resources = /* @__PURE__ */ new Map();
|
||||
const hook = createHook({
|
||||
init(asyncId, type, triggerAsyncId, resource) {
|
||||
if (IGNORED_TYPES.has(type)) return;
|
||||
let stack = "";
|
||||
const limit = Error.stackTraceLimit;
|
||||
// VitestModuleEvaluator's async wrapper of node:vm causes out-of-bound stack traces, simply skip it.
|
||||
// Crash fixed in https://github.com/vitejs/vite/pull/21585
|
||||
try {
|
||||
Error.stackTraceLimit = 100;
|
||||
stack = (/* @__PURE__ */ new Error("VITEST_DETECT_ASYNC_LEAKS")).stack || "";
|
||||
} catch {
|
||||
return;
|
||||
} finally {
|
||||
Error.stackTraceLimit = limit;
|
||||
}
|
||||
if (!stack.includes(testFile)) {
|
||||
const trigger = resources.get(triggerAsyncId);
|
||||
if (!trigger) return;
|
||||
stack = trigger.stack;
|
||||
}
|
||||
let isActive = isActiveDefault;
|
||||
if ("hasRef" in resource) {
|
||||
const ref = new WeakRef(resource);
|
||||
isActive = () => ref.deref()?.hasRef() ?? false;
|
||||
}
|
||||
resources.set(asyncId, {
|
||||
type,
|
||||
stack,
|
||||
projectName,
|
||||
filename: testFile,
|
||||
isActive
|
||||
});
|
||||
},
|
||||
destroy(asyncId) {
|
||||
if (resources.get(asyncId)?.type !== "PROMISE") resources.delete(asyncId);
|
||||
},
|
||||
promiseResolve(asyncId) {
|
||||
resources.delete(asyncId);
|
||||
}
|
||||
});
|
||||
hook.enable();
|
||||
return async function collect() {
|
||||
await Promise.resolve(setImmediate);
|
||||
hook.disable();
|
||||
const leaks = [];
|
||||
for (const resource of resources.values()) if (resource.isActive()) leaks.push({
|
||||
stack: resource.stack,
|
||||
type: resource.type,
|
||||
filename: resource.filename,
|
||||
projectName: resource.projectName
|
||||
});
|
||||
resources.clear();
|
||||
return leaks;
|
||||
};
|
||||
}
|
||||
function isActiveDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async function getTestRunnerConstructor(config, moduleRunner) {
|
||||
if (!config.runner) return config.mode === "test" ? TestRunner : NodeBenchmarkRunner;
|
||||
const mod = await moduleRunner.import(config.runner);
|
||||
if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`);
|
||||
return mod.default;
|
||||
}
|
||||
async function resolveTestRunner(config, moduleRunner, traces) {
|
||||
const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config);
|
||||
// inject private executor to every runner
|
||||
Object.defineProperty(testRunner, "moduleRunner", {
|
||||
value: moduleRunner,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
});
|
||||
if (!testRunner.config) testRunner.config = config;
|
||||
if (!testRunner.importFile) throw new Error("Runner must implement \"importFile\" method.");
|
||||
if ("__setTraces" in testRunner) testRunner.__setTraces(traces);
|
||||
const [diffOptions] = await Promise.all([loadDiffConfig(config, moduleRunner), loadSnapshotSerializers(config, moduleRunner)]);
|
||||
testRunner.config.diffOptions = diffOptions;
|
||||
// patch some methods, so custom runners don't need to call RPC
|
||||
const originalOnTaskUpdate = testRunner.onTaskUpdate;
|
||||
testRunner.onTaskUpdate = async (task, events) => {
|
||||
const p = rpc().onTaskUpdate(task, events);
|
||||
await originalOnTaskUpdate?.call(testRunner, task, events);
|
||||
return p;
|
||||
};
|
||||
// patch some methods, so custom runners don't need to call RPC
|
||||
const originalOnTestAnnotate = testRunner.onTestAnnotate;
|
||||
testRunner.onTestAnnotate = async (test, annotation) => {
|
||||
const p = rpc().onTaskArtifactRecord(test.id, {
|
||||
type: "internal:annotation",
|
||||
location: annotation.location,
|
||||
annotation
|
||||
});
|
||||
const overriddenResult = await originalOnTestAnnotate?.call(testRunner, test, annotation);
|
||||
const vitestResult = await p;
|
||||
return overriddenResult || vitestResult.annotation;
|
||||
};
|
||||
const originalOnTestArtifactRecord = testRunner.onTestArtifactRecord;
|
||||
testRunner.onTestArtifactRecord = async (test, artifact) => {
|
||||
const p = rpc().onTaskArtifactRecord(test.id, artifact);
|
||||
const overriddenResult = await originalOnTestArtifactRecord?.call(testRunner, test, artifact);
|
||||
const vitestResult = await p;
|
||||
return overriddenResult || vitestResult;
|
||||
};
|
||||
const originalOnCollectStart = testRunner.onCollectStart;
|
||||
testRunner.onCollectStart = async (file) => {
|
||||
await rpc().onQueued(file);
|
||||
await originalOnCollectStart?.call(testRunner, file);
|
||||
};
|
||||
const originalOnCollected = testRunner.onCollected;
|
||||
testRunner.onCollected = async (files) => {
|
||||
const state = getWorkerState();
|
||||
files.forEach((file) => {
|
||||
file.prepareDuration = state.durations.prepare;
|
||||
file.environmentLoad = state.durations.environment;
|
||||
// should be collected only for a single test file in a batch
|
||||
state.durations.prepare = 0;
|
||||
state.durations.environment = 0;
|
||||
});
|
||||
// Strip function conditions from retry config before sending via RPC
|
||||
// Functions cannot be cloned by structured clone algorithm
|
||||
const sanitizeRetryConditions = (task) => {
|
||||
if (task.retry && typeof task.retry === "object" && typeof task.retry.condition === "function")
|
||||
// Remove function condition - it can't be serialized
|
||||
task.retry = {
|
||||
...task.retry,
|
||||
condition: void 0
|
||||
};
|
||||
if (task.tasks) task.tasks.forEach(sanitizeRetryConditions);
|
||||
};
|
||||
files.forEach(sanitizeRetryConditions);
|
||||
rpc().onCollected(files);
|
||||
await originalOnCollected?.call(testRunner, files);
|
||||
};
|
||||
const originalOnAfterRun = testRunner.onAfterRunFiles;
|
||||
testRunner.onAfterRunFiles = async (files) => {
|
||||
const state = getWorkerState();
|
||||
const coverage = await takeCoverageInsideWorker(config.coverage, moduleRunner);
|
||||
if (coverage) rpc().onAfterSuiteRun({
|
||||
coverage,
|
||||
testFiles: files.map((file) => file.name).sort(),
|
||||
environment: state.environment.viteEnvironment || state.environment.name,
|
||||
projectName: state.ctx.projectName
|
||||
});
|
||||
await originalOnAfterRun?.call(testRunner, files);
|
||||
};
|
||||
const originalOnAfterRunTask = testRunner.onAfterRunTask;
|
||||
testRunner.onAfterRunTask = async (test) => {
|
||||
if (config.bail && test.result?.state === "fail") {
|
||||
if (1 + await rpc().getCountOfFailedTests() >= config.bail) {
|
||||
rpc().onCancel("test-failure");
|
||||
testRunner.cancel?.("test-failure");
|
||||
}
|
||||
}
|
||||
await originalOnAfterRunTask?.call(testRunner, test);
|
||||
};
|
||||
return testRunner;
|
||||
}
|
||||
|
||||
export { resolveSnapshotEnvironment as a, detectAsyncLeaks as d, resolveTestRunner as r, setupChaiConfig as s };
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"assert-valid-pattern.js","sourceRoot":"","sources":["../../src/assert-valid-pattern.ts"],"names":[],"mappings":";;;AAAA,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAE,CAAA;AAC7B,MAAM,kBAAkB,GAA+B,CAC5D,OAAgB,EACW,EAAE;IAC7B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC,CAAA;AAVY,QAAA,kBAAkB,sBAU9B","sourcesContent":["const MAX_PATTERN_LENGTH = 1024 * 64\nexport const assertValidPattern: (pattern: unknown) => void = (\n pattern: unknown,\n): asserts pattern is string => {\n if (typeof pattern !== 'string') {\n throw new TypeError('invalid pattern')\n }\n\n if (pattern.length > MAX_PATTERN_LENGTH) {\n throw new TypeError('pattern is too long')\n }\n}\n"]}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { ConnectionOptions } from "tls";
|
||||
import { ConnectionConfig } from "..";
|
||||
|
||||
interface ConnectionParametersConfig extends
|
||||
Pick<
|
||||
ConnectionConfig,
|
||||
| "user"
|
||||
| "database"
|
||||
| "password"
|
||||
| "port"
|
||||
| "host"
|
||||
| "options"
|
||||
| "ssl"
|
||||
| "application_name"
|
||||
| "statement_timeout"
|
||||
| "idle_in_transaction_session_timeout"
|
||||
| "query_timeout"
|
||||
>
|
||||
{
|
||||
binary?: unknown;
|
||||
client_encoding?: unknown;
|
||||
replication?: unknown;
|
||||
isDomainSocket?: unknown;
|
||||
fallback_application_name?: unknown;
|
||||
lock_timeout?: unknown;
|
||||
connect_timeout?: unknown;
|
||||
keepalives?: unknown;
|
||||
keepalives_idle?: unknown;
|
||||
}
|
||||
|
||||
export = ConnectionParameters;
|
||||
declare class ConnectionParameters implements ConnectionParametersConfig {
|
||||
user?: string | undefined;
|
||||
database?: string | undefined;
|
||||
password?: string | (() => string | Promise<string>) | undefined;
|
||||
port?: number | undefined;
|
||||
host?: string | undefined;
|
||||
statement_timeout?: false | number | undefined;
|
||||
ssl?: boolean | ConnectionOptions | undefined;
|
||||
query_timeout?: number | undefined;
|
||||
idle_in_transaction_session_timeout?: number | undefined;
|
||||
application_name?: string | undefined;
|
||||
options?: string | undefined;
|
||||
|
||||
binary?: unknown;
|
||||
client_encoding?: unknown;
|
||||
replication?: unknown;
|
||||
isDomainSocket?: unknown;
|
||||
fallback_application_name?: unknown;
|
||||
lock_timeout?: unknown;
|
||||
connect_timeout?: unknown;
|
||||
keepalives?: unknown;
|
||||
keepalives_idle?: unknown;
|
||||
|
||||
constructor(config?: string | ConnectionParametersConfig);
|
||||
|
||||
getLibpqConnectionString<TResult>(cb: (err: Error | null, params: string | null) => TResult): TResult;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "type-check",
|
||||
"version": "0.4.0",
|
||||
"author": "George Zahariev <z@georgezahariev.com>",
|
||||
"description": "type-check allows you to check the types of JavaScript values at runtime with a Haskell like type syntax.",
|
||||
"homepage": "https://github.com/gkz/type-check",
|
||||
"keywords": [
|
||||
"type",
|
||||
"check",
|
||||
"checking",
|
||||
"library"
|
||||
],
|
||||
"files": [
|
||||
"lib",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"main": "./lib/",
|
||||
"bugs": "https://github.com/gkz/type-check/issues",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/gkz/type-check.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"dependencies": {
|
||||
"prelude-ls": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"livescript": "^1.6.0",
|
||||
"mocha": "^7.1.1",
|
||||
"browserify": "^16.5.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export declare function objectForEachKey<T extends Record<string, unknown>>(obj: T, callback: (key: keyof T) => void): void;
|
||||
export declare function objectMapKey<T extends Record<string, unknown>, Return>(obj: T, callback: (key: keyof T) => Return): Return[];
|
||||
export declare function objectReduceKey<T extends Record<string, unknown>, Accumulator>(obj: T, callback: (acc: Accumulator, key: keyof T) => Accumulator, initial: Accumulator): Accumulator;
|
||||
@@ -0,0 +1,11 @@
|
||||
import pino from '../../..'
|
||||
|
||||
const transport = pino.transport({
|
||||
target: 'pino/file'
|
||||
})
|
||||
const logger = pino(transport)
|
||||
|
||||
transport.on('ready', function () {
|
||||
logger.info('Hello')
|
||||
process.exit(0)
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
|
||||
function _iterable_to_array_limit(arr, i) {
|
||||
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
||||
|
||||
if (_i == null) return;
|
||||
|
||||
var _arr = [];
|
||||
var _n = true;
|
||||
var _d = false;
|
||||
var _s, _e;
|
||||
|
||||
try {
|
||||
for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
|
||||
_arr.push(_s.value);
|
||||
if (i && _arr.length === i) break;
|
||||
}
|
||||
} catch (err) {
|
||||
_d = true;
|
||||
_e = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_n && _i["return"] != null) _i["return"]();
|
||||
} finally {
|
||||
if (_d) throw _e;
|
||||
}
|
||||
}
|
||||
|
||||
return _arr;
|
||||
}
|
||||
exports._ = _iterable_to_array_limit;
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createMockInstance } from '@vitest/spy';
|
||||
import { M as ModuleMocker, r as rpc, c as createCompilerHints, h as hot } from './chunk-mocker.js';
|
||||
import './chunk-helpers.js';
|
||||
import './index.js';
|
||||
import './chunk-registry.js';
|
||||
import './chunk-pathe.M-eThtNZ.js';
|
||||
|
||||
function registerModuleMocker(interceptor) {
|
||||
const mocker = new ModuleMocker(interceptor(__VITEST_GLOBAL_THIS_ACCESSOR__), {
|
||||
resolveId(id, importer) {
|
||||
return rpc("vitest:mocks:resolveId", {
|
||||
id,
|
||||
importer
|
||||
});
|
||||
},
|
||||
resolveMock(id, importer, options) {
|
||||
return rpc("vitest:mocks:resolveMock", {
|
||||
id,
|
||||
importer,
|
||||
options
|
||||
});
|
||||
},
|
||||
async invalidate(ids) {
|
||||
return rpc("vitest:mocks:invalidate", { ids });
|
||||
}
|
||||
}, createMockInstance, { root: __VITEST_MOCKER_ROOT__ });
|
||||
globalThis[__VITEST_GLOBAL_THIS_ACCESSOR__] = mocker;
|
||||
registerNativeFactoryResolver(mocker);
|
||||
return createCompilerHints({ globalThisKey: __VITEST_GLOBAL_THIS_ACCESSOR__ });
|
||||
}
|
||||
function registerNativeFactoryResolver(mocker) {
|
||||
hot.on("vitest:interceptor:resolve", async (url) => {
|
||||
const exports$1 = await mocker.resolveFactoryModule(url);
|
||||
const keys = Object.keys(exports$1);
|
||||
hot.send("vitest:interceptor:resolved", {
|
||||
url,
|
||||
keys
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export { registerModuleMocker, registerNativeFactoryResolver };
|
||||
@@ -0,0 +1,124 @@
|
||||
import { fsCallbackNames } from "../fs.js";
|
||||
import { isSpawnOptions, resolveExePath, } from "../options.js";
|
||||
import { SyncRpcChannel } from "../syncChannel.js";
|
||||
import { combineTimingInfo, disabledTimingInfo, TimingCollector, } from "../timing.js";
|
||||
export class Client {
|
||||
channel;
|
||||
encoder = new TextEncoder();
|
||||
timing;
|
||||
constructor(options) {
|
||||
if (!isSpawnOptions(options)) {
|
||||
throw new Error("Socket connections are not yet supported in the sync client");
|
||||
}
|
||||
const cwd = options.cwd ?? process.cwd();
|
||||
const args = [
|
||||
"--api",
|
||||
"--cwd",
|
||||
cwd,
|
||||
];
|
||||
// Enable virtual FS callbacks for each provided FS function
|
||||
const enabledCallbacks = [];
|
||||
if (options.fs) {
|
||||
for (const name of fsCallbackNames) {
|
||||
if (options.fs[name]) {
|
||||
enabledCallbacks.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enabledCallbacks.length > 0) {
|
||||
args.push(`--callbacks=${enabledCallbacks.join(",")}`);
|
||||
}
|
||||
const collectTiming = options.collectTiming ?? false;
|
||||
if (collectTiming) {
|
||||
args.push("--timing");
|
||||
this.timing = new TimingCollector();
|
||||
}
|
||||
const channel = new SyncRpcChannel(resolveExePath(options), args, collectTiming);
|
||||
this.channel = channel;
|
||||
if (options.fs) {
|
||||
for (const name of enabledCallbacks) {
|
||||
const callback = options.fs[name];
|
||||
channel.registerCallback(name, (_, arg) => {
|
||||
const result = callback(JSON.parse(arg));
|
||||
if (name === "readFile") {
|
||||
// readFile has 3 returns: string (content), null (not found), undefined (fall back).
|
||||
// Wrap in object to preserve null vs undefined distinction.
|
||||
if (result === undefined)
|
||||
return "";
|
||||
return JSON.stringify({ content: result });
|
||||
}
|
||||
return JSON.stringify(result) ?? "";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
apiRequest(method, params) {
|
||||
const encodedPayload = JSON.stringify(params);
|
||||
const start = performance.now();
|
||||
const result = this.channel.requestSync(method, encodedPayload);
|
||||
this.recordTiming(method, start);
|
||||
if (result.length) {
|
||||
return JSON.parse(result);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
apiRequestBinary(method, params) {
|
||||
const start = performance.now();
|
||||
const result = this.channel.requestBinarySync(method, this.encoder.encode(JSON.stringify(params)));
|
||||
this.recordTiming(method, start);
|
||||
if (result.length === 0)
|
||||
return undefined;
|
||||
return result;
|
||||
}
|
||||
echo(payload) {
|
||||
return this.channel.requestSync("echo", payload);
|
||||
}
|
||||
echoBinary(payload) {
|
||||
return this.channel.requestBinarySync("echo", payload);
|
||||
}
|
||||
/**
|
||||
* Returns a combined timing snapshot: client-measured round-trip and byte
|
||||
* counts folded together with the server's own per-request processing time
|
||||
* (fetched via a getServerTiming request) and estimated transport overhead.
|
||||
*/
|
||||
getTimingInfo() {
|
||||
if (!this.timing) {
|
||||
return disabledTimingInfo();
|
||||
}
|
||||
const local = this.timing.getInfo();
|
||||
// requestSync bypasses recordTiming, so this query does not pollute the
|
||||
// client-side collector.
|
||||
const result = this.channel.requestSync("getServerTiming", "");
|
||||
return combineTimingInfo(local, JSON.parse(result));
|
||||
}
|
||||
resetTimingInfo() {
|
||||
if (!this.timing)
|
||||
return;
|
||||
this.timing.reset();
|
||||
// Keep the server's collection in sync so combined totals stay meaningful.
|
||||
this.channel.requestSync("resetServerTiming", "");
|
||||
}
|
||||
/**
|
||||
* Returns the timing collector that per-node materialization is reported
|
||||
* into, or undefined when timing collection is disabled. The returned
|
||||
* collector is the same one folded into {@link getTimingInfo}, so
|
||||
* materialization totals surface alongside request timings.
|
||||
*/
|
||||
getTimingCollector() {
|
||||
return this.timing;
|
||||
}
|
||||
recordTiming(method, start) {
|
||||
if (!this.timing)
|
||||
return;
|
||||
this.timing.record({
|
||||
method,
|
||||
roundTripMs: performance.now() - start,
|
||||
bytesSent: this.channel.lastBytesSent,
|
||||
bytesReceived: this.channel.lastBytesReceived,
|
||||
});
|
||||
}
|
||||
close() {
|
||||
this.channel.close();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=client.js.map
|
||||
@@ -0,0 +1 @@
|
||||
export * from './dist/suite.js'
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
import { a as RolldownLog } from "./shared/logging-xuHO4mAy.mjs";
|
||||
import { n as getLogFilter, t as GetLogFilter } from "./shared/get-log-filter-AjBknEEO.mjs";
|
||||
export { GetLogFilter, type RolldownLog, type RolldownLog as RollupLog, getLogFilter as default };
|
||||
@@ -0,0 +1,149 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const prettifyMetadata = require('./prettify-metadata')
|
||||
const getColorizer = require('../colors')
|
||||
const context = {
|
||||
customPrettifiers: {},
|
||||
colorizer: {
|
||||
colors: {}
|
||||
}
|
||||
}
|
||||
|
||||
test('returns `undefined` if no metadata present', t => {
|
||||
const str = prettifyMetadata({ log: {}, context })
|
||||
t.assert.strictEqual(str, undefined)
|
||||
})
|
||||
|
||||
test('works with only `name` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo' }, context })
|
||||
t.assert.strictEqual(str, '(foo)')
|
||||
})
|
||||
|
||||
test('works with only `pid` present', t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234' }, context })
|
||||
t.assert.strictEqual(str, '(1234)')
|
||||
})
|
||||
|
||||
test('works with only `hostname` present', t => {
|
||||
const str = prettifyMetadata({ log: { hostname: 'bar' }, context })
|
||||
t.assert.strictEqual(str, '(on bar)')
|
||||
})
|
||||
|
||||
test('works with only `name` & `pid` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234' }, context })
|
||||
t.assert.strictEqual(str, '(foo/1234)')
|
||||
})
|
||||
|
||||
test('works with only `name` & `hostname` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', hostname: 'bar' }, context })
|
||||
t.assert.strictEqual(str, '(foo on bar)')
|
||||
})
|
||||
|
||||
test('works with only `pid` & `hostname` present', t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234', hostname: 'bar' }, context })
|
||||
t.assert.strictEqual(str, '(1234 on bar)')
|
||||
})
|
||||
|
||||
test('works with only `name`, `pid`, & `hostname` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234', hostname: 'bar' }, context })
|
||||
t.assert.strictEqual(str, '(foo/1234 on bar)')
|
||||
})
|
||||
|
||||
test('works with only `name` & `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(foo) <baz>')
|
||||
})
|
||||
|
||||
test('works with only `pid` & `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(1234) <baz>')
|
||||
})
|
||||
|
||||
test('works with only `hostname` & `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { hostname: 'bar', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(on bar) <baz>')
|
||||
})
|
||||
|
||||
test('works with only `name`, `pid`, & `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(foo/1234) <baz>')
|
||||
})
|
||||
|
||||
test('works with only `name`, `hostname`, & `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', hostname: 'bar', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(foo on bar) <baz>')
|
||||
})
|
||||
|
||||
test('works with only `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '<baz>')
|
||||
})
|
||||
|
||||
test('works with only `pid`, `hostname`, & `caller` present', t => {
|
||||
const str = prettifyMetadata({ log: { pid: '1234', hostname: 'bar', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(1234 on bar) <baz>')
|
||||
})
|
||||
|
||||
test('works with all four present', t => {
|
||||
const str = prettifyMetadata({ log: { name: 'foo', pid: '1234', hostname: 'bar', caller: 'baz' }, context })
|
||||
t.assert.strictEqual(str, '(foo/1234 on bar) <baz>')
|
||||
})
|
||||
|
||||
test('uses prettifiers from passed prettifiers object', t => {
|
||||
const prettifiers = {
|
||||
name (input) {
|
||||
return input.toUpperCase()
|
||||
},
|
||||
pid (input) {
|
||||
return input + '__'
|
||||
},
|
||||
hostname (input) {
|
||||
return input.toUpperCase()
|
||||
},
|
||||
caller (input) {
|
||||
return input.toUpperCase()
|
||||
}
|
||||
}
|
||||
const str = prettifyMetadata({
|
||||
log: { pid: '1234', hostname: 'bar', caller: 'baz', name: 'joe' },
|
||||
context: {
|
||||
customPrettifiers: prettifiers,
|
||||
colorizer: { colors: {} }
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '(JOE/1234__ on BAR) <BAZ>')
|
||||
})
|
||||
|
||||
test('uses colorizer from passed context to colorize metadata', t => {
|
||||
const prettifiers = {
|
||||
name (input, _key, _log, { colors }) {
|
||||
return colors.blue(input)
|
||||
},
|
||||
pid (input, _key, _log, { colors }) {
|
||||
return colors.red(input)
|
||||
},
|
||||
hostname (input, _key, _log, { colors }) {
|
||||
return colors.green(input)
|
||||
},
|
||||
caller (input, _key, _log, { colors }) {
|
||||
return colors.cyan(input)
|
||||
}
|
||||
}
|
||||
const log = { name: 'foo', pid: '1234', hostname: 'bar', caller: 'baz' }
|
||||
const colorizer = getColorizer(true)
|
||||
const context = {
|
||||
customPrettifiers: prettifiers,
|
||||
colorizer
|
||||
}
|
||||
|
||||
const result = prettifyMetadata({ log, context })
|
||||
|
||||
const colorizedName = colorizer.colors.blue(log.name)
|
||||
const colorizedPid = colorizer.colors.red(log.pid)
|
||||
const colorizedHostname = colorizer.colors.green(log.hostname)
|
||||
const colorizedCaller = colorizer.colors.cyan(log.caller)
|
||||
const expected = `(${colorizedName}/${colorizedPid} on ${colorizedHostname}) <${colorizedCaller}>`
|
||||
|
||||
t.assert.strictEqual(result, expected)
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
import rng from './rng.js';
|
||||
import stringify from './stringify.js';
|
||||
|
||||
function v4(options, buf, offset) {
|
||||
options = options || {};
|
||||
var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
||||
|
||||
rnds[6] = rnds[6] & 0x0f | 0x40;
|
||||
rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
|
||||
|
||||
if (buf) {
|
||||
offset = offset || 0;
|
||||
|
||||
for (var i = 0; i < 16; ++i) {
|
||||
buf[offset + i] = rnds[i];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
return stringify(rnds);
|
||||
}
|
||||
|
||||
export default v4;
|
||||
@@ -0,0 +1,486 @@
|
||||
/**
|
||||
* blake2b (64-bit) & blake2s (8 to 32-bit) hash functions.
|
||||
* b could have been faster, but there is no fast u64 in js, so s is 1.5x faster.
|
||||
* @module
|
||||
*/
|
||||
import { BSIGMA, G1s, G2s } from './_blake.ts';
|
||||
import { SHA256_IV } from './_md.ts';
|
||||
import * as u64 from './_u64.ts';
|
||||
// prettier-ignore
|
||||
import {
|
||||
abytes, aexists, anumber, aoutput,
|
||||
clean, createOptHasher, Hash, swap32IfBE, swap8IfBE, toBytes, u32,
|
||||
type CHashO, type Input
|
||||
} from './utils.ts';
|
||||
|
||||
/** Blake hash options. dkLen is output length. key is used in MAC mode. salt is used in KDF mode. */
|
||||
export type Blake2Opts = {
|
||||
dkLen?: number;
|
||||
key?: Input;
|
||||
salt?: Input;
|
||||
personalization?: Input;
|
||||
};
|
||||
|
||||
// Same as SHA512_IV, but swapped endianness: LE instead of BE. iv[1] is iv[0], etc.
|
||||
const B2B_IV = /* @__PURE__ */ Uint32Array.from([
|
||||
0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a,
|
||||
0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19,
|
||||
]);
|
||||
// Temporary buffer
|
||||
const BBUF = /* @__PURE__ */ new Uint32Array(32);
|
||||
|
||||
// Mixing function G splitted in two halfs
|
||||
function G1b(a: number, b: number, c: number, d: number, msg: Uint32Array, x: number) {
|
||||
// NOTE: V is LE here
|
||||
const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore
|
||||
let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore
|
||||
let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore
|
||||
let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore
|
||||
let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore
|
||||
// v[a] = (v[a] + v[b] + x) | 0;
|
||||
let ll = u64.add3L(Al, Bl, Xl);
|
||||
Ah = u64.add3H(ll, Ah, Bh, Xh);
|
||||
Al = ll | 0;
|
||||
// v[d] = rotr(v[d] ^ v[a], 32)
|
||||
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
|
||||
({ Dh, Dl } = { Dh: u64.rotr32H(Dh, Dl), Dl: u64.rotr32L(Dh, Dl) });
|
||||
// v[c] = (v[c] + v[d]) | 0;
|
||||
({ h: Ch, l: Cl } = u64.add(Ch, Cl, Dh, Dl));
|
||||
// v[b] = rotr(v[b] ^ v[c], 24)
|
||||
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
|
||||
({ Bh, Bl } = { Bh: u64.rotrSH(Bh, Bl, 24), Bl: u64.rotrSL(Bh, Bl, 24) });
|
||||
(BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah);
|
||||
(BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh);
|
||||
(BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch);
|
||||
(BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh);
|
||||
}
|
||||
|
||||
function G2b(a: number, b: number, c: number, d: number, msg: Uint32Array, x: number) {
|
||||
// NOTE: V is LE here
|
||||
const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore
|
||||
let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore
|
||||
let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore
|
||||
let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore
|
||||
let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore
|
||||
// v[a] = (v[a] + v[b] + x) | 0;
|
||||
let ll = u64.add3L(Al, Bl, Xl);
|
||||
Ah = u64.add3H(ll, Ah, Bh, Xh);
|
||||
Al = ll | 0;
|
||||
// v[d] = rotr(v[d] ^ v[a], 16)
|
||||
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
|
||||
({ Dh, Dl } = { Dh: u64.rotrSH(Dh, Dl, 16), Dl: u64.rotrSL(Dh, Dl, 16) });
|
||||
// v[c] = (v[c] + v[d]) | 0;
|
||||
({ h: Ch, l: Cl } = u64.add(Ch, Cl, Dh, Dl));
|
||||
// v[b] = rotr(v[b] ^ v[c], 63)
|
||||
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
|
||||
({ Bh, Bl } = { Bh: u64.rotrBH(Bh, Bl, 63), Bl: u64.rotrBL(Bh, Bl, 63) });
|
||||
(BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah);
|
||||
(BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh);
|
||||
(BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch);
|
||||
(BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh);
|
||||
}
|
||||
|
||||
function checkBlake2Opts(
|
||||
outputLen: number,
|
||||
opts: Blake2Opts | undefined = {},
|
||||
keyLen: number,
|
||||
saltLen: number,
|
||||
persLen: number
|
||||
) {
|
||||
anumber(keyLen);
|
||||
if (outputLen < 0 || outputLen > keyLen) throw new Error('outputLen bigger than keyLen');
|
||||
const { key, salt, personalization } = opts;
|
||||
if (key !== undefined && (key.length < 1 || key.length > keyLen))
|
||||
throw new Error('key length must be undefined or 1..' + keyLen);
|
||||
if (salt !== undefined && salt.length !== saltLen)
|
||||
throw new Error('salt must be undefined or ' + saltLen);
|
||||
if (personalization !== undefined && personalization.length !== persLen)
|
||||
throw new Error('personalization must be undefined or ' + persLen);
|
||||
}
|
||||
|
||||
/** Class, from which others are subclassed. */
|
||||
export abstract class BLAKE2<T extends BLAKE2<T>> extends Hash<T> {
|
||||
protected abstract compress(msg: Uint32Array, offset: number, isLast: boolean): void;
|
||||
protected abstract get(): number[];
|
||||
protected abstract set(...args: number[]): void;
|
||||
abstract destroy(): void;
|
||||
protected buffer: Uint8Array;
|
||||
protected buffer32: Uint32Array;
|
||||
protected finished = false;
|
||||
protected destroyed = false;
|
||||
protected length: number = 0;
|
||||
protected pos: number = 0;
|
||||
readonly blockLen: number;
|
||||
readonly outputLen: number;
|
||||
|
||||
constructor(blockLen: number, outputLen: number) {
|
||||
super();
|
||||
anumber(blockLen);
|
||||
anumber(outputLen);
|
||||
this.blockLen = blockLen;
|
||||
this.outputLen = outputLen;
|
||||
this.buffer = new Uint8Array(blockLen);
|
||||
this.buffer32 = u32(this.buffer);
|
||||
}
|
||||
update(data: Input): this {
|
||||
aexists(this);
|
||||
data = toBytes(data);
|
||||
abytes(data);
|
||||
// Main difference with other hashes: there is flag for last block,
|
||||
// so we cannot process current block before we know that there
|
||||
// is the next one. This significantly complicates logic and reduces ability
|
||||
// to do zero-copy processing
|
||||
const { blockLen, buffer, buffer32 } = this;
|
||||
const len = data.length;
|
||||
const offset = data.byteOffset;
|
||||
const buf = data.buffer;
|
||||
for (let pos = 0; pos < len; ) {
|
||||
// If buffer is full and we still have input (don't process last block, same as blake2s)
|
||||
if (this.pos === blockLen) {
|
||||
swap32IfBE(buffer32);
|
||||
this.compress(buffer32, 0, false);
|
||||
swap32IfBE(buffer32);
|
||||
this.pos = 0;
|
||||
}
|
||||
const take = Math.min(blockLen - this.pos, len - pos);
|
||||
const dataOffset = offset + pos;
|
||||
// full block && aligned to 4 bytes && not last in input
|
||||
if (take === blockLen && !(dataOffset % 4) && pos + take < len) {
|
||||
const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4));
|
||||
swap32IfBE(data32);
|
||||
for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) {
|
||||
this.length += blockLen;
|
||||
this.compress(data32, pos32, false);
|
||||
}
|
||||
swap32IfBE(data32);
|
||||
continue;
|
||||
}
|
||||
buffer.set(data.subarray(pos, pos + take), this.pos);
|
||||
this.pos += take;
|
||||
this.length += take;
|
||||
pos += take;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
digestInto(out: Uint8Array): void {
|
||||
aexists(this);
|
||||
aoutput(out, this);
|
||||
const { pos, buffer32 } = this;
|
||||
this.finished = true;
|
||||
// Padding
|
||||
clean(this.buffer.subarray(pos));
|
||||
swap32IfBE(buffer32);
|
||||
this.compress(buffer32, 0, true);
|
||||
swap32IfBE(buffer32);
|
||||
const out32 = u32(out);
|
||||
this.get().forEach((v, i) => (out32[i] = swap8IfBE(v)));
|
||||
}
|
||||
digest(): Uint8Array {
|
||||
const { buffer, outputLen } = this;
|
||||
this.digestInto(buffer);
|
||||
const res = buffer.slice(0, outputLen);
|
||||
this.destroy();
|
||||
return res;
|
||||
}
|
||||
_cloneInto(to?: T): T {
|
||||
const { buffer, length, finished, destroyed, outputLen, pos } = this;
|
||||
to ||= new (this.constructor as any)({ dkLen: outputLen }) as T;
|
||||
to.set(...this.get());
|
||||
to.buffer.set(buffer);
|
||||
to.destroyed = destroyed;
|
||||
to.finished = finished;
|
||||
to.length = length;
|
||||
to.pos = pos;
|
||||
// @ts-ignore
|
||||
to.outputLen = outputLen;
|
||||
return to;
|
||||
}
|
||||
clone(): T {
|
||||
return this._cloneInto();
|
||||
}
|
||||
}
|
||||
|
||||
export class BLAKE2b extends BLAKE2<BLAKE2b> {
|
||||
// Same as SHA-512, but LE
|
||||
private v0l = B2B_IV[0] | 0;
|
||||
private v0h = B2B_IV[1] | 0;
|
||||
private v1l = B2B_IV[2] | 0;
|
||||
private v1h = B2B_IV[3] | 0;
|
||||
private v2l = B2B_IV[4] | 0;
|
||||
private v2h = B2B_IV[5] | 0;
|
||||
private v3l = B2B_IV[6] | 0;
|
||||
private v3h = B2B_IV[7] | 0;
|
||||
private v4l = B2B_IV[8] | 0;
|
||||
private v4h = B2B_IV[9] | 0;
|
||||
private v5l = B2B_IV[10] | 0;
|
||||
private v5h = B2B_IV[11] | 0;
|
||||
private v6l = B2B_IV[12] | 0;
|
||||
private v6h = B2B_IV[13] | 0;
|
||||
private v7l = B2B_IV[14] | 0;
|
||||
private v7h = B2B_IV[15] | 0;
|
||||
|
||||
constructor(opts: Blake2Opts = {}) {
|
||||
const olen = opts.dkLen === undefined ? 64 : opts.dkLen;
|
||||
super(128, olen);
|
||||
checkBlake2Opts(olen, opts, 64, 16, 16);
|
||||
let { key, personalization, salt } = opts;
|
||||
let keyLength = 0;
|
||||
if (key !== undefined) {
|
||||
key = toBytes(key);
|
||||
keyLength = key.length;
|
||||
}
|
||||
this.v0l ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24);
|
||||
if (salt !== undefined) {
|
||||
salt = toBytes(salt);
|
||||
const slt = u32(salt);
|
||||
this.v4l ^= swap8IfBE(slt[0]);
|
||||
this.v4h ^= swap8IfBE(slt[1]);
|
||||
this.v5l ^= swap8IfBE(slt[2]);
|
||||
this.v5h ^= swap8IfBE(slt[3]);
|
||||
}
|
||||
if (personalization !== undefined) {
|
||||
personalization = toBytes(personalization);
|
||||
const pers = u32(personalization);
|
||||
this.v6l ^= swap8IfBE(pers[0]);
|
||||
this.v6h ^= swap8IfBE(pers[1]);
|
||||
this.v7l ^= swap8IfBE(pers[2]);
|
||||
this.v7h ^= swap8IfBE(pers[3]);
|
||||
}
|
||||
if (key !== undefined) {
|
||||
// Pad to blockLen and update
|
||||
const tmp = new Uint8Array(this.blockLen);
|
||||
tmp.set(key);
|
||||
this.update(tmp);
|
||||
}
|
||||
}
|
||||
// prettier-ignore
|
||||
protected get(): [
|
||||
number, number, number, number, number, number, number, number,
|
||||
number, number, number, number, number, number, number, number
|
||||
] {
|
||||
let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this;
|
||||
return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h];
|
||||
}
|
||||
// prettier-ignore
|
||||
protected set(
|
||||
v0l: number, v0h: number, v1l: number, v1h: number,
|
||||
v2l: number, v2h: number, v3l: number, v3h: number,
|
||||
v4l: number, v4h: number, v5l: number, v5h: number,
|
||||
v6l: number, v6h: number, v7l: number, v7h: number
|
||||
): void {
|
||||
this.v0l = v0l | 0;
|
||||
this.v0h = v0h | 0;
|
||||
this.v1l = v1l | 0;
|
||||
this.v1h = v1h | 0;
|
||||
this.v2l = v2l | 0;
|
||||
this.v2h = v2h | 0;
|
||||
this.v3l = v3l | 0;
|
||||
this.v3h = v3h | 0;
|
||||
this.v4l = v4l | 0;
|
||||
this.v4h = v4h | 0;
|
||||
this.v5l = v5l | 0;
|
||||
this.v5h = v5h | 0;
|
||||
this.v6l = v6l | 0;
|
||||
this.v6h = v6h | 0;
|
||||
this.v7l = v7l | 0;
|
||||
this.v7h = v7h | 0;
|
||||
}
|
||||
protected compress(msg: Uint32Array, offset: number, isLast: boolean): void {
|
||||
this.get().forEach((v, i) => (BBUF[i] = v)); // First half from state.
|
||||
BBUF.set(B2B_IV, 16); // Second half from IV.
|
||||
let { h, l } = u64.fromBig(BigInt(this.length));
|
||||
BBUF[24] = B2B_IV[8] ^ l; // Low word of the offset.
|
||||
BBUF[25] = B2B_IV[9] ^ h; // High word.
|
||||
// Invert all bits for last block
|
||||
if (isLast) {
|
||||
BBUF[28] = ~BBUF[28];
|
||||
BBUF[29] = ~BBUF[29];
|
||||
}
|
||||
let j = 0;
|
||||
const s = BSIGMA;
|
||||
for (let i = 0; i < 12; i++) {
|
||||
G1b(0, 4, 8, 12, msg, offset + 2 * s[j++]);
|
||||
G2b(0, 4, 8, 12, msg, offset + 2 * s[j++]);
|
||||
G1b(1, 5, 9, 13, msg, offset + 2 * s[j++]);
|
||||
G2b(1, 5, 9, 13, msg, offset + 2 * s[j++]);
|
||||
G1b(2, 6, 10, 14, msg, offset + 2 * s[j++]);
|
||||
G2b(2, 6, 10, 14, msg, offset + 2 * s[j++]);
|
||||
G1b(3, 7, 11, 15, msg, offset + 2 * s[j++]);
|
||||
G2b(3, 7, 11, 15, msg, offset + 2 * s[j++]);
|
||||
|
||||
G1b(0, 5, 10, 15, msg, offset + 2 * s[j++]);
|
||||
G2b(0, 5, 10, 15, msg, offset + 2 * s[j++]);
|
||||
G1b(1, 6, 11, 12, msg, offset + 2 * s[j++]);
|
||||
G2b(1, 6, 11, 12, msg, offset + 2 * s[j++]);
|
||||
G1b(2, 7, 8, 13, msg, offset + 2 * s[j++]);
|
||||
G2b(2, 7, 8, 13, msg, offset + 2 * s[j++]);
|
||||
G1b(3, 4, 9, 14, msg, offset + 2 * s[j++]);
|
||||
G2b(3, 4, 9, 14, msg, offset + 2 * s[j++]);
|
||||
}
|
||||
this.v0l ^= BBUF[0] ^ BBUF[16];
|
||||
this.v0h ^= BBUF[1] ^ BBUF[17];
|
||||
this.v1l ^= BBUF[2] ^ BBUF[18];
|
||||
this.v1h ^= BBUF[3] ^ BBUF[19];
|
||||
this.v2l ^= BBUF[4] ^ BBUF[20];
|
||||
this.v2h ^= BBUF[5] ^ BBUF[21];
|
||||
this.v3l ^= BBUF[6] ^ BBUF[22];
|
||||
this.v3h ^= BBUF[7] ^ BBUF[23];
|
||||
this.v4l ^= BBUF[8] ^ BBUF[24];
|
||||
this.v4h ^= BBUF[9] ^ BBUF[25];
|
||||
this.v5l ^= BBUF[10] ^ BBUF[26];
|
||||
this.v5h ^= BBUF[11] ^ BBUF[27];
|
||||
this.v6l ^= BBUF[12] ^ BBUF[28];
|
||||
this.v6h ^= BBUF[13] ^ BBUF[29];
|
||||
this.v7l ^= BBUF[14] ^ BBUF[30];
|
||||
this.v7h ^= BBUF[15] ^ BBUF[31];
|
||||
clean(BBUF);
|
||||
}
|
||||
destroy(): void {
|
||||
this.destroyed = true;
|
||||
clean(this.buffer32);
|
||||
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blake2b hash function. 64-bit. 1.5x slower than blake2s in JS.
|
||||
* @param msg - message that would be hashed
|
||||
* @param opts - dkLen output length, key for MAC mode, salt, personalization
|
||||
*/
|
||||
export const blake2b: CHashO = /* @__PURE__ */ createOptHasher<BLAKE2b, Blake2Opts>(
|
||||
(opts) => new BLAKE2b(opts)
|
||||
);
|
||||
|
||||
// =================
|
||||
// Blake2S
|
||||
// =================
|
||||
|
||||
// prettier-ignore
|
||||
export type Num16 = {
|
||||
v0: number; v1: number; v2: number; v3: number;
|
||||
v4: number; v5: number; v6: number; v7: number;
|
||||
v8: number; v9: number; v10: number; v11: number;
|
||||
v12: number; v13: number; v14: number; v15: number;
|
||||
};
|
||||
|
||||
// prettier-ignore
|
||||
export function compress(s: Uint8Array, offset: number, msg: Uint32Array, rounds: number,
|
||||
v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number,
|
||||
v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number,
|
||||
): Num16 {
|
||||
let j = 0;
|
||||
for (let i = 0; i < rounds; i++) {
|
||||
({ a: v0, b: v4, c: v8, d: v12 } = G1s(v0, v4, v8, v12, msg[offset + s[j++]]));
|
||||
({ a: v0, b: v4, c: v8, d: v12 } = G2s(v0, v4, v8, v12, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v5, c: v9, d: v13 } = G1s(v1, v5, v9, v13, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v5, c: v9, d: v13 } = G2s(v1, v5, v9, v13, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v6, c: v10, d: v14 } = G1s(v2, v6, v10, v14, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v6, c: v10, d: v14 } = G2s(v2, v6, v10, v14, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v7, c: v11, d: v15 } = G1s(v3, v7, v11, v15, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v7, c: v11, d: v15 } = G2s(v3, v7, v11, v15, msg[offset + s[j++]]));
|
||||
|
||||
({ a: v0, b: v5, c: v10, d: v15 } = G1s(v0, v5, v10, v15, msg[offset + s[j++]]));
|
||||
({ a: v0, b: v5, c: v10, d: v15 } = G2s(v0, v5, v10, v15, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v6, c: v11, d: v12 } = G1s(v1, v6, v11, v12, msg[offset + s[j++]]));
|
||||
({ a: v1, b: v6, c: v11, d: v12 } = G2s(v1, v6, v11, v12, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v7, c: v8, d: v13 } = G1s(v2, v7, v8, v13, msg[offset + s[j++]]));
|
||||
({ a: v2, b: v7, c: v8, d: v13 } = G2s(v2, v7, v8, v13, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v4, c: v9, d: v14 } = G1s(v3, v4, v9, v14, msg[offset + s[j++]]));
|
||||
({ a: v3, b: v4, c: v9, d: v14 } = G2s(v3, v4, v9, v14, msg[offset + s[j++]]));
|
||||
}
|
||||
return { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 };
|
||||
}
|
||||
|
||||
const B2S_IV = SHA256_IV;
|
||||
export class BLAKE2s extends BLAKE2<BLAKE2s> {
|
||||
// Internal state, same as SHA-256
|
||||
private v0 = B2S_IV[0] | 0;
|
||||
private v1 = B2S_IV[1] | 0;
|
||||
private v2 = B2S_IV[2] | 0;
|
||||
private v3 = B2S_IV[3] | 0;
|
||||
private v4 = B2S_IV[4] | 0;
|
||||
private v5 = B2S_IV[5] | 0;
|
||||
private v6 = B2S_IV[6] | 0;
|
||||
private v7 = B2S_IV[7] | 0;
|
||||
|
||||
constructor(opts: Blake2Opts = {}) {
|
||||
const olen = opts.dkLen === undefined ? 32 : opts.dkLen;
|
||||
super(64, olen);
|
||||
checkBlake2Opts(olen, opts, 32, 8, 8);
|
||||
let { key, personalization, salt } = opts;
|
||||
let keyLength = 0;
|
||||
if (key !== undefined) {
|
||||
key = toBytes(key);
|
||||
keyLength = key.length;
|
||||
}
|
||||
this.v0 ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24);
|
||||
if (salt !== undefined) {
|
||||
salt = toBytes(salt);
|
||||
const slt = u32(salt as Uint8Array);
|
||||
this.v4 ^= swap8IfBE(slt[0]);
|
||||
this.v5 ^= swap8IfBE(slt[1]);
|
||||
}
|
||||
if (personalization !== undefined) {
|
||||
personalization = toBytes(personalization);
|
||||
const pers = u32(personalization as Uint8Array);
|
||||
this.v6 ^= swap8IfBE(pers[0]);
|
||||
this.v7 ^= swap8IfBE(pers[1]);
|
||||
}
|
||||
if (key !== undefined) {
|
||||
// Pad to blockLen and update
|
||||
abytes(key);
|
||||
const tmp = new Uint8Array(this.blockLen);
|
||||
tmp.set(key);
|
||||
this.update(tmp);
|
||||
}
|
||||
}
|
||||
protected get(): [number, number, number, number, number, number, number, number] {
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7 } = this;
|
||||
return [v0, v1, v2, v3, v4, v5, v6, v7];
|
||||
}
|
||||
// prettier-ignore
|
||||
protected set(
|
||||
v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number
|
||||
): void {
|
||||
this.v0 = v0 | 0;
|
||||
this.v1 = v1 | 0;
|
||||
this.v2 = v2 | 0;
|
||||
this.v3 = v3 | 0;
|
||||
this.v4 = v4 | 0;
|
||||
this.v5 = v5 | 0;
|
||||
this.v6 = v6 | 0;
|
||||
this.v7 = v7 | 0;
|
||||
}
|
||||
protected compress(msg: Uint32Array, offset: number, isLast: boolean): void {
|
||||
const { h, l } = u64.fromBig(BigInt(this.length));
|
||||
// prettier-ignore
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =
|
||||
compress(
|
||||
BSIGMA, offset, msg, 10,
|
||||
this.v0, this.v1, this.v2, this.v3, this.v4, this.v5, this.v6, this.v7,
|
||||
B2S_IV[0], B2S_IV[1], B2S_IV[2], B2S_IV[3], l ^ B2S_IV[4], h ^ B2S_IV[5], isLast ? ~B2S_IV[6] : B2S_IV[6], B2S_IV[7]
|
||||
);
|
||||
this.v0 ^= v0 ^ v8;
|
||||
this.v1 ^= v1 ^ v9;
|
||||
this.v2 ^= v2 ^ v10;
|
||||
this.v3 ^= v3 ^ v11;
|
||||
this.v4 ^= v4 ^ v12;
|
||||
this.v5 ^= v5 ^ v13;
|
||||
this.v6 ^= v6 ^ v14;
|
||||
this.v7 ^= v7 ^ v15;
|
||||
}
|
||||
destroy(): void {
|
||||
this.destroyed = true;
|
||||
clean(this.buffer32);
|
||||
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blake2s hash function. Focuses on 8-bit to 32-bit platforms. 1.5x faster than blake2b in JS.
|
||||
* @param msg - message that would be hashed
|
||||
* @param opts - dkLen output length, key for MAC mode, salt, personalization
|
||||
*/
|
||||
export const blake2s: CHashO = /* @__PURE__ */ createOptHasher<BLAKE2s, Blake2Opts>(
|
||||
(opts) => new BLAKE2s(opts)
|
||||
);
|
||||
@@ -0,0 +1,814 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const tsutils = __importStar(require("ts-api-utils"));
|
||||
const ts = __importStar(require("typescript"));
|
||||
const util_1 = require("../util");
|
||||
function isAtExpressionStatementStart(node) {
|
||||
let current = node;
|
||||
while (true) {
|
||||
const { parent } = current;
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
if (parent.range[0] !== current.range[0]) {
|
||||
return false;
|
||||
}
|
||||
if (parent.type === utils_1.AST_NODE_TYPES.ExpressionStatement) {
|
||||
return true;
|
||||
}
|
||||
current = parent;
|
||||
}
|
||||
}
|
||||
function isAtArrowFunctionBodyStart(node, sourceCode) {
|
||||
let current = node;
|
||||
while (true) {
|
||||
if ((0, util_1.isParenthesized)(current, sourceCode)) {
|
||||
return false;
|
||||
}
|
||||
const { parent } = current;
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
if (parent.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
||||
parent.body === current) {
|
||||
return true;
|
||||
}
|
||||
if (parent.range[0] !== current.range[0]) {
|
||||
return false;
|
||||
}
|
||||
current = parent;
|
||||
}
|
||||
}
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'no-unnecessary-type-assertion',
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Disallow type assertions that do not change the type of an expression',
|
||||
recommended: 'recommended',
|
||||
requiresTypeChecking: true,
|
||||
},
|
||||
fixable: 'code',
|
||||
messages: {
|
||||
contextuallyUnnecessary: 'This assertion is unnecessary since the receiver accepts the original type of the expression.',
|
||||
unnecessaryAssertion: 'This assertion is unnecessary since it does not change the type of the expression.',
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
checkLiteralConstAssertions: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to check literal const assertions.',
|
||||
},
|
||||
typesToIgnore: {
|
||||
type: 'array',
|
||||
description: 'A list of type names to ignore.',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultOptions: [{}],
|
||||
create(context, [options]) {
|
||||
const services = (0, util_1.getParserServices)(context);
|
||||
const checker = services.program.getTypeChecker();
|
||||
const compilerOptions = services.program.getCompilerOptions();
|
||||
/**
|
||||
* Returns true if there's a chance the variable has been used before a value has been assigned to it
|
||||
*/
|
||||
function isPossiblyUsedBeforeAssigned(node) {
|
||||
const declaration = (0, util_1.getDeclaration)(services, node);
|
||||
if (!declaration) {
|
||||
// don't know what the declaration is for some reason, so just assume the worst
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
// non-strict mode doesn't care about used before assigned errors
|
||||
tsutils.isStrictCompilerOptionEnabled(compilerOptions, 'strictNullChecks') &&
|
||||
// ignore class properties as they are compile time guarded
|
||||
// also ignore function arguments as they can't be used before defined
|
||||
ts.isVariableDeclaration(declaration)) {
|
||||
// For var declarations, we need to check whether the node
|
||||
// is actually in a descendant of its declaration or not. If not,
|
||||
// it may be used before defined.
|
||||
// eg
|
||||
// if (Math.random() < 0.5) {
|
||||
// var x: number = 2;
|
||||
// } else {
|
||||
// x!.toFixed();
|
||||
// }
|
||||
if (ts.isVariableDeclarationList(declaration.parent) &&
|
||||
// var
|
||||
declaration.parent.flags === ts.NodeFlags.None &&
|
||||
// If they are not in the same file it will not exist.
|
||||
// This situation must not occur using before defined.
|
||||
services.tsNodeToESTreeNodeMap.has(declaration)) {
|
||||
const declaratorNode = services.tsNodeToESTreeNodeMap.get(declaration);
|
||||
const scope = context.sourceCode.getScope(node);
|
||||
const declaratorScope = context.sourceCode.getScope(declaratorNode);
|
||||
let parentScope = declaratorScope;
|
||||
while ((parentScope = parentScope.upper)) {
|
||||
if (parentScope === scope) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
// is it `const x!: number`
|
||||
declaration.initializer == null &&
|
||||
declaration.exclamationToken == null &&
|
||||
declaration.type != null) {
|
||||
// check if the defined variable type has changed since assignment
|
||||
const declarationType = checker.getTypeFromTypeNode(declaration.type);
|
||||
const type = (0, util_1.getConstrainedTypeAtLocation)(services, node);
|
||||
if (declarationType === type &&
|
||||
// `declare`s are never narrowed, so never skip them
|
||||
!(ts.isVariableDeclarationList(declaration.parent) &&
|
||||
ts.isVariableStatement(declaration.parent.parent) &&
|
||||
tsutils.includesModifier((0, util_1.getModifiers)(declaration.parent.parent), ts.SyntaxKind.DeclareKeyword))) {
|
||||
// possibly used before assigned, so just skip it
|
||||
// better to false negative and skip it, than false positive and fix to compile erroring code
|
||||
//
|
||||
// no better way to figure this out right now
|
||||
// https://github.com/Microsoft/TypeScript/issues/31124
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isConstAssertion(node) {
|
||||
return (node.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
||||
node.typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
|
||||
node.typeName.name === 'const');
|
||||
}
|
||||
function isTemplateLiteralWithExpressions(expression) {
|
||||
return (expression.type === utils_1.AST_NODE_TYPES.TemplateLiteral &&
|
||||
expression.expressions.length !== 0);
|
||||
}
|
||||
function isImplicitlyNarrowedLiteralDeclaration({ expression, parent, }) {
|
||||
/**
|
||||
* Even on `const` variable declarations, template literals with expressions can sometimes be widened without a type assertion.
|
||||
* @see https://github.com/typescript-eslint/typescript-eslint/issues/8737
|
||||
*/
|
||||
if (isTemplateLiteralWithExpressions(expression)) {
|
||||
return false;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const maybeDeclarationNode = parent.parent;
|
||||
return ((maybeDeclarationNode.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
|
||||
maybeDeclarationNode.kind === 'const') ||
|
||||
(parent.type === utils_1.AST_NODE_TYPES.PropertyDefinition && parent.readonly));
|
||||
}
|
||||
function isTypeUnchanged(node, expression, uncast, cast) {
|
||||
if (uncast === cast) {
|
||||
return true;
|
||||
}
|
||||
if (node.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSIntersectionType &&
|
||||
containsTypeVariable(cast)) {
|
||||
return false;
|
||||
}
|
||||
if ((0, util_1.isTypeFlagSet)(uncast, ts.TypeFlags.Undefined) &&
|
||||
(0, util_1.isTypeFlagSet)(cast, ts.TypeFlags.Undefined) &&
|
||||
tsutils.isCompilerOptionEnabled(compilerOptions, 'exactOptionalPropertyTypes')) {
|
||||
return areUnionPartsEquivalentIgnoringUndefined(uncast, cast);
|
||||
}
|
||||
if (((0, util_1.isTypeFlagSet)(uncast, ts.TypeFlags.NonPrimitive) &&
|
||||
!(0, util_1.isTypeFlagSet)(cast, ts.TypeFlags.NonPrimitive)) ||
|
||||
(hasIndexSignature(uncast) && !hasIndexSignature(cast)) ||
|
||||
containsAny(uncast) ||
|
||||
containsAny(cast) ||
|
||||
(containsTypeVariable(cast) && !containsTypeVariable(uncast))) {
|
||||
return false;
|
||||
}
|
||||
if (isConceptuallyLiteral(expression) &&
|
||||
(expression.type !== utils_1.AST_NODE_TYPES.ObjectExpression ||
|
||||
expression.properties.length === 0 ||
|
||||
cast
|
||||
.getProperties()
|
||||
.some(p => isTypeLiteral(checker.getTypeOfSymbol(p))))) {
|
||||
return false;
|
||||
}
|
||||
if (cast.isIntersection() && !uncast.isIntersection()) {
|
||||
const castParts = cast.types;
|
||||
const otherPart = castParts.find(part => part !== uncast);
|
||||
if (tsutils.isTypeParameter(uncast) &&
|
||||
castParts.length === 2 &&
|
||||
castParts.some(part => part === uncast) &&
|
||||
otherPart != null &&
|
||||
isEmptyObjectType(otherPart) &&
|
||||
!containsTypeVariable(otherPart)) {
|
||||
const constraint = checker.getBaseConstraintOfType(uncast);
|
||||
if (constraint && !(0, util_1.isNullableType)(constraint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!hasSameProperties(uncast, cast) ||
|
||||
!haveSameTypeArguments(uncast, cast)) {
|
||||
return false;
|
||||
}
|
||||
return areMutuallyAssignable(uncast, cast);
|
||||
}
|
||||
function isTypeLiteral(type) {
|
||||
return type.isLiteral() || tsutils.isBooleanLiteralType(type);
|
||||
}
|
||||
function hasIndexSignature(type) {
|
||||
return tsutils
|
||||
.unionConstituents(type)
|
||||
.some(part => checker.getIndexInfosOfType(part).length > 0);
|
||||
}
|
||||
function getTypeArguments(type) {
|
||||
return (type.aliasTypeArguments ??
|
||||
(tsutils.isTypeReference(type) ? checker.getTypeArguments(type) : []));
|
||||
}
|
||||
function typeContains(type, predicate, seen = new Set()) {
|
||||
if (seen.has(type)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(type);
|
||||
if (predicate(type)) {
|
||||
return true;
|
||||
}
|
||||
if (type.isUnionOrIntersection()) {
|
||||
return type.types.some(t => typeContains(t, predicate, seen));
|
||||
}
|
||||
const nestedTypes = [
|
||||
...getTypeArguments(type),
|
||||
...type
|
||||
.getCallSignatures()
|
||||
.flatMap(sig => [
|
||||
sig.getReturnType(),
|
||||
...sig.getParameters().map(p => checker.getTypeOfSymbol(p)),
|
||||
]),
|
||||
];
|
||||
return nestedTypes.some(t => typeContains(t, predicate, seen));
|
||||
}
|
||||
function containsAny(type) {
|
||||
return typeContains(type, t => (0, util_1.isTypeFlagSet)(t, ts.TypeFlags.Any));
|
||||
}
|
||||
function containsTypeVariable(type) {
|
||||
return typeContains(type, t => (0, util_1.isTypeFlagSet)(t, ts.TypeFlags.TypeVariable | ts.TypeFlags.Index));
|
||||
}
|
||||
function hasPhantomTypeArguments(type) {
|
||||
return isEmptyObjectType(type) && getTypeArguments(type).length > 0;
|
||||
}
|
||||
function hasTypeParams(sig) {
|
||||
return (sig.getTypeParameters()?.length ?? 0) > 0;
|
||||
}
|
||||
function genericsMismatch(uncast, contextual) {
|
||||
return contextual.getProperties().some(prop => {
|
||||
const contextualSigs = checker.getSignaturesOfType(checker.getTypeOfSymbol(prop), ts.SignatureKind.Call);
|
||||
if (!contextualSigs.some(hasTypeParams)) {
|
||||
return false;
|
||||
}
|
||||
const uncastProp = uncast.getProperty(prop.getEscapedName());
|
||||
if (!uncastProp) {
|
||||
return true;
|
||||
}
|
||||
return !checker
|
||||
.getSignaturesOfType(checker.getTypeOfSymbol(uncastProp), ts.SignatureKind.Call)
|
||||
.some(hasTypeParams);
|
||||
});
|
||||
}
|
||||
function hasSameProperties(uncast, cast) {
|
||||
const uncastProps = uncast.getProperties();
|
||||
const castProps = cast.getProperties();
|
||||
if (uncastProps.length !== castProps.length) {
|
||||
return false;
|
||||
}
|
||||
const castPropNames = new Set(castProps.map(p => p.getEscapedName()));
|
||||
return uncastProps.every(prop => {
|
||||
const name = prop.getEscapedName();
|
||||
return (castPropNames.has(name) &&
|
||||
tsutils.isPropertyReadonlyInType(uncast, name, checker) ===
|
||||
tsutils.isPropertyReadonlyInType(cast, name, checker));
|
||||
});
|
||||
}
|
||||
function haveSameTypeArguments(uncast, cast) {
|
||||
const uncastArgs = getTypeArguments(uncast);
|
||||
const castArgs = getTypeArguments(cast);
|
||||
return (uncastArgs.length === castArgs.length &&
|
||||
uncastArgs.every((arg, i) => arg === castArgs[i]));
|
||||
}
|
||||
function areMutuallyAssignable(a, b) {
|
||||
return (checker.isTypeAssignableTo(a, b) && checker.isTypeAssignableTo(b, a));
|
||||
}
|
||||
function areUnionPartsEquivalentIgnoringUndefined(uncast, cast) {
|
||||
const filterUndefined = (part) => !(0, util_1.isTypeFlagSet)(part, ts.TypeFlags.Undefined);
|
||||
const uncastParts = tsutils
|
||||
.unionConstituents(uncast)
|
||||
.filter(filterUndefined);
|
||||
const castParts = tsutils.unionConstituents(cast).filter(filterUndefined);
|
||||
if (uncastParts.length !== castParts.length) {
|
||||
return false;
|
||||
}
|
||||
const uncastPartsSet = new Set(uncastParts);
|
||||
return castParts.every(part => uncastPartsSet.has(part));
|
||||
}
|
||||
function getOriginalExpression(node) {
|
||||
let current = node.expression;
|
||||
while (current.type === utils_1.AST_NODE_TYPES.TSAsExpression ||
|
||||
current.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
|
||||
current = current.expression;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
function isDoubleAssertionUnnecessary(node, contextualType) {
|
||||
const innerExpression = node.expression;
|
||||
if (innerExpression.type !== utils_1.AST_NODE_TYPES.TSAsExpression &&
|
||||
innerExpression.type !== utils_1.AST_NODE_TYPES.TSTypeAssertion) {
|
||||
return false;
|
||||
}
|
||||
const originalExpr = getOriginalExpression(node);
|
||||
const originalType = services.getTypeAtLocation(originalExpr);
|
||||
const castType = services.getTypeAtLocation(node);
|
||||
if (isTypeUnchanged(node, innerExpression, originalType, castType) &&
|
||||
!(0, util_1.isTypeFlagSet)(castType, ts.TypeFlags.Any)) {
|
||||
return 'unnecessaryAssertion';
|
||||
}
|
||||
if (contextualType) {
|
||||
const intermediateType = services.getTypeAtLocation(innerExpression);
|
||||
if (((0, util_1.isTypeFlagSet)(intermediateType, ts.TypeFlags.Any) ||
|
||||
(0, util_1.isTypeFlagSet)(intermediateType, ts.TypeFlags.Unknown)) &&
|
||||
checker.isTypeAssignableTo(originalType, contextualType)) {
|
||||
return 'contextuallyUnnecessary';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const CONCEPTUALLY_LITERAL_TYPES = new Set([
|
||||
utils_1.AST_NODE_TYPES.Literal,
|
||||
utils_1.AST_NODE_TYPES.ArrayExpression,
|
||||
utils_1.AST_NODE_TYPES.ObjectExpression,
|
||||
utils_1.AST_NODE_TYPES.TemplateLiteral,
|
||||
utils_1.AST_NODE_TYPES.ClassExpression,
|
||||
utils_1.AST_NODE_TYPES.FunctionExpression,
|
||||
utils_1.AST_NODE_TYPES.ArrowFunctionExpression,
|
||||
utils_1.AST_NODE_TYPES.JSXElement,
|
||||
utils_1.AST_NODE_TYPES.JSXFragment,
|
||||
]);
|
||||
function isConceptuallyLiteral(node) {
|
||||
return CONCEPTUALLY_LITERAL_TYPES.has(node.type);
|
||||
}
|
||||
function isIIFE(expression) {
|
||||
return (expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
||||
(expression.callee.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
||||
expression.callee.type === utils_1.AST_NODE_TYPES.FunctionExpression));
|
||||
}
|
||||
function isEmptyObjectType(type) {
|
||||
return ((0, util_1.isTypeFlagSet)(type, ts.TypeFlags.NonPrimitive) ||
|
||||
(type.getProperties().length === 0 &&
|
||||
!type.getCallSignatures().length &&
|
||||
!type.getConstructSignatures().length &&
|
||||
!type.getStringIndexType() &&
|
||||
!type.getNumberIndexType()));
|
||||
}
|
||||
function hasGenericCallSignature(type) {
|
||||
return type.getCallSignatures().some(hasTypeParams);
|
||||
}
|
||||
function isArgumentToOverloadedFunction(node) {
|
||||
const { parent } = node;
|
||||
if ((parent.type !== utils_1.AST_NODE_TYPES.CallExpression &&
|
||||
parent.type !== utils_1.AST_NODE_TYPES.NewExpression) ||
|
||||
!parent.arguments.includes(node)) {
|
||||
return false;
|
||||
}
|
||||
// An optional-chained callee (`foo?.bar(...)`) types as `<method> | undefined`,
|
||||
// and a union exposes no call signatures — strip the nullability first.
|
||||
const calleeType = services
|
||||
.getTypeAtLocation(parent.callee)
|
||||
.getNonNullableType();
|
||||
const signatures = calleeType.getCallSignatures();
|
||||
if (signatures.length <= 1) {
|
||||
return false;
|
||||
}
|
||||
const argIndex = parent.arguments.indexOf(node);
|
||||
const paramTypes = signatures.map(sig => {
|
||||
const params = sig.getParameters();
|
||||
if (argIndex >= params.length) {
|
||||
return undefined;
|
||||
}
|
||||
const param = params[argIndex];
|
||||
let paramType = checker.getTypeOfSymbol(param);
|
||||
if (param.valueDeclaration &&
|
||||
ts.isParameter(param.valueDeclaration) &&
|
||||
param.valueDeclaration.dotDotDotToken) {
|
||||
const typeArgs = getTypeArguments(paramType);
|
||||
if (typeArgs.length > 0) {
|
||||
paramType = typeArgs[0];
|
||||
}
|
||||
}
|
||||
return paramType;
|
||||
});
|
||||
if (paramTypes.some(type => type == null)) {
|
||||
return true;
|
||||
}
|
||||
const definedParamTypes = paramTypes;
|
||||
const firstParamType = definedParamTypes[0];
|
||||
if (definedParamTypes.every(type => type === firstParamType)) {
|
||||
return false;
|
||||
}
|
||||
const uncastType = services.getTypeAtLocation(node.expression);
|
||||
return !definedParamTypes.every(type => checker.isTypeAssignableTo(uncastType, type));
|
||||
}
|
||||
function isInDestructuringDeclaration(node) {
|
||||
const { parent } = node;
|
||||
return (parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
|
||||
parent.init === node &&
|
||||
(parent.id.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
||||
parent.id.type === utils_1.AST_NODE_TYPES.ArrayPattern));
|
||||
}
|
||||
function isPropertyInProblematicContext(node) {
|
||||
const { parent } = node;
|
||||
if (parent.type !== utils_1.AST_NODE_TYPES.Property || parent.value !== node) {
|
||||
return false;
|
||||
}
|
||||
const objectExpr = parent.parent;
|
||||
if (objectExpr.type !== utils_1.AST_NODE_TYPES.ObjectExpression) {
|
||||
return false;
|
||||
}
|
||||
const objectTsNode = services.esTreeNodeToTSNodeMap.get(objectExpr);
|
||||
if (checker.getContextualType(objectTsNode)?.isUnion()) {
|
||||
const nodeTsNode = services.esTreeNodeToTSNodeMap.get(node);
|
||||
const propContextualType = checker.getContextualType(nodeTsNode);
|
||||
if (propContextualType == null) {
|
||||
return true;
|
||||
}
|
||||
const nonNullableContextualType = checker.getNonNullableType(propContextualType);
|
||||
if (nonNullableContextualType.isUnion()) {
|
||||
return true;
|
||||
}
|
||||
const uncastType = services.getTypeAtLocation(node.expression);
|
||||
return !checker.isTypeAssignableTo(uncastType, nonNullableContextualType);
|
||||
}
|
||||
const objectParent = objectExpr.parent;
|
||||
return (objectParent.type === utils_1.AST_NODE_TYPES.TSSatisfiesExpression ||
|
||||
(objectParent.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
||||
objectParent.parent.type === utils_1.AST_NODE_TYPES.TSSatisfiesExpression));
|
||||
}
|
||||
function isAssignmentInNonStatementContext(node) {
|
||||
const { parent } = node;
|
||||
if (parent.type !== utils_1.AST_NODE_TYPES.AssignmentExpression ||
|
||||
parent.right !== node) {
|
||||
return false;
|
||||
}
|
||||
const assignmentParent = parent.parent;
|
||||
return assignmentParent.type !== utils_1.AST_NODE_TYPES.ExpressionStatement;
|
||||
}
|
||||
function isRightHandSideOfLogicalAssignment(node) {
|
||||
const { parent } = node;
|
||||
return (parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
|
||||
parent.right === node &&
|
||||
(parent.operator === '&&=' ||
|
||||
parent.operator === '||=' ||
|
||||
parent.operator === '??='));
|
||||
}
|
||||
function isInGenericContext(node) {
|
||||
let seenFunction = false;
|
||||
for (let current = node.parent; current; current = current.parent) {
|
||||
if (current.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
||||
return false;
|
||||
}
|
||||
if (current.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
||||
current.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
||||
if (current.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
||||
return false;
|
||||
}
|
||||
if (seenFunction) {
|
||||
return false;
|
||||
}
|
||||
seenFunction = true;
|
||||
}
|
||||
if (current.type === utils_1.AST_NODE_TYPES.CallExpression ||
|
||||
current.type === utils_1.AST_NODE_TYPES.NewExpression) {
|
||||
if (current.typeArguments != null) {
|
||||
continue;
|
||||
}
|
||||
if (current.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
||||
current.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
||||
current.arguments.includes(node)) {
|
||||
continue;
|
||||
}
|
||||
const calleeType = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(current.callee));
|
||||
if (hasGenericCallSignature(calleeType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function hasPhantomTypeArgumentMismatch(node, uncastType, contextualType) {
|
||||
return (isInGenericContext(node) &&
|
||||
(hasPhantomTypeArguments(uncastType) ||
|
||||
hasPhantomTypeArguments(contextualType)) &&
|
||||
!haveSameTypeArguments(uncastType, contextualType));
|
||||
}
|
||||
const SKIP_PARENT_TYPES = new Set([
|
||||
utils_1.AST_NODE_TYPES.TSAsExpression,
|
||||
utils_1.AST_NODE_TYPES.TSTypeAssertion,
|
||||
utils_1.AST_NODE_TYPES.SpreadElement,
|
||||
utils_1.AST_NODE_TYPES.TSSatisfiesExpression,
|
||||
]);
|
||||
function shouldSkipContextualTypeFallback(node, castIsAny) {
|
||||
if (castIsAny) {
|
||||
return (node.parent.type === utils_1.AST_NODE_TYPES.LogicalExpression ||
|
||||
isInGenericContext(node));
|
||||
}
|
||||
/**
|
||||
* Interpolated template literals can be widened to `string` while contextual
|
||||
* typing still accepts them, so the assertion may be required.
|
||||
* @see https://github.com/typescript-eslint/typescript-eslint/issues/12276
|
||||
*/
|
||||
if (isTemplateLiteralWithExpressions(node.expression)) {
|
||||
return true;
|
||||
}
|
||||
if (SKIP_PARENT_TYPES.has(node.parent.type) ||
|
||||
node.expression.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
|
||||
isInDestructuringDeclaration(node) ||
|
||||
isPropertyInProblematicContext(node) ||
|
||||
isAssignmentInNonStatementContext(node) ||
|
||||
isRightHandSideOfLogicalAssignment(node) ||
|
||||
isArgumentToOverloadedFunction(node)) {
|
||||
return true;
|
||||
}
|
||||
if (isInGenericContext(node)) {
|
||||
const originalExpr = getOriginalExpression(node);
|
||||
return (!isConceptuallyLiteral(originalExpr) &&
|
||||
node.parent.type !== utils_1.AST_NODE_TYPES.Property);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getUncastType(node) {
|
||||
// Special handling for IIFE: extract the function's return type
|
||||
if (isIIFE(node.expression)) {
|
||||
const callee = node.expression.callee;
|
||||
const functionType = services.getTypeAtLocation(callee);
|
||||
const signatures = functionType.getCallSignatures();
|
||||
if (signatures.length > 0) {
|
||||
const returnType = checker.getReturnTypeOfSignature(signatures[0]);
|
||||
// If the function has no explicit return type annotation and returns undefined,
|
||||
// treat it as void (TypeScript infers () => {} as () => undefined, but it should be void)
|
||||
if (callee.returnType == null &&
|
||||
(0, util_1.isTypeFlagSet)(returnType, ts.TypeFlags.Undefined)) {
|
||||
return checker.getVoidType();
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
return services.getTypeAtLocation(node.expression);
|
||||
}
|
||||
function createAssertionFixer(node) {
|
||||
return fixer => {
|
||||
if (node.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
|
||||
const openingAngleBracket = (0, util_1.nullThrows)(context.sourceCode.getTokenBefore(node.typeAnnotation, token => token.type === utils_1.AST_TOKEN_TYPES.Punctuator &&
|
||||
token.value === '<'), util_1.NullThrowsReasons.MissingToken('<', 'type annotation'));
|
||||
const closingAngleBracket = (0, util_1.nullThrows)(context.sourceCode.getTokenAfter(node.typeAnnotation, token => token.type === utils_1.AST_TOKEN_TYPES.Punctuator &&
|
||||
token.value === '>'), util_1.NullThrowsReasons.MissingToken('>', 'type annotation'));
|
||||
// Removing the angle brackets leaves the asserted operand at the
|
||||
// assertion's position, so its first token leads whatever the
|
||||
// assertion led. A leading `{`/`function`/`class` at the start of an
|
||||
// expression statement is parsed as a block / function or class
|
||||
// declaration, and a leading `{` at the start of a concise arrow body
|
||||
// is parsed as a block body. In those positions the operand must be
|
||||
// wrapped in parentheses to stay an expression.
|
||||
const firstOperandToken = (0, util_1.nullThrows)(context.sourceCode.getTokenAfter(closingAngleBracket), util_1.NullThrowsReasons.MissingToken('operand', 'type assertion'));
|
||||
const breaksExpressionStatement = ['{', 'function', 'class'].includes(firstOperandToken.value) &&
|
||||
isAtExpressionStatementStart(node);
|
||||
const breaksArrowFunctionBody = firstOperandToken.value === '{' &&
|
||||
isAtArrowFunctionBodyStart(node, context.sourceCode);
|
||||
const needsParens = breaksExpressionStatement || breaksArrowFunctionBody;
|
||||
const fixes = [];
|
||||
if (needsParens) {
|
||||
fixes.push(fixer.insertTextBefore(node, '('));
|
||||
}
|
||||
fixes.push(fixer.removeRange([
|
||||
openingAngleBracket.range[0],
|
||||
closingAngleBracket.range[1],
|
||||
]));
|
||||
if (needsParens) {
|
||||
fixes.push(fixer.insertTextAfter(node, ')'));
|
||||
}
|
||||
return fixes;
|
||||
}
|
||||
const asToken = (0, util_1.nullThrows)(context.sourceCode.getTokenAfter(node.expression, token => token.type === utils_1.AST_TOKEN_TYPES.Identifier && token.value === 'as'), util_1.NullThrowsReasons.MissingToken('>', 'type annotation'));
|
||||
const tokenBeforeAs = (0, util_1.nullThrows)(context.sourceCode.getTokenBefore(asToken, {
|
||||
includeComments: true,
|
||||
}), util_1.NullThrowsReasons.MissingToken('comment', 'as'));
|
||||
return fixer.removeRange([tokenBeforeAs.range[1], node.range[1]]);
|
||||
};
|
||||
}
|
||||
function reportDoubleAssertionIfUnnecessary(node, contextualType) {
|
||||
const doubleAssertionResult = isDoubleAssertionUnnecessary(node, contextualType);
|
||||
if (doubleAssertionResult) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: doubleAssertionResult,
|
||||
fix(fixer) {
|
||||
const originalExpr = getOriginalExpression(node);
|
||||
let text = context.sourceCode.getText(originalExpr);
|
||||
if (originalExpr.type === utils_1.AST_NODE_TYPES.ObjectExpression &&
|
||||
node.parent.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
||||
node.parent.body === node) {
|
||||
text = `(${text})`;
|
||||
}
|
||||
return fixer.replaceText(node, text);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
'TSAsExpression, TSTypeAssertion'(node) {
|
||||
if (options.typesToIgnore?.includes(context.sourceCode.getText(node.typeAnnotation))) {
|
||||
return;
|
||||
}
|
||||
const castType = services.getTypeAtLocation(node);
|
||||
const castTypeIsLiteral = isTypeLiteral(castType);
|
||||
const typeAnnotationIsConstAssertion = isConstAssertion(node.typeAnnotation);
|
||||
if (!options.checkLiteralConstAssertions &&
|
||||
castTypeIsLiteral &&
|
||||
typeAnnotationIsConstAssertion) {
|
||||
return;
|
||||
}
|
||||
const uncastType = getUncastType(node);
|
||||
const typeIsUnchanged = isTypeUnchanged(node, node.expression, uncastType, castType);
|
||||
const wouldSameTypeBeInferred = castTypeIsLiteral
|
||||
? isImplicitlyNarrowedLiteralDeclaration(node)
|
||||
: !typeAnnotationIsConstAssertion;
|
||||
if (typeIsUnchanged && wouldSameTypeBeInferred) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'unnecessaryAssertion',
|
||||
fix: createAssertionFixer(node),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const originalNode = services.esTreeNodeToTSNodeMap.get(node);
|
||||
const castIsAny = (0, util_1.isTypeFlagSet)(castType, ts.TypeFlags.Any) &&
|
||||
!SKIP_PARENT_TYPES.has(node.parent.type);
|
||||
const contextualType = shouldSkipContextualTypeFallback(node, castIsAny)
|
||||
? undefined
|
||||
: checker.getContextualType(originalNode);
|
||||
if (contextualType) {
|
||||
const contextualTypeIsAny = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Any);
|
||||
const isCallArgument = (node.parent.type === utils_1.AST_NODE_TYPES.CallExpression ||
|
||||
node.parent.type === utils_1.AST_NODE_TYPES.NewExpression) &&
|
||||
node.parent.arguments.includes(node);
|
||||
const anyInvolvedInContextualCheck = contextualTypeIsAny
|
||||
? isCallArgument && !containsAny(castType)
|
||||
: !containsAny(contextualType);
|
||||
const isNullishLiteralToUnion = castType.isUnion() &&
|
||||
((node.expression.type === utils_1.AST_NODE_TYPES.Literal &&
|
||||
node.expression.value == null) ||
|
||||
(node.expression.type === utils_1.AST_NODE_TYPES.Identifier &&
|
||||
node.expression.name === 'undefined'));
|
||||
const isContextuallyUnnecessary = !typeAnnotationIsConstAssertion &&
|
||||
!containsAny(uncastType) &&
|
||||
anyInvolvedInContextualCheck &&
|
||||
!hasPhantomTypeArgumentMismatch(node, uncastType, contextualType) &&
|
||||
(castIsAny || !genericsMismatch(uncastType, contextualType)) &&
|
||||
(contextualTypeIsAny ||
|
||||
checker.isTypeAssignableTo(uncastType, contextualType)) &&
|
||||
!isNullishLiteralToUnion;
|
||||
if (isContextuallyUnnecessary) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'contextuallyUnnecessary',
|
||||
fix: createAssertionFixer(node),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
reportDoubleAssertionIfUnnecessary(node, contextualType);
|
||||
},
|
||||
TSNonNullExpression(node) {
|
||||
const removeExclamationFix = fixer => {
|
||||
const exclamationToken = (0, util_1.nullThrows)(context.sourceCode.getLastToken(node, token => token.value === '!'), util_1.NullThrowsReasons.MissingToken('exclamation mark', 'non-null assertion'));
|
||||
return fixer.removeRange(exclamationToken.range);
|
||||
};
|
||||
if (node.parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
|
||||
node.parent.operator === '=') {
|
||||
if (node.parent.left === node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'contextuallyUnnecessary',
|
||||
fix: removeExclamationFix,
|
||||
});
|
||||
}
|
||||
// for all other = assignments we ignore non-null checks
|
||||
// this is because non-null assertions can change the type-flow of the code
|
||||
// so whilst they might be unnecessary for the assignment - they are necessary
|
||||
// for following code
|
||||
return;
|
||||
}
|
||||
const originalNode = services.esTreeNodeToTSNodeMap.get(node);
|
||||
const constrainedType = (0, util_1.getConstrainedTypeAtLocation)(services, node.expression);
|
||||
const actualType = services.getTypeAtLocation(node.expression);
|
||||
// Check both the constrained type and the actual type.
|
||||
// If either is nullable, we should not report the assertion as unnecessary.
|
||||
// This handles cases like generic constraints with `any` where the
|
||||
// constrained type is `any` (nullable) but the actual type might be
|
||||
// a type parameter that TypeScript treats nominally.
|
||||
// See: https://github.com/typescript-eslint/typescript-eslint/issues/11559
|
||||
const constrainedTypeIsNullable = (0, util_1.isNullableType)(constrainedType);
|
||||
const actualTypeIsNullable = (0, util_1.isNullableType)(actualType);
|
||||
if (!constrainedTypeIsNullable && !actualTypeIsNullable) {
|
||||
if (node.expression.type === utils_1.AST_NODE_TYPES.Identifier &&
|
||||
isPossiblyUsedBeforeAssigned(node.expression)) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'unnecessaryAssertion',
|
||||
fix: removeExclamationFix,
|
||||
});
|
||||
}
|
||||
else {
|
||||
// we know it's a nullable type
|
||||
// so figure out if the variable is used in a place that accepts nullable types
|
||||
// If the constrained type differs from the actual type (e.g., when dealing
|
||||
// with unresolved generic type parameters), we should not report the assertion
|
||||
// as contextually unnecessary. TypeScript may still require the assertion
|
||||
// even if the constraint is nullable (like `any`).
|
||||
// See: https://github.com/typescript-eslint/typescript-eslint/issues/11559
|
||||
if (constrainedType !== actualType) {
|
||||
return;
|
||||
}
|
||||
const contextualType = (0, util_1.getContextualType)(checker, originalNode);
|
||||
if (contextualType) {
|
||||
if ((0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Unknown) &&
|
||||
!(0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Unknown)) {
|
||||
return;
|
||||
}
|
||||
// in strict mode you can't assign null to undefined, so we have to make sure that
|
||||
// the two types share a nullable type
|
||||
const typeIncludesUndefined = (0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Undefined);
|
||||
const typeIncludesNull = (0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Null);
|
||||
const typeIncludesVoid = (0, util_1.isTypeFlagSet)(constrainedType, ts.TypeFlags.Void);
|
||||
const contextualTypeIncludesUndefined = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Undefined);
|
||||
const contextualTypeIncludesNull = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Null);
|
||||
const contextualTypeIncludesVoid = (0, util_1.isTypeFlagSet)(contextualType, ts.TypeFlags.Void);
|
||||
// make sure that the parent accepts the same types
|
||||
// i.e. assigning `string | null | undefined` to `string | undefined` is invalid
|
||||
const isValidUndefined = typeIncludesUndefined
|
||||
? contextualTypeIncludesUndefined
|
||||
: true;
|
||||
const isValidNull = typeIncludesNull
|
||||
? contextualTypeIncludesNull
|
||||
: true;
|
||||
const isValidVoid = typeIncludesVoid
|
||||
? contextualTypeIncludesVoid
|
||||
: true;
|
||||
if (isValidUndefined && isValidNull && isValidVoid) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'contextuallyUnnecessary',
|
||||
fix: removeExclamationFix,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "es6-promisify",
|
||||
"version": "5.0.0",
|
||||
"description": "Converts callback-based functions to ES6 Promises",
|
||||
"main": "dist/promisify.js",
|
||||
"author": "Mike Hall <mikehall314@gmail.com>",
|
||||
"keywords": [
|
||||
"promises",
|
||||
"es6",
|
||||
"promisify"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es6-promise": "^4.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"pretest": "./node_modules/eslint/bin/eslint.js ./lib/*.js ./tests/*.js",
|
||||
"test": "gulp && nodeunit tests"
|
||||
},
|
||||
"bugs": "http://github.com/digitaldesignlabs/es6-promisify/issues",
|
||||
"files": [
|
||||
"dist/promisify.js",
|
||||
"dist/promise.js"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/digitaldesignlabs/es6-promisify.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-es2015": "^6.9.0",
|
||||
"eslint": "^2.13.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-babel": "^6.1.2",
|
||||
"nodeunit": "^0.10.0"
|
||||
},
|
||||
"greenkeeper": {
|
||||
"ignore": [
|
||||
"eslint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"unsafeMerging", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ExportVisitor = void 0;
|
||||
const types_1 = require("@typescript-eslint/types");
|
||||
const Visitor_1 = require("./Visitor");
|
||||
class ExportVisitor extends Visitor_1.Visitor {
|
||||
#exportNode;
|
||||
#referencer;
|
||||
constructor(node, referencer) {
|
||||
super(referencer);
|
||||
this.#exportNode = node;
|
||||
this.#referencer = referencer;
|
||||
}
|
||||
static visit(referencer, node) {
|
||||
const exportReferencer = new ExportVisitor(node, referencer);
|
||||
exportReferencer.visit(node);
|
||||
}
|
||||
ExportDefaultDeclaration(node) {
|
||||
if (node.declaration.type === types_1.AST_NODE_TYPES.Identifier) {
|
||||
// export default A;
|
||||
// this could be a type or a variable
|
||||
this.visit(node.declaration);
|
||||
}
|
||||
else {
|
||||
// export const a = 1;
|
||||
// export something();
|
||||
// etc
|
||||
// these not included in the scope of this visitor as they are all guaranteed to be values or declare variables
|
||||
}
|
||||
}
|
||||
ExportNamedDeclaration(node) {
|
||||
if (node.source) {
|
||||
// export ... from 'foo';
|
||||
// these are external identifiers so there shouldn't be references or defs
|
||||
return;
|
||||
}
|
||||
if (!node.declaration) {
|
||||
// export { x };
|
||||
this.visitChildren(node);
|
||||
}
|
||||
else {
|
||||
// export const x = 1;
|
||||
// this is not included in the scope of this visitor as it creates a variable
|
||||
}
|
||||
}
|
||||
ExportSpecifier(node) {
|
||||
if (node.exportKind === 'type' &&
|
||||
node.local.type === types_1.AST_NODE_TYPES.Identifier) {
|
||||
// export { type T };
|
||||
// type exports can only reference types
|
||||
//
|
||||
// we can't let this fall through to the Identifier selector because the exportKind is on this node
|
||||
// and we don't have access to the `.parent` during scope analysis
|
||||
this.#referencer.currentScope().referenceType(node.local);
|
||||
}
|
||||
else {
|
||||
this.visit(node.local);
|
||||
}
|
||||
}
|
||||
Identifier(node) {
|
||||
if (this.#exportNode.exportKind === 'type') {
|
||||
// export type { T };
|
||||
// type exports can only reference types
|
||||
this.#referencer.currentScope().referenceType(node);
|
||||
}
|
||||
else {
|
||||
this.#referencer.currentScope().referenceDualValueType(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ExportVisitor = ExportVisitor;
|
||||
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce getter and setter pairs in objects and classes.
|
||||
* @author Gyandeep Singh
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Property name if it can be computed statically, otherwise the list of the tokens of the key node.
|
||||
* @typedef {string|Token[]} Key
|
||||
*/
|
||||
|
||||
/**
|
||||
* Accessor nodes with the same key.
|
||||
* @typedef {Object} AccessorData
|
||||
* @property {Key} key Accessor's key
|
||||
* @property {ASTNode[]} getters List of getter nodes.
|
||||
* @property {ASTNode[]} setters List of setter nodes.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not the given lists represent the equal tokens in the same order.
|
||||
* Tokens are compared by their properties, not by instance.
|
||||
* @param {Token[]} left First list of tokens.
|
||||
* @param {Token[]} right Second list of tokens.
|
||||
* @returns {boolean} `true` if the lists have same tokens.
|
||||
*/
|
||||
function areEqualTokenLists(left, right) {
|
||||
if (left.length !== right.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < left.length; i++) {
|
||||
const leftToken = left[i],
|
||||
rightToken = right[i];
|
||||
|
||||
if (
|
||||
leftToken.type !== rightToken.type ||
|
||||
leftToken.value !== rightToken.value
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the given keys are equal.
|
||||
* @param {Key} left First key.
|
||||
* @param {Key} right Second key.
|
||||
* @returns {boolean} `true` if the keys are equal.
|
||||
*/
|
||||
function areEqualKeys(left, right) {
|
||||
if (typeof left === "string" && typeof right === "string") {
|
||||
// Statically computed names.
|
||||
return left === right;
|
||||
}
|
||||
if (Array.isArray(left) && Array.isArray(right)) {
|
||||
// Token lists.
|
||||
return areEqualTokenLists(left, right);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is of an accessor kind ('get' or 'set').
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node is of an accessor kind.
|
||||
*/
|
||||
function isAccessorKind(node) {
|
||||
return node.kind === "get" || node.kind === "set";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
enforceForTSTypes: false,
|
||||
enforceForClassMembers: true,
|
||||
getWithoutSet: false,
|
||||
setWithoutGet: true,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce getter and setter pairs in objects and classes",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/accessor-pairs",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
getWithoutSet: {
|
||||
type: "boolean",
|
||||
},
|
||||
setWithoutGet: {
|
||||
type: "boolean",
|
||||
},
|
||||
enforceForClassMembers: {
|
||||
type: "boolean",
|
||||
},
|
||||
enforceForTSTypes: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
missingGetterInPropertyDescriptor:
|
||||
"Getter is not present in property descriptor.",
|
||||
missingSetterInPropertyDescriptor:
|
||||
"Setter is not present in property descriptor.",
|
||||
missingGetterInObjectLiteral:
|
||||
"Getter is not present for {{ name }}.",
|
||||
missingSetterInObjectLiteral:
|
||||
"Setter is not present for {{ name }}.",
|
||||
missingGetterInClass: "Getter is not present for class {{ name }}.",
|
||||
missingSetterInClass: "Setter is not present for class {{ name }}.",
|
||||
missingGetterInType: "Getter is not present for type {{ name }}.",
|
||||
missingSetterInType: "Setter is not present for type {{ name }}.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const [
|
||||
{
|
||||
getWithoutSet: checkGetWithoutSet,
|
||||
setWithoutGet: checkSetWithoutGet,
|
||||
enforceForClassMembers,
|
||||
enforceForTSTypes,
|
||||
},
|
||||
] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Reports the given node.
|
||||
* @param {ASTNode} node The node to report.
|
||||
* @param {string} messageKind "missingGetter" or "missingSetter".
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node, messageKind) {
|
||||
if (node.type === "Property") {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InObjectLiteral`,
|
||||
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node.value),
|
||||
},
|
||||
});
|
||||
} else if (node.type === "MethodDefinition") {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InClass`,
|
||||
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node.value),
|
||||
},
|
||||
});
|
||||
} else if (node.type === "TSMethodSignature") {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InType`,
|
||||
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
||||
data: {
|
||||
name: astUtils.getFunctionNameWithKind(node),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
context.report({
|
||||
node,
|
||||
messageId: `${messageKind}InPropertyDescriptor`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports each of the nodes in the given list using the same messageId.
|
||||
* @param {ASTNode[]} nodes Nodes to report.
|
||||
* @param {string} messageKind "missingGetter" or "missingSetter".
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function reportList(nodes, messageKind) {
|
||||
for (const node of nodes) {
|
||||
report(node, messageKind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks accessor pairs in the given list of nodes.
|
||||
* @param {ASTNode[]} nodes The list to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkList(nodes) {
|
||||
const accessors = [];
|
||||
let found = false;
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
|
||||
if (isAccessorKind(node)) {
|
||||
// Creates a new `AccessorData` object for the given getter or setter node.
|
||||
const name = astUtils.getStaticPropertyName(node);
|
||||
const key =
|
||||
name !== null ? name : sourceCode.getTokens(node.key);
|
||||
|
||||
// Merges the given `AccessorData` object into the given accessors list.
|
||||
for (let j = 0; j < accessors.length; j++) {
|
||||
const accessor = accessors[j];
|
||||
|
||||
if (areEqualKeys(accessor.key, key)) {
|
||||
accessor.getters.push(
|
||||
...(node.kind === "get" ? [node] : []),
|
||||
);
|
||||
accessor.setters.push(
|
||||
...(node.kind === "set" ? [node] : []),
|
||||
);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
accessors.push({
|
||||
key,
|
||||
getters: node.kind === "get" ? [node] : [],
|
||||
setters: node.kind === "set" ? [node] : [],
|
||||
});
|
||||
}
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const { getters, setters } of accessors) {
|
||||
if (checkSetWithoutGet && setters.length && !getters.length) {
|
||||
reportList(setters, "missingGetter");
|
||||
}
|
||||
if (checkGetWithoutSet && getters.length && !setters.length) {
|
||||
reportList(getters, "missingSetter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks accessor pairs in an object literal.
|
||||
* @param {ASTNode} node `ObjectExpression` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkObjectLiteral(node) {
|
||||
checkList(node.properties.filter(p => p.type === "Property"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks accessor pairs in a property descriptor.
|
||||
* @param {ASTNode} node Property descriptor `ObjectExpression` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkPropertyDescriptor(node) {
|
||||
const namesToCheck = new Set(
|
||||
node.properties
|
||||
.filter(
|
||||
p =>
|
||||
p.type === "Property" &&
|
||||
p.kind === "init" &&
|
||||
!p.computed,
|
||||
)
|
||||
.map(({ key }) => key.name),
|
||||
);
|
||||
|
||||
const hasGetter = namesToCheck.has("get");
|
||||
const hasSetter = namesToCheck.has("set");
|
||||
|
||||
if (checkSetWithoutGet && hasSetter && !hasGetter) {
|
||||
report(node, "missingGetter");
|
||||
}
|
||||
if (checkGetWithoutSet && hasGetter && !hasSetter) {
|
||||
report(node, "missingSetter");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given object expression as an object literal and as a possible property descriptor.
|
||||
* @param {ASTNode} node `ObjectExpression` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkObjectExpression(node) {
|
||||
checkObjectLiteral(node);
|
||||
if (astUtils.isPropertyDescriptor(node, sourceCode)) {
|
||||
checkPropertyDescriptor(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given class body.
|
||||
* @param {ASTNode} node `ClassBody` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkClassBody(node) {
|
||||
const methodDefinitions = node.body.filter(
|
||||
m => m.type === "MethodDefinition",
|
||||
);
|
||||
|
||||
checkList(methodDefinitions.filter(m => m.static));
|
||||
checkList(methodDefinitions.filter(m => !m.static));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given type.
|
||||
* @param {ASTNode} node `TSTypeLiteral` or `TSInterfaceBody` node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkType(node) {
|
||||
const members =
|
||||
node.type === "TSTypeLiteral" ? node.members : node.body;
|
||||
const methodDefinitions = members.filter(
|
||||
m => m.type === "TSMethodSignature",
|
||||
);
|
||||
|
||||
checkList(methodDefinitions);
|
||||
}
|
||||
|
||||
const listeners = {};
|
||||
|
||||
if (checkSetWithoutGet || checkGetWithoutSet) {
|
||||
listeners.ObjectExpression = checkObjectExpression;
|
||||
if (enforceForClassMembers) {
|
||||
listeners.ClassBody = checkClassBody;
|
||||
}
|
||||
if (enforceForTSTypes) {
|
||||
listeners["TSTypeLiteral, TSInterfaceBody"] = checkType;
|
||||
}
|
||||
}
|
||||
|
||||
return listeners;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @fileoverview Rule to disallow use of void operator.
|
||||
* @author Mike Sidorov
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allowAsStatement: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Disallow `void` operators",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-void",
|
||||
},
|
||||
|
||||
messages: {
|
||||
noVoid: "Expected 'undefined' and instead saw 'void'.",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowAsStatement: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [{ allowAsStatement }] = context.options;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
'UnaryExpression[operator="void"]'(node) {
|
||||
if (
|
||||
allowAsStatement &&
|
||||
node.parent &&
|
||||
node.parent.type === "ExpressionStatement"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId: "noVoid",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2015_promise = void 0;
|
||||
const base_config_1 = require("./base-config");
|
||||
exports.es2015_promise = {
|
||||
libs: [],
|
||||
variables: [['PromiseConstructor', base_config_1.TYPE]],
|
||||
};
|
||||
Reference in New Issue
Block a user