@nx-lang / sdk-wasm
浏览器和Node访问NX编译器、NX IR生成和语言服务,通过一个 WebAssembly模块。没有服务器,没有本地插件。
这个包裹是分开的 @nx-lang/ir-runtime 下 runtime/typescript:使用 @nx-lang/sdk-wasm
当JavaScript需要 编译 NX源代码或回答编辑器对它的查询,以及IR运行时的查询
JavaScript只需要 执行 已经保存的NX红外图像。它还计算程序的
root() 到NX文本,窗体 nxlang run 印刷品,用于向人显示价值。Filesystem-backed
工作流-从磁盘加载的库注册表,工作区目录, root() JSON求值
Values—属于 @nx-lang/sdk-node;这个包只能看到源文本
它是递过来的,包括主机加载到注册表中的库的源代码。
范围
| 提供 | 没有提供 |
|---|---|
| 从内存模块构建程序工件 | 库和工作区从目录中读取 |
| 从内存模块加载的库注册表 | 计算NX到JSON的值(使用IR运行时) |
| 验证工作空间,将诊断作为数据回答 | |
| 每个模块发出一个NX IR工件,库模块也是如此 | |
| 将规范值格式化为带注释的NX文本 | |
| JSON函数或类型的模式和文档 | 从NX红外图像派生模式 |
| 悬停,补全,诊断,文件符号 | 线程、流、增量分析 |
一个进程内 NxLanguageService 通过主机文档 |
这里的所有内容都在内存文档中响应。不需要文件存在。
工具链
模块目标 wasm32-wasip1它的标准库捆绑了wasi-libc,所以tree-sitter的C
运行时和NX语法没有任何关联。构建它需要:
- 这个
wasm32-wasip1生锈的目标-列在rust-toolchain.toml,所以rustup将其安装为 工具链。 clang,为该目标编译C源代码。- 固定的wasi-sdk
wasi-sysroot,这scripts/fetch-wasi-sysroot.mjs下载到 gitignored.cache/在存储库下,通过SHA-256验证,然后重用。
pnpm --filter @nx-lang/sdk-wasm build 运行所有这些:获取,为asm目标装载
这个 wasm-release 配置文件,以及该模块的副本 dist/nx.wasm。没有铭文,没有
wasm-bind和no -pack;ABI是通过手写加载器的JSON输入和JSON输出,除了
NX IR调用,它携带图像的字节(参见 ABI 下文)。
pnpm install
pnpm --filter @nx-lang/sdk-wasm build
pnpm --filter @nx-lang/sdk-wasm test
加载:编译一次,主机多次
装货的两部分是故意分开的。 compileNxModule 产生一个 WebAssembly.Module
-昂贵的,可缓存的一半-和 createNxHost 实例化它,这需要几十个
毫秒。调用者保留模块,并根据需要经常从中创建主机。
import { compileNxModule, createNxHost } from "@nx-lang/sdk-wasm";
// In a browser: stream the module straight from the network.
const module = await compileNxModule(fetch(nxModuleUrl));
const host = createNxHost(module);
const artifact = host.buildProgramArtifact(source, { fileName: "input.nx" });
try {
const [{ bytes, metadata }] = artifact.generateNxIr();
console.log(metadata.identity, metadata.fingerprint, bytes.byteLength);
} finally {
artifact.dispose();
}
buildProgramArtifact 是工作空间构建的单模块情况;看到 工作空间构建 下面。
报告错误的构建抛出 NxEvaluationError。一个成功的人仍然可以拥有
警告,例如文档链接没有任何名称; artifact.diagnostics() 返回它们,带有info和
提示,同样的形状。
compileNxModule 也接受模块的字节或已编译的 WebAssembly.Module,所以。
已经有一个的调用者可以在没有特殊情况的情况下传递它。
两个入口点由包选择 exports 条件,两者暴露相同
createNxHost:
- 默认条目通过提供WASI
@bjorn3/browser_wasi_shim; - 这个
node入口通过node:wasi,并补充道loadNxModule()为来电者阅读 模块。节点是node:wasi试验和进口警告;包的 自己的测试和操场的例子检查运行--no-warnings.
语言的快照
const uri = "nx://tenant/form.nx";
const snapshot = host.createLanguageSnapshot([{ uri, version: 1, source }]);
try {
const hover = snapshot.hover(uri, { line: 2, character: 3 });
const completions = snapshot.completions(uri, { line: 2, character: 7 });
const report = snapshot.diagnostics();
const symbols = snapshot.documentSymbols(uri);
const tree = snapshot.sourceTree(uri); // unstable
// The value of `let greeting = "Hello"`, by its key in the source tree.
const answer = snapshot.sourceEdit(uri, "greeting.value", {
kind: "setValue",
value: { kind: "string", value: "Hi" },
}); // unstable
} finally {
snapshot.dispose();
}
快照是不可变的:当文档更改时,构建一个新的快照。分析在第一个查询上运行
并且在快照的生命周期内被缓存,因此对未更改的文本进行多次查询只需要一次
分析。位置计算UTF-16代码单元,就像JavaScript字符串和浏览器编辑器计数一样,
结果是 @nx-lang/language-protocol 形状,在这里重新导出。
sourceTree(uri) 将文档的每个部分作为类型化节点进行应答,并将声明作为节点
指的是;协议的README描述了答案。它是 不稳定它的形状随时都可能改变
释放,直到后面的人提交。 sourceEdit(uri, key, edit),也不稳定
用于设置值、设置文本行或删除带有该键的节点上的属性的文本编辑,或
为什么它不能。
createLanguageService(host, options) 实现协议的 NxLanguageService 对这些
快照,具有有限的分析缓存。其上下文声明位于目录中的主机
将目录作为自己的文档传递,并将其命名为隐式导入:
const service = createLanguageService(host, {
documents: [{ uri: "nx://host/drawnui.nx", identity: "drawnui.nx", source: catalog }],
implicitImports: ["drawnui.nx"]
});
然后,每个查询的文档都可以看到目录的导出声明,而不需要导入行
因为它的文本是按书面形式分析的,所以每个答案都已经在自己的坐标中了。一个
根据目录的URI报告目录内的诊断,而不是根据访问者的URI报告。这个
回答和缓存是 @nx-lang/language-core,与HTTP处理程序运行的代码相同。
工作空间构建
一个程序可以跨越多个内存模块。构建将它们与一个条目一起接受,并且可选地,
标识所有其他模块的隐式导入,就好像它以 import "<identity>":
const artifact = host.buildWorkspaceArtifact({
modules: [
{ identity: "drawnui.nx", source: catalog, version: "9" },
{ identity: "input.nx", source }
],
entry: "input.nx",
implicitImports: ["drawnui.nx"]
});
try {
const [snippet] = artifact.generateNxIr();
// snippet.bytes names drawnui.nx at version "9" in its module table and carries none of it.
} finally {
artifact.dispose();
}
隐式导入的行为与写入的通配符导入完全相同,这意味着它看到了什么
模块导出;目录声明其控件 export。构建失败是一个
NxEvaluationError 谁的每个诊断都带有一个标签来标识它们的模块
属于,在该模块自己的行和字节。
generateNxIr(options) 每个请求的模块发出一个图像,条目单独由
默认值: { modules: [] } 发出程序的每个模块,条目优先,和 { modules: ["drawnui.nx"] } 自行发出目录。每个工件的模块表记录了版本
每个模块都给出了 modules[].version,或者 "" 为一个一无所有的人。调试部分,范围和源代码
文本,被省略,除非 { debug: true } 传递;有了它,藏物就不一样了
只在那一节。每个工件旁边的元数据命名模块,指纹,
模式和ABI、所需的特性以及模块的功能和组件入口点
名字。
库
根据相同的库编译许多租户的NX的服务器将它们在每个主机上加载一次 注册中心,然后根据其中的构建上下文构建并验证每个租户的工作空间。一个 Library是一个逻辑根,一个可选的版本,它的模块相对于根命名;一个 库通过相对路径导入另一个库的根目录,就像目录库一样:
const registry = host.createLibraryRegistry();
const libraryWarnings = registry.loadLibraries([
{ root: "libraries/chat-link", modules: [{ identity: "ChatLinkConfig.nx", source: chatLinkSource }] },
{ root: "libraries/question-flow", version: "3", modules: questionFlowModules }
]);
const context = registry.createBuildContext({
implicitImports: ["libraries/chat-link", "libraries/question-flow"]
});
const diagnostics = host.validateWorkspace({ modules: tenantModules, buildContext: context });
const artifact = host.buildWorkspaceArtifact({
modules: tenantModules,
entry: "chat-link.nx",
buildContext: context
});
loadLibraries 按照依赖顺序加载一个列表,不管它的顺序是什么; loadLibrary
加载依赖项已经加载的组件。其分析报告错误的库
导入未加载的根,不保留,调用抛出 NxEvaluationError 与
诊断。加载带有自己的警告、信息和提示的答案的库
它的来源;这是主机看到它们的地方,因为工作区的验证和构建离开了
出来。在注册表的生命周期中,根目录是不可变的:使用相同的模块重新加载它
Version不做任何事情,用不同的变量加载它会引发命名根的问题。构建上下文
保存它所看到的库,因此它在其注册表被处置后仍然可用;一个由
visibleRoots 只看到这些库及其所依赖的内容,以及一个不是
被加载的库引发命名。
隐式导入可以命名加载的库的根目录,也可以命名工作空间模块
的写入通配符导入库,因此租户源使用库的声明
没有导入行。既是工作空间模块又是库的根的标识将被拒绝
模棱两可的。 implicitImports 给定的构建或验证将替换上下文本身,因此
implicitImports: [] 没有它们的构建。
一个库的根命名它的模块,所以它保留了它的整个命名空间:一个工作空间模块
标识位于可见或链接库的根目录下,例如 libraries/question-flow/Step.nx,
验证和构建失败 workspace-module-in-library-root 而不是代替
库的模块。
validateWorkspace 分析工作空间而不构建它,并回答每个诊断
提交的模块-错误,警告,信息和提示-作为数据,从不抛出NX
诊断。内存库自己的警告不在其中;它的错误,失败了
构建。它是
编辑器或编写API向编写源代码的人报告的内容;然后一个构建抛出
只针对已经说过的验证,使用相同的诊断。
程序链接的库中的每个模块都是该程序的一个模块: generateNxIr({ modules: [] }) 为每一个发出一个图像,命名为 <root>/<module> (例如
libraries/question-flow/QuestionFlow.nx),并记录图书馆的版本。一个库模块
无论租户的程序发出它,Image都是相同的字节-它携带每个using声明
图像可以到达,派生的包括在内-所以运行时准备它一次 @nx-lang/ir-runtime
并将每个房客的入住照片与之相关联
const prepared = new Map(libraryImages.map((image) => [image.identity, prepareNxIrModule(image.bytes)]));
const program = linkNxIrProgram(prepareNxIrModule(entry.bytes), {
resolve: (identity) => prepared.get(identity)
});
标准库
标准库是模块本身携带的NX源代码,通过保留名称导入:
import "@nx/agent"。它没有装载任何东西。分析或构建NX的每个入口点都会解析
它没有注册表、构建上下文或选项 loadLibrary 他的根在 @nx/ 是
拒绝与 library-root-reserved。下面的小路 @nx/ 没有标准库的名字
报告为 unknown-standard-library,列出存在的。
@nx/agent 是第一个:用于声明AI代理、其文档和其
工具。它是 不稳定,因此它的声明可能会在任何版本中不兼容地更改,包括
补丁发布;主机只有通过移动其NX包的引脚才能得到更改。
const registry = host.createLibraryRegistry();
// A host library that names an agent type writes the import itself: a module of an implicitly
// imported library receives no implicit imports.
registry.loadLibrary({
root: "libraries/chat-link",
modules: [{ identity: "ChatLink.nx", source: 'import "@nx/agent"\nexport type AssistantConfig = { agent?:Agent }' }]
});
// Naming the standard library's root as an implicit import puts it in scope for tenant source, so
// an authored config needs no import line.
const context = registry.createBuildContext({ implicitImports: ["libraries/chat-link", "@nx/agent"] });
const artifact = host.buildWorkspaceArtifact({ modules: tenantModules, entry: "main.nx", buildContext: context });
// The library's image is emitted like any library module's and stored with the program's others;
// no runtime carries it.
const images = artifact.generateNxIr({ modules: [] });
const library = prepareNxIrModule(images.find((image) => image.identity === "@nx/agent/agent.nx")!.bytes);
const version = library.version; // 16 hex digits derived from the library's source
A节目链接 @nx/agent/agent.nx 只有当它使用的东西导入库和图像时
是与发出它的程序相同的字节数。它的版本是从图像中读取的;一个宿主
在任何租户编译构建单行源代码之前都需要它 import "@nx/agent" 并发出
从它的图书馆图像。库映像列出了所需的特性 function-reference-type-v1,
所以链接它的运行时必须是支持该特性的版本。
声明的模式
将NX函数传递给使用JSON Schema(语言模型的工具)的系统的主机
接口(MCP客户端)在编译时向工件请求它。 functionSchema 答案与
JSON模式(草案2020-12)的函数的参数和它的结果,its /// 文档,
每个参数一个条目:
const artifact = host.buildWorkspaceArtifact({
modules: [{ identity: "tools.nx", source }],
entry: "tools.nx"
});
try {
const tool = artifact.functionSchema({ name: "findPlans" });
tool.description; // "Finds the plans that fit a team.\n\nPlans are sorted by price."
tool.summary; // "Finds the plans that fit a team."
tool.inputSchema; // { $schema, type: "object", properties: { teamSize: { type: "integer", … } }, … }
tool.outputSchema; // { $schema, type: "array", items: { $ref: "#/$defs/Plan" }, $defs: { Plan: … } }
tool.parameters; // [{ name: "teamSize", type: "int", required: true, description: "…" }, …]
const images = artifact.generateNxIr(); // the image a runtime calls the function from
store(tool, images);
} finally {
artifact.dispose();
}
与 tools.nx:
/// A plan a team can buy.
type Plan = {
name:string /// The plan's display name.
}
/// Finds the plans that fit a team.
///
/// Plans are sorted by price.
let findPlans(
teamSize:int, /// Number of people who need a seat.
maxMonthlyPrice?:int
): Plan* = { <Plan name="Team" /> }
这两个查询是读取程序类型和文档的支持方式。新一代IR
Image两者都不包含——它擦除通用参数,不记录别名目标,也不携带文档
注释——一个只执行图像的主机 @nx-lang/ir-runtime,派生模式。
当它编译并将它们存储在图像旁边时。文档注释和这些查询首先发布
在发行版0.6.0中,这是两者的最低版本。
函数由其模块的标识及其名称A对命名 Function 记录
携带,因此主机从计算值中持有一个直接请求其模式。该模块
默认为条目;命名库模块 <root>/<module>, @nx/agent/agent.nx 为
代理库。任何函数都符合条件,无论是否导出。 typeSchema(reference, { direction })
记录、动作、联合、类型别名、 <Target>.Update 或者 <Target>.Property.
| 选项 | 查询 | 意义 |
|---|---|---|
hostSuppliedTypes | functionSchema | 主机自己填充其参数的类型,例如 { module: "@nx/agent/agent.nx", name: "ToolContext" }. 用1声明的参数、用扩展1的记录声明的参数,或者用其中任何一种类型别名声明的参数,都将被排除在外 inputSchema 它的条目将类型命名为 hostSupplied. 类型为1而不为1的形参 + 或者作为任何深度的记录的字段,留在里面 inputSchema 它的条目列出了它保存的类型 hostSuppliedWithin. 程序没有声明的类型不匹配任何内容。一个条目的 typeRef 命名用于声明参数的记录或联合,并通过类型别名指定别名所表示的内容。 |
direction | typeSchema | output (默认值)描述运行时返回的值:每条记录携带 $type. input 描述主机提供的值: $type 仅在运行时需要它选择形状时(在抽象记录或负载联合情况下)才被要求。 |
模式描述的是规范的JSON编码,而不是更广泛的:一个有效的值
inputSchema 由运行相同图像的运行时接受为函数的参数
工件,并且函数返回的值是有效的 outputSchema;软件包的测试
都反对 @nx-lang/ir-runtime. 对象是封闭的(additionalProperties: false),一个
省略可选字段或参数 required 而不是使其为空 object 是
{ "not": { "type": "null" } },任何值,但是 null. 记录、联合记录和应用的通用记录是 $defs 文档引用的项
$ref,所以递归类型只描述一次。每种类型表单的映射都在网站的
声明的模式 参考页面。
报告一个没有JSON表单的类型,从不进行近似,并且仍然返回答案:
不存在受影响的模式 diagnostics 一边说为什么,一边回答。
| 代码 | 意义 |
|---|---|
schema-inexpressible-type | 参数、字段或结果具有函数类型,即函数引用类型(FunctionTool.function),组件类型,标记,程序中没有扩展的抽象记录,或检查器无法推断的结果。标记在成员上。 |
schema-ambiguous-discriminator | 一个摘要记录站点的两个形状共享一个 $type,运行时将其视为二义性而拒绝。 |
schema-unknown-declaration | 该引用在程序中没有任何名称。被作为 NxEvaluationError,没有人回答。 |
拼写运行时值
IR运行时以规范JSON格式返回值。 artifact.formatValue(value, options) 法术等
值为 { text, nodes } 从格式化程序中找到的 formatValue(value) 用途,
运行程序的主机 @nx-lang/ir-runtime 像命令行那样显示它的值。
程序不被求值。
const artifact = host.buildProgramArtifact(`external component <Button label:string emits { Tapped { } } />
type Size = { width:float64 }`);
try {
artifact.formatValue({ $type: "Size", width: 3 }).text; // <Size width=3.0 />
artifact.formatValue({
$type: "Button",
label: "Add",
onTapped: { $type: "ActionHandler", action: "Button.Tapped", token: "h1-1" }
}).text;
// <Button
// label="Add"
// onTapped=<ActionHandler action="Button.Tapped" token="h1-1" />
// />
} finally {
artifact.dispose();
}
一个 ActionHandler 在绑定处理程序的地方,运行时返回的Record被拼写为
记录; formatValue(value) 拒绝,因为解释器处理程序没有令牌。规范的JSON写入
一个整体 float64 当它写一个 int,以及作为裸字符串的常量并集情况,因此每个数字
string被它的记录为它声明的类型读取: width=3.0 以上。对于带有no的值
记录周围的情况, options.type 给出其类型(formatValue(3, { type: "float64" }) 是 3.0). 这个
记录可以在输入模块中声明,也可以在程序链接的库中声明。输入的字段
类型参数被读取为 int 当为整时,因为值不携带类型参数。
options.state 命名一个组件,值是该组件的状态,拼写为1
name=value 按声明顺序,每行在其状态字段声明。
超出规范格式的值抛出 NxEvaluationError 使用代码 nx-value-invalid,
一个没有NX拼写的,一个直接在序列中的序列, nx-text-unspellable;两者都可以命名
出错值的指针。工件保持可用。 undefined, JSON不能携带,
抛出 TypeError;空值为 null 或者 [].
图像
NxGeneratedNxIr.bytes 作为NX红外图像的工件:32位单元的二进制是什么
@nx-lang/ir-runtime 在适当的地方读取,从模块的内存中复制出来,所以它比工件更长寿
还有主人。这是一个字节对一个字节的Node SDK。. NET SDK和CLI所发出的
输入,除非要求,否则没有调试部分。 host.explainNxIr(bytes) 类渲染图像
文本 nxlang ir explain 打印已解析的每个表索引,并抛出 NxEvaluationError
对于不是映像的字节,此构建读取。文档中记录了布局
docs/nx-ir-format.md.
陷阱结束了主人;调用者替换它
模块目标 wasm32-wasip1在美国,恐慌会中止而不是消散。恐慌或恐惧
因此,模块内部的越界访问将终止实例及其内存——没有越界访问
catch_unwind 这样可以隐藏它,并且被捕获的请求丢失。
SDK明确了这一点,而不是掩盖它:
- 陷阱抛出的调用
NxHostCrashedError,命名操作; - 以后对该主机的每次调用在没有进入模块的情况下都会抛出相同的错误,并且
host.crashed是true; dispose()在来自崩溃主机的资源上是可以容忍的,因此清理路径永远不会掩盖崩溃;- 呼叫恢复
createNxHost在已经编译的模块上。那 代价是实例化,而不是下载或重新编译。
try {
return compile(host, source);
} catch (error) {
if (error instanceof NxHostCrashedError) {
host = createNxHost(module); // same module; no fetch
}
throw error;
}
playground正是在它的工作线程中做这件事的,所以编译器崩溃的代价是一个请求 编辑还活着。
错误
| 错误 | 时抛出 |
|---|---|
NxEvaluationError | NX报告诊断:不能编译的源代码 root 丢失、失败或没有NX拼写、无法解析的快照URI、重复的标识、无法加载的库、针对程序没有的声明的模式查询。携带 diagnostics. |
NxDisposedResourceError | 在已处置的工件、快照、注册表、构建上下文或主机上尝试操作。允许处理两次。 |
NxHostCrashedError | 该模块被捕获,并在以后每次调用该主机时被捕获。携带 operation. |
NxWasmError | 模块的ABI版本不是加载程序的,或者它以加载程序无法读取的形状回答。 |
名字和形状是匹配的 @nx-lang/sdk-node,因此代码可以在两个绑定之间移动。
ABI
模块导出 nx_wasm_abi_version,加载程序在任何其他调用之前检查并拒绝
当它不同意时,命名两个版本。当前的版本是9。版本4添加了库
注册表(nx_wasm_registry_new, nx_wasm_registry_load, nx_wasm_registry_free),构建
上下文(nx_wasm_build_context_new, nx_wasm_build_context_free),
nx_wasm_workspace_validate,并给予 nx_wasm_workspace_build 构建上下文句柄参数
(null表示无);5添加 nx_wasm_program_diagnostics;6补充道 nx_wasm_program_function_schema
和 nx_wasm_program_type_schema;7添加 nx_wasm_snapshot_source_tree;8补充道
nx_wasm_program_format_value 和一个 pointer 在每个值节点上;9添加
nx_wasm_snapshot_source_edit.
| 出口 | 目的 |
|---|---|
nx_wasm_abi_version, nx_wasm_alloc, nx_wasm_free, nx_wasm_result_free | 版本检查和模块的内存 |
nx_wasm_program_build, nx_wasm_workspace_build, nx_wasm_workspace_validate | 构建和验证程序 |
nx_wasm_registry_new, nx_wasm_registry_load, nx_wasm_registry_free, nx_wasm_build_context_new, nx_wasm_build_context_free | 库注册中心和构建上下文 |
nx_wasm_snapshot_new, nx_wasm_snapshot_hover, nx_wasm_snapshot_completions, nx_wasm_snapshot_diagnostics, nx_wasm_snapshot_document_symbols, nx_wasm_snapshot_source_tree, nx_wasm_snapshot_free | 语言的快照 |
nx_wasm_ir_explain | 解释图像 |
参数在缓冲区中作为UTF-8 JSON交叉 nx_wasm_alloc,或作为图像的字节
nx_wasm_ir_explain;每个操作都返回一个指向a的指针 { status, ptr, len } 记录
其有效载荷是UTF-8 JSON,除此之外 nx_wasm_program_nx_ir 答案与NX IR包(a)
u32 header长度,一个JSON头 [{ identity, metadata, offset, length }],填充为4
字节,然后图像),通过释放 nx_wasm_result_free 在调用返回之前。处理
对于工件,快照、注册表和构建上下文对于加载程序和构建都是不透明的
除了创建上下文的主机外,任何主机都拒绝上下文。
Rust方面是 bindings/wasm/native (箱 nx-sdk-wasm-native),在 nx-api, nx-codegen 和
nx-language-service. 它的NX IR、诊断和模式有效负载是节点绑定序列化的
包的奇偶性测试在每次测试运行时比较两个绑定的答案,因此分歧失败
构建而不是到达一个站点。
布局
| 路径 | 它包含什么 |
|---|---|
native/ | Rust箱子和它的ABI |
src/ | 加载器、两个WASI入口点、语言服务、错误和类型 |
scripts/ | wasm构建和清理脚本 |
test/ | 加载器、SDK、语言服务、陷阱、入口点、架构协议和Node-SDK奇偶性测试 |
test/fixtures/schema/ | 模式语料库:每个映射一个NX源,其中包含导出答案和参数用例的文档 |
dist/nx.wasm | 生成的模块(被忽略;由 pnpm run build) |
实验图形准备
artifact.prepareGraphics(request) 使用共享的方法验证ir评估的图形值
nx-graphics 从该工件解析的核心和声明标识。公众不稳定
NxGraphicsPreparationRequest / NxGraphicsPreparation 接口描述了价值和结构
起源,视口/资源限制和提供的文本测量。来源/测量是可信的
宿主报告,而不是任意调用者的身份验证边界。没有Skia被链接到SDK中。
使用 preflight: true 首先:它验证身份和几何/限制,并返回重复数据删除
textRequests (各有各的) request(首先请求元素ID和来源),用
scene: null. 使用目标提供的字体度量这些请求
服务,然后再次调用 measurements 获得一个准备好的场景。事先准备的稿子永远不会出版
带有占位符参数的场景。诊断包含构造来源和可选的授权
调用网站。在JSON编码之前会检查图形编号的有限性;畸形的请求
抛出和支持的配置文件准备失败将返回结构化诊断。
执行迁移
evaluateNx() 已被移除。编译成IR并执行 @nx-lang/ir-runtime,然后通过
它的规范值为 artifact.formatValue(value, options). 格式化不执行源文件。
看到 迁移指南.