From ff3184846080e7f60948c1099f7c176016f559f6 Mon Sep 17 00:00:00 2001 From: Alexander Zinn Date: Sat, 27 Sep 2025 13:43:30 -0400 Subject: [PATCH] websocket server: initial commit. Add Asserts static class --- Web/WebSocket/websocket/server/.npmrc | 2 + Web/WebSocket/websocket/server/.nvmrc | 1 + Web/WebSocket/websocket/server/.prettierrc | 12 ++ .../websocket/server/eslint.config.ts | 15 +++ Web/WebSocket/websocket/server/package.json | 31 +++++ .../websocket/server/src/WebSocketServer.ts | 1 + .../websocket/server/src/lang/Assert.ts | 111 ++++++++++++++++++ Web/WebSocket/websocket/server/tsconfig.json | 13 ++ 8 files changed, 186 insertions(+) create mode 100644 Web/WebSocket/websocket/server/.npmrc create mode 100644 Web/WebSocket/websocket/server/.nvmrc create mode 100644 Web/WebSocket/websocket/server/.prettierrc create mode 100644 Web/WebSocket/websocket/server/eslint.config.ts create mode 100644 Web/WebSocket/websocket/server/package.json create mode 100644 Web/WebSocket/websocket/server/src/WebSocketServer.ts create mode 100644 Web/WebSocket/websocket/server/src/lang/Assert.ts create mode 100644 Web/WebSocket/websocket/server/tsconfig.json diff --git a/Web/WebSocket/websocket/server/.npmrc b/Web/WebSocket/websocket/server/.npmrc new file mode 100644 index 0000000..4fef437 --- /dev/null +++ b/Web/WebSocket/websocket/server/.npmrc @@ -0,0 +1,2 @@ +save-exact=true +package-lock=false diff --git a/Web/WebSocket/websocket/server/.nvmrc b/Web/WebSocket/websocket/server/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/Web/WebSocket/websocket/server/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/Web/WebSocket/websocket/server/.prettierrc b/Web/WebSocket/websocket/server/.prettierrc new file mode 100644 index 0000000..caa814d --- /dev/null +++ b/Web/WebSocket/websocket/server/.prettierrc @@ -0,0 +1,12 @@ +{ + "arrowParens": "avoid", + "bracketSameLine": true, + "bracketSpacing": false, + "printWidth": 160, + "semi": true, + "singleAttributePerLine": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false +} diff --git a/Web/WebSocket/websocket/server/eslint.config.ts b/Web/WebSocket/websocket/server/eslint.config.ts new file mode 100644 index 0000000..900f136 --- /dev/null +++ b/Web/WebSocket/websocket/server/eslint.config.ts @@ -0,0 +1,15 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; +import json from '@eslint/json'; +import markdown from '@eslint/markdown'; +import css from '@eslint/css'; +import {defineConfig} from 'eslint/config'; + +export default defineConfig([ + {files: ['**/*.{js,mjs,cjs,ts,mts,cts}'], plugins: {js}, extends: ['js/recommended'], languageOptions: {globals: globals.node}}, + tseslint.configs.recommended, + {files: ['**/*.json'], plugins: {json}, language: 'json/json', extends: ['json/recommended']}, + {files: ['**/*.md'], plugins: {markdown}, language: 'markdown/commonmark', extends: ['markdown/recommended']}, + {files: ['**/*.css'], plugins: {css}, language: 'css/css', extends: ['css/recommended']} +]); diff --git a/Web/WebSocket/websocket/server/package.json b/Web/WebSocket/websocket/server/package.json new file mode 100644 index 0000000..1834682 --- /dev/null +++ b/Web/WebSocket/websocket/server/package.json @@ -0,0 +1,31 @@ +{ + "name": "@techniker-me/websocket-server", + "version": "0.0.0", + "type": "module", + "scripts": { + "format": "prettier --write .", + "lint": "eslint --max-warnings 0 .", + "prelint:fix": "npm run format", + "lint:fix": "eslint --fix .", + "dev": "tsx watch --clear-screen=false", + "typecheck": "tsc" + }, + "author": "Alexander Zinn", + "license": "ISC", + "description": "", + "devDependencies": { + "@eslint/css": "0.11.1", + "@eslint/js": "9.36.0", + "@eslint/json": "0.13.2", + "@eslint/markdown": "7.3.0", + "@types/node": "24.5.2", + "eslint": "9.36.0", + "globals": "16.4.0", + "jiti": "2.6.0", + "nodemon": "3.1.10", + "prettier": "3.6.2", + "tsx": "4.20.6", + "typescript": "5.9.2", + "typescript-eslint": "8.44.1" + } +} diff --git a/Web/WebSocket/websocket/server/src/WebSocketServer.ts b/Web/WebSocket/websocket/server/src/WebSocketServer.ts new file mode 100644 index 0000000..c0bf704 --- /dev/null +++ b/Web/WebSocket/websocket/server/src/WebSocketServer.ts @@ -0,0 +1 @@ +export default class WebSocketServer {} diff --git a/Web/WebSocket/websocket/server/src/lang/Assert.ts b/Web/WebSocket/websocket/server/src/lang/Assert.ts new file mode 100644 index 0000000..c36b5a0 --- /dev/null +++ b/Web/WebSocket/websocket/server/src/lang/Assert.ts @@ -0,0 +1,111 @@ +export default class Assert { + public static isUndefined(name: string, value: unknown): asserts value is undefined { + if (value !== undefined) { + throw new Error(`[${name}] must be undefined instead received [${typeof value}]`); + } + } + + public static isNull(name: string, value: unknown): asserts value is null { + if (value !== null) { + throw new Error(`[${name}] must be null instead received [${typeof value}]`); + } + } + + public static isDefined(name: string, value: unknown): asserts value is undefined | null { + if (value === undefined || value === null) { + throw new Error(`[${name}] must be defined instead received [${typeof value}]`); + } + } + + public static isBoolean(name: string, value: unknown): asserts value is boolean { + if (!Assert._isBoolean(value)) { + throw new Error(`[${name}] must be a boolean instead received [${typeof value}]`); + } + } + + public static isTrue(name: string, value: unknown): asserts value is true { + Assert.isBoolean(name, value); + + if (!value) { + throw new Error(`[${name}] must be true`); + } + } + + public static isString(name: string, value: unknown): asserts value is string { + if (!Assert._isString(value)) { + throw new Error(`[${name}] must be a string instead received [${typeof value}]`); + } + } + + public static isNonEmptyString(name: string, value: unknown): asserts value is string { + if (!Assert._isNonEmptyString(value)) { + throw new Error(`[${name}] must be a non-empty string instead received [${typeof value}]`); + } + } + + public static isNumber(name: string, value: unknown): asserts value is number { + if (!Assert._isNumber(value)) { + throw new Error(`[${name}] must be a number instead received [${typeof value}]`); + } + } + + public static isInteger(name: string, value: unknown): asserts value is number { + Assert.isNumber(name, value); + + if (!Number.isInteger(value)) { + throw new Error(`[${name}] must be an integer, received [${value}]`); + } + } + + public static isPositiveNumber(name: string, value: unknown): asserts value is number { + if (!Assert._isNumberPositive(value)) { + throw new Error(`[${name}] must be a positive number instead received [${typeof value}]`); + } + } + + public static isNumberInRange(name: string, lowerBound: number, upperBound: number, value: unknown): asserts value is number { + if (upperBound < lowerBound) { + throw new Error(`Invalid Range: [${name}] bounds are invalid, lower bound [${lowerBound}] must be less than upper bound [${upperBound}]`); + } + + if (!(Assert._isNumber(value) && Assert._isNumberInRange(value, lowerBound, upperBound))) { + throw new Error(`[${name}] must have a value between [${lowerBound}] and [${upperBound}] instead received [${value}]`); + } + } + + public static isObject(name: string, value: unknown): asserts value is T { + if (value === null || typeof value !== 'object') { + throw new Error(`[${name}] must be an object, instead received [${typeof value}]`); + } + } + + public static isEnumMember(name: string, enumObj: T, value: unknown): asserts value is T[keyof T] { + if (!Object.values(enumObj).includes(value as T[keyof T])) { + throw new Error(`[${name}] is not a member of the enum`); + } + } + + private static _isBoolean(value: unknown): value is boolean { + return typeof value === 'boolean'; + } + + private static _isString(value: unknown): value is string { + return typeof value === 'string'; + } + + private static _isNonEmptyString(value: unknown): value is string { + return Assert._isString(value) && value.length > 0; + } + + private static _isNumber(value: unknown): value is number { + return typeof value === 'number'; + } + + private static _isNumberPositive(value: unknown): value is number { + return Assert._isNumber(value) && value > 0; + } + + private static _isNumberInRange(value: unknown, lowerBound: number, upperBound: number): value is number { + return Assert._isNumber(value) && value >= lowerBound && value <= upperBound; + } +} diff --git a/Web/WebSocket/websocket/server/tsconfig.json b/Web/WebSocket/websocket/server/tsconfig.json new file mode 100644 index 0000000..82aefac --- /dev/null +++ b/Web/WebSocket/websocket/server/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "esnext", + "moduleDetection": "force", + "module": "Preserve", + "resolveJsonModule": true, + "allowJs": false, + "esModuleInterop": true, + "isolatedModules": true, + "strict": true, + "noEmit": true + } +}