recogn-parse
Version:
recogn-parse 提供了 识别--解析 的机制,使用者只需要添加识别器 和 解析器,然后就可以对事件进行识别和解析,适合用所有具备 识别--解析 流程的场景中,如:加载并显示各种模型、预览文件等
107 lines (78 loc) • 7.25 kB
Markdown
[识别解析_时序图]: ./assets/识别解析_时序图.png
[识别解析_活动图]: ./assets/识别解析_活动图.png
[对鉴定者列表执行识别]: ./assets/对鉴定者列表执行识别.png
[执行鉴定者]: ./assets/执行鉴定者.png
[识别]: ./assets/识别.png
[执行鉴定者]: ./assets/执行鉴定者.png
[解决]: ./assets/解决.png
**目录:**
<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=true} -->
<!-- code_chunk_output -->
1. [类的关系](#-类的关系)
2. [识别解析的逻辑](#-识别解析的逻辑)
1. [识别的逻辑](#-识别的逻辑)
2. [解析的逻辑](#-解析的逻辑)
<!-- /code_chunk_output -->
-------
# 类的关系
recogn-parse 包含以下几个主要类:
- `RecognParse`:识别解析,是用户直接操作的主类,提供了完整的 `识别-解析` 机制。
- `Recognizer`:识别器。负责识别操作,所有的识别逻辑都是由该类来完成的。
- `Resolver`:解决者。负责解析操作,所有的解析逻辑都是由该类来完成的。
它们之间的关系如下图:
![识别解析_时序图][]
# 识别解析的逻辑
当需要对目标 `target` 进行识别并解析时,可以调用以下任一方法:
- `recognParse.resolve(target)`
- `recognParse.resolveAsync(target)`
**识别解析的逻辑步骤如下:**
1. 对目标 `target` 进行识别:这一步的目的是识别出目标 `target` 的类型 `type`;
1. 前置识别:如果没有前置鉴定者,则跳过此步;否则,依次执行前置鉴定者列表中的鉴定者,直到 鉴定者成功识别出 `target` 的类型 `type` 或者 前置鉴定者列表中的鉴定者执行完毕(详见下图 `对鉴定者列表执行识别`);
2. 识别:如果指定了鉴定者的名字,则直接执行对应的鉴定者;否则,将依次执行鉴定者列表中的鉴定者,直到 鉴定者成功识别出 `target` 的类型 `type` 或者 前置鉴定者列表中的鉴定者执行完毕(详见下图 `对鉴定者列表执行识别`);
3. 后置识别:如果没有后置鉴定者,则跳过此步;否则,依次执行后置鉴定者列表中的鉴定者,直到 鉴定者成功识别出 `target` 的类型 `type` 或者 后置鉴定者列表中的鉴定者执行完毕(详见下图 `对鉴定者列表执行识别`);
4. 经过以上几步,如果最后一步没有返回的识别结果,则终止程序;否则,继续下一步;
2. 对目标 `target` 进行解析:依次对每个识别出来的类型执行以下步骤:
1. 如果没有对应类型的解析器,则跳过些类型的解析;否则,继续;
2. 前置解析:如果没有前置解析函数,则跳过此步;否则,依次执行前置解析函数列表中的所有函数,并忽略执行解析函数时抛出的异常;
3. 解析:获取对应类型的解析器,并执行该解析器;
4. 后置解析:如果没有后置解析函数,则跳过此步;否则,依次执行后置解析函数列表中的所有函数,并忽略执行解析函数时抛出的异常;
5. 将以上几步中最后一步的解析结果视作该类型的解析结果;
3. 汇总每个类型的识别结果和解析结果,并返回;
**流程图如下:**
![识别解析_活动图][]
![对鉴定者列表执行识别][]
其中 `鉴定者` 分为两类:
- `鉴定函数`:类型为 `type Judge<Options = any> = (target: any, targetOptions: Options, preResult: FormatJudgeResult) => JudgeReturn`,用于鉴定 target 的类型 和 格式化数据,如果返回 空,表示鉴定失败,参数如下:
* @param `target` - 目标
* @param `targetOptions` - 目标相关的选项
* @param `preResult` - 上一个鉴定函数的鉴定结果
* @returns 返回鉴定结果,可以是异步的鉴定结果;鉴定结果是可以是 一个 或 一组 鉴定信息 {@link JudgeInfo},也可以是空,如果是空 表示鉴定失败
- `串行鉴定者`:类型为 `type SerialJudger<Options = any> = Judge<Options>[]` 串行鉴定者就是一组鉴定函数,所有的鉴定函数都会依次执行,不论中间有没有失败,都会依次执行完所有的鉴定函数,并会以最后一个鉴定函数返回的结果为最终的鉴定结果。
* 串行鉴定者序列中的任何项识别失败都不会中止 串行鉴定者序列 的执行。即:即使 串行鉴定者序列 `SerialJudger` 中的某一个 `Judge` 返回 null 或者 抛出错误,则仍会执行此 串行鉴定者序列 SerialJudger 中的下一个 Judge
**鉴定者的执行流程如下:**
![执行鉴定者][]
`解析器`也分为两类:
+ `解析函数`:类型为 `type Parse<Options = any> = (target: any, targetOptions: Options, preResult: any, recognResult: JudgeInfo) => any`,用于对 target 进行解析,参数如下:
* @param `target` - 目标
* @param `targetOptions` - 目标相关的选项
* @param `preResult` - 之前的解析结果
* @param `recognResult` - 识别结果
* @returns 解析的结果
+ `串行解析器`: 类型为 `type SerialParser<Options = any> = Parse<Options>[]`,串行解析器就是一组解析函数,这些解析函数会依次执行,并会以最后一个解析函数返回的结果为最终的解析结果。这组解析函数中如果有解析函数抛出错误,则会终止解决流程。
## 识别的逻辑
每次执行识别操作时,会按照如下顺序调用鉴定者:
1. 依次执行前置鉴定者列表 `preJudgers` 中的鉴定者,如果有鉴定成功的,则会停止后续的前置鉴定者的执行,并将鉴定结果 传给后续流程。
2. 如果提供了 `name`,则会在 命名的鉴定者 中查找 `name` 对应的鉴定者,然后执行指定的鉴定者。然后 跳到 步骤 5。
3. 如果没有提供 `name`,则会执行 匿名的鉴定者列表。如果有鉴定结果,则会 跳到 步骤 5。
4. 否则,则会执行 所有的命名鉴定者。如果有鉴定结果,则会 跳到 步骤 5。
5. 依次执行后置鉴定者列表 `postJudgers` 中的鉴定者,如果有鉴定成功的,则会停止后续的后置鉴定者的执行,并返回 鉴定结果。否则返回 空;
![识别][]
![对鉴定者列表执行识别][]
![执行鉴定者][]
## 解析的逻辑
每次执行解决操作时,会按照如下顺序调用解析器:
1. 如果找不到对应类型 type 的 解析器,则会终止解决流程。
2. 依次执行前置解析器 `preParses` 中的所有解析函数,即使有抛出错误,也会继续执行,并会以最后一个解析函数返回的结果为最终前置解析器的解析结果,然后将 前置解析的结果 传给后续的解析器。
3. 依次执行根据 类型 type 查找到的解析器序列。如果序列中任意解析器抛出错误,则会终止解决流程。否则,以最后一个解析函数返回的结果为最终的解析结果 并 传递给后续的解析器。
4. 依次执行后置解析器 `postParses` 中的所有解析函数,即使有抛出错误,也会继续执行,并会以最后一个解析函数返回的结果为最终的解析结果。
![解决][]