-
Notifications
You must be signed in to change notification settings - Fork 0
Typed Document
Typed Document (TDoc)
适用版本:4.0.0。
Applies to 4.0.0.
首页 · 脚本 TDoc API · .NET TDoc API
Introduction
TDoc 是 AuroraScript 的带类型文本数据格式。它将一个 AuroraScript 值写成独立文档,并在读取时恢复普通对象、数组、Packed Array、Date、Path、Regex、HashMap、StringBuffer 与宿主已注册的 CLR/CIL 对象。
TDoc is AuroraScript's typed text-data format. It writes one AuroraScript value as a standalone document and restores ordinary objects, arrays, packed arrays,
Date,Path,Regex,HashMap,StringBuffer, and host-registered CLR/CIL objects when read.
独立 TDoc 文档不是第二套脚本语法:文档内容不会执行代码,也不支持变量、函数调用、脚本 tdoc 标记或内联表达式,并且从根值直接开始。
A standalone TDoc document is not a second scripting syntax: its content does not execute code and does not support variables, calls, the script
tdocmarker, or inline expressions; it starts directly with its root value.
Use Cases
- 保存需要保留 AuroraScript 类型身份的配置、快照或持久化状态。
Persist configuration, snapshots, or state that must retain AuroraScript type identity.
- 在同一 AuroraScript 宿主之间交换数据,并且需要保留 Packed Array 或
Date等类型。Exchange data between AuroraScript hosts when types such as packed arrays or
Datemust be preserved. - 将经
AuroraEngine.RegisterType明确注册的 CLR/CIL 对象写入受控数据契约。Write CLR/CIL objects explicitly registered through
AuroraEngine.RegisterTypeinto a controlled data contract.
TDoc 不会将运行时行为当成持久化数据。写入时,函数、代理、访问器属性、未注册 CLR/CIL 对象、非有限 Number,以及已在当前文档中出现过的循环/共享引用都会按“可跳过值”处理,而不是使整个 stringify 失败。
TDoc does not treat runtime behavior as persistent data. When writing, functions, proxies, accessor properties, unregistered CLR/CIL objects, non-finite Numbers, and circular/shared references already seen in the current document are treated as skippable values rather than failing the entire
stringify.
Quick Example
Object {
readonly String id "u-001",
String name "Aurora",
Number version 4,
Int8Array payload [-128, 0, 127],
Date createdAt "2026-08-20 10:00:00",
}
上面的文档根值是 ScriptObject;id 是浅只读属性,payload 保持为 ScriptInt8Array,而不是一般 Array。
The root value above is a
ScriptObject;idis a shallow read-only property andpayloadremains aScriptInt8Array, rather than becoming a generalArray.
脚本中使用 TDoc:
Use
TDocin scripts:
var profile = TDoc.parse('Object { String name "Aurora", Int8Array levels [1, 2] }');
var text = TDoc.stringify(profile, false);
return text;宿主中使用 AuroraTypedDocument:
Use
AuroraTypedDocumentin a host:
var tdoc = new AuroraTypedDocument(engine);
var text = tdoc.Serialize(ScriptDatum.FromString("Aurora"));
var value = tdoc.Deserialize(text);Native
tdocLiterals in Scripts
在 .as 脚本中,可以用小写 tdoc 直接构造一个 TDoc 值。它是编译器识别的表达式边界,不是 TDoc 全局对象的方法调用;结果是普通的 AuroraScript 运行时值,可以赋给变量、作为返回值或放在模块初始化器中。
In an
.asscript, lowercasetdocconstructs a TDoc value directly. It is a compiler-recognized expression boundary, not a method call on theTDocglobal; the result is a normal AuroraScript runtime value that can be assigned, returned, or created in a module initializer.
Basic Syntax
func createProfile(user, baseAge) {
return tdoc Object {
readonly String id $(user.id),
name "Aurora",
age $(baseAge + 1),
tags [String "system", Number 4],
};
}
语法形状如下:
The syntax shape is:
tdoc-literal = "tdoc" typed-value ;
typed-value = [ type-name ] raw-value ;
raw-value = "null" | boolean | number | string | array | object | interpolation ;
array = "[" [ typed-value { "," typed-value } [ "," ] ] "]" ;
object = "{" [ member { "," member } [ "," ] ] "}" ;
member = [ "readonly" ] [ type-name ] property-name raw-value ;
property-name = identifier | string ;
interpolation = "$(" aurora-expression ")" ;-
tdoc必须使用小写,并且后面必须紧跟一个 TDoc 值;独立.tdoc文件不写这个前缀。tdocis lowercase and must be followed by one TDoc value; standalone.tdocfiles do not write this prefix. - 类型名是可选的。
Object、Array、String、Number和Boolean等可由字面量唯一推断的类型可以省略;Int8Array、Date、Path、Regex、HashMap和StringBuffer等内置类型可以显式写出以保留身份。The type name is optional. Types uniquely inferred from their literals, such as
Object,Array,String,Number, andBoolean, may be omitted; built-in types such asInt8Array,Date,Path,Regex,HashMap, andStringBuffermay be written explicitly to preserve identity. - 脚本原生字面量不会通过类型名构造注册的 CLR/CIL 对象;已有实例可以通过
$()注入。注册类型别名的文本读写由TDoc.parse、TDoc.stringify和宿主AuroraTypedDocumentAPI 负责。Native script literals do not construct registered CLR/CIL objects from a type name; an existing instance may be supplied through
$(). Text round-tripping of registered aliases is provided byTDoc.parse,TDoc.stringify, and the hostAuroraTypedDocumentAPI. - 对象成员使用空格分隔的
类型名 属性名 值形式,不使用:。只有一个标识符时,它是属性名,例如name "Aurora";两个连续标识符表示String name "Aurora"这样的显式类型和属性名。Object members use space-separated
type-name property-name valuesyntax, not:. With one identifier it is a property name, such asname "Aurora"; two adjacent identifiers mean an explicit type and property name, such asString name "Aurora". -
readonly只能修饰对象成员,作用是浅层只读属性;它不会冻结属性值内部的对象。readonlyapplies only to object members and creates a shallow read-only property; it does not freeze an object stored in that property.
Dynamic Values
只有值位置允许使用 $()。括号内是普通 AuroraScript 表达式,在脚本运行时求值;数组元素、对象成员值和根值都可以使用它。
Only value positions accept
$(). The contents are ordinary AuroraScript expressions evaluated at script runtime; it can be used for array elements, object member values, and the root value.
func createProfile(user, baseAge) {
return tdoc Object {
readonly String id $(user.id),
role $(user.role),
age $(baseAge + 1),
tags [$(user.role), "system"],
};
}
属性名和类型名必须是静态文本,不支持动态注入:
Property names and type names must be static text; dynamic injection is not supported:
tdoc Object { $(key) "value" } // invalid: dynamic property name
tdoc $(typeName) { enabled true } // invalid: dynamic type name
TDoc 纯数据部分不会执行函数调用或其他脚本表达式;需要动态计算时必须明确写在 $() 中。模板字符串、任意一元表达式和未包裹的函数调用不能直接作为 TDoc 值。
The pure TDoc data portion does not execute calls or other script expressions; dynamic computation must be explicit inside
$(). Template strings, arbitrary unary expressions, and unwrapped calls cannot be used directly as TDoc values.
Boundary with Standalone
.tdocDocuments
脚本原生字面量和独立文档共享对象、数组、类型名、尾逗号和 readonly 语法,但入口不同:
Native script literals and standalone documents share objects, arrays, type names, trailing commas, and
readonly, but their entry points differ:
| 入口 | 根值写法 | $() |
典型用途 |
|---|---|---|---|
.as 脚本 |
tdoc Object { ... } |
允许,仅用于值 | 在代码中构造配置或请求 |
.tdoc 文件 / TDoc.parse
|
Object { ... } |
禁止 | 配置、持久化和宿主交换 |
Entry Root syntax $()Typical use .asscripttdoc Object { ... }Allowed for values only Construct configuration or requests in code .tdocfile /TDoc.parseObject { ... }Forbidden Configuration, persistence, and host exchange
tdoc 表达式本身不会产生文本。需要文本时调用 TDoc.stringify(value, indented, emitTypes);需要从文本恢复值时调用 TDoc.parse(text)。独立 .tdoc 文件不能包含变量、函数调用或 $()。
A
tdocexpression does not produce text by itself. CallTDoc.stringify(value, indented, emitTypes)when text is needed, andTDoc.parse(text)to restore a value from text. Standalone.tdocfiles cannot contain variables, calls, or$().
Object View and Skippable Values
普通 ScriptObject 会按脚本可见的可枚举属性写入:先取自身属性,再沿 prototype 链取未被遮蔽的属性。写入后的 TDoc 是一个扁平对象;prototype 身份、原型链和访问器本身不会保留。
An ordinary
ScriptObjectis written from its script-visible enumerable properties: own properties first, then unshadowed properties along its prototype chain. The resulting TDoc is a flat object; prototype identity, the prototype chain, and accessors themselves are not preserved.
stringify 遇到不可表示的运行时值时采用固定的无异常降级规则:对象属性(包括从 prototype 看到的属性)会被省略;数组元素会写为 null 以保持索引;HashMap 条目中的不可表示键或值会写为 null;根值不可表示时结果为 null。因此 TDoc 是数据快照,不是完整对象图的保真克隆。
stringifyuses fixed, non-throwing degradation for unrepresentable runtime values: object properties (including properties visible through a prototype) are omitted; array elements becomenullto preserve indices; an unrepresentable key or value in aHashMapentry becomesnull; and an unrepresentable root becomesnull. TDoc is therefore a data snapshot, not a lossless clone of a full object graph.
var action = () => true;
var value = { name: "Aurora", cancel: action, values: [1, action, 3] };
TDoc.stringify(value, false);
// {name "Aurora",values [1,null,3,],}Text Structure
一个文档只允许一个根值。类型名可显式写出;未写出时,只有原始字面量可唯一确定的类型会自动推断。
A document permits one root value. A type name may be explicit; when it is absent, only values uniquely determined by their raw literal are inferred automatically.
document = typed-value EOF ;
typed-value = [ type-name ] raw-value ;
raw-value = "null" | boolean | number | string | array | object ;
array = "[" [ typed-value { "," typed-value } [ "," ] ] "]" ;
object = "{" [ member { "," member } [ "," ] ] "}" ;
member = [ "readonly" ] [ type-name ] property-name raw-value ;
property-name = identifier | string ;
type-name = identifier ;对象成员中,两个连续标识符表示“类型名 + 属性名”;只有一个标识符时,它是属性名。例如 String name "Aurora" 显式声明 String,而 name "Aurora" 让读取器推断字符串。
In an object member, two consecutive identifiers mean “type name + property name”; one identifier is the property name. For example,
String name "Aurora"explicitly declaresString, whilename "Aurora"lets the reader infer a string.
字符串值必须使用单引号或双引号。Object { id UX01 } 和 Object { id UX01-03 } 都无效:前者中的 UX01 是标识符位置,后者的 - 也不属于标识符。请写为 Object { id "UX01" } 或 Object { id "UX01-03" }。
String values must use single or double quotes.
Object { id UX01 }andObject { id UX01-03 }are both invalid:UX01is in an identifier position in the former, and-is not part of an identifier in the latter. WriteObject { id "UX01" }orObject { id "UX01-03" }instead.
支持 // 行注释、/* ... */ 块注释和尾逗号。脚本 tdoc 标记在独立文档中无效并会产生语法错误。
Line comments (
//), block comments (/* ... */), and trailing commas are supported. The scripttdocmarker is invalid in standalone documents and produces a syntax error.
Types and Inference
| 文本形状 | 读取结果 | 默认是否输出类型名 |
|---|---|---|
null |
Null |
否 |
true / false
|
Boolean |
否 |
42 / 1.5 / 0xFF
|
Number(double) |
否 |
"text" / 'text'
|
String |
否 |
[ ... ] |
ScriptArray |
否 |
{ ... } |
ScriptObject |
否 |
StringBuffer "text" |
StringBuffer |
是 |
Date "..." / Date 14425655658
|
ScriptDate |
是 |
Regex { ... } |
ScriptRegex |
是 |
Path "a/b.as" |
ScriptPathValue |
是 |
HashMap [[key, value]] |
ScriptHashMap |
是 |
Int32Array / Int8Array / Float64Array / BooleanArray
|
对应 Packed Array | 始终是 |
已注册类型,例如 User { ... }
|
已注册 CLR/CIL 实例 | 始终是 |
The table lists read results and whether a type name is emitted by default.
默认 EmitTypeNames 为 false,写入器仅输出无法由原始字面量唯一推断的类型名。Object、Array、String、Number 与 Boolean 默认省略;Date、所有对象形内置类型、所有 Packed Array 和注册 CLR/CIL 类型仍强制输出类型名。将 EmitTypeNames 设为 true 可强制输出所有可用类型名。
EmitTypeNamesdefaults tofalse, so the writer emits only type names that cannot be uniquely inferred from raw literals.Object,Array,String,Number, andBooleanare omitted by default;Date, all object-like built-ins, all packed arrays, and registered CLR/CIL types still force a type name. SetEmitTypeNamestotrueto force every available type name.
// default: EmitTypeNames = false
{ name "Aurora", Int8Array bytes [1, 2] }
// EmitTypeNames = true
Object { String name "Aurora", Int8Array bytes [1, 2] }
readonlyProperties
readonly 是对象属性描述符,不是类型。它使该属性不能再次写入,但不会冻结其对象值。
readonlyis an object-property descriptor, not a type. It prevents the property from being written again, but does not freeze its object value.
Object {
readonly Object settings { retries 3 },
}
读取后 settings = other 会失败,而 settings.retries = 4 仍然可以执行。TDoc 写入器会保留 readonly 标记。
After reading,
settings = otherfails, whilesettings.retries = 4remains valid. The TDoc writer preserves thereadonlymarker.
Date, Regex, and HashMap
Date 的字符串形式必须匹配当前 AuroraEngine 的 EngineOptions.Runtime.DateTimeFormat;数值形式是 .NET ticks,必须是有效整数范围。写入时始终按引擎日期格式输出字符串。
A
Datestring must match the currentAuroraEngineEngineOptions.Runtime.DateTimeFormat; a numeric form is .NET ticks and must be an in-range integer. Writing always produces a string using the engine date format.
Date "2026-08-20 10:00:00"
Regex { pattern "ab+", flags "gi" }
HashMap [["name", "Aurora"], [1, true]]
HashMap 使用二元数组保存键和值,因此非字符串键不会降级为对象属性。
HashMapuses two-element arrays for keys and values, so non-string keys do not degrade into object properties.
CLR/CIL Type Boundary
文档中的 CLR/CIL 类型名必须是当前引擎已经注册的别名。TDoc 不会根据程序集名、.NET 类型名或反射自动加载类型。
A CLR/CIL type name in a document must be an alias already registered on the current engine. TDoc never auto-loads a type from an assembly name, .NET type name, or reflection.
engine.RegisterType<User>("User");
var tdoc = new AuroraTypedDocument(engine);
var user = tdoc.Deserialize("User { String Name \"Hanks\", Number Age 18 }");读取时,未注册对象的显式别名、未知别名、不可构造类型和不符合注册成员契约的文本都会失败;写入时,未注册或不可写入的 CLR/CIL 值按可跳过值规则处理。即使 EmitTypeNames 为 false,User 这类已注册类型名也不会被省略。
When reading, an explicit alias for an unregistered object, an unknown alias, a non-constructible type, or text that violates the registered member contract fails. When writing, an unregistered or non-writable CLR/CIL value follows the skippable-value rules. A registered type name such as
Useris never omitted, even whenEmitTypeNamesisfalse.
Errors and Diagnostics
宿主 API 会抛出 TypedDocumentException。其中 SourceName、Line、Column 和 DataPath 用于定位错误;例如 $.meta.tags[2] 表示嵌套数组中的第三项。
Host APIs throw
TypedDocumentException. ItsSourceName,Line,Column, andDataPathlocate the error; for example,$.meta.tags[2]identifies the third item in a nested array.
脚本 API 将该异常转换为 AuroraRuntimeException,消息以 TDoc.parse error: 或 TDoc.stringify error: 开头。
The script API converts this exception to
AuroraRuntimeException, with a message starting withTDoc.parse error:orTDoc.stringify error:.
Related APIs
AuroraScript.JIT 4.0.0 · Documentation Home · Repository · MIT License