beginnings: rendering text to message

This commit is contained in:
MapleLeaf
2021-12-08 14:12:26 -06:00
parent c0aa4ee108
commit 57d55fe58f
17 changed files with 516 additions and 27 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@ dist
node_modules
.vscode
coverage
.env

View File

@@ -23,14 +23,26 @@
"author": "itsMapleLeaf",
"license": "MIT",
"dependencies": {
"match-sorter": "^6.3.1"
"@types/node": "*",
"@types/react": "*",
"@types/react-reconciler": "^0.26.4",
"react-reconciler": "^0.26.2"
},
"peerDependencies": {
"@types/scheduler": "^0.16.2",
"discord.js": "^13.3",
"react": "^17.0.2",
"scheduler": "^0.20.2"
},
"devDependencies": {
"@itsmapleleaf/configs": "^1.0.4",
"@types/scheduler": "^0.16.2",
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0",
"ava": "^4.0.0-rc.1",
"c8": "^7.10.0",
"discord.js": "^13.3.1",
"dotenv": "^10.0.0",
"esbuild-node-loader": "^0.6.3",
"eslint": "^8.4.1",
"eslint-config-prettier": "^8.3.0",
@@ -39,8 +51,11 @@
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.3.0",
"nanoid": "^3.1.30",
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1",
"react": "^17.0.2",
"scheduler": "^0.20.2",
"tsup": "^5.10.3",
"typescript": "^4.5.2"
},

288
pnpm-lock.yaml generated
View File

@@ -2,10 +2,16 @@ lockfileVersion: 5.3
specifiers:
'@itsmapleleaf/configs': ^1.0.4
'@types/node': '*'
'@types/react': '*'
'@types/react-reconciler': ^0.26.4
'@types/scheduler': ^0.16.2
'@typescript-eslint/eslint-plugin': ^5.6.0
'@typescript-eslint/parser': ^5.6.0
ava: ^4.0.0-rc.1
c8: ^7.10.0
discord.js: ^13.3.1
dotenv: ^10.0.0
esbuild-node-loader: ^0.6.3
eslint: ^8.4.1
eslint-config-prettier: ^8.3.0
@@ -14,21 +20,30 @@ specifiers:
eslint-plugin-jsx-a11y: ^6.5.1
eslint-plugin-react: ^7.27.1
eslint-plugin-react-hooks: ^4.3.0
match-sorter: ^6.3.1
nanoid: ^3.1.30
npm-run-all: ^4.1.5
prettier: ^2.5.1
react: ^17.0.2
react-reconciler: ^0.26.2
scheduler: ^0.20.2
tsup: ^5.10.3
typescript: ^4.5.2
dependencies:
match-sorter: 6.3.1
'@types/node': 16.11.12
'@types/react': 17.0.37
'@types/react-reconciler': 0.26.4
react-reconciler: 0.26.2_react@17.0.2
devDependencies:
'@itsmapleleaf/configs': 1.0.4
'@types/scheduler': 0.16.2
'@typescript-eslint/eslint-plugin': 5.6.0_16d83f5c41c3abb1061a82b07c18e4f3
'@typescript-eslint/parser': 5.6.0_eslint@8.4.1+typescript@4.5.2
ava: 4.0.0-rc.1
c8: 7.10.0
discord.js: 13.3.1
dotenv: 10.0.0
esbuild-node-loader: 0.6.3_typescript@4.5.2
eslint: 8.4.1
eslint-config-prettier: 8.3.0_eslint@8.4.1
@@ -37,8 +52,11 @@ devDependencies:
eslint-plugin-jsx-a11y: 6.5.1_eslint@8.4.1
eslint-plugin-react: 7.27.1_eslint@8.4.1
eslint-plugin-react-hooks: 4.3.0_eslint@8.4.1
nanoid: 3.1.30
npm-run-all: 4.1.5
prettier: 2.5.1
react: 17.0.2
scheduler: 0.20.2
tsup: 5.10.3_typescript@4.5.2
typescript: 4.5.2
@@ -57,11 +75,37 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.9
dev: true
/@bcoe/v8-coverage/0.2.3:
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
dev: true
/@discordjs/builders/0.8.2:
resolution: {integrity: sha512-/YRd11SrcluqXkKppq/FAVzLIPRVlIVmc6X8ZklspzMIHDtJ+A4W37D43SHvLdH//+NnK+SHW/WeOF4Ts54PeQ==}
engines: {node: '>=16.0.0', npm: '>=7.0.0'}
dependencies:
'@sindresorhus/is': 4.2.0
discord-api-types: 0.24.0
ow: 0.27.0
ts-mixer: 6.0.0
tslib: 2.3.1
dev: true
/@discordjs/collection/0.3.2:
resolution: {integrity: sha512-dMjLl60b2DMqObbH1MQZKePgWhsNe49XkKBZ0W5Acl5uVV43SN414i2QfZwRI7dXAqIn8pEWD2+XXQFn9KWxqg==}
engines: {node: '>=16.0.0', npm: '>=7.0.0'}
dev: true
/@discordjs/form-data/3.0.1:
resolution: {integrity: sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.34
dev: true
/@eslint/eslintrc/1.0.5:
resolution: {integrity: sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -145,6 +189,16 @@ packages:
fastq: 1.13.0
dev: true
/@sapphire/async-queue/1.1.9:
resolution: {integrity: sha512-CbXaGwwlEMq+l1TRu01FJCvySJ1CEFKFclHT48nIfNeZXaAAmmwwy7scUKmYHPUa3GhoMp6Qr1B3eAJux6XgOQ==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
dev: true
/@sindresorhus/is/4.2.0:
resolution: {integrity: sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==}
engines: {node: '>=10'}
dev: true
/@types/eslint/8.2.1:
resolution: {integrity: sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==}
dependencies:
@@ -179,8 +233,41 @@ packages:
resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
dev: true
/@types/node-fetch/2.5.12:
resolution: {integrity: sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==}
dependencies:
'@types/node': 16.11.12
form-data: 3.0.1
dev: true
/@types/node/16.11.12:
resolution: {integrity: sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==}
/@types/prop-types/15.7.4:
resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==}
dev: false
/@types/react-reconciler/0.26.4:
resolution: {integrity: sha512-bdx4aIBkQRDAnzc23JBFeZmVpmfLJHfHikmQukEt9qs4bQtq9f+PDbNwhR9u74FkIUyIDz1I1qJ8OF6RwadKpw==}
dependencies:
'@types/react': 17.0.37
dev: false
/@types/react/17.0.37:
resolution: {integrity: sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==}
dependencies:
'@types/prop-types': 15.7.4
'@types/scheduler': 0.16.2
csstype: 3.0.10
dev: false
/@types/scheduler/0.16.2:
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
/@types/ws/8.2.2:
resolution: {integrity: sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==}
dependencies:
'@types/node': 16.11.12
dev: true
/@typescript-eslint/eslint-plugin/5.6.0_16d83f5c41c3abb1061a82b07c18e4f3:
@@ -497,6 +584,10 @@ packages:
resolution: {integrity: sha1-9wtzXGvKGlycItmCw+Oef+ujva0=}
dev: true
/asynckit/0.4.0:
resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=}
dev: true
/atob/2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
engines: {node: '>= 4.5.0'}
@@ -867,6 +958,13 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/combined-stream/1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: true
/commander/4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
@@ -964,6 +1062,10 @@ packages:
which: 2.0.2
dev: true
/csstype/3.0.10:
resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==}
dev: false
/currently-unhandled/0.4.1:
resolution: {integrity: sha1-mI3zP+qxke95mmE2nddsF635V+o=}
engines: {node: '>=0.10.0'}
@@ -1064,6 +1166,11 @@ packages:
slash: 3.0.0
dev: true
/delayed-stream/1.0.0:
resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=}
engines: {node: '>=0.4.0'}
dev: true
/dir-glob/2.2.2:
resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==}
engines: {node: '>=4'}
@@ -1078,6 +1185,29 @@ packages:
path-type: 4.0.0
dev: true
/discord-api-types/0.24.0:
resolution: {integrity: sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A==}
engines: {node: '>=12'}
dev: true
/discord.js/13.3.1:
resolution: {integrity: sha512-zn4G8tL5+tMV00+0aSsVYNYcIfMSdT2g0nudKny+Ikd+XKv7m6bqI7n3Vji0GIRqXDr5ArPaw+iYFM2I1Iw3vg==}
engines: {node: '>=16.6.0', npm: '>=7.0.0'}
dependencies:
'@discordjs/builders': 0.8.2
'@discordjs/collection': 0.3.2
'@discordjs/form-data': 3.0.1
'@sapphire/async-queue': 1.1.9
'@types/node-fetch': 2.5.12
'@types/ws': 8.2.2
discord-api-types: 0.24.0
node-fetch: 2.6.6
ws: 8.3.0
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/doctrine/2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@@ -1092,6 +1222,18 @@ packages:
esutils: 2.0.3
dev: true
/dot-prop/6.0.1:
resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
engines: {node: '>=10'}
dependencies:
is-obj: 2.0.0
dev: true
/dotenv/10.0.0:
resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==}
engines: {node: '>=10'}
dev: true
/emittery/0.10.0:
resolution: {integrity: sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==}
engines: {node: '>=12'}
@@ -1794,6 +1936,15 @@ packages:
signal-exit: 3.0.6
dev: true
/form-data/3.0.1:
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.34
dev: true
/fragment-cache/0.2.1:
resolution: {integrity: sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=}
engines: {node: '>=0.10.0'}
@@ -2285,6 +2436,11 @@ packages:
engines: {node: '>=0.12.0'}
dev: true
/is-obj/2.0.0:
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
engines: {node: '>=8'}
dev: true
/is-path-cwd/2.2.0:
resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
engines: {node: '>=6'}
@@ -2421,7 +2577,6 @@ packages:
/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml/3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
@@ -2558,6 +2713,10 @@ packages:
p-locate: 6.0.0
dev: true
/lodash.isequal/4.5.0:
resolution: {integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=}
dev: true
/lodash.merge/4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
@@ -2579,7 +2738,6 @@ packages:
hasBin: true
dependencies:
js-tokens: 4.0.0
dev: true
/lru-cache/6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
@@ -2614,13 +2772,6 @@ packages:
object-visit: 1.0.1
dev: true
/match-sorter/6.3.1:
resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==}
dependencies:
'@babel/runtime': 7.16.3
remove-accents: 0.4.2
dev: false
/matcher/5.0.0:
resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2684,6 +2835,18 @@ packages:
picomatch: 2.3.0
dev: true
/mime-db/1.51.0:
resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==}
engines: {node: '>= 0.6'}
dev: true
/mime-types/2.1.34:
resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.51.0
dev: true
/mimic-fn/2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
@@ -2732,6 +2895,12 @@ packages:
thenify-all: 1.6.0
dev: true
/nanoid/3.1.30:
resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: true
/nanomatch/1.2.13:
resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
engines: {node: '>=0.10.0'}
@@ -2761,6 +2930,13 @@ packages:
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
dev: true
/node-fetch/2.6.6:
resolution: {integrity: sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==}
engines: {node: 4.x || >=6.0.0}
dependencies:
whatwg-url: 5.0.0
dev: true
/nofilter/3.1.0:
resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==}
engines: {node: '>=12.19'}
@@ -2813,7 +2989,6 @@ packages:
/object-assign/4.1.1:
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
engines: {node: '>=0.10.0'}
dev: true
/object-copy/0.1.0:
resolution: {integrity: sha1-fn2Fi3gb18mRpBupde04EnVOmYw=}
@@ -2938,6 +3113,18 @@ packages:
wcwidth: 1.0.1
dev: true
/ow/0.27.0:
resolution: {integrity: sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==}
engines: {node: '>=12'}
dependencies:
'@sindresorhus/is': 4.2.0
callsites: 3.1.0
dot-prop: 6.0.1
lodash.isequal: 4.5.0
type-fest: 1.4.0
vali-date: 1.0.0
dev: true
/p-all/2.1.0:
resolution: {integrity: sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==}
engines: {node: '>=6'}
@@ -3240,6 +3427,26 @@ packages:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
/react-reconciler/0.26.2_react@17.0.2:
resolution: {integrity: sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==}
engines: {node: '>=0.10.0'}
peerDependencies:
react: ^17.0.2
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react: 17.0.2
scheduler: 0.20.2
dev: false
/react/17.0.2:
resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
engines: {node: '>=0.10.0'}
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
dev: true
/read-pkg/3.0.0:
resolution: {integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=}
engines: {node: '>=4'}
@@ -3267,6 +3474,7 @@ packages:
/regenerator-runtime/0.13.9:
resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
dev: true
/regex-not/1.0.2:
resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==}
@@ -3289,10 +3497,6 @@ packages:
engines: {node: '>=8'}
dev: true
/remove-accents/0.4.2:
resolution: {integrity: sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=}
dev: false
/repeat-element/1.1.4:
resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
engines: {node: '>=0.10.0'}
@@ -3397,6 +3601,12 @@ packages:
ret: 0.1.15
dev: true
/scheduler/0.20.2:
resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
/semver/5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
hasBin: true
@@ -3797,6 +4007,10 @@ packages:
safe-regex: 1.1.0
dev: true
/tr46/0.0.3:
resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=}
dev: true
/tree-kill/1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -3806,6 +4020,10 @@ packages:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
dev: true
/ts-mixer/6.0.0:
resolution: {integrity: sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==}
dev: true
/tsconfig-paths/3.12.0:
resolution: {integrity: sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==}
dependencies:
@@ -3819,6 +4037,10 @@ packages:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
/tslib/2.3.1:
resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==}
dev: true
/tsup/5.10.3_typescript@4.5.2:
resolution: {integrity: sha512-yjbup830+Ym6ahEkIrwIiy0DlY3xkfmGBcvxQLXOa2cUIwRIP8HdrEheg9E1Fthqrzf9Gus9SO1UFiz+Dz+/tQ==}
hasBin: true
@@ -3874,6 +4096,11 @@ packages:
engines: {node: '>=10'}
dev: true
/type-fest/1.4.0:
resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
engines: {node: '>=10'}
dev: true
/type-fest/2.6.0:
resolution: {integrity: sha512-XN1FDGGtaSDA6CFsCW5iolTQqFsnJ+ZF6JqSz0SqXoh4F8GY0xqUv5RYnTilpmL+sOH8OH4FX8tf9YyAPM2LDA==}
engines: {node: '>=12.20'}
@@ -3951,6 +4178,11 @@ packages:
source-map: 0.7.3
dev: true
/vali-date/1.0.0:
resolution: {integrity: sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=}
engines: {node: '>=0.10.0'}
dev: true
/validate-npm-package-license/3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
dependencies:
@@ -3964,11 +4196,22 @@ packages:
defaults: 1.0.3
dev: true
/webidl-conversions/3.0.1:
resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=}
dev: true
/well-known-symbols/2.0.0:
resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==}
engines: {node: '>=6'}
dev: true
/whatwg-url/5.0.0:
resolution: {integrity: sha1-lmRU6HZUYuN2RNNib2dCzotwll0=}
dependencies:
tr46: 0.0.3
webidl-conversions: 3.0.1
dev: true
/which-boxed-primitive/1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
@@ -4021,6 +4264,19 @@ packages:
typedarray-to-buffer: 3.1.5
dev: true
/ws/8.3.0:
resolution: {integrity: sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: true
/y18n/5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}

28
src/container.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { TextBasedChannels } from "discord.js"
import type { ReacordInstance } from "./instance.js"
export class ReacordContainer {
channel: TextBasedChannels
instances = new Set<ReacordInstance>()
constructor(channel: TextBasedChannels) {
this.channel = channel
}
add(instance: ReacordInstance) {
this.instances.add(instance)
instance.render(this.channel)
}
remove(instance: ReacordInstance) {
this.instances.delete(instance)
instance.destroy()
}
clear() {
this.instances.forEach((instance) => {
instance.destroy()
})
this.instances.clear()
}
}

5
src/helpers/raise.ts Normal file
View File

@@ -0,0 +1,5 @@
import { toError } from "./to-error.js"
export function raise(error: unknown): never {
throw toError(error)
}

View File

@@ -0,0 +1,6 @@
import { setTimeout } from "node:timers/promises"
export async function rejectAfter(timeMs: number) {
await setTimeout(timeMs)
return Promise.reject(`rejected after ${timeMs}ms`)
}

3
src/helpers/to-error.ts Normal file
View File

@@ -0,0 +1,3 @@
export function toError(value: unknown) {
return value instanceof Error ? value : new Error(String(value))
}

1
src/helpers/types.ts Normal file
View File

@@ -0,0 +1 @@
export type MaybePromise<T> = T | Promise<T>

View File

@@ -0,0 +1,10 @@
import { rejectAfter } from "./reject-after.js"
import type { MaybePromise } from "./types.js"
import { waitFor } from "./wait-for.js"
export function waitForWithTimeout(
condition: () => MaybePromise<boolean>,
timeout = 1000,
) {
return Promise.race([waitFor(condition), rejectAfter(timeout)])
}

8
src/helpers/wait-for.ts Normal file
View File

@@ -0,0 +1,8 @@
import { setTimeout } from "node:timers/promises"
import type { MaybePromise } from "./types.js"
export async function waitFor(condition: () => MaybePromise<boolean>) {
while (!(await condition())) {
await setTimeout()
}
}

25
src/instance.ts Normal file
View File

@@ -0,0 +1,25 @@
import type { Message, TextBasedChannels } from "discord.js"
export class ReacordInstance {
message?: Message
content: string
constructor(content: string) {
this.content = content
}
render(channel: TextBasedChannels) {
if (this.message) {
this.message.edit(this.content).catch(console.error)
} else {
channel.send(this.content).then((message) => {
this.message = message
}, console.error)
}
}
destroy() {
this.message?.delete().catch(console.error)
this.message?.channel.messages.cache.delete(this.message?.id)
}
}

View File

@@ -1,6 +0,0 @@
import test from "ava"
import { result } from "./main.js"
test("it is b", (t) => {
t.deepEqual(result, ["b"])
})

View File

@@ -1,4 +1 @@
/* eslint-disable import/no-unused-modules */
import { matchSorter } from "match-sorter"
export const result = matchSorter(["a", "b", "c"], "b")
export * from "./render.js"

62
src/reconciler.ts Normal file
View File

@@ -0,0 +1,62 @@
import ReactReconciler from "react-reconciler"
import type { ReacordContainer } from "./container.js"
import { ReacordInstance } from "./instance.js"
export const reconciler = ReactReconciler<
unknown,
Record<string, unknown>,
ReacordContainer,
ReacordInstance,
ReacordInstance,
unknown,
unknown,
unknown,
unknown,
unknown,
unknown,
unknown,
unknown
>({
now: Date.now,
supportsMutation: true,
isPrimaryRenderer: true,
noTimeout: -1,
supportsHydration: false,
supportsPersistence: false,
getRootHostContext: () => ({}),
getChildHostContext: () => ({}),
shouldSetTextContent: () => false,
createInstance: (
type,
props,
rootContainerInstance,
hostContext,
internalInstanceHandle,
) => {
throw new Error("Not implemented")
},
createTextInstance: (
text,
rootContainerInstance,
hostContext,
internalInstanceHandle,
) => {
return new ReacordInstance(text)
},
prepareForCommit: () => null,
resetAfterCommit: () => null,
clearContainer: (container) => {
container.clear()
},
appendChildToContainer: (container, child) => {
container.add(child)
},
removeChildFromContainer: (container, child) => {
container.remove(child)
},
})

52
src/render.test.ts Normal file
View File

@@ -0,0 +1,52 @@
import test from "ava"
import { Client, TextChannel } from "discord.js"
import { nanoid } from "nanoid"
import { testBotToken, testChannelId } from "../test/env.js"
import { raise } from "./helpers/raise.js"
import { waitForWithTimeout } from "./helpers/wait-for-with-timeout.js"
import { render } from "./render.js"
const client = new Client({
intents: ["GUILDS"],
})
let channel: TextChannel
test.before(async () => {
await client.login(testBotToken)
const result =
client.channels.cache.get(testChannelId) ??
(await client.channels.fetch(testChannelId)) ??
raise("Channel not found")
if (!(result instanceof TextChannel)) {
throw new Error("Channel must be a text channel")
}
channel = result
})
test.after(() => {
client.destroy()
})
test("rendering text", async (t) => {
const content = nanoid()
const root = render(content, channel)
await waitForWithTimeout(
() => channel.messages.cache.some((m) => m.content === content),
4000,
)
root.destroy()
await waitForWithTimeout(() => {
return channel.messages.cache
.filter((m) => !m.deleted)
.every((m) => m.content !== content)
}, 4000)
t.pass()
})

16
src/render.ts Normal file
View File

@@ -0,0 +1,16 @@
import type { TextBasedChannels } from "discord.js"
import { ReacordContainer } from "./container"
import { reconciler } from "./reconciler"
export type ReacordRenderTarget = TextBasedChannels
export function render(content: string, target: ReacordRenderTarget) {
const container = new ReacordContainer(target)
const containerId = reconciler.createContainer(container, 0, false, null)
reconciler.updateContainer(content, containerId)
return {
destroy: () => {
reconciler.updateContainer(null, containerId)
},
}
}

10
test/env.ts Normal file
View File

@@ -0,0 +1,10 @@
import "dotenv/config.js"
import { raise } from "../src/helpers/raise.js"
function getEnv(name: string) {
return process.env[name] ?? raise(`Missing environment variable: ${name}`)
}
export const testBotToken = getEnv("TEST_BOT_TOKEN")
export const testGuildId = getEnv("TEST_GUILD_ID")
export const testChannelId = getEnv("TEST_CHANNEL_ID")