microsoft/typespec

Public

mirrored from https://github.com/microsoft/typespecAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
ce9c567e5bfb441bb6415699a6b6fa797bc08f2e

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

packages/json-schema/src/index.ts

304lines · modecode

1import {
2 DecoratorContext,
3 EmitContext,
4 Enum,
5 Model,
6 ModelProperty,
7 Namespace,
8 Program,
9 Scalar,
10 Tuple,
11 Type,
12 Union,
13 setTypeSpecNamespace,
14 typespecTypeToJson,
15} from "@typespec/compiler";
16import { ValidatesRawJsonDecorator } from "../generated-defs/TypeSpec.JsonSchema.Private.js";
17import {
18 BaseUriDecorator,
19 ContainsDecorator,
20 ContentEncodingDecorator,
21 ContentMediaTypeDecorator,
22 ContentSchemaDecorator,
23 ExtensionDecorator,
24 IdDecorator,
25 JsonSchemaDecorator,
26 MaxContainsDecorator,
27 MaxPropertiesDecorator,
28 MinContainsDecorator,
29 MinPropertiesDecorator,
30 MultipleOfDecorator,
31 PrefixItemsDecorator,
32 UniqueItemsDecorator,
33} from "../generated-defs/TypeSpec.JsonSchema.js";
34import { JsonSchemaEmitter } from "./json-schema-emitter.js";
35import { JSONSchemaEmitterOptions, createStateSymbol } from "./lib.js";
36
37export { JsonSchemaEmitter } from "./json-schema-emitter.js";
38export { $lib, EmitterOptionsSchema, JSONSchemaEmitterOptions } from "./lib.js";
39
40export const namespace = "TypeSpec.JsonSchema";
41export type JsonSchemaDeclaration = Model | Union | Enum | Scalar;
42
43const jsonSchemaKey = createStateSymbol("JsonSchema");
44
45export async function $onEmit(context: EmitContext<JSONSchemaEmitterOptions>) {
46 const emitter = context.getAssetEmitter(JsonSchemaEmitter);
47
48 if (emitter.getOptions().emitAllModels) {
49 emitter.emitProgram({ emitTypeSpecNamespace: false });
50 } else {
51 for (const item of getJsonSchemaTypes(context.program)) {
52 emitter.emitType(item);
53 }
54 }
55
56 await emitter.writeOutput();
57}
58
59export const $jsonSchema: JsonSchemaDecorator = (
60 context: DecoratorContext,
61 target: Type,
62 baseUriOrId?: string
63) => {
64 context.program.stateSet(jsonSchemaKey).add(target);
65 if (baseUriOrId) {
66 if (target.kind === "Namespace") {
67 context.call($baseUri, target, baseUriOrId);
68 } else {
69 context.call($id, target, baseUriOrId);
70 }
71 }
72};
73
74const baseUriKey = createStateSymbol("JsonSchema.baseURI");
75export const $baseUri: BaseUriDecorator = (
76 context: DecoratorContext,
77 target: Namespace,
78 baseUri: string
79) => {
80 context.program.stateMap(baseUriKey).set(target, baseUri);
81};
82
83export function getBaseUri(program: Program, target: Type) {
84 return program.stateMap(baseUriKey).get(target);
85}
86
87export function findBaseUri(
88 program: Program,
89 target: JsonSchemaDeclaration | Namespace
90): string | undefined {
91 let baseUrl: string | undefined;
92 let current: JsonSchemaDeclaration | Namespace | undefined = target;
93 do {
94 baseUrl = getBaseUri(program, current);
95 current = current.namespace;
96 } while (!baseUrl && current);
97
98 return baseUrl;
99}
100
101export function isJsonSchemaDeclaration(program: Program, target: JsonSchemaDeclaration) {
102 let current: JsonSchemaDeclaration | Namespace | undefined = target;
103 do {
104 if (getJsonSchema(program, current)) {
105 return true;
106 }
107
108 current = current.namespace;
109 } while (current);
110
111 return false;
112}
113
114export function getJsonSchemaTypes(program: Program): (Namespace | Model)[] {
115 return [...(program.stateSet(jsonSchemaKey) || [])] as (Namespace | Model)[];
116}
117
118export function getJsonSchema(program: Program, target: Type) {
119 return program.stateSet(jsonSchemaKey).has(target);
120}
121
122const multipleOfKey = createStateSymbol("JsonSchema.multipleOf");
123export const $multipleOf: MultipleOfDecorator = (
124 context: DecoratorContext,
125 target: Scalar | ModelProperty,
126 value: number
127) => {
128 context.program.stateMap(multipleOfKey).set(target, value);
129};
130
131export function getMultipleOf(program: Program, target: Type) {
132 return program.stateMap(multipleOfKey).get(target);
133}
134
135const idKey = createStateSymbol("JsonSchema.id");
136export const $id: IdDecorator = (context: DecoratorContext, target: Type, value: string) => {
137 context.program.stateMap(idKey).set(target, value);
138};
139
140export function getId(program: Program, target: Type) {
141 return program.stateMap(idKey).get(target);
142}
143
144const containsKey = createStateSymbol("JsonSchema.contains");
145export const $contains: ContainsDecorator = (
146 context: DecoratorContext,
147 target: Type,
148 value: Type
149) => {
150 context.program.stateMap(containsKey).set(target, value);
151};
152
153export function getContains(program: Program, target: Type) {
154 return program.stateMap(containsKey).get(target);
155}
156
157const minContainsKey = createStateSymbol("JsonSchema.minContains");
158export const $minContains: MinContainsDecorator = (
159 context: DecoratorContext,
160 target: Type,
161 value: number
162) => {
163 context.program.stateMap(minContainsKey).set(target, value);
164};
165
166export function getMinContains(program: Program, target: Type) {
167 return program.stateMap(minContainsKey).get(target);
168}
169
170const maxContainsKey = createStateSymbol("JsonSchema.maxContains");
171export const $maxContains: MaxContainsDecorator = (
172 context: DecoratorContext,
173 target: Type,
174 value: number
175) => {
176 context.program.stateMap(maxContainsKey).set(target, value);
177};
178
179export function getMaxContains(program: Program, target: Type) {
180 return program.stateMap(maxContainsKey).get(target);
181}
182
183const uniqueItemsKey = createStateSymbol("JsonSchema.uniqueItems");
184export const $uniqueItems: UniqueItemsDecorator = (context: DecoratorContext, target: Type) => {
185 context.program.stateMap(uniqueItemsKey).set(target, true);
186};
187
188export function getUniqueItems(program: Program, target: Type) {
189 return program.stateMap(uniqueItemsKey).get(target);
190}
191
192const minPropertiesKey = createStateSymbol("JsonSchema.minProperties");
193export const $minProperties: MinPropertiesDecorator = (
194 context: DecoratorContext,
195 target: Type,
196 value: number
197) => {
198 context.program.stateMap(minPropertiesKey).set(target, value);
199};
200
201export function getMinProperties(program: Program, target: Type) {
202 return program.stateMap(minPropertiesKey).get(target);
203}
204
205const maxPropertiesKey = createStateSymbol("JsonSchema.maxProperties");
206export const $maxProperties: MaxPropertiesDecorator = (
207 context: DecoratorContext,
208 target: Type,
209 value: number
210) => {
211 context.program.stateMap(maxPropertiesKey).set(target, value);
212};
213
214export function getMaxProperties(program: Program, target: Type) {
215 return program.stateMap(maxPropertiesKey).get(target);
216}
217
218const contentEncodingKey = createStateSymbol("JsonSchema.contentEncoding");
219export const $contentEncoding: ContentEncodingDecorator = (
220 context: DecoratorContext,
221 target: Scalar | ModelProperty,
222 value: string
223) => {
224 context.program.stateMap(contentEncodingKey).set(target, value);
225};
226
227export function getContentEncoding(program: Program, target: Type): string {
228 return program.stateMap(contentEncodingKey).get(target);
229}
230
231const contentMediaType = createStateSymbol("JsonSchema.contentMediaType");
232export const $contentMediaType: ContentMediaTypeDecorator = (
233 context: DecoratorContext,
234 target: Scalar | ModelProperty,
235 value: string
236) => {
237 context.program.stateMap(contentMediaType).set(target, value);
238};
239
240export function getContentMediaType(program: Program, target: Type): string {
241 return program.stateMap(contentMediaType).get(target);
242}
243
244const contentSchemaKey = createStateSymbol("JsonSchema.contentSchema");
245export const $contentSchema: ContentSchemaDecorator = (
246 context: DecoratorContext,
247 target: Scalar | ModelProperty,
248 value: Type
249) => {
250 context.program.stateMap(contentSchemaKey).set(target, value);
251};
252
253export function getContentSchema(program: Program, target: Type) {
254 return program.stateMap(contentSchemaKey).get(target);
255}
256
257const prefixItemsKey = createStateSymbol("JsonSchema.prefixItems");
258export const $prefixItems: PrefixItemsDecorator = (
259 context: DecoratorContext,
260 target: Type,
261 value: Type
262) => {
263 context.program.stateMap(prefixItemsKey).set(target, value);
264};
265
266export function getPrefixItems(program: Program, target: Type): Tuple | undefined {
267 return program.stateMap(prefixItemsKey).get(target);
268}
269
270export interface ExtensionRecord {
271 key: string;
272 value: Type;
273}
274
275const extensionsKey = createStateSymbol("JsonSchema.extension");
276export const $extension: ExtensionDecorator = (
277 context: DecoratorContext,
278 target: Type,
279 key: string,
280 value: Type
281) => {
282 const stateMap = context.program.stateMap(extensionsKey) as Map<Type, ExtensionRecord[]>;
283 const extensions = stateMap.has(target)
284 ? stateMap.get(target)!
285 : stateMap.set(target, []).get(target)!;
286
287 extensions.push({ key, value });
288};
289
290export function getExtensions(program: Program, target: Type): ExtensionRecord[] {
291 return program.stateMap(extensionsKey).get(target) ?? [];
292}
293
294export const $validatesRawJson: ValidatesRawJsonDecorator = (
295 context: DecoratorContext,
296 target: Model,
297 value: Type
298) => {
299 const [_, diagnostics] = typespecTypeToJson(value, target);
300 if (diagnostics.length > 0) {
301 context.program.reportDiagnostics(diagnostics);
302 }
303};
304setTypeSpecNamespace("Private", $validatesRawJson);
305