@typespec/http-server-js 0.58.0-alpha.10-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/build-helpers.ts +170 -0
- package/dist/generated-defs/helpers/header.d.ts +4 -0
- package/dist/generated-defs/helpers/header.d.ts.map +1 -0
- package/dist/generated-defs/helpers/header.js +76 -0
- package/dist/generated-defs/helpers/header.js.map +1 -0
- package/dist/generated-defs/helpers/http.d.ts +4 -0
- package/dist/generated-defs/helpers/http.d.ts.map +1 -0
- package/dist/generated-defs/helpers/http.js +134 -0
- package/dist/generated-defs/helpers/http.js.map +1 -0
- package/dist/generated-defs/helpers/index.d.ts +4 -0
- package/dist/generated-defs/helpers/index.d.ts.map +1 -0
- package/dist/generated-defs/helpers/index.js +21 -0
- package/dist/generated-defs/helpers/index.js.map +1 -0
- package/dist/generated-defs/helpers/multipart.d.ts +4 -0
- package/dist/generated-defs/helpers/multipart.d.ts.map +1 -0
- package/dist/generated-defs/helpers/multipart.js +249 -0
- package/dist/generated-defs/helpers/multipart.js.map +1 -0
- package/dist/generated-defs/helpers/router.d.ts +4 -0
- package/dist/generated-defs/helpers/router.d.ts.map +1 -0
- package/dist/generated-defs/helpers/router.js +259 -0
- package/dist/generated-defs/helpers/router.js.map +1 -0
- package/dist/src/common/declaration.d.ts +13 -0
- package/dist/src/common/declaration.d.ts.map +1 -0
- package/dist/src/common/declaration.js +45 -0
- package/dist/src/common/declaration.js.map +1 -0
- package/dist/src/common/documentation.d.ts +12 -0
- package/dist/src/common/documentation.d.ts.map +1 -0
- package/dist/src/common/documentation.js +21 -0
- package/dist/src/common/documentation.js.map +1 -0
- package/dist/src/common/enum.d.ts +10 -0
- package/dist/src/common/enum.d.ts.map +1 -0
- package/dist/src/common/enum.js +21 -0
- package/dist/src/common/enum.js.map +1 -0
- package/dist/src/common/interface.d.ts +50 -0
- package/dist/src/common/interface.d.ts.map +1 -0
- package/dist/src/common/interface.js +194 -0
- package/dist/src/common/interface.js.map +1 -0
- package/dist/src/common/model.d.ts +26 -0
- package/dist/src/common/model.d.ts.map +1 -0
- package/dist/src/common/model.js +115 -0
- package/dist/src/common/model.js.map +1 -0
- package/dist/src/common/namespace.d.ts +38 -0
- package/dist/src/common/namespace.d.ts.map +1 -0
- package/dist/src/common/namespace.js +184 -0
- package/dist/src/common/namespace.js.map +1 -0
- package/dist/src/common/reference.d.ts +46 -0
- package/dist/src/common/reference.d.ts.map +1 -0
- package/dist/src/common/reference.js +243 -0
- package/dist/src/common/reference.js.map +1 -0
- package/dist/src/common/scalar.d.ts +50 -0
- package/dist/src/common/scalar.d.ts.map +1 -0
- package/dist/src/common/scalar.js +144 -0
- package/dist/src/common/scalar.js.map +1 -0
- package/dist/src/common/serialization/index.d.ts +11 -0
- package/dist/src/common/serialization/index.d.ts.map +1 -0
- package/dist/src/common/serialization/index.js +72 -0
- package/dist/src/common/serialization/index.js.map +1 -0
- package/dist/src/common/serialization/json.d.ts +6 -0
- package/dist/src/common/serialization/json.d.ts.map +1 -0
- package/dist/src/common/serialization/json.js +341 -0
- package/dist/src/common/serialization/json.js.map +1 -0
- package/dist/src/common/union.d.ts +23 -0
- package/dist/src/common/union.d.ts.map +1 -0
- package/dist/src/common/union.js +57 -0
- package/dist/src/common/union.js.map +1 -0
- package/dist/src/ctx.d.ts +242 -0
- package/dist/src/ctx.d.ts.map +1 -0
- package/dist/src/ctx.js +211 -0
- package/dist/src/ctx.js.map +1 -0
- package/dist/src/helpers/header.d.ts +14 -0
- package/dist/src/helpers/header.d.ts.map +1 -0
- package/dist/src/helpers/header.js +38 -0
- package/dist/src/helpers/header.js.map +1 -0
- package/dist/src/helpers/http.d.ts +70 -0
- package/dist/src/helpers/http.d.ts.map +1 -0
- package/dist/src/helpers/http.js +86 -0
- package/dist/src/helpers/http.js.map +1 -0
- package/dist/src/helpers/multipart.d.ts +26 -0
- package/dist/src/helpers/multipart.d.ts.map +1 -0
- package/dist/src/helpers/multipart.js +182 -0
- package/dist/src/helpers/multipart.js.map +1 -0
- package/dist/src/helpers/router.d.ts +176 -0
- package/dist/src/helpers/router.d.ts.map +1 -0
- package/dist/src/helpers/router.js +55 -0
- package/dist/src/helpers/router.js.map +1 -0
- package/dist/src/http/index.d.ts +24 -0
- package/dist/src/http/index.d.ts.map +1 -0
- package/dist/src/http/index.js +52 -0
- package/dist/src/http/index.js.map +1 -0
- package/dist/src/http/server/index.d.ts +11 -0
- package/dist/src/http/server/index.d.ts.map +1 -0
- package/dist/src/http/server/index.js +413 -0
- package/dist/src/http/server/index.js.map +1 -0
- package/dist/src/http/server/multipart.d.ts +16 -0
- package/dist/src/http/server/multipart.d.ts.map +1 -0
- package/dist/src/http/server/multipart.js +214 -0
- package/dist/src/http/server/multipart.js.map +1 -0
- package/dist/src/http/server/router.d.ts +15 -0
- package/dist/src/http/server/router.d.ts.map +1 -0
- package/dist/src/http/server/router.js +459 -0
- package/dist/src/http/server/router.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib.d.ts +141 -0
- package/dist/src/lib.d.ts.map +1 -0
- package/dist/src/lib.js +116 -0
- package/dist/src/lib.js.map +1 -0
- package/dist/src/scripts/scaffold/bin.d.mts +14 -0
- package/dist/src/scripts/scaffold/bin.d.mts.map +1 -0
- package/dist/src/scripts/scaffold/bin.mjs +559 -0
- package/dist/src/scripts/scaffold/bin.mjs.map +1 -0
- package/dist/src/testing/index.d.ts +3 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +6 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/util/case.d.ts +81 -0
- package/dist/src/util/case.d.ts.map +1 -0
- package/dist/src/util/case.js +111 -0
- package/dist/src/util/case.js.map +1 -0
- package/dist/src/util/differentiate.d.ts +251 -0
- package/dist/src/util/differentiate.d.ts.map +1 -0
- package/dist/src/util/differentiate.js +580 -0
- package/dist/src/util/differentiate.js.map +1 -0
- package/dist/src/util/error.d.ts +13 -0
- package/dist/src/util/error.d.ts.map +1 -0
- package/dist/src/util/error.js +25 -0
- package/dist/src/util/error.js.map +1 -0
- package/dist/src/util/extends.d.ts +10 -0
- package/dist/src/util/extends.d.ts.map +1 -0
- package/dist/src/util/extends.js +31 -0
- package/dist/src/util/extends.js.map +1 -0
- package/dist/src/util/iter.d.ts +39 -0
- package/dist/src/util/iter.d.ts.map +1 -0
- package/dist/src/util/iter.js +72 -0
- package/dist/src/util/iter.js.map +1 -0
- package/dist/src/util/keywords.d.ts +10 -0
- package/dist/src/util/keywords.d.ts.map +1 -0
- package/dist/src/util/keywords.js +85 -0
- package/dist/src/util/keywords.js.map +1 -0
- package/dist/src/util/name.d.ts +12 -0
- package/dist/src/util/name.d.ts.map +1 -0
- package/dist/src/util/name.js +26 -0
- package/dist/src/util/name.js.map +1 -0
- package/dist/src/util/once-queue.d.ts +24 -0
- package/dist/src/util/once-queue.d.ts.map +1 -0
- package/dist/src/util/once-queue.js +34 -0
- package/dist/src/util/once-queue.js.map +1 -0
- package/dist/src/util/openapi3.d.ts +23 -0
- package/dist/src/util/openapi3.d.ts.map +1 -0
- package/dist/src/util/openapi3.js +40 -0
- package/dist/src/util/openapi3.js.map +1 -0
- package/dist/src/util/pluralism.d.ts +23 -0
- package/dist/src/util/pluralism.d.ts.map +1 -0
- package/dist/src/util/pluralism.js +36 -0
- package/dist/src/util/pluralism.js.map +1 -0
- package/dist/src/util/scope.d.ts +85 -0
- package/dist/src/util/scope.d.ts.map +1 -0
- package/dist/src/util/scope.js +111 -0
- package/dist/src/util/scope.js.map +1 -0
- package/dist/src/write.d.ts +23 -0
- package/dist/src/write.d.ts.map +1 -0
- package/dist/src/write.js +62 -0
- package/dist/src/write.js.map +1 -0
- package/generated-defs/helpers/header.ts +83 -0
- package/generated-defs/helpers/http.ts +141 -0
- package/generated-defs/helpers/index.ts +27 -0
- package/generated-defs/helpers/multipart.ts +256 -0
- package/generated-defs/helpers/router.ts +266 -0
- package/package.json +71 -0
- package/src/common/declaration.ts +52 -0
- package/src/common/documentation.ts +26 -0
- package/src/common/enum.ts +28 -0
- package/src/common/interface.ts +264 -0
- package/src/common/model.ts +160 -0
- package/src/common/namespace.ts +243 -0
- package/src/common/reference.ts +319 -0
- package/src/common/scalar.ts +173 -0
- package/src/common/serialization/index.ts +124 -0
- package/src/common/serialization/json.ts +444 -0
- package/src/common/union.ts +76 -0
- package/src/ctx.ts +497 -0
- package/src/helpers/header.ts +55 -0
- package/src/helpers/http.ts +113 -0
- package/src/helpers/multipart.ts +228 -0
- package/src/helpers/router.ts +238 -0
- package/src/http/index.ts +81 -0
- package/src/http/server/index.ts +548 -0
- package/src/http/server/multipart.ts +272 -0
- package/src/http/server/router.ts +686 -0
- package/src/index.ts +56 -0
- package/src/lib.ts +130 -0
- package/src/scripts/scaffold/bin.mts +781 -0
- package/src/testing/index.ts +10 -0
- package/src/util/case.ts +182 -0
- package/src/util/differentiate.ts +957 -0
- package/src/util/error.ts +28 -0
- package/src/util/extends.ts +43 -0
- package/src/util/iter.ts +85 -0
- package/src/util/keywords.ts +90 -0
- package/src/util/name.ts +33 -0
- package/src/util/once-queue.ts +55 -0
- package/src/util/openapi3.ts +53 -0
- package/src/util/pluralism.ts +37 -0
- package/src/util/scope.ts +211 -0
- package/src/write.ts +88 -0
- package/temp/tsconfig.tsbuildinfo +1 -0
- package/test/header.test.ts +26 -0
- package/test/multipart.test.ts +169 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +4 -0
package/src/ctx.ts
ADDED
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation
|
|
2
|
+
// Licensed under the MIT license.
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
compilerAssert,
|
|
6
|
+
Enum,
|
|
7
|
+
Interface,
|
|
8
|
+
isArrayModelType,
|
|
9
|
+
isRecordModelType,
|
|
10
|
+
listServices,
|
|
11
|
+
Model,
|
|
12
|
+
Namespace,
|
|
13
|
+
NoTarget,
|
|
14
|
+
Program,
|
|
15
|
+
Scalar,
|
|
16
|
+
Service,
|
|
17
|
+
Type,
|
|
18
|
+
Union,
|
|
19
|
+
UnionVariant,
|
|
20
|
+
} from "@typespec/compiler";
|
|
21
|
+
import { emitDeclaration } from "./common/declaration.js";
|
|
22
|
+
import { createOrGetModuleForNamespace } from "./common/namespace.js";
|
|
23
|
+
import { SerializableType } from "./common/serialization/index.js";
|
|
24
|
+
import { emitUnion } from "./common/union.js";
|
|
25
|
+
import { JsEmitterOptions, reportDiagnostic } from "./lib.js";
|
|
26
|
+
import { parseCase } from "./util/case.js";
|
|
27
|
+
import { UnimplementedError } from "./util/error.js";
|
|
28
|
+
import { createOnceQueue, OnceQueue } from "./util/once-queue.js";
|
|
29
|
+
|
|
30
|
+
import { createModule as initializeHelperModule } from "../generated-defs/helpers/index.js";
|
|
31
|
+
|
|
32
|
+
export type DeclarationType = Model | Enum | Union | Interface | Scalar;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Determines whether or not a type is importable into a JavaScript module.
|
|
36
|
+
*
|
|
37
|
+
* i.e. whether or not it is declared as a named symbol within the module.
|
|
38
|
+
*
|
|
39
|
+
* In TypeScript, unions are rendered inline, so they are not ordinarily
|
|
40
|
+
* considered importable.
|
|
41
|
+
*
|
|
42
|
+
* @param ctx - The JS emitter context.
|
|
43
|
+
* @param t - the type to test
|
|
44
|
+
* @returns `true` if the type is an importable declaration, `false` otherwise.
|
|
45
|
+
*/
|
|
46
|
+
export function isImportableType(ctx: JsContext, t: Type): t is DeclarationType {
|
|
47
|
+
return (
|
|
48
|
+
(t.kind === "Model" &&
|
|
49
|
+
!isArrayModelType(ctx.program, t) &&
|
|
50
|
+
!isRecordModelType(ctx.program, t)) ||
|
|
51
|
+
t.kind === "Enum" ||
|
|
52
|
+
t.kind === "Interface"
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Stores stateful information consumed and modified by the JavaScript server
|
|
58
|
+
* emitter.
|
|
59
|
+
*/
|
|
60
|
+
export interface JsContext {
|
|
61
|
+
/**
|
|
62
|
+
* The TypeSpec Program that this emitter instance operates over.
|
|
63
|
+
*/
|
|
64
|
+
program: Program;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The emitter options.
|
|
68
|
+
*/
|
|
69
|
+
options: JsEmitterOptions;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The global (root) namespace of the program.
|
|
73
|
+
*/
|
|
74
|
+
globalNamespace: Namespace;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The service definition to use for emit.
|
|
78
|
+
*/
|
|
79
|
+
service: Service;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A queue of all types to be included in the emit tree. This queue
|
|
83
|
+
* automatically deduplicates types, so if a type is added multiple times it
|
|
84
|
+
* will only be visited once.
|
|
85
|
+
*/
|
|
86
|
+
typeQueue: OnceQueue<DeclarationType>;
|
|
87
|
+
/**
|
|
88
|
+
* A list of synthetic types (anonymous types that are given names) that are
|
|
89
|
+
* included in the emit tree.
|
|
90
|
+
*/
|
|
91
|
+
synthetics: Synthetic[];
|
|
92
|
+
/**
|
|
93
|
+
* A cache of names given to synthetic types. These names may be used to avoid
|
|
94
|
+
* emitting the same synthetic type multiple times.
|
|
95
|
+
*/
|
|
96
|
+
syntheticNames: Map<DeclarationType, string>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The root module for the emit tree.
|
|
100
|
+
*/
|
|
101
|
+
rootModule: Module;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The parent of the generated module.
|
|
105
|
+
*/
|
|
106
|
+
srcModule: Module;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The module that contains all generated code.
|
|
110
|
+
*/
|
|
111
|
+
generatedModule: Module;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A map relating each namespace to the module that contains its declarations.
|
|
115
|
+
*
|
|
116
|
+
* @see createOrGetModuleForNamespace
|
|
117
|
+
*/
|
|
118
|
+
namespaceModules: Map<Namespace, Module>;
|
|
119
|
+
/**
|
|
120
|
+
* The module that contains all synthetic types.
|
|
121
|
+
*/
|
|
122
|
+
syntheticModule: Module;
|
|
123
|
+
/**
|
|
124
|
+
* The root module for all named declarations of types referenced by the program.
|
|
125
|
+
*/
|
|
126
|
+
modelsModule: Module;
|
|
127
|
+
/**
|
|
128
|
+
* The module within `models` that maps to the global namespace.
|
|
129
|
+
*/
|
|
130
|
+
globalNamespaceModule: Module;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A map of all types that require serialization code to the formats they require.
|
|
134
|
+
*/
|
|
135
|
+
serializations: OnceQueue<SerializableType>;
|
|
136
|
+
|
|
137
|
+
gensym: (name: string) => string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function createInitialContext(
|
|
141
|
+
program: Program,
|
|
142
|
+
options: JsEmitterOptions,
|
|
143
|
+
): Promise<JsContext | undefined> {
|
|
144
|
+
const services = listServices(program);
|
|
145
|
+
|
|
146
|
+
if (services.length === 0) {
|
|
147
|
+
reportDiagnostic(program, {
|
|
148
|
+
code: "no-services-in-program",
|
|
149
|
+
target: NoTarget,
|
|
150
|
+
messageId: "default",
|
|
151
|
+
});
|
|
152
|
+
return undefined;
|
|
153
|
+
} else if (services.length > 1) {
|
|
154
|
+
throw new UnimplementedError("multiple service definitions per program.");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const [service] = services;
|
|
158
|
+
|
|
159
|
+
const serviceModuleName = parseCase(service.type.name).snakeCase;
|
|
160
|
+
|
|
161
|
+
const rootCursor = createPathCursor();
|
|
162
|
+
|
|
163
|
+
const globalNamespace = program.getGlobalNamespaceType();
|
|
164
|
+
|
|
165
|
+
// Root module for emit.
|
|
166
|
+
const rootModule: Module = {
|
|
167
|
+
name: serviceModuleName,
|
|
168
|
+
cursor: rootCursor,
|
|
169
|
+
|
|
170
|
+
imports: [],
|
|
171
|
+
declarations: [],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const srcModule = createModule("src", rootModule);
|
|
175
|
+
|
|
176
|
+
const generatedModule = createModule("generated", srcModule);
|
|
177
|
+
|
|
178
|
+
// This has the side effect of setting the `module` property of all helpers.
|
|
179
|
+
// Don't do anything with the emitter code before this is called.
|
|
180
|
+
await initializeHelperModule(generatedModule);
|
|
181
|
+
|
|
182
|
+
// Module for all models, including synthetic and all.
|
|
183
|
+
const modelsModule: Module = createModule("models", generatedModule);
|
|
184
|
+
|
|
185
|
+
// Module for all types in all namespaces.
|
|
186
|
+
const allModule: Module = createModule("all", modelsModule, globalNamespace);
|
|
187
|
+
|
|
188
|
+
// Module for all synthetic (named ad-hoc) types.
|
|
189
|
+
const syntheticModule: Module = createModule("synthetic", modelsModule);
|
|
190
|
+
|
|
191
|
+
const jsCtx: JsContext = {
|
|
192
|
+
program,
|
|
193
|
+
options,
|
|
194
|
+
globalNamespace,
|
|
195
|
+
service,
|
|
196
|
+
|
|
197
|
+
typeQueue: createOnceQueue(),
|
|
198
|
+
synthetics: [],
|
|
199
|
+
syntheticNames: new Map(),
|
|
200
|
+
|
|
201
|
+
rootModule,
|
|
202
|
+
srcModule,
|
|
203
|
+
generatedModule,
|
|
204
|
+
namespaceModules: new Map([[globalNamespace, allModule]]),
|
|
205
|
+
syntheticModule,
|
|
206
|
+
modelsModule,
|
|
207
|
+
globalNamespaceModule: allModule,
|
|
208
|
+
|
|
209
|
+
serializations: createOnceQueue(),
|
|
210
|
+
|
|
211
|
+
gensym: (name) => {
|
|
212
|
+
return gensym(jsCtx, name);
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return jsCtx;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* A synthetic type that is not directly represented with a name in the TypeSpec program.
|
|
221
|
+
*/
|
|
222
|
+
export type Synthetic = AnonymousSynthetic | PartialUnionSynthetic;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* An ordinary, anonymous type that is given a name.
|
|
226
|
+
*/
|
|
227
|
+
export interface AnonymousSynthetic {
|
|
228
|
+
kind: "anonymous";
|
|
229
|
+
name: string;
|
|
230
|
+
underlying: DeclarationType;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* A partial union with a name for the given variants.
|
|
235
|
+
*/
|
|
236
|
+
export interface PartialUnionSynthetic {
|
|
237
|
+
kind: "partialUnion";
|
|
238
|
+
name: string;
|
|
239
|
+
variants: UnionVariant[];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Adds all pending declarations from the type queue to the module tree.
|
|
244
|
+
*
|
|
245
|
+
* The JavaScript emitter is lazy, and sometimes emitter components may visit
|
|
246
|
+
* types that are not yet declared. This function ensures that all types
|
|
247
|
+
* reachable from existing declarations are complete.
|
|
248
|
+
*
|
|
249
|
+
* @param ctx - The JavaScript emitter context.
|
|
250
|
+
*/
|
|
251
|
+
export function completePendingDeclarations(ctx: JsContext): void {
|
|
252
|
+
// Add all pending declarations to the module tree.
|
|
253
|
+
while (!ctx.typeQueue.isEmpty() || ctx.synthetics.length > 0) {
|
|
254
|
+
while (!ctx.typeQueue.isEmpty()) {
|
|
255
|
+
const type = ctx.typeQueue.take()!;
|
|
256
|
+
|
|
257
|
+
compilerAssert(type.namespace !== undefined, "no namespace for declaration type", type);
|
|
258
|
+
|
|
259
|
+
const module = createOrGetModuleForNamespace(ctx, type.namespace);
|
|
260
|
+
|
|
261
|
+
module.declarations.push([...emitDeclaration(ctx, type, module)]);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
while (ctx.synthetics.length > 0) {
|
|
265
|
+
const synthetic = ctx.synthetics.shift()!;
|
|
266
|
+
|
|
267
|
+
switch (synthetic.kind) {
|
|
268
|
+
case "anonymous": {
|
|
269
|
+
ctx.syntheticModule.declarations.push([
|
|
270
|
+
...emitDeclaration(ctx, synthetic.underlying, ctx.syntheticModule, synthetic.name),
|
|
271
|
+
]);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
case "partialUnion": {
|
|
275
|
+
ctx.syntheticModule.declarations.push([
|
|
276
|
+
...emitUnion(ctx, synthetic, ctx.syntheticModule, synthetic.name),
|
|
277
|
+
]);
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// #region Module
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* A declaration within a module. This may be a string (i.e. a line), an array of
|
|
289
|
+
* strings (emitted as multiple lines), or another module (emitted as a nested module).
|
|
290
|
+
*/
|
|
291
|
+
export type ModuleBodyDeclaration = string[] | string | Module;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* A type-guard that checks whether or not a given value is a module.
|
|
295
|
+
* @returns `true` if the value is a module, `false` otherwise.
|
|
296
|
+
*/
|
|
297
|
+
export function isModule(value: unknown): value is Module {
|
|
298
|
+
return (
|
|
299
|
+
typeof value === "object" &&
|
|
300
|
+
value !== null &&
|
|
301
|
+
"declarations" in value &&
|
|
302
|
+
Array.isArray(value.declarations)
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Creates a new module with the given name and attaches it to the parent module.
|
|
308
|
+
*
|
|
309
|
+
* Optionally, a namespace may be associated with the module. This namespace is
|
|
310
|
+
* _NOT_ stored in the context (this function does not use the JsContext), and
|
|
311
|
+
* is only stored as metadata within the module. To associate a module with a
|
|
312
|
+
* namespace inside the context, use `createOrGetModuleForNamespace`.
|
|
313
|
+
*
|
|
314
|
+
* The module is automatically declared as a declaration within its parent
|
|
315
|
+
* module.
|
|
316
|
+
*
|
|
317
|
+
* @param name - The name of the module.
|
|
318
|
+
* @param parent - The parent module to attach the new module to.
|
|
319
|
+
* @param namespace - an optional TypeSpec Namespace to associate with the module
|
|
320
|
+
* @returns the newly created module
|
|
321
|
+
*/
|
|
322
|
+
export function createModule(name: string, parent: Module, namespace?: Namespace): Module {
|
|
323
|
+
const self = {
|
|
324
|
+
name,
|
|
325
|
+
cursor: parent.cursor.enter(name),
|
|
326
|
+
namespace,
|
|
327
|
+
|
|
328
|
+
imports: [],
|
|
329
|
+
declarations: [],
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
parent.declarations.push(self);
|
|
333
|
+
|
|
334
|
+
return self;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* The type of a binding for an import statement. Either:
|
|
339
|
+
*
|
|
340
|
+
* - A string beginning with `* as` followed by the name of the binding, which
|
|
341
|
+
* imports all exports from the module as a single object.
|
|
342
|
+
* - A binding name, which imports the default export of the module.
|
|
343
|
+
* - An array of strings, each of which is a named import from the module.
|
|
344
|
+
*/
|
|
345
|
+
export type ImportBinder = string | string[];
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* An object representing a ECMAScript module import declaration.
|
|
349
|
+
*/
|
|
350
|
+
export interface Import {
|
|
351
|
+
/**
|
|
352
|
+
* The binder to define the import as.
|
|
353
|
+
*/
|
|
354
|
+
binder: ImportBinder;
|
|
355
|
+
/**
|
|
356
|
+
* Where to import from. This is either a literal string (which will be used verbatim), or Module object, which will
|
|
357
|
+
* be resolved to a relative file path.
|
|
358
|
+
*/
|
|
359
|
+
from: Module | string;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* An output module within the module tree.
|
|
364
|
+
*/
|
|
365
|
+
export interface Module {
|
|
366
|
+
/**
|
|
367
|
+
* The name of the module, which should be suitable for use as the basename of
|
|
368
|
+
* a file and as an identifier.
|
|
369
|
+
*/
|
|
370
|
+
name: string;
|
|
371
|
+
/**
|
|
372
|
+
* The cursor for the module, which assists navigation and relative path
|
|
373
|
+
* computation between modules.
|
|
374
|
+
*/
|
|
375
|
+
readonly cursor: PathCursor;
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* An optional namespace for the module. This is not used by the code writer,
|
|
379
|
+
* but is used to track dependencies between TypeSpec namespaces and create
|
|
380
|
+
* imports between them.
|
|
381
|
+
*/
|
|
382
|
+
namespace?: Namespace;
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* A list of imports that the module requires.
|
|
386
|
+
*/
|
|
387
|
+
imports: Import[];
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* A list of declarations within the module.
|
|
391
|
+
*/
|
|
392
|
+
declarations: ModuleBodyDeclaration[];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// #endregion
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* A cursor that assists in navigating the module tree and computing relative
|
|
399
|
+
* paths between modules.
|
|
400
|
+
*/
|
|
401
|
+
export interface PathCursor {
|
|
402
|
+
/**
|
|
403
|
+
* The path to this cursor. This is an array of strings that represents the
|
|
404
|
+
* path from the root module to another module.
|
|
405
|
+
*/
|
|
406
|
+
readonly path: string[];
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* The parent cursor of this cursor (equivalent to moving up one level in the
|
|
410
|
+
* module tree). If this cursor is the root cursor, this property is `undefined`.
|
|
411
|
+
*/
|
|
412
|
+
readonly parent: PathCursor | undefined;
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Returns a new cursor that includes the given path components appended to
|
|
416
|
+
* this cursor's path.
|
|
417
|
+
*
|
|
418
|
+
* @param path - the path to append to this cursor
|
|
419
|
+
*/
|
|
420
|
+
enter(...path: string[]): PathCursor;
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Computes a relative path from this cursor to another cursor, using the string `up`
|
|
424
|
+
* to navigate upwards one level in the path. This is similar to `path.relative` when
|
|
425
|
+
* working with file paths, but operates over PathCursor objects.
|
|
426
|
+
*
|
|
427
|
+
* @param to - the cursor to compute the path to
|
|
428
|
+
* @param up - the string to use to move up a level in the path (defaults to "..")
|
|
429
|
+
*/
|
|
430
|
+
relativePath(to: PathCursor, up?: string): string[];
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Create a new cursor with the given path.
|
|
435
|
+
*
|
|
436
|
+
* @param base - the base path of this cursor
|
|
437
|
+
* @returns
|
|
438
|
+
*/
|
|
439
|
+
export function createPathCursor(...base: string[]): PathCursor {
|
|
440
|
+
const self: PathCursor = {
|
|
441
|
+
path: base,
|
|
442
|
+
|
|
443
|
+
get parent() {
|
|
444
|
+
return self.path.length === 0 ? undefined : createPathCursor(...self.path.slice(0, -1));
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
enter(...path: string[]) {
|
|
448
|
+
return createPathCursor(...self.path, ...path);
|
|
449
|
+
},
|
|
450
|
+
|
|
451
|
+
relativePath(to: PathCursor, up: string = ".."): string[] {
|
|
452
|
+
const commonPrefix = getCommonPrefix(self.path, to.path);
|
|
453
|
+
|
|
454
|
+
const outputPath = [];
|
|
455
|
+
|
|
456
|
+
for (let i = 0; i < self.path.length - commonPrefix.length; i++) {
|
|
457
|
+
outputPath.push(up);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
outputPath.push(...to.path.slice(commonPrefix.length));
|
|
461
|
+
|
|
462
|
+
return outputPath;
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
return self;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Compute the common prefix of two paths.
|
|
471
|
+
*/
|
|
472
|
+
function getCommonPrefix(a: string[], b: string[]): string[] {
|
|
473
|
+
const prefix = [];
|
|
474
|
+
|
|
475
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
476
|
+
if (a[i] !== b[i]) {
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
prefix.push(a[i]);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
return prefix;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const SYM_TAB = new WeakMap<Program, { idx: number }>();
|
|
487
|
+
|
|
488
|
+
export function gensym(ctx: JsContext, name: string): string {
|
|
489
|
+
let symTab = SYM_TAB.get(ctx.program);
|
|
490
|
+
|
|
491
|
+
if (symTab === undefined) {
|
|
492
|
+
symTab = { idx: 0 };
|
|
493
|
+
SYM_TAB.set(ctx.program, symTab);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return `__${name}_${symTab.idx++}`;
|
|
497
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation
|
|
2
|
+
// Licensed under the MIT license.
|
|
3
|
+
|
|
4
|
+
export interface HeaderValueParameters {
|
|
5
|
+
value: string;
|
|
6
|
+
verbatim: string;
|
|
7
|
+
params: { [k: string]: string };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parses a header value that may contain additional parameters (e.g. `text/html; charset=utf-8`).
|
|
12
|
+
* @param headerValueText - the text of the header value to parse
|
|
13
|
+
* @returns an object containing the value and a map of parameters
|
|
14
|
+
*/
|
|
15
|
+
export function parseHeaderValueParameters<Header extends string | undefined>(
|
|
16
|
+
headerValueText: Header,
|
|
17
|
+
): undefined extends Header ? HeaderValueParameters | undefined : HeaderValueParameters {
|
|
18
|
+
if (headerValueText === undefined) {
|
|
19
|
+
return undefined as any;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const idx = headerValueText.indexOf(";");
|
|
23
|
+
const [value, _paramsText] =
|
|
24
|
+
idx === -1
|
|
25
|
+
? [headerValueText, ""]
|
|
26
|
+
: [headerValueText.slice(0, idx), headerValueText.slice(idx + 1)];
|
|
27
|
+
|
|
28
|
+
let paramsText = _paramsText;
|
|
29
|
+
|
|
30
|
+
// Parameters are a sequence of key=value pairs separated by semicolons, but the value may be quoted in which case it
|
|
31
|
+
// may contain semicolons. We use a regular expression to iteratively split the parameters into key=value pairs.
|
|
32
|
+
const params: { [k: string]: string } = {};
|
|
33
|
+
|
|
34
|
+
let match;
|
|
35
|
+
|
|
36
|
+
// TODO: may need to support ext-parameter (e.g. "filename*=UTF-8''%e2%82%ac%20rates" => { filename: "€ rates" }).
|
|
37
|
+
// By default we decoded everything as UTF-8, and non-UTF-8 agents are a dying breed, but we may need to support
|
|
38
|
+
// this for completeness. If we do support it, we'll prefer an ext-parameter over a regular parameter. Currently, we'll
|
|
39
|
+
// just treat them as separate keys and put the raw value in the parameter.
|
|
40
|
+
//
|
|
41
|
+
// https://datatracker.ietf.org/doc/html/rfc5987#section-3.2.1
|
|
42
|
+
while ((match = paramsText.match(/\s*([^=]+)=(?:"([^"]+)"|([^;]+));?/))) {
|
|
43
|
+
const [, key, quotedValue, unquotedValue] = match;
|
|
44
|
+
|
|
45
|
+
params[key.trim()] = quotedValue ?? unquotedValue;
|
|
46
|
+
|
|
47
|
+
paramsText = paramsText.slice(match[0].length);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
value: value.trim(),
|
|
52
|
+
verbatim: headerValueText,
|
|
53
|
+
params,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
import { HttpContext } from "./router.js";
|
|
5
|
+
|
|
6
|
+
export const HTTP_RESPONDER = Symbol.for("@typespec/http-server-js.HttpResponder");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A type that can respond to an HTTP request.
|
|
10
|
+
*/
|
|
11
|
+
export interface HttpResponder {
|
|
12
|
+
/**
|
|
13
|
+
* A function that handles an HTTP request and response.
|
|
14
|
+
*
|
|
15
|
+
* @param context - The HTTP context.
|
|
16
|
+
*/
|
|
17
|
+
[HTTP_RESPONDER]: (context: HttpContext) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Determines if a value is an HttpResponder.
|
|
22
|
+
* @param value - The value to check.
|
|
23
|
+
* @returns `true` if the value is an HttpResponder, otherwise `false`.
|
|
24
|
+
*/
|
|
25
|
+
export function isHttpResponder(value: unknown): value is HttpResponder {
|
|
26
|
+
return (
|
|
27
|
+
typeof value === "object" &&
|
|
28
|
+
value !== null &&
|
|
29
|
+
HTTP_RESPONDER in value &&
|
|
30
|
+
typeof value[HTTP_RESPONDER] === "function"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* An Error that can respond to an HTTP request if thrown from a route handler.
|
|
36
|
+
*/
|
|
37
|
+
export class HttpResponderError extends Error implements HttpResponder {
|
|
38
|
+
#statusCode: number;
|
|
39
|
+
|
|
40
|
+
constructor(statusCode: number, message: string) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.#statusCode = statusCode;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[HTTP_RESPONDER](ctx: HttpContext): void {
|
|
46
|
+
ctx.response.statusCode = this.#statusCode;
|
|
47
|
+
ctx.response.setHeader("Content-Type", "text/plain");
|
|
48
|
+
ctx.response.end(this.message);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The requested resource was not found.
|
|
54
|
+
*/
|
|
55
|
+
export class NotFoundError extends HttpResponderError {
|
|
56
|
+
constructor() {
|
|
57
|
+
super(404, "Not Found");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The request was malformed.
|
|
63
|
+
*/
|
|
64
|
+
export class BadRequestError extends HttpResponderError {
|
|
65
|
+
constructor() {
|
|
66
|
+
super(400, "Bad Request");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The request is missing required authentication credentials.
|
|
72
|
+
*/
|
|
73
|
+
export class UnauthorizedError extends HttpResponderError {
|
|
74
|
+
constructor() {
|
|
75
|
+
super(401, "Unauthorized");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The request is missing required permissions.
|
|
81
|
+
*/
|
|
82
|
+
export class ForbiddenError extends HttpResponderError {
|
|
83
|
+
constructor() {
|
|
84
|
+
super(403, "Forbidden");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The request conflicts with the current state of the server.
|
|
90
|
+
*/
|
|
91
|
+
export class ConflictError extends HttpResponderError {
|
|
92
|
+
constructor() {
|
|
93
|
+
super(409, "Conflict");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The server encountered an unexpected condition that prevented it from fulfilling the request.
|
|
99
|
+
*/
|
|
100
|
+
export class InternalServerError extends HttpResponderError {
|
|
101
|
+
constructor() {
|
|
102
|
+
super(500, "Internal Server Error");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The server does not support the functionality required to fulfill the request.
|
|
108
|
+
*/
|
|
109
|
+
export class NotImplementedError extends HttpResponderError {
|
|
110
|
+
constructor() {
|
|
111
|
+
super(501, "Not Implemented");
|
|
112
|
+
}
|
|
113
|
+
}
|