From 891c097fed0074d6c215d0bc849c4d60ad6240be Mon Sep 17 00:00:00 2001 From: Kazuhito Suda Date: Fri, 31 May 2024 19:17:14 +0900 Subject: [PATCH] (JP) ADD documentation about JEXL expressions in custom notifications --- doc/manuals.jp/admin/build_source.md | 2 + doc/manuals.jp/admin/statistics.md | 35 +- doc/manuals.jp/devel/sourceCode.md | 7 + doc/manuals.jp/orion-api.md | 794 ++++++++++++++++++++++++++- 4 files changed, 805 insertions(+), 33 deletions(-) diff --git a/doc/manuals.jp/admin/build_source.md b/doc/manuals.jp/admin/build_source.md index 2797e3f5b3..b5464ae4ea 100644 --- a/doc/manuals.jp/admin/build_source.md +++ b/doc/manuals.jp/admin/build_source.md @@ -4,6 +4,8 @@ Orion Context Broker のリファレンス配布は Debian 12 です。これは 公式以外のディストリビューションで Docker コンテナ・イメージをビルドする方法は、Docker ドキュメントの [3.1 非公式ディストリビューションでのビルド](../../../docker/README.jp.md#31-building-in-not-official-distributions)・セクションで確認できます。 +*注:* このドキュメントで説明されているビルド プロセスには cjexl ライブラリは含まれていません。これは、基本的なビルド プロセスの観点からはオプションであると見なされているためです。 + ## Debian 12 (正式サポート) Orion Context Broker は、以下のライブラリをビルドの依存関係として使用します : diff --git a/doc/manuals.jp/admin/statistics.md b/doc/manuals.jp/admin/statistics.md index 2f25673ebb..bcf301f0be 100644 --- a/doc/manuals.jp/admin/statistics.md +++ b/doc/manuals.jp/admin/statistics.md @@ -115,20 +115,22 @@ SemWait ブロックは、メインの内部セマフォの累積待ち時間を "timing": { "accumulated": { "jsonV1Parse": 7.860908311, - "mongoBackend": 416.796091597, - "mongoReadWait": 4656.924425628, - "mongoWriteWait": 259.347915990, - "mongoCommandWait": 0.514811318, - "render": 108.162782114, - "total": 6476.593504743 - }, + "jsonV2Parse": 120.680244446, + "mongoBackend": 12778.52734375, + "mongoReadWait": 7532.301757812, + "mongoWriteWait": 3619.282226562, + "mongoCommandWait": 0.120559767, + "exprJexlCtxBld": 27.092681885, + "exprJexlEval": 124.217208862, + "render": 44.540554047, + "total": 25051.384765625 + }, "last": { - "mongoBackend": 0.014752309, - "mongoReadWait": 0.012018445, - "mongoWriteWait": 0.000574611, - "render": 0.000019136, - "total": 0.015148915 - } + "mongoBackend": 0.003775352, + "mongoReadWait": 0.0013743, + "render": 0.000286864, + "total": 0.00440685 + } } ... } @@ -147,8 +149,13 @@ SemWait ブロックは、メインの内部セマフォの累積待ち時間を * `mongoBackend` : mongoBackend モジュールで渡された時間です (疑似セルフタイム) * `render` : レンダリングモジュールに渡された時間です (擬似セルフタイム) * `mongo*Wait``Read`, `Write` または `Cmd` オペレーションのために MongoDB を待っている時間です。与えられた要求が MongoDB への複数の read/write/cmd の呼び出しを含む場合、`last` 下の `mongo*Wait` に示された時間は、それらすべてのための蓄積を含むことに注意してください。mongoReadWait の場合、結果カーソルを取得するために使用された時間のみが考慮されますが、カーソル結果を処理する時間 (mongoBackend カウンタに属する時間) は考慮されません +* `exprJexlCtxBld`: カスタム通知式の評価のためのコンテキストの構築にかかった時間 ([マクロ置換](../orion-api.md#macro-substitution) および [JEXL サポート](../orion-api.md#jexl-support) を参照) +* `exprJexlEval`: カスタム通知式の評価にかかった時間 ([マクロ置換](../orion-api.md#macro-substitution) および [JEXL サポート](../orion-api.md#jexl-support) を参照) + +*注*: Orion バイナリが cjexl を使用せずにビルドされ、基本的な置換のみが使用可能な場合、`exprJexlCtxBld` および `exprJexlEval` の代わりに +`exprBasicCtxtBld` フィールドと `exprBasicEval` フィールドが表示されます。 -時間は、特定のスレッド・リクエストがモジュールの使用を開始し、使用を終了するまでの時間から測定されます。したがって、何らかの理由でスレッドが停止した場合 (カーネルがそのスケジューリングポリシーに基づいて別のスレッドに優先順位を与えることを決定した場合)、スレッドがスリープしていた時間が再び実行を待っている時間が測定に含まれているため、正確ではありません。このため、擬似 selt/end-to-end 時間と言っています。しかし、低負荷条件下では、この状況は重大な影響を及ぼさないと予想されます +時間は、特定のスレッド・リクエストがモジュールの使用を開始し、使用を終了するまでの時間から測定されます。したがって、何らかの理由でスレッドが停止した場合 (カーネルがそのスケジューリングポリシーに基づいて別のスレッドに優先順位を与えることを決定した場合)、スレッドがスリープしていた時間が再び実行を待っている時間が測定に含まれているため、正確ではありません。このため、擬似 self/end-to-end 時間と言っています。しかし、低負荷条件下では、この状況は重大な影響を及ぼさないと予想されます ### NotifQueue ブロック diff --git a/doc/manuals.jp/devel/sourceCode.md b/doc/manuals.jp/devel/sourceCode.md index d2deec1157..0c8186a8b8 100644 --- a/doc/manuals.jp/devel/sourceCode.md +++ b/doc/manuals.jp/devel/sourceCode.md @@ -24,6 +24,7 @@ * [src/lib/cache/](#srclibcache) (サブスクリプション・キャッシュの実装) * [src/lib/logSummary/](#srcliblogsummary) (ログ・サマリの実装) * [src/lib/metricsMgr/](#srclibmetricsmgr) (メトリック・マネージャの実装) +* [src/lib/expressions/](#srclibexpressions) (カスタム通知式のサポート) ## src/app/contextBroker/ @@ -540,3 +541,9 @@ NGSIv2 GET サブスクリプションのリクエストはサブスクリプシ プラットフォーム全体で同様のメトリックを使用するには、一般的なメトリックが考案され、Orion の場合は、この目的のためにマネージャが実装されました。この メトリック・マネージャは、ライブラリ **metricsMgr** にあります。メトリックについては、[このドキュメント](../admin/metrics_api.md)を参照してください。 [トップ](#top) + +## src/lib/expressions/ + +[カスタム通知で使用されるマクロ置換ロジック](../orion-api.md#macro-substitution) のサポートを提供します。このライブラリは、式評価の抽象化を提供し、JEXL ベースと基本置換ベースの 2 つの実装を提供します (使用する実装は、cjex ライブラリの可用性に基づいて、ビルド時に選択されます)。 + +[トップ](#top) diff --git a/doc/manuals.jp/orion-api.md b/doc/manuals.jp/orion-api.md index c7684fec8c..0221a4d105 100644 --- a/doc/manuals.jp/orion-api.md +++ b/doc/manuals.jp/orion-api.md @@ -73,6 +73,35 @@ - [NGSI ペイロードのパッチ適用 (NGSI payload patching)](#ngsi-payload-patching) - [ペイロードの省略 (Omitting payload)](#omitting-payload) - [その他の考慮事項](#additional-considerations) + - [JEXL サポート (JEXL Support)](#jexl-support) + - [JEXL 使用例 (JEXL usage example)](#jexl-usage-example) + - [利用可能な変換 (Available Transformations)](#available-transformations) + - [`uppercase`](#uppercase) + - [`lowercase`](#lowercase) + - [`split`](#split) + - [`indexOf`](#indexOf) + - [`len`](#len) + - [`trim`](#trim) + - [`substring`](#substring) + - [`includes`](#includes) + - [`isNaN`](#isNaN) + - [`parseInt`](#parseInt) + - [`parseFloat`](#parseFloat) + - [`typeOf`](#typeOf) + - [`toString`](#toString) + - [`floor`](#floor) + - [`ceil`](#ceil) + - [`round`](#round) + - [`toFixed`](#toFixed) + - [`log`](#log) + - [`log10`](#log10) + - [`log2`](#log2) + - [`sqrt`](#sqrt) + - [`replaceStr`](#replaceStr) + - [`mapper`](#mapper) + - [`thMapper`](#thmapper) + - [フェイルセーフ・ケース (Failsafe cases)](#failsafe-cases) + - [既知の制限 (Known limitations)](#known-limitations) - [Oneshot サブスクリプション (Oneshot Subscriptions)](#oneshot-subscriptions) - [カバード・サブスクリプション (Covered subscriptions)](#covered-subscriptions) - [変更タイプに基づくサブスクリプション (Subscriptions based in alteration type)](#subscriptions-based-in-alteration-type) @@ -391,11 +420,12 @@ Orion で使用されるメタデータ更新セマンティクス (および関 GET /v2/entities/E%253C01%253E ``` -上記の制限が適用されない例外的なケースがいくつかあります。 特に、次のフィールドで: +上記の制限が適用されない例外的なケースがいくつかあります。 特に、次のケースで: - URL パラメータ `q` は、[シンプル・クエリ言語](#simple-query-language) に必要な特殊文字を許可します - URL パラメータ `mq` は、[シンプル・クエリ言語](#simple-query-language) に必要な特殊文字を許可します - URL パラメータ `georel` と `coords` は `;` を許可します +- [NGSI ペイロード パッチ](#ngsi-payload-patching) の `ngsi` (つまり `id`、`type`、および属性値) 内 ([JEXL 式構文](#jexl-support) で使用される文字をサポートするため) - 属性タイプとして `TextUnrestricted` を使用する属性値 ([特別な属性タイプ](#special-attribute-types)のセクションを参照) @@ -422,6 +452,8 @@ GET /v2/entities/E%253C01%253E クライアントが構文の観点から無効なフィールドを使用しようとすると、クライアントは、原因を説明する "Bad Request" エラーの レスポンスを受け取ります。 +`:` と `-` は識別子で使用できますが、[JEXL 構文](#jexl-support) と衝突するため、使用は強く推奨されません。特に、`-` は減算演算 (例: `${A-B}`) に使用され、`:` は三項演算子 (例: `A?'A is true':'A is false`) に使用されます。したがって、式 `${lower-temperature}` 内の属性名 `lower-temperature` は、`lower` 属性の値から `temperature` 属性を引いた値として解釈されます (`lower-temperature` という名前の属性の値として解釈されるわけではありません)。 + ## エラー・レスポンス (Error Responses) @@ -2008,22 +2040,22 @@ NGSIv1 は非推奨であることに注意してください。したがって - `payload`, `json`, `ngsi` (すべてペイロード関連のフィールド) - `topic` -テンプレートのマクロ置換は、構文 `${..}` に基づいています。特に: +テンプレートのマクロ置換は、構文 `${}` に基づいています。JEXL のサポートについては、 +[JEXL サポート](#jexl-support) セクションで説明されています。JEXL 式によって評価されるコンテキストには、 +次の識別子が含まれます: -- `${id}` は、エンティティの `id` に置き換えられます -- `${type}` は、エンティティの `type` に置き換えられます -- `${service}` は、サブスクリプションをトリガーする更新リクエストのサービス (つまり、`Fiware-Service` ヘッダ値) - に置き換えられます -- `${servicePath}` は、サブスクリプションをトリガーする更新リクエストのサービス パス (つまり、`Fiware-Servicepath` - ヘッダ値) に置き換えられます -- `${authToken}` は、サブスクリプションをトリガーする更新リクエストで認証トークン (つまり、`x-auth-token` ヘッダ値) - に置き換えられます -- 他の `${token}` は、名前が `token` の属性の値に置き換えられます。属性が通知に含まれていない場合は空文字列に - 置き換えられます。値が数値、bool または null の場合、その文字列表現が使用されます。値が JSON 配列または - オブジェクトの場合、JSON 表現は文字列として使用されます +- `id`: エンティティの `id` +- `type`: エンティティの `type` +- `service`: サブスクリプションをトリガーする更新リクエスト内のサービス + (つまり、`fiware-service` ヘッダ値) +- `servicePath`: サブスクリプションをトリガーする更新リクエスト内のサービス・パス + (つまり、`fiware-servicepath` ヘッダ値) +- `authToken: サブスクリプションをトリガーする更新リクエスト内の認証トークン + (つまり、`x-auth-token` ヘッダ値) +- 通知をトリガーするエンティティ内のすべての属性(通知をトリガーする更新に含まれているかどうか) -まれに、属性が `${service}`, `${servicePath}` または `${authToken}` と同じ方法で命名された場合 (例: `service` -という名前の属性)、属性値が優先されます。 +まれに、属性の名前が `service`、`servicePath`、または `authToken` と同じ名前になっている場合 +(名前が `service` である属性など)、属性値が優先されます。 例: @@ -2293,6 +2325,734 @@ the value of the "temperature" attribute (of type Number) is 23.4 `Ngsiv2-AttrsFormat` ヘッダは `custom` に設定されます。ただし、NGSI patch が使用される場合 (つまり、`ngsi` フィールド)、 通常の通知と同様に、`Ngsiv2-AttrsFormat: normalized` が使用されることに注意してください (通知形式が実際には同じである場合) + + +## JEXL サポート (JEXL Support) + +Orion Context Brokerは、カスタム通知の[マクロ置換](#macro-substitution)で[JEXL式](https://github.com/TomFrost/Jexl)をサポートしています。したがって、次のようなサブスクリプションを定義できます: + +``` +"httpCustom": { + ... + "ngsi": { + "relativeHumidity": { + "value": "${humidity/100}", + "type": "Calculated" + } + } +} +``` + +したがって、特定の更新によってエンティティの `humidity` 属性が `84.4` に設定された場合、通知には値 `0.844` の `relativeHumidity` 属性が含まれます。 + +式の特殊なケースとしては、式が特定のコンテキスト識別子であり、実際の式でそれを使用しないケースがあります。たとえば、次のようになります: + +``` +"httpCustom": { + ... + "ngsi": { + "originalHumidity": { + "value": "${humidity}", + "type": "Calculated" + } + } +} +``` + +このケースを *基本置換* (basic replacement) とも呼びます。 + +JEXL 式をテストするための便利なリソースは [JEXL プレイグラウンド](https://czosel.github.io/jexl-playground) です。ただし、[既知の制限](#known-limitations) セクションで説明されているように、JavaScript での元の JEXL 実装と Orion に含まれる実装の違いを考慮してください。 + +Orion は、この機能を提供するために cjexl ライブラリに依存しています。Orion バイナリが cjexl を使用せずにビルドされている場合、基本置換機能のみが利用できます。 + + + +### JEXL 使用例 (JEXL usage example) + +例として、次のようなサブスクリプションを考えてみましょう: + +``` +"httpCustom": { + ... + "ngsi": { + "speed": { + "value": "${(speed|split(' '))[0]|parseInt}", + "type": "Calculated" + }, + "ratio": { + "value": "${count.sum/count.count}", + "type": "Calculated" + }, + "code": { + "value": "${code||'invalid'}", + "type": "Calculated" + }, + "alert": { + "value": "${(value>max)?'nok':'ok'}", + "type": "Calculated" + }, + "count": { + "value": "${{count:count.count+1, sum:count.sum+((speed|split(' '))[0]|parseInt)}}", + "type": "Calculated" + } +} +``` + +エンティティの更新は次のようになります: + +``` +{ + ... + "speed": { + "value": "10 m/s", + "type": "Text" + }, + "count": { + "value": { + "count": 5, + "sum": 100 + }, + "type": "StructuredValue" + }, + "code": { + "value": null, + "type": "Number" + }, + "value": { + "value": 14, + "type": "Number" + }, + "max": { + "value": 50, + "type": "Number" + } +} +``` + +次のような通知がトリガーされます: + +``` +"data": [ + { + ... + "speed": { + "metadata": {}, + "type": "Calculated", + "value": 10 + }, + "ratio": { + "metadata": {}, + "type": "Calculated", + "value": 20 + }, + "code": { + "metadata": {}, + "type": "Calculated", + "value": "invalid" + }, + "alert": { + "metadata": {}, + "type": "Calculated", + "value": "ok" + }, + "count": { + "metadata": {}, + "type": "Calculated", + "value": { + "count": 6, + "sum": 110 + } + } + } +] +``` + +新しいエンティティの更新は次のようになります: + +``` +{ + ... + "speed": { + "value": "30 m/s", + "type": "Text" + }, + "count": { + "value": { + "count": 5, + "sum": 500 + }, + "type": "StructuredValue" + }, + "code": { + "value": 456, + "type": "Number" + }, + "value": { + "value": 75, + "type": "Number" + }, + "max": { + "value": 50, + "type": "Number" + } +} +``` + +次のような通知が表示されます: + +``` +"data": [ + { + ... + "speed": { + "metadata": {}, + "type": "Calculated", + "value": 30 + }, + "ratio": { + "metadata": {}, + "type": "Calculated", + "value": 100 + }, + "code": { + "metadata": {}, + "type": "Calculated", + "value": 456 + }, + "alert": { + "metadata": {}, + "type": "Calculated", + "value": "nok" + }, + "count": { + "metadata": {}, + "type": "Calculated", + "value": { + "count": 6, + "sum": 530 + } + } + } +] +``` + + + +### 利用可能な変換 (Available Transformations) + + + +#### `uppercase` + +文字列を大文字に変換します。 + +追加引数: なし + +例 (コンテキスト `{"c": "fooBAR"}`): + +``` +c|uppercase +``` + +結果 + +``` +"FOOBAR" +``` + + + +#### lowercase + +文字列を小文字に変換します。 + +追加引数: なし + +例 (コンテキスト `{"c": "fooBAR"}`): + +``` +c|lowercase +``` + +結果 + +``` +"foobar" +``` + + + +#### split + +入力文字列を配列項目に分割します。 + +追加引数: 分割に使用する区切り文字 + +例 (コンテキスト `{"c": "foo,bar,zzz"}`): + +``` +c|split(',') +``` + +結果 + +``` +[ "foo", "bar", "zzz" ] +``` + + + +#### indexOf + +入力文字列内の指定された文字列の位置を提供します。文字列が見つからない場合は、`null` を返します。 + +追加引数: 検索する入力文字列 + +この関数は、入力が配列の場合は機能しないことに注意してください (文字列に対してのみ機能します)。 + +例 (コンテキスト `{"c": "fooxybar"}`): + +``` +c|indexOf('xy') +``` + +結果 + +``` +3 +``` + + + +#### len + +文字列の長さを提供します。 + +追加引数: なし + +この関数は、入力が配列の場合は機能しないことに注意してください (文字列に対してのみ機能します)。 + +例 (コンテキスト `{"c": "foobar"}`): + +``` +c|len +``` + +結果 + +``` +6 +``` + + + +#### trim + +先頭と末尾の空白を削除します。 + +追加引数: なし + +例 (コンテキスト `{"c": " foo bar "}`): + +``` +c|trim +``` + +結果 + +``` +foo bar +``` + + + +#### substring + +2つの位置の間の部分文字列を返します。 + +追加引数: +* 開始位置 +* 終了位置 + +例 (コンテキスト `{"c": "foobar"}`): + +``` +c|substring(3,5) +``` + +結果 + +``` +ba +``` + + + +#### includes + +指定された文字列が入力文字列に含まれている場合は `true` を返し、含まれていない場合は `false` を返します。 + +追加引数: 検索する入力文字列 + +例 (コンテキスト `{"c": "foobar"}`): + +``` +c|includes('ba') +``` + +結果 + +``` +true +``` + + + +#### isNaN + +入力が数値でない場合は `true` を返し、それ以外の場合は `false` を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": "foobar"}`): + +``` +c|isNaN +``` + +結果 + +``` +true +``` + + + +#### parseInt + +文字列を解析し、対応する整数を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": "25"}`): + +``` +c|parseInt +``` + +結果 + +``` +25 +``` + + + +#### parseFloat + +文字列を解析し、対応する浮動小数点数を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": "25.33"}`): + +``` +c|parseFloat +``` + +結果 + +``` +25.33 +``` + + + +#### typeOf + +入力の型を含む文字列を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": 23}`): + +``` +c|typeOf +``` + +結果 + +``` +"Number" +``` + + + +#### toString + +Return a string representation of the input. + +追加引数: なし + +例 (コンテキスト `{"c": 23}`): + +``` +c|toString +``` + +結果 + +``` +"23" +``` + + + +#### floor + +指定された数値に最も近い小さい整数を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|floor +``` + +結果 + +``` +3 +``` + + + +#### ceil + +指定された数値に最も近い上位の整数を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|ceil +``` + +結果 + +``` +4 +``` + + + +#### round + +指定された数値に最も近い整数(下限または上限)を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|round +``` + +結果 + +``` +3 +``` + + + +#### toFixed + +数値を小数点以下の桁数に丸めます。 + +追加引数: 小数点以下の桁数 + +例 (コンテキスト `{"c": 3.18}`): + +``` +c|toFixed(1) +``` + +結果 + +``` +3.2 +``` + + + +#### log + +与えられた数値の自然対数を返す。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|log +``` + +結果 + +``` +1.144222799920162 +``` + + + +#### log10 + +与えられた数値の10を底とする対数を返す。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|log10 +``` + +結果 + +``` +0.49692964807321494 +``` + + + +#### log2 + +指定された数値の 2 を底とする対数を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|log2 +``` + +結果 + +``` +1.6507645591169025 +``` + + + +#### sqrt + +指定された数値の平方根を返します。 + +追加引数: なし + +例 (コンテキスト `{"c": 3.14}`): + +``` +c|sqrt +``` + +結果 + +``` +1.772004514666935 +``` + + + +#### replaceStr + +入力文字列内の文字列を別の文字列に置き換えます。 + +追加引数: +* 置換するソース文字列 +* 置換先の文字列 + +例 (コンテキスト `{"c": "foobar"}`): + +``` +c|replaceStr('o','u') +``` + +結果 + +``` +"fuubar" +``` + + + +#### mapper + +1 対 1 のマッピングに基づいて、複数の選択肢の中から値を返します。この関数は、値の配列 (*value*) と選択肢の配列 (*choices*) に基づいています (長さはまったく同じ) 。したがって、入力値が *values* の *i* 番目の項目と等しい場合は、*choices* の *i* 番目の項目が返されます。 + +この変換は、引数に何らかの問題が見つかった場合 (つまり、入力が値の中に見つからない、選択肢の長さが値とまったく同じではない、入力が文字列ではないなど)、`null` を返します。 + +追加引数: +* 値の配列 (values array) +* 選択肢の配列 (choices array) + +例 (コンテキスト `{"c": "fr", "values": ["es", "fr", "de"], "choices": ["Spain", "France", "Germany"]}`): + +``` +c|mapper(values,choices) +``` + +結果 + +``` +"France" +``` + + + +#### thMapper + +しきい値に基づいて、複数の選択肢の中から値を返します。この関数は、値の配列 (*values*) と選択肢の配列 (*choices*) に基づいています (長さは、値に 1 を加えた値とまったく同じです)。したがって、入力値が *values* の *i* 番目と *i+1* 番目の項目の間にある場合は、*choices* の *i*+1 番目の項目が返されます。 + +引数に問題が見つかった場合 (つまり、選択肢の長さが値に 1 を加えた値とまったく同じではない、値配列の一部の項目が数値ではないなど)、この変換は `null` を返します。 + +追加引数: +* 値の配列 (values array) +* 選択肢の配列 (choices array) + +例 (コンテキスト `{"c": 0.5, "values": [-1, 1], "choices": ["low", "medium", "high"]}`): + +``` +c|thMapper(values,choices) +``` + +結果 + +``` +"medium" +``` + + + +### フェイルセーフ・ケース (Failsafe cases) + +フェイルセーフ動作として、評価は次の場合に `null` を返します: + +* 式で使用されている変換の一部が不明です (例: `A|undefinedExpression`) +* コンテキストで定義されていない識別子を使用した演算が使用されています。たとえば、`(A==null)?0:A` は、`A` がコンテキストにない場合、`null` (`0` ではありません) になります。これは、`==` が未定義の識別子では実行できない演算であるためです。ただし、`||` は `A` に対する演算とは見なされないため、`A||0` は機能します (つまり、`A` がコンテキストにない場合は `0` になります) +* JEXL 式の構文エラーです (例: `A[0|uppercase`) + + + +### 既知の制限 (Known limitations) + +- 単位マイナス演算子が正しく動作しません。たとえば、次の式は動作しません (`null` にフェイルセーフされます): `A||-1`。ただし、次の代替式は動作します: `A||0-1` および `A||'-1'|parseInt)` +- 否定演算子 `!` (元の JavaScript JEXL でサポート) はサポートされていません + ## Oneshot サブスクリプション (Oneshot Subscriptions) @@ -2397,10 +3157,6 @@ EOF この場合、エンティティに存在するかどうかに関係なく、すべての属性が通知に含まれます。存在しないこれらの属性 (この例では `brightness`) には、`null` 値 (タイプ `"None"`) が使用されます。 -カスタム通知の場合、`covered` が `true` に設定されていると、`null` は、存在しない属性の `${...}` を置き換えるために -使用されます (`covered` が `true` に設定されていない場合のデフォルトの動作は、存在しない属性を空の文字列に -置き換えることです)。 - 通知が `notification.attrs` フィールドのすべての属性を完全に "カバーする" (covers) という意味で "カバーされる" (covered) という用語を使用します。これは、可変の属性セットに対して十分な柔軟性がなく、受信したすべての通知で常に同じ着信属性の セットを必要とする通知エンドポイントに役立ちます。