使用 ReScript 开发
ReScript 是一门健壮的类型化语言,可以编译成高效易读的 JavaScript。相比于 TypeScript,ReScript 是 JavaScript 的子集,有着远比 TypeScript 更为严格和安全的类型系统。也是 OCaml 的方言之一,结合了大量函数式编程与现代化编程特性,同时保留了 C 系语言的花括号语法风格,这使你不会像面对其它函数式编程一样对其陌生语法感到茫然,变得极易上手和入门。如果你是一名 Rust 开发者将会对 ReScript 很多地方感到亲切(就像是没有所有权和生命周期的 Rust)。
NOTE
详细信息与入门指南请参考 The ReScript Programming Language。
基本使用
Kotori 从 v1.7 开始支持用 ReScript 编写插件,尽管这并非强制性,但如若你对函数式编程感兴趣或者对安全性有要求,那么使用 ReScript 编写 Kotori 插件将是不二之举。
ReScript 模块的 package.json
会有所不同:
json
{
"name": "kotori-plugin-my-project-res",
"version": "1.0.0",
"description": "a kotori project kotori project by rescript",
"main": "src/Main.res.js",
"scripts": {
"res:build": "rescript",
"res:clean": "rescript clean",
"res:dev": "rescript -w"
},
"keywords": [
"kotori",
"chatbot",
"kotori-plugin",
"rescript"
],
"license": "BAN-ZHINESE-USING",
"files": [
"src",
"LICENSE",
"README.md"
],
"author": "Himeno",
"peerDependencies": {
"kotori-bot": "^1.7.1"
},
"dependencies": {
"rescript-kotori": "^1.0.0",
"rescript": "11.1.4",
"@rescript/core": "^1.6.1"
}
}
此外,模块根目录(并非工作区)的 rescript.json
也是必要的:
json
{
"$schema": "./node_modules/rescript/docs/docson/build-schema.json",
"name": "kotori-plugin-res-test",
"sources": {
"dir": "src",
"subdirs": true
},
"package-specs": {
"module": "commonjs",
"in-source": true
},
"suffix": ".res.js",
"bs-dependencies": [
"@rescript/core",
"rescript-kotori"
],
"bsc-flags": [
"-open RescriptCore"
],
"jsx": {
"module": "KotoriMsg"
}
}
基本示例
res
open Kotori
open Msg
open Session
open Ctx
let inject = ["browser"]
@scope("logger") @send external logger: (context, 'a) => unit = "debug"
@send external task: (context, string, unit => unit) => unit = "task"
type config = {
times: int,
duration: int,
steps: int,
minNum: int,
maxNum: int,
}
let config =
[
("times", Tsu.int()->Tsu.default(7)),
("duration", Tsu.int()->Tsu.default(180)),
("steps", Tsu.int()->Tsu.default(3)),
("minNum", Tsu.int()->Tsu.default(1)),
("maxNum", Tsu.int()->Tsu.default(10)),
]
->Dict.fromArray
->Tsu.object
let main = (ctx: context, config: config) => {
ctx->on(
#ready(
() => {
ctx->logger(config)
},
),
)
ctx
->Cmd.make("greet - get a greeting")
->Cmd.action_async(async (_, session) => {
let res =
await ctx->Http.get("https://api.hotaru.icu/ial/hitokoto/v2/?format=text", Js.Undefined)
<Text>
{switch res->Type.typeof {
| #string => session->format("Greet: \n{0}", [res->Kotori.Utils.toAny])
| _ => "Sorry, I cannot get a greeting right now."
}}
</Text>
})
->Cmd.help("Get a greeting from hotaru.icu")
->Cmd.scope(#all)
->Cmd.alias(["hi", "hey", "hello"])
->ignore
ctx
->Cmd.make("res [saying=functional]")
->Cmd.action_async(async ({args}, session) => {
let userId = switch session.userId {
| Some(userId) => userId
| None => "Unknown"
}
<Seg>
<Text> {"Hello "} </Text>
<Mention userId />
<Br />
<Text>
{switch args {
| [String(saying)] => session->format("Greet: \n{0}", [saying])
| _ => "Sorry, I cannot get a greeting right now."
}}
</Text>
<Seg>
<Text> {"he is a example image"} </Text>
<Image src="https://i.imgur.com/y5y5y5.png" />
</Seg>
</Seg>
})
->ignore
ctx
->on(
#on_group_increase(
async session => {
switch session.userId {
| Some(userId) if userId !== session.api.adapter.selfId =>
session
->quick(
<Seg>
<Text> {"welcome to here!"} </Text>
<Mention userId />
</Seg>,
)
->ignore
| _ => ()
}
},
),
)
->ignore
ctx
->task("0/10 * * * * *", () => {
ctx->logger("hi! this message is from rescript plugin!")
})
->ignore
}
TIP
ReScript 与 React 均由 Facebook 开发,因此它天然支持 JSX 语法。
NOTE
Kotori 提供的 ReScript 相关 API 请参考 接口文档。