@aster-cloud/aster-lang-ts 1.0.28 → 1.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/generate_error_codes.js +49 -6
- package/dist/scripts/generate_error_codes.js.map +1 -1
- package/dist/src/ai/providers/openai.d.ts +10 -0
- package/dist/src/ai/providers/openai.d.ts.map +1 -1
- package/dist/src/ai/providers/openai.js +4 -0
- package/dist/src/ai/providers/openai.js.map +1 -1
- package/dist/src/config/lexicons/regex-guard.d.ts.map +1 -1
- package/dist/src/config/lexicons/regex-guard.js +128 -0
- package/dist/src/config/lexicons/regex-guard.js.map +1 -1
- package/dist/src/core/interpreter.d.ts.map +1 -1
- package/dist/src/core/interpreter.js +221 -27
- package/dist/src/core/interpreter.js.map +1 -1
- package/dist/src/cst/cst_builder.js +0 -14
- package/dist/src/cst/cst_builder.js.map +1 -1
- package/dist/src/cst/cst_printer.d.ts.map +1 -1
- package/dist/src/cst/cst_printer.js +20 -3
- package/dist/src/cst/cst_printer.js.map +1 -1
- package/dist/src/diagnostics/error_codes.d.ts +3 -3
- package/dist/src/diagnostics/error_codes.d.ts.map +1 -1
- package/dist/src/diagnostics/error_codes.js +509 -78
- package/dist/src/diagnostics/error_codes.js.map +1 -1
- package/dist/src/formatter.d.ts +7 -0
- package/dist/src/formatter.d.ts.map +1 -1
- package/dist/src/formatter.js +175 -5
- package/dist/src/formatter.js.map +1 -1
- package/dist/src/frontend/canonicalizer.d.ts.map +1 -1
- package/dist/src/frontend/canonicalizer.js +47 -6
- package/dist/src/frontend/canonicalizer.js.map +1 -1
- package/dist/src/frontend/lexer.d.ts +2 -1
- package/dist/src/frontend/lexer.d.ts.map +1 -1
- package/dist/src/frontend/lexer.js +10 -3
- package/dist/src/frontend/lexer.js.map +1 -1
- package/dist/src/frontend/transformers.d.ts.map +1 -1
- package/dist/src/frontend/transformers.js +50 -3
- package/dist/src/frontend/transformers.js.map +1 -1
- package/dist/src/lower_to_core.js +101 -4
- package/dist/src/lower_to_core.js.map +1 -1
- package/dist/src/lsp/canonicalize-options.d.ts +26 -0
- package/dist/src/lsp/canonicalize-options.d.ts.map +1 -0
- package/dist/src/lsp/canonicalize-options.js +14 -0
- package/dist/src/lsp/canonicalize-options.js.map +1 -0
- package/dist/src/lsp/completion.d.ts.map +1 -1
- package/dist/src/lsp/completion.js +22 -4
- package/dist/src/lsp/completion.js.map +1 -1
- package/dist/src/lsp/server.js +29 -1
- package/dist/src/lsp/server.js.map +1 -1
- package/dist/src/lsp/tenant-init.d.ts +55 -0
- package/dist/src/lsp/tenant-init.d.ts.map +1 -0
- package/dist/src/lsp/tenant-init.js +88 -0
- package/dist/src/lsp/tenant-init.js.map +1 -0
- package/dist/src/mapping/candidate-generator.d.ts +84 -0
- package/dist/src/mapping/candidate-generator.d.ts.map +1 -0
- package/dist/src/mapping/candidate-generator.js +114 -0
- package/dist/src/mapping/candidate-generator.js.map +1 -0
- package/dist/src/mapping/entity-proposer.d.ts +85 -0
- package/dist/src/mapping/entity-proposer.d.ts.map +1 -0
- package/dist/src/mapping/entity-proposer.js +162 -0
- package/dist/src/mapping/entity-proposer.js.map +1 -0
- package/dist/src/mapping/mapping-ir.d.ts +85 -0
- package/dist/src/mapping/mapping-ir.d.ts.map +1 -0
- package/dist/src/mapping/mapping-ir.js +195 -0
- package/dist/src/mapping/mapping-ir.js.map +1 -0
- package/dist/src/mapping/proof-ir.d.ts +125 -0
- package/dist/src/mapping/proof-ir.d.ts.map +1 -0
- package/dist/src/mapping/proof-ir.js +48 -0
- package/dist/src/mapping/proof-ir.js.map +1 -0
- package/dist/src/mapping/quantity-ir.d.ts +93 -0
- package/dist/src/mapping/quantity-ir.d.ts.map +1 -0
- package/dist/src/mapping/quantity-ir.js +151 -0
- package/dist/src/mapping/quantity-ir.js.map +1 -0
- package/dist/src/mapping/source-ir.d.ts +82 -0
- package/dist/src/mapping/source-ir.d.ts.map +1 -0
- package/dist/src/mapping/source-ir.js +231 -0
- package/dist/src/mapping/source-ir.js.map +1 -0
- package/dist/src/nodeid/change-impact.d.ts +77 -0
- package/dist/src/nodeid/change-impact.d.ts.map +1 -0
- package/dist/src/nodeid/change-impact.js +132 -0
- package/dist/src/nodeid/change-impact.js.map +1 -0
- package/dist/src/nodeid/node-id-map.d.ts +69 -0
- package/dist/src/nodeid/node-id-map.d.ts.map +1 -0
- package/dist/src/nodeid/node-id-map.js +193 -0
- package/dist/src/nodeid/node-id-map.js.map +1 -0
- package/dist/src/parser/decl-parser.d.ts.map +1 -1
- package/dist/src/parser/decl-parser.js +10 -4
- package/dist/src/parser/decl-parser.js.map +1 -1
- package/dist/src/parser/expr-stmt-parser.d.ts.map +1 -1
- package/dist/src/parser/expr-stmt-parser.js +36 -24
- package/dist/src/parser/expr-stmt-parser.js.map +1 -1
- package/dist/src/parser/span-utils.d.ts +25 -0
- package/dist/src/parser/span-utils.d.ts.map +1 -1
- package/dist/src/parser/span-utils.js +43 -0
- package/dist/src/parser/span-utils.js.map +1 -1
- package/dist/src/parser/type-parser.d.ts.map +1 -1
- package/dist/src/parser/type-parser.js +21 -0
- package/dist/src/parser/type-parser.js.map +1 -1
- package/dist/src/typecheck/expression.d.ts.map +1 -1
- package/dist/src/typecheck/expression.js +26 -0
- package/dist/src/typecheck/expression.js.map +1 -1
- package/dist/test/fuzz/fuzz.test.js +62 -2
- package/dist/test/fuzz/fuzz.test.js.map +1 -1
- package/dist/test/unit/call-arity.test.d.ts +2 -0
- package/dist/test/unit/call-arity.test.d.ts.map +1 -0
- package/dist/test/unit/call-arity.test.js +71 -0
- package/dist/test/unit/call-arity.test.js.map +1 -0
- package/dist/test/unit/canonicalizer/canonicalizer.test.js +42 -4
- package/dist/test/unit/canonicalizer/canonicalizer.test.js.map +1 -1
- package/dist/test/unit/canonicalizer/line-preservation.test.d.ts +2 -0
- package/dist/test/unit/canonicalizer/line-preservation.test.d.ts.map +1 -0
- package/dist/test/unit/canonicalizer/line-preservation.test.js +71 -0
- package/dist/test/unit/canonicalizer/line-preservation.test.js.map +1 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.d.ts +2 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.d.ts.map +1 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.js +98 -0
- package/dist/test/unit/canonicalizer/marker-restore-linear.test.js.map +1 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.d.ts +2 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.d.ts.map +1 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.js +101 -0
- package/dist/test/unit/canonicalizer/possessive-anchor.test.js.map +1 -0
- package/dist/test/unit/formatter-redos.test.d.ts +2 -0
- package/dist/test/unit/formatter-redos.test.d.ts.map +1 -0
- package/dist/test/unit/formatter-redos.test.js +196 -0
- package/dist/test/unit/formatter-redos.test.js.map +1 -0
- package/dist/test/unit/interpreter/interpreter.test.js +7 -2
- package/dist/test/unit/interpreter/interpreter.test.js.map +1 -1
- package/dist/test/unit/lexer/bom.test.d.ts +2 -0
- package/dist/test/unit/lexer/bom.test.d.ts.map +1 -0
- package/dist/test/unit/lexer/bom.test.js +49 -0
- package/dist/test/unit/lexer/bom.test.js.map +1 -0
- package/dist/test/unit/list-get-bounds.test.d.ts +2 -0
- package/dist/test/unit/list-get-bounds.test.d.ts.map +1 -0
- package/dist/test/unit/list-get-bounds.test.js +66 -0
- package/dist/test/unit/list-get-bounds.test.js.map +1 -0
- package/dist/test/unit/long-bigint-exact.test.d.ts +2 -0
- package/dist/test/unit/long-bigint-exact.test.d.ts.map +1 -0
- package/dist/test/unit/long-bigint-exact.test.js +79 -0
- package/dist/test/unit/long-bigint-exact.test.js.map +1 -0
- package/dist/test/unit/lsp/completion-lexicon.test.d.ts +2 -0
- package/dist/test/unit/lsp/completion-lexicon.test.d.ts.map +1 -0
- package/dist/test/unit/lsp/completion-lexicon.test.js +83 -0
- package/dist/test/unit/lsp/completion-lexicon.test.js.map +1 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.d.ts +2 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.d.ts.map +1 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.js +187 -0
- package/dist/test/unit/lsp/tenant-vocabulary.test.js.map +1 -0
- package/dist/test/unit/map-builtins.test.js +163 -3
- package/dist/test/unit/map-builtins.test.js.map +1 -1
- package/dist/test/unit/map-structural-equality.test.d.ts +2 -0
- package/dist/test/unit/map-structural-equality.test.d.ts.map +1 -0
- package/dist/test/unit/map-structural-equality.test.js +64 -0
- package/dist/test/unit/map-structural-equality.test.js.map +1 -0
- package/dist/test/unit/map-type-guard.test.js +8 -5
- package/dist/test/unit/map-type-guard.test.js.map +1 -1
- package/dist/test/unit/mapping/candidate-generator.test.d.ts +2 -0
- package/dist/test/unit/mapping/candidate-generator.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/candidate-generator.test.js +177 -0
- package/dist/test/unit/mapping/candidate-generator.test.js.map +1 -0
- package/dist/test/unit/mapping/entity-proposer.test.d.ts +2 -0
- package/dist/test/unit/mapping/entity-proposer.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/entity-proposer.test.js +168 -0
- package/dist/test/unit/mapping/entity-proposer.test.js.map +1 -0
- package/dist/test/unit/mapping/mapping-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/mapping-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/mapping-ir.test.js +144 -0
- package/dist/test/unit/mapping/mapping-ir.test.js.map +1 -0
- package/dist/test/unit/mapping/proof-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/proof-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/proof-ir.test.js +119 -0
- package/dist/test/unit/mapping/proof-ir.test.js.map +1 -0
- package/dist/test/unit/mapping/quantity-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/quantity-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/quantity-ir.test.js +144 -0
- package/dist/test/unit/mapping/quantity-ir.test.js.map +1 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.d.ts +2 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.js +182 -0
- package/dist/test/unit/mapping/quantity-redos-property.test.js.map +1 -0
- package/dist/test/unit/mapping/redos-budget.test.d.ts +2 -0
- package/dist/test/unit/mapping/redos-budget.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/redos-budget.test.js +168 -0
- package/dist/test/unit/mapping/redos-budget.test.js.map +1 -0
- package/dist/test/unit/mapping/source-ir.test.d.ts +2 -0
- package/dist/test/unit/mapping/source-ir.test.d.ts.map +1 -0
- package/dist/test/unit/mapping/source-ir.test.js +113 -0
- package/dist/test/unit/mapping/source-ir.test.js.map +1 -0
- package/dist/test/unit/nodeid/change-impact.test.d.ts +2 -0
- package/dist/test/unit/nodeid/change-impact.test.d.ts.map +1 -0
- package/dist/test/unit/nodeid/change-impact.test.js +152 -0
- package/dist/test/unit/nodeid/change-impact.test.js.map +1 -0
- package/dist/test/unit/nodeid/rename-declaration.test.d.ts +2 -0
- package/dist/test/unit/nodeid/rename-declaration.test.d.ts.map +1 -0
- package/dist/test/unit/nodeid/rename-declaration.test.js +75 -0
- package/dist/test/unit/nodeid/rename-declaration.test.js.map +1 -0
- package/dist/test/unit/parse-type-recursion.test.d.ts +2 -0
- package/dist/test/unit/parse-type-recursion.test.d.ts.map +1 -0
- package/dist/test/unit/parse-type-recursion.test.js +58 -0
- package/dist/test/unit/parse-type-recursion.test.js.map +1 -0
- package/dist/test/unit/regex-guard.test.js +64 -0
- package/dist/test/unit/regex-guard.test.js.map +1 -1
- package/dist/test/unit/strict-int-coercion.test.d.ts +2 -0
- package/dist/test/unit/strict-int-coercion.test.d.ts.map +1 -0
- package/dist/test/unit/strict-int-coercion.test.js +96 -0
- package/dist/test/unit/strict-int-coercion.test.js.map +1 -0
- package/dist/test/unit/ufcs-receiver.test.d.ts +2 -0
- package/dist/test/unit/ufcs-receiver.test.d.ts.map +1 -0
- package/dist/test/unit/ufcs-receiver.test.js +75 -0
- package/dist/test/unit/ufcs-receiver.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { TextSpan } from './mapping-ir.js';
|
|
2
|
+
/**
|
|
3
|
+
* QuantityIR —— 从人类文档里**机械抽取**数量实体(ADR 0037 §2/§10.5)。
|
|
4
|
+
*
|
|
5
|
+
* <h2>为什么 Quantity 和 Entity 要分开</h2>
|
|
6
|
+
*
|
|
7
|
+
* ADR §2 把它们并列为 `Document/Section/Span/Entity/Quantity`,但实测两者的
|
|
8
|
+
* 可抽取性**完全不同**:
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* Quantity(金额/百分比/时长/日期) 有稳定的**形态特征** → 机械抽取,零 AI
|
|
12
|
+
* Entity (角色/主体/义务) **没有**形态特征 → 需要识别,LLM 的位置
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* 实测一份典型付款政策:
|
|
16
|
+
*
|
|
17
|
+
* ```
|
|
18
|
+
* 金额 $10,000 / $50,000 / $25 4 例 ← 正则可抽,100%
|
|
19
|
+
* 百分比 1.5% 1 例 ← 同上
|
|
20
|
+
* 时长 24 小时 1 例 ← 同上
|
|
21
|
+
* 日期 2026-01-01 / 2026-12-31 2 例 ← 同上
|
|
22
|
+
* 角色「财务经理」「部门主管」 2 例 ← **无任何可靠形态特征**
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* 本模块**只做 Quantity**。Entity 的接口在 {@link EntityCandidate} 声明,
|
|
26
|
+
* 但**不提供实现**——按 ADR §3/§10,那是 LLM 提出候选、由人复核的部分,
|
|
27
|
+
* 不该由本模块假装能机械得出。
|
|
28
|
+
*
|
|
29
|
+
* <h2>★与 MappingIR 的关系:本模块只负责「找到」,不负责「判定」</h2>
|
|
30
|
+
*
|
|
31
|
+
* 抽取出的 Quantity 是**候选映射的左半边**(文本片段 + 位置)。它是否真的对应
|
|
32
|
+
* 某个 IR 节点,仍由 `MappingIR.verifyMapping` 判定。本模块**不做任何语义断言**。
|
|
33
|
+
*/
|
|
34
|
+
/** 数量的类别。刻意小而封闭——每多一种就多一份误抽风险。 */
|
|
35
|
+
export type QuantityKind =
|
|
36
|
+
/** 货币金额(带货币符号)。 */
|
|
37
|
+
'MONEY'
|
|
38
|
+
/** 百分比。 */
|
|
39
|
+
| 'PERCENT'
|
|
40
|
+
/** 时长(含单位)。 */
|
|
41
|
+
| 'DURATION'
|
|
42
|
+
/** ISO 8601 日期。 */
|
|
43
|
+
| 'DATE';
|
|
44
|
+
export interface Quantity {
|
|
45
|
+
readonly kind: QuantityKind;
|
|
46
|
+
readonly span: TextSpan;
|
|
47
|
+
/** 原文片段,**逐字节**取自文档(与 SourceIR 同规则:不改内容)。 */
|
|
48
|
+
readonly text: string;
|
|
49
|
+
/**
|
|
50
|
+
* 规范化后的数值,**十进制字符串**。
|
|
51
|
+
*
|
|
52
|
+
* <p>★不用 `number`:金额/时长可能超出 JS 安全整数,过一次 number 就丢精度
|
|
53
|
+
* (本仓实测踩过 `9007199254740993` → `…992`)。与 `MappingIR` 的比较口径一致。
|
|
54
|
+
*
|
|
55
|
+
* <p>`DATE` 的 `value` 是 ISO 日期串本身(`2026-01-01`),不转成时间戳——
|
|
56
|
+
* 时间戳依赖时区,不是原文里的信息。
|
|
57
|
+
*/
|
|
58
|
+
readonly value: string;
|
|
59
|
+
/** 货币符号 / 时长单位;`PERCENT`、`DATE` 为 `undefined`。 */
|
|
60
|
+
readonly unit?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Entity 候选(角色、主体、义务这类**语义实体**)。
|
|
64
|
+
*
|
|
65
|
+
* <p>★本模块**不实现**它的抽取。Entity 没有可靠的形态特征——「财务经理」
|
|
66
|
+
* 与「财务报表」在字符层面无从区分,只能靠语义识别。按 ADR §3:
|
|
67
|
+
*
|
|
68
|
+
* ```
|
|
69
|
+
* LLM / 启发式 / 人 → 提出 EntityCandidate
|
|
70
|
+
* 确定性 verifier → 判定(但对 Entity 只能给 REVIEW_REQUIRED)
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* <p>此处声明接口是为了**把边界写进类型系统**:调用方一看就知道 Entity 必须
|
|
74
|
+
* 从外部传入,而不是指望本模块变出来。
|
|
75
|
+
*/
|
|
76
|
+
export interface EntityCandidate {
|
|
77
|
+
readonly span: TextSpan;
|
|
78
|
+
readonly text: string;
|
|
79
|
+
/** 提出者给出的类别(`Role` / `Party` / `Obligation` …),本模块不校验。 */
|
|
80
|
+
readonly proposedKind: string;
|
|
81
|
+
/** 谁提出的——与 `ProofIR.ProofSubject` 同源,便于追溯。 */
|
|
82
|
+
readonly proposedBy: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 从文档中抽取所有数量实体。
|
|
86
|
+
*
|
|
87
|
+
* <p>★**不做任何语义判断**——只按形态特征找出「这里有个数量」,以及它的
|
|
88
|
+
* 规范化数值。它是否对应某个 IR 节点,由 `MappingIR.verifyMapping` 判定。
|
|
89
|
+
*
|
|
90
|
+
* @returns 按出现位置升序;互不重叠
|
|
91
|
+
*/
|
|
92
|
+
export declare function extractQuantities(document: string): readonly Quantity[];
|
|
93
|
+
//# sourceMappingURL=quantity-ir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quantity-ir.d.ts","sourceRoot":"","sources":["../../../src/mapping/quantity-ir.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,kCAAkC;AAClC,MAAM,MAAM,YAAY;AACtB,mBAAmB;AACjB,OAAO;AACT,WAAW;GACT,SAAS;AACX,eAAe;GACb,UAAU;AACZ,mBAAmB;GACjB,MAAM,CAAC;AAEX,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAqCD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CA4DvE"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 抽取顺序**有意义**:先匹配的先占位,后面的不再重叠抽取。
|
|
3
|
+
*
|
|
4
|
+
* <p>★当前四类模式**几乎互斥**,唯一会相交的形态是 `$1.5%`:
|
|
5
|
+
* `MONEY` 匹配 `$1.5`、`PERCENT` 匹配 `1.5%`,区间重叠。此时**先声明者胜出**。
|
|
6
|
+
*
|
|
7
|
+
* <p>★我初稿在这里写了「MONEY 必须排在纯数字之前,否则 `$10,000` 会被拆成
|
|
8
|
+
* `10` 和 `000`」——**那是错的**:本模块根本没有「纯数字」模式,挪动 MONEY
|
|
9
|
+
* 的位置对 `$10,000` 毫无影响(已实测)。注释若声称一个并不存在的保护,
|
|
10
|
+
* 会误导后来者以为某处有约束而不敢动。
|
|
11
|
+
*/
|
|
12
|
+
const PATTERNS = [
|
|
13
|
+
// 货币:符号 + 数字(可含千分位与小数)。★`[$€£¥]` 本身就是左锚,无回溯问题。
|
|
14
|
+
{ kind: 'MONEY', re: /[$€£¥]\s?\d[\d,]*(?:\.\d+)?/g },
|
|
15
|
+
// ISO 日期:定长,无回溯问题。
|
|
16
|
+
{ kind: 'DATE', re: /\d{4}-\d{2}-\d{2}/g },
|
|
17
|
+
// ★以下两条必须带 `(?<![\d.])` 左锚——**这是 ReDoS 修复,不是可选优化**。
|
|
18
|
+
//
|
|
19
|
+
// 没有锚点时,`\d+` 会在**每个数字位置**重新起跑、贪婪吃到串尾,再因后缀
|
|
20
|
+
// (`%` / 单位)不匹配而整体回退。对长数字串就是 O(n²):
|
|
21
|
+
//
|
|
22
|
+
// 长度 5000 → 36ms
|
|
23
|
+
// 长度 10000 → 144ms ← 翻倍
|
|
24
|
+
// 长度 20000 → 576ms ← 再翻 4 倍
|
|
25
|
+
// 长度 40000 → 2304ms ← 实测确认二次增长
|
|
26
|
+
//
|
|
27
|
+
// 加锚后同样输入 **0ms**(左锚让每个起点 O(1) 失败,不再重新贪婪扫描)。
|
|
28
|
+
// ★语义完全不变:已逐例对照 9 组输入,新旧匹配结果逐字节相同。
|
|
29
|
+
//
|
|
30
|
+
// 本模块吃的是**人类文档**——攻击者可控的输入。没有这个锚点,一份构造过
|
|
31
|
+
// 的文档就能把抽取线程钉死。
|
|
32
|
+
{ kind: 'PERCENT', re: /(?<![\d.])\d+(?:\.\d+)?\s?%/g },
|
|
33
|
+
{ kind: 'DURATION', re: /(?<![\d.])\d+(?:\.\d+)?\s?(?:小时|分钟|天|秒|hours?|minutes?|days?|seconds?)/g },
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* 从文档中抽取所有数量实体。
|
|
37
|
+
*
|
|
38
|
+
* <p>★**不做任何语义判断**——只按形态特征找出「这里有个数量」,以及它的
|
|
39
|
+
* 规范化数值。它是否对应某个 IR 节点,由 `MappingIR.verifyMapping` 判定。
|
|
40
|
+
*
|
|
41
|
+
* @returns 按出现位置升序;互不重叠
|
|
42
|
+
*/
|
|
43
|
+
export function extractQuantities(document) {
|
|
44
|
+
const found = [];
|
|
45
|
+
// ★`claimed` 始终按 start 升序,用二分查重叠 —— 这是 **O(m²) 修复**。
|
|
46
|
+
//
|
|
47
|
+
// 原写法是 `claimed.some(c => ...)`:每个匹配都线性扫一遍已占位区间,
|
|
48
|
+
// m 个匹配总功 O(m²)。实测(多匹配载荷 `'1% '.repeat(n)`):
|
|
49
|
+
// 2000→12ms 4000→11ms 8000→35ms(×3.3) 16000→183ms(×5.2)
|
|
50
|
+
//
|
|
51
|
+
// ★这个缺陷**逃过了 §12.6 的 ReDoS 门禁**:那里的载荷是
|
|
52
|
+
// `'$' + '1'.repeat(40000)`——**只有一个匹配**,`claimed` 恒为 1,
|
|
53
|
+
// O(m²) 项永不激活。门禁量的是对的东西(增长率),但**语料有盲区**。
|
|
54
|
+
const claimed = [];
|
|
55
|
+
/** 二分定位第一个 `end > start` 的区间;只需检查它是否与 [start,end) 重叠。 */
|
|
56
|
+
const overlaps = (start, end) => {
|
|
57
|
+
let lo = 0;
|
|
58
|
+
let hi = claimed.length;
|
|
59
|
+
while (lo < hi) {
|
|
60
|
+
const mid = (lo + hi) >> 1;
|
|
61
|
+
if (claimed[mid].end <= start)
|
|
62
|
+
lo = mid + 1;
|
|
63
|
+
else
|
|
64
|
+
hi = mid;
|
|
65
|
+
}
|
|
66
|
+
// claimed 互不重叠且有序,故只有 lo 处那个区间可能与之相交。
|
|
67
|
+
return lo < claimed.length && claimed[lo].start < end;
|
|
68
|
+
};
|
|
69
|
+
/** 按 start 升序插入,维持 `claimed` 的有序不变式。 */
|
|
70
|
+
const insertClaimed = (start, end) => {
|
|
71
|
+
let lo = 0;
|
|
72
|
+
let hi = claimed.length;
|
|
73
|
+
while (lo < hi) {
|
|
74
|
+
const mid = (lo + hi) >> 1;
|
|
75
|
+
if (claimed[mid].start < start)
|
|
76
|
+
lo = mid + 1;
|
|
77
|
+
else
|
|
78
|
+
hi = mid;
|
|
79
|
+
}
|
|
80
|
+
claimed.splice(lo, 0, { start, end });
|
|
81
|
+
};
|
|
82
|
+
for (const { kind, re } of PATTERNS) {
|
|
83
|
+
re.lastIndex = 0;
|
|
84
|
+
for (let m = re.exec(document); m !== null; m = re.exec(document)) {
|
|
85
|
+
const start = m.index;
|
|
86
|
+
const end = start + m[0].length;
|
|
87
|
+
// ★后来者不得与已占位区间重叠:保证输出无重叠,且优先级由 PATTERNS 顺序决定。
|
|
88
|
+
if (overlaps(start, end))
|
|
89
|
+
continue;
|
|
90
|
+
const parsed = normalize(kind, m[0]);
|
|
91
|
+
if (parsed === undefined)
|
|
92
|
+
continue; // 形态像但规范化不出来 → 不抽,绝不编造
|
|
93
|
+
insertClaimed(start, end);
|
|
94
|
+
found.push({
|
|
95
|
+
kind, span: { start, end }, text: m[0],
|
|
96
|
+
value: parsed.value,
|
|
97
|
+
...(parsed.unit === undefined ? {} : { unit: parsed.unit }),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return found.sort((a, b) => a.span.start - b.span.start);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 把匹配到的文本规范化成「数值 + 单位」。
|
|
105
|
+
*
|
|
106
|
+
* <p>★返回 `undefined` = 规范化不出来(不抽取),**不是**抽成错的值。
|
|
107
|
+
*/
|
|
108
|
+
function normalize(kind, text) {
|
|
109
|
+
switch (kind) {
|
|
110
|
+
case 'DATE': {
|
|
111
|
+
// 日期保持原串——转时间戳会引入时区,那不是原文里的信息。
|
|
112
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(text) ? { value: text } : undefined;
|
|
113
|
+
}
|
|
114
|
+
case 'MONEY': {
|
|
115
|
+
const m = /^([$€£¥])\s?(\d[\d,]*(?:\.\d+)?)$/.exec(text);
|
|
116
|
+
if (m === null)
|
|
117
|
+
return undefined;
|
|
118
|
+
const value = canonicalDecimal(m[2].replace(/,/g, ''));
|
|
119
|
+
return value === undefined ? undefined : { value, unit: m[1] };
|
|
120
|
+
}
|
|
121
|
+
case 'PERCENT': {
|
|
122
|
+
const m = /^(\d+(?:\.\d+)?)\s?%$/.exec(text);
|
|
123
|
+
if (m === null)
|
|
124
|
+
return undefined;
|
|
125
|
+
const value = canonicalDecimal(m[1]);
|
|
126
|
+
return value === undefined ? undefined : { value };
|
|
127
|
+
}
|
|
128
|
+
case 'DURATION': {
|
|
129
|
+
const m = /^(\d+(?:\.\d+)?)\s?(.+)$/.exec(text);
|
|
130
|
+
if (m === null)
|
|
131
|
+
return undefined;
|
|
132
|
+
const value = canonicalDecimal(m[1]);
|
|
133
|
+
return value === undefined ? undefined : { value, unit: m[2] };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 规范成可比较的十进制字符串:去尾随零、去多余前导零。
|
|
139
|
+
*
|
|
140
|
+
* <p>★全程字符串运算,**不经过 JS number** —— 与 `MappingIR.canonicalDecimalString`
|
|
141
|
+
* 同口径,保证「文档里的 $10,000」与「IR 里的 Int 10000」能按值比对。
|
|
142
|
+
*/
|
|
143
|
+
function canonicalDecimal(s) {
|
|
144
|
+
const m = /^(\d+)(?:\.(\d*))?$/.exec(s.trim());
|
|
145
|
+
if (m === null)
|
|
146
|
+
return undefined;
|
|
147
|
+
const intPart = m[1].replace(/^0+(?=\d)/, '');
|
|
148
|
+
const frac = (m[2] ?? '').replace(/0+$/, '');
|
|
149
|
+
return frac.length > 0 ? `${intPart}.${frac}` : intPart;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=quantity-ir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quantity-ir.js","sourceRoot":"","sources":["../../../src/mapping/quantity-ir.ts"],"names":[],"mappings":"AAwFA;;;;;;;;;;GAUG;AACH,MAAM,QAAQ,GAAsD;IAClE,+CAA+C;IAC/C,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,8BAA8B,EAAE;IACrD,mBAAmB;IACnB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,oBAAoB,EAAE;IAC1C,oDAAoD;IACpD,EAAE;IACF,6CAA6C;IAC7C,sCAAsC;IACtC,EAAE;IACF,uBAAuB;IACvB,kCAAkC;IAClC,sCAAsC;IACtC,wCAAwC;IACxC,EAAE;IACF,+CAA+C;IAC/C,qCAAqC;IACrC,EAAE;IACF,0CAA0C;IAC1C,kBAAkB;IAClB,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,8BAA8B,EAAE;IACvD,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,yEAAyE,EAAE;CACpG,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,KAAK,GAAe,EAAE,CAAC;IAE7B,qDAAqD;IACrD,EAAE;IACF,mDAAmD;IACnD,+CAA+C;IAC/C,+DAA+D;IAC/D,EAAE;IACF,yCAAyC;IACzC,0DAA0D;IAC1D,2CAA2C;IAC3C,MAAM,OAAO,GAAqC,EAAE,CAAC;IAErD,yDAAyD;IACzD,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,GAAW,EAAW,EAAE;QACvD,IAAI,EAAE,GAAG,CAAC,CAAC;QACX,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACxB,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,OAAO,CAAC,GAAG,CAAE,CAAC,GAAG,IAAI,KAAK;gBAAE,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;;gBACxC,EAAE,GAAG,GAAG,CAAC;QAChB,CAAC;QACD,sCAAsC;QACtC,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,EAAE,CAAE,CAAC,KAAK,GAAG,GAAG,CAAC;IACzD,CAAC,CAAC;IAEF,wCAAwC;IACxC,MAAM,aAAa,GAAG,CAAC,KAAa,EAAE,GAAW,EAAQ,EAAE;QACzD,IAAI,EAAE,GAAG,CAAC,CAAC;QACX,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACxB,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,OAAO,CAAC,GAAG,CAAE,CAAC,KAAK,GAAG,KAAK;gBAAE,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;;gBACzC,EAAE,GAAG,GAAG,CAAC;QAChB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,QAAQ,EAAE,CAAC;QACpC,EAAE,CAAC,SAAS,GAAG,CAAC,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;YACtB,MAAM,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAChC,8CAA8C;YAC9C,IAAI,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;gBAAE,SAAS;YAEnC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,MAAM,KAAK,SAAS;gBAAE,SAAS,CAAC,uBAAuB;YAE3D,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACtC,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;aAC5D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,IAAkB,EAAE,IAAY;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,+BAA+B;YAC/B,OAAO,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzD,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YACjC,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YACxD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC;QAClE,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YACjC,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;YACtC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACrD,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,CAAC,GAAG,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YACjC,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;YACtC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC;QAClE,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,CAAS;IACjC,MAAM,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { TextSpan } from './mapping-ir.js';
|
|
2
|
+
/**
|
|
3
|
+
* SourceIR —— 人类 artifact 的结构化表示(ADR 0037 §2/§9.5)。
|
|
4
|
+
*
|
|
5
|
+
* <h2>它解决的问题,与 LayoutMap 不是同一个</h2>
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* LayoutMap(aster-dev/src/lib/layout-map.ts)
|
|
9
|
+
* display ↔ canonical,用于**本来就是 Aster 源码**的文本(《静夜思》demo)
|
|
10
|
+
* 手写、平铺、全文档逐字符覆盖 —— 20 字的诗可以,50 页的 Policy 不行
|
|
11
|
+
*
|
|
12
|
+
* SourceIR(本模块)
|
|
13
|
+
* **从未是 Aster** 的人类文档(Policy / SOP / 合同)的结构
|
|
14
|
+
* 机械推导、**嵌套**(标题层级)、只标结构不改内容
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* <h2>★唯一的硬约束:offset 必须可回切原文</h2>
|
|
18
|
+
*
|
|
19
|
+
* `MappingIR.TextSpan` 是**字符偏移**的。SourceIR 的每个节点都必须携带能**逐字节
|
|
20
|
+
* 切回原文**的 span,否则「文本片段 ↔ IR 节点」这条链在第一步就断了。
|
|
21
|
+
*
|
|
22
|
+
* 故本模块**不做任何文本改写**——不 trim、不规范化、不转义。节点只记
|
|
23
|
+
* 「这段文本在哪里、是什么结构角色」,内容永远从原文按 span 切。
|
|
24
|
+
*
|
|
25
|
+
* <p>★这条约束还带来一个可机械验证的不变式:
|
|
26
|
+
* {@link verifyCoverage} 检查所有叶子 span 拼起来是否**无重叠、无越界**。
|
|
27
|
+
* 没有它,一个错位的 span 会静默把映射指向错误的文本。
|
|
28
|
+
*/
|
|
29
|
+
/** 结构角色。刻意保持**小而封闭**——每多一种就多一份解析歧义。 */
|
|
30
|
+
export type SectionKind =
|
|
31
|
+
/** 整篇文档。 */
|
|
32
|
+
'DOCUMENT'
|
|
33
|
+
/** 标题及其管辖范围(`#`..`######`)。 */
|
|
34
|
+
| 'HEADING'
|
|
35
|
+
/** 普通段落。 */
|
|
36
|
+
| 'PARAGRAPH'
|
|
37
|
+
/** 列表项(`-` / `*` / `1.`)。 */
|
|
38
|
+
| 'LIST_ITEM'
|
|
39
|
+
/** 代码块(``` 围栏)——★内容不参与语义映射,但位置要占住,否则覆盖率对不上。 */
|
|
40
|
+
| 'CODE_BLOCK';
|
|
41
|
+
/**
|
|
42
|
+
* SourceIR 节点。
|
|
43
|
+
*
|
|
44
|
+
* <p>★`span` 指向**原始文档**的字符偏移;`text` 是冗余副本,便于调用方
|
|
45
|
+
* 独立核对(与 `MappingIR.CandidateMapping` 同样的设计——不依赖调用方重新切片)。
|
|
46
|
+
*/
|
|
47
|
+
export interface SourceNode {
|
|
48
|
+
/** 稳定标识,形如 `doc` / `doc.h[0]` / `doc.h[0].p[1]`。 */
|
|
49
|
+
readonly nodeId: string;
|
|
50
|
+
readonly kind: SectionKind;
|
|
51
|
+
readonly span: TextSpan;
|
|
52
|
+
readonly text: string;
|
|
53
|
+
/** 标题层级(1..6);非 HEADING 为 `undefined`。 */
|
|
54
|
+
readonly level?: number;
|
|
55
|
+
readonly children: readonly SourceNode[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 从 Markdown 文本推导 SourceIR。
|
|
59
|
+
*
|
|
60
|
+
* <p>★**只标结构,不改内容**。返回的每个节点都能用 `text.slice(span.start, span.end)`
|
|
61
|
+
* 逐字节切回原文——这由 {@link verifyCoverage} 机械验证。
|
|
62
|
+
*
|
|
63
|
+
* <p>选 Markdown 是因为它是本仓 Policy/SOP 的实际载体(实测
|
|
64
|
+
* `docs/p0a-signability-policy.md`:8 个标题、8 个列表项、19 个段落块)。
|
|
65
|
+
* 其他格式(docx/pdf)应当先转成 Markdown 再进本模块,而不是在这里堆解析器。
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseSourceIr(document: string): SourceNode;
|
|
68
|
+
/**
|
|
69
|
+
* 机械验证 SourceIR 的覆盖不变式。
|
|
70
|
+
*
|
|
71
|
+
* <p>检查每个节点的 `text` 是否**逐字节等于** `document.slice(span.start, span.end)`,
|
|
72
|
+
* 以及叶子节点之间**无重叠**。
|
|
73
|
+
*
|
|
74
|
+
* <p>★没有这道检查,一个错位的 span 会静默把映射指向错误的文本——不报错,
|
|
75
|
+
* 只是双向导航跳到别处。这与 `MappingIR` 里「span 与 text 必须自洽」同源。
|
|
76
|
+
*
|
|
77
|
+
* @returns 违规列表;空数组表示通过
|
|
78
|
+
*/
|
|
79
|
+
export declare function verifyCoverage(root: SourceNode, document: string): string[];
|
|
80
|
+
/** 找出包含某个字符偏移的**最深**节点——「点击原文 → 定位结构」的基础。 */
|
|
81
|
+
export declare function nodeAtOffset(root: SourceNode, offset: number): SourceNode | undefined;
|
|
82
|
+
//# sourceMappingURL=source-ir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-ir.d.ts","sourceRoot":"","sources":["../../../src/mapping/source-ir.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,uCAAuC;AACvC,MAAM,MAAM,WAAW;AACrB,YAAY;AACV,UAAU;AACZ,+BAA+B;GAC7B,SAAS;AACX,YAAY;GACV,WAAW;AACb,6BAA6B;GAC3B,WAAW;AACb,+CAA+C;GAC7C,YAAY,CAAC;AAEjB;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA6C1D;AAmBD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA4C3E;AAED,6CAA6C;AAC7C,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAOrF"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从 Markdown 文本推导 SourceIR。
|
|
3
|
+
*
|
|
4
|
+
* <p>★**只标结构,不改内容**。返回的每个节点都能用 `text.slice(span.start, span.end)`
|
|
5
|
+
* 逐字节切回原文——这由 {@link verifyCoverage} 机械验证。
|
|
6
|
+
*
|
|
7
|
+
* <p>选 Markdown 是因为它是本仓 Policy/SOP 的实际载体(实测
|
|
8
|
+
* `docs/p0a-signability-policy.md`:8 个标题、8 个列表项、19 个段落块)。
|
|
9
|
+
* 其他格式(docx/pdf)应当先转成 Markdown 再进本模块,而不是在这里堆解析器。
|
|
10
|
+
*/
|
|
11
|
+
export function parseSourceIr(document) {
|
|
12
|
+
// ★`text` 在 span 扩展后必须重算,否则 text 与 span 不再自洽(verifyCoverage 会抓)。
|
|
13
|
+
const blocks = splitBlocks(document);
|
|
14
|
+
const root = {
|
|
15
|
+
nodeId: 'doc', kind: 'DOCUMENT',
|
|
16
|
+
span: { start: 0, end: document.length },
|
|
17
|
+
text: document, children: [],
|
|
18
|
+
};
|
|
19
|
+
// 标题栈:栈顶是当前生效的最深标题。遇到同级或更浅的标题就出栈。
|
|
20
|
+
const stack = [];
|
|
21
|
+
const counters = new Map();
|
|
22
|
+
for (const block of blocks) {
|
|
23
|
+
const parent = stack.length > 0 ? stack[stack.length - 1].node : root;
|
|
24
|
+
const heading = matchHeading(block.text);
|
|
25
|
+
if (heading !== undefined) {
|
|
26
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= heading.level) {
|
|
27
|
+
stack.pop();
|
|
28
|
+
}
|
|
29
|
+
const host = stack.length > 0 ? stack[stack.length - 1].node : root;
|
|
30
|
+
const node = {
|
|
31
|
+
nodeId: nextId(counters, host.nodeId, 'h'),
|
|
32
|
+
kind: 'HEADING', span: block.span, text: block.text,
|
|
33
|
+
level: heading.level, children: [],
|
|
34
|
+
};
|
|
35
|
+
host.children.push(node);
|
|
36
|
+
stack.push({ level: heading.level, node });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const kind = classify(block.text);
|
|
40
|
+
parent.children.push({
|
|
41
|
+
nodeId: nextId(counters, parent.nodeId, prefixOf(kind)),
|
|
42
|
+
kind, span: block.span, text: block.text, children: [],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// ★HEADING 的 span 必须**覆盖其管辖范围**,而不只是标题那一行。
|
|
46
|
+
// 否则父子 span 不满足包含关系:`doc.h[0]` = [0,8) 而其子段落 = [17,42),
|
|
47
|
+
// `nodeAtOffset` 无法从父下降到子,「点击原文 → 定位结构」直接失效。
|
|
48
|
+
// 实测踩过:查 `$10,000` 的所在节点返回 DOCUMENT 而非那个段落。
|
|
49
|
+
extendHeadingSpans(root, document.length);
|
|
50
|
+
return freeze(root, document);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 把每个 HEADING 的 `span.end` 扩展到它最后一个后代的结尾。
|
|
54
|
+
*
|
|
55
|
+
* <p>★这使 span 树满足**包含不变式**(父覆盖子),这是 {@link nodeAtOffset}
|
|
56
|
+
* 能逐层下降的前提,也是 {@link verifyCoverage} 现在会检查的一条。
|
|
57
|
+
*
|
|
58
|
+
* <p>`text` 同步扩展——`text` 必须始终等于 `document.slice(span)`。
|
|
59
|
+
*/
|
|
60
|
+
function extendHeadingSpans(node, docLength) {
|
|
61
|
+
node.children.forEach(c => extendHeadingSpans(c, docLength));
|
|
62
|
+
if (node.kind !== 'HEADING' || node.children.length === 0)
|
|
63
|
+
return;
|
|
64
|
+
const lastEnd = Math.max(...node.children.map(c => c.span.end));
|
|
65
|
+
if (lastEnd > node.span.end) {
|
|
66
|
+
node.span = { start: node.span.start, end: lastEnd };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 机械验证 SourceIR 的覆盖不变式。
|
|
71
|
+
*
|
|
72
|
+
* <p>检查每个节点的 `text` 是否**逐字节等于** `document.slice(span.start, span.end)`,
|
|
73
|
+
* 以及叶子节点之间**无重叠**。
|
|
74
|
+
*
|
|
75
|
+
* <p>★没有这道检查,一个错位的 span 会静默把映射指向错误的文本——不报错,
|
|
76
|
+
* 只是双向导航跳到别处。这与 `MappingIR` 里「span 与 text 必须自洽」同源。
|
|
77
|
+
*
|
|
78
|
+
* @returns 违规列表;空数组表示通过
|
|
79
|
+
*/
|
|
80
|
+
export function verifyCoverage(root, document) {
|
|
81
|
+
const problems = [];
|
|
82
|
+
const leaves = [];
|
|
83
|
+
(function walk(n) {
|
|
84
|
+
const slice = document.slice(n.span.start, n.span.end);
|
|
85
|
+
if (slice !== n.text) {
|
|
86
|
+
problems.push(`${n.nodeId}: text 与 span 切片不符 —— span=[${n.span.start},${n.span.end}) `
|
|
87
|
+
+ `切片 ${JSON.stringify(slice.slice(0, 30))} vs text ${JSON.stringify(n.text.slice(0, 30))}`);
|
|
88
|
+
}
|
|
89
|
+
if (n.span.start < 0 || n.span.end > document.length || n.span.end < n.span.start) {
|
|
90
|
+
problems.push(`${n.nodeId}: span 越界或倒置 [${n.span.start},${n.span.end})`);
|
|
91
|
+
}
|
|
92
|
+
if (n.children.length === 0) {
|
|
93
|
+
leaves.push(n);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// ★包含不变式:父的 span 必须覆盖每个子。
|
|
97
|
+
// 没有这条,`doc.h[0]`=[0,8) 而其子段落=[17,42) 这种「子在父之外」
|
|
98
|
+
// 的树能悄悄通过——`nodeAtOffset` 无法下降,「点击原文→定位结构」
|
|
99
|
+
// 静默失效。实测踩过:查 $10,000 返回 DOCUMENT 而非那个段落。
|
|
100
|
+
for (const c of n.children) {
|
|
101
|
+
if (c.span.start < n.span.start || c.span.end > n.span.end) {
|
|
102
|
+
problems.push(`${c.nodeId} 不被父 ${n.nodeId} 包含:子 [${c.span.start},${c.span.end}) `
|
|
103
|
+
+ `父 [${n.span.start},${n.span.end})`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
n.children.forEach(walk);
|
|
107
|
+
}
|
|
108
|
+
})(root);
|
|
109
|
+
// 叶子按起点排序后,相邻两个不得重叠。
|
|
110
|
+
const sorted = [...leaves].sort((a, b) => a.span.start - b.span.start);
|
|
111
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
112
|
+
const prev = sorted[i - 1];
|
|
113
|
+
const cur = sorted[i];
|
|
114
|
+
if (cur.span.start < prev.span.end) {
|
|
115
|
+
problems.push(`叶子 span 重叠:${prev.nodeId} [${prev.span.start},${prev.span.end}) `
|
|
116
|
+
+ `与 ${cur.nodeId} [${cur.span.start},${cur.span.end})`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return problems;
|
|
120
|
+
}
|
|
121
|
+
/** 找出包含某个字符偏移的**最深**节点——「点击原文 → 定位结构」的基础。 */
|
|
122
|
+
export function nodeAtOffset(root, offset) {
|
|
123
|
+
if (offset < root.span.start || offset >= root.span.end)
|
|
124
|
+
return undefined;
|
|
125
|
+
for (const child of root.children) {
|
|
126
|
+
const hit = nodeAtOffset(child, offset);
|
|
127
|
+
if (hit !== undefined)
|
|
128
|
+
return hit;
|
|
129
|
+
}
|
|
130
|
+
return root;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 按空行切块,并**保留每块的精确偏移**。
|
|
134
|
+
*
|
|
135
|
+
* <p>★不能用 `split(/\n\s*\n/)` 然后累加长度——分隔符长度不固定(`\n\n` vs
|
|
136
|
+
* `\n \n`),累加会漂移。这里逐字符扫描,偏移由扫描位置直接给出。
|
|
137
|
+
*
|
|
138
|
+
* <p>围栏代码块(```)内的空行**不切**——否则一个代码块会被撕成多块,
|
|
139
|
+
* 而它的内容本就不该参与结构划分。
|
|
140
|
+
*/
|
|
141
|
+
function splitBlocks(doc) {
|
|
142
|
+
const blocks = [];
|
|
143
|
+
const lines = lineSpans(doc);
|
|
144
|
+
let fenced = false;
|
|
145
|
+
let cur = null;
|
|
146
|
+
const flush = () => {
|
|
147
|
+
if (cur === null)
|
|
148
|
+
return;
|
|
149
|
+
const text = doc.slice(cur.start, cur.end);
|
|
150
|
+
if (text.trim().length > 0)
|
|
151
|
+
blocks.push({ span: { ...cur }, text });
|
|
152
|
+
cur = null;
|
|
153
|
+
};
|
|
154
|
+
for (const ls of lines) {
|
|
155
|
+
const line = doc.slice(ls.start, ls.end);
|
|
156
|
+
if (/^\s*```/.test(line)) {
|
|
157
|
+
if (fenced) { // 收尾围栏:并入当前块后结束
|
|
158
|
+
if (cur !== null)
|
|
159
|
+
cur.end = ls.end;
|
|
160
|
+
fenced = false;
|
|
161
|
+
flush();
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
flush();
|
|
165
|
+
fenced = true;
|
|
166
|
+
cur = { start: ls.start, end: ls.end };
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (!fenced && line.trim().length === 0) {
|
|
171
|
+
flush();
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (cur === null)
|
|
175
|
+
cur = { start: ls.start, end: ls.end };
|
|
176
|
+
else
|
|
177
|
+
cur.end = ls.end;
|
|
178
|
+
}
|
|
179
|
+
flush();
|
|
180
|
+
return blocks;
|
|
181
|
+
}
|
|
182
|
+
/** 每行的 `[start, end)`,**不含**行尾换行(换行归入块间空隙)。 */
|
|
183
|
+
function lineSpans(doc) {
|
|
184
|
+
const out = [];
|
|
185
|
+
let start = 0;
|
|
186
|
+
for (let i = 0; i <= doc.length; i++) {
|
|
187
|
+
if (i === doc.length || doc[i] === '\n') {
|
|
188
|
+
out.push({ start, end: i });
|
|
189
|
+
start = i + 1;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
function matchHeading(text) {
|
|
195
|
+
const m = /^(#{1,6})\s+\S/.exec(text);
|
|
196
|
+
return m === null ? undefined : { level: m[1].length };
|
|
197
|
+
}
|
|
198
|
+
function classify(text) {
|
|
199
|
+
if (/^\s*```/.test(text))
|
|
200
|
+
return 'CODE_BLOCK';
|
|
201
|
+
if (/^\s*(?:[-*+]\s|\d+\.\s)/.test(text))
|
|
202
|
+
return 'LIST_ITEM';
|
|
203
|
+
return 'PARAGRAPH';
|
|
204
|
+
}
|
|
205
|
+
function prefixOf(kind) {
|
|
206
|
+
switch (kind) {
|
|
207
|
+
case 'LIST_ITEM': return 'li';
|
|
208
|
+
case 'CODE_BLOCK': return 'code';
|
|
209
|
+
default: return 'p';
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** 在**同一父节点**下按前缀递增编号——保证 nodeId 在文档内唯一且可预测。 */
|
|
213
|
+
function nextId(counters, parentId, prefix) {
|
|
214
|
+
let byPrefix = counters.get(parentId);
|
|
215
|
+
if (byPrefix === undefined) {
|
|
216
|
+
byPrefix = new Map();
|
|
217
|
+
counters.set(parentId, byPrefix);
|
|
218
|
+
}
|
|
219
|
+
const n = byPrefix.get(prefix) ?? 0;
|
|
220
|
+
byPrefix.set(prefix, n + 1);
|
|
221
|
+
return `${parentId}.${prefix}[${n}]`;
|
|
222
|
+
}
|
|
223
|
+
function freeze(n, document) {
|
|
224
|
+
const children = n.children.map(c => freeze(c, document));
|
|
225
|
+
if (document !== undefined)
|
|
226
|
+
n.text = document.slice(n.span.start, n.span.end);
|
|
227
|
+
return n.level === undefined
|
|
228
|
+
? { nodeId: n.nodeId, kind: n.kind, span: n.span, text: n.text, children }
|
|
229
|
+
: { nodeId: n.nodeId, kind: n.kind, span: n.span, text: n.text, level: n.level, children };
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=source-ir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-ir.js","sourceRoot":"","sources":["../../../src/mapping/source-ir.ts"],"names":[],"mappings":"AA4DA;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,iEAAiE;IACjE,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,IAAI,GAAgB;QACxB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU;QAC/B,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,EAAE;QACxC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;KAC7B,CAAC;IAEF,kCAAkC;IAClC,MAAM,KAAK,GAA2C,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;IAExD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACvE,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEzC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC3E,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACrE,MAAM,IAAI,GAAgB;gBACxB,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;gBAC1C,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI;gBACnD,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;aACnC,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YACnB,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YACvD,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;SACvD,CAAC,CAAC;IACL,CAAC;IAED,2CAA2C;IAC3C,0DAA0D;IAC1D,+CAA+C;IAC/C,8CAA8C;IAC9C,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,kBAAkB,CAAC,IAAiB,EAAE,SAAiB;IAC9D,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAClE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;IACvD,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,QAAgB;IAC/D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,CAAC,SAAS,IAAI,CAAC,CAAa;QAC1B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvD,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CACX,GAAG,CAAC,CAAC,MAAM,+BAA+B,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI;kBACtE,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAClF,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,0BAA0B;YAC1B,kDAAkD;YAClD,6CAA6C;YAC7C,4CAA4C;YAC5C,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC3B,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;oBAC3D,QAAQ,CAAC,IAAI,CACX,GAAG,CAAC,CAAC,MAAM,QAAQ,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI;0BACjE,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC;YACD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAET,qBAAqB;IACrB,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACvB,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CACX,cAAc,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI;kBAChE,KAAK,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,YAAY,CAAC,IAAgB,EAAE,MAAc;IAC3D,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC1E,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACxC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAeD;;;;;;;;GAQG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,GAAG,GAA0C,IAAI,CAAC;IAEtD,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,GAAG,GAAG,IAAI,CAAC;IACb,CAAC,CAAC;IAEF,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,IAAI,MAAM,EAAE,CAAC,CAAC,gBAAgB;gBAC5B,IAAI,GAAG,KAAK,IAAI;oBAAE,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;gBACnC,MAAM,GAAG,KAAK,CAAC;gBACf,KAAK,EAAE,CAAC;YACV,CAAC;iBAAM,CAAC;gBACN,KAAK,EAAE,CAAC;gBACR,MAAM,GAAG,IAAI,CAAC;gBACd,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;YACzC,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAAC,KAAK,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QAC/D,IAAI,GAAG,KAAK,IAAI;YAAE,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;;YACpD,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;IACxB,CAAC;IACD,KAAK,EAAE,CAAC;IACR,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+CAA+C;AAC/C,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,GAAG,GAAqC,EAAE,CAAC;IACjD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACxC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC5B,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,CAAC,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,MAAM,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC;IAC9C,IAAI,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,WAAW,CAAC;IAC7D,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,QAAQ,CAAC,IAAiB;IACjC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW,CAAC,CAAC,OAAO,IAAI,CAAC;QAC9B,KAAK,YAAY,CAAC,CAAC,OAAO,MAAM,CAAC;QACjC,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC;IACtB,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,SAAS,MAAM,CAAC,QAA0C,EAAE,QAAgB,EAAE,MAAc;IAC1F,IAAI,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAAC,CAAC;IACvF,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,OAAO,GAAG,QAAQ,IAAI,MAAM,IAAI,CAAC,GAAG,CAAC;AACvC,CAAC;AAED,SAAS,MAAM,CAAC,CAAc,EAAE,QAAiB;IAC/C,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1D,IAAI,QAAQ,KAAK,SAAS;QAAE,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9E,OAAO,CAAC,CAAC,KAAK,KAAK,SAAS;QAC1B,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE;QAC1E,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC/F,CAAC"}
|