WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Namespace available as require('jayson')
|
||||
* @namespace Jayson
|
||||
*/
|
||||
const Jayson = module.exports;
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @type Client
|
||||
*/
|
||||
Jayson.Client = Jayson.client = require('./client');
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @type Server
|
||||
*/
|
||||
Jayson.Server = Jayson.server = require('./server');
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @type Utils
|
||||
*/
|
||||
Jayson.Utils = Jayson.utils = require('./utils');
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @type Method
|
||||
*/
|
||||
Jayson.Method = Jayson.method = require('./method');
|
||||
@@ -0,0 +1,17 @@
|
||||
"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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("../v4/locales/index.cjs"), exports);
|
||||
@@ -0,0 +1,5 @@
|
||||
export declare enum SignatureKind {
|
||||
Call = 0,
|
||||
Construct = 1
|
||||
}
|
||||
//# sourceMappingURL=signatureKind.enum.d.ts.map
|
||||
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag non-quoted property names in object literals.
|
||||
* @author Mathias Bynens <http://mathiasbynens.be/>
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const espree = require("espree");
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const keywords = require("./utils/keywords");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "11.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "quote-props",
|
||||
url: "https://eslint.style/rules/quote-props",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Require quotes around object literal property names",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/quote-props",
|
||||
},
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: [
|
||||
"always",
|
||||
"as-needed",
|
||||
"consistent",
|
||||
"consistent-as-needed",
|
||||
],
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 1,
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
items: [
|
||||
{
|
||||
enum: [
|
||||
"always",
|
||||
"as-needed",
|
||||
"consistent",
|
||||
"consistent-as-needed",
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
keywords: {
|
||||
type: "boolean",
|
||||
},
|
||||
unnecessary: {
|
||||
type: "boolean",
|
||||
},
|
||||
numbers: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
minItems: 0,
|
||||
maxItems: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
fixable: "code",
|
||||
messages: {
|
||||
requireQuotesDueToReservedWord:
|
||||
"Properties should be quoted as '{{property}}' is a reserved word.",
|
||||
inconsistentlyQuotedProperty:
|
||||
"Inconsistently quoted property '{{key}}' found.",
|
||||
unnecessarilyQuotedProperty:
|
||||
"Unnecessarily quoted property '{{property}}' found.",
|
||||
unquotedReservedProperty:
|
||||
"Unquoted reserved word '{{property}}' used as key.",
|
||||
unquotedNumericProperty:
|
||||
"Unquoted number literal '{{property}}' used as key.",
|
||||
unquotedPropertyFound: "Unquoted property '{{property}}' found.",
|
||||
redundantQuoting:
|
||||
"Properties shouldn't be quoted as all quotes are redundant.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const MODE = context.options[0],
|
||||
KEYWORDS = context.options[1] && context.options[1].keywords,
|
||||
CHECK_UNNECESSARY =
|
||||
!context.options[1] || context.options[1].unnecessary !== false,
|
||||
NUMBERS = context.options[1] && context.options[1].numbers,
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Checks whether a certain string constitutes an ES3 token
|
||||
* @param {string} tokenStr The string to be checked.
|
||||
* @returns {boolean} `true` if it is an ES3 token.
|
||||
*/
|
||||
function isKeyword(tokenStr) {
|
||||
return keywords.includes(tokenStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an espree-tokenized key has redundant quotes (i.e. whether quotes are unnecessary)
|
||||
* @param {string} rawKey The raw key value from the source
|
||||
* @param {espreeTokens} tokens The espree-tokenized node key
|
||||
* @param {boolean} [skipNumberLiterals=false] Indicates whether number literals should be checked
|
||||
* @returns {boolean} Whether or not a key has redundant quotes.
|
||||
* @private
|
||||
*/
|
||||
function areQuotesRedundant(rawKey, tokens, skipNumberLiterals) {
|
||||
return (
|
||||
tokens.length === 1 &&
|
||||
tokens[0].start === 0 &&
|
||||
tokens[0].end === rawKey.length &&
|
||||
(["Identifier", "Keyword", "Null", "Boolean"].includes(
|
||||
tokens[0].type,
|
||||
) ||
|
||||
(tokens[0].type === "Numeric" &&
|
||||
!skipNumberLiterals &&
|
||||
String(+tokens[0].value) === tokens[0].value))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of a property node with quotes removed
|
||||
* @param {ASTNode} key Key AST Node, which may or may not be quoted
|
||||
* @returns {string} A replacement string for this property
|
||||
*/
|
||||
function getUnquotedKey(key) {
|
||||
return key.type === "Identifier" ? key.name : key.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of a property node with quotes added
|
||||
* @param {ASTNode} key Key AST Node, which may or may not be quoted
|
||||
* @returns {string} A replacement string for this property
|
||||
*/
|
||||
function getQuotedKey(key) {
|
||||
if (key.type === "Literal" && typeof key.value === "string") {
|
||||
// If the key is already a string literal, don't replace the quotes with double quotes.
|
||||
return sourceCode.getText(key);
|
||||
}
|
||||
|
||||
// Otherwise, the key is either an identifier or a number literal.
|
||||
return `"${key.type === "Identifier" ? key.name : key.value}"`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a property's key is quoted only when necessary
|
||||
* @param {ASTNode} node Property AST node
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkUnnecessaryQuotes(node) {
|
||||
const key = node.key;
|
||||
|
||||
if (node.method || node.computed || node.shorthand) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.type === "Literal" && typeof key.value === "string") {
|
||||
let tokens;
|
||||
|
||||
try {
|
||||
tokens = espree.tokenize(key.value);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isKeywordToken = isKeyword(tokens[0].value);
|
||||
|
||||
if (isKeywordToken && KEYWORDS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
CHECK_UNNECESSARY &&
|
||||
areQuotesRedundant(key.value, tokens, NUMBERS)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unnecessarilyQuotedProperty",
|
||||
data: { property: key.value },
|
||||
fix: fixer =>
|
||||
fixer.replaceText(key, getUnquotedKey(key)),
|
||||
});
|
||||
}
|
||||
} else if (
|
||||
KEYWORDS &&
|
||||
key.type === "Identifier" &&
|
||||
isKeyword(key.name)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unquotedReservedProperty",
|
||||
data: { property: key.name },
|
||||
fix: fixer => fixer.replaceText(key, getQuotedKey(key)),
|
||||
});
|
||||
} else if (
|
||||
NUMBERS &&
|
||||
key.type === "Literal" &&
|
||||
astUtils.isNumericLiteral(key)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unquotedNumericProperty",
|
||||
data: { property: key.value },
|
||||
fix: fixer => fixer.replaceText(key, getQuotedKey(key)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a property's key is quoted
|
||||
* @param {ASTNode} node Property AST node
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkOmittedQuotes(node) {
|
||||
const key = node.key;
|
||||
|
||||
if (
|
||||
!node.method &&
|
||||
!node.computed &&
|
||||
!node.shorthand &&
|
||||
!(key.type === "Literal" && typeof key.value === "string")
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unquotedPropertyFound",
|
||||
data: { property: key.name || key.value },
|
||||
fix: fixer => fixer.replaceText(key, getQuotedKey(key)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that an object's keys are consistently quoted, optionally checks for redundancy of quotes
|
||||
* @param {ASTNode} node Property AST node
|
||||
* @param {boolean} checkQuotesRedundancy Whether to check quotes' redundancy
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkConsistency(node, checkQuotesRedundancy) {
|
||||
const quotedProps = [],
|
||||
unquotedProps = [];
|
||||
let keywordKeyName = null,
|
||||
necessaryQuotes = false;
|
||||
|
||||
node.properties.forEach(property => {
|
||||
const key = property.key;
|
||||
|
||||
if (
|
||||
!key ||
|
||||
property.method ||
|
||||
property.computed ||
|
||||
property.shorthand
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.type === "Literal" && typeof key.value === "string") {
|
||||
quotedProps.push(property);
|
||||
|
||||
if (checkQuotesRedundancy) {
|
||||
let tokens;
|
||||
|
||||
try {
|
||||
tokens = espree.tokenize(key.value);
|
||||
} catch {
|
||||
necessaryQuotes = true;
|
||||
return;
|
||||
}
|
||||
|
||||
necessaryQuotes =
|
||||
necessaryQuotes ||
|
||||
!areQuotesRedundant(key.value, tokens) ||
|
||||
(KEYWORDS && isKeyword(tokens[0].value));
|
||||
}
|
||||
} else if (
|
||||
KEYWORDS &&
|
||||
checkQuotesRedundancy &&
|
||||
key.type === "Identifier" &&
|
||||
isKeyword(key.name)
|
||||
) {
|
||||
unquotedProps.push(property);
|
||||
necessaryQuotes = true;
|
||||
keywordKeyName = key.name;
|
||||
} else {
|
||||
unquotedProps.push(property);
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
checkQuotesRedundancy &&
|
||||
quotedProps.length &&
|
||||
!necessaryQuotes
|
||||
) {
|
||||
quotedProps.forEach(property => {
|
||||
context.report({
|
||||
node: property,
|
||||
messageId: "redundantQuoting",
|
||||
fix: fixer =>
|
||||
fixer.replaceText(
|
||||
property.key,
|
||||
getUnquotedKey(property.key),
|
||||
),
|
||||
});
|
||||
});
|
||||
} else if (unquotedProps.length && keywordKeyName) {
|
||||
unquotedProps.forEach(property => {
|
||||
context.report({
|
||||
node: property,
|
||||
messageId: "requireQuotesDueToReservedWord",
|
||||
data: { property: keywordKeyName },
|
||||
fix: fixer =>
|
||||
fixer.replaceText(
|
||||
property.key,
|
||||
getQuotedKey(property.key),
|
||||
),
|
||||
});
|
||||
});
|
||||
} else if (quotedProps.length && unquotedProps.length) {
|
||||
unquotedProps.forEach(property => {
|
||||
context.report({
|
||||
node: property,
|
||||
messageId: "inconsistentlyQuotedProperty",
|
||||
data: { key: property.key.name || property.key.value },
|
||||
fix: fixer =>
|
||||
fixer.replaceText(
|
||||
property.key,
|
||||
getQuotedKey(property.key),
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
Property(node) {
|
||||
if (MODE === "always" || !MODE) {
|
||||
checkOmittedQuotes(node);
|
||||
}
|
||||
if (MODE === "as-needed") {
|
||||
checkUnnecessaryQuotes(node);
|
||||
}
|
||||
},
|
||||
ObjectExpression(node) {
|
||||
if (MODE === "consistent") {
|
||||
checkConsistency(node, false);
|
||||
}
|
||||
if (MODE === "consistent-as-needed") {
|
||||
checkConsistency(node, true);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const assert = require('node:assert')
|
||||
const { join } = require('path')
|
||||
const { once } = require('events')
|
||||
const { MessageChannel } = require('worker_threads')
|
||||
const ThreadStream = require('..')
|
||||
|
||||
// threadName was added in Node.js v22.20.0 and v24.6.0
|
||||
const [major, minor] = process.versions.node.split('.').map(Number)
|
||||
const supportsThreadName = (major === 22 && minor >= 20) || major >= 24
|
||||
|
||||
test('worker has default name "thread-stream"', { skip: !supportsThreadName }, async function (t) {
|
||||
const { port1, port2 } = new MessageChannel()
|
||||
const stream = new ThreadStream({
|
||||
filename: join(__dirname, 'report-thread-name.js'),
|
||||
sync: true
|
||||
})
|
||||
|
||||
t.after(() => stream.end())
|
||||
|
||||
stream.emit('message', { port: port1 }, [port1])
|
||||
const [{ threadName }] = await once(port2, 'message')
|
||||
assert.strictEqual(threadName, 'thread-stream')
|
||||
})
|
||||
|
||||
test('worker name can be overridden via workerOpts', { skip: !supportsThreadName }, async function (t) {
|
||||
const { port1, port2 } = new MessageChannel()
|
||||
const stream = new ThreadStream({
|
||||
filename: join(__dirname, 'report-thread-name.js'),
|
||||
workerOpts: {
|
||||
name: 'my-custom-worker'
|
||||
},
|
||||
sync: true
|
||||
})
|
||||
|
||||
t.after(() => stream.end())
|
||||
|
||||
stream.emit('message', { port: port1 }, [port1])
|
||||
const [{ threadName }] = await once(port2, 'message')
|
||||
assert.strictEqual(threadName, 'my-custom-worker')
|
||||
})
|
||||
@@ -0,0 +1,452 @@
|
||||
declare module "node:stream/iter" {
|
||||
import { Abortable } from "node:events";
|
||||
import { Readable, Writable } from "node:stream";
|
||||
// Symbols and custom typedefs
|
||||
const broadcastProtocol: unique symbol;
|
||||
const drainableProtocol: unique symbol;
|
||||
const shareProtocol: unique symbol;
|
||||
const shareSyncProtocol: unique symbol;
|
||||
const toAsyncStreamable: unique symbol;
|
||||
const toStreamable: unique symbol;
|
||||
type Source =
|
||||
| string
|
||||
| ArrayBufferLike
|
||||
| ArrayBufferView
|
||||
| Iterable<SyncSource>
|
||||
| AsyncIterable<Source>
|
||||
| Streamable
|
||||
| AsyncStreamable;
|
||||
type SyncSource = string | ArrayBufferLike | ArrayBufferView | Iterable<SyncSource> | Streamable;
|
||||
type Transform = StatelessTransformFn | StatefulTransform;
|
||||
type SyncTransform = SyncStatelessTransformFn | SyncStatefulTransform;
|
||||
type TransformResult =
|
||||
| string
|
||||
| ArrayBufferLike
|
||||
| ArrayBufferView
|
||||
| Iterable<SyncTransformResult>
|
||||
| AsyncIterable<TransformResult>;
|
||||
type SyncTransformResult = string | ArrayBufferLike | ArrayBufferView | Iterable<SyncTransformResult>;
|
||||
interface AsyncStreamable {
|
||||
[toAsyncStreamable](): Source;
|
||||
}
|
||||
interface Broadcastable {
|
||||
[broadcastProtocol](options: BroadcastOptions): Broadcast;
|
||||
}
|
||||
interface Drainable {
|
||||
[drainableProtocol](): Promise<boolean> | null;
|
||||
}
|
||||
interface Shareable {
|
||||
[shareProtocol](options: ShareOptions): Share;
|
||||
}
|
||||
interface Streamable {
|
||||
[toStreamable](): SyncSource;
|
||||
}
|
||||
interface SyncShareable {
|
||||
[shareSyncProtocol](options: ShareSyncOptions): SyncShare;
|
||||
}
|
||||
// IDL dictionaries, enums, typedefs
|
||||
type BackpressurePolicy = "strict" | "block" | "drop-oldest" | "drop-newest";
|
||||
type ByteReadableStream = AsyncIterable<Uint8Array[]>;
|
||||
type SyncByteReadableStream = Iterable<Uint8Array[]>;
|
||||
interface WriteOptions {
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface PushStreamOptions {
|
||||
highWaterMark?: number;
|
||||
backpressure?: BackpressurePolicy;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface PullOptions {
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface PipeToOptions {
|
||||
signal?: AbortSignal;
|
||||
preventClose?: boolean;
|
||||
preventFail?: boolean;
|
||||
}
|
||||
interface PipeToSyncOptions {
|
||||
preventClose?: boolean;
|
||||
preventFail?: boolean;
|
||||
}
|
||||
interface ConsumeOptions {
|
||||
signal?: AbortSignal;
|
||||
limit?: number;
|
||||
}
|
||||
interface ConsumeSyncOptions {
|
||||
limit?: number;
|
||||
}
|
||||
interface TextConsumeOptions extends ConsumeOptions {
|
||||
encoding?: string;
|
||||
}
|
||||
interface TextConsumeSyncOptions extends ConsumeSyncOptions {
|
||||
encoding?: string;
|
||||
}
|
||||
interface MergeOptions {
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface BroadcastOptions {
|
||||
highWaterMark?: number;
|
||||
backpressure?: BackpressurePolicy;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface ShareOptions {
|
||||
highWaterMark?: number;
|
||||
backpressure?: BackpressurePolicy;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface ShareSyncOptions {
|
||||
highWaterMark?: number;
|
||||
backpressure?: BackpressurePolicy;
|
||||
}
|
||||
interface DuplexDirectionOptions {
|
||||
highWaterMark?: number;
|
||||
backpressure?: BackpressurePolicy;
|
||||
}
|
||||
interface DuplexOptions {
|
||||
highWaterMark?: number;
|
||||
backpressure?: BackpressurePolicy;
|
||||
a?: DuplexDirectionOptions;
|
||||
b?: DuplexDirectionOptions;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
interface TransformCallbackOptions {
|
||||
signal: AbortSignal;
|
||||
}
|
||||
interface StatelessTransformFn {
|
||||
(
|
||||
chunks: Uint8Array[] | null,
|
||||
options: TransformCallbackOptions,
|
||||
): Promise<TransformResult | null> | TransformResult | null;
|
||||
}
|
||||
interface SyncStatelessTransformFn {
|
||||
(chunks: Uint8Array[] | null): SyncTransformResult | null;
|
||||
}
|
||||
interface StatefulTransform {
|
||||
transform(
|
||||
source: AsyncIterable<Uint8Array[] | null>,
|
||||
options: TransformCallbackOptions,
|
||||
): AsyncIterable<TransformResult>;
|
||||
}
|
||||
interface SyncStatefulTransform {
|
||||
transform(source: Iterable<Uint8Array[] | null>): Iterable<SyncTransformResult>;
|
||||
}
|
||||
// IDL interfaces
|
||||
interface PushWriter extends Writer, Drainable {}
|
||||
interface PushStreamResult {
|
||||
writer: PushWriter;
|
||||
readable: ByteReadableStream;
|
||||
}
|
||||
interface BroadcastWriter extends Writer, Drainable {}
|
||||
interface BroadcastResult {
|
||||
writer: BroadcastWriter;
|
||||
broadcast: Broadcast;
|
||||
}
|
||||
interface Writer extends Disposable, AsyncDisposable {
|
||||
readonly desiredSize: number | null;
|
||||
write(chunk: Uint8Array | string, options?: WriteOptions): Promise<void>;
|
||||
writev(chunks: Array<Uint8Array | string>, options?: WriteOptions): Promise<void>;
|
||||
writeSync(chunk: Uint8Array | string): boolean;
|
||||
writevSync(chunks: Array<Uint8Array | string>): boolean;
|
||||
end(options?: WriteOptions): Promise<number>;
|
||||
endSync(): number;
|
||||
fail(reason?: any): void;
|
||||
}
|
||||
interface PartialWriter extends Partial<Writer> {
|
||||
write(chunk: Uint8Array | string, options?: WriteOptions): Promise<void>;
|
||||
}
|
||||
interface SyncWriter extends Disposable {
|
||||
readonly desiredSize: number | null;
|
||||
writeSync(chunk: Uint8Array | string): number;
|
||||
writevSync(chunks: Array<Uint8Array | string>): number;
|
||||
endSync(): number;
|
||||
fail(reason?: any): void;
|
||||
}
|
||||
interface PartialSyncWriter extends Partial<SyncWriter> {
|
||||
writeSync(chunk: Uint8Array | string): number;
|
||||
}
|
||||
interface Broadcast extends Disposable {
|
||||
readonly consumerCount: number;
|
||||
readonly bufferSize: number;
|
||||
push(...args: any[]): ByteReadableStream;
|
||||
cancel(reason?: any): void;
|
||||
}
|
||||
interface Share extends Disposable {
|
||||
readonly consumerCount: number;
|
||||
readonly bufferSize: number;
|
||||
pull(...args: any[]): ByteReadableStream;
|
||||
cancel(reason?: any): void;
|
||||
}
|
||||
interface SyncShare extends Disposable {
|
||||
readonly consumerCount: number;
|
||||
readonly bufferSize: number;
|
||||
pull(...args: any): SyncByteReadableStream;
|
||||
cancel(reason?: any): void;
|
||||
}
|
||||
interface DuplexChannel extends AsyncDisposable {
|
||||
readonly writer: Writer;
|
||||
readonly readable: ByteReadableStream;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
// Push stream creation
|
||||
function push(...transforms: Transform[]): PushStreamResult;
|
||||
function push(...args: [...transforms: Transform[], options: PushStreamOptions]): PushStreamResult;
|
||||
// Stream factories
|
||||
function from(input: Source): ByteReadableStream;
|
||||
function fromSync(input: SyncSource): SyncByteReadableStream;
|
||||
// Pull pipelines
|
||||
function pull(source: Source, ...transforms: Transform[]): ByteReadableStream;
|
||||
function pull(
|
||||
source: Source,
|
||||
...args: [...transforms: Transform[], options: PullOptions]
|
||||
): ByteReadableStream;
|
||||
function pullSync(source: SyncSource, ...transforms: SyncTransform[]): SyncByteReadableStream;
|
||||
// Pipe operations
|
||||
function pipeTo(source: Source, writer: PartialWriter, options?: PipeToOptions): Promise<number>;
|
||||
function pipeTo(source: Source, ...args: [...transforms: Transform[], writer: PartialWriter]): Promise<number>;
|
||||
function pipeTo(
|
||||
source: Source,
|
||||
...args: [...transforms: Transform[], writer: PartialWriter, options: PipeToOptions]
|
||||
): Promise<number>;
|
||||
function pipeToSync(source: SyncSource, writer: PartialSyncWriter, options?: PipeToSyncOptions): number;
|
||||
function pipeToSync(
|
||||
source: SyncSource,
|
||||
...args: [...transforms: SyncTransform[], writer: PartialSyncWriter]
|
||||
): number;
|
||||
function pipeToSync(
|
||||
source: SyncSource,
|
||||
...args: [...transforms: SyncTransform[], writer: PartialSyncWriter, options: PipeToSyncOptions]
|
||||
): number;
|
||||
// Consumers
|
||||
function bytes(source: Source, options?: ConsumeOptions): Promise<Uint8Array>;
|
||||
function bytesSync(source: SyncSource, options?: ConsumeSyncOptions): Uint8Array;
|
||||
function text(source: Source, options?: TextConsumeOptions): Promise<string>;
|
||||
function textSync(source: SyncSource, options?: TextConsumeSyncOptions): string;
|
||||
function arrayBuffer(source: Source, options?: ConsumeOptions): Promise<ArrayBuffer>;
|
||||
function arrayBufferSync(source: SyncSource, options?: ConsumeSyncOptions): ArrayBuffer;
|
||||
function array(source: Source, options?: ConsumeOptions): Promise<Uint8Array[]>;
|
||||
function arraySync(source: SyncSource, options?: ConsumeSyncOptions): Uint8Array[];
|
||||
// Utilities
|
||||
function tap(callback: StatelessTransformFn): StatelessTransformFn;
|
||||
function tapSync(callback: SyncStatelessTransformFn): SyncStatelessTransformFn;
|
||||
function merge(...sources: Source[]): ByteReadableStream;
|
||||
function merge(...args: [...sources: Source[], options: MergeOptions]): ByteReadableStream;
|
||||
function ondrain(drainable: any): Promise<boolean> | null;
|
||||
// Multi-consumer
|
||||
function broadcast(options?: BroadcastOptions): BroadcastResult;
|
||||
function share(source: Source, options?: ShareOptions): Share;
|
||||
function shareSync(source: SyncSource, options?: ShareSyncOptions): SyncShare;
|
||||
// Duplex
|
||||
function duplex(options?: DuplexOptions): [DuplexChannel, DuplexChannel];
|
||||
// Node.js-specific extensions
|
||||
namespace Broadcast {
|
||||
/**
|
||||
* Create a `Broadcast` from an existing source. The source is consumed
|
||||
* automatically and pushed to all subscribers.
|
||||
* @since v25.9.0
|
||||
* @param options Same as `broadcast()`.
|
||||
*/
|
||||
function from(
|
||||
input: ByteReadableStream | SyncByteReadableStream | Broadcastable,
|
||||
options?: BroadcastOptions,
|
||||
): BroadcastResult;
|
||||
}
|
||||
namespace Share {
|
||||
/**
|
||||
* Create a `Share` from an existing source.
|
||||
* @since v25.9.0
|
||||
* @param options Same as `share()`.
|
||||
*/
|
||||
function from(input: ByteReadableStream | SyncByteReadableStream | Shareable, options?: ShareOptions): Share;
|
||||
}
|
||||
namespace SyncShare {
|
||||
/**
|
||||
* @since v25.9.0
|
||||
*/
|
||||
function from(input: SyncByteReadableStream | SyncShareable, options?: ShareSyncOptions): SyncShare;
|
||||
}
|
||||
/**
|
||||
* Converts a classic Readable stream (or duck-typed equivalent) into a
|
||||
* stream/iter async iterable source that can be passed to `from()`,
|
||||
* `pull()`, `text()`, etc.
|
||||
*
|
||||
* If the object implements the `toAsyncStreamable` protocol (as
|
||||
* `stream.Readable` does), that protocol is used. Otherwise, the function
|
||||
* duck-types on `read()` and `on()` (EventEmitter) and wraps the stream with
|
||||
* a batched async iterator.
|
||||
*
|
||||
* The result is cached per instance -- calling `fromReadable()` twice with the
|
||||
* same stream returns the same iterable.
|
||||
*
|
||||
* For object-mode or encoded Readable streams, chunks are automatically
|
||||
* normalized to `Uint8Array`.
|
||||
*
|
||||
* ```js
|
||||
* import { Readable } from 'node:stream';
|
||||
* import { fromReadable, text } from 'node:stream/iter';
|
||||
*
|
||||
* const readable = new Readable({
|
||||
* read() { this.push('hello world'); this.push(null); },
|
||||
* });
|
||||
*
|
||||
* const result = await text(fromReadable(readable));
|
||||
* console.log(result); // 'hello world'
|
||||
* ```
|
||||
* @since v26.1.0
|
||||
* @experimental
|
||||
* @param readable A classic Readable stream or any object
|
||||
* with `read()` and `on()` methods.
|
||||
* @returns A stream/iter async iterable source.
|
||||
*/
|
||||
function fromReadable(readable: NodeJS.ReadableStream): ByteReadableStream;
|
||||
interface FromWritableOptions {
|
||||
backpressure?: BackpressurePolicy | undefined;
|
||||
}
|
||||
/**
|
||||
* Creates a stream/iter Writer adapter from a classic Writable stream (or
|
||||
* duck-typed equivalent). The adapter can be passed to `pipeTo()` as a
|
||||
* destination.
|
||||
*
|
||||
* Since all writes on a classic Writable are fundamentally asynchronous,
|
||||
* the synchronous Writer methods (`writeSync`, `writevSync`, `endSync`) always
|
||||
* return `false` or `-1`, deferring to the async path. The per-write
|
||||
* `options.signal` parameter from the Writer interface is also ignored.
|
||||
*
|
||||
* The result is cached per instance and backpressure policy -- calling
|
||||
* `fromWritable()` twice with the same stream and `backpressure` option returns
|
||||
* the same Writer.
|
||||
*
|
||||
* For duck-typed streams that do not expose `writableHighWaterMark`,
|
||||
* `writableLength`, or similar properties, sensible defaults are used.
|
||||
* Object-mode writables (if detectable) are rejected since the Writer
|
||||
* interface is bytes-only.
|
||||
*
|
||||
* ```js
|
||||
* import { Writable } from 'node:stream';
|
||||
* import { from, fromWritable, pipeTo } from 'node:stream/iter';
|
||||
*
|
||||
* const writable = new Writable({
|
||||
* write(chunk, encoding, cb) { console.log(chunk.toString()); cb(); },
|
||||
* });
|
||||
*
|
||||
* await pipeTo(from('hello world'),
|
||||
* fromWritable(writable, { backpressure: 'block' }));
|
||||
* ```
|
||||
* @since v26.1.0
|
||||
* @experimental
|
||||
* @param writable A classic Writable stream or any object
|
||||
* with `write()` and `on()` methods.
|
||||
* @returns A stream/iter Writer adapter.
|
||||
*/
|
||||
function fromWritable(writable: NodeJS.WritableStream, options?: FromWritableOptions): Writer;
|
||||
interface ToReadableOptions extends Abortable {
|
||||
highWaterMark?: number | undefined;
|
||||
}
|
||||
/**
|
||||
* Creates a byte-mode `stream.Readable` from an `AsyncIterable<Uint8Array[]>`
|
||||
* (the native batch format used by the stream/iter API). Each `Uint8Array` in a
|
||||
* yielded batch is pushed as a separate chunk into the Readable.
|
||||
*
|
||||
* ```js
|
||||
* import { createWriteStream } from 'node:fs';
|
||||
* import { from, pull, toReadable } from 'node:stream/iter';
|
||||
* import { compressGzip } from 'node:zlib/iter';
|
||||
*
|
||||
* const source = pull(from('hello world'), compressGzip());
|
||||
* const readable = toReadable(source);
|
||||
*
|
||||
* readable.pipe(createWriteStream('output.gz'));
|
||||
* ```
|
||||
* @since v26.1.0
|
||||
* @experimental
|
||||
* @param source An `AsyncIterable<Uint8Array[]>` source, such as
|
||||
* the return value of `pull()` or `from()`.
|
||||
*/
|
||||
function toReadable(source: Source, options?: ToReadableOptions): Readable;
|
||||
interface ToReadableSyncOptions {
|
||||
highWaterMark?: number | undefined;
|
||||
}
|
||||
/**
|
||||
* Creates a byte-mode `stream.Readable` from a synchronous
|
||||
* `Iterable<Uint8Array[]>`. The `_read()` method pulls from the iterator
|
||||
* synchronously, so data is available immediately via `readable.read()`.
|
||||
*
|
||||
* ```js
|
||||
* import { fromSync, toReadableSync } from 'node:stream/iter';
|
||||
*
|
||||
* const source = fromSync('hello world');
|
||||
* const readable = toReadableSync(source);
|
||||
*
|
||||
* console.log(readable.read().toString()); // 'hello world'
|
||||
* ```
|
||||
* @since v26.1.0
|
||||
* @experimental
|
||||
* @param source An `Iterable<Uint8Array[]>` source, such as the
|
||||
* return value of `pullSync()` or `fromSync()`.
|
||||
*/
|
||||
function toReadableSync(source: SyncSource, options?: ToReadableSyncOptions): Readable;
|
||||
/**
|
||||
* Creates a classic `stream.Writable` backed by a stream/iter Writer.
|
||||
*
|
||||
* Each `_write()` / `_writev()` call attempts the Writer's synchronous method
|
||||
* first (`writeSync` / `writevSync`), falling back to the async method if the
|
||||
* sync path returns `false` or throws. Similarly, `_final()` tries `endSync()`
|
||||
* before `end()`. When the sync path succeeds, the callback is deferred via
|
||||
* `queueMicrotask` to preserve the async resolution contract.
|
||||
*
|
||||
* The Writable's `highWaterMark` is set to `Number.MAX_SAFE_INTEGER` to
|
||||
* effectively disable its internal buffering, allowing the underlying Writer
|
||||
* to manage backpressure directly.
|
||||
*
|
||||
* ```js
|
||||
* import { push, toWritable } from 'node:stream/iter';
|
||||
*
|
||||
* const { writer, readable } = push();
|
||||
* const writable = toWritable(writer);
|
||||
*
|
||||
* writable.write('hello');
|
||||
* writable.end();
|
||||
* ```
|
||||
* @since v26.1.0
|
||||
* @experimental
|
||||
* @param writer A stream/iter Writer. Only the `write()` method is
|
||||
* required; `end()`, `fail()`, `writeSync()`, `writevSync()`, `endSync()`,
|
||||
* and `writev()` are optional.
|
||||
*/
|
||||
function toWritable(writer: PartialWriter): Writable;
|
||||
namespace Stream {
|
||||
export {
|
||||
array,
|
||||
arrayBuffer,
|
||||
arrayBufferSync,
|
||||
arraySync,
|
||||
broadcast,
|
||||
broadcastProtocol,
|
||||
bytes,
|
||||
bytesSync,
|
||||
drainableProtocol,
|
||||
duplex,
|
||||
from,
|
||||
fromSync,
|
||||
merge,
|
||||
ondrain,
|
||||
pipeTo,
|
||||
pipeToSync,
|
||||
pull,
|
||||
pullSync,
|
||||
push,
|
||||
share,
|
||||
shareProtocol,
|
||||
shareSync,
|
||||
shareSyncProtocol,
|
||||
tap,
|
||||
tapSync,
|
||||
text,
|
||||
textSync,
|
||||
toAsyncStreamable,
|
||||
toStreamable,
|
||||
};
|
||||
}
|
||||
}
|
||||
declare module "stream/iter" {
|
||||
export * from "node:stream/iter";
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
declare namespace deepEqual {
|
||||
/**
|
||||
* Memoization class used to speed up comparison.
|
||||
*/
|
||||
class MemoizeMap extends WeakMap<object, MemoizeMap | boolean> {}
|
||||
|
||||
interface DeepEqualOptions<T1 = unknown, T2 = unknown> {
|
||||
/**
|
||||
* Override default algorithm, determining custom equality.
|
||||
*/
|
||||
comparator?: (leftHandOperand: T1, rightHandOperand: T2) => boolean | null;
|
||||
|
||||
/**
|
||||
* Provide a custom memoization object which will cache the results of
|
||||
* complex objects for a speed boost.
|
||||
*
|
||||
* By passing `false` you can disable memoization, but this will cause circular
|
||||
* references to blow the stack.
|
||||
*/
|
||||
memoize?: MemoizeMap | false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert deeply nested sameValue equality between two objects of any type.
|
||||
*
|
||||
* @param leftHandOperand
|
||||
* @param rightHandOperand
|
||||
* @param [options] Additional options
|
||||
* @return equal match
|
||||
*/
|
||||
declare function deepEqual<T1, T2>(
|
||||
leftHandOperand: T1,
|
||||
rightHandOperand: T2,
|
||||
options?: deepEqual.DeepEqualOptions<T1, T2>,
|
||||
): boolean;
|
||||
|
||||
export = deepEqual;
|
||||
@@ -0,0 +1,361 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const tsutils = __importStar(require("ts-api-utils"));
|
||||
const ts = __importStar(require("typescript"));
|
||||
const util_1 = require("../util");
|
||||
/**
|
||||
* Static methods on these globals are either not `this`-aware or supported being
|
||||
* called without `this`.
|
||||
*
|
||||
* - `Promise` is not in the list because it supports subclassing by using `this`
|
||||
* - `Array` is in the list because although it supports subclassing, the `this`
|
||||
* value defaults to `Array` when unbound
|
||||
*
|
||||
* This is now a language-design invariant: static methods are never `this`-aware
|
||||
* because TC39 wants to make `array.map(Class.method)` work!
|
||||
*/
|
||||
const SUPPORTED_GLOBALS = [
|
||||
'Number',
|
||||
'Object',
|
||||
'String', // eslint-disable-line @typescript-eslint/internal/prefer-ast-types-enum
|
||||
'RegExp',
|
||||
'Symbol',
|
||||
'Array',
|
||||
'Proxy',
|
||||
'Date',
|
||||
'Atomics',
|
||||
'Reflect',
|
||||
'console',
|
||||
'Math',
|
||||
'JSON',
|
||||
'Intl',
|
||||
];
|
||||
const nativelyBoundMembers = new Set(SUPPORTED_GLOBALS.flatMap(namespace => {
|
||||
if (!(namespace in global)) {
|
||||
// node.js might not have namespaces like Intl depending on compilation options
|
||||
// https://nodejs.org/api/intl.html#intl_options_for_building_node_js
|
||||
return [];
|
||||
}
|
||||
const object = global[namespace];
|
||||
return Object.getOwnPropertyNames(object)
|
||||
.filter(name => !name.startsWith('_') &&
|
||||
typeof object[name] === 'function')
|
||||
.map(name => `${namespace}.${name}`);
|
||||
}));
|
||||
const SUPPORTED_GLOBAL_TYPES = [
|
||||
'NumberConstructor',
|
||||
'ObjectConstructor',
|
||||
'StringConstructor',
|
||||
'SymbolConstructor',
|
||||
'ArrayConstructor',
|
||||
'Array',
|
||||
'ProxyConstructor',
|
||||
'Console',
|
||||
'DateConstructor',
|
||||
'Atomics',
|
||||
'Math',
|
||||
'JSON',
|
||||
];
|
||||
const isNotImported = (symbol, currentSourceFile) => {
|
||||
const { valueDeclaration } = symbol;
|
||||
if (!valueDeclaration) {
|
||||
// working around https://github.com/microsoft/TypeScript/issues/31294
|
||||
return false;
|
||||
}
|
||||
return (!!currentSourceFile &&
|
||||
currentSourceFile !== valueDeclaration.getSourceFile());
|
||||
};
|
||||
const BASE_MESSAGE = [
|
||||
`A method that is not declared with \`this: void\` may cause unintentional scoping of \`this\` when separated from its object.`,
|
||||
`Consider using an arrow function or explicitly \`.bind()\`ing the method to avoid calling the method with an unintended \`this\` value. `,
|
||||
].join('\n');
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'unbound-method',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce unbound methods are called with their expected scope',
|
||||
recommended: 'recommended',
|
||||
requiresTypeChecking: true,
|
||||
},
|
||||
messages: {
|
||||
unbound: BASE_MESSAGE,
|
||||
unboundWithoutThisAnnotation: `${BASE_MESSAGE}\nIf a function does not access \`this\`, it can be annotated with \`this: void\`.`,
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
ignoreStatic: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to skip checking whether `static` methods are correctly bound.',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultOptions: [
|
||||
{
|
||||
ignoreStatic: false,
|
||||
},
|
||||
],
|
||||
create(context, [{ ignoreStatic }]) {
|
||||
const services = (0, util_1.getParserServices)(context);
|
||||
const currentSourceFile = services.program.getSourceFile(context.filename);
|
||||
function checkIfMethodAndReport(node, symbol) {
|
||||
if (!symbol) {
|
||||
return false;
|
||||
}
|
||||
const { dangerous, firstParamIsThis } = checkIfMethod(symbol, ignoreStatic);
|
||||
if (dangerous) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: firstParamIsThis === false
|
||||
? 'unboundWithoutThisAnnotation'
|
||||
: 'unbound',
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function checkUnionConstituentsAndReport(reportNode, propertyName, type) {
|
||||
for (const intersectionPart of tsutils
|
||||
.unionConstituents(type)
|
||||
.flatMap(unionPart => tsutils.intersectionConstituents(unionPart))) {
|
||||
const reported = checkIfMethodAndReport(reportNode, intersectionPart.getProperty(propertyName));
|
||||
if (reported) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getAccessedPropertyNames(node) {
|
||||
if (!node.computed) {
|
||||
return node.property.type === utils_1.AST_NODE_TYPES.Identifier
|
||||
? [node.property.name]
|
||||
: [];
|
||||
}
|
||||
return tsutils
|
||||
.unionConstituents(services.getTypeAtLocation(node.property))
|
||||
.flatMap(part => {
|
||||
return part.isStringLiteral() || part.isNumberLiteral()
|
||||
? [part.value.toString()]
|
||||
: [];
|
||||
});
|
||||
}
|
||||
function isNativelyBound(object, property) {
|
||||
// We can't rely entirely on the type-level checks made at the end of this
|
||||
// function, because sometimes type declarations don't come from the
|
||||
// default library, but come from, for example, "@types/node". And we can't
|
||||
// tell if a method is unbound just by looking at its signature declared in
|
||||
// the interface.
|
||||
//
|
||||
// See related discussion https://github.com/typescript-eslint/typescript-eslint/pull/8952#discussion_r1576543310
|
||||
if (object.type === utils_1.AST_NODE_TYPES.Identifier &&
|
||||
property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
||||
const objectSymbol = services.getSymbolAtLocation(object);
|
||||
const notImported = objectSymbol != null &&
|
||||
isNotImported(objectSymbol, currentSourceFile);
|
||||
if (notImported &&
|
||||
nativelyBoundMembers.has(`${object.name}.${property.name}`)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// if `${object.name}.${property.name}` doesn't match any of
|
||||
// the nativelyBoundMembers, then we fallback to type-level checks
|
||||
return ((0, util_1.isBuiltinSymbolLike)(services.program, services.getTypeAtLocation(object), SUPPORTED_GLOBAL_TYPES) &&
|
||||
(0, util_1.isSymbolFromDefaultLibrary)(services.program, services.getTypeAtLocation(property).getSymbol()));
|
||||
}
|
||||
return {
|
||||
MemberExpression(node) {
|
||||
if (isSafeUse(node) || isNativelyBound(node.object, node.property)) {
|
||||
return;
|
||||
}
|
||||
const propertyNames = getAccessedPropertyNames(node);
|
||||
if (propertyNames.length === 0) {
|
||||
return;
|
||||
}
|
||||
const objectType = services.getTypeAtLocation(node.object);
|
||||
for (const propertyName of propertyNames) {
|
||||
if (checkUnionConstituentsAndReport(node, propertyName, objectType)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
ObjectPattern(node) {
|
||||
if (isNodeInsideTypeDeclaration(node)) {
|
||||
return;
|
||||
}
|
||||
let initNode = null;
|
||||
if (node.parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
||||
initNode = node.parent.init;
|
||||
}
|
||||
else if (node.parent.type === utils_1.AST_NODE_TYPES.AssignmentPattern ||
|
||||
node.parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
||||
initNode = node.parent.right;
|
||||
}
|
||||
for (const property of node.properties) {
|
||||
if (property.type !== utils_1.AST_NODE_TYPES.Property ||
|
||||
property.key.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
||||
continue;
|
||||
}
|
||||
if (initNode) {
|
||||
if (!isNativelyBound(initNode, property.key)) {
|
||||
const reported = checkIfMethodAndReport(property.key, services
|
||||
.getTypeAtLocation(initNode)
|
||||
.getProperty(property.key.name));
|
||||
if (reported) {
|
||||
continue;
|
||||
}
|
||||
// In assignment patterns, we should also check the type of
|
||||
// Foo's nativelyBound method because initNode might be used as
|
||||
// default value:
|
||||
// function ({ nativelyBound }: Foo = NativeObject) {}
|
||||
}
|
||||
else if (node.parent.type !== utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
checkUnionConstituentsAndReport(property.key, property.key.name, services.getTypeAtLocation(node));
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
function isNodeInsideTypeDeclaration(node) {
|
||||
let parent = node;
|
||||
while ((parent = parent.parent)) {
|
||||
if ((parent.type === utils_1.AST_NODE_TYPES.ClassDeclaration && parent.declare) ||
|
||||
parent.type === utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition ||
|
||||
parent.type === utils_1.AST_NODE_TYPES.TSDeclareFunction ||
|
||||
parent.type === utils_1.AST_NODE_TYPES.TSFunctionType ||
|
||||
parent.type === utils_1.AST_NODE_TYPES.TSInterfaceDeclaration ||
|
||||
parent.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration ||
|
||||
(parent.type === utils_1.AST_NODE_TYPES.VariableDeclaration && parent.declare)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function checkIfMethod(symbol, ignoreStatic) {
|
||||
const { valueDeclaration } = symbol;
|
||||
if (!valueDeclaration) {
|
||||
// working around https://github.com/microsoft/TypeScript/issues/31294
|
||||
return { dangerous: false };
|
||||
}
|
||||
switch (valueDeclaration.kind) {
|
||||
case ts.SyntaxKind.PropertyDeclaration:
|
||||
return {
|
||||
dangerous: valueDeclaration.initializer?.kind ===
|
||||
ts.SyntaxKind.FunctionExpression,
|
||||
};
|
||||
case ts.SyntaxKind.PropertyAssignment: {
|
||||
const assignee = valueDeclaration.initializer;
|
||||
if (assignee.kind !== ts.SyntaxKind.FunctionExpression) {
|
||||
return {
|
||||
dangerous: false,
|
||||
};
|
||||
}
|
||||
return checkMethod(assignee, ignoreStatic);
|
||||
}
|
||||
case ts.SyntaxKind.MethodDeclaration:
|
||||
case ts.SyntaxKind.MethodSignature: {
|
||||
return checkMethod(valueDeclaration, ignoreStatic);
|
||||
}
|
||||
}
|
||||
return { dangerous: false };
|
||||
}
|
||||
function checkMethod(valueDeclaration, ignoreStatic) {
|
||||
const firstParam = valueDeclaration.parameters.at(0);
|
||||
const firstParamIsThis = firstParam?.name.kind === ts.SyntaxKind.Identifier &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
||||
firstParam.name.escapedText === 'this';
|
||||
const thisArgIsVoid = firstParamIsThis && firstParam.type?.kind === ts.SyntaxKind.VoidKeyword;
|
||||
return {
|
||||
dangerous: !thisArgIsVoid &&
|
||||
!(ignoreStatic &&
|
||||
tsutils.includesModifier((0, util_1.getModifiers)(valueDeclaration), ts.SyntaxKind.StaticKeyword)),
|
||||
firstParamIsThis,
|
||||
};
|
||||
}
|
||||
function isSafeUse(node) {
|
||||
const parent = node.parent;
|
||||
switch (parent?.type) {
|
||||
case utils_1.AST_NODE_TYPES.IfStatement:
|
||||
case utils_1.AST_NODE_TYPES.ForStatement:
|
||||
case utils_1.AST_NODE_TYPES.MemberExpression:
|
||||
case utils_1.AST_NODE_TYPES.SwitchStatement:
|
||||
case utils_1.AST_NODE_TYPES.UpdateExpression:
|
||||
case utils_1.AST_NODE_TYPES.WhileStatement:
|
||||
return true;
|
||||
case utils_1.AST_NODE_TYPES.CallExpression:
|
||||
return parent.callee === node;
|
||||
case utils_1.AST_NODE_TYPES.ConditionalExpression:
|
||||
return parent.test === node;
|
||||
case utils_1.AST_NODE_TYPES.TaggedTemplateExpression:
|
||||
return parent.tag === node;
|
||||
case utils_1.AST_NODE_TYPES.UnaryExpression:
|
||||
// the first case is safe for obvious
|
||||
// reasons. The second one is also fine
|
||||
// since we're returning something falsy
|
||||
return ['!', 'delete', 'typeof', 'void'].includes(parent.operator);
|
||||
case utils_1.AST_NODE_TYPES.BinaryExpression:
|
||||
return ['!=', '!==', '==', '===', 'instanceof'].includes(parent.operator);
|
||||
case utils_1.AST_NODE_TYPES.AssignmentExpression:
|
||||
return (parent.operator === '=' &&
|
||||
(node === parent.left ||
|
||||
(node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
||||
node.object.type === utils_1.AST_NODE_TYPES.Super &&
|
||||
parent.left.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
||||
parent.left.object.type === utils_1.AST_NODE_TYPES.ThisExpression)));
|
||||
case utils_1.AST_NODE_TYPES.ChainExpression:
|
||||
case utils_1.AST_NODE_TYPES.TSNonNullExpression:
|
||||
case utils_1.AST_NODE_TYPES.TSAsExpression:
|
||||
case utils_1.AST_NODE_TYPES.TSTypeAssertion:
|
||||
return isSafeUse(parent);
|
||||
case utils_1.AST_NODE_TYPES.LogicalExpression:
|
||||
if (parent.operator === '&&' && parent.left === node) {
|
||||
// this is safe, as && will return the left if and only if it's falsy
|
||||
return true;
|
||||
}
|
||||
// in all other cases, it's likely the logical expression will return the method ref
|
||||
// so make sure the parent is a safe usage
|
||||
return isSafeUse(parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"p384.js","sourceRoot":"","sources":["src/p384.ts"],"names":[],"mappings":";;;AAMA,uCAAuD;AACvD,sEAAsE;AACzD,QAAA,IAAI,GAAiB,cAAK,CAAC;AACxC,sEAAsE;AACzD,QAAA,SAAS,GAAiB,cAAK,CAAC;AAC7C,6EAA6E;AAChE,QAAA,WAAW,GAAsC,CAAC,GAAG,EAAE,CAAC,qBAAW,CAAC,WAAW,CAAC,EAAE,CAAC;AAChG,6EAA6E;AAChE,QAAA,aAAa,GAAsC,CAAC,GAAG,EAAE,CAAC,qBAAW,CAAC,aAAa,CAAC,EAAE,CAAC"}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*!
|
||||
* is-glob <https://github.com/jonschlinkert/is-glob>
|
||||
*
|
||||
* Copyright (c) 2014-2017, Jon Schlinkert.
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
|
||||
var isExtglob = require('is-extglob');
|
||||
var chars = { '{': '}', '(': ')', '[': ']'};
|
||||
var strictCheck = function(str) {
|
||||
if (str[0] === '!') {
|
||||
return true;
|
||||
}
|
||||
var index = 0;
|
||||
var pipeIndex = -2;
|
||||
var closeSquareIndex = -2;
|
||||
var closeCurlyIndex = -2;
|
||||
var closeParenIndex = -2;
|
||||
var backSlashIndex = -2;
|
||||
while (index < str.length) {
|
||||
if (str[index] === '*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str[index + 1] === '?' && /[\].+)]/.test(str[index])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (closeSquareIndex !== -1 && str[index] === '[' && str[index + 1] !== ']') {
|
||||
if (closeSquareIndex < index) {
|
||||
closeSquareIndex = str.indexOf(']', index);
|
||||
}
|
||||
if (closeSquareIndex > index) {
|
||||
if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) {
|
||||
return true;
|
||||
}
|
||||
backSlashIndex = str.indexOf('\\', index);
|
||||
if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closeCurlyIndex !== -1 && str[index] === '{' && str[index + 1] !== '}') {
|
||||
closeCurlyIndex = str.indexOf('}', index);
|
||||
if (closeCurlyIndex > index) {
|
||||
backSlashIndex = str.indexOf('\\', index);
|
||||
if (backSlashIndex === -1 || backSlashIndex > closeCurlyIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closeParenIndex !== -1 && str[index] === '(' && str[index + 1] === '?' && /[:!=]/.test(str[index + 2]) && str[index + 3] !== ')') {
|
||||
closeParenIndex = str.indexOf(')', index);
|
||||
if (closeParenIndex > index) {
|
||||
backSlashIndex = str.indexOf('\\', index);
|
||||
if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pipeIndex !== -1 && str[index] === '(' && str[index + 1] !== '|') {
|
||||
if (pipeIndex < index) {
|
||||
pipeIndex = str.indexOf('|', index);
|
||||
}
|
||||
if (pipeIndex !== -1 && str[pipeIndex + 1] !== ')') {
|
||||
closeParenIndex = str.indexOf(')', pipeIndex);
|
||||
if (closeParenIndex > pipeIndex) {
|
||||
backSlashIndex = str.indexOf('\\', pipeIndex);
|
||||
if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str[index] === '\\') {
|
||||
var open = str[index + 1];
|
||||
index += 2;
|
||||
var close = chars[open];
|
||||
|
||||
if (close) {
|
||||
var n = str.indexOf(close, index);
|
||||
if (n !== -1) {
|
||||
index = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (str[index] === '!') {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var relaxedCheck = function(str) {
|
||||
if (str[0] === '!') {
|
||||
return true;
|
||||
}
|
||||
var index = 0;
|
||||
while (index < str.length) {
|
||||
if (/[*?{}()[\]]/.test(str[index])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str[index] === '\\') {
|
||||
var open = str[index + 1];
|
||||
index += 2;
|
||||
var close = chars[open];
|
||||
|
||||
if (close) {
|
||||
var n = str.indexOf(close, index);
|
||||
if (n !== -1) {
|
||||
index = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (str[index] === '!') {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
module.exports = function isGlob(str, options) {
|
||||
if (typeof str !== 'string' || str === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isExtglob(str)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var check = strictCheck;
|
||||
|
||||
// optionally relax check
|
||||
if (options && options.strict === false) {
|
||||
check = relaxedCheck;
|
||||
}
|
||||
|
||||
return check(str);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Utilities for short weierstrass curves, combined with noble-hashes.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { type CurveFn, type CurveType } from './abstract/weierstrass.ts';
|
||||
import type { CHash } from './utils.ts';
|
||||
/** connects noble-curves to noble-hashes */
|
||||
export declare function getHash(hash: CHash): {
|
||||
hash: CHash;
|
||||
};
|
||||
/** Same API as @noble/hashes, with ability to create curve with custom hash */
|
||||
export type CurveDef = Readonly<Omit<CurveType, 'hash'>>;
|
||||
export type CurveFnWithCreate = CurveFn & {
|
||||
create: (hash: CHash) => CurveFn;
|
||||
};
|
||||
/** @deprecated use new `weierstrass()` and `ecdsa()` methods */
|
||||
export declare function createCurve(curveDef: CurveDef, defHash: CHash): CurveFnWithCreate;
|
||||
//# sourceMappingURL=_shortw_utils.d.ts.map
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2017 Lovell Fuller and others.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
'use strict';
|
||||
|
||||
const isLinux = () => process.platform === 'linux';
|
||||
|
||||
let report = null;
|
||||
const getReport = () => {
|
||||
if (!report) {
|
||||
/* istanbul ignore next */
|
||||
if (isLinux() && process.report) {
|
||||
const orig = process.report.excludeNetwork;
|
||||
process.report.excludeNetwork = true;
|
||||
report = process.report.getReport();
|
||||
process.report.excludeNetwork = orig;
|
||||
} else {
|
||||
report = {};
|
||||
}
|
||||
}
|
||||
return report;
|
||||
};
|
||||
|
||||
module.exports = { isLinux, getReport };
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
|
||||
## Security contact information
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
||||
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getForStatementHeadLoc = getForStatementHeadLoc;
|
||||
const eslint_utils_1 = require("@typescript-eslint/utils/eslint-utils");
|
||||
/**
|
||||
* Gets the location of the head of the given for statement variant for reporting.
|
||||
*
|
||||
* - `for (const foo in bar) expressionOrBlock`
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^
|
||||
*
|
||||
* - `for (const foo of bar) expressionOrBlock`
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^
|
||||
*
|
||||
* - `for await (const foo of bar) expressionOrBlock`
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
*
|
||||
* - `for (let i = 0; i < 10; i++) expressionOrBlock`
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
*/
|
||||
function getForStatementHeadLoc(sourceCode, node) {
|
||||
const closingParens = (0, eslint_utils_1.nullThrows)(sourceCode.getTokenBefore(node.body, token => token.value === ')'), 'for statement must have a closing parenthesis.');
|
||||
return {
|
||||
end: structuredClone(closingParens.loc.end),
|
||||
start: structuredClone(node.loc.start),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import * as util from "../core/util.js";
|
||||
const error = () => {
|
||||
const Sizable = {
|
||||
string: { unit: "знаци", verb: "да имаат" },
|
||||
file: { unit: "бајти", verb: "да имаат" },
|
||||
array: { unit: "ставки", verb: "да имаат" },
|
||||
set: { unit: "ставки", verb: "да имаат" },
|
||||
};
|
||||
function getSizing(origin) {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
const FormatDictionary = {
|
||||
regex: "внес",
|
||||
email: "адреса на е-пошта",
|
||||
url: "URL",
|
||||
emoji: "емоџи",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "ISO датум и време",
|
||||
date: "ISO датум",
|
||||
time: "ISO време",
|
||||
duration: "ISO времетраење",
|
||||
ipv4: "IPv4 адреса",
|
||||
ipv6: "IPv6 адреса",
|
||||
cidrv4: "IPv4 опсег",
|
||||
cidrv6: "IPv6 опсег",
|
||||
base64: "base64-енкодирана низа",
|
||||
base64url: "base64url-енкодирана низа",
|
||||
json_string: "JSON низа",
|
||||
e164: "E.164 број",
|
||||
jwt: "JWT",
|
||||
template_literal: "внес",
|
||||
};
|
||||
const TypeDictionary = {
|
||||
nan: "NaN",
|
||||
number: "број",
|
||||
array: "низа",
|
||||
};
|
||||
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 `Грешен внес: се очекува instanceof ${issue.expected}, примено ${received}`;
|
||||
}
|
||||
return `Грешен внес: се очекува ${expected}, примено ${received}`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1)
|
||||
return `Invalid input: expected ${util.stringifyPrimitive(issue.values[0])}`;
|
||||
return `Грешана опција: се очекува една ${util.joinValues(issue.values, "|")}`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "<=" : "<";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `Премногу голем: се очекува ${issue.origin ?? "вредноста"} да има ${adj}${issue.maximum.toString()} ${sizing.unit ?? "елементи"}`;
|
||||
return `Премногу голем: се очекува ${issue.origin ?? "вредноста"} да биде ${adj}${issue.maximum.toString()}`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? ">=" : ">";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `Премногу мал: се очекува ${issue.origin} да има ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
}
|
||||
return `Премногу мал: се очекува ${issue.origin} да биде ${adj}${issue.minimum.toString()}`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue;
|
||||
if (_issue.format === "starts_with") {
|
||||
return `Неважечка низа: мора да започнува со "${_issue.prefix}"`;
|
||||
}
|
||||
if (_issue.format === "ends_with")
|
||||
return `Неважечка низа: мора да завршува со "${_issue.suffix}"`;
|
||||
if (_issue.format === "includes")
|
||||
return `Неважечка низа: мора да вклучува "${_issue.includes}"`;
|
||||
if (_issue.format === "regex")
|
||||
return `Неважечка низа: мора да одгоара на патернот ${_issue.pattern}`;
|
||||
return `Invalid ${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `Грешен број: мора да биде делив со ${issue.divisor}`;
|
||||
case "unrecognized_keys":
|
||||
return `${issue.keys.length > 1 ? "Непрепознаени клучеви" : "Непрепознаен клуч"}: ${util.joinValues(issue.keys, ", ")}`;
|
||||
case "invalid_key":
|
||||
return `Грешен клуч во ${issue.origin}`;
|
||||
case "invalid_union":
|
||||
return "Грешен внес";
|
||||
case "invalid_element":
|
||||
return `Грешна вредност во ${issue.origin}`;
|
||||
default:
|
||||
return `Грешен внес`;
|
||||
}
|
||||
};
|
||||
};
|
||||
export default function () {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,464 @@
|
||||
import { RawSourceMap, SourceMapGenerator } from 'source-map-js'
|
||||
|
||||
import AtRule, { AtRuleProps } from './at-rule.js'
|
||||
import Comment, { CommentProps } from './comment.js'
|
||||
import Container, { ContainerProps, NewChild } from './container.js'
|
||||
import CssSyntaxError from './css-syntax-error.js'
|
||||
import Declaration, { DeclarationProps } from './declaration.js'
|
||||
import Document, { DocumentProps } from './document.js'
|
||||
import Input, { FilePosition } from './input.js'
|
||||
import LazyResult from './lazy-result.js'
|
||||
import list from './list.js'
|
||||
import Node, {
|
||||
AnyNode,
|
||||
ChildNode,
|
||||
ChildProps,
|
||||
NodeErrorOptions,
|
||||
NodeProps,
|
||||
Position,
|
||||
Source
|
||||
} from './node.js'
|
||||
import Processor from './processor.js'
|
||||
import Result, { Message } from './result.js'
|
||||
import Root, { RootProps } from './root.js'
|
||||
import Rule, { RuleProps } from './rule.js'
|
||||
import Warning, { WarningOptions } from './warning.js'
|
||||
|
||||
type DocumentProcessor = (
|
||||
document: Document,
|
||||
helper: postcss.Helpers
|
||||
) => Promise<void> | void
|
||||
type RootProcessor = (
|
||||
root: Root,
|
||||
helper: postcss.Helpers
|
||||
) => Promise<void> | void
|
||||
type DeclarationProcessor = (
|
||||
decl: Declaration,
|
||||
helper: postcss.Helpers
|
||||
) => Promise<void> | void
|
||||
type RuleProcessor = (
|
||||
rule: Rule,
|
||||
helper: postcss.Helpers
|
||||
) => Promise<void> | void
|
||||
type AtRuleProcessor = (
|
||||
atRule: AtRule,
|
||||
helper: postcss.Helpers
|
||||
) => Promise<void> | void
|
||||
type CommentProcessor = (
|
||||
comment: Comment,
|
||||
helper: postcss.Helpers
|
||||
) => Promise<void> | void
|
||||
|
||||
interface Processors {
|
||||
/**
|
||||
* Will be called on all`AtRule` nodes.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
AtRule?: { [name: string]: AtRuleProcessor } | AtRuleProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `AtRule` nodes, when all children will be processed.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
AtRuleExit?: { [name: string]: AtRuleProcessor } | AtRuleProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `Comment` nodes.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
Comment?: CommentProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `Comment` nodes after listeners
|
||||
* for `Comment` event.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
CommentExit?: CommentProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `Declaration` nodes after listeners
|
||||
* for `Declaration` event.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
Declaration?: { [prop: string]: DeclarationProcessor } | DeclarationProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `Declaration` nodes.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
DeclarationExit?:
|
||||
| { [prop: string]: DeclarationProcessor }
|
||||
| DeclarationProcessor
|
||||
|
||||
/**
|
||||
* Will be called on `Document` node.
|
||||
*
|
||||
* Will be called again on children changes.
|
||||
*/
|
||||
Document?: DocumentProcessor
|
||||
|
||||
/**
|
||||
* Will be called on `Document` node, when all children will be processed.
|
||||
*
|
||||
* Will be called again on children changes.
|
||||
*/
|
||||
DocumentExit?: DocumentProcessor
|
||||
|
||||
/**
|
||||
* Will be called on `Root` node once.
|
||||
*/
|
||||
Once?: RootProcessor
|
||||
|
||||
/**
|
||||
* Will be called on `Root` node once, when all children will be processed.
|
||||
*/
|
||||
OnceExit?: RootProcessor
|
||||
|
||||
/**
|
||||
* Will be called on `Root` node.
|
||||
*
|
||||
* Will be called again on children changes.
|
||||
*/
|
||||
Root?: RootProcessor
|
||||
|
||||
/**
|
||||
* Will be called on `Root` node, when all children will be processed.
|
||||
*
|
||||
* Will be called again on children changes.
|
||||
*/
|
||||
RootExit?: RootProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `Rule` nodes.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
Rule?: RuleProcessor
|
||||
|
||||
/**
|
||||
* Will be called on all `Rule` nodes, when all children will be processed.
|
||||
*
|
||||
* Will be called again on node or children changes.
|
||||
*/
|
||||
RuleExit?: RuleProcessor
|
||||
}
|
||||
|
||||
declare namespace postcss {
|
||||
export {
|
||||
AnyNode,
|
||||
AtRule,
|
||||
AtRuleProps,
|
||||
ChildNode,
|
||||
ChildProps,
|
||||
Comment,
|
||||
CommentProps,
|
||||
Container,
|
||||
ContainerProps,
|
||||
CssSyntaxError,
|
||||
Declaration,
|
||||
DeclarationProps,
|
||||
Document,
|
||||
DocumentProps,
|
||||
FilePosition,
|
||||
Input,
|
||||
LazyResult,
|
||||
list,
|
||||
Message,
|
||||
NewChild,
|
||||
Node,
|
||||
NodeErrorOptions,
|
||||
NodeProps,
|
||||
Position,
|
||||
Processor,
|
||||
Result,
|
||||
Root,
|
||||
RootProps,
|
||||
Rule,
|
||||
RuleProps,
|
||||
Source,
|
||||
Warning,
|
||||
WarningOptions
|
||||
}
|
||||
|
||||
export type SourceMap = {
|
||||
toJSON(): RawSourceMap
|
||||
} & SourceMapGenerator
|
||||
|
||||
export type Helpers = { postcss: Postcss; result: Result } & Postcss
|
||||
|
||||
export interface Plugin extends Processors {
|
||||
postcssPlugin: string
|
||||
prepare?: (result: Result) => Processors
|
||||
}
|
||||
|
||||
export interface PluginCreator<PluginOptions> {
|
||||
(opts?: PluginOptions): Plugin | Processor
|
||||
postcss: true
|
||||
}
|
||||
|
||||
export interface Transformer extends TransformCallback {
|
||||
postcssPlugin: string
|
||||
postcssVersion: string
|
||||
}
|
||||
|
||||
export interface TransformCallback {
|
||||
(root: Root, result: Result): Promise<void> | void
|
||||
}
|
||||
|
||||
export interface OldPlugin<T> extends Transformer {
|
||||
(opts?: T): Transformer
|
||||
postcss: Transformer
|
||||
}
|
||||
|
||||
export type AcceptedPlugin =
|
||||
| {
|
||||
postcss: Processor | TransformCallback
|
||||
}
|
||||
| OldPlugin<any>
|
||||
| Plugin
|
||||
| PluginCreator<any>
|
||||
| Processor
|
||||
| TransformCallback
|
||||
|
||||
export interface Parser<RootNode = Document | Root> {
|
||||
(
|
||||
css: { toString(): string } | string,
|
||||
opts?: Pick<ProcessOptions, 'document' | 'from' | 'map' | 'unsafeMap'>
|
||||
): RootNode
|
||||
}
|
||||
|
||||
export interface Builder {
|
||||
(part: string, node?: AnyNode, type?: 'end' | 'start'): void
|
||||
}
|
||||
|
||||
export interface Stringifier {
|
||||
(node: AnyNode, builder: Builder): void
|
||||
}
|
||||
|
||||
export interface JSONHydrator {
|
||||
(data: object): Node
|
||||
(data: object[]): Node[]
|
||||
}
|
||||
|
||||
export interface Syntax<RootNode = Document | Root> {
|
||||
/**
|
||||
* Function to generate AST by string.
|
||||
*/
|
||||
parse?: Parser<RootNode>
|
||||
|
||||
/**
|
||||
* Class to generate string by AST.
|
||||
*/
|
||||
stringify?: Stringifier
|
||||
}
|
||||
|
||||
export interface SourceMapOptions {
|
||||
/**
|
||||
* Use absolute path in generated source map.
|
||||
*/
|
||||
absolute?: boolean
|
||||
|
||||
/**
|
||||
* Indicates that PostCSS should add annotation comments to the CSS.
|
||||
* By default, PostCSS will always add a comment with a path
|
||||
* to the source map. PostCSS will not add annotations to CSS files
|
||||
* that do not contain any comments.
|
||||
*
|
||||
* By default, PostCSS presumes that you want to save the source map as
|
||||
* `opts.to + '.map'` and will use this path in the annotation comment.
|
||||
* A different path can be set by providing a string value for annotation.
|
||||
*
|
||||
* If you have set `inline: true`, annotation cannot be disabled.
|
||||
*/
|
||||
annotation?: ((file: string, root: Root) => string) | boolean | string
|
||||
|
||||
/**
|
||||
* Override `from` in map’s sources.
|
||||
*/
|
||||
from?: string
|
||||
|
||||
/**
|
||||
* Indicates that the source map should be embedded in the output CSS
|
||||
* as a Base64-encoded comment. By default, it is `true`.
|
||||
* But if all previous maps are external, not inline, PostCSS will not embed
|
||||
* the map even if you do not set this option.
|
||||
*
|
||||
* If you have an inline source map, the result.map property will be empty,
|
||||
* as the source map will be contained within the text of `result.css`.
|
||||
*/
|
||||
inline?: boolean
|
||||
|
||||
/**
|
||||
* Source map content from a previous processing step (e.g., Sass).
|
||||
*
|
||||
* PostCSS will try to read the previous source map
|
||||
* automatically (based on comments within the source CSS), but you can use
|
||||
* this option to identify it manually.
|
||||
*
|
||||
* If desired, you can omit the previous map with prev: `false`.
|
||||
*/
|
||||
prev?: ((file: string) => string) | boolean | object | string
|
||||
|
||||
/**
|
||||
* Indicates that PostCSS should set the origin content (e.g., Sass source)
|
||||
* of the source map. By default, it is true. But if all previous maps do not
|
||||
* contain sources content, PostCSS will also leave it out even if you
|
||||
* do not set this option.
|
||||
*/
|
||||
sourcesContent?: boolean
|
||||
}
|
||||
|
||||
export interface ProcessOptions<RootNode = Document | Root> {
|
||||
/**
|
||||
* Input file if it is not simple CSS file, but HTML with <style> or JS with CSS-in-JS blocks.
|
||||
*/
|
||||
document?: string
|
||||
|
||||
/**
|
||||
* The path of the CSS source file. You should always set `from`,
|
||||
* because it is used in source map generation and syntax error messages.
|
||||
*/
|
||||
from?: string | undefined
|
||||
|
||||
/**
|
||||
* Source map options
|
||||
*/
|
||||
map?: boolean | SourceMapOptions
|
||||
|
||||
/**
|
||||
* Function to generate AST by string.
|
||||
*/
|
||||
parser?: Parser<RootNode> | Syntax<RootNode>
|
||||
|
||||
/**
|
||||
* Class to generate string by AST.
|
||||
*/
|
||||
stringifier?: Stringifier | Syntax<RootNode>
|
||||
|
||||
/**
|
||||
* Object with parse and stringify.
|
||||
*/
|
||||
syntax?: Syntax<RootNode>
|
||||
|
||||
/**
|
||||
* The path where you'll put the output CSS file. You should always set `to`
|
||||
* to generate correct source maps.
|
||||
*/
|
||||
to?: string
|
||||
|
||||
/**
|
||||
* Disable source map file protections.
|
||||
*
|
||||
* By default source map is limited only for `.map` files
|
||||
* in the `from` folder.
|
||||
*/
|
||||
unsafeMap?: boolean
|
||||
}
|
||||
|
||||
export type Postcss = typeof postcss
|
||||
|
||||
/**
|
||||
* Default function to convert a node tree into a CSS string.
|
||||
*/
|
||||
export let stringify: Stringifier
|
||||
|
||||
/**
|
||||
* Parses source css and returns a new `Root` or `Document` node,
|
||||
* which contains the source CSS nodes.
|
||||
*
|
||||
* ```js
|
||||
* // Simple CSS concatenation with source map support
|
||||
* const root1 = postcss.parse(css1, { from: file1 })
|
||||
* const root2 = postcss.parse(css2, { from: file2 })
|
||||
* root1.append(root2).toResult().css
|
||||
* ```
|
||||
*/
|
||||
export let parse: Parser<Root>
|
||||
|
||||
/**
|
||||
* Rehydrate a JSON AST (from `Node#toJSON`) back into the AST classes.
|
||||
*
|
||||
* ```js
|
||||
* const json = root.toJSON()
|
||||
* // save to file, send by network, etc
|
||||
* const root2 = postcss.fromJSON(json)
|
||||
* ```
|
||||
*/
|
||||
export let fromJSON: JSONHydrator
|
||||
|
||||
/**
|
||||
* Creates a new `Comment` node.
|
||||
*
|
||||
* @param defaults Properties for the new node.
|
||||
* @return New comment node
|
||||
*/
|
||||
export function comment(defaults?: CommentProps): Comment
|
||||
|
||||
/**
|
||||
* Creates a new `AtRule` node.
|
||||
*
|
||||
* @param defaults Properties for the new node.
|
||||
* @return New at-rule node.
|
||||
*/
|
||||
export function atRule(defaults?: AtRuleProps): AtRule
|
||||
|
||||
/**
|
||||
* Creates a new `Declaration` node.
|
||||
*
|
||||
* @param defaults Properties for the new node.
|
||||
* @return New declaration node.
|
||||
*/
|
||||
export function decl(defaults?: DeclarationProps): Declaration
|
||||
|
||||
/**
|
||||
* Creates a new `Rule` node.
|
||||
*
|
||||
* @param default Properties for the new node.
|
||||
* @return New rule node.
|
||||
*/
|
||||
export function rule(defaults?: RuleProps): Rule
|
||||
|
||||
/**
|
||||
* Creates a new `Root` node.
|
||||
*
|
||||
* @param defaults Properties for the new node.
|
||||
* @return New root node.
|
||||
*/
|
||||
export function root(defaults?: RootProps): Root
|
||||
|
||||
/**
|
||||
* Creates a new `Document` node.
|
||||
*
|
||||
* @param defaults Properties for the new node.
|
||||
* @return New document node.
|
||||
*/
|
||||
export function document(defaults?: DocumentProps): Document
|
||||
|
||||
export { postcss as default }
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new `Processor` instance that will apply `plugins`
|
||||
* as CSS processors.
|
||||
*
|
||||
* ```js
|
||||
* let postcss = require('postcss')
|
||||
*
|
||||
* postcss(plugins).process(css, { from, to }).then(result => {
|
||||
* console.log(result.css)
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @param plugins PostCSS plugins.
|
||||
* @return Processor to process multiple CSS.
|
||||
*/
|
||||
declare function postcss(plugins?: readonly postcss.AcceptedPlugin[]): Processor
|
||||
declare function postcss(...plugins: postcss.AcceptedPlugin[]): Processor
|
||||
|
||||
export = postcss
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
export type Options = [
|
||||
{
|
||||
ignoreArrowShorthand?: boolean;
|
||||
ignoreVoidOperator?: boolean;
|
||||
ignoreVoidReturningFunctions?: boolean;
|
||||
}
|
||||
];
|
||||
export type MessageId = 'invalidVoidExpr' | 'invalidVoidExprArrow' | 'invalidVoidExprArrowWrapVoid' | 'invalidVoidExprReturn' | 'invalidVoidExprReturnLast' | 'invalidVoidExprReturnWrapVoid' | 'invalidVoidExprWrapVoid' | 'voidExprWrapVoid';
|
||||
declare const _default: TSESLint.RuleModule<MessageId, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @typedef { import('estree').Node} Node
|
||||
* @typedef { import('./walker.js').WalkerContext} WalkerContext
|
||||
* @typedef {(
|
||||
* this: WalkerContext,
|
||||
* node: Node,
|
||||
* parent: Node | null,
|
||||
* key: string | number | symbol | null | undefined,
|
||||
* index: number | null | undefined
|
||||
* ) => void} SyncHandler
|
||||
*/
|
||||
export class SyncWalker extends WalkerBase {
|
||||
/**
|
||||
*
|
||||
* @param {SyncHandler} [enter]
|
||||
* @param {SyncHandler} [leave]
|
||||
*/
|
||||
constructor(enter?: SyncHandler | undefined, leave?: SyncHandler | undefined);
|
||||
/** @type {SyncHandler | undefined} */
|
||||
enter: SyncHandler | undefined;
|
||||
/** @type {SyncHandler | undefined} */
|
||||
leave: SyncHandler | undefined;
|
||||
/**
|
||||
* @template {Node} Parent
|
||||
* @param {Node} node
|
||||
* @param {Parent | null} parent
|
||||
* @param {keyof Parent} [prop]
|
||||
* @param {number | null} [index]
|
||||
* @returns {Node | null}
|
||||
*/
|
||||
visit<Parent extends import("estree").Node>(node: Node, parent: Parent | null, prop?: keyof Parent | undefined, index?: number | null | undefined): Node | null;
|
||||
}
|
||||
export type Node = import('estree').Node;
|
||||
export type WalkerContext = import('./walker.js').WalkerContext;
|
||||
export type SyncHandler = (this: WalkerContext, node: Node, parent: Node | null, key: string | number | symbol | null | undefined, index: number | null | undefined) => void;
|
||||
import { WalkerBase } from "./walker.js";
|
||||
@@ -0,0 +1,667 @@
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export * from './add-codec-sentinel';
|
||||
export * from './add-codec-size-prefix';
|
||||
export * from './assertions';
|
||||
export * from './bytes';
|
||||
export * from './codec';
|
||||
export * from './combine-codec';
|
||||
export * from './fix-codec-size';
|
||||
export * from './offset-codec';
|
||||
export * from './pad-codec';
|
||||
export * from './readonly-uint8array';
|
||||
export * from './resize-codec';
|
||||
export * from './reverse-codec';
|
||||
export * from './transform-codec';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
@@ -0,0 +1,4 @@
|
||||
function _instanceof(n, e) {
|
||||
return null != e && "undefined" != typeof Symbol && e[Symbol.hasInstance] ? !!e[Symbol.hasInstance](n) : n instanceof e;
|
||||
}
|
||||
export { _instanceof as default };
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* NIST secp256r1 aka p256.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { type H2CMethod } from './abstract/hash-to-curve.ts';
|
||||
import { p256 as p256n } from './nist.ts';
|
||||
/** @deprecated use `import { p256 } from '@noble/curves/nist.js';` */
|
||||
export declare const p256: typeof p256n;
|
||||
/** @deprecated use `import { p256 } from '@noble/curves/nist.js';` */
|
||||
export declare const secp256r1: typeof p256n;
|
||||
/** @deprecated use `import { p256_hasher } from '@noble/curves/nist.js';` */
|
||||
export declare const hashToCurve: H2CMethod<bigint>;
|
||||
/** @deprecated use `import { p256_hasher } from '@noble/curves/nist.js';` */
|
||||
export declare const encodeToCurve: H2CMethod<bigint>;
|
||||
//# sourceMappingURL=p256.d.ts.map
|
||||
@@ -0,0 +1,167 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const util_1 = require("../util");
|
||||
const printNodeModifiers = (node, final) => `${node.accessibility ?? ''}${node.static ? ' static' : ''} ${final} `.trimStart();
|
||||
const isSupportedLiteral = (node) => {
|
||||
switch (node.type) {
|
||||
case utils_1.AST_NODE_TYPES.Literal:
|
||||
return true;
|
||||
case utils_1.AST_NODE_TYPES.TaggedTemplateExpression:
|
||||
return node.quasi.quasis.length === 1;
|
||||
case utils_1.AST_NODE_TYPES.TemplateLiteral:
|
||||
return node.quasis.length === 1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'class-literal-property-style',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce that literals on classes are exposed in a consistent style',
|
||||
recommended: 'stylistic',
|
||||
},
|
||||
hasSuggestions: true,
|
||||
messages: {
|
||||
preferFieldStyle: 'Literals should be exposed using readonly fields.',
|
||||
preferFieldStyleSuggestion: 'Replace the literals with readonly fields.',
|
||||
preferGetterStyle: 'Literals should be exposed using getters.',
|
||||
preferGetterStyleSuggestion: 'Replace the literals with getters.',
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'string',
|
||||
description: 'Which literal class member syntax to prefer.',
|
||||
enum: ['fields', 'getters'],
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultOptions: ['fields'],
|
||||
create(context, [style]) {
|
||||
const propertiesInfoStack = [];
|
||||
function enterClassBody() {
|
||||
propertiesInfoStack.push({
|
||||
excludeSet: new Set(),
|
||||
properties: [],
|
||||
});
|
||||
}
|
||||
function exitClassBody() {
|
||||
const { excludeSet, properties } = (0, util_1.nullThrows)(propertiesInfoStack.pop(), 'Stack should exist on class exit');
|
||||
properties.forEach(node => {
|
||||
const { value } = node;
|
||||
if (!value || !isSupportedLiteral(value)) {
|
||||
return;
|
||||
}
|
||||
const name = (0, util_1.getStaticMemberAccessValue)(node, context);
|
||||
if (name && excludeSet.has(name)) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node: node.key,
|
||||
messageId: 'preferGetterStyle',
|
||||
suggest: [
|
||||
{
|
||||
messageId: 'preferGetterStyleSuggestion',
|
||||
fix(fixer) {
|
||||
const name = context.sourceCode.getText(node.key);
|
||||
let text = '';
|
||||
text += printNodeModifiers(node, 'get');
|
||||
text += node.computed ? `[${name}]` : name;
|
||||
text += `() { return ${context.sourceCode.getText(value)}; }`;
|
||||
return fixer.replaceText(node, text);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
}
|
||||
function excludeAssignedProperty(node) {
|
||||
if ((0, util_1.isAssignee)(node)) {
|
||||
const { excludeSet } = propertiesInfoStack[propertiesInfoStack.length - 1];
|
||||
const name = (0, util_1.getStaticMemberAccessValue)(node, context);
|
||||
if (name) {
|
||||
excludeSet.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
...(style === 'fields' && {
|
||||
MethodDefinition(node) {
|
||||
if (node.kind !== 'get' ||
|
||||
node.override ||
|
||||
!node.value.body ||
|
||||
node.value.body.body.length === 0) {
|
||||
return;
|
||||
}
|
||||
const [statement] = node.value.body.body;
|
||||
if (statement.type !== utils_1.AST_NODE_TYPES.ReturnStatement) {
|
||||
return;
|
||||
}
|
||||
const { argument } = statement;
|
||||
if (!argument || !isSupportedLiteral(argument)) {
|
||||
return;
|
||||
}
|
||||
const name = (0, util_1.getStaticMemberAccessValue)(node, context);
|
||||
const hasDuplicateKeySetter = name &&
|
||||
node.parent.body.some(element => {
|
||||
return (element.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
||||
element.kind === 'set' &&
|
||||
(0, util_1.isStaticMemberAccessOfValue)(element, context, name));
|
||||
});
|
||||
if (hasDuplicateKeySetter) {
|
||||
return;
|
||||
}
|
||||
const getterBody = node.value.body;
|
||||
context.report({
|
||||
node: node.key,
|
||||
messageId: 'preferFieldStyle',
|
||||
...(0, util_1.getFixOrSuggest)({
|
||||
fixOrSuggest: node.decorators.length === 0 ? 'suggest' : 'none',
|
||||
suggestion: {
|
||||
messageId: 'preferFieldStyleSuggestion',
|
||||
fix(fixer) {
|
||||
const name = context.sourceCode.getText(node.key);
|
||||
const closingParen = (0, util_1.nullThrows)(context.sourceCode.getTokenBefore(node.value.returnType ?? getterBody), 'Getter should have a closing parenthesis.');
|
||||
const betweenParensAndBody = context.sourceCode
|
||||
.getText()
|
||||
.slice(closingParen.range[1], getterBody.range[0]);
|
||||
let text = '';
|
||||
text += printNodeModifiers(node, 'readonly');
|
||||
text += node.computed ? `[${name}]` : name;
|
||||
text += betweenParensAndBody;
|
||||
text += `= ${context.sourceCode.getText(argument)};`;
|
||||
return fixer.replaceText(node, text);
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
},
|
||||
}),
|
||||
...(style === 'getters' && {
|
||||
ClassBody: enterClassBody,
|
||||
'ClassBody:exit': exitClassBody,
|
||||
'MethodDefinition[kind="constructor"] ThisExpression'(node) {
|
||||
if (node.parent.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
||||
let parent = node.parent;
|
||||
while (!(0, util_1.isFunction)(parent)) {
|
||||
parent = parent.parent;
|
||||
}
|
||||
if (parent.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
||||
parent.parent.kind === 'constructor') {
|
||||
excludeAssignedProperty(node.parent);
|
||||
}
|
||||
}
|
||||
},
|
||||
PropertyDefinition(node) {
|
||||
if (!node.readonly || node.declare || node.override) {
|
||||
return;
|
||||
}
|
||||
const { properties } = propertiesInfoStack[propertiesInfoStack.length - 1];
|
||||
properties.push(node);
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
ewweqjewqjewqj
|
||||
Reference in New Issue
Block a user