@openpresentation /消息
JavaScript和TypeScript的Canonical Open Presentation Format包。
发布OPF模式、目录预设、原始规范文件、生成的TypeScript类型、示例、文档和本地验证助手。模式是预稳定的(0。X -预计在1.0之前的小版本之间会有突破性的变化)。这个包不呈现PowerPoint文件,解析 .pptx,获取远程目录,调用托管api,提供遥测或使用AI。
规范的npm包仍然存在 @openpresentation/opf;一个单独的 @openpresentation/opf-spec 包不用于v0.2.0,因此现有的下游导入保持稳定。打包的npm工件包括包可寻址的OPF模式、目录、参考文件和一个可选的下游服务引用 openapi.yaml 下 spec/.
存储库: https://github.com/OpenPresentation/opf
文件命名
使用 *.opf.json 下载完整的开放演示格式文件,例如 deck.opf.json.
OPF文档是纯JSON,而 .opf.json Suffix使其对编辑器、验证器、代理和存储库工具可见。避免裸露的 *.opf 因为该扩展已经被其他文档和项目格式所使用。
安装
pnpm add @openpresentation/opf
# or: npm install @openpresentation/opf
# or: yarn add @openpresentation/opf
要求Node 22或更高版本(engines.node >=22),从0.12.1之后的版本。声明了0.10.0到0.12.1版本 24.x因此,npm在Node 22或26上静默地安装了一个匹配(RR-20)的旧版本。早期发布的版本保留了它们记录的运行时需求。
使用
对大多数应用程序代码使用通用的根API:
import { presentation, validate, embed } from "@openpresentation/opf";
import { gallery } from "@openpresentation/gallery";
import type { Presentation } from "@openpresentation/opf";
const deck: Presentation = {
name: "Quarterly Review",
slides: [{ title: "Quarterly Review", items: ["Revenue", "Product", "Hiring"] }],
};
console.log(presentation.$id);
// Register the catalogs your host trusts; core ships no records. In Node, validate, stats, paginate, embed and edit
// register the gallery (@openpresentation/gallery, a dependency of core) when a call names none.
const catalogs = [gallery];
console.log(validate({ ...deck, design: { theme: "classic" } }, { catalogs }).valid);
// Save with every record the deck uses embedded, so it renders the same with no catalog registered.
const saved = embed({ ...deck, design: { theme: "classic" } }, { catalogs }).document;
console.log(Object.keys(saved.catalogs.default.themes)); // ["classic"]
console.log(Object.keys(gallery.tones));
在Node(以及Bun和Deno)中,根目录添加文件: convert 将一个文件转换为另一个文件(将一个甲板转换为PDF, PNG, SVG或PPTX,将PowerPoint文件转换为甲板,将一个甲板形式转换为另一个甲板,或没有输出路径的字节), open 读取一个甲板文件或导入一个 .pptx, save 写一个。相同的导入在每个运行时都有效,所以一个命名空间导入涵盖了一个应用程序:
import * as opf from "@openpresentation/opf";
await opf.convert("deck.opf.md", "deck.pdf");
const deck = await opf.open("deck.opf.md");
deck.slides.push({ title: "Q4" });
await opf.save(deck, "deck.opf.md");
const { files } = await opf.convert(deck, { format: "pptx" }); // bytes, nothing written
绘图和ppt通过可选的同伴 @openpresentation/opf-render 和 @openpresentation/opf-pptx,哪个核心在调用第一次需要它们时加载;NPM不会为你安装它们。根有条件导出(OPF 0.18删除) /node): node, bun 和 deno 得到这个完整的构建,然后 browser, worker, workerd 和 default 获得具有相同名称和相同类型的浏览器安全构建,其中 open, save 和 convert 拒绝与 OPFApiError 代码 node-only. 其他所有子路径都在浏览器中运行。 parseSlideSelection(3 | "1-3" | [1, 3], total) 在两者中读取幻灯片选择。看到 OPF文件在Node.
在Cloudflare Workers、Vercel Edge和其他拒绝从字符串生成代码的主机上, validate 运行在构建时编译的验证器,而不是用Ajv编译模式。这个 workerd, worker 和 edge-light 条件选择它们,所以Worker不需要别名,也不需要选项;为在工作线程(以及严格的Content-Security-Policy下的页面)导入上运行的Node绑定的代码 @openpresentation/opf/precompiled 一次。结论和发现是相同的,并且CI通道在实际中运行包 workerd 运行时。看到 边缘运行时.
当你只需要一个表面时,使用聚焦导入:
import { presentation, audience } from "@openpresentation/opf/schemas";
import { specFileEntries } from "@openpresentation/opf/spec-files";
import { validate, assertValid, validationRules } from "@openpresentation/opf/validator";
import type { Presentation, Audience, Tone } from "@openpresentation/opf/types";
根条目保存应用程序级API:模式、目录引用及其解析(resolveReference, embed, copySlides, updateFromCatalog)、验证、变量、分页、数据助手、字体策略、 stats, resolveSlideContext 和 resolveSlideVariables. 发动机组成和绘制 context.slide 从 resolveSlideContext(deck, index, { slideNumber, slideCount }):带滑动范围的内置滑块 {{slide.number}}, {{slide.section}} 和 {{deck.slideCount}} 代入相同的数 options 带(resolveSlideVariables(slide, { slideNumber, slideCount }) 单独做替换)页眉和页脚文本由 layoutFurniture,它会记录每张幻灯片的编号 FurnitureTextPart.fields. 看到 模板和变量. 它不携带目录记录:pptx。画廊目录是包 @openpresentation/gallery (gallery, catalogDisplay的布局预览 @openpresentation/gallery/previews),在自己的版本行上发布的core依赖,当调用没有目录时,Node构建会注册它(OPF 0.19删除) @openpresentation/opf/catalog 和 defaultCatalog,没有别名)。解析引用的每个入口点都使用 { catalogs }、主机注册的目录;第一个是省略的文档的默认值 catalogs.default. 看到 目录和默认目录.
布局引擎的名称不在根目录上。 composeSlide, fitText, layoutQuote 另一个 layoutX/fitX 功能,编号,脚注和引用,颜色对比,代码语法,模式填充,度量趋势,图表选项,脚本字体和文本方向来自 @openpresentation/opf/composition;符号字体表来自 @openpresentation/opf/symbol-font-encodings.
事实,幻灯片上下文和字体处理
stats(presentation, options?) 报告关于桥牌的中立事实(结构、文字、注释、图像、图表、表格、数据集、引用、变量、资产、字体),而不进行构图、测量或验证;看到 统计指南. resolveSlideContext(presentation, index, { fonts, catalogs }) 将一张幻灯片的画布、布局、主题和字体系列(幻灯片设计,然后是甲板设计,然后是主题,然后是引擎默认值)解析为 ComposeSlideOptions 那 composeSlide 带一个 unresolved-reference 每个引用的诊断无法解析(strictReferences: true 抛出 OPFUnresolvedReferenceError 相反)。甲板级动词take { fonts }谁的手柄? textMeasurement 是主机的实际字体绘制文本的宽度(paginate(deck, { fonts }));渲染器的字体加载器返回一个扩展它的更丰富句柄。 composeSlide 它本身是发动机水平的 textMeasurement 和 fontFamilies ({ heading, body, code, accent? }直接)。
内容转换
@openpresentation/opf/convert 在文本、列表、引用、度量、代码、时间线、图表、表格和一组度量块之间转换一个有效负载(convertContent, contentConversionTargets)、嵌套列表项、分组块、在内容和幻灯片设计之间移动图像,以及拆分或合并幻灯片(splitSlide, splitSlideOnOverflow, mergeSlides, unpaginate). 每个函数都是纯粹的,从不虚构内容、报告 lossless 和 loss,有理由拒绝并验证其输出。看到 转换指南. 在变更日志中列出它之前的版本中不会。
标记和轮廓
@openpresentation/opf/markdown 读取和写入一个甲板Markdown在一个小文档方言(YAML前端问题), --- 之间的幻灯片, # 标题, ## 副标题、列表、引用、表格、图片、 chart, metric 和 timeline 围栏, Note: 演讲者笔记)。 fromMarkdown(markdown, { split, defaults, validate }) 返回 { presentation, valid, findings, counts } 与发现(共享) Finding 格式),其中载有划线和列划线; toMarkdown(presentation, { unsupported }) 编写任何有效的deck,将该方言没有语法的内容嵌入到YAML中(或将其放入) report.loss),它写入的Markdown会转换回同一套牌。确定性和离线。阅读前面的事项与 yaml 包中。看到 减价指南. 在变更日志中列出它之前的版本中不会。
读写任何形式的牌组
parse(text, { format, filename, catalogs }) 和 stringify(presentation, { format | filename }) (根和 @openpresentation/opf/deck)读取和写入JSON (canonical), YAML或Markdown格式的deck。格式为 format 选项,否则为文件名(.opf.md 减价, .yaml 和 .yml 是YAML,其他都是JSON;一个普通 .md 不是套牌,更不是内容。 parse 返回表示并抛出 OPFValidationError 对于语法、模式或引用错误;错误的 report.findings 在文本中按行和列定位(opf/json-syntax, yaml/<rule> 或者 markdown/<rule> 语法错误)。警告不要抛出: validate(text) 返回完整的报表。两者都在浏览器中运行;文件是Node构建的任务(如上)。
OPF为YAML
@openpresentation/opf/yaml 以YAML(相同数据的创作形式)的形式读写一个deck (JSON保持规范)。 fromYaml(text, { aliases, validate }) 读取严格的json兼容的YAML 1.2(一个文档,根处的映射,没有自定义标记,重复的键或非有限的数字;锚定,别名和合并键只能与 aliases: true)和返回 { presentation, valid, findings, counts, schemaValid, checks }: validate 甲板报告,每一个发现(共享) Finding 格式,YAML语法错误为 yaml/<rule> 发现)位于YAML的行和列。 toYaml(presentation, { schemaComment }) 写入规范的YAML(模式键顺序、块样式、引用的模糊字符串),读取回同一套牌,并抛出 OPFYamlError 无效的。 parseYamlData 和 scanYamlComments 是帮助者。看到 YAML指南.
源代码编辑:模式字段查询,文本寻址和语法恢复
源代码编辑器(CLI和代理)的两个浏览器安全子路径。 @openpresentation/opf/schema 从JSON模式中读取文档的字段模型: describeField(path, document?) 返回类型、描述、枚举值、默认值、示例、父节点是否需要 oneOf 变异(和 primary(表单模板应该使用),排名 children 一个对象(首先需要,然后是策展) COMMON_KEYS 顺序,然后按字母顺序;提升区域, extensions 和 $schema 是 advanced),数组的项模式(itemInfo)或地图(entryInfo), requiredChildren 和 freeText, { known: false } 对于模式没有描述的路径; catalogKindAt(path, document?) 将参考字段指向的目录命名为(layouts, themes, colorSchemes, fontSchemes, narratives, audiences, purposes, tones) schemaCatalogKinds (也可以导出),核心端元数据由模式名称和JSON指针键;发布的模式不携带供应商关键字,并在严格的ajax下编译,因此新的引用字段是其中的一个条目,不需要更改编辑器。它所基于的导航帮助器也被导出(resolveSchema, schemaVariants, activeSchema, schemaAtPath, createSchemaValue, listSchemaFields, splitOpfPath)。 @openpresentation/opf/source 将文本转换为位置和返回: locate(text, format, pointer, { part }) 是JSON、YAML或Markdown (value, key, entry, open 或者 colon;最近的祖先 exact: false 节点缺失时;按其查找结果使用的相同范围来定位标记下滑幻灯片字段 layout= 选项注释的标记,后面的文本 # 或者 - ), pathAt(text, format, offset) 插入符号下的路径, scanMarkdown(text) 带有方言词汇的Markdown deck(前部内容,幻灯片,选项注释,围栏,注释)的区域(SLIDE_OPTION_KEYS, BLOCK_OPTION_KEYS, FENCE_KINDS, METRIC_KEYS), analyzeJsonSyntax(text, { limit }) 每个JSON语法错误的根本原因,一次,按位置顺序(最多五个),包括范围,消息,提示和修复它的修复程序(Insert comma, Add { }, Remove "design", Insert }, Use double quotes,……); validate(text) 报告相同的原因 opf/json-syntax 发现。看到 验证.
验证(0.14.0)
validate(input, options?) 是一个检查器,从根和从 @openpresentation/opf/validator. input 是经过解析的表示或严格的JSON文本;结果是 ValidationReport 谁的 findings (共享 Finding 格式, spec/schemas/finding.schema.json每个人都有一个马厩 opf/<rule> Id,严重程度,六个类别之一: format (JSON语法,重复键,模式) references (目录参考,资产,引文,数据集), policy (主机 contracts), accessibility (对比,Alt文本,阅读顺序,链接), layout (溢出,字体大小,图像分辨率,字体)和 content (占位符、空幻灯片、非数字图表单元格)。 valid 意味着没有严重的发现 error,默认情况下只有 format, references 和 policy 发现可以有。文本输入添加行和列; only, ignore 和 severity 挑选和推广规则或类别;作文是懒惰的,所以 validate(deck, { only: ["format"] }) 成本与模式检查的成本相同。只读且确定性:不获取远程资源。看到 验证指南. 干净的报告不证明布局、字体或本机导出保真度。
describeFinding(finding, { document }) 和 explain(ruleId) 把发现用通俗易懂的语言表达出来。 describeFinding (从 @openpresentation/opf/source)返回 { message, next } 对于任何发现:反引号中的字段有什么问题,接下来可能会发生什么(“你的意思是?” center?”),根据调查结果本身的数据和文件编写;每一个 opf/* 规则有它的文本。 explain (也在包的根目录上)返回规则的摘要、基本原理、 fix 还有一个小的before/after example. 看到 明文文本和 explain.
补丁,diff,合并和格式化(0.12.0)
在0.12.0添加(未在0.11.4或更早版本中添加): @openpresentation/opf/patch 是CLI和编辑器共享的RFC 6902实现(applyPatch, applyPatchWithInverse, invertPatch(严格的指针帮助器,可选的结果模式验证); @openpresentation/opf/diff 有 diff (幻灯片匹配的id,内容和相似性,移动,可读的报告和JSON补丁)和 merge (三向合并与冲突对象,永远不会放弃一方); @openpresentation/opf/format 有 format (规范键顺序和布局,幂等)。看到 该指南.
id,文档散列和补丁范围(CE-04, CE-05)
@openpresentation/opf/ids (所有的都放在包的根上,指针和哈希部分也放在上面 /patch)使编辑可寻址和可检查。 assignIds(document, { generate? }) 填补缺失 id 幻灯片和内容有效载荷的确定性({ document, patch, assigned };现有的id永远不会改变)。在数组中,指针标记 @intro 元素的名称 id 是 intro,所以 /slides/@intro/blocks/@kpi/text 幸存重新排序: applyPatch 和 readPointer 解决它, resolveIdPointer 和 toIdPointer 转换指针, resolveIdPatch 和 toIdPatch 一整块。 documentHash(document) 是 sha256: 和SHA-256的键排序JSON(纯JavaScript,在Node,浏览器和edge运行时相同); applyPatch(document, patch, { expectHash }) 和 edit(deck, patch, { expectHash }) 只应用于获取哈希值的文档,否则抛出 OPFPatchHashError 什么也改变不了。 touches(patch, document?) 返回指针(索引和id形式)、id、幻灯片id和补丁读取和写入的类型,用于冲突检测和权限检查。看到 该指南.
布局预览
@openpresentation/gallery/previews 提供预渲染的SVG缩略图
幻灯片布局目录在pptx.画廊。每个预览都是一个自包含的SVG
大小为16:9的容器,颜色和布局已经渲染。
import { getLayoutPreview } from "@openpresentation/gallery/previews";
export function LayoutThumbnail({ slug }: { slug: string }) {
const html = getLayoutPreview(slug);
if (!html) return null;
return (
<div
className="aspect-[16/9] overflow-hidden rounded-lg border border-border bg-card"
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}
预览源存在于 packages/gallery 检查所读取的存储库的。
例子甲板
@openpresentation/opf/examples 船每 .opf.json 文件从 examples/
在上游回购中,已经针对表示进行了解析和验证
构建时的模式。
import {
examples,
galleries,
getExample,
getExamplesByGallery,
} from "@openpresentation/opf/examples";
const compliance = getExample("compliance-readiness-review");
const businessDecks = getExamplesByGallery("business-functions");
console.log(`${examples.length} example decks across ${galleries.length} galleries`);
每一个 ExampleRecord 包括已解析的 Presentation 对象及其
repo-相对路径,顶级类别(gallery, technical,……),以及
如适用,廊塞。
文档页面
@openpresentation/opf/docs 运顶层 docs/*.md 参考页面
(schema-reference, catalog-schema-reference, content-payloads,
content-item-design-overrides, examples). 子目录等
docs/migrations 和 docs/plans 是故意排除的吗
在固定的NPM发布中快速发布。
import { docs, getDoc } from "@openpresentation/opf/docs";
for (const doc of docs) {
console.log(`${doc.title} — ${doc.file}`);
}
const schemaRef = getDoc("schema-reference");
console.log(schemaRef?.markdown.slice(0, 200));
上游的自述
@openpresentation/opf/repo-readme 暴露上游的原始降价
OpenPresentation/opf 自述文件。在此版本固定在此发布。使用它
当你想在另一个网站或应用程序中镜像规范的README时
不需要进行网络获取。
import { repoReadme } from "@openpresentation/opf/repo-readme";
console.log(repoReadme.split("\n").slice(0, 3).join("\n"));
验证报告包含 findings. 一个严重的发现 error 是一个
结构性问题 valid 虚假的; warning 和 info 发现是
咨询的,如 narrative, design 或者 layout 解析的引用
地方(opf/unresolved-reference)或缺少Alt文本。引用解析
在文件所嵌入的记录中(catalogs.custom, catalogs.default,名叫
组),然后在主机注册的目录中 { catalogs }.
const report = validate(deck, { catalogs: [gallery] });
if (!report.valid) console.error(report.findings.filter((finding) => finding.severity === "error"));
for (const finding of report.findings) console.warn(finding.ruleId, finding.path, finding.message);
本地验证目录记录:
import { validateCatalogRecord } from "@openpresentation/opf";
import { gallery } from "@openpresentation/gallery";
for (const [id, record] of Object.entries(gallery.audiences)) {
// A published record file carries its $schema and id; the gallery keys records by id without them.
const result = validateCatalogRecord("audiences", { $schema: "https://openpresentation.org/schema/opf-audience/v1", id, ...record });
if (!result.valid) {
console.error(result.findings);
}
}
原始规范JSON发布于 spec/:
import presentationSchema from "@openpresentation/opf/spec/schemas/opf.schema.json" with {
type: "json",
};
原始规范清单显示了应该从npm而不是GitHub解析的文件的类型化包路径。 openapi.yaml 是选择通过HTTP公开OPF的下游服务的参考契约;OpenPresentation不承载该API。
import { specFileEntries } from "@openpresentation/opf/spec-files";
const openApi = specFileEntries.find((entry) => entry.path === "openapi.yaml");
console.log(openApi?.packagePath);
核心船没有目录记录文件(RR-78):记录是 @openpresentation/gallery’s,和pptx。库为每个已发布的记录文件提供服务 https://www.pptx.gallery/<kind>/<id>.json. 文件从来没有指向他们。主机转而注册目录:
import { gallery } from "@openpresentation/gallery";
validate(deck, { catalogs: [gallery] });
开发
pnpm --filter @openpresentation/opf typecheck
pnpm --filter @openpresentation/opf test
pnpm --filter @openpresentation/opf pack:dry-run
src/generated/ 和 dist/ 是从根目录生成的 spec/ 目录和被git有意忽略。