refactor: introduce typescript for static type checking

We use JSDoc for documentation, but these annotations
were not being validated. This meant that type information
could become outdated or incorrect without any warning.

This commit introduces the TypeScript compiler (`tsc`) as a static
analysis tool to leverage our existing JSDoc comments.

To support this, JSDoc annotations across the codebase have been
improved for accuracy. Additionally, the `varint` module now uses a
custom `VarIntError` class for better type inference and error handling.
A new `typecheck` script has been added to `package.json` to run this
validation.
This commit is contained in:
2025-06-19 02:57:11 +03:00
parent 7322034aba
commit a1b999ca4e
6 changed files with 168 additions and 80 deletions

View File

@ -6,16 +6,16 @@ export const ERR_VARINT_BUFFER_UNDERFLOW = "VARINT_BUFFER_UNDERFLOW";
export const ERR_VARINT_MALFORMED = "VARINT_MALFORMED";
export const ERR_VARINT_ENCODE_TOO_LARGE = "VARINT_ENCODE_TOO_LARGE";
/**
* Creates a custom error object with a code property.
* @param {string} message The error message
* @param {string} code The error code
* @returns {Error}
*/
function createVarIntError(message, code) {
const err = new Error(message);
err.code = code;
return err;
export class VarIntError extends Error {
/**
* @param {string} message The error message.
* @param {string} code The error code.
*/
constructor(message, code) {
super(message);
this.name = "VarIntError";
this.code = code;
}
}
/**
@ -23,7 +23,7 @@ function createVarIntError(message, code) {
* VarInts are never longer than 5 bytes for the Minecraft protocol.
* @param {number} value The integer to encode
* @returns {Buffer} The encoded VarInt as a buffer
* @throws {Error} if the value is too large to be encoded
* @throws {VarIntError} if the value is too large to be encoded
*/
export function encodeVarInt(value) {
const buf = Buffer.alloc(5);
@ -42,7 +42,7 @@ export function encodeVarInt(value) {
buf.writeUInt8(byte | 0x80, written++);
if (written >= 5 && val > 0) {
throw createVarIntError(
throw new VarIntError(
"Value too large for a 5-byte VarInt",
ERR_VARINT_ENCODE_TOO_LARGE
);
@ -89,11 +89,11 @@ export function concatPackets(chunks) {
* @param {Buffer} buffer The buffer to read from
* @param {number} [offset=0] The starting offset in the buffer
* @returns {{ value: number, bytesRead: number }}
* @throws {Error} if the buffer is too short or the VarInt is malformed
* @throws {VarIntError} if the buffer is too short or the VarInt is malformed
*/
export function decodeVarInt(buffer, offset = 0) {
if (offset >= buffer.length) {
throw createVarIntError(
throw new VarIntError(
"Buffer underflow: Cannot decode VarInt at or beyond buffer length.",
ERR_VARINT_BUFFER_UNDERFLOW
);
@ -113,7 +113,7 @@ export function decodeVarInt(buffer, offset = 0) {
// Max 4 more bytes (total 5 bytes for a VarInt)
for (let i = 0; i < 4; i++) {
if (currentOffset >= buffer.length) {
throw createVarIntError(
throw new VarIntError(
"Buffer underflow: Incomplete VarInt, expected more bytes.",
ERR_VARINT_BUFFER_UNDERFLOW
);
@ -131,7 +131,7 @@ export function decodeVarInt(buffer, offset = 0) {
}
}
throw createVarIntError(
throw new VarIntError(
"VarInt is too big or malformed: 5 bytes read with continuation bit still set.",
ERR_VARINT_MALFORMED
);