|
| 1 | +# アプリに組み込む |
| 2 | + |
| 3 | +このガイドでは、既存のWebアプリにAiScriptを組み込む方法をご紹介します。 |
| 4 | + |
| 5 | +## 1. AiScriptのインストール |
| 6 | + |
| 7 | +まずは、AiScriptをインストールします。 |
| 8 | + |
| 9 | +```sh |
| 10 | +# npm |
| 11 | +npm i @syuilo/aiscript |
| 12 | + |
| 13 | +# yarn |
| 14 | +yarn add @syuilo/aiscript |
| 15 | + |
| 16 | +# pnpm |
| 17 | +pnpm add @syuilo/aiscript |
| 18 | +``` |
| 19 | + |
| 20 | +## 2. AiScriptの読み込み・設定 |
| 21 | + |
| 22 | +今回は、このようにテキストベースで渡されたAiScriptを実行するまでの手順を説明します。 |
| 23 | + |
| 24 | +```ts |
| 25 | +const program = "<: \"Hello, World!\""; |
| 26 | +``` |
| 27 | + |
| 28 | +AiScriptを読み込みます。 |
| 29 | + |
| 30 | +```ts |
| 31 | +import { Parser, Interpreter, utils } from '@syuilo/aiscript'; // [!code ++] |
| 32 | + |
| 33 | +const program = "<: \"Hello, World!\""; |
| 34 | +``` |
| 35 | + |
| 36 | +AiScriptは、まず`Parser`でASTと呼ばれるオブジェクトに変換し、その後`Interpreter`で実行します。 |
| 37 | + |
| 38 | +AiScriptを実行する際に呼び出すJavascript関数を用意しましょう。\ |
| 39 | +AiScriptインタプリタの実行は非同期で行われますので、`async function`を使用します。 |
| 40 | + |
| 41 | +```ts |
| 42 | +import { Parser, Interpreter, utils } from '@syuilo/aiscript'; |
| 43 | + |
| 44 | +const program = "<: \"Hello, World!\""; |
| 45 | + |
| 46 | +async function run() { // [!code ++] |
| 47 | + // 処理を追加していく // [!code ++] |
| 48 | +} // [!code ++] |
| 49 | +// [!code ++] |
| 50 | +run(); // [!code ++] |
| 51 | +``` |
| 52 | + |
| 53 | +次に、`Parser`と`Interpreter`を初期化します。それぞれは再使用が可能なので、関数の外で宣言しておくとよいでしょう。 |
| 54 | + |
| 55 | +```ts |
| 56 | +import { Parser, Interpreter, utils } from '@syuilo/aiscript'; |
| 57 | + |
| 58 | +const program = "<: \"Hello, World!\""; |
| 59 | + |
| 60 | +let parser: Parser; // [!code ++] |
| 61 | +let interpreter: Interpreter; // [!code ++] |
| 62 | + |
| 63 | +async function run() { |
| 64 | + parser = new Parser(); // [!code ++] |
| 65 | + interpreter = new Interpreter(); // [!code ++] |
| 66 | +} |
| 67 | + |
| 68 | +run(); |
| 69 | +``` |
| 70 | + |
| 71 | +`Interpreter`には、AiScriptにグローバル定数や関数を注入できるオプションと、入出力のためのハンドラがあります。 |
| 72 | + |
| 73 | +今回は、`Interpreter`の出力ハンドラから`console.log`を利用して、AiScriptからの出力をコンソールに表示するようにします。 |
| 74 | + |
| 75 | +AiScriptインタプリタとのやり取りでは生のJavascriptの値は使われず、すべてValueというオブジェクトを介しています。今回は簡単のために、`utils.valueToJs`を使ってValueをJavascriptの値に変換しています。 |
| 76 | + |
| 77 | +```ts |
| 78 | +import { Parser, Interpreter, utils } from '@syuilo/aiscript'; |
| 79 | + |
| 80 | +const program = "<: \"Hello, World!\""; |
| 81 | + |
| 82 | +let parser: Parser; |
| 83 | +let interpreter: Interpreter; |
| 84 | + |
| 85 | +async function run() { |
| 86 | + parser = new Parser(); |
| 87 | + interpreter = new Interpreter({}, { // ←第1引数で注入する値を指定できる // [!code ++] |
| 88 | + out: (value) => { // [!code ++] |
| 89 | + console.log(utils.valueToJs(value)); // [!code ++] |
| 90 | + }, // [!code ++] |
| 91 | + }); // [!code ++] |
| 92 | +} |
| 93 | + |
| 94 | +run(); |
| 95 | +``` |
| 96 | + |
| 97 | +これで`Parser`と`Interpreter`の準備は完了です。実際に`program`を実行してみましょう。 |
| 98 | + |
| 99 | +```ts |
| 100 | +import { Parser, Interpreter, utils } from '@syuilo/aiscript'; |
| 101 | + |
| 102 | +const program = "<: \"Hello, World!\""; |
| 103 | + |
| 104 | +let parser: Parser; |
| 105 | +let interpreter: Interpreter; |
| 106 | + |
| 107 | +async function run() { |
| 108 | + parser = new Parser(); |
| 109 | + interpreter = new Interpreter({}, { |
| 110 | + out: (value) => { |
| 111 | + console.log(utils.valueToJs(value)); |
| 112 | + }, |
| 113 | + }); |
| 114 | + |
| 115 | + const ast = parser.parse(program); // [!code ++] |
| 116 | + await interpreter.exec(ast); // [!code ++] |
| 117 | +} |
| 118 | + |
| 119 | +run(); |
| 120 | +``` |
| 121 | + |
| 122 | +お疲れ様でした!コンソールに`Hello, World!`と表示されるはずです。 |
| 123 | + |
| 124 | +:::warning 注意 |
| 125 | +実際の運用では、`parser.parse`および`interpreter.exec`にエラーハンドリングを追加してください。 |
| 126 | +::: |
| 127 | + |
| 128 | +## 3. 独自の値を注入する |
| 129 | + |
| 130 | +先ほど説明した通り、`Interpreter`の第1引数にはAiScriptからアクセス可能なグローバル定数や関数を注入できます。 |
| 131 | + |
| 132 | +今回は、以下のような関数を注入してみましょう。 |
| 133 | + |
| 134 | +- `APP_VERSION`: アプリケーションのバージョンの定数 |
| 135 | +- `App:showAlert(message: string)`: アラートを表示する関数 |
| 136 | + |
| 137 | +そして、これらを組み合わせて、バージョン番号を含むアラートを表示するプログラムを実行してみます。 |
| 138 | + |
| 139 | +```aiscript |
| 140 | +App:showAlert(`You are running MyApp Version {APP_VERSION}`) |
| 141 | +``` |
| 142 | + |
| 143 | +ステップ2のコードをそのまま流用して、AiScriptプログラムだけを変更したのが以下のものです。 |
| 144 | + |
| 145 | +```ts |
| 146 | +import { Parser, Interpreter, utils } from '@syuilo/aiscript'; |
| 147 | + |
| 148 | +const program = `App:showAlert(\`You are running MyApp Version {APP_VERSION}\`)`; // [!code ++] |
| 149 | + |
| 150 | +let parser: Parser; |
| 151 | +let interpreter: Interpreter; |
| 152 | + |
| 153 | +async function run() { |
| 154 | + parser = new Parser(); |
| 155 | + interpreter = new Interpreter({}, { |
| 156 | + out: (value) => { |
| 157 | + console.log(utils.valueToJs(value)); |
| 158 | + }, |
| 159 | + }); |
| 160 | + |
| 161 | + const ast = parser.parse(program); |
| 162 | + await interpreter.exec(ast); |
| 163 | +} |
| 164 | + |
| 165 | +run(); |
| 166 | +``` |
| 167 | + |
| 168 | +ここで、`APP_VERSION`と`App:showAlert`を注入します。 |
| 169 | + |
| 170 | +```ts |
| 171 | +import { Parser, Interpreter, utils, values } from '@syuilo/aiscript'; // [!code ++] |
| 172 | +import { alert } from '@/ui'; // お使いの環境に合わせて変更してください // [!code ++] |
| 173 | + |
| 174 | +const program = `App:showAlert(\`You are running MyApp Version {APP_VERSION}\`)`; |
| 175 | + |
| 176 | +let parser: Parser; |
| 177 | +let interpreter: Interpreter; |
| 178 | + |
| 179 | +async function run() { |
| 180 | + parser = new Parser(); |
| 181 | + interpreter = new Interpreter({ |
| 182 | + APP_VERSION: values.STR('1.0.0'), // [!code ++] |
| 183 | + 'App:showAlert': values.FN_NATIVE(([message]) => { // [!code ++] |
| 184 | + utils.assertString(message); // [!code ++] |
| 185 | + alert(message.value); // [!code ++] |
| 186 | + return values.NULL; // [!code ++] |
| 187 | + }), // [!code ++] |
| 188 | + }, { |
| 189 | + out: (value) => { |
| 190 | + console.log(utils.valueToJs(value)); |
| 191 | + }, |
| 192 | + }); |
| 193 | + |
| 194 | + const ast = parser.parse(program); |
| 195 | + await interpreter.exec(ast); |
| 196 | +} |
| 197 | + |
| 198 | +run(); |
| 199 | +``` |
| 200 | + |
| 201 | +`Interpreter`の第1引数に、注入したい値を**AiScriptの値に変換して**渡します。すべての値は`values`オブジェクトを通じて生成できます。もちろん文字列だけでなく、数値・配列・オブジェクトなども注入することができます。 |
| 202 | + |
| 203 | +また、関数の引数もAiScriptの値として渡されます。`utils`に含まれている`assert*`系の関数を使って、型アサーションを行うとともに、不正な値が含まれていた場合はエラーを返すことができます。 |
| 204 | + |
| 205 | +:::tip ヒント |
| 206 | + |
| 207 | +既存の関数群との衝突を避けるためにも、名前空間を意識して関数名を指定することをお勧めします。 |
| 208 | + |
| 209 | +独自関数を多数実装している[Misskeyの独自関数のリファレンス](https://misskey-hub.net/docs/for-developers/plugin/plugin-api-reference/)や、[実際に独自関数を実装している部分のコード](https://github.com/misskey-dev/misskey/blob/develop/packages/frontend/src/scripts/aiscript/api.ts)が参考になるでしょう。 |
| 210 | + |
| 211 | +::: |
0 commit comments