
TypeSpec JSON Schema 装饰器完全指南typespec/json-schema 的 16 个核心装饰器详解【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec本文是 typespec/json-schema 库装饰器体系的权威参考完整梳理TypeSpec.JsonSchema命名空间下导出的 16 个装饰器jsonSchema、baseUri、id、extension、contains、multipleOf、oneOf等的签名、作用目标与参数语义并结合 packages/json-schema/src/decorators.ts 源码与 packages/json-schema/test 测试用例说明每个装饰器在发射器底层如何被读取、验证并映射为 JSON Schema 关键字。读完本文你将掌握如何通过装饰器精确控制 TypeSpec 程序向 JSON Schema 文档转换时的标识符解析、数组/对象/数值约束、字符串内容注解与厂商扩展字段。背景JSON Schema 发射器与装饰器typespec/json-schema是一个将 TypeSpec 数据类型发射为 JSON Schema 文档、并支持反向转换的官方库。发射器安装方式与基础用法参见 website/src/content/docs/docs/emitters/json-schema/reference/index.mdx 与 website/src/content/docs/docs/emitters/json-schema/reference/emitter.md其核心使用方式为tsp compile . --emittypespec/json-schema所有装饰器的声明都集中在 packages/json-schema/lib/main.tsp 中属于TypeSpec.JsonSchema命名空间因此在使用时需要通过TypeSpec.JsonSchema.xxx全限定名或using TypeSpec.JsonSchema;引入。装饰器按功能可划分为六个组别分组装饰器发射入口与标识符jsonSchema、baseUri、id数组约束contains、minContains、maxContains、uniqueItems、prefixItems对象属性数量约束minProperties、maxProperties数值约束multipleOf联合类型oneOf字符串内容注解contentEncoding、contentMediaType、contentSchema厂商扩展extension发射入口与标识符jsonSchema、baseUri、id这一组装饰器决定哪些类型会被发射以及发射出的$id是什么。jsonSchema声明 JSON Schema 类型将装饰器加在命名空间上则该命名空间内的所有模型都会被发射为 JSON Schema加在其他声明模型、联合、枚举、标量上则仅发射该声明本身。对命名空间可额外传入baseUri对其他声明可传入idTypeSpec.JsonSchema.jsonSchema(baseUri?: valueof string)Targetunknown命名空间或任意声明参数名称类型说明baseUrivalueof stringSchema ID 被解释为相对此 URI。在 packages/json-schema/src/decorators.ts 中$jsonSchema的实现先把目标标记为 JSON Schema 类型随后根据target.kind分流若是Namespace则转发给$baseUri否则转发给$id。判断一个类型是否属于JSON Schema 类型依赖isJsonSchemaDeclaration它会沿着target.namespace链向上逐层检查只要自身或任意祖先命名空间带有jsonSchema标记即视为 JSON Schema 类型见 packages/json-schema/src/decorators.ts。baseUri为命名空间设置基础 URI设置该命名空间内所有类型发射出的 schema 的基础 URIschema 的 ID 均相对此 URI 解析TypeSpec.JsonSchema.baseUri(baseUri: valueof string)TargetNamespace参数名称类型说明baseUrivalueof string基础 URI命名空间内的 Schema ID 都相对于它。基础 URI 的解析支持继承findBaseUri从目标类型出发沿namespace链向上逐层查找第一个已设置的 base URI见 packages/json-schema/src/decorators.ts因此子命名空间可以省略重复声明。测试 packages/json-schema/test/ids.test.ts 验证了带baseUri(http://example.org)的命名空间下model Foo会得到$id: http://example.org/Foo.json。id显式指定 Schema ID指定该声明的 JSON Schema id。如果该模型或某个父命名空间带有 base URI则提供的 id 会相对该 base URI 解析。默认情况下id 由声明名构造例如模型Widget的默认 id 为Widget.yaml文件格式取决于file-type选项TypeSpec.JsonSchema.id(id: valueof string)Targetunknown参数名称类型说明idvalueof string该声明对应 JSON Schema 的 id。从 packages/json-schema/test/ids.test.ts 可以看到三类行为无 base URI 时id(bar)直接产出$id: bar存在baseUri(http://example.org)时产出$id: http://example.org/bar在bundleId打包模式下显式 id 还会作为 bundle 中$defs的键名。另外若两个声明产生了相同的 id发射器会报出typespec/json-schema/duplicate-id诊断见 packages/json-schema/test/ids.test.ts。关于 id 与 base URI 的语义细节website/src/content/docs/docs/emitters/json-schema/guide.md 中的说明值得注意schema 的 base URI 是解析 schema 内部相对引用如$ref的基准点默认行为是让$id保持相对引用如Widget.yaml这样无论文档是从磁盘加载还是经 HTTP 获取实际 base URI 都可以随取用位置而变化从而保证相对引用在不同场景下都能正确解析。数组约束contains、minContains、maxContains、uniqueItems、prefixItems这一组装饰器作用于unknown[]数组类型或ModelProperty对应 JSON Schema 2020-12 中数组相关的验证关键字。contains数组必须包含指定类型指定数组必须至少包含一个所提供的类型的实例TypeSpec.JsonSchema.contains(value: unknown)Targetunknown[] | ModelProperty参数名称类型说明valueunknown数组必须包含的类型。minContains/maxContains控制包含实例的数量与contains配合使用分别指定数组必须包含的contains所给类型的最少与最多实例数TypeSpec.JsonSchema.minContains(value: valueof int32) TypeSpec.JsonSchema.maxContains(value: valueof int32)Targetunknown[] | ModelProperty参数名称类型说明valuevalueof int32数组必须包含minContains或最多包含maxContains的实例数量。测试 packages/json-schema/test/arrays.test.ts 给出了三者组合使用的完整写法contains(string) minContains(1) maxContains(2) uniqueItems myArray: string[];uniqueItems数组元素必须唯一指定数组中的每一项都必须唯一TypeSpec.JsonSchema.uniqueItemsTargetunknown[] | ModelProperty参数无在 packages/json-schema/src/json-schema-emitter.ts 中contains、minContains、maxContains、uniqueItems等装饰器的值通过applyConstraint/applyTypeConstraint统一写入目标 schema 对象的同名关键字uniqueItems的底层实现则是把状态标记为布尔值true见 packages/json-schema/src/decorators.ts。prefixItems数组必须以指定类型开头指定目标数组必须以所提供的类型开头对应 JSON Schema 的prefixItems关键字即元组语义TypeSpec.JsonSchema.prefixItems(value: unknown[])Targetunknown[] | ModelProperty参数名称类型说明valueunknown[]必须出现在数组开头的类型元组。测试 packages/json-schema/test/arrays.test.ts 展示了元组写法prefixItems([string, { x: string }, Foo])。发射时通过emitTupleLiteralValues将元组逐项转换为prefixItems数组见 packages/json-schema/src/json-schema-emitter.ts。对象属性数量约束minProperties、maxProperties作用于Recordunknown对象类型或ModelProperty限制对象可拥有的属性数量TypeSpec.JsonSchema.minProperties(value: valueof int32) TypeSpec.JsonSchema.maxProperties(value: valueof int32)TargetRecordunknown | ModelProperty参数名称类型说明valuevalueof int32对象可拥有的最少minProperties/最多maxProperties属性数量。与contains系列一致这两个装饰器在发射阶段同样经applyConstraint映射到minProperties/maxProperties关键字见 packages/json-schema/src/json-schema-emitter.ts其声明位于 packages/json-schema/lib/main.tsp。数值约束multipleOf指定数值类型必须是某个数值的倍数TypeSpec.JsonSchema.multipleOf(value: valueof numeric)Targetnumeric | ModelProperty参数名称类型说明valuevalueof numeric数值类型必须是此值的倍数。底层实现中$multipleOf将值以Numeric类型存储并提供getMultipleOf读取为 JavaScriptnumber无法表示为 number 或未设置时返回undefined见 packages/json-schema/src/decorators.ts发射时经applyConstraint写入multipleOf关键字。联合类型oneOf默认情况下TypeSpec 的联合类型在发射时使用anyOf。oneOf装饰器可以针对某个联合或其属性指定改用oneOfTypeSpec.JsonSchema.oneOfTargetUnion | ModelProperty参数无实现上$oneOf只是打上一个标记发射器读取isOneOf来决定联合的发射策略见 packages/json-schema/src/decorators.ts。oneOf表达恰好匹配其一anyOf表达匹配其一或多个请根据业务是否需要排他性来选择。字符串内容注解contentEncoding、contentMediaType、contentSchema这组装饰器对应 JSON Schema 中内容字符串content string的语义用于描述字符串中承载的编码内容适用于string类型或ModelProperty。contentEncoding字符串内容的编码方式指定字符串内容所使用的编码如base64TypeSpec.JsonSchema.contentEncoding(value: valueof string)Targetstring | ModelProperty参数名称类型说明valuevalueof string内容编码名称。发射阶段若检测到字符串类型上设置了该装饰器会输出形如{ type: string, contentEncoding: base64 }的 schema见 packages/json-schema/src/json-schema-emitter.ts 与 packages/json-schema/src/json-schema-emitter.ts。contentMediaType字符串内容的媒体类型指定字符串中存储内容的媒体类型MIME typeTypeSpec.JsonSchema.contentMediaType(value: valueof string)Targetstring | ModelProperty参数名称类型说明valuevalueof string字符串内容的媒体类型。contentSchema字符串内容的 Schema当字符串内容按其媒体类型与编码解释时指定其内容应符合的 schemaTypeSpec.JsonSchema.contentSchema(value: unknown)Targetstring | ModelProperty参数名称类型说明valueunknown字符串内容的 schema。三者的存储与读取统一由createDataDecorator生成的状态存取函数完成getContentEncoding、getContentMediaType、getContentSchema见 packages/json-schema/src/decorators.ts并在发射时映射到同名 JSON Schema 关键字。厂商扩展extensionextension允许向发射出的 schema 添加自定义关键字vendor extension例如x-custom。这是与外部工具链对接时最灵活的扩展点。TypeSpec.JsonSchema.extension(key: valueof string, value: unknown | valueof unknown)Targetunknown参数名称类型说明keyvalueof string扩展关键字名称例如x-custom。valueunknown|valueof unknown扩展关键字的值。值会被视为原始值的三种情形文档明确规定了value被当作原始 JSON/YAML 值直接输出而非转换为 schema的三种条件满足任一即可值是标量值如 string、number、boolean 等值被包装在JsonData模板中值使用值语法提供如#{}、#[]。例如extension(x-schema, typeof foo) // 输出 schema 值{ const: foo, type: string } extension(x-schema, foo) // 输出原始代码foo extension(x-schema, { x: value }) // 输出 schema 值模型表达式 extension(x-schema, #{x: value}) // 输出原始 JSON 代码{x: value} extension(x-schema, Json{x: value}) // 输出原始 JSON 代码{x: value}其中JsonData是TypeSpec.JsonSchema命名空间导出的数据模板详见 website/src/content/docs/docs/emitters/json-schema/reference/data-types.md其唯一属性value: Data承载要按原始 JSON/YAML 输出的值。类型定义位于 packages/json-schema/lib/main.tsp并通过Private.validatesRawJson在编译期校验数据确实可序列化为 JSON。底层实现要点在 packages/json-schema/src/decorators.ts 中$extension会先判断传入值是否为 TypeSpec 类型若不是类型即为标量、值语法或普通对象则通过convertRemainingValuesToExtensions递归地序列化为 JSON 可用的值随后setExtension会检测值是否为Json模板模型若是则提取其value属性的类型并调用typespecTypeToJson转成原始 JSON 代码见 packages/json-schema/src/decorators.ts。发射阶段getExtensions返回的扩展记录会被逐一写入 schema 顶层见 packages/json-schema/src/json-schema-emitter.ts。测试 packages/json-schema/test/extension.test.ts 系统性地验证了各种取值形态的发射结果extension(x-model-expression, { name: string })输出一个真正的对象 schema含type: object、required、propertiesextension(x-tuple, [string, string])输出带prefixItems与minItems/maxItems的数组 schemaextension(x-named-model, Thing)输出{ $ref: Thing.json }引用在模型属性上的extension(x-int, int8)会输出包含minimum: -128, maximum: 127的integerschema字面量extension(x-bool-literal, typeof true)输出{ const: true, type: boolean }联合extension(x-union, one | two)输出anyOf结构。组合实战装饰器与发射器选项协同装饰器负责逐类型的语义标注而发射器选项负责整体的输出策略二者常配合使用控制发射范围emitAllModels对所有模型发射无需jsonSchema与emitAllRefs对所有被引用的类型发射可以让你不必为每个类型手工标注jsonSchema具体配置示例见 website/src/content/docs/docs/emitters/json-schema/guide.md。打包输出设置bundleId后所有 schema 被合并进单个文档的$defs下此时id与baseUri依然生效显式 id 会作为$defs的键名见 packages/json-schema/test/ids.test.ts。格式化与整数策略file-typeyaml/json、int64-strategy、seal-object-schemas、polymorphic-models-strategy等选项的完整说明见 website/src/content/docs/docs/emitters/json-schema/reference/emitter.md。一个综合示例——命名空间级标注 标识符定制 数组与数值约束 厂商扩展using TypeSpec.JsonSchema; jsonSchema baseUri(https://example.com/schemas) namespace PetStore { id(pet) model Pet { minContains(1) maxContains(2) contains(string) tags: string[]; multipleOf(0.5) weightKg: float32; extension(x-internal, #{audit: true}) name: string; } }在该示例中Pet会以https://example.com/schemas/pet作为$id发射tags数组要求至少包含 1 个、至多 2 个string实例weightKg必须是 0.5 的倍数name附带原始 JSON 扩展{audit: true}。总结与进一步阅读TypeSpec.JsonSchema的装饰器体系覆盖了 JSON Schema 发射过程中的标识符控制jsonSchema/baseUri/id、数组约束contains系列、uniqueItems、prefixItems、对象与数值约束minProperties/maxProperties、multipleOf、联合策略oneOf、字符串内容注解contentEncoding/contentMediaType/contentSchema以及扩展机制extensionJsonData。所有装饰器的声明可一站式查阅 packages/json-schema/lib/main.tsp其 TypeScript 实现位于 packages/json-schema/src/decorators.ts发射映射逻辑位于 packages/json-schema/src/json-schema-emitter.ts对应的行为验证分散在 packages/json-schema/test 各测试文件中数组、扩展、id、联合、对象等均有专项用例。如需进一步了解发射器的整体配置emitAllModels、bundleId、polymorphic-models-strategy等可继续阅读 website/src/content/docs/docs/emitters/json-schema/reference/emitter.md要理解JSON Schema 类型的判定规则与打包行为请参考 website/src/content/docs/docs/emitters/json-schema/guide.md。【免费下载链接】typespec项目地址: https://gitcode.com/GitHub_Trending/ty/typespec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考