Notist
On this page
  1. Path 字面量
  2. 相对位置
  3. 编译与宿主边界
  4. 本地 embed
  5. 链接与路径派生
  6. 读取文本

Path 字面量

p"./data.json" 是 Path 类型的字面量,与普通字符串不同,没有隐式转换。创建 Path 只确定逻辑资源身份,不读取文件、不检查存在性,也不自动发布资源。

fn identity(source: Path) -> Path { source }

fn view(source: Path = p"./default.json") -> BlockContent {
    // Path 可以转发给其他 notc 函数;不会随调用位置重新解释。
    let input = identity(source);
    [静态正文]
}
#import "../views/lib.notc" as view;
#view.view(source: p"./data.json")

相对位置

  • 文档中写下的 Path 相对该文档所在目录。

  • 默认参数和函数体中的 Path 相对定义模块所在目录。

  • 以 / 开头的字面量相对宿主指定的逻辑资源根,不是操作系统根。

  • .、.. 和多余的 / 按词法规范化;不访问文件系统,不跟随符号链接。

  • 不允许通过 .. 逃出所属逻辑根。相同规范身份的 Path 可以用 == 和 != 比较。

Path 可以出现在参数、返回值、数组、字典和属性注解中;注解和默认值仍只接受字面量,不执行任意表达式。

Path 字面量写作紧邻的单行 p"...",使用普通字符串转义。路径使用 /,不接受反斜杠、控制字符、空路径、URL 或盘符路径。p 本身不是保留字。

编译与宿主边界

Path 字面量在 Resolve 阶段按源文件和逻辑根绑定,后续转发保留该身份。

独立 Pipeline 默认使用虚拟逻辑根 /,不使用进程工作目录。宿主可以用 Context.with_resource_root 指定文档逻辑根,用 Pipeline.compile_module_with_root 指定模块逻辑根;Vault 使用其 Resources 的根。独立内容片段可通过 Pipeline.analyze_content_literal_at 明确提供来源,方言占位路径只用于选择语法。生成页面只需提供逻辑路径和 Markup 源码,不必落盘。

Path 不会自动变成 HTML 属性、组件参数或公开 URL;这类导出会产生诊断。IR/调试 JSON 使用显式的 Path 标记,保留资源身份。

本地 embed

embed 是显式的资源消费边界,接受 Path 或 URL 字符串:

#embed(p"./images/chart.svg", description: "图表", fragment: "detail")
#embed(p"./file?name#part%.svg", query: "raw=1", fragment: "detail")
#embed("https://example.com/chart.svg#detail")

Path 中的 ?、# 和 % 都属于文件名,不拆分也不做 URL 解码。query 是不带 ? 的 URL 查询文本,不能包含控制字符或 #;fragment 是不带 # 的语义片段,发布时编码一次。

也可使用图片语法 ![描述](image.svg?raw=1#detail) 或字符串形式 #embed("image.svg?raw=1#detail")。本地字符串在 embed 构造边界按该操作所在的源文件绑定为 Path;URL 路径和 fragment 百分号解码一次,query 保留 URL 文本。远程 URL 保持字符串,不作为本地资源。同一 query/fragment 不能同时在 URL 和显式参数中提供。转发已经绑定的 Path 不重新解析;转发普通本地字符串则在最终 embed 操作处解释,因此可复用函数推荐使用 Path 参数和 Path 默认值。

ResourceTarget 是接受 Path 或 String 的输入类型,不是另一种运行期 Value,也不提供两者之间的转换。资源存在性、Vault/mount 授权和发布 URL 仍由宿主负责。独立 Renderer 需要 with_resource_resolver 选择本地资源的公开 URL;没有映射时诊断并省略链接,不直接输出 Path。

链接与路径派生

link 是泛型函数,其 where 约束只接受 Path 或 String。Path 保留创建位置绑定的资源身份,经组件转发也不重新解释;宿主将文档映射到页面路由,将其他资源映射到发布 URL。缺少发布映射时诊断并省略 href,不回退到路径字符串。String 保留 URL 链接规则。

#link(p"./guide.not", fragment: "intro")[指南]
#link(p"./model.glb")[下载模型]
#link("https://example.com")[外部网站]

query 与 fragment 是独立字段;Path 文件名中的 ?、#、% 不拆分。

Path.join(relative: String) -> Path 将接收者视为目录,追加非空相对路径并按词法规范化。结果保留同一个逻辑根,拒绝绝对路径、URL 及逃出根的路径;不读取文件,也不将 Path 转为 String。

fn download(directory: Path, name: String) -> InlineContent {
    [#link(directory.join(name + ".glb"))[下载模型]]
}

调用者传入 p"." 可明确选择调用文档所在目录。默认参数中的 p"." 仍绑定定义模块目录,不代表调用者目录。

读取文本

read_text(source: Path) -> String 读取 UTF-8 文本,可在 notc 函数体中使用:

fn from_file(source: Path = p"./intro.txt") -> BlockContent {
    let body = read_text(source);
    [ #text(text: body) ]
}
#import "views/lib.notc" as view;
#view.from_file(p"./private/intro.txt")

在 Markup 中,通过上例的内容函数读取文件。读取发生在实际执行时;check 与 LSP 不执行读取,comptime 中禁止读取。

结果是普通 String,不会再次当作 Markup 解析;text 显式将其变成正文,HTML 正常转义。缺失、拒绝、目录、超限和非法 UTF-8 都在实际读取调用的位置诊断,并沿既有内容边界恢复。

Vault 默认允许项目根内的数据读取;外部模块和 Book mounts 的数据需要单独授权。

同一批次保留每个输入首次读到的字节或错误,包括缺失文件。后续读取使用缓存,不随磁盘修改而变化;文件更新、修复或创建后以新 Vault 开始下一轮。缓存命中仍计费、登记依赖并检查读取授权。

独立 Pipeline 可使用 evaluatewithinputs 接收宿主输入;不带 inputs 的 evaluate 可以执行无读取的文档,实际读取时报告能力不可用。浏览器按 NeedResources 准备字节或明确失败,再以新视图重试,不发布部分结果。接口、预算与一致性规则见 资源输入与求值。

JSON/TOML 解码与受检访问见 Data。