WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* BLS != BLS.
|
||||
* The file implements BLS (Boneh-Lynn-Shacham) signatures.
|
||||
* Used in both BLS (Barreto-Lynn-Scott) and BN (Barreto-Naehrig)
|
||||
* families of pairing-friendly curves.
|
||||
* Consists of two curves: G1 and G2:
|
||||
* - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
|
||||
* - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
|
||||
* - Gt, created by bilinear (ate) pairing e(G1, G2), consists of p-th roots of unity in
|
||||
* Fq^k where k is embedding degree. Only degree 12 is currently supported, 24 is not.
|
||||
* Pairing is used to aggregate and verify signatures.
|
||||
* There are two modes of operation:
|
||||
* - Long signatures: X-byte keys + 2X-byte sigs (G1 keys + G2 sigs).
|
||||
* - Short signatures: 2X-byte keys + X-byte sigs (G2 keys + G1 sigs).
|
||||
* @module
|
||||
**/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { type CHash, type Hex, type PrivKey } from '../utils.ts';
|
||||
import { type H2CHasher, type H2CHashOpts, type H2COpts, type htfBasicOpts, type MapToCurve } from './hash-to-curve.ts';
|
||||
import { type IField } from './modular.ts';
|
||||
import type { Fp12, Fp12Bls, Fp2, Fp2Bls, Fp6Bls } from './tower.ts';
|
||||
import { type CurvePointsRes, type CurvePointsType, type WeierstrassPoint, type WeierstrassPointCons } from './weierstrass.ts';
|
||||
type Fp = bigint;
|
||||
export type TwistType = 'multiplicative' | 'divisive';
|
||||
export type ShortSignatureCoder<Fp> = {
|
||||
fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
|
||||
fromHex(hex: Hex): WeierstrassPoint<Fp>;
|
||||
toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
toHex(point: WeierstrassPoint<Fp>): string;
|
||||
/** @deprecated use `toBytes` */
|
||||
toRawBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
};
|
||||
export type SignatureCoder<Fp> = {
|
||||
fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
|
||||
fromHex(hex: Hex): WeierstrassPoint<Fp>;
|
||||
toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
toHex(point: WeierstrassPoint<Fp>): string;
|
||||
/** @deprecated use `toBytes` */
|
||||
toRawBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
};
|
||||
export type BlsFields = {
|
||||
Fp: IField<Fp>;
|
||||
Fr: IField<bigint>;
|
||||
Fp2: Fp2Bls;
|
||||
Fp6: Fp6Bls;
|
||||
Fp12: Fp12Bls;
|
||||
};
|
||||
export type PostPrecomputePointAddFn = (Rx: Fp2, Ry: Fp2, Rz: Fp2, Qx: Fp2, Qy: Fp2) => {
|
||||
Rx: Fp2;
|
||||
Ry: Fp2;
|
||||
Rz: Fp2;
|
||||
};
|
||||
export type PostPrecomputeFn = (Rx: Fp2, Ry: Fp2, Rz: Fp2, Qx: Fp2, Qy: Fp2, pointAdd: PostPrecomputePointAddFn) => void;
|
||||
export type BlsPairing = {
|
||||
Fp12: Fp12Bls;
|
||||
calcPairingPrecomputes: (p: WeierstrassPoint<Fp2>) => Precompute;
|
||||
millerLoopBatch: (pairs: [Precompute, Fp, Fp][]) => Fp12;
|
||||
pairing: (P: WeierstrassPoint<Fp>, Q: WeierstrassPoint<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
pairingBatch: (pairs: {
|
||||
g1: WeierstrassPoint<Fp>;
|
||||
g2: WeierstrassPoint<Fp2>;
|
||||
}[], withFinalExponent?: boolean) => Fp12;
|
||||
};
|
||||
export type BlsPairingParams = {
|
||||
ateLoopSize: bigint;
|
||||
xNegative: boolean;
|
||||
twistType: TwistType;
|
||||
postPrecompute?: PostPrecomputeFn;
|
||||
};
|
||||
export type CurveType = {
|
||||
G1: CurvePointsType<Fp> & {
|
||||
ShortSignature: SignatureCoder<Fp>;
|
||||
mapToCurve: MapToCurve<Fp>;
|
||||
htfDefaults: H2COpts;
|
||||
};
|
||||
G2: CurvePointsType<Fp2> & {
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
mapToCurve: MapToCurve<Fp2>;
|
||||
htfDefaults: H2COpts;
|
||||
};
|
||||
fields: BlsFields;
|
||||
params: {
|
||||
ateLoopSize: BlsPairingParams['ateLoopSize'];
|
||||
xNegative: BlsPairingParams['xNegative'];
|
||||
r: bigint;
|
||||
twistType: BlsPairingParams['twistType'];
|
||||
};
|
||||
htfDefaults: H2COpts;
|
||||
hash: CHash;
|
||||
randomBytes?: (bytesLength?: number) => Uint8Array;
|
||||
postPrecompute?: PostPrecomputeFn;
|
||||
};
|
||||
type PrecomputeSingle = [Fp2, Fp2, Fp2][];
|
||||
type Precompute = PrecomputeSingle[];
|
||||
/**
|
||||
* BLS consists of two curves: G1 and G2:
|
||||
* - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
|
||||
* - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
|
||||
*/
|
||||
export interface BLSCurvePair {
|
||||
longSignatures: BLSSigs<bigint, Fp2>;
|
||||
shortSignatures: BLSSigs<Fp2, bigint>;
|
||||
millerLoopBatch: BlsPairing['millerLoopBatch'];
|
||||
pairing: BlsPairing['pairing'];
|
||||
pairingBatch: BlsPairing['pairingBatch'];
|
||||
G1: {
|
||||
Point: WeierstrassPointCons<bigint>;
|
||||
} & H2CHasher<Fp>;
|
||||
G2: {
|
||||
Point: WeierstrassPointCons<Fp2>;
|
||||
} & H2CHasher<Fp2>;
|
||||
fields: {
|
||||
Fp: IField<Fp>;
|
||||
Fp2: Fp2Bls;
|
||||
Fp6: Fp6Bls;
|
||||
Fp12: Fp12Bls;
|
||||
Fr: IField<bigint>;
|
||||
};
|
||||
utils: {
|
||||
randomSecretKey: () => Uint8Array;
|
||||
/** @deprecated use randomSecretKey */
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
calcPairingPrecomputes: BlsPairing['calcPairingPrecomputes'];
|
||||
};
|
||||
}
|
||||
export type CurveFn = BLSCurvePair & {
|
||||
/** @deprecated use `longSignatures.getPublicKey` */
|
||||
getPublicKey: (secretKey: PrivKey) => Uint8Array;
|
||||
/** @deprecated use `shortSignatures.getPublicKey` */
|
||||
getPublicKeyForShortSignatures: (secretKey: PrivKey) => Uint8Array;
|
||||
/** @deprecated use `longSignatures.sign` */
|
||||
sign: {
|
||||
(message: Hex, secretKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
(message: WeierstrassPoint<Fp2>, secretKey: PrivKey, htfOpts?: htfBasicOpts): WeierstrassPoint<Fp2>;
|
||||
};
|
||||
/** @deprecated use `shortSignatures.sign` */
|
||||
signShortSignature: {
|
||||
(message: Hex, secretKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
(message: WeierstrassPoint<Fp>, secretKey: PrivKey, htfOpts?: htfBasicOpts): WeierstrassPoint<Fp>;
|
||||
};
|
||||
/** @deprecated use `longSignatures.verify` */
|
||||
verify: (signature: Hex | WeierstrassPoint<Fp2>, message: Hex | WeierstrassPoint<Fp2>, publicKey: Hex | WeierstrassPoint<Fp>, htfOpts?: htfBasicOpts) => boolean;
|
||||
/** @deprecated use `shortSignatures.verify` */
|
||||
verifyShortSignature: (signature: Hex | WeierstrassPoint<Fp>, message: Hex | WeierstrassPoint<Fp>, publicKey: Hex | WeierstrassPoint<Fp2>, htfOpts?: htfBasicOpts) => boolean;
|
||||
verifyBatch: (signature: Hex | WeierstrassPoint<Fp2>, messages: (Hex | WeierstrassPoint<Fp2>)[], publicKeys: (Hex | WeierstrassPoint<Fp>)[], htfOpts?: htfBasicOpts) => boolean;
|
||||
/** @deprecated use `longSignatures.aggregatePublicKeys` */
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: WeierstrassPoint<Fp>[]): WeierstrassPoint<Fp>;
|
||||
};
|
||||
/** @deprecated use `longSignatures.aggregateSignatures` */
|
||||
aggregateSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: WeierstrassPoint<Fp2>[]): WeierstrassPoint<Fp2>;
|
||||
};
|
||||
/** @deprecated use `shortSignatures.aggregateSignatures` */
|
||||
aggregateShortSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: WeierstrassPoint<Fp>[]): WeierstrassPoint<Fp>;
|
||||
};
|
||||
G1: CurvePointsRes<Fp> & H2CHasher<Fp>;
|
||||
G2: CurvePointsRes<Fp2> & H2CHasher<Fp2>;
|
||||
/** @deprecated use `longSignatures.Signature` */
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
/** @deprecated use `shortSignatures.Signature` */
|
||||
ShortSignature: ShortSignatureCoder<Fp>;
|
||||
params: {
|
||||
ateLoopSize: bigint;
|
||||
r: bigint;
|
||||
twistType: TwistType;
|
||||
/** @deprecated */
|
||||
G1b: bigint;
|
||||
/** @deprecated */
|
||||
G2b: Fp2;
|
||||
};
|
||||
};
|
||||
type BLSInput = Hex | Uint8Array;
|
||||
export interface BLSSigs<P, S> {
|
||||
getPublicKey(secretKey: PrivKey): WeierstrassPoint<P>;
|
||||
sign(hashedMessage: WeierstrassPoint<S>, secretKey: PrivKey): WeierstrassPoint<S>;
|
||||
verify(signature: WeierstrassPoint<S> | BLSInput, message: WeierstrassPoint<S>, publicKey: WeierstrassPoint<P> | BLSInput): boolean;
|
||||
verifyBatch: (signature: WeierstrassPoint<S> | BLSInput, messages: WeierstrassPoint<S>[], publicKeys: (WeierstrassPoint<P> | BLSInput)[]) => boolean;
|
||||
aggregatePublicKeys(publicKeys: (WeierstrassPoint<P> | BLSInput)[]): WeierstrassPoint<P>;
|
||||
aggregateSignatures(signatures: (WeierstrassPoint<S> | BLSInput)[]): WeierstrassPoint<S>;
|
||||
hash(message: Uint8Array, DST?: string | Uint8Array, hashOpts?: H2CHashOpts): WeierstrassPoint<S>;
|
||||
Signature: SignatureCoder<S>;
|
||||
}
|
||||
export declare function bls(CURVE: CurveType): CurveFn;
|
||||
export {};
|
||||
//# sourceMappingURL=bls.d.ts.map
|
||||
@@ -0,0 +1,117 @@
|
||||
import type { $ZodStringFormats } from "../core/checks.js";
|
||||
import type * as errors from "../core/errors.js";
|
||||
import * as util from "../core/util.js";
|
||||
|
||||
const error: () => errors.$ZodErrorMap = () => {
|
||||
const Sizable: Record<string, { unit: string; verb: string }> = {
|
||||
string: { unit: "ký tự", verb: "có" },
|
||||
file: { unit: "byte", verb: "có" },
|
||||
array: { unit: "phần tử", verb: "có" },
|
||||
set: { unit: "phần tử", verb: "có" },
|
||||
};
|
||||
|
||||
function getSizing(origin: string): { unit: string; verb: string } | null {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
|
||||
const FormatDictionary: {
|
||||
[k in $ZodStringFormats | (string & {})]?: string;
|
||||
} = {
|
||||
regex: "đầu vào",
|
||||
email: "địa chỉ email",
|
||||
url: "URL",
|
||||
emoji: "emoji",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "ngày giờ ISO",
|
||||
date: "ngày ISO",
|
||||
time: "giờ ISO",
|
||||
duration: "khoảng thời gian ISO",
|
||||
ipv4: "địa chỉ IPv4",
|
||||
ipv6: "địa chỉ IPv6",
|
||||
cidrv4: "dải IPv4",
|
||||
cidrv6: "dải IPv6",
|
||||
base64: "chuỗi mã hóa base64",
|
||||
base64url: "chuỗi mã hóa base64url",
|
||||
json_string: "chuỗi JSON",
|
||||
e164: "số E.164",
|
||||
jwt: "JWT",
|
||||
template_literal: "đầu vào",
|
||||
};
|
||||
|
||||
const TypeDictionary: {
|
||||
[k in errors.$ZodInvalidTypeExpected | (string & {})]?: string;
|
||||
} = {
|
||||
nan: "NaN",
|
||||
number: "số",
|
||||
array: "mảng",
|
||||
};
|
||||
|
||||
return (issue) => {
|
||||
switch (issue.code) {
|
||||
case "invalid_type": {
|
||||
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
||||
const receivedType = util.parsedType(issue.input);
|
||||
const received = TypeDictionary[receivedType] ?? receivedType;
|
||||
if (/^[A-Z]/.test(issue.expected)) {
|
||||
return `Đầu vào không hợp lệ: mong đợi instanceof ${issue.expected}, nhận được ${received}`;
|
||||
}
|
||||
return `Đầu vào không hợp lệ: mong đợi ${expected}, nhận được ${received}`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1)
|
||||
return `Đầu vào không hợp lệ: mong đợi ${util.stringifyPrimitive(issue.values[0])}`;
|
||||
return `Tùy chọn không hợp lệ: mong đợi một trong các giá trị ${util.joinValues(issue.values, "|")}`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "<=" : "<";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `Quá lớn: mong đợi ${issue.origin ?? "giá trị"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "phần tử"}`;
|
||||
return `Quá lớn: mong đợi ${issue.origin ?? "giá trị"} ${adj}${issue.maximum.toString()}`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? ">=" : ">";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `Quá nhỏ: mong đợi ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
}
|
||||
|
||||
return `Quá nhỏ: mong đợi ${issue.origin} ${adj}${issue.minimum.toString()}`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue as errors.$ZodStringFormatIssues;
|
||||
if (_issue.format === "starts_with") return `Chuỗi không hợp lệ: phải bắt đầu bằng "${_issue.prefix}"`;
|
||||
if (_issue.format === "ends_with") return `Chuỗi không hợp lệ: phải kết thúc bằng "${_issue.suffix}"`;
|
||||
if (_issue.format === "includes") return `Chuỗi không hợp lệ: phải bao gồm "${_issue.includes}"`;
|
||||
if (_issue.format === "regex") return `Chuỗi không hợp lệ: phải khớp với mẫu ${_issue.pattern}`;
|
||||
return `${FormatDictionary[_issue.format] ?? issue.format} không hợp lệ`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `Số không hợp lệ: phải là bội số của ${issue.divisor}`;
|
||||
case "unrecognized_keys":
|
||||
return `Khóa không được nhận dạng: ${util.joinValues(issue.keys, ", ")}`;
|
||||
case "invalid_key":
|
||||
return `Khóa không hợp lệ trong ${issue.origin}`;
|
||||
case "invalid_union":
|
||||
return "Đầu vào không hợp lệ";
|
||||
case "invalid_element":
|
||||
return `Giá trị không hợp lệ trong ${issue.origin}`;
|
||||
default:
|
||||
return `Đầu vào không hợp lệ`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default function (): { localeError: errors.$ZodErrorMap } {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2024_arraybuffer: LibDefinition;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,48 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = errWithCauseSerializer
|
||||
|
||||
const { isErrorLike } = require('./err-helpers')
|
||||
const { pinoErrProto, pinoErrorSymbols } = require('./err-proto')
|
||||
const { seen } = pinoErrorSymbols
|
||||
|
||||
const { toString } = Object.prototype
|
||||
|
||||
function errWithCauseSerializer (err) {
|
||||
if (!isErrorLike(err)) {
|
||||
return err
|
||||
}
|
||||
|
||||
err[seen] = undefined // tag to prevent re-looking at this
|
||||
const _err = Object.create(pinoErrProto)
|
||||
_err.type = toString.call(err.constructor) === '[object Function]'
|
||||
? err.constructor.name
|
||||
: err.name
|
||||
_err.message = err.message
|
||||
_err.stack = err.stack
|
||||
|
||||
if (Array.isArray(err.errors)) {
|
||||
_err.aggregateErrors = err.errors.map(err => errWithCauseSerializer(err))
|
||||
}
|
||||
|
||||
if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) {
|
||||
_err.cause = errWithCauseSerializer(err.cause)
|
||||
}
|
||||
|
||||
for (const key in err) {
|
||||
if (_err[key] === undefined) {
|
||||
const val = err[key]
|
||||
if (isErrorLike(val)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(val, seen)) {
|
||||
_err[key] = errWithCauseSerializer(val)
|
||||
}
|
||||
} else {
|
||||
_err[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete err[seen] // clean up tag in case err is serialized again later
|
||||
_err.raw = err
|
||||
return _err
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
/// <reference lib="es2019" />
|
||||
/// <reference lib="es2020.bigint" />
|
||||
/// <reference lib="es2020.date" />
|
||||
/// <reference lib="es2020.number" />
|
||||
/// <reference lib="es2020.promise" />
|
||||
/// <reference lib="es2020.sharedmemory" />
|
||||
/// <reference lib="es2020.string" />
|
||||
/// <reference lib="es2020.symbol.wellknown" />
|
||||
/// <reference lib="es2020.intl" />
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
function _defaults(obj, defaults) {
|
||||
var keys = Object.getOwnPropertyNames(defaults);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var value = Object.getOwnPropertyDescriptor(defaults, key);
|
||||
|
||||
if (value && value.configurable && obj[key] === undefined) Object.defineProperty(obj, key, value);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
exports._ = _defaults;
|
||||
@@ -0,0 +1,233 @@
|
||||
// @ts-ignore TS6133
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
import * as z from "zod/v3";
|
||||
import { util } from "../helpers/util.js";
|
||||
|
||||
const stringToNumber = z.string().transform((arg) => Number.parseFloat(arg));
|
||||
// const numberToString = z
|
||||
// .transformer(z.number())
|
||||
// .transform((n) => String(n));
|
||||
const asyncNumberToString = z.number().transform(async (n) => String(n));
|
||||
|
||||
test("transform ctx.addIssue with parse", () => {
|
||||
const strs = ["foo", "bar"];
|
||||
|
||||
expect(() => {
|
||||
z.string()
|
||||
.transform((data, ctx) => {
|
||||
const i = strs.indexOf(data);
|
||||
if (i === -1) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: `${data} is not one of our allowed strings`,
|
||||
});
|
||||
}
|
||||
return data.length;
|
||||
})
|
||||
.parse("asdf");
|
||||
}).toThrow(
|
||||
JSON.stringify(
|
||||
[
|
||||
{
|
||||
code: "custom",
|
||||
message: "asdf is not one of our allowed strings",
|
||||
path: [],
|
||||
},
|
||||
],
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test("transform ctx.addIssue with parseAsync", async () => {
|
||||
const strs = ["foo", "bar"];
|
||||
|
||||
const result = await z
|
||||
.string()
|
||||
.transform(async (data, ctx) => {
|
||||
const i = strs.indexOf(data);
|
||||
if (i === -1) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: `${data} is not one of our allowed strings`,
|
||||
});
|
||||
}
|
||||
return data.length;
|
||||
})
|
||||
.safeParseAsync("asdf");
|
||||
|
||||
expect(JSON.parse(JSON.stringify(result))).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
issues: [
|
||||
{
|
||||
code: "custom",
|
||||
message: "asdf is not one of our allowed strings",
|
||||
path: [],
|
||||
},
|
||||
],
|
||||
name: "ZodError",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("z.NEVER in transform", () => {
|
||||
const foo = z
|
||||
.number()
|
||||
.optional()
|
||||
.transform((val, ctx) => {
|
||||
if (!val) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "bad" });
|
||||
return z.NEVER;
|
||||
}
|
||||
return val;
|
||||
});
|
||||
type foo = z.infer<typeof foo>;
|
||||
util.assertEqual<foo, number>(true);
|
||||
const arg = foo.safeParse(undefined);
|
||||
if (!arg.success) {
|
||||
expect(arg.error.issues[0].message).toEqual("bad");
|
||||
}
|
||||
});
|
||||
|
||||
test("basic transformations", () => {
|
||||
const r1 = z
|
||||
.string()
|
||||
.transform((data) => data.length)
|
||||
.parse("asdf");
|
||||
expect(r1).toEqual(4);
|
||||
});
|
||||
|
||||
test("coercion", () => {
|
||||
const numToString = z.number().transform((n) => String(n));
|
||||
const data = z
|
||||
.object({
|
||||
id: numToString,
|
||||
})
|
||||
.parse({ id: 5 });
|
||||
|
||||
expect(data).toEqual({ id: "5" });
|
||||
});
|
||||
|
||||
test("async coercion", async () => {
|
||||
const numToString = z.number().transform(async (n) => String(n));
|
||||
const data = await z
|
||||
.object({
|
||||
id: numToString,
|
||||
})
|
||||
.parseAsync({ id: 5 });
|
||||
|
||||
expect(data).toEqual({ id: "5" });
|
||||
});
|
||||
|
||||
test("sync coercion async error", async () => {
|
||||
expect(() =>
|
||||
z
|
||||
.object({
|
||||
id: asyncNumberToString,
|
||||
})
|
||||
.parse({ id: 5 })
|
||||
).toThrow();
|
||||
// expect(data).toEqual({ id: '5' });
|
||||
});
|
||||
|
||||
test("default", () => {
|
||||
const data = z.string().default("asdf").parse(undefined); // => "asdf"
|
||||
expect(data).toEqual("asdf");
|
||||
});
|
||||
|
||||
test("dynamic default", () => {
|
||||
const data = z
|
||||
.string()
|
||||
.default(() => "string")
|
||||
.parse(undefined); // => "asdf"
|
||||
expect(data).toEqual("string");
|
||||
});
|
||||
|
||||
test("default when property is null or undefined", () => {
|
||||
const data = z
|
||||
.object({
|
||||
foo: z.boolean().nullable().default(true),
|
||||
bar: z.boolean().default(true),
|
||||
})
|
||||
.parse({ foo: null });
|
||||
|
||||
expect(data).toEqual({ foo: null, bar: true });
|
||||
});
|
||||
|
||||
test("default with falsy values", () => {
|
||||
const schema = z.object({
|
||||
emptyStr: z.string().default("def"),
|
||||
zero: z.number().default(5),
|
||||
falseBoolean: z.boolean().default(true),
|
||||
});
|
||||
const input = { emptyStr: "", zero: 0, falseBoolean: true };
|
||||
const output = schema.parse(input);
|
||||
// defaults are not supposed to be used
|
||||
expect(output).toEqual(input);
|
||||
});
|
||||
|
||||
test("object typing", () => {
|
||||
const t1 = z.object({
|
||||
stringToNumber,
|
||||
});
|
||||
|
||||
type t1 = z.input<typeof t1>;
|
||||
type t2 = z.output<typeof t1>;
|
||||
|
||||
util.assertEqual<t1, { stringToNumber: string }>(true);
|
||||
util.assertEqual<t2, { stringToNumber: number }>(true);
|
||||
});
|
||||
|
||||
test("transform method overloads", () => {
|
||||
const t1 = z.string().transform((val) => val.toUpperCase());
|
||||
expect(t1.parse("asdf")).toEqual("ASDF");
|
||||
|
||||
const t2 = z.string().transform((val) => val.length);
|
||||
expect(t2.parse("asdf")).toEqual(4);
|
||||
});
|
||||
|
||||
test("multiple transformers", () => {
|
||||
const doubler = stringToNumber.transform((val) => {
|
||||
return val * 2;
|
||||
});
|
||||
expect(doubler.parse("5")).toEqual(10);
|
||||
});
|
||||
|
||||
test("short circuit on dirty", () => {
|
||||
const schema = z
|
||||
.string()
|
||||
.refine(() => false)
|
||||
.transform((val) => val.toUpperCase());
|
||||
const result = schema.safeParse("asdf");
|
||||
expect(result.success).toEqual(false);
|
||||
if (!result.success) {
|
||||
expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom);
|
||||
}
|
||||
|
||||
const result2 = schema.safeParse(1234);
|
||||
expect(result2.success).toEqual(false);
|
||||
if (!result2.success) {
|
||||
expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type);
|
||||
}
|
||||
});
|
||||
|
||||
test("async short circuit on dirty", async () => {
|
||||
const schema = z
|
||||
.string()
|
||||
.refine(() => false)
|
||||
.transform((val) => val.toUpperCase());
|
||||
const result = await schema.spa("asdf");
|
||||
expect(result.success).toEqual(false);
|
||||
if (!result.success) {
|
||||
expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.custom);
|
||||
}
|
||||
|
||||
const result2 = await schema.spa(1234);
|
||||
expect(result2.success).toEqual(false);
|
||||
if (!result2.success) {
|
||||
expect(result2.error.issues[0].code).toEqual(z.ZodIssueCode.invalid_type);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export { _ as default } from "../esm/_class_static_private_field_update.js";
|
||||
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const { ESLint } = require("./eslint");
|
||||
|
||||
module.exports = {
|
||||
ESLint,
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "stream-json",
|
||||
"version": "1.9.1",
|
||||
"description": "stream-json is the micro-library of Node.js stream components for creating custom JSON processing pipelines with a minimal memory footprint. It can parse JSON files far exceeding available memory streaming individual primitives using a SAX-inspired API. Includes utilities to stream JSON database dumps.",
|
||||
"homepage": "http://github.com/uhop/stream-json",
|
||||
"bugs": "http://github.com/uhop/stream-json/issues",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"test": "tests"
|
||||
},
|
||||
"dependencies": {
|
||||
"stream-chain": "^2.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"heya-unit": "^0.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node tests/tests.js",
|
||||
"debug": "node --inspect-brk tests/tests.js"
|
||||
},
|
||||
"github": "http://github.com/uhop/stream-json",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/uhop/stream-json.git"
|
||||
},
|
||||
"keywords": [
|
||||
"scanner",
|
||||
"lexer",
|
||||
"tokenizer",
|
||||
"parser",
|
||||
"django",
|
||||
"stream",
|
||||
"streaming",
|
||||
"json"
|
||||
],
|
||||
"author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (http://lazutkin.com/)",
|
||||
"license": "BSD-3-Clause",
|
||||
"files": [
|
||||
"/*.js",
|
||||
"/filters",
|
||||
"/jsonl",
|
||||
"/streamers",
|
||||
"/utils"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
'use strict'
|
||||
|
||||
let pico = require('picocolors')
|
||||
|
||||
let terminalHighlight = require('./terminal-highlight')
|
||||
|
||||
class CssSyntaxError extends Error {
|
||||
constructor(message, line, column, source, file, plugin) {
|
||||
super(message)
|
||||
this.name = 'CssSyntaxError'
|
||||
this.reason = message
|
||||
|
||||
if (file) {
|
||||
this.file = file
|
||||
}
|
||||
if (source) {
|
||||
this.source = source
|
||||
}
|
||||
if (plugin) {
|
||||
this.plugin = plugin
|
||||
}
|
||||
if (typeof line !== 'undefined' && typeof column !== 'undefined') {
|
||||
if (typeof line === 'number') {
|
||||
this.line = line
|
||||
this.column = column
|
||||
} else {
|
||||
this.line = line.line
|
||||
this.column = line.column
|
||||
this.endLine = column.line
|
||||
this.endColumn = column.column
|
||||
}
|
||||
}
|
||||
|
||||
this.setMessage()
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, CssSyntaxError)
|
||||
}
|
||||
}
|
||||
|
||||
setMessage() {
|
||||
this.message = this.plugin ? this.plugin + ': ' : ''
|
||||
this.message += this.file ? this.file : '<css input>'
|
||||
if (typeof this.line !== 'undefined') {
|
||||
this.message += ':' + this.line + ':' + this.column
|
||||
}
|
||||
this.message += ': ' + this.reason
|
||||
}
|
||||
|
||||
showSourceCode(color) {
|
||||
if (!this.source) return ''
|
||||
|
||||
let css = this.source
|
||||
if (color == null) color = pico.isColorSupported
|
||||
|
||||
let aside = text => text
|
||||
let mark = text => text
|
||||
let highlight = text => text
|
||||
if (color) {
|
||||
let { bold, gray, red } = pico.createColors(true)
|
||||
mark = text => bold(red(text))
|
||||
aside = text => gray(text)
|
||||
if (terminalHighlight) {
|
||||
highlight = text => terminalHighlight(text)
|
||||
}
|
||||
}
|
||||
|
||||
let lines = css.split(/\r?\n/)
|
||||
let start = Math.max(this.line - 3, 0)
|
||||
let end = Math.min(this.line + 2, lines.length)
|
||||
let maxWidth = String(end).length
|
||||
|
||||
return lines
|
||||
.slice(start, end)
|
||||
.map((line, index) => {
|
||||
let number = start + 1 + index
|
||||
let gutter = ' ' + (' ' + number).slice(-maxWidth) + ' | '
|
||||
if (number === this.line) {
|
||||
if (line.length > 160) {
|
||||
let padding = 20
|
||||
let subLineStart = Math.max(0, this.column - padding)
|
||||
let subLineEnd = Math.max(
|
||||
this.column + padding,
|
||||
this.endColumn + padding
|
||||
)
|
||||
let subLine = line.slice(subLineStart, subLineEnd)
|
||||
|
||||
let spacing =
|
||||
aside(gutter.replace(/\d/g, ' ')) +
|
||||
line
|
||||
.slice(0, Math.min(this.column - 1, padding - 1))
|
||||
.replace(/[^\t]/g, ' ')
|
||||
|
||||
return (
|
||||
mark('>') +
|
||||
aside(gutter) +
|
||||
highlight(subLine) +
|
||||
'\n ' +
|
||||
spacing +
|
||||
mark('^')
|
||||
)
|
||||
}
|
||||
|
||||
let spacing =
|
||||
aside(gutter.replace(/\d/g, ' ')) +
|
||||
line.slice(0, this.column - 1).replace(/[^\t]/g, ' ')
|
||||
|
||||
return (
|
||||
mark('>') +
|
||||
aside(gutter) +
|
||||
highlight(line) +
|
||||
'\n ' +
|
||||
spacing +
|
||||
mark('^')
|
||||
)
|
||||
}
|
||||
|
||||
return ' ' + aside(gutter) + highlight(line)
|
||||
})
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
toString() {
|
||||
let code = this.showSourceCode()
|
||||
if (code) {
|
||||
code = '\n\n' + code + '\n'
|
||||
}
|
||||
return this.name + ': ' + this.message + code
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CssSyntaxError
|
||||
CssSyntaxError.default = CssSyntaxError
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,53 @@
|
||||
import { CompareKeys } from '@vitest/pretty-format';
|
||||
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
type DiffOptionsColor = (arg: string) => string;
|
||||
interface DiffOptions {
|
||||
aAnnotation?: string;
|
||||
aColor?: DiffOptionsColor;
|
||||
aIndicator?: string;
|
||||
bAnnotation?: string;
|
||||
bColor?: DiffOptionsColor;
|
||||
bIndicator?: string;
|
||||
changeColor?: DiffOptionsColor;
|
||||
changeLineTrailingSpaceColor?: DiffOptionsColor;
|
||||
commonColor?: DiffOptionsColor;
|
||||
commonIndicator?: string;
|
||||
commonLineTrailingSpaceColor?: DiffOptionsColor;
|
||||
contextLines?: number;
|
||||
emptyFirstOrLastLinePlaceholder?: string;
|
||||
expand?: boolean;
|
||||
includeChangeCounts?: boolean;
|
||||
omitAnnotationLines?: boolean;
|
||||
patchColor?: DiffOptionsColor;
|
||||
printBasicPrototype?: boolean;
|
||||
maxDepth?: number;
|
||||
compareKeys?: CompareKeys;
|
||||
truncateThreshold?: number;
|
||||
truncateAnnotation?: string;
|
||||
truncateAnnotationColor?: DiffOptionsColor;
|
||||
}
|
||||
interface SerializedDiffOptions {
|
||||
aAnnotation?: string;
|
||||
aIndicator?: string;
|
||||
bAnnotation?: string;
|
||||
bIndicator?: string;
|
||||
commonIndicator?: string;
|
||||
contextLines?: number;
|
||||
emptyFirstOrLastLinePlaceholder?: string;
|
||||
expand?: boolean;
|
||||
includeChangeCounts?: boolean;
|
||||
omitAnnotationLines?: boolean;
|
||||
printBasicPrototype?: boolean;
|
||||
maxDepth?: number;
|
||||
truncateThreshold?: number;
|
||||
truncateAnnotation?: string;
|
||||
}
|
||||
|
||||
export type { DiffOptions as D, SerializedDiffOptions as S, DiffOptionsColor as a };
|
||||
@@ -0,0 +1,6 @@
|
||||
var getPrototypeOf = require("./getPrototypeOf.js");
|
||||
function _superPropBase(t, o) {
|
||||
for (; !{}.hasOwnProperty.call(t, o) && null !== (t = getPrototypeOf(t)););
|
||||
return t;
|
||||
}
|
||||
module.exports = _superPropBase, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_inherits_loose.cjs",
|
||||
"module": "../../esm/_inherits_loose.js"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"p521.js","sourceRoot":"","sources":["../src/p521.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,sEAAsE;AACtE,OAAO,EAAkB,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,WAAW,CAAC;AACvD,sEAAsE;AACtE,MAAM,CAAC,MAAM,IAAI,GAAiB,KAAK,CAAC;AACxC,sEAAsE;AACtE,MAAM,CAAC,MAAM,SAAS,GAAiB,KAAK,CAAC;AAC7C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAsB,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC;AAChG,6EAA6E;AAC7E,MAAM,CAAC,MAAM,aAAa,GAAsB,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC"}
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = null
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,453 @@
|
||||
/**
|
||||
* @fileoverview A rule to verify `super()` callings in constructor.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether or not a given node is a constructor.
|
||||
* @param {ASTNode} node A node to check. This node type is one of
|
||||
* `Program`, `FunctionDeclaration`, `FunctionExpression`, and
|
||||
* `ArrowFunctionExpression`.
|
||||
* @returns {boolean} `true` if the node is a constructor.
|
||||
*/
|
||||
function isConstructorFunction(node) {
|
||||
return (
|
||||
node.type === "FunctionExpression" &&
|
||||
node.parent.type === "MethodDefinition" &&
|
||||
node.parent.kind === "constructor"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given node can be a constructor or not.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} `true` if the node can be a constructor.
|
||||
*/
|
||||
function isPossibleConstructor(node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case "ClassExpression":
|
||||
case "FunctionExpression":
|
||||
case "ThisExpression":
|
||||
case "MemberExpression":
|
||||
case "CallExpression":
|
||||
case "NewExpression":
|
||||
case "ChainExpression":
|
||||
case "YieldExpression":
|
||||
case "TaggedTemplateExpression":
|
||||
case "MetaProperty":
|
||||
return true;
|
||||
|
||||
case "Identifier":
|
||||
return node.name !== "undefined";
|
||||
|
||||
case "AssignmentExpression":
|
||||
if (["=", "&&="].includes(node.operator)) {
|
||||
return isPossibleConstructor(node.right);
|
||||
}
|
||||
|
||||
if (["||=", "??="].includes(node.operator)) {
|
||||
return (
|
||||
isPossibleConstructor(node.left) ||
|
||||
isPossibleConstructor(node.right)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* All other assignment operators are mathematical assignment operators (arithmetic or bitwise).
|
||||
* An assignment expression with a mathematical operator can either evaluate to a primitive value,
|
||||
* or throw, depending on the operands. Thus, it cannot evaluate to a constructor function.
|
||||
*/
|
||||
return false;
|
||||
|
||||
case "LogicalExpression":
|
||||
/*
|
||||
* If the && operator short-circuits, the left side was falsy and therefore not a constructor, and if
|
||||
* it doesn't short-circuit, it takes the value from the right side, so the right side must always be a
|
||||
* possible constructor. A future improvement could verify that the left side could be truthy by
|
||||
* excluding falsy literals.
|
||||
*/
|
||||
if (node.operator === "&&") {
|
||||
return isPossibleConstructor(node.right);
|
||||
}
|
||||
|
||||
return (
|
||||
isPossibleConstructor(node.left) ||
|
||||
isPossibleConstructor(node.right)
|
||||
);
|
||||
|
||||
case "ConditionalExpression":
|
||||
return (
|
||||
isPossibleConstructor(node.alternate) ||
|
||||
isPossibleConstructor(node.consequent)
|
||||
);
|
||||
|
||||
case "SequenceExpression": {
|
||||
const lastExpression = node.expressions.at(-1);
|
||||
|
||||
return isPossibleConstructor(lastExpression);
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to store information about a code path segment.
|
||||
*/
|
||||
class SegmentInfo {
|
||||
/**
|
||||
* Indicates if super() is called in all code paths.
|
||||
* @type {boolean}
|
||||
*/
|
||||
calledInEveryPaths = false;
|
||||
|
||||
/**
|
||||
* Indicates if super() is called in any code paths.
|
||||
* @type {boolean}
|
||||
*/
|
||||
calledInSomePaths = false;
|
||||
|
||||
/**
|
||||
* The nodes which have been validated and don't need to be reconsidered.
|
||||
* @type {ASTNode[]}
|
||||
*/
|
||||
validNodes = [];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "Require `super()` calls in constructors",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/constructor-super",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
missingSome: "Lacked a call of 'super()' in some code paths.",
|
||||
missingAll: "Expected to call 'super()'.",
|
||||
|
||||
duplicate: "Unexpected duplicate 'super()'.",
|
||||
badSuper:
|
||||
"Unexpected 'super()' because 'super' is not a constructor.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
/*
|
||||
* {{hasExtends: boolean, scope: Scope, codePath: CodePath}[]}
|
||||
* Information for each constructor.
|
||||
* - upper: Information of the upper constructor.
|
||||
* - hasExtends: A flag which shows whether own class has a valid `extends`
|
||||
* part.
|
||||
* - scope: The scope of own class.
|
||||
* - codePath: The code path object of the constructor.
|
||||
*/
|
||||
let funcInfo = null;
|
||||
|
||||
/**
|
||||
* @type {Record<string, SegmentInfo>}
|
||||
*/
|
||||
const segInfoMap = Object.create(null);
|
||||
|
||||
/**
|
||||
* Gets the flag which shows `super()` is called in some paths.
|
||||
* @param {CodePathSegment} segment A code path segment to get.
|
||||
* @returns {boolean} The flag which shows `super()` is called in some paths
|
||||
*/
|
||||
function isCalledInSomePath(segment) {
|
||||
return (
|
||||
segment.reachable && segInfoMap[segment.id].calledInSomePaths
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a segment has been seen in the traversal.
|
||||
* @param {CodePathSegment} segment A code path segment to check.
|
||||
* @returns {boolean} `true` if the segment has been seen.
|
||||
*/
|
||||
function hasSegmentBeenSeen(segment) {
|
||||
return !!segInfoMap[segment.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag which shows `super()` is called in all paths.
|
||||
* @param {CodePathSegment} segment A code path segment to get.
|
||||
* @returns {boolean} The flag which shows `super()` is called in all paths.
|
||||
*/
|
||||
function isCalledInEveryPath(segment) {
|
||||
return (
|
||||
segment.reachable && segInfoMap[segment.id].calledInEveryPaths
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Stacks a constructor information.
|
||||
* @param {CodePath} codePath A code path which was started.
|
||||
* @param {ASTNode} node The current node.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathStart(codePath, node) {
|
||||
if (isConstructorFunction(node)) {
|
||||
// Class > ClassBody > MethodDefinition > FunctionExpression
|
||||
const classNode = node.parent.parent.parent;
|
||||
const superClass = classNode.superClass;
|
||||
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
isConstructor: true,
|
||||
hasExtends: Boolean(superClass),
|
||||
superIsConstructor: isPossibleConstructor(superClass),
|
||||
codePath,
|
||||
currentSegments: new Set(),
|
||||
};
|
||||
} else {
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
isConstructor: false,
|
||||
hasExtends: false,
|
||||
superIsConstructor: false,
|
||||
codePath,
|
||||
currentSegments: new Set(),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Pops a constructor information.
|
||||
* And reports if `super()` lacked.
|
||||
* @param {CodePath} codePath A code path which was ended.
|
||||
* @param {ASTNode} node The current node.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathEnd(codePath, node) {
|
||||
const hasExtends = funcInfo.hasExtends;
|
||||
|
||||
// Pop.
|
||||
funcInfo = funcInfo.upper;
|
||||
|
||||
if (!hasExtends) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reports if `super()` lacked.
|
||||
const returnedSegments = codePath.returnedSegments;
|
||||
const calledInEveryPaths =
|
||||
returnedSegments.every(isCalledInEveryPath);
|
||||
const calledInSomePaths =
|
||||
returnedSegments.some(isCalledInSomePath);
|
||||
|
||||
if (!calledInEveryPaths) {
|
||||
context.report({
|
||||
messageId: calledInSomePaths
|
||||
? "missingSome"
|
||||
: "missingAll",
|
||||
node: node.parent,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize information of a given code path segment.
|
||||
* @param {CodePathSegment} segment A code path segment to initialize.
|
||||
* @param {CodePathSegment} node Node that starts the segment.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathSegmentStart(segment, node) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize info.
|
||||
const info = (segInfoMap[segment.id] = new SegmentInfo());
|
||||
|
||||
const seenPrevSegments =
|
||||
segment.prevSegments.filter(hasSegmentBeenSeen);
|
||||
|
||||
// When there are previous segments, aggregates these.
|
||||
if (seenPrevSegments.length > 0) {
|
||||
info.calledInSomePaths =
|
||||
seenPrevSegments.some(isCalledInSomePath);
|
||||
info.calledInEveryPaths =
|
||||
seenPrevSegments.every(isCalledInEveryPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* ForStatement > *.update segments are a special case as they are created in advance,
|
||||
* without seen previous segments. Since they logically don't affect `calledInEveryPaths`
|
||||
* calculations, and they can never be a lone previous segment of another one, we'll set
|
||||
* their `calledInEveryPaths` to `true` to effectively ignore them in those calculations.
|
||||
* .
|
||||
*/
|
||||
if (
|
||||
node.parent &&
|
||||
node.parent.type === "ForStatement" &&
|
||||
node.parent.update === node
|
||||
) {
|
||||
info.calledInEveryPaths = true;
|
||||
}
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentStart(segment) {
|
||||
funcInfo.currentSegments.add(segment);
|
||||
},
|
||||
|
||||
onUnreachableCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
onCodePathSegmentEnd(segment) {
|
||||
funcInfo.currentSegments.delete(segment);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update information of the code path segment when a code path was
|
||||
* looped.
|
||||
* @param {CodePathSegment} fromSegment The code path segment of the
|
||||
* end of a loop.
|
||||
* @param {CodePathSegment} toSegment A code path segment of the head
|
||||
* of a loop.
|
||||
* @returns {void}
|
||||
*/
|
||||
onCodePathSegmentLoop(fromSegment, toSegment) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
funcInfo.codePath.traverseSegments(
|
||||
{ first: toSegment, last: fromSegment },
|
||||
(segment, controller) => {
|
||||
const info = segInfoMap[segment.id];
|
||||
|
||||
// skip segments after the loop
|
||||
if (!info) {
|
||||
controller.skip();
|
||||
return;
|
||||
}
|
||||
|
||||
const seenPrevSegments =
|
||||
segment.prevSegments.filter(hasSegmentBeenSeen);
|
||||
const calledInSomePreviousPaths =
|
||||
seenPrevSegments.some(isCalledInSomePath);
|
||||
const calledInEveryPreviousPaths =
|
||||
seenPrevSegments.every(isCalledInEveryPath);
|
||||
|
||||
info.calledInSomePaths ||= calledInSomePreviousPaths;
|
||||
info.calledInEveryPaths ||= calledInEveryPreviousPaths;
|
||||
|
||||
// If flags become true anew, reports the valid nodes.
|
||||
if (calledInSomePreviousPaths) {
|
||||
const nodes = info.validNodes;
|
||||
|
||||
info.validNodes = [];
|
||||
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
const node = nodes[i];
|
||||
|
||||
context.report({
|
||||
messageId: "duplicate",
|
||||
node,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks for a call of `super()`.
|
||||
* @param {ASTNode} node A CallExpression node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
"CallExpression:exit"(node) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skips except `super()`.
|
||||
if (node.callee.type !== "Super") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reports if needed.
|
||||
const segments = funcInfo.currentSegments;
|
||||
let duplicate = false;
|
||||
let info = null;
|
||||
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
info = segInfoMap[segment.id];
|
||||
|
||||
duplicate = duplicate || info.calledInSomePaths;
|
||||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (info) {
|
||||
if (duplicate) {
|
||||
context.report({
|
||||
messageId: "duplicate",
|
||||
node,
|
||||
});
|
||||
} else if (!funcInfo.superIsConstructor) {
|
||||
context.report({
|
||||
messageId: "badSuper",
|
||||
node,
|
||||
});
|
||||
} else {
|
||||
info.validNodes.push(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the mark to the returned path as `super()` was called.
|
||||
* @param {ASTNode} node A ReturnStatement node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
ReturnStatement(node) {
|
||||
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skips if no argument.
|
||||
if (!node.argument) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Returning argument is a substitute of 'super()'.
|
||||
const segments = funcInfo.currentSegments;
|
||||
|
||||
for (const segment of segments) {
|
||||
if (segment.reachable) {
|
||||
const info = segInfoMap[segment.id];
|
||||
|
||||
info.calledInSomePaths = info.calledInEveryPaths = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user