WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,662 @@
|
||||
[![npm][npm-image]][npm-url]
|
||||
[![npm-downloads][npm-downloads-image]][npm-url]
|
||||
<br />
|
||||
[![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]
|
||||
|
||||
[code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
|
||||
[code-style-prettier-url]: https://github.com/prettier/prettier
|
||||
[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/codecs-core?style=flat
|
||||
[npm-image]: https://img.shields.io/npm/v/@solana/codecs-core?style=flat
|
||||
[npm-url]: https://www.npmjs.com/package/@solana/codecs-core
|
||||
|
||||
# @solana/codecs-core
|
||||
|
||||
This package contains the core types and functions for encoding and decoding data structures on Solana. It can be used standalone, but it is also exported as part of Kit [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
|
||||
|
||||
This package is also part of the [`@solana/codecs` package](https://github.com/anza-xyz/kit/tree/main/packages/codecs) which acts as an entry point for all codec packages as well as for their documentation.
|
||||
|
||||
## Composing codecs
|
||||
|
||||
The easiest way to create your own codecs is to compose the [various codecs](https://github.com/anza-xyz/kit/tree/main/packages/codecs) offered by this library. For instance, here’s how you would define a codec for a `Person` object that contains a `name` string attribute and an `age` number stored in 4 bytes.
|
||||
|
||||
```ts
|
||||
type Person = { name: string; age: number };
|
||||
const getPersonCodec = (): Codec<Person> =>
|
||||
getStructCodec([
|
||||
['name', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
|
||||
['age', getU32Codec()],
|
||||
]);
|
||||
```
|
||||
|
||||
This function returns a `Codec` object which contains both an `encode` and `decode` function that can be used to convert a `Person` type to and from a `Uint8Array`.
|
||||
|
||||
```ts
|
||||
const personCodec = getPersonCodec();
|
||||
const bytes = personCodec.encode({ name: 'John', age: 42 });
|
||||
const person = personCodec.decode(bytes);
|
||||
```
|
||||
|
||||
There is a significant library of composable codecs at your disposal, enabling you to compose complex types. You may be interested in the documentation of these other packages to learn more about them:
|
||||
|
||||
- [`@solana/codecs-numbers`](https://github.com/anza-xyz/kit/tree/main/packages/codecs-numbers) for number codecs.
|
||||
- [`@solana/codecs-strings`](https://github.com/anza-xyz/kit/tree/main/packages/codecs-strings) for string codecs.
|
||||
- [`@solana/codecs-data-structures`](https://github.com/anza-xyz/kit/tree/main/packages/codecs-data-structures) for many data structure codecs such as objects, arrays, tuples, sets, maps, enums, discriminated unions, booleans, etc.
|
||||
- [`@solana/options`](https://github.com/anza-xyz/kit/tree/main/packages/options) for a Rust-like `Option` type and associated codec.
|
||||
|
||||
You may also be interested in some of the helpers of this `@solana/codecs-core` library such as `transformCodec`, `fixCodecSize` or `reverseCodec` that create new codecs from existing ones.
|
||||
|
||||
Note that all of these libraries are included in the [`@solana/codecs` package](https://github.com/anza-xyz/kit/tree/main/packages/codecs) as well as the main `@solana/kit` package for your convenience.
|
||||
|
||||
## Composing encoders and decoders
|
||||
|
||||
Whilst Codecs can both encode and decode, it is possible to only focus on encoding or decoding data, enabling the unused logic to be tree-shaken. For instance, here’s our previous example using Encoders only to encode a `Person` type.
|
||||
|
||||
```ts
|
||||
const getPersonEncoder = (): Encoder<Person> =>
|
||||
getStructEncoder([
|
||||
['name', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
|
||||
['age', getU32Encoder()],
|
||||
]);
|
||||
|
||||
const bytes = getPersonEncoder().encode({ name: 'John', age: 42 });
|
||||
```
|
||||
|
||||
The same can be done for decoding the `Person` type by using Decoders like so.
|
||||
|
||||
```ts
|
||||
const getPersonDecoder = (): Decoder<Person> =>
|
||||
getStructDecoder([
|
||||
['name', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
|
||||
['age', getU32Decoder()],
|
||||
]);
|
||||
|
||||
const person = getPersonDecoder().decode(bytes);
|
||||
```
|
||||
|
||||
## Combining encoders and decoders
|
||||
|
||||
Separating Codecs into Encoders and Decoders is particularly good practice for library maintainers as it allows their users to tree-shake any of the encoders and/or decoders they don’t need. However, we may still want to offer a codec helper for users who need both for convenience.
|
||||
|
||||
That’s why this library offers a `combineCodec` helper that creates a `Codec` instance from a matching `Encoder` and `Decoder`.
|
||||
|
||||
```ts
|
||||
const getPersonCodec = (): Codec<Person> => combineCodec(getPersonEncoder(), getPersonDecoder());
|
||||
```
|
||||
|
||||
This means library maintainers can offer Encoders, Decoders and Codecs for all their types whilst staying efficient and tree-shakeable. In summary, we recommend the following pattern when creating codecs for library types.
|
||||
|
||||
```ts
|
||||
type MyType = /* ... */;
|
||||
const getMyTypeEncoder = (): Encoder<MyType> => { /* ... */ };
|
||||
const getMyTypeDecoder = (): Decoder<MyType> => { /* ... */ };
|
||||
const getMyTypeCodec = (): Codec<MyType> =>
|
||||
combineCodec(getMyTypeEncoder(), getMyTypeDecoder());
|
||||
```
|
||||
|
||||
## Different From and To types
|
||||
|
||||
When creating codecs, the encoded type is allowed to be looser than the decoded type. A good example of that is the u64 number codec:
|
||||
|
||||
```ts
|
||||
const u64Codec: Codec<number | bigint, bigint> = getU64Codec();
|
||||
```
|
||||
|
||||
As you can see, the first type parameter is looser since it accepts numbers or big integers, whereas the second type parameter only accepts big integers. That’s because when _encoding_ a u64 number, you may provide either a `bigint` or a `number` for convenience. However, when you decode a u64 number, you will always get a `bigint` because not all u64 values can fit in a JavaScript `number` type.
|
||||
|
||||
```ts
|
||||
const bytes = u64Codec.encode(42);
|
||||
const value = u64Codec.decode(bytes); // BigInt(42)
|
||||
```
|
||||
|
||||
This relationship between the type we encode “From” and decode “To” can be generalized in TypeScript as `To extends From`.
|
||||
|
||||
Here’s another example using an object with default values. You can read more about the `transformEncoder` helper below.
|
||||
|
||||
```ts
|
||||
type Person = { name: string, age: number };
|
||||
type PersonInput = { name: string, age?: number };
|
||||
|
||||
const getPersonEncoder = (): Encoder<PersonInput> =>
|
||||
transformEncoder(
|
||||
getStructEncoder([
|
||||
['name', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
|
||||
['age', getU32Encoder()],
|
||||
]),
|
||||
input => { ...input, age: input.age ?? 42 }
|
||||
);
|
||||
|
||||
const getPersonDecoder = (): Decoder<Person> =>
|
||||
getStructDecoder([
|
||||
['name', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
|
||||
['age', getU32Decoder()],
|
||||
]);
|
||||
|
||||
const getPersonCodec = (): Codec<PersonInput, Person> =>
|
||||
combineCodec(getPersonEncoder(), getPersonDecoder())
|
||||
```
|
||||
|
||||
## Fixed-size and variable-size codecs
|
||||
|
||||
It is also worth noting that Codecs can either be of fixed size or variable size.
|
||||
|
||||
`FixedSizeCodecs` have a `fixedSize` number attribute that tells us exactly how big their encoded data is in bytes.
|
||||
|
||||
```ts
|
||||
const myCodec: FixedSizeCodec<number> = getU32Codec();
|
||||
myCodec.fixedSize; // 4 bytes.
|
||||
```
|
||||
|
||||
On the other hand, `VariableSizeCodecs` do not know the size of their encoded data in advance. Instead, they will grab that information either from the provided encoded data or from the value to encode. For the former, we can simply access the length of the `Uint8Array`. For the latter, it provides a `getSizeFromValue` that tells us the encoded byte size of the provided value.
|
||||
|
||||
```ts
|
||||
const myCodec: VariableSizeCodec<string> = addCodecSizePrefix(getUtf8Codec(), getU32Codec());
|
||||
myCodec.getSizeFromValue('hello world'); // 4 + 11 bytes.
|
||||
```
|
||||
|
||||
Also note that, if the `VariableSizeCodec` is bounded by a maximum size, it can be provided as a `maxSize` number attribute.
|
||||
|
||||
The following type guards are available to identify and/or assert the size of codecs: `isFixedSize`, `isVariableSize`, `assertIsFixedSize` and `assertIsVariableSize`.
|
||||
|
||||
Finally, note that the same is true for `Encoders` and `Decoders`.
|
||||
|
||||
- A `FixedSizeEncoder` has a `fixedSize` number attribute.
|
||||
- A `VariableSizeEncoder` has a `getSizeFromValue` function and an optional `maxSize` number attribute.
|
||||
- A `FixedSizeDecoder` has a `fixedSize` number attribute.
|
||||
- A `VariableSizeDecoder` has an optional `maxSize` number attribute.
|
||||
|
||||
## Creating custom codecs
|
||||
|
||||
If composing codecs isn’t enough for you, you may implement your own codec logic by using the `createCodec` function. This function requires an object with a `read` and a `write` function telling us how to read from and write to an existing byte array.
|
||||
|
||||
The `read` function accepts the `bytes` to decode from and the `offset` at each we should start reading. It returns an array with two items:
|
||||
|
||||
- The first item should be the decoded value.
|
||||
- The second item should be the next offset to read from.
|
||||
|
||||
```ts
|
||||
createCodec({
|
||||
read(bytes, offset) {
|
||||
const value = bytes[offset];
|
||||
return [value, offset + 1];
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Reciprocally, the `write` function accepts the `value` to encode, the array of `bytes` to write the encoded value to and the `offset` at which it should be written. It should encode the given value, insert it in the byte array, and provide the next offset to write to as the return value.
|
||||
|
||||
```ts
|
||||
createCodec({
|
||||
write(value, bytes, offset) {
|
||||
bytes.set(value, offset);
|
||||
return offset + 1;
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Additionally, we must specify the size of the codec. If we are defining a `FixedSizeCodec`, we must simply provide the `fixedSize` number attribute. For `VariableSizeCodecs`, we must provide the `getSizeFromValue` function as described in the previous section.
|
||||
|
||||
```ts
|
||||
// FixedSizeCodec.
|
||||
createCodec({
|
||||
fixedSize: 1,
|
||||
// ...
|
||||
});
|
||||
|
||||
// VariableSizeCodec.
|
||||
createCodec({
|
||||
getSizeFromValue: (value: string) => value.length,
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Here’s a concrete example of a custom codec that encodes any unsigned integer in a single byte. Since a single byte can only store integers from 0 to 255, if any other integer is provided it will take its modulo 256 to ensure it fits in a single byte. Because it always requires a single byte, that codec is a `FixedSizeCodec` of size `1`.
|
||||
|
||||
```ts
|
||||
const getModuloU8Codec = () =>
|
||||
createCodec<number>({
|
||||
fixedSize: 1,
|
||||
read(bytes, offset) {
|
||||
const value = bytes[offset];
|
||||
return [value, offset + 1];
|
||||
},
|
||||
write(value, bytes, offset) {
|
||||
bytes.set(value % 256, offset);
|
||||
return offset + 1;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Note that, it is also possible to create custom encoders and decoders separately by using the `createEncoder` and `createDecoder` functions respectively and then use the `combineCodec` function on them just like we were doing with composed codecs.
|
||||
|
||||
This approach is recommended to library maintainers as it allows their users to tree-shake any of the encoders and/or decoders they don’t need.
|
||||
|
||||
Here’s our previous modulo u8 example but split into separate `Encoder`, `Decoder` and `Codec` instances.
|
||||
|
||||
```ts
|
||||
const getModuloU8Encoder = () =>
|
||||
createEncoder<number>({
|
||||
fixedSize: 1,
|
||||
write(value, bytes, offset) {
|
||||
bytes.set(value % 256, offset);
|
||||
return offset + 1;
|
||||
},
|
||||
});
|
||||
|
||||
const getModuloU8Decoder = () =>
|
||||
createDecoder<number>({
|
||||
fixedSize: 1,
|
||||
read(bytes, offset) {
|
||||
const value = bytes[offset];
|
||||
return [value, offset + 1];
|
||||
},
|
||||
});
|
||||
|
||||
const getModuloU8Codec = () => combineCodec(getModuloU8Encoder(), getModuloU8Decoder());
|
||||
```
|
||||
|
||||
Here’s another example returning a `VariableSizeCodec`. This one transforms a simple string composed of characters from `a` to `z` to a buffer of numbers from `1` to `26` where `0` bytes are spaces.
|
||||
|
||||
```ts
|
||||
const alphabet = ' abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
const getCipherEncoder = () =>
|
||||
createEncoder<string>({
|
||||
getSizeFromValue: value => value.length,
|
||||
write(value, bytes, offset) {
|
||||
const bytesToAdd = [...value].map(char => alphabet.indexOf(char));
|
||||
bytes.set(bytesToAdd, offset);
|
||||
return offset + bytesToAdd.length;
|
||||
},
|
||||
});
|
||||
|
||||
const getCipherDecoder = () =>
|
||||
createDecoder<string>({
|
||||
read(bytes, offset) {
|
||||
const value = [...bytes.slice(offset)].map(byte => alphabet.charAt(byte)).join('');
|
||||
return [value, bytes.length];
|
||||
},
|
||||
});
|
||||
|
||||
const getCipherCodec = () => combineCodec(getCipherEncoder(), getCipherDecoder());
|
||||
```
|
||||
|
||||
## Transforming codecs
|
||||
|
||||
It is possible to transform a `Codec<T>` to a `Codec<U>` by providing two mapping functions: one that goes from `T` to `U` and one that does the opposite.
|
||||
|
||||
For instance, here’s how you would map a `u32` integer into a `string` representation of that number.
|
||||
|
||||
```ts
|
||||
const getStringU32Codec = () =>
|
||||
transformCodec(
|
||||
getU32Codec(),
|
||||
(integerAsString: string): number => parseInt(integerAsString),
|
||||
(integer: number): string => integer.toString(),
|
||||
);
|
||||
|
||||
getStringU32Codec().encode('42'); // new Uint8Array([42])
|
||||
getStringU32Codec().decode(new Uint8Array([42])); // "42"
|
||||
```
|
||||
|
||||
If a `Codec` has [different From and To types](#different-from-and-to-types), say `Codec<OldFrom, OldTo>`, and we want to map it to `Codec<NewFrom, NewTo>`, we must provide functions that map from `NewFrom` to `OldFrom` and from `OldTo` to `NewTo`.
|
||||
|
||||
To illustrate that, let’s take our previous `getStringU32Codec` example but make it use a `getU64Codec` codec instead as it returns a `Codec<number | bigint, bigint>`. Additionally, let’s make it so our `getStringU64Codec` function returns a `Codec<number | string, string>` so that it also accepts numbers when encoding values. Here’s what our mapping functions look like:
|
||||
|
||||
```ts
|
||||
const getStringU64Codec = () =>
|
||||
transformCodec(
|
||||
getU64Codec(),
|
||||
(integerInput: number | string): number | bigint =>
|
||||
typeof integerInput === 'string' ? BigInt(integerAsString) : integerInput,
|
||||
(integer: bigint): string => integer.toString(),
|
||||
);
|
||||
```
|
||||
|
||||
Note that the second function that maps the decoded type is optional. That means, you can omit it to simply update or loosen the type to encode whilst keeping the decoded type the same.
|
||||
|
||||
This is particularly useful to provide default values to object structures. For instance, here’s how we can map our `Person` codec to give a default value to its `age` attribute.
|
||||
|
||||
```ts
|
||||
type Person = { name: string; age: number; }
|
||||
const getPersonCodec = (): Codec<Person> => { /*...*/ }
|
||||
|
||||
type PersonInput = { name: string; age?: number; }
|
||||
const getPersonWithDefaultValueCodec = (): Codec<PersonInput, Person> =>
|
||||
transformCodec(
|
||||
getPersonCodec(),
|
||||
(person: PersonInput): Person => { ...person, age: person.age ?? 42 }
|
||||
)
|
||||
```
|
||||
|
||||
Similar helpers exist to map `Encoder` and `Decoder` instances allowing you to separate your codec logic into tree-shakeable functions. Here’s our `getStringU32Codec` written that way.
|
||||
|
||||
```ts
|
||||
const getStringU32Encoder = () =>
|
||||
transformEncoder(getU32Encoder(), (integerAsString: string): number => parseInt(integerAsString));
|
||||
const getStringU32Decoder = () => transformDecoder(getU32Decoder(), (integer: number): string => integer.toString());
|
||||
const getStringU32Codec = () => combineCodec(getStringU32Encoder(), getStringU32Decoder());
|
||||
```
|
||||
|
||||
## Fixing the size of codecs
|
||||
|
||||
The `fixCodecSize` function allows you to bind the size of a given codec to the given fixed size.
|
||||
|
||||
For instance, say you want to represent a base-58 string that uses exactly 32 bytes when decoded. Here’s how you can use the `fixCodecSize` helper to achieve that.
|
||||
|
||||
```ts
|
||||
const get32BytesBase58Codec = () => fixCodecSize(getBase58Codec(), 32);
|
||||
```
|
||||
|
||||
You may also use the `fixEncoderSize` and `fixDecoderSize` functions to separate your codec logic like so:
|
||||
|
||||
```ts
|
||||
const get32BytesBase58Encoder = () => fixEncoderSize(getBase58Encoder(), 32);
|
||||
const get32BytesBase58Decoder = () => fixDecoderSize(getBase58Decoder(), 32);
|
||||
const get32BytesBase58Codec = () => combineCodec(get32BytesBase58Encoder(), get32BytesBase58Decoder());
|
||||
```
|
||||
|
||||
## Prefixing codecs with their size
|
||||
|
||||
The `addCodecSizePrefix` function allows you to store the byte size of any codec as a number prefix. This allows you to contain variable-size codecs to their actual size.
|
||||
|
||||
When encoding, the size of the encoded data is stored before the encoded data itself. When decoding, the size is read first to know how many bytes to read next.
|
||||
|
||||
For example, say we want to represent a variable-size base-58 string using a `u32` size prefix. Here’s how you can use the `addCodecSizePrefix` function to achieve that.
|
||||
|
||||
```ts
|
||||
const getU32Base58Codec = () => addCodecSizePrefix(getBase58Codec(), getU32Codec());
|
||||
|
||||
getU32Base58Codec().encode('hello world');
|
||||
// 0x0b00000068656c6c6f20776f726c64
|
||||
// | └-- Our encoded base-58 string.
|
||||
// └-- Our encoded u32 size prefix.
|
||||
```
|
||||
|
||||
You may also use the `addEncoderSizePrefix` and `addDecoderSizePrefix` functions to separate your codec logic like so:
|
||||
|
||||
```ts
|
||||
const getU32Base58Encoder = () => addEncoderSizePrefix(getBase58Encoder(), getU32Encoder());
|
||||
const getU32Base58Decoder = () => addDecoderSizePrefix(getBase58Decoder(), getU32Decoder());
|
||||
const getU32Base58Codec = () => combineCodec(getU32Base58Encoder(), getU32Base58Decoder());
|
||||
```
|
||||
|
||||
## Adding sentinels to codecs
|
||||
|
||||
Another way of delimiting the size of a codec is to use sentinels. The `addCodecSentinel` function allows us to add a sentinel to the end of the encoded data and to read until that sentinel is found when decoding. It accepts any codec and a `Uint8Array` sentinel responsible for delimiting the encoded data.
|
||||
|
||||
```ts
|
||||
const codec = addCodecSentinel(getUtf8Codec(), new Uint8Array([255, 255]));
|
||||
codec.encode('hello');
|
||||
// 0x68656c6c6fffff
|
||||
// | └-- Our sentinel.
|
||||
// └-- Our encoded string.
|
||||
```
|
||||
|
||||
Note that the sentinel _must not_ be present in the encoded data and _must_ be present in the decoded data for this to work. If this is not the case, dedicated errors will be thrown.
|
||||
|
||||
```ts
|
||||
const sentinel = new Uint8Array([108, 108]); // 'll'
|
||||
const codec = addCodecSentinel(getUtf8Codec(), sentinel);
|
||||
|
||||
codec.encode('hello'); // Throws: sentinel is in encoded data.
|
||||
codec.decode(new Uint8Array([1, 2, 3])); // Throws: sentinel missing in decoded data.
|
||||
```
|
||||
|
||||
Separate `addEncoderSentinel` and `addDecoderSentinel` functions are also available.
|
||||
|
||||
```ts
|
||||
const bytes = addEncoderSentinel(getUtf8Encoder(), sentinel).encode('hello');
|
||||
const value = addDecoderSentinel(getUtf8Decoder(), sentinel).decode(bytes);
|
||||
```
|
||||
|
||||
## Adjusting the size of codecs
|
||||
|
||||
The `resizeCodec` helper re-defines the size of a given codec by accepting a function that takes the current size of the codec and returns a new size. This works for both fixed-size and variable-size codecs.
|
||||
|
||||
```ts
|
||||
// Fixed-size codec.
|
||||
const getBiggerU32Codec = () => resizeCodec(getU32Codec(), size => size + 4);
|
||||
getBiggerU32Codec().encode(42);
|
||||
// 0x2a00000000000000
|
||||
// | └-- Empty buffer space caused by the resizeCodec function.
|
||||
// └-- Our encoded u32 number.
|
||||
|
||||
// Variable-size codec.
|
||||
const getBiggerUtf8Codec = () => resizeCodec(getUtf8Codec(), size => size + 4);
|
||||
getBiggerUtf8Codec().encode('ABC');
|
||||
// 0x41424300000000
|
||||
// | └-- Empty buffer space caused by the resizeCodec function.
|
||||
// └-- Our encoded string.
|
||||
```
|
||||
|
||||
Note that the `resizeCodec` function doesn't change any encoded or decoded bytes, it merely tells the `encode` and `decode` functions how big the `Uint8Array` should be before delegating to their respective `write` and `read` functions. In fact, this is completely bypassed when using the `write` and `read` functions directly. For instance:
|
||||
|
||||
```ts
|
||||
const getBiggerU32Codec = () => resizeCodec(getU32Codec(), size => size + 4);
|
||||
|
||||
// Using the encode function.
|
||||
getBiggerU32Codec().encode(42);
|
||||
// 0x2a00000000000000
|
||||
|
||||
// Using the lower-level write function.
|
||||
const myCustomBytes = new Uint8Array(4);
|
||||
getBiggerU32Codec().write(42, myCustomBytes, 0);
|
||||
// 0x2a000000
|
||||
```
|
||||
|
||||
So when would it make sense to use the `resizeCodec` function? This function is particularly useful when combined with the `offsetCodec` function described below. Whilst the `offsetCodec` may help us push the offset forward — e.g. to skip some padding — it won't change the size of the encoded data which means the last bytes will be truncated by how much we pushed the offset forward. The `resizeCodec` function can be used to fix that. For instance, here's how we can use the `resizeCodec` and the `offsetCodec` functions together to create a struct codec that includes some padding.
|
||||
|
||||
```ts
|
||||
const personCodec = getStructCodec([
|
||||
['name', fixCodecSize(getUtf8Codec(), 8)],
|
||||
// There is a 4-byte padding between name and age.
|
||||
[
|
||||
'age',
|
||||
offsetCodec(
|
||||
resizeCodec(getU32Codec(), size => size + 4),
|
||||
{ preOffset: ({ preOffset }) => preOffset + 4 },
|
||||
),
|
||||
],
|
||||
]);
|
||||
|
||||
personCodec.encode({ name: 'Alice', age: 42 });
|
||||
// 0x416c696365000000000000002a000000
|
||||
// | | └-- Our encoded u32 (42).
|
||||
// | └-- The 4-bytes of padding we are skipping.
|
||||
// └-- Our 8-byte encoded string ("Alice").
|
||||
```
|
||||
|
||||
As usual, the `resizeEncoder` and `resizeDecoder` functions can also be used to achieve that.
|
||||
|
||||
```ts
|
||||
const getBiggerU32Encoder = () => resizeEncoder(getU32Codec(), size => size + 4);
|
||||
const getBiggerU32Decoder = () => resizeDecoder(getU32Codec(), size => size + 4);
|
||||
const getBiggerU32Codec = () => combineCodec(getBiggerU32Encoder(), getBiggerU32Decoder());
|
||||
```
|
||||
|
||||
## Offsetting codecs
|
||||
|
||||
The `offsetCodec` function is a powerful codec primitive that allows you to move the offset of a given codec forward or backwards. It accepts one or two functions that takes the current offset and returns a new offset.
|
||||
|
||||
To understand how this works, let's take our previous `biggerU32Codec` example which encodes a `u32` number inside an 8-byte buffer.
|
||||
|
||||
```ts
|
||||
const biggerU32Codec = resizeCodec(getU32Codec(), size => size + 4);
|
||||
biggerU32Codec.encode(0xffffffff);
|
||||
// 0xffffffff00000000
|
||||
// | └-- Empty buffer space caused by the resizeCodec function.
|
||||
// └-- Our encoded u32 number.
|
||||
```
|
||||
|
||||
Now, let's say we want to move the offset of that codec 2 bytes forward so that the encoded number sits in the middle of the buffer. To achieve, this we can use the `offsetCodec` helper and provide a `preOffset` function that moves the "pre-offset" of the codec 2 bytes forward.
|
||||
|
||||
```ts
|
||||
const u32InTheMiddleCodec = offsetCodec(biggerU32Codec, {
|
||||
preOffset: ({ preOffset }) => preOffset + 2,
|
||||
});
|
||||
u32InTheMiddleCodec.encode(0xffffffff);
|
||||
// 0x0000ffffffff0000
|
||||
// └-- Our encoded u32 number is now in the middle of the buffer.
|
||||
```
|
||||
|
||||
We refer to this offset as the "pre-offset" because, once the inner codec is encoded or decoded, an additional offset will be returned which we refer to as the "post-offset". That "post-offset" is important as, unless we are reaching the end of our codec, it will be used by any further codecs to continue encoding or decoding data.
|
||||
|
||||
By default, that "post-offset" is simply the addition of the "pre-offset" and the size of the encoded or decoded inner data.
|
||||
|
||||
```ts
|
||||
const u32InTheMiddleCodec = offsetCodec(biggerU32Codec, {
|
||||
preOffset: ({ preOffset }) => preOffset + 2,
|
||||
});
|
||||
u32InTheMiddleCodec.encode(0xffffffff);
|
||||
// 0x0000ffffffff0000
|
||||
// | | └-- Post-offset.
|
||||
// | └-- New pre-offset: The original pre-offset + 2.
|
||||
// └-- Pre-offset: The original pre-offset before we adjusted it.
|
||||
```
|
||||
|
||||
However, you may also provide a `postOffset` function to adjust the "post-offset". For instance, let's push the "post-offset" 2 bytes forward as well such that any further codecs will start doing their job at the end of our 8-byte `u32` number.
|
||||
|
||||
```ts
|
||||
const u32InTheMiddleCodec = offsetCodec(biggerU32Codec, {
|
||||
preOffset: ({ preOffset }) => preOffset + 2,
|
||||
postOffset: ({ postOffset }) => postOffset + 2,
|
||||
});
|
||||
u32InTheMiddleCodec.encode(0xffffffff);
|
||||
// 0x0000ffffffff0000
|
||||
// | | | └-- New post-offset: The original post-offset + 2.
|
||||
// | | └-- Post-offset: The original post-offset before we adjusted it.
|
||||
// | └-- New pre-offset: The original pre-offset + 2.
|
||||
// └-- Pre-offset: The original pre-offset before we adjusted it.
|
||||
```
|
||||
|
||||
Both the `preOffset` and `postOffset` functions offer the following attributes:
|
||||
|
||||
- `bytes`: The entire byte array being encoded or decoded.
|
||||
- `preOffset`: The original and unaltered pre-offset.
|
||||
- `wrapBytes`: A helper function that wraps the given offset around the byte array length. E.g. `wrapBytes(-1)` will refer to the last byte of the byte array.
|
||||
|
||||
Additionally, the post-offset function also provides the following attributes:
|
||||
|
||||
- `newPreOffset`: The new pre-offset after the pre-offset function has been applied.
|
||||
- `postOffset`: The original and unaltered post-offset.
|
||||
|
||||
Note that you may also decide to ignore these attributes to achieve absolute offsets. However, relative offsets are usually recommended as they won't break your codecs when composed with other codecs.
|
||||
|
||||
```ts
|
||||
const u32InTheMiddleCodec = offsetCodec(biggerU32Codec, {
|
||||
preOffset: () => 2,
|
||||
postOffset: () => 8,
|
||||
});
|
||||
u32InTheMiddleCodec.encode(0xffffffff);
|
||||
// 0x0000ffffffff0000
|
||||
```
|
||||
|
||||
Also note that any negative offset or offset that exceeds the size of the byte array will throw a `SolanaError` of code `SOLANA_ERROR__CODECS__OFFSET_OUT_OF_RANGE`.
|
||||
|
||||
```ts
|
||||
const u32InTheEndCodec = offsetCodec(biggerU32Codec, { preOffset: () => -4 });
|
||||
u32InTheEndCodec.encode(0xffffffff);
|
||||
// throws new SolanaError(SOLANA_ERROR__CODECS__OFFSET_OUT_OF_RANGE)
|
||||
```
|
||||
|
||||
To avoid this, you may use the `wrapBytes` function to wrap the offset around the byte array length. For instance, here's how we can use the `wrapBytes` function to move the pre-offset 4 bytes from the end of the byte array.
|
||||
|
||||
```ts
|
||||
const u32InTheEndCodec = offsetCodec(biggerU32Codec, {
|
||||
preOffset: ({ wrapBytes }) => wrapBytes(-4),
|
||||
});
|
||||
u32InTheEndCodec.encode(0xffffffff);
|
||||
// 0x00000000ffffffff
|
||||
```
|
||||
|
||||
As you can see, the `offsetCodec` helper allows you to jump all over the place with your codecs. This non-linear approach to encoding and decoding data allows you to achieve complex serialization strategies that would otherwise be impossible.
|
||||
|
||||
As usual, the `offsetEncoder` and `offsetDecoder` functions can also be used to split your codec logic into tree-shakeable functions.
|
||||
|
||||
```ts
|
||||
const getU32InTheMiddleEncoder = () => offsetEncoder(biggerU32Encoder, { preOffset: ({ preOffset }) => preOffset + 2 });
|
||||
const getU32InTheMiddleDecoder = () => offsetDecoder(biggerU32Decoder, { preOffset: ({ preOffset }) => preOffset + 2 });
|
||||
const getU32InTheMiddleCodec = () => combineCodec(getU32InTheMiddleEncoder(), getU32InTheMiddleDecoder());
|
||||
```
|
||||
|
||||
## Padding codecs
|
||||
|
||||
The `padLeftCodec` and `padRightCodec` helpers can be used to add padding to the left or right of a given codec. They accept an `offset` number that tells us how big the padding should be.
|
||||
|
||||
```ts
|
||||
const getLeftPaddedCodec = () => padLeftCodec(getU16Codec(), 4);
|
||||
getLeftPaddedCodec().encode(0xffff);
|
||||
// 0x00000000ffff
|
||||
// | └-- Our encoded u16 number.
|
||||
// └-- Our 4-byte padding.
|
||||
|
||||
const getRightPaddedCodec = () => padRightCodec(getU16Codec(), 4);
|
||||
getRightPaddedCodec().encode(0xffff);
|
||||
// 0xffff00000000
|
||||
// | └-- Our 4-byte padding.
|
||||
// └-- Our encoded u16 number.
|
||||
```
|
||||
|
||||
Note that both the `padLeftCodec` and `padRightCodec` functions are simple wrappers around the `offsetCodec` and `resizeCodec` functions. For more complex padding strategies, you may want to use the `offsetCodec` and `resizeCodec` functions directly instead.
|
||||
|
||||
As usual, encoder-only and decoder-only helpers are available for these padding functions. Namely, `padLeftEncoder`, `padRightEncoder`, `padLeftDecoder` and `padRightDecoder`.
|
||||
|
||||
```ts
|
||||
const getMyPaddedEncoder = () => padLeftEncoder(getU16Encoder());
|
||||
const getMyPaddedDecoder = () => padLeftDecoder(getU16Decoder());
|
||||
const getMyPaddedCodec = () => combineCodec(getMyPaddedEncoder(), getMyPaddedDecoder());
|
||||
```
|
||||
|
||||
## Reversing codecs
|
||||
|
||||
The `reverseCodec` helper reverses the bytes of the provided `FixedSizeCodec`.
|
||||
|
||||
```ts
|
||||
const getBigEndianU64Codec = () => reverseCodec(getU64Codec());
|
||||
```
|
||||
|
||||
Note that number codecs can already do that for you via their `endian` option.
|
||||
|
||||
```ts
|
||||
const getBigEndianU64Codec = () => getU64Codec({ endian: Endian.Big });
|
||||
```
|
||||
|
||||
As usual, the `reverseEncoder` and `reverseDecoder` functions can also be used to achieve that.
|
||||
|
||||
```ts
|
||||
const getBigEndianU64Encoder = () => reverseEncoder(getU64Encoder());
|
||||
const getBigEndianU64Decoder = () => reverseDecoder(getU64Decoder());
|
||||
const getBigEndianU64Codec = () => combineCodec(getBigEndianU64Encoder(), getBigEndianU64Decoder());
|
||||
```
|
||||
|
||||
## Byte helpers
|
||||
|
||||
This package also provides utility functions for managing bytes such as:
|
||||
|
||||
- `mergeBytes`: Concatenates an array of `Uint8Arrays` into a single `Uint8Array`.
|
||||
- `padBytes`: Pads a `Uint8Array` with zeroes (to the right) to the specified length.
|
||||
- `fixBytes`: Pads or truncates a `Uint8Array` so it has the specified length.
|
||||
- `containsBytes`: Checks if a `Uint8Array` contains another `Uint8Array` at a given offset.
|
||||
|
||||
```ts
|
||||
// Merge multiple Uint8Array buffers into one.
|
||||
mergeBytes([new Uint8Array([1, 2]), new Uint8Array([3, 4])]); // Uint8Array([1, 2, 3, 4])
|
||||
|
||||
// Pad a Uint8Array buffer to the given size.
|
||||
padBytes(new Uint8Array([1, 2]), 4); // Uint8Array([1, 2, 0, 0])
|
||||
padBytes(new Uint8Array([1, 2, 3, 4]), 2); // Uint8Array([1, 2, 3, 4])
|
||||
|
||||
// Pad and truncate a Uint8Array buffer to the given size.
|
||||
fixBytes(new Uint8Array([1, 2]), 4); // Uint8Array([1, 2, 0, 0])
|
||||
fixBytes(new Uint8Array([1, 2, 3, 4]), 2); // Uint8Array([1, 2])
|
||||
|
||||
// Check if a Uint8Array contains another Uint8Array at a given offset.
|
||||
containsBytes(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 3]), 1); // true
|
||||
containsBytes(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 3]), 2); // false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To read more about the available codecs and how to use them, check out the documentation of the main [`@solana/codecs` package](https://github.com/anza-xyz/kit/tree/main/packages/codecs).
|
||||
@@ -0,0 +1,14 @@
|
||||
declare module "node:constants" {
|
||||
const constants:
|
||||
& typeof import("node:os").constants.dlopen
|
||||
& typeof import("node:os").constants.errno
|
||||
& typeof import("node:os").constants.priority
|
||||
& typeof import("node:os").constants.signals
|
||||
& typeof import("node:fs").constants
|
||||
& typeof import("node:crypto").constants;
|
||||
export = constants;
|
||||
}
|
||||
declare module "constants" {
|
||||
import constants = require("node:constants");
|
||||
export = constants;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*! *****************************************************************************
|
||||
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"/>
|
||||
|
||||
interface RegExp {
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the unicodeSets flag (v) used with a regular expression.
|
||||
* Default is false. Read-only.
|
||||
*/
|
||||
readonly unicodeSets: boolean;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Code generated by Herebyfile.mjs generate:enums from internal/checker/types.go. DO NOT EDIT.
|
||||
export var ElementFlags;
|
||||
(function (ElementFlags) {
|
||||
ElementFlags[ElementFlags["None"] = 0] = "None";
|
||||
ElementFlags[ElementFlags["Required"] = 1] = "Required";
|
||||
ElementFlags[ElementFlags["Optional"] = 2] = "Optional";
|
||||
ElementFlags[ElementFlags["Rest"] = 4] = "Rest";
|
||||
ElementFlags[ElementFlags["Variadic"] = 8] = "Variadic";
|
||||
ElementFlags[ElementFlags["Fixed"] = 3] = "Fixed";
|
||||
ElementFlags[ElementFlags["Variable"] = 12] = "Variable";
|
||||
ElementFlags[ElementFlags["NonRequired"] = 14] = "NonRequired";
|
||||
ElementFlags[ElementFlags["NonRest"] = 11] = "NonRest";
|
||||
})(ElementFlags || (ElementFlags = {}));
|
||||
//# sourceMappingURL=elementFlags.js.map
|
||||
@@ -0,0 +1,11 @@
|
||||
import { _ as _get_prototype_of } from "./_get_prototype_of.js";
|
||||
|
||||
function _super_prop_base(object, property) {
|
||||
while (!Object.prototype.hasOwnProperty.call(object, property)) {
|
||||
object = _get_prototype_of(object);
|
||||
if (object === null) break;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
export { _super_prop_base as _ };
|
||||
@@ -0,0 +1,40 @@
|
||||
# Bundling
|
||||
|
||||
Due to its internal architecture based on Worker Threads, it is not possible to bundle Pino *without* generating additional files.
|
||||
|
||||
In particular, a bundler must ensure that the following files are also bundled separately:
|
||||
|
||||
* `lib/worker.js` from the `thread-stream` dependency
|
||||
* `file.js`
|
||||
* `lib/worker.js`
|
||||
* Any transport used by the user (like `pino-pretty`)
|
||||
|
||||
Once the files above have been generated, the bundler must also add information about the files above by injecting a code that sets `__bundlerPathsOverrides` in the `globalThis` object.
|
||||
|
||||
The variable is an object whose keys are an identifier for the files and the values are the paths of files relative to the currently bundle files.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
// Inject this using your bundle plugin
|
||||
globalThis.__bundlerPathsOverrides = {
|
||||
'thread-stream-worker': pinoWebpackAbsolutePath('./thread-stream-worker.js')
|
||||
'pino/file': pinoWebpackAbsolutePath('./pino-file.js'),
|
||||
'pino-worker': pinoWebpackAbsolutePath('./pino-worker.js'),
|
||||
'pino-pretty': pinoWebpackAbsolutePath('./pino-pretty.js'),
|
||||
};
|
||||
```
|
||||
|
||||
Note that `pino/file`, `pino-worker` and `thread-stream-worker` are required identifiers. Other identifiers are possible based on the user configuration.
|
||||
|
||||
## Webpack Plugin
|
||||
|
||||
If you are a Webpack user, you can achieve this with [pino-webpack-plugin](https://github.com/pinojs/pino-webpack-plugin) without manual configuration of `__bundlerPathsOverrides`; however, you still need to configure it manually if you are using other bundlers.
|
||||
|
||||
## Esbuild Plugin
|
||||
|
||||
[esbuild-plugin-pino](https://github.com/davipon/esbuild-plugin-pino) is the esbuild plugin to generate extra pino files for bundling.
|
||||
|
||||
## Bun Plugin
|
||||
|
||||
[bun-plugin-pino](https://github.com/vktrl/bun-plugin-pino) is the Bun plugin to generate extra pino files for bundling.
|
||||
@@ -0,0 +1,279 @@
|
||||
package flatted
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// flattedIndex is a internal type used to distinguish between
|
||||
// actual strings and flatted indices during the reconstruction phase.
|
||||
type flattedIndex string
|
||||
|
||||
// Stringify converts a Go value into a specialized flatted JSON string.
|
||||
func Stringify(value, replacer, space any) (string, error) {
|
||||
knownKeys := []any{}
|
||||
knownValues := []string{}
|
||||
input := []any{}
|
||||
|
||||
index := func(v any) string {
|
||||
input = append(input, v)
|
||||
idx := strconv.Itoa(len(input) - 1)
|
||||
knownKeys = append(knownKeys, v)
|
||||
knownValues = append(knownValues, idx)
|
||||
return idx
|
||||
}
|
||||
|
||||
relate := func(v any) any {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
rv := reflect.ValueOf(v)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.String || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Pointer {
|
||||
for i, k := range knownKeys {
|
||||
if kind == reflect.String {
|
||||
if k == v {
|
||||
return knownValues[i]
|
||||
}
|
||||
} else {
|
||||
rk := reflect.ValueOf(k)
|
||||
if rk.Kind() == kind && rk.Pointer() == rv.Pointer() {
|
||||
return knownValues[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return index(v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
transform := func(v any) any {
|
||||
rv := reflect.ValueOf(v)
|
||||
if !rv.IsValid() {
|
||||
return nil
|
||||
}
|
||||
if _, ok := v.(json.Marshaler); ok {
|
||||
return v
|
||||
}
|
||||
// Dereference pointers to process the underlying Slice, Map, or Array
|
||||
for rv.Kind() == reflect.Pointer && !rv.IsNil() {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
res := make([]any, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
res[i] = relate(rv.Index(i).Interface())
|
||||
}
|
||||
return res
|
||||
case reflect.Map:
|
||||
res := make(map[string]any)
|
||||
keys := rv.MapKeys()
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i].String() < keys[j].String()
|
||||
})
|
||||
|
||||
whitelist, isWhitelist := replacer.([]string)
|
||||
for _, key := range keys {
|
||||
kStr := key.String()
|
||||
if isWhitelist {
|
||||
found := false
|
||||
for _, w := range whitelist {
|
||||
if w == kStr {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
res[kStr] = relate(rv.MapIndex(key).Interface())
|
||||
}
|
||||
return res
|
||||
case reflect.Struct:
|
||||
res := make(map[string]any)
|
||||
t := rv.Type()
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
if field.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
name := field.Name
|
||||
if tag := field.Tag.Get("json"); tag != "" {
|
||||
name = strings.Split(tag, ",")[0]
|
||||
}
|
||||
res[name] = relate(rv.Field(i).Interface())
|
||||
}
|
||||
return res
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
index(value)
|
||||
output := []any{}
|
||||
for i := 0; i < len(input); i++ {
|
||||
output = append(output, transform(input[i]))
|
||||
}
|
||||
|
||||
var b []byte
|
||||
var err error
|
||||
indent := ""
|
||||
switch v := space.(type) {
|
||||
case string:
|
||||
indent = v
|
||||
case int:
|
||||
indent = strings.Repeat(" ", v)
|
||||
}
|
||||
|
||||
if indent != "" {
|
||||
b, err = json.MarshalIndent(output, "", indent)
|
||||
} else {
|
||||
b, err = json.Marshal(output)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// Parse converts a specialized flatted string into a Go value.
|
||||
func Parse(text string, reviver func(key string, value any) any) (any, error) {
|
||||
var jsonInput []any
|
||||
if err := json.Unmarshal([]byte(text), &jsonInput); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var wrap func(any) any
|
||||
wrap = func(v any) any {
|
||||
if s, ok := v.(string); ok {
|
||||
return flattedIndex(s)
|
||||
}
|
||||
if arr, ok := v.([]any); ok {
|
||||
for i, item := range arr {
|
||||
arr[i] = wrap(item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
if m, ok := v.(map[string]any); ok {
|
||||
for k, item := range m {
|
||||
m[k] = wrap(item)
|
||||
}
|
||||
return m
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
wrapped := make([]any, len(jsonInput))
|
||||
for i, v := range jsonInput {
|
||||
wrapped[i] = wrap(v)
|
||||
}
|
||||
|
||||
input := make([]any, len(wrapped))
|
||||
for i, v := range wrapped {
|
||||
if fi, ok := v.(flattedIndex); ok {
|
||||
input[i] = string(fi)
|
||||
} else {
|
||||
input[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(input) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
value := input[0]
|
||||
rv := reflect.ValueOf(value)
|
||||
if rv.IsValid() && (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Map) {
|
||||
set := make(map[uintptr]bool)
|
||||
set[rv.Pointer()] = true
|
||||
res := loop(value, input, set)
|
||||
if reviver != nil {
|
||||
return revive("", res, reviver), nil
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
if reviver != nil {
|
||||
return reviver("", value), nil
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func revive(key string, value any, reviver func(k string, v any) any) any {
|
||||
switch v := value.(type) {
|
||||
case []any:
|
||||
for i, el := range v {
|
||||
v[i] = revive(strconv.Itoa(i), el, reviver)
|
||||
}
|
||||
case map[string]any:
|
||||
keys := make([]string, 0, len(v))
|
||||
for k := range v {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v[k] = revive(k, v[k], reviver)
|
||||
}
|
||||
}
|
||||
return reviver(key, value)
|
||||
}
|
||||
|
||||
func loop(value any, input []any, set map[uintptr]bool) any {
|
||||
if arr, ok := value.([]any); ok {
|
||||
for i, v := range arr {
|
||||
if fi, ok := v.(flattedIndex); ok {
|
||||
idx, _ := strconv.Atoi(string(fi))
|
||||
arr[i] = ref(input[idx], input, set)
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
if m, ok := value.(map[string]any); ok {
|
||||
for k, v := range m {
|
||||
if fi, ok := v.(flattedIndex); ok {
|
||||
idx, _ := strconv.Atoi(string(fi))
|
||||
m[k] = ref(input[idx], input, set)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func ref(value any, input []any, set map[uintptr]bool) any {
|
||||
rv := reflect.ValueOf(value)
|
||||
if rv.IsValid() && (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Map) {
|
||||
ptr := rv.Pointer()
|
||||
if !set[ptr] {
|
||||
set[ptr] = true
|
||||
return loop(value, input, set)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// ToJSON converts a generic value into a JSON serializable object without losing recursion.
|
||||
func ToJSON(value any) (any, error) {
|
||||
s, err := Stringify(value, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res any
|
||||
err = json.Unmarshal([]byte(s), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// FromJSON converts a previously serialized object with recursion into a recursive one.
|
||||
func FromJSON(value any) (any, error) {
|
||||
b, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Parse(string(b), nil)
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import NodeWebSocket, { WebSocketServer } from 'ws';
|
||||
|
||||
type BrowserWebSocketType = InstanceType<typeof WebSocket>;
|
||||
type NodeWebSocketType = InstanceType<typeof NodeWebSocket>;
|
||||
type NodeWebSocketTypeOptions = NodeWebSocket.ClientOptions;
|
||||
interface IWSClientAdditionalOptions {
|
||||
autoconnect?: boolean;
|
||||
reconnect?: boolean;
|
||||
reconnect_interval?: number;
|
||||
max_reconnects?: number;
|
||||
}
|
||||
interface ICommonWebSocketFactory {
|
||||
(address: string, options: IWSClientAdditionalOptions): ICommonWebSocket;
|
||||
}
|
||||
interface ICommonWebSocket {
|
||||
send: (data: Parameters<BrowserWebSocketType["send"]>[0], optionsOrCallback: ((error?: Error) => void) | Parameters<NodeWebSocketType["send"]>[1], callback?: (error?: Error) => void) => void;
|
||||
close: (code?: number, reason?: string) => void;
|
||||
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
}
|
||||
|
||||
interface DataPack<T, R extends string | ArrayBufferLike | Blob | ArrayBufferView> {
|
||||
encode(value: T): R;
|
||||
decode(value: R): T;
|
||||
}
|
||||
declare class DefaultDataPack implements DataPack<Object, string> {
|
||||
encode(value: Object): string;
|
||||
decode(value: string): Object;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Client" wraps "ws" or a browser-implemented "WebSocket" library
|
||||
* according to the environment providing JSON RPC 2.0 support on top.
|
||||
* @module Client
|
||||
*/
|
||||
|
||||
interface IQueueElement {
|
||||
promise: [
|
||||
Parameters<ConstructorParameters<typeof Promise>[0]>[0],
|
||||
Parameters<ConstructorParameters<typeof Promise>[0]>[1]
|
||||
];
|
||||
timeout?: ReturnType<typeof setTimeout>;
|
||||
}
|
||||
interface IQueue {
|
||||
[x: number | string]: IQueueElement;
|
||||
}
|
||||
interface IWSRequestParams {
|
||||
[x: string]: any;
|
||||
[x: number]: any;
|
||||
}
|
||||
declare class CommonClient extends EventEmitter {
|
||||
private address;
|
||||
private rpc_id;
|
||||
private queue;
|
||||
private options;
|
||||
private autoconnect;
|
||||
private ready;
|
||||
private reconnect;
|
||||
private reconnect_timer_id;
|
||||
private reconnect_interval;
|
||||
private max_reconnects;
|
||||
private rest_options;
|
||||
private current_reconnects;
|
||||
private generate_request_id;
|
||||
private socket;
|
||||
private webSocketFactory;
|
||||
private dataPack;
|
||||
/**
|
||||
* Instantiate a Client class.
|
||||
* @constructor
|
||||
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
|
||||
* @param {String} address - url to a websocket server
|
||||
* @param {Object} options - ws options object with reconnect parameters
|
||||
* @param {Function} generate_request_id - custom generation request Id
|
||||
* @param {DataPack} dataPack - data pack contains encoder and decoder
|
||||
* @return {CommonClient}
|
||||
*/
|
||||
constructor(webSocketFactory: ICommonWebSocketFactory, address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: {
|
||||
autoconnect?: boolean;
|
||||
reconnect?: boolean;
|
||||
reconnect_interval?: number;
|
||||
max_reconnects?: number;
|
||||
}, generate_request_id?: (method: string, params: object | Array<any>) => number | string, dataPack?: DataPack<object, string>);
|
||||
/**
|
||||
* Connects to a defined server if not connected already.
|
||||
* @method
|
||||
* @return {Undefined}
|
||||
*/
|
||||
connect(): void;
|
||||
/**
|
||||
* Calls a registered RPC method on server.
|
||||
* @method
|
||||
* @param {String} method - RPC method name
|
||||
* @param {Object|Array} params - optional method parameters
|
||||
* @param {Number} timeout - RPC reply timeout value
|
||||
* @param {Object} ws_opts - options passed to ws
|
||||
* @return {Promise}
|
||||
*/
|
||||
call(method: string, params?: IWSRequestParams, timeout?: number, ws_opts?: Parameters<NodeWebSocketType["send"]>[1]): Promise<unknown>;
|
||||
/**
|
||||
* Logins with the other side of the connection.
|
||||
* @method
|
||||
* @param {Object} params - Login credentials object
|
||||
* @return {Promise}
|
||||
*/
|
||||
login(params: IWSRequestParams): Promise<unknown>;
|
||||
/**
|
||||
* Fetches a list of client's methods registered on server.
|
||||
* @method
|
||||
* @return {Array}
|
||||
*/
|
||||
listMethods(): Promise<unknown>;
|
||||
/**
|
||||
* Sends a JSON-RPC 2.0 notification to server.
|
||||
* @method
|
||||
* @param {String} method - RPC method name
|
||||
* @param {Object} params - optional method parameters
|
||||
* @return {Promise}
|
||||
*/
|
||||
notify(method: string, params?: IWSRequestParams): Promise<void>;
|
||||
/**
|
||||
* Subscribes for a defined event.
|
||||
* @method
|
||||
* @param {String|Array} event - event name
|
||||
* @return {Undefined}
|
||||
* @throws {Error}
|
||||
*/
|
||||
subscribe(event: string | Array<string>): Promise<unknown>;
|
||||
/**
|
||||
* Unsubscribes from a defined event.
|
||||
* @method
|
||||
* @param {String|Array} event - event name
|
||||
* @return {Undefined}
|
||||
* @throws {Error}
|
||||
*/
|
||||
unsubscribe(event: string | Array<string>): Promise<unknown>;
|
||||
/**
|
||||
* Closes a WebSocket connection gracefully.
|
||||
* @method
|
||||
* @param {Number} code - socket close code
|
||||
* @param {String} data - optional data to be sent before closing
|
||||
* @return {Undefined}
|
||||
*/
|
||||
close(code?: number, data?: string): void;
|
||||
/**
|
||||
* Enable / disable automatic reconnection.
|
||||
* @method
|
||||
* @param {Boolean} reconnect - enable / disable reconnection
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setAutoReconnect(reconnect: boolean): void;
|
||||
/**
|
||||
* Set the interval between reconnection attempts.
|
||||
* @method
|
||||
* @param {Number} interval - reconnection interval in milliseconds
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setReconnectInterval(interval: number): void;
|
||||
/**
|
||||
* Set the maximum number of reconnection attempts.
|
||||
* @method
|
||||
* @param {Number} max_reconnects - maximum reconnection attempts
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setMaxReconnects(max_reconnects: number): void;
|
||||
/**
|
||||
* Get the current number of reconnection attempts made.
|
||||
* @method
|
||||
* @return {Number} current reconnection attempts
|
||||
*/
|
||||
getCurrentReconnects(): number;
|
||||
/**
|
||||
* Get the maximum number of reconnection attempts.
|
||||
* @method
|
||||
* @return {Number} maximum reconnection attempts
|
||||
*/
|
||||
getMaxReconnects(): number;
|
||||
/**
|
||||
* Check if the client is currently attempting to reconnect.
|
||||
* @method
|
||||
* @return {Boolean} true if reconnection is in progress
|
||||
*/
|
||||
isReconnecting(): boolean;
|
||||
/**
|
||||
* Check if the client will attempt to reconnect on the next close event.
|
||||
* @method
|
||||
* @return {Boolean} true if reconnection will be attempted
|
||||
*/
|
||||
willReconnect(): boolean;
|
||||
/**
|
||||
* Connection/Message handler.
|
||||
* @method
|
||||
* @private
|
||||
* @param {String} address - WebSocket API address
|
||||
* @param {Object} options - ws options object
|
||||
* @return {Undefined}
|
||||
*/
|
||||
private _connect;
|
||||
}
|
||||
|
||||
/**
|
||||
* factory method for common WebSocket instance
|
||||
* @method
|
||||
* @param {String} address - url to a websocket server
|
||||
* @param {(Object)} options - websocket options
|
||||
* @return {Undefined}
|
||||
*/
|
||||
declare function WebSocket$1(address: string, options: IWSClientAdditionalOptions & NodeWebSocket.ClientOptions): NodeWebSocket;
|
||||
|
||||
/**
|
||||
* "Server" wraps the "ws" library providing JSON RPC 2.0 support on top.
|
||||
* @module Server
|
||||
*/
|
||||
|
||||
interface INamespaceEvent {
|
||||
[x: string]: {
|
||||
sockets: Array<string>;
|
||||
protected: boolean;
|
||||
};
|
||||
}
|
||||
interface IMethod {
|
||||
public: () => void;
|
||||
protected: () => void;
|
||||
}
|
||||
interface IEvent {
|
||||
public: () => void;
|
||||
protected: () => void;
|
||||
}
|
||||
interface IRPCError {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: string;
|
||||
}
|
||||
interface IRPCMethodParams {
|
||||
[x: string]: any;
|
||||
}
|
||||
interface IRPCMethod {
|
||||
[x: string]: {
|
||||
fn: (params: IRPCMethodParams, socket_id: string) => any;
|
||||
protected: boolean;
|
||||
};
|
||||
}
|
||||
interface IClientWebSocket extends NodeWebSocket {
|
||||
_id: string;
|
||||
_authenticated: boolean;
|
||||
}
|
||||
declare class Server extends EventEmitter {
|
||||
private namespaces;
|
||||
private dataPack;
|
||||
wss: InstanceType<typeof WebSocketServer>;
|
||||
/**
|
||||
* Instantiate a Server class.
|
||||
* @constructor
|
||||
* @param {Object} options - ws constructor's parameters with rpc
|
||||
* @param {DataPack} dataPack - data pack contains encoder and decoder
|
||||
* @return {Server} - returns a new Server instance
|
||||
*/
|
||||
constructor(options: NodeWebSocket.ServerOptions, dataPack?: DataPack<object, string>);
|
||||
/**
|
||||
* Registers an RPC method.
|
||||
* @method
|
||||
* @param {String} name - method name
|
||||
* @param {Function} fn - a callee function
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Object} - returns an IMethod object
|
||||
*/
|
||||
register(name: string, fn: (params: IRPCMethodParams, socket_id: string) => void, ns?: string): IMethod;
|
||||
/**
|
||||
* Sets an auth method.
|
||||
* @method
|
||||
* @param {Function} fn - an arbitrary auth method
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setAuth(fn: (params: IRPCMethodParams, socket_id: string) => Promise<boolean>, ns?: string): void;
|
||||
/**
|
||||
* Marks an RPC method as protected.
|
||||
* @method
|
||||
* @param {String} name - method name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
private _makeProtectedMethod;
|
||||
/**
|
||||
* Marks an RPC method as public.
|
||||
* @method
|
||||
* @param {String} name - method name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
private _makePublicMethod;
|
||||
/**
|
||||
* Marks an event as protected.
|
||||
* @method
|
||||
* @param {String} name - event name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
private _makeProtectedEvent;
|
||||
/**
|
||||
* Marks an event as public.
|
||||
* @method
|
||||
* @param {String} name - event name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
private _makePublicEvent;
|
||||
/**
|
||||
* Removes a namespace and closes all connections
|
||||
* @method
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Undefined}
|
||||
*/
|
||||
closeNamespace(ns: string): void;
|
||||
/**
|
||||
* Creates a new event that can be emitted to clients.
|
||||
* @method
|
||||
* @param {String} name - event name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Object} - returns an IEvent object
|
||||
*/
|
||||
event(name: string, ns?: string): IEvent;
|
||||
/**
|
||||
* Returns a requested namespace object
|
||||
* @method
|
||||
* @param {String} name - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Object} - namespace object
|
||||
*/
|
||||
of(name: string): {
|
||||
register(fn_name: string, fn: (params: IRPCMethodParams) => void): IMethod;
|
||||
event(ev_name: string): IEvent;
|
||||
readonly eventList: string[];
|
||||
/**
|
||||
* Emits a specified event to this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @param {String} event - event name
|
||||
* @param {Array} params - event parameters
|
||||
* @return {Undefined}
|
||||
*/
|
||||
emit(event: string, ...params: Array<string>): void;
|
||||
/**
|
||||
* Returns a name of this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @kind constant
|
||||
* @return {String}
|
||||
*/
|
||||
readonly name: string;
|
||||
/**
|
||||
* Returns a hash of websocket objects connected to this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @return {Object}
|
||||
*/
|
||||
connected(): {};
|
||||
/**
|
||||
* Returns a list of client unique identifiers connected to this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @return {Array}
|
||||
*/
|
||||
clients(): {
|
||||
rpc_methods: IRPCMethod;
|
||||
clients: Map<string, IClientWebSocket>;
|
||||
events: INamespaceEvent;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Lists all created events in a given namespace. Defaults to "/".
|
||||
* @method
|
||||
* @param {String} ns - namespaces identifier
|
||||
* @readonly
|
||||
* @return {Array} - returns a list of created events
|
||||
*/
|
||||
eventList(ns?: string): string[];
|
||||
/**
|
||||
* Creates a JSON-RPC 2.0 compliant error
|
||||
* @method
|
||||
* @param {Number} code - indicates the error type that occurred
|
||||
* @param {String} message - provides a short description of the error
|
||||
* @param {String|Object} data - details containing additional information about the error
|
||||
* @return {Object}
|
||||
*/
|
||||
createError(code: number, message: string, data: string | object): {
|
||||
code: number;
|
||||
message: string;
|
||||
data: string | object;
|
||||
};
|
||||
/**
|
||||
* Closes the server and terminates all clients.
|
||||
* @method
|
||||
* @return {Promise}
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
/**
|
||||
* Handles all WebSocket JSON RPC 2.0 requests.
|
||||
* @private
|
||||
* @param {Object} socket - ws socket instance
|
||||
* @param {String} ns - namespaces identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
private _handleRPC;
|
||||
/**
|
||||
* Runs a defined RPC method.
|
||||
* @private
|
||||
* @param {Object} message - a message received
|
||||
* @param {Object} socket_id - user's socket id
|
||||
* @param {String} ns - namespaces identifier
|
||||
* @return {Object|undefined}
|
||||
*/
|
||||
private _runMethod;
|
||||
/**
|
||||
* Generate a new namespace store.
|
||||
* Also preregister some special namespace methods.
|
||||
* @private
|
||||
* @param {String} name - namespaces identifier
|
||||
* @return {undefined}
|
||||
*/
|
||||
private _generateNamespace;
|
||||
}
|
||||
/**
|
||||
* Creates a JSON-RPC 2.0-compliant error.
|
||||
* @param {Number} code - error code
|
||||
* @param {String} details - error details
|
||||
* @return {Object}
|
||||
*/
|
||||
declare function createError(code: number, details?: string): IRPCError;
|
||||
|
||||
/**
|
||||
* WebSocket implements a browser-side WebSocket specification.
|
||||
* @module Client
|
||||
*/
|
||||
|
||||
type WebSocketBrowserOptions = {
|
||||
/**
|
||||
* One or more protocols passed to the websocket constructor
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket
|
||||
*/
|
||||
protocols?: string | string[];
|
||||
};
|
||||
|
||||
declare class Client extends CommonClient {
|
||||
constructor(address?: string, { autoconnect, reconnect, reconnect_interval, max_reconnects, ...rest_options }?: IWSClientAdditionalOptions & NodeWebSocketTypeOptions, generate_request_id?: (method: string, params: object | Array<any>) => number | string);
|
||||
}
|
||||
|
||||
export { type BrowserWebSocketType, Client, CommonClient, type DataPack, DefaultDataPack, type ICommonWebSocket, type ICommonWebSocketFactory, type IQueue, type IWSClientAdditionalOptions, type IWSRequestParams, type NodeWebSocketType, type NodeWebSocketTypeOptions, Server, WebSocket$1 as WebSocket, type WebSocketBrowserOptions, createError };
|
||||
@@ -0,0 +1,605 @@
|
||||
/**
|
||||
* @fileoverview Rule to disallow use of the `RegExp` constructor in favor of regular expression literals
|
||||
* @author Milos Djermanovic
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const {
|
||||
CALL,
|
||||
CONSTRUCT,
|
||||
ReferenceTracker,
|
||||
} = require("@eslint-community/eslint-utils");
|
||||
const {
|
||||
RegExpValidator,
|
||||
visitRegExpAST,
|
||||
RegExpParser,
|
||||
} = require("@eslint-community/regexpp");
|
||||
const { canTokensBeAdjacent } = require("./utils/ast-utils");
|
||||
const { REGEXPP_LATEST_ECMA_VERSION } = require("./utils/regular-expressions");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines whether the given node is a string literal.
|
||||
* @param {ASTNode} node Node to check.
|
||||
* @returns {boolean} True if the node is a string literal.
|
||||
*/
|
||||
function isStringLiteral(node) {
|
||||
return node.type === "Literal" && typeof node.value === "string";
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given node is a regex literal.
|
||||
* @param {ASTNode} node Node to check.
|
||||
* @returns {boolean} True if the node is a regex literal.
|
||||
*/
|
||||
function isRegexLiteral(node) {
|
||||
return node.type === "Literal" && Object.hasOwn(node, "regex");
|
||||
}
|
||||
|
||||
const validPrecedingTokens = new Set([
|
||||
"(",
|
||||
";",
|
||||
"[",
|
||||
",",
|
||||
"=",
|
||||
"+",
|
||||
"*",
|
||||
"-",
|
||||
"?",
|
||||
"~",
|
||||
"%",
|
||||
"**",
|
||||
"!",
|
||||
"typeof",
|
||||
"instanceof",
|
||||
"&&",
|
||||
"||",
|
||||
"??",
|
||||
"return",
|
||||
"...",
|
||||
"delete",
|
||||
"void",
|
||||
"in",
|
||||
"<",
|
||||
">",
|
||||
"<=",
|
||||
">=",
|
||||
"==",
|
||||
"===",
|
||||
"!=",
|
||||
"!==",
|
||||
"<<",
|
||||
">>",
|
||||
">>>",
|
||||
"&",
|
||||
"|",
|
||||
"^",
|
||||
":",
|
||||
"{",
|
||||
"=>",
|
||||
"*=",
|
||||
"<<=",
|
||||
">>=",
|
||||
">>>=",
|
||||
"^=",
|
||||
"|=",
|
||||
"&=",
|
||||
"??=",
|
||||
"||=",
|
||||
"&&=",
|
||||
"**=",
|
||||
"+=",
|
||||
"-=",
|
||||
"/=",
|
||||
"%=",
|
||||
"/",
|
||||
"do",
|
||||
"break",
|
||||
"continue",
|
||||
"debugger",
|
||||
"case",
|
||||
"throw",
|
||||
]);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
disallowRedundantWrapping: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow use of the `RegExp` constructor in favor of regular expression literals",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/prefer-regex-literals",
|
||||
},
|
||||
|
||||
hasSuggestions: true,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
disallowRedundantWrapping: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedRegExp:
|
||||
"Use a regular expression literal instead of the 'RegExp' constructor.",
|
||||
replaceWithLiteral:
|
||||
"Replace with an equivalent regular expression literal.",
|
||||
replaceWithLiteralAndFlags:
|
||||
"Replace with an equivalent regular expression literal with flags '{{ flags }}'.",
|
||||
replaceWithIntendedLiteralAndFlags:
|
||||
"Replace with a regular expression literal with flags '{{ flags }}'.",
|
||||
unexpectedRedundantRegExp:
|
||||
"Regular expression literal is unnecessarily wrapped within a 'RegExp' constructor.",
|
||||
unexpectedRedundantRegExpWithFlags:
|
||||
"Use regular expression literal with flags instead of the 'RegExp' constructor.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [{ disallowRedundantWrapping }] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Determines whether the given node is a String.raw`` tagged template expression
|
||||
* with a static template literal.
|
||||
* @param {ASTNode} node Node to check.
|
||||
* @returns {boolean} True if the node is String.raw`` with a static template.
|
||||
*/
|
||||
function isStringRawTaggedStaticTemplateLiteral(node) {
|
||||
return (
|
||||
node.type === "TaggedTemplateExpression" &&
|
||||
astUtils.isSpecificMemberAccess(node.tag, "String", "raw") &&
|
||||
sourceCode.isGlobalReference(
|
||||
astUtils.skipChainExpression(node.tag).object,
|
||||
) &&
|
||||
astUtils.isStaticTemplateLiteral(node.quasi)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a string
|
||||
* @param {ASTNode} node The node to get the string of.
|
||||
* @returns {string|null} The value of the node.
|
||||
*/
|
||||
function getStringValue(node) {
|
||||
if (isStringLiteral(node)) {
|
||||
return node.value;
|
||||
}
|
||||
|
||||
if (astUtils.isStaticTemplateLiteral(node)) {
|
||||
return node.quasis[0].value.cooked;
|
||||
}
|
||||
|
||||
if (isStringRawTaggedStaticTemplateLiteral(node)) {
|
||||
return node.quasi.quasis[0].value.raw;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given node is considered to be a static string by the logic of this rule.
|
||||
* @param {ASTNode} node Node to check.
|
||||
* @returns {boolean} True if the node is a static string.
|
||||
*/
|
||||
function isStaticString(node) {
|
||||
return (
|
||||
isStringLiteral(node) ||
|
||||
astUtils.isStaticTemplateLiteral(node) ||
|
||||
isStringRawTaggedStaticTemplateLiteral(node)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the relevant arguments of the given are all static string literals.
|
||||
* @param {ASTNode} node Node to check.
|
||||
* @returns {boolean} True if all arguments are static strings.
|
||||
*/
|
||||
function hasOnlyStaticStringArguments(node) {
|
||||
const args = node.arguments;
|
||||
|
||||
if (
|
||||
(args.length === 1 || args.length === 2) &&
|
||||
args.every(isStaticString)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the arguments of the given node indicate that a regex literal is unnecessarily wrapped.
|
||||
* @param {ASTNode} node Node to check.
|
||||
* @returns {boolean} True if the node already contains a regex literal argument.
|
||||
*/
|
||||
function isUnnecessarilyWrappedRegexLiteral(node) {
|
||||
const args = node.arguments;
|
||||
|
||||
if (args.length === 1 && isRegexLiteral(args[0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
args.length === 2 &&
|
||||
isRegexLiteral(args[0]) &&
|
||||
isStaticString(args[1])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ecmaVersion compatible for regexpp.
|
||||
* @param {number} ecmaVersion The ecmaVersion to convert.
|
||||
* @returns {import("@eslint-community/regexpp/ecma-versions").EcmaVersion} The resulting ecmaVersion compatible for regexpp.
|
||||
*/
|
||||
function getRegexppEcmaVersion(ecmaVersion) {
|
||||
if (ecmaVersion <= 5) {
|
||||
return 5;
|
||||
}
|
||||
return Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION);
|
||||
}
|
||||
|
||||
const regexppEcmaVersion = getRegexppEcmaVersion(
|
||||
context.languageOptions.ecmaVersion,
|
||||
);
|
||||
|
||||
/**
|
||||
* Makes a character escaped or else returns null.
|
||||
* @param {string} character The character to escape.
|
||||
* @returns {string} The resulting escaped character.
|
||||
*/
|
||||
function resolveEscapes(character) {
|
||||
switch (character) {
|
||||
case "\n":
|
||||
case "\\\n":
|
||||
return "\\n";
|
||||
|
||||
case "\r":
|
||||
case "\\\r":
|
||||
return "\\r";
|
||||
|
||||
case "\t":
|
||||
case "\\\t":
|
||||
return "\\t";
|
||||
|
||||
case "\v":
|
||||
case "\\\v":
|
||||
return "\\v";
|
||||
|
||||
case "\f":
|
||||
case "\\\f":
|
||||
return "\\f";
|
||||
|
||||
case "/":
|
||||
return "\\/";
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given regex and flags are valid for the ecma version or not.
|
||||
* @param {string} pattern The regex pattern to check.
|
||||
* @param {string | undefined} flags The regex flags to check.
|
||||
* @returns {boolean} True if the given regex pattern and flags are valid for the ecma version.
|
||||
*/
|
||||
function isValidRegexForEcmaVersion(pattern, flags) {
|
||||
const validator = new RegExpValidator({
|
||||
ecmaVersion: regexppEcmaVersion,
|
||||
});
|
||||
|
||||
try {
|
||||
validator.validatePattern(pattern, 0, pattern.length, {
|
||||
unicode: flags ? flags.includes("u") : false,
|
||||
unicodeSets: flags ? flags.includes("v") : false,
|
||||
});
|
||||
if (flags) {
|
||||
validator.validateFlags(flags);
|
||||
}
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two given regex flags contain the same flags or not.
|
||||
* @param {string} flagsA The regex flags.
|
||||
* @param {string} flagsB The regex flags.
|
||||
* @returns {boolean} True if two regex flags contain same flags.
|
||||
*/
|
||||
function areFlagsEqual(flagsA, flagsB) {
|
||||
return [...flagsA].sort().join("") === [...flagsB].sort().join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two regex flags.
|
||||
* @param {string} flagsA The regex flags.
|
||||
* @param {string} flagsB The regex flags.
|
||||
* @returns {string} The merged regex flags.
|
||||
*/
|
||||
function mergeRegexFlags(flagsA, flagsB) {
|
||||
const flagsSet = new Set([...flagsA, ...flagsB]);
|
||||
|
||||
return [...flagsSet].join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a give node can be fixed to the given regex pattern and flags.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @param {string} pattern The regex pattern to check.
|
||||
* @param {string} flags The regex flags
|
||||
* @returns {boolean} True if a node can be fixed to the given regex pattern and flags.
|
||||
*/
|
||||
function canFixTo(node, pattern, flags) {
|
||||
const tokenBefore = sourceCode.getTokenBefore(node);
|
||||
|
||||
return (
|
||||
sourceCode.getCommentsInside(node).length === 0 &&
|
||||
(!tokenBefore || validPrecedingTokens.has(tokenBefore.value)) &&
|
||||
isValidRegexForEcmaVersion(pattern, flags)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a safe output code considering the before and after tokens.
|
||||
* @param {ASTNode} node The regex node.
|
||||
* @param {string} newRegExpValue The new regex expression value.
|
||||
* @returns {string} The output code.
|
||||
*/
|
||||
function getSafeOutput(node, newRegExpValue) {
|
||||
const tokenBefore = sourceCode.getTokenBefore(node);
|
||||
const tokenAfter = sourceCode.getTokenAfter(node);
|
||||
|
||||
return (
|
||||
(tokenBefore &&
|
||||
!canTokensBeAdjacent(tokenBefore, newRegExpValue) &&
|
||||
tokenBefore.range[1] === node.range[0]
|
||||
? " "
|
||||
: "") +
|
||||
newRegExpValue +
|
||||
(tokenAfter &&
|
||||
!canTokensBeAdjacent(newRegExpValue, tokenAfter) &&
|
||||
node.range[1] === tokenAfter.range[0]
|
||||
? " "
|
||||
: "")
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node);
|
||||
const tracker = new ReferenceTracker(scope);
|
||||
const traceMap = {
|
||||
RegExp: {
|
||||
[CALL]: true,
|
||||
[CONSTRUCT]: true,
|
||||
},
|
||||
};
|
||||
|
||||
for (const { node: refNode } of tracker.iterateGlobalReferences(
|
||||
traceMap,
|
||||
)) {
|
||||
if (
|
||||
disallowRedundantWrapping &&
|
||||
isUnnecessarilyWrappedRegexLiteral(refNode)
|
||||
) {
|
||||
const regexNode = refNode.arguments[0];
|
||||
|
||||
if (refNode.arguments.length === 2) {
|
||||
const suggests = [];
|
||||
|
||||
const argFlags =
|
||||
getStringValue(refNode.arguments[1]) || "";
|
||||
|
||||
if (
|
||||
canFixTo(
|
||||
refNode,
|
||||
regexNode.regex.pattern,
|
||||
argFlags,
|
||||
)
|
||||
) {
|
||||
suggests.push({
|
||||
messageId: "replaceWithLiteralAndFlags",
|
||||
pattern: regexNode.regex.pattern,
|
||||
flags: argFlags,
|
||||
});
|
||||
}
|
||||
|
||||
const literalFlags = regexNode.regex.flags || "";
|
||||
const mergedFlags = mergeRegexFlags(
|
||||
literalFlags,
|
||||
argFlags,
|
||||
);
|
||||
|
||||
if (
|
||||
!areFlagsEqual(mergedFlags, argFlags) &&
|
||||
canFixTo(
|
||||
refNode,
|
||||
regexNode.regex.pattern,
|
||||
mergedFlags,
|
||||
)
|
||||
) {
|
||||
suggests.push({
|
||||
messageId:
|
||||
"replaceWithIntendedLiteralAndFlags",
|
||||
pattern: regexNode.regex.pattern,
|
||||
flags: mergedFlags,
|
||||
});
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: refNode,
|
||||
messageId: "unexpectedRedundantRegExpWithFlags",
|
||||
suggest: suggests.map(
|
||||
({ flags, pattern, messageId }) => ({
|
||||
messageId,
|
||||
data: {
|
||||
flags,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(
|
||||
refNode,
|
||||
getSafeOutput(
|
||||
refNode,
|
||||
`/${pattern}/${flags}`,
|
||||
),
|
||||
);
|
||||
},
|
||||
}),
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const outputs = [];
|
||||
|
||||
if (
|
||||
canFixTo(
|
||||
refNode,
|
||||
regexNode.regex.pattern,
|
||||
regexNode.regex.flags,
|
||||
)
|
||||
) {
|
||||
outputs.push(sourceCode.getText(regexNode));
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: refNode,
|
||||
messageId: "unexpectedRedundantRegExp",
|
||||
suggest: outputs.map(output => ({
|
||||
messageId: "replaceWithLiteral",
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(
|
||||
refNode,
|
||||
getSafeOutput(refNode, output),
|
||||
);
|
||||
},
|
||||
})),
|
||||
});
|
||||
}
|
||||
} else if (hasOnlyStaticStringArguments(refNode)) {
|
||||
let regexContent = getStringValue(refNode.arguments[0]);
|
||||
let noFix = false;
|
||||
let flags;
|
||||
|
||||
if (refNode.arguments[1]) {
|
||||
flags = getStringValue(refNode.arguments[1]);
|
||||
}
|
||||
|
||||
if (!canFixTo(refNode, regexContent, flags)) {
|
||||
noFix = true;
|
||||
}
|
||||
|
||||
if (
|
||||
!/^[-\w\\[\](){} \t\r\n\v\f!@#$%^&*+=/~`.><?,'"|:;]*$/u.test(
|
||||
regexContent,
|
||||
)
|
||||
) {
|
||||
noFix = true;
|
||||
}
|
||||
|
||||
if (regexContent && !noFix) {
|
||||
let charIncrease = 0;
|
||||
|
||||
const ast = new RegExpParser({
|
||||
ecmaVersion: regexppEcmaVersion,
|
||||
}).parsePattern(
|
||||
regexContent,
|
||||
0,
|
||||
regexContent.length,
|
||||
{
|
||||
unicode: flags
|
||||
? flags.includes("u")
|
||||
: false,
|
||||
unicodeSets: flags
|
||||
? flags.includes("v")
|
||||
: false,
|
||||
},
|
||||
);
|
||||
|
||||
visitRegExpAST(ast, {
|
||||
onCharacterEnter(characterNode) {
|
||||
const escaped = resolveEscapes(
|
||||
characterNode.raw,
|
||||
);
|
||||
|
||||
if (escaped) {
|
||||
regexContent =
|
||||
regexContent.slice(
|
||||
0,
|
||||
characterNode.start +
|
||||
charIncrease,
|
||||
) +
|
||||
escaped +
|
||||
regexContent.slice(
|
||||
characterNode.end +
|
||||
charIncrease,
|
||||
);
|
||||
|
||||
if (characterNode.raw.length === 1) {
|
||||
charIncrease += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const newRegExpValue = `/${regexContent || "(?:)"}/${flags || ""}`;
|
||||
|
||||
context.report({
|
||||
node: refNode,
|
||||
messageId: "unexpectedRegExp",
|
||||
suggest: noFix
|
||||
? []
|
||||
: [
|
||||
{
|
||||
messageId: "replaceWithLiteral",
|
||||
fix(fixer) {
|
||||
return fixer.replaceText(
|
||||
refNode,
|
||||
getSafeOutput(
|
||||
refNode,
|
||||
newRegExpValue,
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hkdf.js","sourceRoot":"","sources":["../src/hkdf.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAc,KAAK,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,IAAW,EAAE,GAAU,EAAE,IAAY;IAC3D,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,kEAAkE;IAClE,sDAAsD;IACtD,+CAA+C;IAC/C,IAAI,IAAI,KAAK,SAAS;QAAE,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,IAAW,EAAE,GAAU,EAAE,IAAY,EAAE,SAAiB,EAAE;IAC/E,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,CAAC,MAAM,CAAC,CAAC;IAChB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;IAC5B,IAAI,MAAM,GAAG,GAAG,GAAG,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxC,IAAI,IAAI,KAAK,SAAS;QAAE,IAAI,GAAG,YAAY,CAAC;IAC5C,6BAA6B;IAC7B,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,sCAAsC;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IAClC,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;QAClD,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;QAC9B,oCAAoC;QACpC,2CAA2C;QAC3C,OAAO,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;aAC7C,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,CAAC,YAAY,CAAC;aACpB,UAAU,CAAC,CAAC,CAAC,CAAC;QACjB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;IACf,OAAO,CAAC,OAAO,EAAE,CAAC;IAClB,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAW,EACX,GAAU,EACV,IAAuB,EACvB,IAAuB,EACvB,MAAc,EACF,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC"}
|
||||
@@ -0,0 +1,264 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
test("type inference", () => {
|
||||
const schema = z.string().array();
|
||||
expectTypeOf<z.infer<typeof schema>>().toEqualTypeOf<string[]>();
|
||||
});
|
||||
|
||||
test("array min/max", () => {
|
||||
const schema = z.array(z.string()).min(2).max(2);
|
||||
const r1 = schema.safeParse(["asdf"]);
|
||||
expect(r1.success).toEqual(false);
|
||||
expect(r1.error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const r2 = schema.safeParse(["asdf", "asdf", "asdf"]);
|
||||
expect(r2.success).toEqual(false);
|
||||
expect(r2.error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_big",
|
||||
"inclusive": true,
|
||||
"maximum": 2,
|
||||
"message": "Too big: expected array to have <=2 items",
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test("array length", () => {
|
||||
const schema = z.array(z.string()).length(2);
|
||||
schema.parse(["asdf", "asdf"]);
|
||||
|
||||
const r1 = schema.safeParse(["asdf"]);
|
||||
expect(r1.success).toEqual(false);
|
||||
expect(r1.error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"exact": true,
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const r2 = schema.safeParse(["asdf", "asdf", "asdf"]);
|
||||
expect(r2.success).toEqual(false);
|
||||
expect(r2.error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_big",
|
||||
"exact": true,
|
||||
"inclusive": true,
|
||||
"maximum": 2,
|
||||
"message": "Too big: expected array to have <=2 items",
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test("array.nonempty()", () => {
|
||||
const schema = z.string().array().nonempty();
|
||||
schema.parse(["a"]);
|
||||
expect(() => schema.parse([])).toThrow();
|
||||
});
|
||||
|
||||
test("array.nonempty().max()", () => {
|
||||
const schema = z.string().array().nonempty().max(2);
|
||||
schema.parse(["a"]);
|
||||
expect(() => schema.parse([])).toThrow();
|
||||
expect(() => schema.parse(["a", "a", "a"])).toThrow();
|
||||
});
|
||||
|
||||
test("parse empty array in nonempty", () => {
|
||||
expect(() =>
|
||||
z
|
||||
.array(z.string())
|
||||
.nonempty()
|
||||
.parse([] as any)
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
test("get element", () => {
|
||||
const schema = z.string().array();
|
||||
schema.element.parse("asdf");
|
||||
expect(() => schema.element.parse(12)).toThrow();
|
||||
});
|
||||
|
||||
test("continue parsing despite array size error", () => {
|
||||
const schema = z.object({
|
||||
people: z.string().array().min(2),
|
||||
});
|
||||
|
||||
const result = schema.safeParse({
|
||||
people: [123],
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"people",
|
||||
0
|
||||
],
|
||||
"message": "Invalid input: expected string, received number"
|
||||
},
|
||||
{
|
||||
"origin": "array",
|
||||
"code": "too_small",
|
||||
"minimum": 2,
|
||||
"inclusive": true,
|
||||
"path": [
|
||||
"people"
|
||||
],
|
||||
"message": "Too small: expected array to have >=2 items"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("parse should fail given sparse array", () => {
|
||||
const schema = z.array(z.string()).nonempty().min(1).max(3);
|
||||
const result = schema.safeParse(new Array(3));
|
||||
expect(result.success).toEqual(false);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
0
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
1
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
2
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
// const unique = z.string().array().unique();
|
||||
// const uniqueArrayOfObjects = z.array(z.object({ name: z.string() })).unique({ identifier: (item) => item.name });
|
||||
|
||||
// test("passing unique validation", () => {
|
||||
// unique.parse(["a", "b", "c"]);
|
||||
// uniqueArrayOfObjects.parse([{ name: "Leo" }, { name: "Joe" }]);
|
||||
// });
|
||||
|
||||
// test("failing unique validation", () => {
|
||||
// expect(() => unique.parse(["a", "a", "b"])).toThrow();
|
||||
// expect(() => uniqueArrayOfObjects.parse([{ name: "Leo" }, { name: "Leo" }])).toThrow();
|
||||
// });
|
||||
|
||||
// test("continue parsing despite array of primitives uniqueness error", () => {
|
||||
// const schema = z.number().array().unique();
|
||||
|
||||
// const result = schema.safeParse([1, 1, 2, 2, 3]);
|
||||
|
||||
// expect(result.success).toEqual(false);
|
||||
// if (!result.success) {
|
||||
// const issue = result.error.issues.find(({ code }) => code === "not_unique");
|
||||
// expect(issue?.message).toEqual("Values must be unique");
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("continue parsing despite array of objects not_unique error", () => {
|
||||
// const schema = z.array(z.object({ name: z.string() })).unique({
|
||||
// identifier: (item) => item.name,
|
||||
// showDuplicates: true,
|
||||
// });
|
||||
|
||||
// const result = schema.safeParse([
|
||||
// { name: "Leo" },
|
||||
// { name: "Joe" },
|
||||
// { name: "Leo" },
|
||||
// ]);
|
||||
|
||||
// expect(result.success).toEqual(false);
|
||||
// if (!result.success) {
|
||||
// const issue = result.error.issues.find(({ code }) => code === "not_unique");
|
||||
// expect(issue?.message).toEqual("Element(s): 'Leo' not unique");
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("returns custom error message without duplicate elements", () => {
|
||||
// const schema = z.number().array().unique({ message: "Custom message" });
|
||||
|
||||
// const result = schema.safeParse([1, 1, 2, 2, 3]);
|
||||
|
||||
// expect(result.success).toEqual(false);
|
||||
// if (!result.success) {
|
||||
// const issue = result.error.issues.find(({ code }) => code === "not_unique");
|
||||
// expect(issue?.message).toEqual("Custom message");
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("returns error message with duplicate elements", () => {
|
||||
// const schema = z.number().array().unique({ showDuplicates: true });
|
||||
|
||||
// const result = schema.safeParse([1, 1, 2, 2, 3]);
|
||||
|
||||
// expect(result.success).toEqual(false);
|
||||
// if (!result.success) {
|
||||
// const issue = result.error.issues.find(({ code }) => code === "not_unique");
|
||||
// expect(issue?.message).toEqual("Element(s): '1,2' not unique");
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("returns custom error message with duplicate elements", () => {
|
||||
// const schema = z
|
||||
// .number()
|
||||
// .array()
|
||||
// .unique({
|
||||
// message: (item) => `Custom message: '${item}' are not unique`,
|
||||
// showDuplicates: true,
|
||||
// });
|
||||
|
||||
// const result = schema.safeParse([1, 1, 2, 2, 3]);
|
||||
|
||||
// expect(result.success).toEqual(false);
|
||||
// if (!result.success) {
|
||||
// const issue = result.error.issues.find(({ code }) => code === "not_unique");
|
||||
// expect(issue?.message).toEqual("Custom message: '1,2' are not unique");
|
||||
// }
|
||||
// });
|
||||
@@ -0,0 +1,23 @@
|
||||
export declare enum InternalSymbolName {
|
||||
Call = "__call",
|
||||
Constructor = "__constructor",
|
||||
New = "__new",
|
||||
Index = "__index",
|
||||
ExportStar = "__export",
|
||||
Global = "__global",
|
||||
Missing = "__missing",
|
||||
Type = "__type",
|
||||
Object = "__object",
|
||||
JSXAttributes = "__jsxAttributes",
|
||||
Class = "__class",
|
||||
Function = "__function",
|
||||
Computed = "__computed",
|
||||
AssignmentDeclaration = "__assignment",
|
||||
InstantiationExpression = "__instantiationExpression",
|
||||
ImportAttributes = "__importAttributes",
|
||||
ExportEquals = "export=",
|
||||
Default = "default",
|
||||
This = "this",
|
||||
ModuleExports = "module.exports"
|
||||
}
|
||||
//# sourceMappingURL=internalSymbolName.enum.d.ts.map
|
||||
@@ -0,0 +1,8 @@
|
||||
function _instanceof(left, right) {
|
||||
"@swc/helpers - instanceof";
|
||||
|
||||
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
||||
return !!right[Symbol.hasInstance](left);
|
||||
} else return left instanceof right;
|
||||
}
|
||||
export { _instanceof as _ };
|
||||
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
function _read_only_error(name) {
|
||||
throw new TypeError("\"" + name + "\" is read-only");
|
||||
}
|
||||
exports._ = _read_only_error;
|
||||
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
/* eslint no-prototype-builtins: 0 */
|
||||
|
||||
const test = require('node:test')
|
||||
const assert = require('node:assert')
|
||||
|
||||
const { sink, once } = require('./helper')
|
||||
|
||||
test('pino.stdTimeFunctions.isoTimeNano returns RFC 3339 timestamps', async () => {
|
||||
// Mock Date.now at module initialization time
|
||||
const now = Date.now
|
||||
Date.now = () => new Date('2025-08-01T15:03:45.000000000Z').getTime()
|
||||
|
||||
// Mock process.hrtime.bigint at module initialization time
|
||||
const hrTimeBigint = process.hrtime.bigint
|
||||
process.hrtime.bigint = () => 100000000000000n
|
||||
|
||||
const pino = require('../')
|
||||
|
||||
const opts = {
|
||||
timestamp: pino.stdTimeFunctions.isoTimeNano
|
||||
}
|
||||
const stream = sink()
|
||||
|
||||
// Mock process.hrtime.bigint at invocation time, add 1 day to the timestamp
|
||||
process.hrtime.bigint = () => 100000000000000n + 86400012345678n
|
||||
|
||||
const instance = pino(opts, stream)
|
||||
instance.info('foobar')
|
||||
const result = await once(stream, 'data')
|
||||
assert.equal(result.hasOwnProperty('time'), true)
|
||||
assert.equal(result.time, '2025-08-02T15:03:45.012345678Z')
|
||||
|
||||
Date.now = now
|
||||
process.hrtime.bigint = hrTimeBigint
|
||||
})
|
||||
@@ -0,0 +1,68 @@
|
||||
import Container, { ContainerProps } from './container.js'
|
||||
import { ProcessOptions } from './postcss.js'
|
||||
import Result from './result.js'
|
||||
import Root from './root.js'
|
||||
|
||||
declare namespace Document {
|
||||
export interface DocumentProps extends ContainerProps {
|
||||
nodes?: readonly Root[]
|
||||
|
||||
/**
|
||||
* Information to generate byte-to-byte equal node string as it was
|
||||
* in the origin input.
|
||||
*
|
||||
* Every parser saves its own properties.
|
||||
*/
|
||||
raws?: Record<string, any>
|
||||
}
|
||||
|
||||
export { Document_ as default }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a file and contains all its parsed nodes.
|
||||
*
|
||||
* **Experimental:** some aspects of this node could change within minor
|
||||
* or patch version releases.
|
||||
*
|
||||
* ```js
|
||||
* const document = htmlParser(
|
||||
* '<html><style>a{color:black}</style><style>b{z-index:2}</style>'
|
||||
* )
|
||||
* document.type //=> 'document'
|
||||
* document.nodes.length //=> 2
|
||||
* ```
|
||||
*/
|
||||
declare class Document_ extends Container<Root> {
|
||||
nodes: Root[]
|
||||
parent: undefined
|
||||
type: 'document'
|
||||
|
||||
constructor(defaults?: Document.DocumentProps)
|
||||
|
||||
assign(overrides: Document.DocumentProps | object): this
|
||||
clone(overrides?: Partial<Document.DocumentProps>): this
|
||||
cloneAfter(overrides?: Partial<Document.DocumentProps>): this
|
||||
cloneBefore(overrides?: Partial<Document.DocumentProps>): this
|
||||
|
||||
/**
|
||||
* Returns a `Result` instance representing the document’s CSS roots.
|
||||
*
|
||||
* ```js
|
||||
* const root1 = postcss.parse(css1, { from: 'a.css' })
|
||||
* const root2 = postcss.parse(css2, { from: 'b.css' })
|
||||
* const document = postcss.document()
|
||||
* document.append(root1)
|
||||
* document.append(root2)
|
||||
* const result = document.toResult({ to: 'all.css', map: true })
|
||||
* ```
|
||||
*
|
||||
* @param opts Options.
|
||||
* @return Result with current document’s CSS.
|
||||
*/
|
||||
toResult(options?: ProcessOptions): Result
|
||||
}
|
||||
|
||||
declare class Document extends Document_ {}
|
||||
|
||||
export = Document
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Colors } from "./types"
|
||||
|
||||
declare const picocolors: Colors & { createColors: (enabled?: boolean) => Colors }
|
||||
|
||||
export = picocolors
|
||||
@@ -0,0 +1,81 @@
|
||||
import type {
|
||||
ErrorPayload,
|
||||
FullReloadPayload,
|
||||
PrunePayload,
|
||||
UpdatePayload,
|
||||
} from './hmrPayload.js'
|
||||
|
||||
export interface CustomEventMap {
|
||||
// client events
|
||||
'vite:beforeUpdate': UpdatePayload
|
||||
'vite:afterUpdate': UpdatePayload
|
||||
'vite:beforePrune': PrunePayload
|
||||
'vite:beforeFullReload': FullReloadPayload
|
||||
'vite:error': ErrorPayload
|
||||
'vite:invalidate': InvalidatePayload
|
||||
'vite:ws:connect': WebSocketConnectionPayload
|
||||
'vite:ws:disconnect': WebSocketConnectionPayload
|
||||
/** @internal */
|
||||
'vite:forward-console': ForwardConsolePayload
|
||||
/** @internal */
|
||||
'vite:client-connected': { clientId: string }
|
||||
/** @internal */
|
||||
'vite:bundled-dev:reload-needed': { reason: string }
|
||||
|
||||
// server events
|
||||
'vite:client:connect': undefined
|
||||
'vite:client:disconnect': undefined
|
||||
}
|
||||
|
||||
export interface WebSocketConnectionPayload {
|
||||
/**
|
||||
* @experimental
|
||||
* We expose this instance experimentally to see potential usage.
|
||||
* This might be removed in the future if we didn't find reasonable use cases.
|
||||
* If you find this useful, please open an issue with details so we can discuss and make it stable API.
|
||||
*/
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
||||
webSocket: WebSocket
|
||||
}
|
||||
|
||||
export interface InvalidatePayload {
|
||||
path: string
|
||||
message: string | undefined
|
||||
firstInvalidatedBy: string
|
||||
}
|
||||
|
||||
export type ForwardConsolePayload =
|
||||
| {
|
||||
type: 'error'
|
||||
data: {
|
||||
name: string
|
||||
message: string
|
||||
stack?: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: 'unhandled-rejection'
|
||||
data: {
|
||||
name: string
|
||||
message: string
|
||||
stack?: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: 'log'
|
||||
data: {
|
||||
level: string
|
||||
message: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* provides types for payloads of built-in Vite events
|
||||
*/
|
||||
export type InferCustomEventPayload<T extends string> =
|
||||
T extends keyof CustomEventMap ? CustomEventMap[T] : any
|
||||
|
||||
/**
|
||||
* provides types for names of built-in Vite events
|
||||
*/
|
||||
export type CustomEventName = keyof CustomEventMap | (string & {})
|
||||
@@ -0,0 +1,64 @@
|
||||
"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 });
|
||||
exports.isArrayMethodCallWithPredicate = isArrayMethodCallWithPredicate;
|
||||
const type_utils_1 = require("@typescript-eslint/type-utils");
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const tsutils = __importStar(require("ts-api-utils"));
|
||||
const misc_1 = require("./misc");
|
||||
const ARRAY_PREDICATE_FUNCTIONS = new Set([
|
||||
'every',
|
||||
'filter',
|
||||
'find',
|
||||
'findIndex',
|
||||
'findLast',
|
||||
'findLastIndex',
|
||||
'some',
|
||||
]);
|
||||
function isArrayMethodCallWithPredicate(context, services, node) {
|
||||
if (node.callee.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
|
||||
return false;
|
||||
}
|
||||
const staticAccessValue = (0, misc_1.getStaticMemberAccessValue)(node.callee, context);
|
||||
if (!ARRAY_PREDICATE_FUNCTIONS.has(staticAccessValue)) {
|
||||
return false;
|
||||
}
|
||||
const checker = services.program.getTypeChecker();
|
||||
const type = (0, type_utils_1.getConstrainedTypeAtLocation)(services, node.callee.object);
|
||||
return tsutils
|
||||
.unionConstituents(type)
|
||||
.flatMap(part => tsutils.intersectionConstituents(part))
|
||||
.some(t => checker.isArrayType(t) || checker.isTupleType(t));
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
'use strict';
|
||||
|
||||
const uuid = require('uuid').v4;
|
||||
const generateRequest = require('../../generateRequest');
|
||||
|
||||
/**
|
||||
* Constructor for a Jayson Browser Client that does not depend any node.js core libraries
|
||||
* @class ClientBrowser
|
||||
* @param {Function} callServer Method that calls the server, receives the stringified request and a regular node-style callback
|
||||
* @param {Object} [options]
|
||||
* @param {Function} [options.reviver] Reviver function for JSON
|
||||
* @param {Function} [options.replacer] Replacer function for JSON
|
||||
* @param {Number} [options.version=2] JSON-RPC version to use (1|2)
|
||||
* @param {Function} [options.generator] Function to use for generating request IDs
|
||||
* @param {Boolean} [options.notificationIdNull=false] When true, version 2 requests will set id to null instead of omitting it
|
||||
* @return {ClientBrowser}
|
||||
*/
|
||||
const ClientBrowser = function(callServer, options) {
|
||||
if(!(this instanceof ClientBrowser)) {
|
||||
return new ClientBrowser(callServer, options);
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
this.options = {
|
||||
reviver: typeof options.reviver !== 'undefined' ? options.reviver : null,
|
||||
replacer: typeof options.replacer !== 'undefined' ? options.replacer : null,
|
||||
generator: typeof options.generator !== 'undefined' ? options.generator : function() { return uuid(); },
|
||||
version: typeof options.version !== 'undefined' ? options.version : 2,
|
||||
notificationIdNull: typeof options.notificationIdNull === 'boolean' ? options.notificationIdNull : false,
|
||||
};
|
||||
|
||||
this.callServer = callServer;
|
||||
};
|
||||
|
||||
module.exports = ClientBrowser;
|
||||
|
||||
/**
|
||||
* Creates a request and dispatches it if given a callback.
|
||||
* @param {String|Array} method A batch request if passed an Array, or a method name if passed a String
|
||||
* @param {Array|Object} [params] Parameters for the method
|
||||
* @param {String|Number} [id] Optional id. If undefined an id will be generated. If null it creates a notification request
|
||||
* @param {Function} [callback] Request callback. If specified, executes the request rather than only returning it.
|
||||
* @throws {TypeError} Invalid parameters
|
||||
* @return {Object} JSON-RPC 1.0 or 2.0 compatible request
|
||||
*/
|
||||
ClientBrowser.prototype.request = function(method, params, id, callback) {
|
||||
const self = this;
|
||||
let request = null;
|
||||
|
||||
// is this a batch request?
|
||||
const isBatch = Array.isArray(method) && typeof params === 'function';
|
||||
|
||||
if (this.options.version === 1 && isBatch) {
|
||||
throw new TypeError('JSON-RPC 1.0 does not support batching');
|
||||
}
|
||||
|
||||
// is this a raw request?
|
||||
const isRaw = !isBatch && method && typeof method === 'object' && typeof params === 'function';
|
||||
|
||||
if(isBatch || isRaw) {
|
||||
callback = params;
|
||||
request = method;
|
||||
} else {
|
||||
if(typeof id === 'function') {
|
||||
callback = id;
|
||||
// specifically undefined because "null" is a notification request
|
||||
id = undefined;
|
||||
}
|
||||
|
||||
const hasCallback = typeof callback === 'function';
|
||||
|
||||
try {
|
||||
request = generateRequest(method, params, id, {
|
||||
generator: this.options.generator,
|
||||
version: this.options.version,
|
||||
notificationIdNull: this.options.notificationIdNull,
|
||||
});
|
||||
} catch(err) {
|
||||
if(hasCallback) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
// no callback means we should just return a raw request
|
||||
if(!hasCallback) {
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let message;
|
||||
try {
|
||||
message = JSON.stringify(request, this.options.replacer);
|
||||
} catch(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.callServer(message, function(err, response) {
|
||||
self._parseResponse(err, response, callback);
|
||||
});
|
||||
|
||||
// always return the raw request
|
||||
return request;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses a response from a server
|
||||
* @param {Object} err Error to pass on that is unrelated to the actual response
|
||||
* @param {String} responseText JSON-RPC 1.0 or 2.0 response
|
||||
* @param {Function} callback Callback that will receive different arguments depending on the amount of parameters
|
||||
* @private
|
||||
*/
|
||||
ClientBrowser.prototype._parseResponse = function(err, responseText, callback) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!responseText) {
|
||||
// empty response text, assume that is correct because it could be a
|
||||
// notification which jayson does not give any body for
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = JSON.parse(responseText, this.options.reviver);
|
||||
} catch(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if(callback.length === 3) {
|
||||
// if callback length is 3, we split callback arguments on error and response
|
||||
|
||||
// is batch response?
|
||||
if(Array.isArray(response)) {
|
||||
|
||||
// necessary to split strictly on validity according to spec here
|
||||
const isError = function(res) {
|
||||
return typeof res.error !== 'undefined';
|
||||
};
|
||||
|
||||
const isNotError = function (res) {
|
||||
return !isError(res);
|
||||
};
|
||||
|
||||
callback(null, response.filter(isError), response.filter(isNotError));
|
||||
return;
|
||||
} else {
|
||||
|
||||
// split regardless of validity
|
||||
callback(null, response.error, response.result);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
callback(null, response);
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { T as Plugin, Ut as MaybePromise } from "./shared/define-config-Dsp5YQR4.mjs";
|
||||
//#region src/plugin/parallel-plugin-implementation.d.ts
|
||||
type ParallelPluginImplementation = Plugin;
|
||||
type Context = {
|
||||
/**
|
||||
* Thread number
|
||||
*/
|
||||
threadNumber: number;
|
||||
};
|
||||
declare function defineParallelPluginImplementation<Options>(plugin: (Options: Options, context: Context) => MaybePromise<ParallelPluginImplementation>): (Options: Options, context: Context) => MaybePromise<ParallelPluginImplementation>;
|
||||
//#endregion
|
||||
export { type Context, type ParallelPluginImplementation, defineParallelPluginImplementation };
|
||||
@@ -0,0 +1,137 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = default_1;
|
||||
const util = __importStar(require("../core/util.cjs"));
|
||||
const error = () => {
|
||||
const Sizable = {
|
||||
string: { unit: "tecken", verb: "att ha" },
|
||||
file: { unit: "bytes", verb: "att ha" },
|
||||
array: { unit: "objekt", verb: "att innehålla" },
|
||||
set: { unit: "objekt", verb: "att innehålla" },
|
||||
};
|
||||
function getSizing(origin) {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
const FormatDictionary = {
|
||||
regex: "reguljärt uttryck",
|
||||
email: "e-postadress",
|
||||
url: "URL",
|
||||
emoji: "emoji",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "ISO-datum och tid",
|
||||
date: "ISO-datum",
|
||||
time: "ISO-tid",
|
||||
duration: "ISO-varaktighet",
|
||||
ipv4: "IPv4-intervall",
|
||||
ipv6: "IPv6-intervall",
|
||||
cidrv4: "IPv4-spektrum",
|
||||
cidrv6: "IPv6-spektrum",
|
||||
base64: "base64-kodad sträng",
|
||||
base64url: "base64url-kodad sträng",
|
||||
json_string: "JSON-sträng",
|
||||
e164: "E.164-nummer",
|
||||
jwt: "JWT",
|
||||
template_literal: "mall-literal",
|
||||
};
|
||||
const TypeDictionary = {
|
||||
nan: "NaN",
|
||||
number: "antal",
|
||||
array: "lista",
|
||||
};
|
||||
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 `Ogiltig inmatning: förväntat instanceof ${issue.expected}, fick ${received}`;
|
||||
}
|
||||
return `Ogiltig inmatning: förväntat ${expected}, fick ${received}`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1)
|
||||
return `Ogiltig inmatning: förväntat ${util.stringifyPrimitive(issue.values[0])}`;
|
||||
return `Ogiltigt val: förväntade en av ${util.joinValues(issue.values, "|")}`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "<=" : "<";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `För stor(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.maximum.toString()} ${sizing.unit ?? "element"}`;
|
||||
}
|
||||
return `För stor(t): förväntat ${issue.origin ?? "värdet"} att ha ${adj}${issue.maximum.toString()}`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? ">=" : ">";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `För lite(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
}
|
||||
return `För lite(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.minimum.toString()}`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue;
|
||||
if (_issue.format === "starts_with") {
|
||||
return `Ogiltig sträng: måste börja med "${_issue.prefix}"`;
|
||||
}
|
||||
if (_issue.format === "ends_with")
|
||||
return `Ogiltig sträng: måste sluta med "${_issue.suffix}"`;
|
||||
if (_issue.format === "includes")
|
||||
return `Ogiltig sträng: måste innehålla "${_issue.includes}"`;
|
||||
if (_issue.format === "regex")
|
||||
return `Ogiltig sträng: måste matcha mönstret "${_issue.pattern}"`;
|
||||
return `Ogiltig(t) ${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `Ogiltigt tal: måste vara en multipel av ${issue.divisor}`;
|
||||
case "unrecognized_keys":
|
||||
return `${issue.keys.length > 1 ? "Okända nycklar" : "Okänd nyckel"}: ${util.joinValues(issue.keys, ", ")}`;
|
||||
case "invalid_key":
|
||||
return `Ogiltig nyckel i ${issue.origin ?? "värdet"}`;
|
||||
case "invalid_union":
|
||||
return "Ogiltig input";
|
||||
case "invalid_element":
|
||||
return `Ogiltigt värde i ${issue.origin ?? "värdet"}`;
|
||||
default:
|
||||
return `Ogiltig input`;
|
||||
}
|
||||
};
|
||||
};
|
||||
function default_1() {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
module.exports = exports.default;
|
||||
@@ -0,0 +1,270 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const prettifyMessage = require('./prettify-message')
|
||||
const getColorizer = require('../colors')
|
||||
const {
|
||||
LEVEL_KEY,
|
||||
LEVEL_LABEL
|
||||
} = require('../constants')
|
||||
const context = {
|
||||
colorizer: getColorizer(),
|
||||
levelKey: LEVEL_KEY,
|
||||
levelLabel: LEVEL_LABEL,
|
||||
messageKey: 'msg'
|
||||
}
|
||||
|
||||
test('returns `undefined` if `messageKey` not found', t => {
|
||||
const str = prettifyMessage({ log: {}, context })
|
||||
t.assert.strictEqual(str, undefined)
|
||||
})
|
||||
|
||||
test('returns `undefined` if `messageKey` not string', t => {
|
||||
const str = prettifyMessage({ log: { msg: {} }, context })
|
||||
t.assert.strictEqual(str, undefined)
|
||||
})
|
||||
|
||||
test('returns non-colorized value for default colorizer', t => {
|
||||
const colorizer = getColorizer()
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo' },
|
||||
context: { ...context, colorizer }
|
||||
})
|
||||
t.assert.strictEqual(str, 'foo')
|
||||
})
|
||||
|
||||
test('returns non-colorized value for alternate `messageKey`', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { message: 'foo' },
|
||||
context: { ...context, messageKey: 'message' }
|
||||
})
|
||||
t.assert.strictEqual(str, 'foo')
|
||||
})
|
||||
|
||||
test('returns colorized value for color colorizer', t => {
|
||||
const colorizer = getColorizer(true)
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo' },
|
||||
context: { ...context, colorizer }
|
||||
})
|
||||
t.assert.strictEqual(str, '\u001B[36mfoo\u001B[39m')
|
||||
})
|
||||
|
||||
test('returns colorized value for color colorizer for alternate `messageKey`', t => {
|
||||
const colorizer = getColorizer(true)
|
||||
const str = prettifyMessage({
|
||||
log: { message: 'foo' },
|
||||
context: { ...context, messageKey: 'message', colorizer }
|
||||
})
|
||||
t.assert.strictEqual(str, '\u001B[36mfoo\u001B[39m')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule' },
|
||||
context: { ...context, messageFormat: '{context} - {msg}' }
|
||||
})
|
||||
t.assert.strictEqual(str, 'appModule - foo')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - missing prop', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { context: 'appModule' },
|
||||
context: { ...context, messageFormat: '{context} - {msg}' }
|
||||
})
|
||||
t.assert.strictEqual(str, 'appModule - ')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - levelLabel & useOnlyCustomProps false', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: {}
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '[30] INFO appModule - foo')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - levelLabel & useOnlyCustomProps true', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 30: 'CHECK' },
|
||||
useOnlyCustomProps: true
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '[30] CHECK appModule - foo')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - levelLabel & customLevels', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 123 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 123: 'CUSTOM' }
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '[123] CUSTOM appModule - foo')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - levelLabel, customLevels & useOnlyCustomProps', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 123 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 123: 'CUSTOM' },
|
||||
useOnlyCustomProps: true
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '[123] CUSTOM appModule - foo')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - levelLabel, customLevels & useOnlyCustomProps false', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { msg: 'foo', context: 'appModule', level: 40 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '[{level}] {levelLabel} {context} - {msg}',
|
||||
customLevels: { 123: 'CUSTOM' },
|
||||
useOnlyCustomProps: false
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '[40] WARN appModule - foo')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - value 0', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { value: 0 },
|
||||
context: { ...context, messageFormat: '{value}' },
|
||||
})
|
||||
t.assert.strictEqual(str, '0')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - value false', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { value: false },
|
||||
context: { ...context, messageFormat: '{value}' },
|
||||
})
|
||||
t.assert.strictEqual(str, 'false')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - value undefined', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { value: undefined },
|
||||
context: { ...context, messageFormat: '{value}' },
|
||||
})
|
||||
t.assert.strictEqual(str, '')
|
||||
})
|
||||
|
||||
test('returns message formatted by `messageFormat` option - value null', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { value: null },
|
||||
context: { ...context, messageFormat: '{value}' },
|
||||
})
|
||||
t.assert.strictEqual(str, 'null')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports nested curly brackets', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30 },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '{{level}}-{level}-{{level}-{level}}'
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '{30}-30-{30-30}')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports nested object', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'foo' },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '{request.url} - param: {request.params.process} - {msg}'
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, 'localhost/test - param: - foo')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports conditional blocks', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, req: { id: 'foo' } },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: '{level} | {if req.id}({req.id}){end}{if msg}{msg}{end}'
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '30 | (foo)')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports function definition', t => {
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'incoming request' },
|
||||
context: {
|
||||
...context,
|
||||
messageFormat: (log, messageKey, levelLabel) => {
|
||||
let msg = log[messageKey]
|
||||
if (msg === 'incoming request') msg = `--> ${log.request.url}`
|
||||
return msg
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '--> localhost/test')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports function definition with colorizer object', t => {
|
||||
const colorizer = getColorizer(true)
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'incoming request' },
|
||||
context: {
|
||||
...context,
|
||||
colorizer,
|
||||
messageFormat: (log, messageKey, levelLabel, { colors }) => {
|
||||
let msg = log[messageKey]
|
||||
if (msg === 'incoming request') msg = `--> ${colors.red(log.request.url)}`
|
||||
return msg
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '\u001B[36m--> \u001B[31mlocalhost/test\u001B[36m\u001B[39m')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports function definition with colorizer object when using custom colors', t => {
|
||||
const colorizer = getColorizer(true, [[30, 'brightGreen']], false)
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'incoming request' },
|
||||
context: {
|
||||
...context,
|
||||
colorizer,
|
||||
messageFormat: (log, messageKey, levelLabel, { colors }) => {
|
||||
let msg = log[messageKey]
|
||||
if (msg === 'incoming request') msg = `--> ${colors.red(log.request.url)}`
|
||||
return msg
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '\u001B[36m--> \u001B[31mlocalhost/test\u001B[36m\u001B[39m')
|
||||
})
|
||||
|
||||
test('`messageFormat` supports function definition with colorizer object when no color is supported', t => {
|
||||
const colorizer = getColorizer(false)
|
||||
const str = prettifyMessage({
|
||||
log: { level: 30, request: { url: 'localhost/test' }, msg: 'incoming request' },
|
||||
context: {
|
||||
...context,
|
||||
colorizer,
|
||||
messageFormat: (log, messageKey, levelLabel, { colors }) => {
|
||||
let msg = log[messageKey]
|
||||
if (msg === 'incoming request') msg = `--> ${colors.red(log.request.url)}`
|
||||
return msg
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(str, '--> localhost/test')
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
export declare enum ScopeType {
|
||||
block = "block",
|
||||
catch = "catch",
|
||||
class = "class",
|
||||
classFieldInitializer = "class-field-initializer",
|
||||
classStaticBlock = "class-static-block",
|
||||
conditionalType = "conditionalType",
|
||||
for = "for",
|
||||
function = "function",
|
||||
functionExpressionName = "function-expression-name",
|
||||
functionType = "functionType",
|
||||
global = "global",
|
||||
mappedType = "mappedType",
|
||||
module = "module",
|
||||
switch = "switch",
|
||||
tsEnum = "tsEnum",
|
||||
tsModule = "tsModule",
|
||||
type = "type",
|
||||
with = "with"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*! *****************************************************************************
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
|
||||
// src/watchGuard/watchGuard.ts
|
||||
var fs = __toESM(require("fs"));
|
||||
if (process.argv.length < 3) {
|
||||
process.exit(1);
|
||||
}
|
||||
var directoryName = process.argv[2];
|
||||
try {
|
||||
const watcher = fs.watch(directoryName, { recursive: true }, () => ({}));
|
||||
watcher.close();
|
||||
} catch {
|
||||
}
|
||||
process.exit(0);
|
||||
//# sourceMappingURL=watchGuard.js.map
|
||||
@@ -0,0 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
const { Writable } = require('stream')
|
||||
const { threadName, parentPort } = require('worker_threads')
|
||||
|
||||
module.exports = function () {
|
||||
parentPort.once('message', function ({ port }) {
|
||||
port.postMessage({ threadName })
|
||||
})
|
||||
|
||||
return new Writable({
|
||||
write (chunk, encoding, callback) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ConditionalTypeScope = void 0;
|
||||
const ScopeBase_1 = require("./ScopeBase");
|
||||
const ScopeType_1 = require("./ScopeType");
|
||||
class ConditionalTypeScope extends ScopeBase_1.ScopeBase {
|
||||
constructor(scopeManager, upperScope, block) {
|
||||
super(scopeManager, ScopeType_1.ScopeType.conditionalType, upperScope, block, false);
|
||||
}
|
||||
}
|
||||
exports.ConditionalTypeScope = ConditionalTypeScope;
|
||||
@@ -0,0 +1,218 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var tty = require('tty');
|
||||
|
||||
function _interopNamespace(e) {
|
||||
if (e && e.__esModule) return e;
|
||||
var n = Object.create(null);
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||
Object.defineProperty(n, k, d.get ? d : {
|
||||
enumerable: true,
|
||||
get: function () { return e[k]; }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
n["default"] = e;
|
||||
return Object.freeze(n);
|
||||
}
|
||||
|
||||
var tty__namespace = /*#__PURE__*/_interopNamespace(tty);
|
||||
|
||||
const {
|
||||
env = {},
|
||||
argv = [],
|
||||
platform = "",
|
||||
} = typeof process === "undefined" ? {} : process;
|
||||
|
||||
const isDisabled = "NO_COLOR" in env || argv.includes("--no-color");
|
||||
const isForced = "FORCE_COLOR" in env || argv.includes("--color");
|
||||
const isWindows = platform === "win32";
|
||||
const isDumbTerminal = env.TERM === "dumb";
|
||||
|
||||
const isCompatibleTerminal =
|
||||
tty__namespace && tty__namespace.isatty && tty__namespace.isatty(1) && env.TERM && !isDumbTerminal;
|
||||
|
||||
const isCI =
|
||||
"CI" in env &&
|
||||
("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env);
|
||||
|
||||
const isColorSupported =
|
||||
!isDisabled &&
|
||||
(isForced || (isWindows && !isDumbTerminal) || isCompatibleTerminal || isCI);
|
||||
|
||||
const replaceClose = (
|
||||
index,
|
||||
string,
|
||||
close,
|
||||
replace,
|
||||
head = string.substring(0, index) + replace,
|
||||
tail = string.substring(index + close.length),
|
||||
next = tail.indexOf(close)
|
||||
) => head + (next < 0 ? tail : replaceClose(next, tail, close, replace));
|
||||
|
||||
const clearBleed = (index, string, open, close, replace) =>
|
||||
index < 0
|
||||
? open + string + close
|
||||
: open + replaceClose(index, string, close, replace) + close;
|
||||
|
||||
const filterEmpty =
|
||||
(open, close, replace = open, at = open.length + 1) =>
|
||||
(string) =>
|
||||
string || !(string === "" || string === undefined)
|
||||
? clearBleed(
|
||||
("" + string).indexOf(close, at),
|
||||
string,
|
||||
open,
|
||||
close,
|
||||
replace
|
||||
)
|
||||
: "";
|
||||
|
||||
const init = (open, close, replace) =>
|
||||
filterEmpty(`\x1b[${open}m`, `\x1b[${close}m`, replace);
|
||||
|
||||
const colors = {
|
||||
reset: init(0, 0),
|
||||
bold: init(1, 22, "\x1b[22m\x1b[1m"),
|
||||
dim: init(2, 22, "\x1b[22m\x1b[2m"),
|
||||
italic: init(3, 23),
|
||||
underline: init(4, 24),
|
||||
inverse: init(7, 27),
|
||||
hidden: init(8, 28),
|
||||
strikethrough: init(9, 29),
|
||||
black: init(30, 39),
|
||||
red: init(31, 39),
|
||||
green: init(32, 39),
|
||||
yellow: init(33, 39),
|
||||
blue: init(34, 39),
|
||||
magenta: init(35, 39),
|
||||
cyan: init(36, 39),
|
||||
white: init(37, 39),
|
||||
gray: init(90, 39),
|
||||
bgBlack: init(40, 49),
|
||||
bgRed: init(41, 49),
|
||||
bgGreen: init(42, 49),
|
||||
bgYellow: init(43, 49),
|
||||
bgBlue: init(44, 49),
|
||||
bgMagenta: init(45, 49),
|
||||
bgCyan: init(46, 49),
|
||||
bgWhite: init(47, 49),
|
||||
blackBright: init(90, 39),
|
||||
redBright: init(91, 39),
|
||||
greenBright: init(92, 39),
|
||||
yellowBright: init(93, 39),
|
||||
blueBright: init(94, 39),
|
||||
magentaBright: init(95, 39),
|
||||
cyanBright: init(96, 39),
|
||||
whiteBright: init(97, 39),
|
||||
bgBlackBright: init(100, 49),
|
||||
bgRedBright: init(101, 49),
|
||||
bgGreenBright: init(102, 49),
|
||||
bgYellowBright: init(103, 49),
|
||||
bgBlueBright: init(104, 49),
|
||||
bgMagentaBright: init(105, 49),
|
||||
bgCyanBright: init(106, 49),
|
||||
bgWhiteBright: init(107, 49),
|
||||
};
|
||||
|
||||
const createColors = ({ useColor = isColorSupported } = {}) =>
|
||||
useColor
|
||||
? colors
|
||||
: Object.keys(colors).reduce(
|
||||
(colors, key) => ({ ...colors, [key]: String }),
|
||||
{}
|
||||
);
|
||||
|
||||
const {
|
||||
reset,
|
||||
bold,
|
||||
dim,
|
||||
italic,
|
||||
underline,
|
||||
inverse,
|
||||
hidden,
|
||||
strikethrough,
|
||||
black,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
gray,
|
||||
bgBlack,
|
||||
bgRed,
|
||||
bgGreen,
|
||||
bgYellow,
|
||||
bgBlue,
|
||||
bgMagenta,
|
||||
bgCyan,
|
||||
bgWhite,
|
||||
blackBright,
|
||||
redBright,
|
||||
greenBright,
|
||||
yellowBright,
|
||||
blueBright,
|
||||
magentaBright,
|
||||
cyanBright,
|
||||
whiteBright,
|
||||
bgBlackBright,
|
||||
bgRedBright,
|
||||
bgGreenBright,
|
||||
bgYellowBright,
|
||||
bgBlueBright,
|
||||
bgMagentaBright,
|
||||
bgCyanBright,
|
||||
bgWhiteBright,
|
||||
} = createColors();
|
||||
|
||||
exports.bgBlack = bgBlack;
|
||||
exports.bgBlackBright = bgBlackBright;
|
||||
exports.bgBlue = bgBlue;
|
||||
exports.bgBlueBright = bgBlueBright;
|
||||
exports.bgCyan = bgCyan;
|
||||
exports.bgCyanBright = bgCyanBright;
|
||||
exports.bgGreen = bgGreen;
|
||||
exports.bgGreenBright = bgGreenBright;
|
||||
exports.bgMagenta = bgMagenta;
|
||||
exports.bgMagentaBright = bgMagentaBright;
|
||||
exports.bgRed = bgRed;
|
||||
exports.bgRedBright = bgRedBright;
|
||||
exports.bgWhite = bgWhite;
|
||||
exports.bgWhiteBright = bgWhiteBright;
|
||||
exports.bgYellow = bgYellow;
|
||||
exports.bgYellowBright = bgYellowBright;
|
||||
exports.black = black;
|
||||
exports.blackBright = blackBright;
|
||||
exports.blue = blue;
|
||||
exports.blueBright = blueBright;
|
||||
exports.bold = bold;
|
||||
exports.createColors = createColors;
|
||||
exports.cyan = cyan;
|
||||
exports.cyanBright = cyanBright;
|
||||
exports.dim = dim;
|
||||
exports.gray = gray;
|
||||
exports.green = green;
|
||||
exports.greenBright = greenBright;
|
||||
exports.hidden = hidden;
|
||||
exports.inverse = inverse;
|
||||
exports.isColorSupported = isColorSupported;
|
||||
exports.italic = italic;
|
||||
exports.magenta = magenta;
|
||||
exports.magentaBright = magentaBright;
|
||||
exports.red = red;
|
||||
exports.redBright = redBright;
|
||||
exports.reset = reset;
|
||||
exports.strikethrough = strikethrough;
|
||||
exports.underline = underline;
|
||||
exports.white = white;
|
||||
exports.whiteBright = whiteBright;
|
||||
exports.yellow = yellow;
|
||||
exports.yellowBright = yellowBright;
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"signatureKind.js","sourceRoot":"","sources":["../../src/enums/signatureKind.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,CAAC,IAAI,aAAkB,CAAC;AAC9B,CAAC,UAAU,aAAa;IACpB,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IAClD,aAAa,CAAC,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;AAChE,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,CAAC,CAAC"}
|
||||
@@ -0,0 +1,349 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createValidator = createValidator;
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const util_1 = require("../../util");
|
||||
const enums_1 = require("./enums");
|
||||
const format_1 = require("./format");
|
||||
const shared_1 = require("./shared");
|
||||
function createValidator(type, context, allConfigs) {
|
||||
// make sure the "highest priority" configs are checked first
|
||||
const selectorType = enums_1.Selectors[type];
|
||||
const configs = allConfigs
|
||||
// gather all of the applicable selectors
|
||||
.filter(c => (c.selector & selectorType) !== 0 ||
|
||||
c.selector === enums_1.MetaSelectors.default)
|
||||
.sort((a, b) => {
|
||||
if (a.selector === b.selector) {
|
||||
// in the event of the same selector, order by modifier weight
|
||||
// sort descending - the type modifiers are "more important"
|
||||
return b.modifierWeight - a.modifierWeight;
|
||||
}
|
||||
const aIsMeta = (0, shared_1.isMetaSelector)(a.selector);
|
||||
const bIsMeta = (0, shared_1.isMetaSelector)(b.selector);
|
||||
// non-meta selectors should go ahead of meta selectors
|
||||
if (aIsMeta && !bIsMeta) {
|
||||
return 1;
|
||||
}
|
||||
if (!aIsMeta && bIsMeta) {
|
||||
return -1;
|
||||
}
|
||||
const aIsMethodOrProperty = (0, shared_1.isMethodOrPropertySelector)(a.selector);
|
||||
const bIsMethodOrProperty = (0, shared_1.isMethodOrPropertySelector)(b.selector);
|
||||
// for backward compatibility, method and property have higher precedence than other meta selectors
|
||||
if (aIsMethodOrProperty && !bIsMethodOrProperty) {
|
||||
return -1;
|
||||
}
|
||||
if (!aIsMethodOrProperty && bIsMethodOrProperty) {
|
||||
return 1;
|
||||
}
|
||||
// both aren't meta selectors
|
||||
// sort descending - the meta selectors are "least important"
|
||||
return b.selector - a.selector;
|
||||
});
|
||||
return (node, modifiers = new Set()) => {
|
||||
const originalName = node.type === utils_1.AST_NODE_TYPES.Identifier ||
|
||||
node.type === utils_1.AST_NODE_TYPES.PrivateIdentifier
|
||||
? node.name
|
||||
: `${node.value}`;
|
||||
// return will break the loop and stop checking configs
|
||||
// it is only used when the name is known to have failed or succeeded a config.
|
||||
for (const config of configs) {
|
||||
if (config.filter?.regex.test(originalName) !== config.filter?.match) {
|
||||
// name does not match the filter
|
||||
continue;
|
||||
}
|
||||
if (config.modifiers?.some(modifier => !modifiers.has(modifier))) {
|
||||
// does not have the required modifiers
|
||||
continue;
|
||||
}
|
||||
if (!isCorrectType(node, config, context, selectorType)) {
|
||||
// is not the correct type
|
||||
continue;
|
||||
}
|
||||
let name = originalName;
|
||||
name = validateUnderscore('leading', config, name, node, originalName);
|
||||
if (name == null) {
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
name = validateUnderscore('trailing', config, name, node, originalName);
|
||||
if (name == null) {
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
name = validateAffix('prefix', config, name, node, originalName);
|
||||
if (name == null) {
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
name = validateAffix('suffix', config, name, node, originalName);
|
||||
if (name == null) {
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
if (!validateCustom(config, name, node, originalName)) {
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
if (!validatePredefinedFormat(config, name, node, originalName, modifiers)) {
|
||||
// fail
|
||||
return;
|
||||
}
|
||||
// it's valid for this config, so we don't need to check any more configs
|
||||
return;
|
||||
}
|
||||
};
|
||||
// centralizes the logic for formatting the report data
|
||||
function formatReportData({ affixes, count, custom, formats, originalName, position, processedName, }) {
|
||||
return {
|
||||
affixes: affixes?.join(', '),
|
||||
count,
|
||||
formats: formats?.map(f => enums_1.PredefinedFormats[f]).join(', '),
|
||||
name: originalName,
|
||||
position,
|
||||
processedName,
|
||||
regex: custom?.regex.toString(),
|
||||
regexMatch: custom?.match === true
|
||||
? 'match'
|
||||
: custom?.match === false
|
||||
? 'not match'
|
||||
: null,
|
||||
type: (0, shared_1.selectorTypeToMessageString)(type),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @returns the name with the underscore removed, if it is valid according to the specified underscore option, null otherwise
|
||||
*/
|
||||
function validateUnderscore(position, config, name, node, originalName) {
|
||||
const option = position === 'leading'
|
||||
? config.leadingUnderscore
|
||||
: config.trailingUnderscore;
|
||||
if (!option) {
|
||||
return name;
|
||||
}
|
||||
const hasSingleUnderscore = position === 'leading'
|
||||
? () => name.startsWith('_')
|
||||
: () => name.endsWith('_');
|
||||
const trimSingleUnderscore = position === 'leading'
|
||||
? () => name.slice(1)
|
||||
: () => name.slice(0, -1);
|
||||
const hasDoubleUnderscore = position === 'leading'
|
||||
? () => name.startsWith('__')
|
||||
: () => name.endsWith('__');
|
||||
const trimDoubleUnderscore = position === 'leading'
|
||||
? () => name.slice(2)
|
||||
: () => name.slice(0, -2);
|
||||
switch (option) {
|
||||
// ALLOW - no conditions as the user doesn't care if it's there or not
|
||||
case enums_1.UnderscoreOptions.allow: {
|
||||
if (hasSingleUnderscore()) {
|
||||
return trimSingleUnderscore();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
case enums_1.UnderscoreOptions.allowDouble: {
|
||||
if (hasDoubleUnderscore()) {
|
||||
return trimDoubleUnderscore();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
case enums_1.UnderscoreOptions.allowSingleOrDouble: {
|
||||
if (hasDoubleUnderscore()) {
|
||||
return trimDoubleUnderscore();
|
||||
}
|
||||
if (hasSingleUnderscore()) {
|
||||
return trimSingleUnderscore();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
// FORBID
|
||||
case enums_1.UnderscoreOptions.forbid: {
|
||||
if (hasSingleUnderscore()) {
|
||||
context.report({
|
||||
data: formatReportData({
|
||||
count: 'one',
|
||||
originalName,
|
||||
position,
|
||||
}),
|
||||
messageId: 'unexpectedUnderscore',
|
||||
node,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
// REQUIRE
|
||||
case enums_1.UnderscoreOptions.require: {
|
||||
if (!hasSingleUnderscore()) {
|
||||
context.report({
|
||||
data: formatReportData({
|
||||
count: 'one',
|
||||
originalName,
|
||||
position,
|
||||
}),
|
||||
messageId: 'missingUnderscore',
|
||||
node,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return trimSingleUnderscore();
|
||||
}
|
||||
case enums_1.UnderscoreOptions.requireDouble: {
|
||||
if (!hasDoubleUnderscore()) {
|
||||
context.report({
|
||||
data: formatReportData({
|
||||
count: 'two',
|
||||
originalName,
|
||||
position,
|
||||
}),
|
||||
messageId: 'missingUnderscore',
|
||||
node,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return trimDoubleUnderscore();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @returns the name with the affix removed, if it is valid according to the specified affix option, null otherwise
|
||||
*/
|
||||
function validateAffix(position, config, name, node, originalName) {
|
||||
const affixes = config[position];
|
||||
if (!affixes || affixes.length === 0) {
|
||||
return name;
|
||||
}
|
||||
for (const affix of affixes) {
|
||||
const hasAffix = position === 'prefix' ? name.startsWith(affix) : name.endsWith(affix);
|
||||
const trimAffix = position === 'prefix'
|
||||
? () => name.slice(affix.length)
|
||||
: () => name.slice(0, -affix.length);
|
||||
if (hasAffix) {
|
||||
// matches, so trim it and return
|
||||
return trimAffix();
|
||||
}
|
||||
}
|
||||
context.report({
|
||||
data: formatReportData({
|
||||
affixes,
|
||||
originalName,
|
||||
position,
|
||||
}),
|
||||
messageId: 'missingAffix',
|
||||
node,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @returns true if the name is valid according to the `regex` option, false otherwise
|
||||
*/
|
||||
function validateCustom(config, name, node, originalName) {
|
||||
const custom = config.custom;
|
||||
if (!custom) {
|
||||
return true;
|
||||
}
|
||||
const result = custom.regex.test(name);
|
||||
if (custom.match && result) {
|
||||
return true;
|
||||
}
|
||||
if (!custom.match && !result) {
|
||||
return true;
|
||||
}
|
||||
context.report({
|
||||
data: formatReportData({
|
||||
custom,
|
||||
originalName,
|
||||
}),
|
||||
messageId: 'satisfyCustom',
|
||||
node,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @returns true if the name is valid according to the `format` option, false otherwise
|
||||
*/
|
||||
function validatePredefinedFormat(config, name, node, originalName, modifiers) {
|
||||
const formats = config.format;
|
||||
if (!formats?.length) {
|
||||
return true;
|
||||
}
|
||||
if (!modifiers.has(enums_1.Modifiers.requiresQuotes)) {
|
||||
for (const format of formats) {
|
||||
const checker = format_1.PredefinedFormatToCheckFunction[format];
|
||||
if (checker(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
context.report({
|
||||
data: formatReportData({
|
||||
formats,
|
||||
originalName,
|
||||
processedName: name,
|
||||
}),
|
||||
messageId: originalName === name
|
||||
? 'doesNotMatchFormat'
|
||||
: 'doesNotMatchFormatTrimmed',
|
||||
node,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const SelectorsAllowedToHaveTypes = enums_1.Selectors.variable |
|
||||
enums_1.Selectors.parameter |
|
||||
enums_1.Selectors.classProperty |
|
||||
enums_1.Selectors.objectLiteralProperty |
|
||||
enums_1.Selectors.typeProperty |
|
||||
enums_1.Selectors.parameterProperty |
|
||||
enums_1.Selectors.classicAccessor;
|
||||
function isCorrectType(node, config, context, selector) {
|
||||
if (config.types == null) {
|
||||
return true;
|
||||
}
|
||||
if ((SelectorsAllowedToHaveTypes & selector) === 0) {
|
||||
return true;
|
||||
}
|
||||
const services = (0, util_1.getParserServices)(context);
|
||||
const checker = services.program.getTypeChecker();
|
||||
const type = services
|
||||
.getTypeAtLocation(node)
|
||||
// remove null and undefined from the type, as we don't care about it here
|
||||
.getNonNullableType();
|
||||
for (const allowedType of config.types) {
|
||||
switch (allowedType) {
|
||||
case enums_1.TypeModifiers.array:
|
||||
if (isAllTypesMatch(type, t => checker.isArrayType(t) || checker.isTupleType(t))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case enums_1.TypeModifiers.function:
|
||||
if (isAllTypesMatch(type, t => t.getCallSignatures().length > 0)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case enums_1.TypeModifiers.boolean:
|
||||
case enums_1.TypeModifiers.number:
|
||||
case enums_1.TypeModifiers.string: {
|
||||
const typeString = checker.typeToString(
|
||||
// this will resolve things like true => boolean, 'a' => string and 1 => number
|
||||
checker.getWidenedType(checker.getBaseTypeOfLiteralType(type)));
|
||||
const allowedTypeString = enums_1.TypeModifiers[allowedType];
|
||||
if (typeString === allowedTypeString) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @returns `true` if the type (or all union types) in the given type return true for the callback
|
||||
*/
|
||||
function isAllTypesMatch(type, cb) {
|
||||
if (type.isUnion()) {
|
||||
return type.types.every(t => cb(t));
|
||||
}
|
||||
return cb(type);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @fileoverview ESLint Scope types in ESM format.
|
||||
* @author Francesco Trotta
|
||||
*/
|
||||
|
||||
export * from "./index.cjs";
|
||||
@@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const util_1 = require("../util");
|
||||
const getESLintCoreRule_1 = require("../util/getESLintCoreRule");
|
||||
const baseRule = (0, getESLintCoreRule_1.getESLintCoreRule)('no-dupe-class-members');
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'no-dupe-class-members',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
// defaultOptions, -- base rule does not use defaultOptions
|
||||
docs: {
|
||||
description: 'Disallow duplicate class members',
|
||||
extendsBaseRule: true,
|
||||
},
|
||||
hasSuggestions: baseRule.meta.hasSuggestions,
|
||||
messages: baseRule.meta.messages,
|
||||
schema: baseRule.meta.schema,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
const rules = baseRule.create(context);
|
||||
function wrapMemberDefinitionListener(coreListener) {
|
||||
return (node) => {
|
||||
if (node.computed) {
|
||||
return;
|
||||
}
|
||||
if (node.value?.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
|
||||
return;
|
||||
}
|
||||
return coreListener(node);
|
||||
};
|
||||
}
|
||||
return {
|
||||
...rules,
|
||||
'MethodDefinition, PropertyDefinition': wrapMemberDefinitionListener(rules['MethodDefinition, PropertyDefinition']),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,178 @@
|
||||
import type { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/types';
|
||||
import type * as ts from 'typescript';
|
||||
import type { TSNode } from './ts-nodes';
|
||||
export interface EstreeToTsNodeTypes {
|
||||
[AST_NODE_TYPES.AccessorProperty]: ts.PropertyDeclaration;
|
||||
[AST_NODE_TYPES.ArrayExpression]: ts.ArrayLiteralExpression;
|
||||
[AST_NODE_TYPES.ArrayPattern]: ts.ArrayBindingPattern | ts.ArrayLiteralExpression;
|
||||
[AST_NODE_TYPES.ArrowFunctionExpression]: ts.ArrowFunction;
|
||||
[AST_NODE_TYPES.AssignmentExpression]: ts.BinaryExpression;
|
||||
[AST_NODE_TYPES.AssignmentPattern]: ts.BinaryExpression | ts.BindingElement | ts.ParameterDeclaration | ts.ShorthandPropertyAssignment;
|
||||
[AST_NODE_TYPES.AwaitExpression]: ts.AwaitExpression;
|
||||
[AST_NODE_TYPES.BinaryExpression]: ts.BinaryExpression;
|
||||
[AST_NODE_TYPES.BlockStatement]: ts.Block;
|
||||
[AST_NODE_TYPES.BreakStatement]: ts.BreakStatement;
|
||||
[AST_NODE_TYPES.CallExpression]: ts.CallExpression;
|
||||
[AST_NODE_TYPES.CatchClause]: ts.CatchClause;
|
||||
[AST_NODE_TYPES.ChainExpression]: ts.CallExpression | ts.ElementAccessExpression | ts.NonNullExpression | ts.PropertyAccessExpression;
|
||||
[AST_NODE_TYPES.ClassBody]: ts.ClassDeclaration | ts.ClassExpression;
|
||||
[AST_NODE_TYPES.ClassDeclaration]: ts.ClassDeclaration;
|
||||
[AST_NODE_TYPES.ClassExpression]: ts.ClassExpression;
|
||||
[AST_NODE_TYPES.ConditionalExpression]: ts.ConditionalExpression;
|
||||
[AST_NODE_TYPES.ContinueStatement]: ts.ContinueStatement;
|
||||
[AST_NODE_TYPES.DebuggerStatement]: ts.DebuggerStatement;
|
||||
[AST_NODE_TYPES.Decorator]: ts.Decorator;
|
||||
[AST_NODE_TYPES.DoWhileStatement]: ts.DoStatement;
|
||||
[AST_NODE_TYPES.EmptyStatement]: ts.EmptyStatement;
|
||||
[AST_NODE_TYPES.ExportAllDeclaration]: ts.ExportDeclaration;
|
||||
[AST_NODE_TYPES.ExportDefaultDeclaration]: ts.ClassDeclaration | ts.ClassExpression | ts.EnumDeclaration | ts.ExportAssignment | ts.FunctionDeclaration | ts.InterfaceDeclaration | ts.ModuleDeclaration | ts.TypeAliasDeclaration | ts.VariableStatement;
|
||||
[AST_NODE_TYPES.ExportNamedDeclaration]: ts.ClassDeclaration | ts.ClassExpression | ts.EnumDeclaration | ts.ExportDeclaration | ts.FunctionDeclaration | ts.ImportEqualsDeclaration | ts.InterfaceDeclaration | ts.ModuleDeclaration | ts.TypeAliasDeclaration | ts.VariableStatement;
|
||||
[AST_NODE_TYPES.ExportSpecifier]: ts.ExportSpecifier;
|
||||
[AST_NODE_TYPES.ExpressionStatement]: ts.ExpressionStatement;
|
||||
[AST_NODE_TYPES.ForInStatement]: ts.ForInStatement;
|
||||
[AST_NODE_TYPES.ForOfStatement]: ts.ForOfStatement;
|
||||
[AST_NODE_TYPES.ForStatement]: ts.ForStatement;
|
||||
[AST_NODE_TYPES.FunctionDeclaration]: ts.FunctionDeclaration;
|
||||
[AST_NODE_TYPES.FunctionExpression]: ts.ConstructorDeclaration | ts.FunctionExpression | ts.GetAccessorDeclaration | ts.MethodDeclaration | ts.SetAccessorDeclaration;
|
||||
[AST_NODE_TYPES.Identifier]: ts.ConstructorDeclaration | ts.Identifier | ts.Token<ts.SyntaxKind.ImportKeyword | ts.SyntaxKind.NewKeyword>;
|
||||
[AST_NODE_TYPES.IfStatement]: ts.IfStatement;
|
||||
[AST_NODE_TYPES.PrivateIdentifier]: ts.PrivateIdentifier;
|
||||
[AST_NODE_TYPES.PropertyDefinition]: ts.PropertyDeclaration;
|
||||
[AST_NODE_TYPES.ImportAttribute]: 'ImportAttribute' extends keyof typeof ts ? ts.ImportAttribute : ts.AssertEntry;
|
||||
[AST_NODE_TYPES.ImportDeclaration]: ts.ImportDeclaration;
|
||||
[AST_NODE_TYPES.ImportDefaultSpecifier]: ts.ImportClause;
|
||||
[AST_NODE_TYPES.ImportExpression]: ts.CallExpression;
|
||||
[AST_NODE_TYPES.ImportNamespaceSpecifier]: ts.NamespaceImport;
|
||||
[AST_NODE_TYPES.ImportSpecifier]: ts.ImportSpecifier;
|
||||
[AST_NODE_TYPES.JSXAttribute]: ts.JsxAttribute;
|
||||
[AST_NODE_TYPES.JSXClosingElement]: ts.JsxClosingElement;
|
||||
[AST_NODE_TYPES.JSXClosingFragment]: ts.JsxClosingFragment;
|
||||
[AST_NODE_TYPES.JSXElement]: ts.JsxElement | ts.JsxSelfClosingElement;
|
||||
[AST_NODE_TYPES.JSXEmptyExpression]: ts.JsxExpression;
|
||||
[AST_NODE_TYPES.JSXExpressionContainer]: ts.JsxExpression;
|
||||
[AST_NODE_TYPES.JSXFragment]: ts.JsxFragment;
|
||||
[AST_NODE_TYPES.JSXIdentifier]: ts.Identifier | ts.ThisExpression;
|
||||
[AST_NODE_TYPES.JSXMemberExpression]: ts.PropertyAccessExpression;
|
||||
[AST_NODE_TYPES.JSXNamespacedName]: ts.JsxNamespacedName;
|
||||
[AST_NODE_TYPES.JSXOpeningElement]: ts.JsxOpeningElement | ts.JsxSelfClosingElement;
|
||||
[AST_NODE_TYPES.JSXOpeningFragment]: ts.JsxOpeningFragment;
|
||||
[AST_NODE_TYPES.JSXSpreadAttribute]: ts.JsxSpreadAttribute;
|
||||
[AST_NODE_TYPES.JSXSpreadChild]: ts.JsxExpression;
|
||||
[AST_NODE_TYPES.JSXText]: ts.JsxText;
|
||||
[AST_NODE_TYPES.LabeledStatement]: ts.LabeledStatement;
|
||||
[AST_NODE_TYPES.Literal]: ts.BigIntLiteral | ts.BooleanLiteral | ts.NullLiteral | ts.NumericLiteral | ts.RegularExpressionLiteral | ts.StringLiteral;
|
||||
[AST_NODE_TYPES.LogicalExpression]: ts.BinaryExpression;
|
||||
[AST_NODE_TYPES.MemberExpression]: ts.ElementAccessExpression | ts.PropertyAccessExpression;
|
||||
[AST_NODE_TYPES.MetaProperty]: ts.MetaProperty;
|
||||
[AST_NODE_TYPES.MethodDefinition]: ts.ConstructorDeclaration | ts.GetAccessorDeclaration | ts.MethodDeclaration | ts.SetAccessorDeclaration;
|
||||
[AST_NODE_TYPES.NewExpression]: ts.NewExpression;
|
||||
[AST_NODE_TYPES.ObjectExpression]: ts.ObjectLiteralExpression;
|
||||
[AST_NODE_TYPES.ObjectPattern]: ts.ObjectBindingPattern | ts.ObjectLiteralExpression;
|
||||
[AST_NODE_TYPES.Program]: ts.SourceFile;
|
||||
[AST_NODE_TYPES.Property]: ts.BindingElement | ts.GetAccessorDeclaration | ts.MethodDeclaration | ts.PropertyAssignment | ts.SetAccessorDeclaration | ts.ShorthandPropertyAssignment;
|
||||
[AST_NODE_TYPES.RestElement]: ts.BindingElement | ts.ParameterDeclaration | ts.SpreadAssignment | ts.SpreadElement;
|
||||
[AST_NODE_TYPES.ReturnStatement]: ts.ReturnStatement;
|
||||
[AST_NODE_TYPES.SequenceExpression]: ts.BinaryExpression;
|
||||
[AST_NODE_TYPES.SpreadElement]: ts.SpreadAssignment | ts.SpreadElement;
|
||||
[AST_NODE_TYPES.StaticBlock]: ts.ClassStaticBlockDeclaration;
|
||||
[AST_NODE_TYPES.Super]: ts.SuperExpression;
|
||||
[AST_NODE_TYPES.SwitchCase]: ts.CaseClause | ts.DefaultClause;
|
||||
[AST_NODE_TYPES.SwitchStatement]: ts.SwitchStatement;
|
||||
[AST_NODE_TYPES.TaggedTemplateExpression]: ts.TaggedTemplateExpression;
|
||||
[AST_NODE_TYPES.TemplateElement]: ts.NoSubstitutionTemplateLiteral | ts.TemplateHead | ts.TemplateMiddle | ts.TemplateTail;
|
||||
[AST_NODE_TYPES.TemplateLiteral]: ts.NoSubstitutionTemplateLiteral | ts.TemplateExpression;
|
||||
[AST_NODE_TYPES.ThisExpression]: ts.Identifier | ts.KeywordTypeNode | ts.ThisExpression;
|
||||
[AST_NODE_TYPES.ThrowStatement]: ts.ThrowStatement;
|
||||
[AST_NODE_TYPES.TryStatement]: ts.TryStatement;
|
||||
[AST_NODE_TYPES.TSAbstractAccessorProperty]: ts.PropertyDeclaration;
|
||||
[AST_NODE_TYPES.TSAbstractMethodDefinition]: ts.ConstructorDeclaration | ts.GetAccessorDeclaration | ts.MethodDeclaration | ts.SetAccessorDeclaration;
|
||||
[AST_NODE_TYPES.TSAbstractPropertyDefinition]: ts.PropertyDeclaration;
|
||||
[AST_NODE_TYPES.TSArrayType]: ts.ArrayTypeNode;
|
||||
[AST_NODE_TYPES.TSAsExpression]: ts.AsExpression;
|
||||
[AST_NODE_TYPES.TSCallSignatureDeclaration]: ts.CallSignatureDeclaration;
|
||||
[AST_NODE_TYPES.TSClassImplements]: ts.ExpressionWithTypeArguments;
|
||||
[AST_NODE_TYPES.TSConditionalType]: ts.ConditionalTypeNode;
|
||||
[AST_NODE_TYPES.TSConstructorType]: ts.ConstructorTypeNode;
|
||||
[AST_NODE_TYPES.TSConstructSignatureDeclaration]: ts.ConstructSignatureDeclaration;
|
||||
[AST_NODE_TYPES.TSDeclareFunction]: ts.FunctionDeclaration;
|
||||
[AST_NODE_TYPES.TSEnumBody]: ts.EnumDeclaration;
|
||||
[AST_NODE_TYPES.TSEnumDeclaration]: ts.EnumDeclaration;
|
||||
[AST_NODE_TYPES.TSEnumMember]: ts.EnumMember;
|
||||
[AST_NODE_TYPES.TSExportAssignment]: ts.ExportAssignment;
|
||||
[AST_NODE_TYPES.TSExternalModuleReference]: ts.ExternalModuleReference;
|
||||
[AST_NODE_TYPES.TSFunctionType]: ts.FunctionTypeNode;
|
||||
[AST_NODE_TYPES.TSImportEqualsDeclaration]: ts.ImportEqualsDeclaration;
|
||||
[AST_NODE_TYPES.TSImportType]: ts.ImportTypeNode;
|
||||
[AST_NODE_TYPES.TSIndexedAccessType]: ts.IndexedAccessTypeNode;
|
||||
[AST_NODE_TYPES.TSIndexSignature]: ts.IndexSignatureDeclaration;
|
||||
[AST_NODE_TYPES.TSInferType]: ts.InferTypeNode;
|
||||
[AST_NODE_TYPES.TSInstantiationExpression]: ts.ExpressionWithTypeArguments;
|
||||
[AST_NODE_TYPES.TSInterfaceBody]: ts.InterfaceDeclaration;
|
||||
[AST_NODE_TYPES.TSInterfaceDeclaration]: ts.InterfaceDeclaration;
|
||||
[AST_NODE_TYPES.TSInterfaceHeritage]: ts.ExpressionWithTypeArguments;
|
||||
[AST_NODE_TYPES.TSIntersectionType]: ts.IntersectionTypeNode;
|
||||
[AST_NODE_TYPES.TSLiteralType]: ts.LiteralTypeNode;
|
||||
[AST_NODE_TYPES.TSMappedType]: ts.MappedTypeNode;
|
||||
[AST_NODE_TYPES.TSMethodSignature]: ts.GetAccessorDeclaration | ts.MethodSignature | ts.SetAccessorDeclaration;
|
||||
[AST_NODE_TYPES.TSModuleBlock]: ts.ModuleBlock;
|
||||
[AST_NODE_TYPES.TSModuleDeclaration]: ts.ModuleDeclaration;
|
||||
[AST_NODE_TYPES.TSNamedTupleMember]: ts.NamedTupleMember;
|
||||
[AST_NODE_TYPES.TSNamespaceExportDeclaration]: ts.NamespaceExportDeclaration;
|
||||
[AST_NODE_TYPES.TSNonNullExpression]: ts.NonNullExpression;
|
||||
[AST_NODE_TYPES.TSOptionalType]: ts.OptionalTypeNode;
|
||||
[AST_NODE_TYPES.TSParameterProperty]: ts.ParameterDeclaration;
|
||||
[AST_NODE_TYPES.TSPropertySignature]: ts.PropertySignature;
|
||||
[AST_NODE_TYPES.TSQualifiedName]: ts.Identifier | ts.QualifiedName;
|
||||
[AST_NODE_TYPES.TSRestType]: ts.NamedTupleMember | ts.RestTypeNode;
|
||||
[AST_NODE_TYPES.TSSatisfiesExpression]: ts.SatisfiesExpression;
|
||||
[AST_NODE_TYPES.TSTemplateLiteralType]: ts.TemplateLiteralTypeNode;
|
||||
[AST_NODE_TYPES.TSThisType]: ts.ThisTypeNode;
|
||||
[AST_NODE_TYPES.TSTupleType]: ts.TupleTypeNode;
|
||||
[AST_NODE_TYPES.TSTypeAliasDeclaration]: ts.TypeAliasDeclaration;
|
||||
[AST_NODE_TYPES.TSTypeAnnotation]: undefined;
|
||||
[AST_NODE_TYPES.TSTypeAssertion]: ts.TypeAssertion;
|
||||
[AST_NODE_TYPES.TSTypeLiteral]: ts.TypeLiteralNode;
|
||||
[AST_NODE_TYPES.TSTypeOperator]: ts.TypeOperatorNode;
|
||||
[AST_NODE_TYPES.TSTypeParameter]: ts.TypeParameterDeclaration;
|
||||
[AST_NODE_TYPES.TSTypeParameterDeclaration]: undefined;
|
||||
[AST_NODE_TYPES.TSTypeParameterInstantiation]: ts.CallExpression | ts.ExpressionWithTypeArguments | ts.ImportTypeNode | ts.JsxOpeningElement | ts.JsxSelfClosingElement | ts.NewExpression | ts.TaggedTemplateExpression | ts.TypeQueryNode | ts.TypeReferenceNode;
|
||||
[AST_NODE_TYPES.TSTypePredicate]: ts.TypePredicateNode;
|
||||
[AST_NODE_TYPES.TSTypeQuery]: ts.ImportTypeNode | ts.TypeQueryNode;
|
||||
[AST_NODE_TYPES.TSTypeReference]: ts.TypeReferenceNode;
|
||||
[AST_NODE_TYPES.TSUnionType]: ts.UnionTypeNode;
|
||||
[AST_NODE_TYPES.UnaryExpression]: ts.DeleteExpression | ts.PostfixUnaryExpression | ts.PrefixUnaryExpression | ts.TypeOfExpression | ts.VoidExpression;
|
||||
[AST_NODE_TYPES.UpdateExpression]: ts.PostfixUnaryExpression | ts.PrefixUnaryExpression;
|
||||
[AST_NODE_TYPES.VariableDeclaration]: ts.VariableDeclarationList | ts.VariableStatement;
|
||||
[AST_NODE_TYPES.VariableDeclarator]: ts.VariableDeclaration;
|
||||
[AST_NODE_TYPES.WhileStatement]: ts.WhileStatement;
|
||||
[AST_NODE_TYPES.WithStatement]: ts.WithStatement;
|
||||
[AST_NODE_TYPES.YieldExpression]: ts.YieldExpression;
|
||||
[AST_NODE_TYPES.TSEmptyBodyFunctionExpression]: ts.ConstructorDeclaration | ts.FunctionExpression | ts.GetAccessorDeclaration | ts.MethodDeclaration | ts.SetAccessorDeclaration;
|
||||
[AST_NODE_TYPES.TSAbstractKeyword]: ts.Token<ts.SyntaxKind.AbstractKeyword>;
|
||||
[AST_NODE_TYPES.TSAnyKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSBigIntKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSBooleanKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSIntrinsicKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSNeverKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSNullKeyword]: ts.KeywordTypeNode | ts.NullLiteral;
|
||||
[AST_NODE_TYPES.TSNumberKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSObjectKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSStringKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSSymbolKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSUndefinedKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSUnknownKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSVoidKeyword]: ts.KeywordTypeNode;
|
||||
[AST_NODE_TYPES.TSAsyncKeyword]: ts.Token<ts.SyntaxKind.AsyncKeyword>;
|
||||
[AST_NODE_TYPES.TSDeclareKeyword]: ts.Token<ts.SyntaxKind.DeclareKeyword>;
|
||||
[AST_NODE_TYPES.TSExportKeyword]: ts.Token<ts.SyntaxKind.ExportKeyword>;
|
||||
[AST_NODE_TYPES.TSPrivateKeyword]: ts.Token<ts.SyntaxKind.PrivateKeyword>;
|
||||
[AST_NODE_TYPES.TSProtectedKeyword]: ts.Token<ts.SyntaxKind.ProtectedKeyword>;
|
||||
[AST_NODE_TYPES.TSPublicKeyword]: ts.Token<ts.SyntaxKind.PublicKeyword>;
|
||||
[AST_NODE_TYPES.TSReadonlyKeyword]: ts.Token<ts.SyntaxKind.ReadonlyKeyword>;
|
||||
[AST_NODE_TYPES.TSStaticKeyword]: ts.Token<ts.SyntaxKind.StaticKeyword>;
|
||||
}
|
||||
/**
|
||||
* Maps TSESTree AST Node type to the expected TypeScript AST Node type(s).
|
||||
* This mapping is based on the internal logic of the parser.
|
||||
*/
|
||||
export type TSESTreeToTSNode<T extends TSESTree.Node = TSESTree.Node> = Extract<ts.Token<ts.SyntaxKind.ImportKeyword | ts.SyntaxKind.NewKeyword> | TSNode, EstreeToTsNodeTypes[T['type']]>;
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag bitwise identifiers
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
*
|
||||
* Set of bitwise operators.
|
||||
*
|
||||
*/
|
||||
const BITWISE_OPERATORS = [
|
||||
"^",
|
||||
"|",
|
||||
"&",
|
||||
"<<",
|
||||
">>",
|
||||
">>>",
|
||||
"^=",
|
||||
"|=",
|
||||
"&=",
|
||||
"<<=",
|
||||
">>=",
|
||||
">>>=",
|
||||
"~",
|
||||
];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allow: [],
|
||||
int32Hint: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Disallow bitwise operators",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-bitwise",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allow: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: BITWISE_OPERATORS,
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
int32Hint: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpected: "Unexpected use of '{{operator}}'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [{ allow: allowed, int32Hint }] = context.options;
|
||||
|
||||
/**
|
||||
* Reports an unexpected use of a bitwise operator.
|
||||
* @param {ASTNode} node Node which contains the bitwise operator.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpected",
|
||||
data: { operator: node.operator },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given node has a bitwise operator.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} Whether or not the node has a bitwise operator.
|
||||
*/
|
||||
function hasBitwiseOperator(node) {
|
||||
return BITWISE_OPERATORS.includes(node.operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if exceptions were provided, e.g. `{ allow: ['~', '|'] }`.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} Whether or not the node has a bitwise operator.
|
||||
*/
|
||||
function allowedOperator(node) {
|
||||
return allowed.includes(node.operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given bitwise operator is used for integer typecasting, i.e. "|0"
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} whether the node is used in integer typecasting.
|
||||
*/
|
||||
function isInt32Hint(node) {
|
||||
return (
|
||||
int32Hint &&
|
||||
node.operator === "|" &&
|
||||
node.right &&
|
||||
node.right.type === "Literal" &&
|
||||
node.right.value === 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report if the given node contains a bitwise operator.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkNodeForBitwiseOperator(node) {
|
||||
if (
|
||||
hasBitwiseOperator(node) &&
|
||||
!allowedOperator(node) &&
|
||||
!isInt32Hint(node)
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
AssignmentExpression: checkNodeForBitwiseOperator,
|
||||
BinaryExpression: checkNodeForBitwiseOperator,
|
||||
UnaryExpression: checkNodeForBitwiseOperator,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
exports.URL = require("./URL").interface;
|
||||
exports.serializeURL = require("./url-state-machine").serializeURL;
|
||||
exports.serializeURLOrigin = require("./url-state-machine").serializeURLOrigin;
|
||||
exports.basicURLParse = require("./url-state-machine").basicURLParse;
|
||||
exports.setTheUsername = require("./url-state-machine").setTheUsername;
|
||||
exports.setThePassword = require("./url-state-machine").setThePassword;
|
||||
exports.serializeHost = require("./url-state-machine").serializeHost;
|
||||
exports.serializeInteger = require("./url-state-machine").serializeInteger;
|
||||
exports.parseURL = require("./url-state-machine").parseURL;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
/*! *****************************************************************************
|
||||
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,
|
||||
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="dom" />
|
||||
/// <reference lib="webworker.importscripts" />
|
||||
/// <reference lib="scripthost" />
|
||||
/// <reference lib="dom.iterable" />
|
||||
/// <reference lib="dom.asynciterable" />
|
||||
@@ -0,0 +1,17 @@
|
||||
export declare enum ModuleKind {
|
||||
None = 0,
|
||||
CommonJS = 1,
|
||||
AMD = 2,
|
||||
UMD = 3,
|
||||
System = 4,
|
||||
ES2015 = 5,
|
||||
ES2020 = 6,
|
||||
ES2022 = 7,
|
||||
ESNext = 99,
|
||||
Node16 = 100,
|
||||
Node18 = 101,
|
||||
Node20 = 102,
|
||||
NodeNext = 199,
|
||||
Preserve = 200
|
||||
}
|
||||
//# sourceMappingURL=moduleKind.enum.d.ts.map
|
||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
const re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/
|
||||
|
||||
module.exports = function optionMatcher (args) {
|
||||
const options = args.reduce(function (acc, cur) {
|
||||
const matches = cur.match(re)
|
||||
if (matches) {
|
||||
acc[matches[1]] = matches[2]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
if (!('quiet' in options)) {
|
||||
options.quiet = 'true'
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isNotTokenOfTypeWithConditions = exports.isTokenOfTypeWithConditions = exports.isNodeOfTypeWithConditions = exports.isNodeOfTypes = exports.isNodeOfType = void 0;
|
||||
const isNodeOfType = (nodeType) => (node) => node?.type === nodeType;
|
||||
exports.isNodeOfType = isNodeOfType;
|
||||
const isNodeOfTypes = (nodeTypes) => (node) => !!node && nodeTypes.includes(node.type);
|
||||
exports.isNodeOfTypes = isNodeOfTypes;
|
||||
const isNodeOfTypeWithConditions = (nodeType, conditions) => {
|
||||
const entries = Object.entries(conditions);
|
||||
return (node) => node?.type === nodeType &&
|
||||
entries.every(([key, value]) => node[key] === value);
|
||||
};
|
||||
exports.isNodeOfTypeWithConditions = isNodeOfTypeWithConditions;
|
||||
const isTokenOfTypeWithConditions = (tokenType, conditions) => {
|
||||
const entries = Object.entries(conditions);
|
||||
return (token) => token?.type === tokenType &&
|
||||
entries.every(([key, value]) => token[key] === value);
|
||||
};
|
||||
exports.isTokenOfTypeWithConditions = isTokenOfTypeWithConditions;
|
||||
const isNotTokenOfTypeWithConditions = (tokenType, conditions) => (token) => !(0, exports.isTokenOfTypeWithConditions)(tokenType, conditions)(token);
|
||||
exports.isNotTokenOfTypeWithConditions = isNotTokenOfTypeWithConditions;
|
||||
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TSESTree = exports.AST_TOKEN_TYPES = exports.AST_NODE_TYPES = void 0;
|
||||
// for convenience's sake - export the types directly from here so consumers
|
||||
// don't need to reference/install both packages in their code
|
||||
var types_1 = require("@typescript-eslint/types");
|
||||
Object.defineProperty(exports, "AST_NODE_TYPES", { enumerable: true, get: function () { return types_1.AST_NODE_TYPES; } });
|
||||
Object.defineProperty(exports, "AST_TOKEN_TYPES", { enumerable: true, get: function () { return types_1.AST_TOKEN_TYPES; } });
|
||||
Object.defineProperty(exports, "TSESTree", { enumerable: true, get: function () { return types_1.TSESTree; } });
|
||||
Reference in New Issue
Block a user