forked from microsoft/typespec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.ts
181 lines (171 loc) · 6.34 KB
/
lib.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { createTypeSpecLibrary, JSONSchemaType, paramMessage } from "@typespec/compiler";
/**
* Options that the Protobuf emitter accepts.
*/
export interface ProtobufEmitterOptions {
/**
* Don't emit anything.
*/
noEmit?: boolean;
/**
* Omit unreachable types.
*
* By default, types under a package namespace will be emitted if they are fully annotated with `@field` decorators.
* With this flag on, only types that are explicitly marked with `@message` or that are referenced by an operation
* in an interface decoarated with `@service` will be emitted.
*/
"omit-unreachable-types"?: boolean;
}
const EmitterOptionsSchema: JSONSchemaType<ProtobufEmitterOptions> = {
type: "object",
additionalProperties: false,
properties: {
noEmit: {
type: "boolean",
nullable: true,
description:
"If set to `true`, this emitter will not write any files. It will still validate the TypeSpec sources to ensure they are compatible with Protobuf, but the files will simply not be written to the output directory.",
},
"omit-unreachable-types": {
type: "boolean",
nullable: true,
description:
"By default, the emitter will create `message` declarations for any models in a namespace decorated with `@package` that have an `@field` decorator on every property. If this option is set to true, this behavior will be disabled, and only messages that are explicitly decorated with `@message` or that are reachable from a service operation will be emitted.",
},
},
required: [],
};
const PACKAGE_NAME = "@typespec/protobuf";
export const TypeSpecProtobufLibrary = createTypeSpecLibrary({
name: PACKAGE_NAME,
requireImports: [PACKAGE_NAME],
diagnostics: {
"field-index": {
severity: "error",
messages: {
missing: paramMessage`field ${"name"} does not have a field index, but one is required (try using the '@field' decorator)`,
invalid: paramMessage`field index ${"index"} is invalid (must be an integer greater than zero)`,
"out-of-bounds": paramMessage`field index ${"index"} is out of bounds (must be less than ${"max"})`,
reserved: paramMessage`field index ${"index"} falls within the implementation-reserved range of 19000-19999 inclusive`,
"user-reserved": paramMessage`field index ${"index"} was reserved by a call to @reserve on this model`,
"user-reserved-range": paramMessage`field index ${"index"} falls within a range reserved by a call to @reserve on this model`,
},
},
"field-name": {
severity: "error",
messages: {
"user-reserved": paramMessage`field name '${"name"}' was reserved by a call to @reserve on this model`,
},
},
"root-operation": {
severity: "error",
messages: {
default:
"operations in the root namespace are not supported (no associated Protobuf service)",
},
},
"unsupported-intrinsic": {
severity: "error",
messages: {
default: paramMessage`intrinsic type ${"name"} is not supported in Protobuf`,
},
},
"unsupported-return-type": {
severity: "error",
messages: {
default: "Protobuf methods must return a named Model",
},
},
"unsupported-input-type": {
severity: "error",
messages: {
"wrong-number":
"Protobuf methods must accept exactly one Model input (an empty model will do)",
"wrong-type": "Protobuf methods may only accept a named Model as an input",
unconvertible: "input parameters cannot be converted to a Protobuf message",
},
},
"unsupported-field-type": {
severity: "error",
messages: {
unconvertible: paramMessage`cannot convert a ${"type"} to a protobuf type (only intrinsic types and models are supported)`,
"unknown-intrinsic": paramMessage`no known protobuf scalar for intrinsic type ${"name"}`,
"unknown-scalar": paramMessage`no known protobuf scalar for TypeSpec scalar type ${"name"}`,
"recursive-map": "a protobuf map's 'value' type may not refer to another map",
union: "a message field's type may not be a union",
},
},
"namespace-collision": {
severity: "error",
messages: {
default: paramMessage`the package name ${"name"} has already been used`,
},
},
"unconvertible-enum": {
severity: "error",
messages: {
default:
"enums must explicitly assign exactly one integer to each member to be used in a Protobuf message",
"no-zero-first":
"the first variant of an enum must be set to zero to be used in a Protobuf message",
},
},
"nested-array": {
severity: "error",
messages: {
default: "nested arrays are not supported by the Protobuf emitter",
},
},
"invalid-package-name": {
severity: "error",
messages: {
default: paramMessage`${"name"} is not a valid package name (must consist of letters and numbers separated by ".")`,
},
},
"illegal-reservation": {
severity: "error",
messages: {
default:
"reservation value must be a string literal, uint32 literal, or a tuple of two uint32 literals denoting a range",
},
},
"model-not-in-package": {
severity: "error",
messages: {
default: paramMessage`model ${"name"} is not in a namespace that uses the '@Protobuf.package' decorator`,
},
},
"anonymous-model": {
severity: "error",
messages: {
default: "anonymous models cannot be used in Protobuf messages",
},
},
package: {
severity: "error",
messages: {
"disallowed-option-type": paramMessage`option '${"name"}' with type '${"type"}' is not allowed in a package declaration (only string, boolean, and numeric types are allowed)`,
},
},
},
emitter: { options: EmitterOptionsSchema },
});
export const { reportDiagnostic } = TypeSpecProtobufLibrary;
export type TypeSpecProtobufLibrary = typeof TypeSpecProtobufLibrary;
const keys = [
"fieldIndex",
"package",
"service",
"externRef",
"stream",
"reserve",
"message",
"_map",
] as const;
export const state = Object.fromEntries(
keys.map((k) => [k, TypeSpecProtobufLibrary.createStateSymbol(k)])
) as {
[K in (typeof keys)[number]]: symbol;
};