@endo/patterns
可通过数据的匹配和验证模式,包括复制收集以及 界面保护.
概览
这个 @ endo/ patters( 签名) 软件包提供 M 创建模式的命名空间
匹配者可以验证可通过的数据,并描述行为合同.
这是上面的验证层 @ endo/ pass 风格, (中文(简体) ),
允许您在使用前检查与预期形状相匹配的数据.
模式使:
- 数据验证: 检查符合预期类型和结构的值
- 接口合同: 描述带有界面守护符的方法签名
- 复制收藏: CopySet, CopyBag, CopyMap 可通过的数据结构
- 关键比较: 分布式平等,用于比较不同瓦特的数值
快速启动
import { M, mustMatch } from '@endo/patterns';
const specimen = harden({ foo: 3, bar: 4 });
const pattern = M.splitRecord(
{ foo: M.number() }, // required properties
{ bar: M.string(), baz: M.number() } // optional properties
);
mustMatch(specimen, pattern);
// throws: 'bar?: number 4 - Must be a string'
为了最佳渲染效果,请使用 Endo 参考文件 网站.
M 命名空间
这个 M 对象提供了创建图案匹配器的方法
几类:
初级火柴
匹配特定的 JavaScript 类型 :
M.any() // Matches any passable
M.undefined() // Matches undefined
M.null() // Matches null
M.boolean() // Matches true or false
M.number() // Matches any number (including NaN, Infinity)
M.bigint() // Matches any bigint
M.string() // Matches any string
M.symbol() // Matches registered/well-known symbols
// Constrained primitives
M.nat() // Non-negative bigint
M.gte(5) // Number >= 5
M.lte(100) // Number <= 100
集装箱火柴
匹配复制本、复制记录和其他结构 :
M.array() // Any CopyArray
M.record() // Any CopyRecord
M.set() // Any CopySet
M.bag() // Any CopyBag
M.map() // Any CopyMap
// With constraints
M.array({ maxSize: 10 }) // Array with at most 10 elements
M.string({ maxSize: 100 }) // String with at most 100 characters
// Structured content
M.arrayOf(M.number()) // Array of numbers only
M.recordOf(M.string(), M.number()) // Record with string keys, number values
M.setOf(M.string()) // Set of strings only
结构匹配器
匹配特定形状 :
// Split patterns: required, optional, rest
M.splitArray(
[M.string(), M.number()], // required elements
[M.boolean()], // optional elements
M.any() // rest elements
)
M.splitRecord(
{ name: M.string() }, // required properties
{ age: M.number() }, // optional properties
M.any() // rest properties
)
// Partial matches
M.partial({ name: M.string() }) // Has at least 'name' property
// Split auto-detects array vs record
M.split({ x: M.number() }, M.any())
逻辑运算符
组合匹配者 :
M.and(M.number(), M.gte(0), M.lte(100)) // 0 <= n <= 100
M.or(M.string(), M.number()) // String or number
M.not(M.undefined()) // Anything except undefined
M.opt(M.string()) // undefined or string (optional)
比较匹配符
匹配比对密钥的值 :
M.eq('hello') // Equal to 'hello'
M.neq(0) // Not equal to 0
M.lt(10) // Less than 10
M.lte(100) // Less than or equal to 100
M.gte(0) // Greater than or equal to 0
M.gt(-1) // Greater than -1
特殊火柴
M.remotable() // Any remotable object
M.remotable('Counter') // Remotable with specific label
M.error() // Any error
M.promise() // Any promise
M.eref(M.number()) // Number or promise for number (eventual reference)
M.kind('copyArray') // Specific pass style
M.pattern() // Any valid pattern
M.key() // Any valid Key
M.scalar() // Any primitive or remotable
模式匹配
匹配( specimen,图案)
回返 true 如果标本符合模式, false 否则:
import { M, matches } from '@endo/patterns';
matches(42, M.number()); // true
matches('hello', M.number()); // false
matches([1, 2, 3], M.arrayOf(M.number())); // true
mustMatch( specimen, 模式, 标签 )
如果标本不匹配, 则带有描述错误 :
import { mustMatch } from '@endo/patterns';
mustMatch(42, M.string());
// throws: "number 42 - Must be a string"
mustMatch(-5, M.and(M.number(), M.gte(0)), 'count');
// throws: "count: number -5 - Must be >= 0"
错误消息旨在帮助您准确理解错误 与数据.
复制收藏
模式引入了基于三种可通行的收藏类型 makeTagged()数字 :
复制集
一组独有的密钥(原始或可再移动的密钥):
import { makeCopySet } from '@endo/patterns';
const colors = makeCopySet(['red', 'blue', 'green']);
// Elements are sorted in rank order
// Duplicates are removed
// Can be passed between vats
// Pattern for sets
const ColorSet = M.setOf(M.string());
mustMatch(colors, ColorSet); // passes
为什么不使用 JavaScript 集 ?
Java 脚本 设定不能通过.
CopySet被冻结,通过 keyEQ,可以高效地序列化.
复制文件夹
多集( 有计数要素) :
import { makeCopyBag } from '@endo/patterns';
const inventory = makeCopyBag([
['apples', 5n],
['oranges', 3n],
['apples', 2n] // counts are combined
]);
// Result: [['apples', 7n], ['oranges', 3n]]
const InventoryPattern = M.bagOf(M.string(), M.bigint());
mustMatch(inventory, InventoryPattern);
复制地图
从密钥到通过值的映射 :
import { makeCopyMap } from '@endo/patterns';
const balances = makeCopyMap([
['alice', 100],
['bob', 50]
]);
// Keys are sorted in rank order
// Can use any Key as a key (not just strings!)
const remotableKey = Far('Key', {});
const map = makeCopyMap([[remotableKey, 'value']]);
const BalancesPattern = M.mapOf(M.string(), M.number());
mustMatch(balances, BalancesPattern);
为什么不使用普通物体? 复制映射支持 :
- 任意密钥作为密钥( 对象, 可调动, 不仅仅是字符串)
- 使用有效的密钥比较
compareKeys() - 用于部分排序的子集关系
界面守护
界面保护描述对象的行为契约, 尤其有用 与 @ endo/ exo (帮助)数字 :
创建界面保护
import { M } from '@endo/patterns';
const CounterI = M.interface('Counter', {
// Synchronous method
increment: M.call(M.number()).returns(M.number()),
// Method with optional arguments
reset: M.call().optional(M.number()).returns(),
// Method with rest arguments
add: M.call(M.number()).rest(M.number()).returns(M.number()),
// Async method (awaits arguments)
asyncOp: M.callWhen(M.string()).returns(M.string())
});
方法守护结构
// Basic call: call(required args...)
M.call(M.string(), M.number())
// With optional args
M.call(M.string()).optional(M.number())
// With rest args
M.call(M.string()).rest(M.any())
// Specify return type
M.call(M.string()).returns(M.number())
// Async method (awaits promise args)
M.callWhen(M.remotable()).returns(M.string())
与 Exo 合并
界面保护由 exos 自动执行 :
import { makeExo } from '@endo/exo';
import { M } from '@endo/patterns';
const CounterI = M.interface('Counter', {
increment: M.call(M.number()).returns(M.number())
});
const counter = makeExo('Counter', CounterI, {
increment(n) {
// n is guaranteed to be a number by the guard
return count += n;
}
});
counter.increment(5); // OK
counter.increment('5'); // throws: Must be a number
这是远藤防御性编程的基础:卫兵验证输入 自动,因此您的方法可以专注于商业逻辑.
密钥比较
平等与秩序的密钥可以比较:
键EQ( 键 1, 键2)
使用分布式平等语义测试两个密钥是否相等 :
import { keyEQ } from '@endo/patterns';
keyEQ('hello', 'hello'); // true
keyEQ(42, 42); // true
keyEQ([1, 2], [1, 2]); // true (compares content)
const r1 = Far('Obj', {});
const r2 = Far('Obj', {});
keyEQ(r1, r1); // true (same remotable)
keyEQ(r1, r2); // false (different remotables)
比较 Keys( key1, key2)
返回比较结果 部分顺序数字 :
0: 键相等-1: 键 1 < 键 21: 键 1 > 键 2NaN: 密钥不可比
import { compareKeys, keyLT, keyGT } from '@endo/patterns';
compareKeys('a', 'b'); // -1
compareKeys(5, 5); // 0
compareKeys(10, 3); // 1
// Convenience functions
keyLT('a', 'b'); // true
keyGT(10, 3); // true
// Incomparable keys
const r1 = Far('A', {});
const r2 = Far('B', {});
compareKeys(r1, r2); // NaN (different remotables)
为什么是局部命令? 并不是所有的键都可以比较. 例如,不同的可移动性没有定义的顺序, CopySets 使用 子集关系.
密钥、图案和可通行等级
了解类型等级 :
Passable (everything that can pass)
├── Error
├── Promise
├── Key (stable, comparable)
│ ├── Primitives (null, undefined, boolean, number, bigint, string, symbol)
│ ├── Remotable
│ ├── CopyArray<Key>
│ ├── CopyRecord<Key>
│ ├── CopySet<Key>
│ ├── CopyBag<Key>
│ └── CopyMap<Key, Passable>
└── Pattern (describes a set of Passables)
├── Key (matches itself)
└── Key-like with Matcher leaves
- 可通行: 能够跨越瓦特边界(来自 @endo/pass-tyle)
- 密钥: 可通行性中稳定和可比较的子集
- 图案: 描述匹配的可通性子集
与 Endo 软件包集成
- 基金会数字 : @ endo/ pass 风格 - 会是什么 已通过(密码)
- 执行数字 : @ endo/ exo (帮助) - 使用界面保护 自动验证
- 通讯数字 : @ endo/ eventual- send (日语) - 发送 给已验证对象的信件
完成教学: 见 消息传递 页:1 综合指南,说明模式如何与通行证式、exo和 最终发送.
深潜
详细执行情况: