Compare commits

...

4 Commits

10 changed files with 274 additions and 63 deletions

View File

@ -1,11 +0,0 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 80,
"tabWidth": 2,
"arrowParens": "always",
"bracketSpacing": true,
"endOfLine": "lf"
}

View File

@ -8,8 +8,10 @@
"@maxmorozoff/try-catch-tuple": "^0.1.2", "@maxmorozoff/try-catch-tuple": "^0.1.2",
"@maxmorozoff/try-catch-tuple-ts-plugin": "^0.0.1", "@maxmorozoff/try-catch-tuple-ts-plugin": "^0.0.1",
"@types/bun": "latest", "@types/bun": "latest",
"dprint": "^0.50.0",
"eslint": "^9.27.0", "eslint": "^9.27.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-fp": "^2.3.0",
"globals": "^16.1.0", "globals": "^16.1.0",
"ts-patch": "^3.3.0", "ts-patch": "^3.3.0",
"typescript-eslint": "^8.32.1", "typescript-eslint": "^8.32.1",
@ -20,6 +22,24 @@
}, },
}, },
"packages": { "packages": {
"@dprint/darwin-arm64": ["@dprint/darwin-arm64@0.50.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-KqWpsvm4JveYdKDLSLlQINGNW4pEAGHcTFPEHR5qXMYV4pPomLgHHPyBrxe3XdGtlUp4I8HfvBMBw3b/LKd06A=="],
"@dprint/darwin-x64": ["@dprint/darwin-x64@0.50.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-kFeeLYhCIVAe1SMtFYk1q0qWxrkmW8FhOBTUh2oblr4AnAjpjb03m8BVUrHHKFeBTsppwck+1b8hzU6LRZO7fA=="],
"@dprint/linux-arm64-glibc": ["@dprint/linux-arm64-glibc@0.50.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EL0+uMSdj/n+cZOP9ZO8ndvjmtOSWXNsMHKdAAaTG0+EjH9M9YKXD6kopP6PKOR5pJuiyHCRpVKJ4xoD4adfpQ=="],
"@dprint/linux-arm64-musl": ["@dprint/linux-arm64-musl@0.50.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-bzyYxKtFw/hYAA+7lWQGQGo2YFPnH7Ql9uWxxWqiGaWVPU66K9WQt0RUEqu1hQBrCk9mMz3jx5l4oKWQ/Dc0fw=="],
"@dprint/linux-riscv64-glibc": ["@dprint/linux-riscv64-glibc@0.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-ElFqmKs96NyVXWqd2SJGJGtyVmUWNiLUyaImEzL7XZRmpoJG+Ky7SryhccMQU0ENtQmY0CVgZipLZ1SqhIoluA=="],
"@dprint/linux-x64-glibc": ["@dprint/linux-x64-glibc@0.50.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Kim8TtCdpCQUNqF2D96vunuonYy6tPfp/AQblSVA4ADChVyFLGfPaQIECpGAAKxXnIG2SX5JRQP7nB/4JgPNbA=="],
"@dprint/linux-x64-musl": ["@dprint/linux-x64-musl@0.50.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ChZf0BnS3S6BIfqAPgQKqEh/7vgD1xc0MpcFcTrvkVQHuSdCQu1XiqUN12agzxB+Y5Ml9exgzP8lYgNza7iXvw=="],
"@dprint/win32-arm64": ["@dprint/win32-arm64@0.50.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xSY607bRyIPG7UO3uRa5c5wTGHKJqLUkQst85Hcz89EL/It6wswwUSNcywDydssN99HmSHop4fIf6FJTEpEp2g=="],
"@dprint/win32-x64": ["@dprint/win32-x64@0.50.0", "", { "os": "win32", "cpu": "x64" }, "sha512-uGDjrK88LOet9a8pPRM9nKins93mK2NLozqL/hCNV88Nu5Nk0bBeVwRMAnPapjV3Jo+hsJOeq3Z1ibrq2c3v8w=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
@ -110,18 +130,26 @@
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"create-eslint-index": ["create-eslint-index@1.0.0", "", { "dependencies": { "lodash.get": "^4.3.0" } }, "sha512-nXvJjnfDytOOaPOonX0h0a1ggMoqrhdekGeZkD6hkcWYvlCWhU719tKFVh8eU04CnMwu3uwe1JjwuUF2C3k2qg=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"dprint": ["dprint@0.50.0", "", { "optionalDependencies": { "@dprint/darwin-arm64": "0.50.0", "@dprint/darwin-x64": "0.50.0", "@dprint/linux-arm64-glibc": "0.50.0", "@dprint/linux-arm64-musl": "0.50.0", "@dprint/linux-riscv64-glibc": "0.50.0", "@dprint/linux-x64-glibc": "0.50.0", "@dprint/linux-x64-musl": "0.50.0", "@dprint/win32-arm64": "0.50.0", "@dprint/win32-x64": "0.50.0" }, "bin": { "dprint": "bin.js" } }, "sha512-aNJhOQsUS5D9k/YkMUaLLniIpxEBUR0ZwT0RXGQV5YpaGwE2nx6FcKuVkC6wRaZXTr8X0NpV/2HFbcvNuI2jtA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.27.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.27.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q=="], "eslint": ["eslint@9.27.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.27.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q=="],
"eslint-ast-utils": ["eslint-ast-utils@1.1.0", "", { "dependencies": { "lodash.get": "^4.4.2", "lodash.zip": "^4.2.0" } }, "sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA=="],
"eslint-config-prettier": ["eslint-config-prettier@10.1.5", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw=="], "eslint-config-prettier": ["eslint-config-prettier@10.1.5", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw=="],
"eslint-plugin-fp": ["eslint-plugin-fp@2.3.0", "", { "dependencies": { "create-eslint-index": "^1.0.0", "eslint-ast-utils": "^1.0.0", "lodash": "^4.13.1", "req-all": "^0.1.0" }, "peerDependencies": { "eslint": ">=3" } }, "sha512-3n2oHibwoIxAht9/+ZaTldhI6brXORgl8oNXqZd+d9xuAQt2SBJ2/aml0oQRMWvXrgsz2WG6wfC++NjzSG3prA=="],
"eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="], "eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="],
@ -204,8 +232,14 @@
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"lodash.zip": ["lodash.zip@4.2.0", "", {}, "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
@ -240,6 +274,8 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"req-all": ["req-all@0.1.0", "", {}, "sha512-ZdvPr8uXy9ujX3KujwE2P1HWkMYgogIhqeAeyb47MqWjSfyxERSm0TNbN/IapCCmWDufXab04AYrRgObaJCJ6Q=="],
"resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],

56
dprint.json Normal file
View File

@ -0,0 +1,56 @@
{
"typescript": {
"lineWidth": 70,
"indentWidth": 2,
"useTabs": false,
"semiColons": "asi",
"quoteStyle": "alwaysSingle",
"trailingCommas": "onlyMultiLine",
"operatorPosition": "nextLine",
"arrowFunction.useParentheses": "preferNone",
"binaryExpression.linePerExpression": false,
"memberExpression.linePerExpression": false,
"bracePosition": "sameLineUnlessHanging",
"spaceSurroundingProperties": false,
"objectExpression.spaceSurroundingProperties": false,
"objectPattern.spaceSurroundingProperties": false,
"typeLiteral.spaceSurroundingProperties": false,
"functionDeclaration.spaceBeforeParentheses": false,
"method.spaceBeforeParentheses": false,
"constructor.spaceBeforeParentheses": false,
"typeAnnotation.spaceBeforeColon": false,
"jsx.quoteStyle": "preferSingle",
"jsxSelfClosingElement.spaceBeforeSlash": false,
"useBraces": "whenNotSingleLine",
"preferHanging": false,
"conditionalExpression.linePerExpression": false,
"arguments.preferHanging": "never",
"arguments.spaceAround": false,
"parameters.spaceAround": false,
"parameters.trailingCommas": "onlyMultiLine",
"parameters.preferSingleLine": true,
"parameters.preferHanging": "onlySingleItem",
"typeLiteral.separatorKind": "comma",
"parentheses.preferSingleLine": true
},
"json": {},
"markdown": {},
"toml": {},
"malva": {},
"markup": {},
"yaml": {},
"excludes": ["**/node_modules", "**/*-lock.json"],
"plugins": [
"https://plugins.dprint.dev/typescript-0.95.4.wasm",
"https://plugins.dprint.dev/json-0.20.0.wasm",
"https://plugins.dprint.dev/markdown-0.18.0.wasm",
"https://plugins.dprint.dev/toml-0.7.0.wasm",
"https://plugins.dprint.dev/g-plane/malva-v0.12.1.wasm",
"https://plugins.dprint.dev/g-plane/markup_fmt-v0.20.0.wasm",
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm"
]
}

View File

@ -1,17 +1,21 @@
import js from "@eslint/js"; import fp from 'eslint-plugin-fp';
import globals from "globals"; import js from '@eslint/js';
import tseslint from "typescript-eslint"; import globals from 'globals';
import { defineConfig } from "eslint/config"; import tseslint from 'typescript-eslint';
import eslintConfigPrettier from "eslint-config-prettier/flat"; import { defineConfig } from 'eslint/config';
import eslintConfigPrettier from 'eslint-config-prettier/flat';
export default defineConfig([ export default defineConfig([
{ {
files: ["**/*.{js,mjs,cjs,ts}"], files: ['**/*.{js,mjs,cjs,ts}'],
plugins: { js }, plugins: { js, fp },
extends: ["js/recommended"], extends: ['js/recommended'],
rules: {
'fp/no-mutation': 'error',
},
}, },
{ {
files: ["**/*.{js,mjs,cjs,ts}"], files: ['**/*.{js,mjs,cjs,ts}'],
languageOptions: { globals: globals.browser }, languageOptions: { globals: globals.browser },
}, },
tseslint.configs.recommended, tseslint.configs.recommended,

View File

@ -8,8 +8,10 @@
"@maxmorozoff/try-catch-tuple": "^0.1.2", "@maxmorozoff/try-catch-tuple": "^0.1.2",
"@maxmorozoff/try-catch-tuple-ts-plugin": "^0.0.1", "@maxmorozoff/try-catch-tuple-ts-plugin": "^0.0.1",
"@types/bun": "latest", "@types/bun": "latest",
"dprint": "^0.50.0",
"eslint": "^9.27.0", "eslint": "^9.27.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-fp": "^2.3.0",
"globals": "^16.1.0", "globals": "^16.1.0",
"ts-patch": "^3.3.0", "ts-patch": "^3.3.0",
"typescript-eslint": "^8.32.1" "typescript-eslint": "^8.32.1"

View File

@ -1,47 +1,63 @@
import { tryCatch } from '@maxmorozoff/try-catch-tuple'; import { type CursorPos } from 'node:readline'
import type { CursorPosition } from '../util/terminal';
const setInitialEnd = (pos: { // Cursor stuffs
origin: CursorPosition; interface CursorPosX {
end?: CursorPosition; readonly _tag: 'X'
lines?: number; readonly value: number
}) => { }
if (!pos.end || !pos.lines)
throw TypeError("One of 'end' or 'lines' must be set");
if (Object.keys(pos).includes('end') || Object.keys(pos).includes('end'))
throw TypeError("Cannot set both 'end' and 'lines'");
if (pos.end) return pos.end;
return {
row: pos.origin.row + pos.lines,
col: pos.origin.col,
};
};
export const createCanvas = ( interface CursorPosY {
pos: { origin: CursorPosition; end?: CursorPosition; lines?: number }, readonly _tag: 'Y'
paint: () => Promise<number>, readonly value: number
cleanup?: () => Promise<number> }
) => {
let currentOrigin = pos.origin;
let currentEnd; const cursorPosX = (x: number): CursorPosX => ({_tag: 'X', value: x})
const [endVal, endError] = tryCatch(() => setInitialEnd(pos));
if (endError) throw endError;
currentEnd = endVal;
paint(); const cursorPosY = (x: number): CursorPosY => ({_tag: 'Y', value: x})
//
// Paint function type IsCursorPos =
// (x: 'X' | 'Y') => (y: CursorPosX | CursorPosY) => boolean
// Restore origin position const isCursorPos: IsCursorPos = x => y => y._tag === x
// Clear to cursor end position
// // Tagged types
// API interface CanvasOrigin {
// --- readonly _tag: 'Origin'
// get origin readonly value: CursorPos
// get end }
// move end
// get line count interface CanvasEnd {
// clear canvas readonly _tag: 'End'
return [1]; readonly value: CursorPos
}; }
// Canvas type using tagged positions
type Canvas = {
origin: CanvasOrigin,
end: CanvasEnd,
}
// Cursor Position
// const cursorPos: CursorPos = ()
// Constructor helpers
const origin = (pos: CursorPos): CanvasOrigin => ({
_tag: 'Origin',
value: pos,
})
const end = (pos: CursorPos): CanvasEnd => ({
_tag: 'End',
value: pos,
})
// Curried canvas creator with type safety
const canvas =
(origin: CanvasOrigin) => (end: CanvasEnd): Canvas => ({
origin,
end,
})
// Usage with proper type safety
const myCanvas = canvas(origin({rows: 3, cols: 1}))(
end({rows: 8, cols: 1}),
)

View File

@ -0,0 +1,28 @@
export type Left<E> = {readonly _tag: 'Left', readonly left: E}
export type Right<A> = {readonly _tag: 'Right', readonly right: A}
export type Either<E, A> = Left<E> | Right<A>
// Constructors
export const left = <E>(e: E): Either<E, never> => ({
_tag: 'Left',
left: e,
})
export const right = <A>(a: A): Either<never, A> => ({
_tag: 'Right',
right: a,
})
// Operations
export const eitherMap =
<E, A, B>(f: (a: A) => B) => (fa: Either<E, A>): Either<E, B> =>
fa._tag === 'Right' ? right(f(fa.right)) : fa
export const eitherChain =
<E, A, B>(f: (a: A) => Either<E, B>) =>
(fa: Either<E, A>): Either<E, B> =>
fa._tag === 'Right' ? f(fa.right) : fa
export const fold =
<E, A, B>(onLeft: (e: E) => B, onRight: (a: A) => B) =>
(fa: Either<E, A>): B =>
fa._tag === 'Left' ? onLeft(fa.left) : onRight(fa.right)

View File

@ -0,0 +1,36 @@
export type Nil = { readonly _tag: 'Nil' };
export type Cons<A> = {
readonly _tag: 'Cons';
readonly head: A;
readonly tail: List<A>;
};
export type List<A> = Nil | Cons<A>;
// Constructors
export const nil: Nil = { _tag: 'Nil' };
export const cons = <A>(head: A, tail: List<A>): List<A> => ({
_tag: 'Cons',
head,
tail,
});
// Operations
type ListMap = <A, B>(f: (a: A) => B) => (fa: List<A>) => List<B>;
export const listMap: ListMap = (f) => (fa) =>
fa._tag === 'Cons' ? cons(f(fa.head), listMap(f)(fa.tail)) : nil;
type ListReduce = <A, B>(
f: (b: B, a: A) => B,
initial: B
) => (fa: List<A>) => B;
export const listReduce: ListReduce = (f, initial) => (fa) =>
fa._tag === 'Cons' ? listReduce(f, f(initial, fa.head))(fa.tail) : initial;
// Helpers
type FromArray = <A>(arr: Array<A>) => List<A>;
export const fromArray: FromArray = <A>(arr: Array<A>) =>
arr.reduceRight((acc: List<A>, val: A) => cons(val, acc), nil as List<A>);
type ToArray = <A>(fa: List<A>) => Array<A>;
export const toArray: ToArray = <A>(fa: List<A>) =>
listReduce<A, Array<A>>((acc, val) => [...acc, val], [] as Array<A>)(fa);

View File

@ -0,0 +1,22 @@
export type None = {readonly _tag: 'None'}
export type Some<A> = {readonly _tag: 'Some', readonly value: A}
export type Option<A> = Some<A> | None
// Constructors
export const none: Option<never> = {_tag: 'None'}
export const some = <A>(value: A): Option<A> => ({
_tag: 'Some',
value,
})
// Operations
export const map =
<A, B>(f: (a: A) => B) => (fa: Option<A>): Option<B> =>
fa._tag === 'Some' ? some(f(fa.value)) : none
export const chain =
<A, B>(f: (a: A) => Option<B>) => (fa: Option<A>): Option<B> =>
fa._tag === 'Some' ? f(fa.value) : none
export const getOrElse = <A>(defaultValue: A) => (fa: Option<A>): A =>
fa._tag === 'Some' ? fa.value : defaultValue

View File

@ -0,0 +1,22 @@
import { type Either, left, right } from './either'
import { none, type Option, some } from './option'
// Pipe function for composition
export const pipe = <A, B, C>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
): C => bc(ab(a))
// TryCatch helper using Either
export const tryCatch = <A>(f: () => A): Either<Error, A> => {
try {
return right(f())
} catch (e) {
return left(e instanceof Error ? e : new Error(String(e)))
}
}
// Option from nullable
export const fromNullable = <A>(a: A | null | undefined): Option<A> =>
a == null ? none : some(a)