typespec-hono 0.14.0 → 0.15.0
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/dist/src/app.js +59 -2
- package/package.json +2 -2
package/dist/src/app.js
CHANGED
|
@@ -375,11 +375,68 @@ securityFor) {
|
|
|
375
375
|
: validated === undefined
|
|
376
376
|
? negotiated
|
|
377
377
|
: `${validated} & ${negotiated}`;
|
|
378
|
-
|
|
378
|
+
/**
|
|
379
|
+
* **The RETURN type drops index signatures; the input type keeps them.**
|
|
380
|
+
*
|
|
381
|
+
* A handler receives whatever the validator let through, and an open model's validator really
|
|
382
|
+
* does pass unknown keys along - so the input saying `[key: string]: unknown` describes the
|
|
383
|
+
* value in hand. Returning is the opposite direction: the handler supplies a value the
|
|
384
|
+
* application already holds, and an index signature there is an obligation rather than a
|
|
385
|
+
* description. TypeScript gives an interface no implicit index signature, so a domain type
|
|
386
|
+
* could not satisfy it without a spread at every level of the tree.
|
|
387
|
+
*
|
|
388
|
+
* `typespec-http-zod@0.17.0` took the catchall off the contract types for this reason. It did
|
|
389
|
+
* not reach here, because this signature is derived from `z.infer` rather than from those
|
|
390
|
+
* types - which is exactly the half-fix `test/openmodel/` now guards against.
|
|
391
|
+
*/
|
|
392
|
+
const output = names.response === undefined ? "void" : `Declared<z.infer<typeof ${names.response}>>`;
|
|
379
393
|
const signature = input === undefined ? "ctx: Ctx" : `ctx: Ctx, input: ${input}`;
|
|
380
394
|
const doc = route.summary === undefined ? "" : `\t/** ${route.summary} */\n`;
|
|
381
395
|
return `${doc}\t${route.operationId}(${signature}): Awaitable<Result<${output}>>;`;
|
|
382
396
|
});
|
|
397
|
+
/**
|
|
398
|
+
* Emitted only when an operation actually returns something, because a generated file has to pass
|
|
399
|
+
* `noUnusedLocals` like any other - the lint that has already failed this emitter twice over an
|
|
400
|
+
* import written for a construct the service did not use.
|
|
401
|
+
*
|
|
402
|
+
* **Decided from the routes, not by searching the rendered text.** Asking whether the output
|
|
403
|
+
* mentions a name is how this package lost the `byContentType` import: the call gained an argument
|
|
404
|
+
* and the substring stopped matching, so a module referenced a function it no longer imported.
|
|
405
|
+
*/
|
|
406
|
+
const returnsAnything = entries.some((entry) => entry.names.response !== undefined);
|
|
407
|
+
const declaredHelper = returnsAnything
|
|
408
|
+
? `/**
|
|
409
|
+
* A shape with its index signatures removed, at every depth.
|
|
410
|
+
*
|
|
411
|
+
* An open model - one declared with \`...Record<T>\` - infers \`[key: string]: unknown\`, because its
|
|
412
|
+
* validator really does pass unknown keys through. That is true of what a handler RECEIVES, so the
|
|
413
|
+
* input types above keep it. It is not true of what a handler must SUPPLY: TypeScript gives an
|
|
414
|
+
* interface no implicit index signature, so a domain type could not be returned without spreading
|
|
415
|
+
* every level of the tree, which on one real service meant a structural deep copy per response.
|
|
416
|
+
*
|
|
417
|
+
* Returning extra properties still works - excess-property checks apply to object literals, not to
|
|
418
|
+
* a value the application already holds.
|
|
419
|
+
*/
|
|
420
|
+
type Declared<T> = T extends (...args: never[]) => unknown
|
|
421
|
+
? T
|
|
422
|
+
: T extends readonly (infer Element)[]
|
|
423
|
+
? T extends Element[]
|
|
424
|
+
? Declared<Element>[]
|
|
425
|
+
: readonly Declared<Element>[]
|
|
426
|
+
: T extends object
|
|
427
|
+
? {
|
|
428
|
+
[K in keyof T as string extends K
|
|
429
|
+
? never
|
|
430
|
+
: number extends K
|
|
431
|
+
? never
|
|
432
|
+
: symbol extends K
|
|
433
|
+
? never
|
|
434
|
+
: K]: Declared<T[K]>;
|
|
435
|
+
}
|
|
436
|
+
: T;
|
|
437
|
+
|
|
438
|
+
`
|
|
439
|
+
: "";
|
|
383
440
|
const aliases = entries.map((entry) => `export type ${capitaliseId(entry.route.operationId)}Handler = Operations[${JSON.stringify(entry.route.operationId)}];`);
|
|
384
441
|
/**
|
|
385
442
|
* **Which resources get a sub-app, and which routes stay on the root.**
|
|
@@ -808,7 +865,7 @@ ${imports}
|
|
|
808
865
|
* There is no cast anywhere in this file, and no dynamic lookup: the generated call sites name the
|
|
809
866
|
* method, so an implementation whose input or output does not match the contract fails to compile.
|
|
810
867
|
*/
|
|
811
|
-
export interface Operations {
|
|
868
|
+
${declaredHelper}export interface Operations {
|
|
812
869
|
${methods.join("\n")}
|
|
813
870
|
}
|
|
814
871
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typespec-hono",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "TypeSpec emitter: generate a Hono server, and the Zod validators it enforces, from an HTTP service definition, agreeing with the OpenAPI document @typespec/openapi3 publishes from the same source.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"provenance": true
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"typespec-http-zod": "^0.
|
|
47
|
+
"typespec-http-zod": "^0.17.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@hono/zod-openapi": "^1.4.0",
|