@nxgt/typespec 0.12.0 → 0.13.1
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/README.md +57 -14
- package/dist/emitter.d.ts +12 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -2
- package/dist/index.js.map +8 -6
- package/dist/lib.d.ts +9 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/operation-ids.d.ts +1 -1
- package/dist/query-method.d.ts +6 -1
- package/dist/query-method.d.ts.map +1 -1
- package/dist/query-operations.d.ts +8 -0
- package/dist/query-operations.d.ts.map +1 -0
- package/dist/resource.d.ts +1 -1
- package/docs/README.md +1 -0
- package/docs/guide/emitter.md +159 -0
- package/docs/guide/errors.md +2 -2
- package/docs/guide/getting-started.md +9 -5
- package/docs/guide/linter.md +2 -2
- package/docs/guide/operation-ids.md +17 -14
- package/docs/roadmap.md +17 -6
- package/docs/troubleshooting.md +65 -7
- package/package.json +14 -5
- package/templates/scaffolding.json +3 -2
package/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
nxgt's HTTP conventions as a [TypeSpec](https://typespec.io) library, so an
|
|
4
4
|
API spec states them in one word instead of rewriting them. Compile the spec to
|
|
5
|
-
OpenAPI 3.1 or 3.2 with `@typespec/openapi3`,
|
|
5
|
+
OpenAPI 3.1 or 3.2 with its emitter, `@nxgt/typespec` (`@typespec/openapi3`, and a
|
|
6
|
+
real `QUERY` in 3.2), then generate the code with
|
|
6
7
|
[`@nxgt/openapi-codegen`](https://github.com/softistx/nxgt-http/blob/develop/packages/openapi-codegen/README.md).
|
|
7
8
|
Each shape here is one the `@nxgt/*` packages already send on the wire.
|
|
8
9
|
|
|
@@ -18,20 +19,22 @@ bun add -d @nxgt/typespec @typespec/compiler @typespec/http @typespec/openapi @t
|
|
|
18
19
|
|
|
19
20
|
`@typespec/compiler`, `@typespec/http` and `@typespec/openapi` 1.16 or later
|
|
20
21
|
are peer dependencies,
|
|
21
|
-
and `typescript` 6 or 7 too, as for every `@nxgt` package.
|
|
22
|
-
|
|
22
|
+
and `typescript` 6 or 7 too, as for every `@nxgt` package.
|
|
23
|
+
`@typespec/openapi3` 1.16 or later is an optional peer, loaded only when the
|
|
24
|
+
spec is emitted: install it to compile the spec to OpenAPI.
|
|
25
|
+
`@nxgt/openapi-codegen` generates the code from the document.
|
|
23
26
|
The generator's CLI, `nxgt-openapi`, runs on [Bun](https://bun.sh): it needs
|
|
24
27
|
`bun` on the PATH, even when called through `npx` or an npm script.
|
|
25
|
-
Emit OpenAPI 3.1 or 3.2 in `tspconfig.yaml
|
|
26
|
-
by default, and the generator refuses it. Every convention here is compiled
|
|
28
|
+
Emit OpenAPI 3.1 or 3.2 in `tspconfig.yaml` with this package's emitter:
|
|
29
|
+
`@typespec/openapi3` emits 3.0 by default, and the generator refuses it. Every convention here is compiled
|
|
27
30
|
to both in CI, and generates the same code from either.
|
|
28
31
|
|
|
29
32
|
```yaml
|
|
30
33
|
# api/tspconfig.yaml
|
|
31
34
|
emit:
|
|
32
|
-
- '@typespec
|
|
35
|
+
- '@nxgt/typespec'
|
|
33
36
|
options:
|
|
34
|
-
'@typespec
|
|
37
|
+
'@nxgt/typespec':
|
|
35
38
|
openapi-versions: ['3.1.0']
|
|
36
39
|
emitter-output-dir: '{project-root}/../openapi'
|
|
37
40
|
output-file: openapi.yaml
|
|
@@ -56,7 +59,7 @@ It installs the compiler, `@typespec/http`, `@typespec/openapi`,
|
|
|
56
59
|
`@typespec/openapi3`, this package and `@nxgt/openapi-codegen`, and writes:
|
|
57
60
|
|
|
58
61
|
- `tspconfig.yaml`: the linter's recommended rules, and OpenAPI 3.1 written
|
|
59
|
-
to `openapi/openapi.yaml`;
|
|
62
|
+
to `openapi/openapi.yaml` by the emitter `@nxgt/typespec`;
|
|
60
63
|
- `main.tsp`: the service in the namespace `Api`, with `@operationIds`, and a
|
|
61
64
|
`Users` resource with a paged, sorted list, `get`, `create`, `update` and
|
|
62
65
|
`delete`, and their error aliases;
|
|
@@ -459,10 +462,12 @@ The verbs `verbs` adds are not checked, nor an operation with its own
|
|
|
459
462
|
### A search with a body
|
|
460
463
|
|
|
461
464
|
`QUERY` is the HTTP method for a safe request with a body, and
|
|
462
|
-
`@typespec/http` 1.17 declares none. Mark a `@post` with `@queryMethod
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
`@
|
|
465
|
+
`@typespec/http` 1.17 declares none. Mark a `@post` with `@queryMethod`, and
|
|
466
|
+
emit OpenAPI 3.2 with the emitter [`@nxgt/typespec`](#the-emitter): the
|
|
467
|
+
document gets a real `query` operation. Only 3.2 has one, so the mark with
|
|
468
|
+
any older version in `openapi-versions`, or with the plain `@typespec/openapi3`
|
|
469
|
+
emitter, is an error, not a `POST`: `query-method-needs-openapi-3.2`,
|
|
470
|
+
`query-method-needs-nxgt-emitter`.
|
|
466
471
|
|
|
467
472
|
```tsp
|
|
468
473
|
@route("/authors")
|
|
@@ -477,7 +482,34 @@ interface Authors {
|
|
|
477
482
|
`QUERY` is not their method. The decorator on anything but a `@post` is the
|
|
478
483
|
error `query-method-not-post`. When `@typespec/http` declares `QUERY`, the
|
|
479
484
|
decorator is what changes, not your spec. More, in
|
|
480
|
-
[Operation ids](docs/guide/operation-ids.md#a-query-
|
|
485
|
+
[Operation ids](docs/guide/operation-ids.md#a-query-in-openapi-32) and
|
|
486
|
+
[The emitter](docs/guide/emitter.md).
|
|
487
|
+
|
|
488
|
+
### The emitter
|
|
489
|
+
|
|
490
|
+
`@nxgt/typespec` is also a TypeSpec emitter. It runs `@typespec/openapi3` with
|
|
491
|
+
the options and the files you give that one, and in an OpenAPI 3.2 document
|
|
492
|
+
moves each `@post` marked `@queryMethod` to a `query` operation, in place and
|
|
493
|
+
without `x-nxgt-method`. Without a marked operation its output is
|
|
494
|
+
byte-identical to `@typespec/openapi3`'s. With a marked operation and an
|
|
495
|
+
older version in `openapi-versions` (unset means 3.0), it reports
|
|
496
|
+
`query-method-needs-openapi-3.2` and emits nothing.
|
|
497
|
+
|
|
498
|
+
```yaml
|
|
499
|
+
# api/tspconfig.yaml
|
|
500
|
+
emit:
|
|
501
|
+
- '@nxgt/typespec'
|
|
502
|
+
options:
|
|
503
|
+
'@nxgt/typespec':
|
|
504
|
+
openapi-versions: ['3.2.0'] # 3.1.0 is an error beside a @queryMethod
|
|
505
|
+
emitter-output-dir: '{project-root}/../openapi'
|
|
506
|
+
output-file: openapi.yaml
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
`@nxgt/openapi-codegen` then generates `method: 'query'`, `@nxgt/openapi-hono`
|
|
510
|
+
serves `.query(...)`, and the `@nxgt/httpyz` client sends `QUERY`. A real
|
|
511
|
+
`QUERY` needs a server stack that accepts the method, and a preflight under
|
|
512
|
+
CORS: [The emitter](docs/guide/emitter.md#a-query-on-the-wire).
|
|
481
513
|
|
|
482
514
|
### Linter
|
|
483
515
|
|
|
@@ -513,7 +545,7 @@ passing example of each rule, in [Linter](docs/guide/linter.md).
|
|
|
513
545
|
|
|
514
546
|
| Decorator | On | What it does |
|
|
515
547
|
| --- | --- | --- |
|
|
516
|
-
| `@queryMethod` | an operation | marks a `@post` as a `QUERY`:
|
|
548
|
+
| `@queryMethod` | an operation | marks a `@post` as a `QUERY`: needs the emitter `@nxgt/typespec` and OpenAPI 3.2, where the document gets a `query` operation, and is an error otherwise; `@operationIds` checks its verb as a `QUERY`'s |
|
|
517
549
|
| `@operationIds(options?: OperationIdsOptions)` | a namespace or an interface | makes each operation's id its name, as written, or a known verb with the interface's resource (`list` in `Users` is `listUsers`), in the namespace however deep or in the interface, unless it has an `@operationId` |
|
|
518
550
|
|
|
519
551
|
`OperationIdsOptions` is `#{ singular?: string, plural?: string, verbs?: Record<"singular" | "plural"> }`:
|
|
@@ -522,6 +554,12 @@ overrides verbs, on a namespace or an interface.
|
|
|
522
554
|
|
|
523
555
|
`@queryMethod` has no options.
|
|
524
556
|
|
|
557
|
+
### Emitter
|
|
558
|
+
|
|
559
|
+
| Name | In | What it does |
|
|
560
|
+
| --- | --- | --- |
|
|
561
|
+
| `@nxgt/typespec` | `emit:` in `tspconfig.yaml` | `@typespec/openapi3` with its options and files; each marked `@post` becomes a `query` operation in a 3.2 document, and a marked one with an older version is an error. Needs the optional peer `@typespec/openapi3` |
|
|
562
|
+
|
|
525
563
|
### Diagnostics
|
|
526
564
|
|
|
527
565
|
| Code | Reported when |
|
|
@@ -532,6 +570,9 @@ overrides verbs, on a namespace or an interface.
|
|
|
532
570
|
| `merged-status-reply` | warning: an operation declares two replies with a body of one status code, which the emitter merges under the first one's description |
|
|
533
571
|
| `verb-method-mismatch` | warning: an operation `@operationIds` names after one of the library's verbs, in an interface, is sent with a method that verb does not name: `create` with a `GET`, or marked `@queryMethod` |
|
|
534
572
|
| `query-method-not-post` | error: an operation marked `@queryMethod` is not a `@post` |
|
|
573
|
+
| `query-method-needs-openapi-3.2` | error: the emitter `@nxgt/typespec` is asked for a version below 3.2 (or none, which is 3.0) beside a `@queryMethod`; nothing is emitted |
|
|
574
|
+
| `query-method-needs-nxgt-emitter` | error: `@typespec/openapi3` is in `emit` beside a `@queryMethod` |
|
|
575
|
+
| `openapi3-missing` | error: the emitter `@nxgt/typespec` runs `@typespec/openapi3`, which is not installed |
|
|
535
576
|
|
|
536
577
|
### Linter rules
|
|
537
578
|
|
|
@@ -690,6 +731,8 @@ envelope and the rate limit's headers.
|
|
|
690
731
|
|
|
691
732
|
- [Getting started](docs/guide/getting-started.md): the `tsp init`
|
|
692
733
|
template, the files it writes, and the steps from the spec to a Hono route;
|
|
734
|
+
- [The emitter](docs/guide/emitter.md): `@nxgt/typespec` in `tspconfig.yaml`,
|
|
735
|
+
a `@queryMethod` as a real `QUERY` in OpenAPI 3.2, and what that needs;
|
|
693
736
|
- [Error replies](docs/guide/errors.md): the envelope, each response, the
|
|
694
737
|
aliases by verb, and what the generator makes of them;
|
|
695
738
|
- [Pagination](docs/guide/pagination.md): offset and cursor pages, and
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The emitter `@nxgt/typespec`: `@typespec/openapi3`, with its options,
|
|
3
|
+
* checked by its own schema, and its files, and each `POST` marked
|
|
4
|
+
* `@queryMethod` a real `QUERY` in an OpenAPI 3.2 document
|
|
5
|
+
* (`query-operations.ts`). Only 3.2 has a `QUERY`: a marked operation with
|
|
6
|
+
* an older version asked for is an error, and nothing is emitted.
|
|
7
|
+
* `@typespec/openapi3` is loaded only here, so a spec that only imports the
|
|
8
|
+
* library does not need it.
|
|
9
|
+
*/
|
|
10
|
+
import { type EmitContext } from '@typespec/compiler';
|
|
11
|
+
export declare function $onEmit(context: EmitContext): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAGN,KAAK,WAAW,EAEhB,MAAM,oBAAoB,CAAC;AAmE5B,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BjE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* export would declare it a second time, in the global namespace.
|
|
8
8
|
*/
|
|
9
9
|
import type { Program } from '@typespec/compiler';
|
|
10
|
-
import { operationIds } from './operation-ids';
|
|
11
|
-
import { queryMethod } from './query-method';
|
|
12
|
-
export { $
|
|
13
|
-
export { $
|
|
10
|
+
import { operationIds } from './operation-ids.js';
|
|
11
|
+
import { queryMethod } from './query-method.js';
|
|
12
|
+
export { $onEmit } from './emitter.js';
|
|
13
|
+
export { $lib } from './lib.js';
|
|
14
|
+
export { $linter } from './linter.js';
|
|
14
15
|
export declare function $onValidate(program: Program): void;
|
|
15
16
|
export declare const $decorators: {
|
|
16
17
|
Nxgt: {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAwB,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAwB,MAAM,gBAAgB,CAAC;AAGnE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAOlD;AAED,eAAO,MAAM,WAAW;;;;;CAEvB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAwB,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAwB,MAAM,gBAAgB,CAAC;AAGnE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAOlD;AAED,eAAO,MAAM,WAAW;;;;;CAEvB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,25 @@ var $lib = createTypeSpecLibrary({
|
|
|
42
42
|
"query-method-not-post": {
|
|
43
43
|
severity: "error",
|
|
44
44
|
messages: {
|
|
45
|
-
default: paramMessage`${"operation"} is marked @queryMethod and sent with ${"method"}: a
|
|
45
|
+
default: paramMessage`${"operation"} is marked @queryMethod and sent with ${"method"}: @queryMethod marks a @post, which @nxgt/typespec writes as a QUERY in OpenAPI 3.2. Make it a @post.`
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"query-method-needs-openapi-3.2": {
|
|
49
|
+
severity: "error",
|
|
50
|
+
messages: {
|
|
51
|
+
default: paramMessage`${"operation"} is marked @queryMethod: only OpenAPI 3.2 has a QUERY operation, and openapi-versions asks for ${"version"}. Emit 3.2 only, or take off @queryMethod.`
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"query-method-needs-nxgt-emitter": {
|
|
55
|
+
severity: "error",
|
|
56
|
+
messages: {
|
|
57
|
+
default: paramMessage`${"operation"} is marked @queryMethod: emit with @nxgt/typespec, which writes it as a QUERY; @typespec/openapi3 would write a POST.`
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"openapi3-missing": {
|
|
61
|
+
severity: "error",
|
|
62
|
+
messages: {
|
|
63
|
+
default: "The emitter @nxgt/typespec runs @typespec/openapi3, which is not installed: add it beside @nxgt/typespec."
|
|
46
64
|
}
|
|
47
65
|
},
|
|
48
66
|
"duplicate-status-reply": {
|
|
@@ -58,6 +76,7 @@ var $lib = createTypeSpecLibrary({
|
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
78
|
},
|
|
79
|
+
capabilities: { dryRun: true },
|
|
61
80
|
state: {
|
|
62
81
|
queryMethod: {
|
|
63
82
|
description: "The operations marked with @queryMethod"
|
|
@@ -338,6 +357,9 @@ function queryMethod(context, target) {
|
|
|
338
357
|
function isQueryMethod(program, operation) {
|
|
339
358
|
return program.stateSet($lib.stateKeys.queryMethod).has(operation);
|
|
340
359
|
}
|
|
360
|
+
function queryMethods(program) {
|
|
361
|
+
return [...program.stateSet($lib.stateKeys.queryMethod)];
|
|
362
|
+
}
|
|
341
363
|
function validateQueryMethods(program) {
|
|
342
364
|
eachHttpOperation(program, ({ operation, verb: method }) => {
|
|
343
365
|
if (!isQueryMethod(program, operation) || method === "post")
|
|
@@ -348,6 +370,16 @@ function validateQueryMethods(program) {
|
|
|
348
370
|
target: operation
|
|
349
371
|
});
|
|
350
372
|
});
|
|
373
|
+
if (!(program.compilerOptions.emit ?? []).includes("@typespec/openapi3")) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
for (const operation of queryMethods(program)) {
|
|
377
|
+
$lib.reportDiagnostic(program, {
|
|
378
|
+
code: "query-method-needs-nxgt-emitter",
|
|
379
|
+
format: { operation: operation.name },
|
|
380
|
+
target: operation
|
|
381
|
+
});
|
|
382
|
+
}
|
|
351
383
|
}
|
|
352
384
|
|
|
353
385
|
// src/verb-methods.ts
|
|
@@ -380,6 +412,119 @@ function validateVerbMethods(program) {
|
|
|
380
412
|
});
|
|
381
413
|
});
|
|
382
414
|
}
|
|
415
|
+
|
|
416
|
+
// src/emitter.ts
|
|
417
|
+
import {
|
|
418
|
+
NoTarget
|
|
419
|
+
} from "@typespec/compiler";
|
|
420
|
+
|
|
421
|
+
// src/query-operations.ts
|
|
422
|
+
import { parse, stringify } from "yaml";
|
|
423
|
+
function moveQueries(document) {
|
|
424
|
+
if (!String(document["openapi"]).startsWith("3.2"))
|
|
425
|
+
return false;
|
|
426
|
+
const paths = document["paths"];
|
|
427
|
+
if (typeof paths !== "object" || paths === null)
|
|
428
|
+
return false;
|
|
429
|
+
let moved = false;
|
|
430
|
+
for (const [path, item] of Object.entries(paths)) {
|
|
431
|
+
const post = item["post"];
|
|
432
|
+
if (post?.["x-nxgt-method"] !== "query" || item["query"] !== undefined) {
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
const { "x-nxgt-method": _, ...operation } = post;
|
|
436
|
+
paths[path] = Object.fromEntries(Object.entries(item).map(([key, value]) => key === "post" ? ["query", operation] : [key, value]));
|
|
437
|
+
moved = true;
|
|
438
|
+
}
|
|
439
|
+
return moved;
|
|
440
|
+
}
|
|
441
|
+
function withQueryOperations(content) {
|
|
442
|
+
const json = content.trimStart().startsWith("{");
|
|
443
|
+
const document = json ? JSON.parse(content) : parse(content);
|
|
444
|
+
if (typeof document !== "object" || document === null)
|
|
445
|
+
return content;
|
|
446
|
+
if (!moveQueries(document))
|
|
447
|
+
return content;
|
|
448
|
+
const text = json ? `${JSON.stringify(document, null, 2)}
|
|
449
|
+
` : stringify(document, {
|
|
450
|
+
singleQuote: true,
|
|
451
|
+
aliasDuplicateObjects: false,
|
|
452
|
+
lineWidth: 0,
|
|
453
|
+
compat: "yaml-1.1"
|
|
454
|
+
});
|
|
455
|
+
return content.includes(`\r
|
|
456
|
+
`) ? text.replace(/\n/g, `\r
|
|
457
|
+
`) : text;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/emitter.ts
|
|
461
|
+
var DEFAULT_VERSIONS = ["3.0.0"];
|
|
462
|
+
function invalidOptions(openapi3, options) {
|
|
463
|
+
const lib = openapi3.$lib;
|
|
464
|
+
const validator = "emitterOptionValidator" in lib ? lib.emitterOptionValidator : undefined;
|
|
465
|
+
if (typeof validator !== "object" || validator === null || !("validate" in validator) || typeof validator.validate !== "function") {
|
|
466
|
+
return [];
|
|
467
|
+
}
|
|
468
|
+
return validator.validate(options, NoTarget);
|
|
469
|
+
}
|
|
470
|
+
async function loadOpenAPI3(context) {
|
|
471
|
+
try {
|
|
472
|
+
return await import("@typespec/openapi3");
|
|
473
|
+
} catch {
|
|
474
|
+
$lib.reportDiagnostic(context.program, {
|
|
475
|
+
code: "openapi3-missing",
|
|
476
|
+
target: NoTarget
|
|
477
|
+
});
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function queriesFit(context) {
|
|
482
|
+
const { program } = context;
|
|
483
|
+
const marked = queryMethods(program);
|
|
484
|
+
if (marked.length === 0)
|
|
485
|
+
return true;
|
|
486
|
+
const versions = context.options["openapi-versions"] ?? DEFAULT_VERSIONS;
|
|
487
|
+
const older = versions.find((version) => !version.startsWith("3.2"));
|
|
488
|
+
if (older === undefined)
|
|
489
|
+
return true;
|
|
490
|
+
for (const operation of marked) {
|
|
491
|
+
$lib.reportDiagnostic(program, {
|
|
492
|
+
code: "query-method-needs-openapi-3.2",
|
|
493
|
+
format: { operation: operation.name, version: older },
|
|
494
|
+
target: operation
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
async function $onEmit(context) {
|
|
500
|
+
const openapi3 = await loadOpenAPI3(context);
|
|
501
|
+
if (openapi3 === undefined)
|
|
502
|
+
return;
|
|
503
|
+
const { program } = context;
|
|
504
|
+
const invalid = invalidOptions(openapi3, context.options);
|
|
505
|
+
if (invalid.length > 0) {
|
|
506
|
+
program.reportDiagnostics(invalid);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (!queriesFit(context))
|
|
510
|
+
return;
|
|
511
|
+
const host = program.host;
|
|
512
|
+
const writing = new Proxy(host, {
|
|
513
|
+
get(target, key) {
|
|
514
|
+
if (key === "writeFile") {
|
|
515
|
+
return (path, content) => target.writeFile(path, withQueryOperations(content));
|
|
516
|
+
}
|
|
517
|
+
const value = Reflect.get(target, key, target);
|
|
518
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
program.host = writing;
|
|
522
|
+
try {
|
|
523
|
+
await openapi3.$onEmit(context);
|
|
524
|
+
} finally {
|
|
525
|
+
program.host = host;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
383
528
|
// src/linter.ts
|
|
384
529
|
import { defineLinter } from "@typespec/compiler";
|
|
385
530
|
|
|
@@ -516,8 +661,9 @@ export {
|
|
|
516
661
|
$decorators,
|
|
517
662
|
$lib,
|
|
518
663
|
$linter,
|
|
664
|
+
$onEmit,
|
|
519
665
|
$onValidate
|
|
520
666
|
};
|
|
521
667
|
|
|
522
|
-
//# debugId=
|
|
668
|
+
//# debugId=3B14A4A66C69185964756E2164756E21
|
|
523
669
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/one-reply-per-status.ts", "../src/http-operations.ts", "../src/lib.ts", "../src/operation-ids.ts", "../src/verbs.ts", "../src/resource.ts", "../src/query-method.ts", "../src/verb-methods.ts", "../src/linter.ts", "../src/rules/error-body-shape.ts", "../src/rules/written.ts", "../src/rules/list-returns-page.ts", "../src/rules/service-operation-ids.ts", "../src/index.ts"],
|
|
3
|
+
"sources": ["../src/one-reply-per-status.ts", "../src/http-operations.ts", "../src/lib.ts", "../src/operation-ids.ts", "../src/verbs.ts", "../src/resource.ts", "../src/query-method.ts", "../src/verb-methods.ts", "../src/emitter.ts", "../src/query-operations.ts", "../src/linter.ts", "../src/rules/error-body-shape.ts", "../src/rules/written.ts", "../src/rules/list-returns-page.ts", "../src/rules/service-operation-ids.ts", "../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * One reply per status: `@typespec/openapi3` merges two replies of one\n * status into one without a word. A reply without a body beside one with a\n * body is lost in the merge, an error; a `void` body is none, as the emitter\n * sees it. Two bodies of one content type are merged under the first reply's\n * description, a warning where the status is a code. Under `*` or a range,\n * where undocumented `@error` models share one description, they pass.\n * Bodies of different content types are one reply, negotiated, and pass.\n */\nimport { isVoidType, type Program } from '@typespec/compiler';\nimport type {\n\tHttpOperationResponse,\n\tHttpStatusCodesEntry,\n} from '@typespec/http';\nimport { eachHttpOperation } from './http-operations';\nimport { $lib } from './lib';\n\nfunction statusOf(code: HttpStatusCodesEntry): string {\n\treturn typeof code === 'object' ? `${code.start}-${code.end}` : `${code}`;\n}\n\n/** What the emitter's merge costs: a reply, a description, or nothing. */\nfunction mergeOf({\n\tstatusCodes,\n\tresponses,\n}: HttpOperationResponse):\n\t| 'duplicate-status-reply'\n\t| 'merged-status-reply'\n\t| undefined {\n\tconst bodies = responses.flatMap(({ body }) =>\n\t\tbody && !isVoidType(body.type) ? [body] : [],\n\t);\n\tif (bodies.length > 0 && bodies.length < responses.length) {\n\t\treturn 'duplicate-status-reply';\n\t}\n\tif (typeof statusCodes !== 'number') return undefined;\n\tconst seen = new Set<string>();\n\tfor (const body of bodies) {\n\t\tif (body.contentTypes.some((type) => seen.has(type))) {\n\t\t\treturn 'merged-status-reply';\n\t\t}\n\t\tfor (const type of body.contentTypes) seen.add(type);\n\t}\n\treturn undefined;\n}\n\n/** Checks each operation of each service, as the emitter sees it, once. */\nexport function validateOneReplyPerStatus(program: Program): void {\n\teachHttpOperation(program, (operation) => {\n\t\tfor (const response of operation.responses) {\n\t\t\tconst code = mergeOf(response);\n\t\t\tif (code === undefined) continue;\n\t\t\t$lib.reportDiagnostic(program, {\n\t\t\t\tcode,\n\t\t\t\tformat: {\n\t\t\t\t\toperation: operation.operation.name,\n\t\t\t\t\tstatus: statusOf(response.statusCodes),\n\t\t\t\t},\n\t\t\t\ttarget: operation.operation,\n\t\t\t});\n\t\t}\n\t});\n}\n",
|
|
6
6
|
"/**\n * Each HTTP operation of each service, once, as the emitter sends it: a\n * service nested in another lists its operations in both. The services' own\n * diagnostics are the emitter's to report.\n */\nimport type { Program } from '@typespec/compiler';\nimport { getAllHttpServices, type HttpOperation } from '@typespec/http';\n\nexport function eachHttpOperation(\n\tprogram: Program,\n\tvisit: (operation: HttpOperation) => void,\n): void {\n\tconst [services] = getAllHttpServices(program);\n\tconst visited = new Set<HttpOperation['operation']>();\n\tfor (const service of services) {\n\t\tfor (const operation of service.operations) {\n\t\t\tif (visited.has(operation.operation)) continue;\n\t\t\tvisited.add(operation.operation);\n\t\t\tvisit(operation);\n\t\t}\n\t}\n}\n",
|
|
7
|
-
"/** The library's definition: its name, diagnostics and state keys. */\nimport { createTypeSpecLibrary, paramMessage } from '@typespec/compiler';\n\nexport const $lib = createTypeSpecLibrary({\n\tname: '@nxgt/typespec',\n\tdiagnostics: {\n\t\t'duplicate-operation-id': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`Two operations are named ${'id'}: an OpenAPI operation id must be unique.`,\n\t\t\t},\n\t\t},\n\t\t'resource-name-on-namespace': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault:\n\t\t\t\t\t\"`singular` and `plural` name an interface's resource: a namespace has none. Put them on the interface.\",\n\t\t\t},\n\t\t},\n\t\t'verb-method-mismatch': {\n\t\t\tseverity: 'warning',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} is sent with ${'method'}, where its verb ${'verb'} is sent with ${'expected'}. Give it that method, or a name that is not a verb.`,\n\t\t\t},\n\t\t},\n\t\t'query-method-not-post': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} is marked @queryMethod and sent with ${'method'}: a QUERY is
|
|
7
|
+
"/** The library's definition: its name, diagnostics and state keys. */\nimport { createTypeSpecLibrary, paramMessage } from '@typespec/compiler';\n\nexport const $lib = createTypeSpecLibrary({\n\tname: '@nxgt/typespec',\n\tdiagnostics: {\n\t\t'duplicate-operation-id': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`Two operations are named ${'id'}: an OpenAPI operation id must be unique.`,\n\t\t\t},\n\t\t},\n\t\t'resource-name-on-namespace': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault:\n\t\t\t\t\t\"`singular` and `plural` name an interface's resource: a namespace has none. Put them on the interface.\",\n\t\t\t},\n\t\t},\n\t\t'verb-method-mismatch': {\n\t\t\tseverity: 'warning',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} is sent with ${'method'}, where its verb ${'verb'} is sent with ${'expected'}. Give it that method, or a name that is not a verb.`,\n\t\t\t},\n\t\t},\n\t\t'query-method-not-post': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} is marked @queryMethod and sent with ${'method'}: @queryMethod marks a @post, which @nxgt/typespec writes as a QUERY in OpenAPI 3.2. Make it a @post.`,\n\t\t\t},\n\t\t},\n\t\t'query-method-needs-openapi-3.2': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} is marked @queryMethod: only OpenAPI 3.2 has a QUERY operation, and openapi-versions asks for ${'version'}. Emit 3.2 only, or take off @queryMethod.`,\n\t\t\t},\n\t\t},\n\t\t'query-method-needs-nxgt-emitter': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} is marked @queryMethod: emit with @nxgt/typespec, which writes it as a QUERY; @typespec/openapi3 would write a POST.`,\n\t\t\t},\n\t\t},\n\t\t'openapi3-missing': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault:\n\t\t\t\t\t'The emitter @nxgt/typespec runs @typespec/openapi3, which is not installed: add it beside @nxgt/typespec.',\n\t\t\t},\n\t\t},\n\t\t'duplicate-status-reply': {\n\t\t\tseverity: 'error',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} declares a reply without a body and one with a body of status ${'status'}: the emitter merges them into one, and the reply without a body is lost. Declare the one the route sends.`,\n\t\t\t},\n\t\t},\n\t\t'merged-status-reply': {\n\t\t\tseverity: 'warning',\n\t\t\tmessages: {\n\t\t\t\tdefault: paramMessage`${'operation'} declares two replies with a body of status ${'status'}: the emitter merges their bodies under the first one's description. Declare the one the route sends.`,\n\t\t\t},\n\t\t},\n\t},\n\t// `@typespec/openapi3` returns before writing anything on a dry run.\n\tcapabilities: { dryRun: true },\n\tstate: {\n\t\tqueryMethod: {\n\t\t\tdescription: 'The operations marked with @queryMethod',\n\t\t},\n\t\toperationIds: {\n\t\t\tdescription: 'The interfaces and namespaces marked with @operationIds',\n\t\t},\n\t\toperationIdsOptions: {\n\t\t\tdescription:\n\t\t\t\t\"Each marked interface's or namespace's @operationIds options\",\n\t\t},\n\t},\n});\n",
|
|
8
8
|
"/**\n * `@operationIds`: the id of each operation is its name, as written:\n * `@get findPostComments()` is `findPostComments`, where `@typespec/openapi3`\n * would write `Posts_findPostComments`. In an interface, a known verb takes\n * the interface's resource: `create` in `Users` is `createUser` (`verbs.ts`).\n */\nimport {\n\ttype DecoratorContext,\n\ttype Interface,\n\tisService,\n\tisTemplateInstance,\n\tlistServices,\n\ttype Namespace,\n\tnavigateProgram,\n\ttype Operation,\n\ttype Program,\n} from '@typespec/compiler';\nimport {\n\tgetOperationId,\n\tresolveOperationId,\n\tsetOperationId,\n} from '@typespec/openapi';\nimport { $lib } from './lib';\nimport { idOf, type OperationIdsOptions } from './resource';\n\n/**\n * Marks the interface or the namespace; its ids are set once the program is\n * checked. On a template, TypeSpec runs it on each instance, which\n * `isMarkedInterface` follows to the interfaces extending it. A namespace\n * has no resource to name: `singular` and `plural` are an interface's.\n */\nexport function operationIds(\n\tcontext: DecoratorContext,\n\ttarget: Interface | Namespace,\n\toptions: OperationIdsOptions = {},\n): void {\n\tconst { program } = context;\n\tprogram.stateSet($lib.stateKeys.operationIds).add(target);\n\tprogram.stateMap($lib.stateKeys.operationIdsOptions).set(target, options);\n\tif (\n\t\ttarget.kind === 'Namespace' &&\n\t\t(options.singular !== undefined || options.plural !== undefined)\n\t) {\n\t\t$lib.reportDiagnostic(program, {\n\t\t\tcode: 'resource-name-on-namespace',\n\t\t\ttarget: context.decoratorTarget,\n\t\t});\n\t}\n}\n\n/** Marked itself, or in a marked namespace, however deep. */\nexport function isMarkedNamespace(\n\tprogram: Program,\n\ttarget: Namespace | undefined,\n): boolean {\n\tfor (let at = target; at !== undefined; at = at.namespace) {\n\t\tif (program.stateSet($lib.stateKeys.operationIds).has(at)) return true;\n\t}\n\treturn false;\n}\n\n/** Marked itself, or extending a marked interface: an instance of a marked template included. */\nfunction isMarkedInterface(program: Program, target: Interface): boolean {\n\treturn (\n\t\tprogram.stateSet($lib.stateKeys.operationIds).has(target) ||\n\t\ttarget.sourceInterfaces.some((source) => isMarkedInterface(program, source))\n\t);\n}\n\n/**\n * Whether `@operationIds` names the operation's id, or checks it: its\n * interface or one of its namespaces is marked. An interface template's\n * instance is never emitted; only the interfaces extending it are.\n */\nexport function isNamed(program: Program, operation: Operation): boolean {\n\tconst container = operation.interface;\n\tif (container === undefined) {\n\t\treturn isMarkedNamespace(program, operation.namespace);\n\t}\n\treturn (\n\t\t!isTemplateInstance(container) &&\n\t\t(isMarkedInterface(program, container) ||\n\t\t\tisMarkedNamespace(program, container.namespace))\n\t);\n}\n\n/**\n * Whether the emitter writes the operation: not an instance of an operation\n * template, `Read<Pet>`, nor an operation of an interface template's\n * instance. An interface extending an instance copies its operations, which\n * are instances too, and emitted.\n */\nexport function isEmitted(operation: Operation): boolean {\n\tconst container = operation.interface;\n\tif (container === undefined) return !isTemplateInstance(operation);\n\treturn !isTemplateInstance(container);\n}\n\n/**\n * The services whose document the operation is in: each `@service`\n * namespace around it, a nested one and the one outside it both. None, in a\n * program without a service, is the one document the emitter writes; in a\n * program with one, no document at all.\n */\nfunction servicesOf(program: Program, operation: Operation): Namespace[] {\n\tconst services: Namespace[] = [];\n\tfor (\n\t\tlet at = operation.interface?.namespace ?? operation.namespace;\n\t\tat !== undefined;\n\t\tat = at.namespace\n\t) {\n\t\tif (isService(program, at)) services.push(at);\n\t}\n\treturn services;\n}\n\n/**\n * Sets the ids, after every decorator, so the order of `@operationId` and\n * `@operationIds` in the source does not matter. Two operations with one id\n * in one service's document, one of them named by `@operationIds`, are an\n * error: one name in two interfaces, an interface that `extends` another and\n * so copies its operations, or an `@operationId` written elsewhere.\n * `@typespec/openapi3` would emit both without a word. An operation\n * template's instance, such as `Read<Pet>`, is never emitted; only the\n * operations declared from it (`op readPet is Read<Pet>`) are.\n */\nexport function validateOperationIds(program: Program): void {\n\tconst seen = new Map<Namespace | undefined, Map<string, boolean>>();\n\tconst hasServices = listServices(program).length > 0;\n\tnavigateProgram(program, {\n\t\toperation(operation) {\n\t\t\tif (!isEmitted(operation)) return;\n\t\t\tconst named = isNamed(program, operation);\n\t\t\tconst own = getOperationId(program, operation);\n\t\t\t// Elsewhere, only checked: the id `@typespec/openapi3` gives under its\n\t\t\t// default strategy.\n\t\t\tconst id =\n\t\t\t\town ??\n\t\t\t\t(named\n\t\t\t\t\t? idOf(program, operation)\n\t\t\t\t\t: resolveOperationId(program, operation));\n\t\t\tconst services = servicesOf(program, operation);\n\t\t\t// Outside every service of a program that has one: in no document.\n\t\t\tconst emitted = services.length > 0 || !hasServices;\n\t\t\tlet duplicate = false;\n\t\t\tfor (const service of services.length > 0 ? services : [undefined]) {\n\t\t\t\tconst ids = seen.get(service) ?? new Map<string, boolean>();\n\t\t\t\tseen.set(service, ids);\n\t\t\t\tif (emitted && ids.has(id) && (named || ids.get(id))) duplicate = true;\n\t\t\t\tids.set(id, named || (ids.get(id) ?? false));\n\t\t\t}\n\t\t\tif (duplicate) {\n\t\t\t\t$lib.reportDiagnostic(program, {\n\t\t\t\t\tcode: 'duplicate-operation-id',\n\t\t\t\t\tformat: { id },\n\t\t\t\t\ttarget: operation,\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Only the ids it gives: an explicit id on any other operation would\n\t\t\t// override the emitter's `operation-id-strategy`.\n\t\t\tif (named && own === undefined) setOperationId(program, operation, id);\n\t\t},\n\t});\n}\n",
|
|
9
9
|
"/**\n * The verbs `@operationIds` completes with an interface's resource: `create`\n * in `Users` is `createUser`, `list` is `listUsers`, and `findById` is\n * `findUserById`. Any other name is the id as written.\n */\n\n/** Whether a verb takes the resource's singular or its plural. */\nexport type Grammar = 'singular' | 'plural';\n\n/** A resource's two names: `User` and `Users`. */\nexport interface Resource {\n\treadonly singular: string;\n\treadonly plural: string;\n}\n\n/** The library's own verbs. */\nexport const VERBS: Readonly<Record<string, Grammar>> = {\n\tlist: 'plural',\n\tread: 'plural',\n\tfind: 'plural',\n\tsearch: 'plural',\n\tquery: 'plural',\n\tcount: 'plural',\n\tcreateMany: 'plural',\n\tupdateMany: 'plural',\n\tdeleteMany: 'plural',\n\tget: 'singular',\n\tcreate: 'singular',\n\tupdate: 'singular',\n\tpatch: 'singular',\n\treplace: 'singular',\n\tupsert: 'singular',\n\tdelete: 'singular',\n};\n\n/**\n * The HTTP methods each of the library's verbs is sent with: a read is a\n * `GET` (or a `HEAD`), a search may carry its criteria in a `POST` body, a\n * bulk delete its ids. A `QUERY`, a `POST` marked `@queryMethod`, is\n * a search too.\n */\nexport const METHODS: Readonly<Record<string, readonly string[]>> = {\n\tlist: ['get', 'head'],\n\tread: ['get', 'head'],\n\tfind: ['get', 'head'],\n\tcount: ['get', 'head'],\n\tget: ['get', 'head'],\n\tsearch: ['get', 'post', 'query'],\n\tquery: ['get', 'post', 'query'],\n\tcreate: ['post'],\n\tcreateMany: ['post'],\n\tupdate: ['put', 'patch'],\n\tupdateMany: ['put', 'patch'],\n\tpatch: ['patch'],\n\treplace: ['put'],\n\tupsert: ['put'],\n\tdelete: ['delete'],\n\tdeleteMany: ['delete', 'post'],\n};\n\n/** Plurals the rules below get wrong, by their singular. */\nconst IRREGULAR: Readonly<Record<string, string>> = {\n\tpeople: 'person',\n\tchildren: 'child',\n\tmen: 'man',\n\twomen: 'woman',\n\tmice: 'mouse',\n\tfeet: 'foot',\n\tteeth: 'tooth',\n\tgeese: 'goose',\n\tmovies: 'movie',\n\tcookies: 'cookie',\n\tseries: 'series',\n\tspecies: 'species',\n\tnews: 'news',\n};\n\n/** `-es` plurals of a singular in `-us`: `Statuses`, not `Houses`. */\nconst US_ES = /(stat|bon|camp|vir|b|foc|cens|corp|radi|syllab)uses$/i;\n\n/** `-es` plurals of a singular in a sibilant: `Boxes`, `Matches`, `Wishes`. */\nconst SIBILANT_ES = /(ss|x|zz|sh|tch|nch|rch|oach)es$/i;\n\n/**\n * The singular of a plural name, by a short English rule on its last word:\n * `Users`, `BlogPosts`, `Categories`, `Addresses`, `Statuses`, `People`. A\n * guess: it misses some (`Heroes`, `Analysis`), which `singular` names.\n */\nexport function singularOf(plural: string): string {\n\tconst word = /[A-Z]?[a-z0-9]*$/.exec(plural)?.[0] ?? '';\n\tconst head = plural.slice(0, plural.length - word.length);\n\tconst key = word.toLowerCase();\n\tconst irregular = Object.hasOwn(IRREGULAR, key) ? IRREGULAR[key] : undefined;\n\tif (irregular !== undefined) {\n\t\tconst cased = word[0] === word[0]?.toUpperCase();\n\t\treturn `${head}${cased ? irregular[0]?.toUpperCase() + irregular.slice(1) : irregular}`;\n\t}\n\tif (/ies$/.test(word) && word.length > 4)\n\t\treturn `${head}${word.slice(0, -3)}y`;\n\tif (US_ES.test(word) || SIBILANT_ES.test(word)) {\n\t\treturn `${head}${word.slice(0, -2)}`;\n\t}\n\tif (/[^su]s$/.test(word)) return `${head}${word.slice(0, -1)}`;\n\treturn plural;\n}\n\n/**\n * The verb a name starts with, and the rest: the whole name, `list`, or the\n * verb before a `By`, `findById`. `undefined` when the name is neither.\n */\nexport function verbIn(\n\tname: string,\n\tverbs: Readonly<Record<string, Grammar>>,\n): { readonly verb: string; readonly rest: string } | undefined {\n\tif (Object.hasOwn(verbs, name)) return { verb: name, rest: '' };\n\tfor (const by of name.matchAll(/By[A-Z]/g)) {\n\t\tconst verb = name.slice(0, by.index);\n\t\tif (verb !== '' && Object.hasOwn(verbs, verb)) {\n\t\t\treturn { verb, rest: name.slice(by.index) };\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/**\n * The id of an operation of a resource: the verb and the resource's singular\n * or plural, or the verb, the resource and the rest of a `By` name:\n * `findById` to `findUserById`, the singular, but `deleteManyByTeam` to\n * `deleteManyUsersByTeam`, the plural of a `*Many` verb. `undefined` when\n * the name is none of them. The resource is taken only then.\n */\nexport function idWithVerb(\n\tname: string,\n\tresource: () => Resource,\n\tverbs: Readonly<Record<string, Grammar>>,\n): string | undefined {\n\tconst found = verbIn(name, verbs);\n\tif (found === undefined) return undefined;\n\tconst { verb, rest } = found;\n\tconst names = resource();\n\tconst noun =\n\t\trest === ''\n\t\t\t? names[verbs[verb] as Grammar]\n\t\t\t: verb.endsWith('Many')\n\t\t\t\t? names.plural\n\t\t\t\t: names.singular;\n\treturn `${verb}${noun}${rest}`;\n}\n",
|
|
10
10
|
"/**\n * What `@operationIds` names an operation of an interface after: the\n * interface's resource, its singular and plural, and the verbs that take\n * them, layered from the library's, the namespaces', and the interface's.\n */\nimport type {\n\tInterface,\n\tNamespace,\n\tOperation,\n\tProgram,\n} from '@typespec/compiler';\nimport { $lib } from './lib';\nimport {\n\ttype Grammar,\n\tidWithVerb,\n\ttype Resource,\n\tsingularOf,\n\tVERBS,\n\tverbIn,\n} from './verbs';\n\n/** `@operationIds`' options, as `OperationIdsOptions` declares them. */\nexport interface OperationIdsOptions {\n\treadonly singular?: string;\n\treadonly plural?: string;\n\treadonly verbs?: Readonly<Record<string, Grammar>>;\n}\n\nfunction optionsOf(\n\tprogram: Program,\n\ttarget: Interface | Namespace,\n): OperationIdsOptions | undefined {\n\treturn program.stateMap($lib.stateKeys.operationIdsOptions).get(target);\n}\n\n/** The interface, then those it extends, however deep. */\nfunction lineageOf(target: Interface): Interface[] {\n\treturn [target, ...target.sourceInterfaces.flatMap(lineageOf)];\n}\n\n/**\n * The verbs an interface's operations take: the library's, then each marked\n * namespace's around it, outermost first, then its lineage's, its own last,\n * each overriding the one before.\n */\nfunction verbsOf(program: Program, target: Interface): Record<string, Grammar> {\n\tconst namespaces: Namespace[] = [];\n\tfor (let at = target.namespace; at !== undefined; at = at.namespace) {\n\t\tnamespaces.unshift(at);\n\t}\n\tconst layers = [...namespaces, ...lineageOf(target).reverse()];\n\treturn Object.assign(\n\t\t{},\n\t\tVERBS,\n\t\t...layers.map((layer) => optionsOf(program, layer)?.verbs ?? {}),\n\t);\n}\n\n/**\n * An interface's resource: its own `plural`, or its name, and its own\n * `singular`, or the plural's singular. Never an interface it extends: two\n * interfaces extending one would share its names, and collide.\n */\nfunction resourceOf(program: Program, target: Interface): Resource {\n\tconst options = optionsOf(program, target);\n\tconst plural = options?.plural || target.name;\n\treturn { plural, singular: options?.singular || singularOf(plural) };\n}\n\n/** The id `@operationIds` gives: the name as written, or a verb with its resource. */\nexport function idOf(program: Program, operation: Operation): string {\n\tconst container = operation.interface;\n\tif (container === undefined) return operation.name;\n\treturn (\n\t\tidWithVerb(\n\t\t\toperation.name,\n\t\t\t() => resourceOf(program, container),\n\t\t\tverbsOf(program, container),\n\t\t) ?? operation.name\n\t);\n}\n\n/** The verb an operation of an interface is named with, `find` in `findById`. */\nexport function verbOf(\n\tprogram: Program,\n\toperation: Operation,\n): string | undefined {\n\tconst container = operation.interface;\n\tif (container === undefined) return undefined;\n\treturn verbIn(operation.name, verbsOf(program, container))?.verb;\n}\n",
|
|
11
|
-
"/**\n * `@queryMethod`: a `POST` that is a `QUERY`, a safe request with its\n * criteria in the body. `@typespec/http` declares no `QUERY` yet, so the\n * operation is sent as a `POST` and the document marks it,\n * `x-nxgt-method: query`, for `@nxgt/openapi-codegen`.\n */\nimport type { DecoratorContext, Operation, Program } from '@typespec/compiler';\nimport { setExtension } from '@typespec/openapi';\nimport { eachHttpOperation } from './http-operations';\nimport { $lib } from './lib';\n\nexport function queryMethod(\n\tcontext: DecoratorContext,\n\ttarget: Operation,\n): void {\n\tconst { program } = context;\n\tprogram.stateSet($lib.stateKeys.queryMethod).add(target);\n\tsetExtension(program, target, 'x-nxgt-method', 'query');\n}\n\n/** Marked with `@queryMethod`. */\nexport function isQueryMethod(program: Program, operation: Operation): boolean {\n\treturn program.stateSet($lib.stateKeys.queryMethod).has(operation);\n}\n\n/** Each marked operation is a `POST`, as the emitter sends it
|
|
11
|
+
"/**\n * `@queryMethod`: a `POST` that is a `QUERY`, a safe request with its\n * criteria in the body. `@typespec/http` declares no `QUERY` yet, so the\n * operation is sent as a `POST` and the document marks it,\n * `x-nxgt-method: query`, for `@nxgt/openapi-codegen`.\n */\nimport type { DecoratorContext, Operation, Program } from '@typespec/compiler';\nimport { setExtension } from '@typespec/openapi';\nimport { eachHttpOperation } from './http-operations';\nimport { $lib } from './lib';\n\nexport function queryMethod(\n\tcontext: DecoratorContext,\n\ttarget: Operation,\n): void {\n\tconst { program } = context;\n\tprogram.stateSet($lib.stateKeys.queryMethod).add(target);\n\tsetExtension(program, target, 'x-nxgt-method', 'query');\n}\n\n/** Marked with `@queryMethod`. */\nexport function isQueryMethod(program: Program, operation: Operation): boolean {\n\treturn program.stateSet($lib.stateKeys.queryMethod).has(operation);\n}\n\n/** The operations marked with `@queryMethod`, each once. */\nexport function queryMethods(program: Program): Operation[] {\n\treturn [...program.stateSet($lib.stateKeys.queryMethod)] as Operation[];\n}\n\n/**\n * Each marked operation is a `POST`, as the emitter sends it, and is emitted\n * by `@nxgt/typespec`: `@typespec/openapi3` alone would write the `POST`.\n */\nexport function validateQueryMethods(program: Program): void {\n\teachHttpOperation(program, ({ operation, verb: method }) => {\n\t\tif (!isQueryMethod(program, operation) || method === 'post') return;\n\t\t$lib.reportDiagnostic(program, {\n\t\t\tcode: 'query-method-not-post',\n\t\t\tformat: { operation: operation.name, method: method.toUpperCase() },\n\t\t\ttarget: operation,\n\t\t});\n\t});\n\tif (!(program.compilerOptions.emit ?? []).includes('@typespec/openapi3')) {\n\t\treturn;\n\t}\n\tfor (const operation of queryMethods(program)) {\n\t\t$lib.reportDiagnostic(program, {\n\t\t\tcode: 'query-method-needs-nxgt-emitter',\n\t\t\tformat: { operation: operation.name },\n\t\t\ttarget: operation,\n\t\t});\n\t}\n}\n",
|
|
12
12
|
"/**\n * A verb names what an operation does, and its method says the same:\n * `create` in `Users` is `createUser`, and a `GET` would tell a cache, a\n * proxy or a retry it is safe. An operation `@operationIds` names after one\n * of the library's verbs is sent with that verb's methods (`verbs.ts`), or\n * warned of. A verb `verbs` adds has no method to check, and an operation's\n * own `@operationId` is an id that is no verb. It runs before\n * `validateOperationIds` sets the others.\n */\nimport type { Program } from '@typespec/compiler';\nimport { getOperationId } from '@typespec/openapi';\nimport { eachHttpOperation } from './http-operations';\nimport { $lib } from './lib';\nimport { isNamed } from './operation-ids';\nimport { isQueryMethod } from './query-method';\nimport { verbOf } from './resource';\nimport { METHODS } from './verbs';\n\n/** `PUT or PATCH`. */\nfunction methodsOf(methods: readonly string[]): string {\n\treturn methods.map((method) => method.toUpperCase()).join(' or ');\n}\n\n/** Checks each operation of each service once, as the emitter sends it. */\nexport function validateVerbMethods(program: Program): void {\n\teachHttpOperation(program, ({ operation, verb: sent }) => {\n\t\tif (!isNamed(program, operation)) return;\n\t\tif (getOperationId(program, operation) !== undefined) return;\n\t\tconst verb = verbOf(program, operation);\n\t\tif (verb === undefined || !Object.hasOwn(METHODS, verb)) return;\n\t\t// A `POST` marked `@queryMethod` is checked as the `QUERY` it is.\n\t\tconst method =\n\t\t\tsent === 'post' && isQueryMethod(program, operation) ? 'query' : sent;\n\t\tconst expected = METHODS[verb] as readonly string[];\n\t\tif (expected.includes(method)) return;\n\t\t$lib.reportDiagnostic(program, {\n\t\t\tcode: 'verb-method-mismatch',\n\t\t\tformat: {\n\t\t\t\toperation: operation.name,\n\t\t\t\tmethod: method.toUpperCase(),\n\t\t\t\tverb,\n\t\t\t\texpected: methodsOf(expected),\n\t\t\t},\n\t\t\ttarget: operation,\n\t\t});\n\t});\n}\n",
|
|
13
|
+
"/**\n * The emitter `@nxgt/typespec`: `@typespec/openapi3`, with its options,\n * checked by its own schema, and its files, and each `POST` marked\n * `@queryMethod` a real `QUERY` in an OpenAPI 3.2 document\n * (`query-operations.ts`). Only 3.2 has a `QUERY`: a marked operation with\n * an older version asked for is an error, and nothing is emitted.\n * `@typespec/openapi3` is loaded only here, so a spec that only imports the\n * library does not need it.\n */\nimport {\n\ttype CompilerHost,\n\ttype Diagnostic,\n\ttype EmitContext,\n\tNoTarget,\n} from '@typespec/compiler';\nimport { $lib } from './lib';\nimport { queryMethods } from './query-method';\nimport { withQueryOperations } from './query-operations';\n\n/** `@typespec/openapi3`'s default, when `openapi-versions` is not set. */\nconst DEFAULT_VERSIONS = ['3.0.0'];\n\ntype OpenAPI3 = typeof import('@typespec/openapi3');\n\n/**\n * `@typespec/openapi3`'s options checked by its own schema, as the compiler\n * checks them under its name: `createTypeSpecLibrary` gives each library an\n * `emitterOptionValidator`, which its types leave out.\n */\nfunction invalidOptions(\n\topenapi3: OpenAPI3,\n\toptions: unknown,\n): readonly Diagnostic[] {\n\tconst lib: object = openapi3.$lib;\n\tconst validator =\n\t\t'emitterOptionValidator' in lib ? lib.emitterOptionValidator : undefined;\n\tif (\n\t\ttypeof validator !== 'object' ||\n\t\tvalidator === null ||\n\t\t!('validate' in validator) ||\n\t\ttypeof validator.validate !== 'function'\n\t) {\n\t\treturn [];\n\t}\n\treturn validator.validate(options, NoTarget);\n}\n\nasync function loadOpenAPI3(\n\tcontext: EmitContext,\n): Promise<OpenAPI3 | undefined> {\n\ttry {\n\t\treturn await import('@typespec/openapi3');\n\t} catch {\n\t\t$lib.reportDiagnostic(context.program, {\n\t\t\tcode: 'openapi3-missing',\n\t\t\ttarget: NoTarget,\n\t\t});\n\t\treturn undefined;\n\t}\n}\n\n/** Whether every version asked for has a `QUERY`; each marked operation is reported otherwise. */\nfunction queriesFit(context: EmitContext): boolean {\n\tconst { program } = context;\n\tconst marked = queryMethods(program);\n\tif (marked.length === 0) return true;\n\tconst versions =\n\t\t(context.options['openapi-versions'] as string[] | undefined) ??\n\t\tDEFAULT_VERSIONS;\n\tconst older = versions.find((version) => !version.startsWith('3.2'));\n\tif (older === undefined) return true;\n\tfor (const operation of marked) {\n\t\t$lib.reportDiagnostic(program, {\n\t\t\tcode: 'query-method-needs-openapi-3.2',\n\t\t\tformat: { operation: operation.name, version: older },\n\t\t\ttarget: operation,\n\t\t});\n\t}\n\treturn false;\n}\n\nexport async function $onEmit(context: EmitContext): Promise<void> {\n\tconst openapi3 = await loadOpenAPI3(context);\n\tif (openapi3 === undefined) return;\n\tconst { program } = context;\n\t// `@typespec/openapi3`'s schema: a typo or a bad value is refused, as\n\t// under its own name, instead of reaching it unchecked.\n\tconst invalid = invalidOptions(openapi3, context.options);\n\tif (invalid.length > 0) {\n\t\tprogram.reportDiagnostics(invalid);\n\t\treturn;\n\t}\n\tif (!queriesFit(context)) return;\n\t// Every file `@typespec/openapi3` writes goes through `program.host`: a\n\t// stand-in whose every call is the real host's, on the real host.\n\tconst host = program.host;\n\tconst writing = new Proxy(host, {\n\t\tget(target, key) {\n\t\t\tif (key === 'writeFile') {\n\t\t\t\treturn (path: string, content: string) =>\n\t\t\t\t\ttarget.writeFile(path, withQueryOperations(content));\n\t\t\t}\n\t\t\tconst value = Reflect.get(target, key, target);\n\t\t\treturn typeof value === 'function' ? value.bind(target) : value;\n\t\t},\n\t}) satisfies CompilerHost;\n\tprogram.host = writing;\n\ttry {\n\t\tawait openapi3.$onEmit(context as Parameters<OpenAPI3['$onEmit']>[0]);\n\t} finally {\n\t\tprogram.host = host;\n\t}\n}\n",
|
|
14
|
+
"/**\n * A `POST` marked `@queryMethod` made the `QUERY` it is, in an emitted\n * OpenAPI 3.2 document: its operation moves from `post` to `query` and loses\n * `x-nxgt-method`, which says nothing more there. A 3.1 document has no\n * `query` operation and keeps the `POST` and the mark. The text is written\n * again as `@typespec/openapi3` writes it, and left alone when nothing moves.\n */\nimport { parse, stringify } from 'yaml';\n\ntype PathItem = Record<string, unknown>;\n\n/** Moves each marked `post` of a 3.2 document to `query`; whether any moved. */\nfunction moveQueries(document: Record<string, unknown>): boolean {\n\tif (!String(document['openapi']).startsWith('3.2')) return false;\n\tconst paths = document['paths'];\n\tif (typeof paths !== 'object' || paths === null) return false;\n\tlet moved = false;\n\tfor (const [path, item] of Object.entries(\n\t\tpaths as Record<string, PathItem>,\n\t)) {\n\t\tconst post = item['post'] as Record<string, unknown> | undefined;\n\t\tif (post?.['x-nxgt-method'] !== 'query' || item['query'] !== undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst { 'x-nxgt-method': _, ...operation } = post;\n\t\t// In place of the `post`, so the path item keeps its order.\n\t\t(paths as Record<string, PathItem>)[path] = Object.fromEntries(\n\t\t\tObject.entries(item).map(([key, value]) =>\n\t\t\t\tkey === 'post' ? ['query', operation] : [key, value],\n\t\t\t),\n\t\t);\n\t\tmoved = true;\n\t}\n\treturn moved;\n}\n\n/**\n * The document's text with its queries moved. The format is the text's:\n * `@typespec/openapi3` writes YAML whatever the file is named, unless\n * `file-type` says JSON. Line endings stay as written: `new-line: crlf`\n * reaches here already applied.\n */\nexport function withQueryOperations(content: string): string {\n\tconst json = content.trimStart().startsWith('{');\n\tconst document = (json ? JSON.parse(content) : parse(content)) as unknown;\n\tif (typeof document !== 'object' || document === null) return content;\n\tif (!moveQueries(document as Record<string, unknown>)) return content;\n\tconst text = json\n\t\t? `${JSON.stringify(document, null, 2)}\\n`\n\t\t: // `@typespec/openapi3`'s own options, so the rest of the text is unchanged.\n\t\t\tstringify(document, {\n\t\t\t\tsingleQuote: true,\n\t\t\t\taliasDuplicateObjects: false,\n\t\t\t\tlineWidth: 0,\n\t\t\t\tcompat: 'yaml-1.1',\n\t\t\t});\n\treturn content.includes('\\r\\n') ? text.replace(/\\n/g, '\\r\\n') : text;\n}\n",
|
|
13
15
|
"/**\n * The library's linter: rules a spec opts into in its `tspconfig.yaml`,\n * each a warning, each one it can turn off.\n *\n * ```yaml\n * linter:\n * extends:\n * - \"@nxgt/typespec/recommended\"\n * ```\n */\nimport { defineLinter } from '@typespec/compiler';\nimport { errorBodyShape } from './rules/error-body-shape';\nimport { listReturnsPage } from './rules/list-returns-page';\nimport { serviceOperationIds } from './rules/service-operation-ids';\n\nconst rules = [listReturnsPage, serviceOperationIds, errorBodyShape];\n\nexport const $linter = defineLinter({\n\trules,\n\truleSets: {\n\t\trecommended: {\n\t\t\tenable: Object.fromEntries(\n\t\t\t\trules.map(({ name }) => [`@nxgt/typespec/${name}`, true]),\n\t\t\t),\n\t\t},\n\t},\n});\n",
|
|
14
16
|
"/**\n * An error reply's body is the envelope `@nxgt/openapi-hono` sends: a\n * `status`, a `message` and a `timestamp`, as `ErrorBody<Status>` declares\n * them. A reply without a body passes: `AuthenticationRequired` has none.\n */\nimport {\n\tcreateRule,\n\tisVoidType,\n\ttype Model,\n\tparamMessage,\n\twalkPropertiesInherited,\n} from '@typespec/compiler';\nimport { getHttpOperation } from '@typespec/http';\nimport { isWritten } from './written';\n\nconst ENVELOPE = ['status', 'message', 'timestamp'];\n\n/** Its own properties and those of the models it extends. */\nfunction isEnvelope(body: Model): boolean {\n\tconst names = new Set(\n\t\t[...walkPropertiesInherited(body)].map(({ name }) => name),\n\t);\n\treturn ENVELOPE.every((name) => names.has(name));\n}\n\nfunction statusOf(code: number | { start: number; end: number } | '*'): string {\n\treturn typeof code === 'object' ? `${code.start}-${code.end}` : `${code}`;\n}\n\nexport const errorBodyShape = createRule({\n\tname: 'error-body-shape',\n\tseverity: 'warning',\n\tdescription:\n\t\t'An error reply has the nxgt envelope: status, message and timestamp.',\n\tmessages: {\n\t\tdefault: paramMessage`${'operation'} answers ${'status'} with a body that is not the nxgt envelope: declare BadRequest, NotFound or another of the library's errors, or a body that spreads or extends ErrorBody<Status>.`,\n\t},\n\tcreate: (context) => ({\n\t\toperation(operation) {\n\t\t\tif (!isWritten(operation)) return;\n\t\t\tconst [http] = getHttpOperation(context.program, operation);\n\t\t\tfor (const { statusCodes, responses } of http.responses) {\n\t\t\t\tconst error =\n\t\t\t\t\tstatusCodes === '*' ||\n\t\t\t\t\t(typeof statusCodes === 'number'\n\t\t\t\t\t\t? statusCodes >= 400\n\t\t\t\t\t\t: statusCodes.start >= 400);\n\t\t\t\tif (!error) continue;\n\t\t\t\tconst wrong = responses.some(({ body }) => {\n\t\t\t\t\tif (body === undefined || isVoidType(body.type)) return false;\n\t\t\t\t\treturn body.type.kind !== 'Model' || !isEnvelope(body.type);\n\t\t\t\t});\n\t\t\t\tif (!wrong) continue;\n\t\t\t\tcontext.reportDiagnostic({\n\t\t\t\t\tformat: { operation: operation.name, status: statusOf(statusCodes) },\n\t\t\t\t\ttarget: operation,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t}),\n});\n",
|
|
15
17
|
"/**\n * Whether the emitter writes an operation: not a template's declaration,\n * nor its instance (`Read<Pet>`), nor an operation of an interface\n * template's. Only the operations declared from them are checked.\n */\nimport { isTemplateDeclaration, type Operation } from '@typespec/compiler';\nimport { isEmitted } from '../operation-ids';\n\nexport function isWritten(operation: Operation): boolean {\n\tconst container = operation.interface;\n\treturn (\n\t\tisEmitted(operation) &&\n\t\t!isTemplateDeclaration(operation) &&\n\t\t(container === undefined || !isTemplateDeclaration(container))\n\t);\n}\n",
|
|
16
18
|
"/**\n * A list returns a page: `Page<Item>` or `CursorPage<Item>`, never a bare\n * array, which cannot grow a `total` or a `nextCursor` without breaking its\n * clients. A list is an operation named `list`, `search` or `query`, alone\n * or followed by more: `listUsers`, `searchPosts`.\n */\nimport { createRule, isArrayModelType, paramMessage } from '@typespec/compiler';\nimport { getHttpOperation } from '@typespec/http';\nimport { isWritten } from './written';\n\nconst LIST = /^(list|search|query)(?=[A-Z]|$)/;\n\nexport const listReturnsPage = createRule({\n\tname: 'list-returns-page',\n\tseverity: 'warning',\n\tdescription:\n\t\t'A list, search or query returns Page<Item> or CursorPage<Item>.',\n\tmessages: {\n\t\tdefault: paramMessage`${'operation'} returns an array: return Page<Item> or CursorPage<Item>, which can carry a total or a next cursor.`,\n\t},\n\tcreate: (context) => ({\n\t\toperation(operation) {\n\t\t\tif (!isWritten(operation) || !LIST.test(operation.name)) return;\n\t\t\tconst [http] = getHttpOperation(context.program, operation);\n\t\t\tconst array = http.responses.some(\n\t\t\t\t({ statusCodes, responses }) =>\n\t\t\t\t\ttypeof statusCodes === 'number' &&\n\t\t\t\t\tstatusCodes >= 200 &&\n\t\t\t\t\tstatusCodes < 300 &&\n\t\t\t\t\tresponses.some(\n\t\t\t\t\t\t({ body }) =>\n\t\t\t\t\t\t\tbody?.type.kind === 'Model' && isArrayModelType(body.type),\n\t\t\t\t\t),\n\t\t\t);\n\t\t\tif (!array) return;\n\t\t\tcontext.reportDiagnostic({\n\t\t\t\tformat: { operation: operation.name },\n\t\t\t\ttarget: operation,\n\t\t\t});\n\t\t},\n\t}),\n});\n",
|
|
17
19
|
"/**\n * A service without `@operationIds` gets the emitter's ids: `Users_list`,\n * which the generated client's methods are named after.\n */\nimport { createRule, isService, paramMessage } from '@typespec/compiler';\nimport { isMarkedNamespace } from '../operation-ids';\n\nexport const serviceOperationIds = createRule({\n\tname: 'service-operation-ids',\n\tseverity: 'warning',\n\tdescription:\n\t\t'A service namespace marks its operation ids with @operationIds.',\n\tmessages: {\n\t\tdefault: paramMessage`The service ${'service'} has no @operationIds: its ids are the emitter's, such as Users_list. Mark the namespace with @operationIds.`,\n\t},\n\tcreate: (context) => ({\n\t\tnamespace(namespace) {\n\t\t\tconst { program } = context;\n\t\t\tif (!isService(program, namespace)) return;\n\t\t\tif (isMarkedNamespace(program, namespace)) return;\n\t\t\tcontext.reportDiagnostic({\n\t\t\t\tformat: { service: namespace.name },\n\t\t\t\ttarget: namespace,\n\t\t\t});\n\t\t},\n\t}),\n});\n",
|
|
18
|
-
"/**\n * The JavaScript side of the `@nxgt/typespec` library, which `lib/main.tsp`\n * imports from `dist/`: its name and diagnostics, and the decorators a\n * template cannot express. The conventions themselves are in `lib/`.\n *\n * A decorator is exported only through `$decorators`: a top-level `$name`\n * export would declare it a second time, in the global namespace.\n */\nimport type { Program } from '@typespec/compiler';\nimport { validateOneReplyPerStatus } from './one-reply-per-status';\nimport { operationIds, validateOperationIds } from './operation-ids';\nimport { queryMethod, validateQueryMethods } from './query-method';\nimport { validateVerbMethods } from './verb-methods';\n\nexport { $lib } from './lib';\nexport { $linter } from './linter';\n\nexport function $onValidate(program: Program): void {\n\tvalidateQueryMethods(program);\n\t// Before the ids are set: only an `@operationId` written in the spec is\n\t// one then, and the operation it names is not checked.\n\tvalidateVerbMethods(program);\n\tvalidateOperationIds(program);\n\tvalidateOneReplyPerStatus(program);\n}\n\nexport const $decorators = {\n\tNxgt: { operationIds, queryMethod },\n};\n"
|
|
20
|
+
"/**\n * The JavaScript side of the `@nxgt/typespec` library, which `lib/main.tsp`\n * imports from `dist/`: its name and diagnostics, and the decorators a\n * template cannot express. The conventions themselves are in `lib/`.\n *\n * A decorator is exported only through `$decorators`: a top-level `$name`\n * export would declare it a second time, in the global namespace.\n */\nimport type { Program } from '@typespec/compiler';\nimport { validateOneReplyPerStatus } from './one-reply-per-status';\nimport { operationIds, validateOperationIds } from './operation-ids';\nimport { queryMethod, validateQueryMethods } from './query-method';\nimport { validateVerbMethods } from './verb-methods';\n\nexport { $onEmit } from './emitter';\nexport { $lib } from './lib';\nexport { $linter } from './linter';\n\nexport function $onValidate(program: Program): void {\n\tvalidateQueryMethods(program);\n\t// Before the ids are set: only an `@operationId` written in the spec is\n\t// one then, and the operation it names is not checked.\n\tvalidateVerbMethods(program);\n\tvalidateOperationIds(program);\n\tvalidateOneReplyPerStatus(program);\n}\n\nexport const $decorators = {\n\tNxgt: { operationIds, queryMethod },\n};\n"
|
|
19
21
|
],
|
|
20
|
-
"mappings": "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",
|
|
21
|
-
"debugId": "
|
|
22
|
+
"mappings": "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",
|
|
23
|
+
"debugId": "3B14A4A66C69185964756E2164756E21",
|
|
22
24
|
"names": []
|
|
23
25
|
}
|
package/dist/lib.d.ts
CHANGED
|
@@ -11,6 +11,15 @@ export declare const $lib: import("@typespec/compiler").TypeSpecLibrary<{
|
|
|
11
11
|
'query-method-not-post': {
|
|
12
12
|
readonly default: import("@typespec/compiler").CallableMessage<["operation", "method"]>;
|
|
13
13
|
};
|
|
14
|
+
'query-method-needs-openapi-3.2': {
|
|
15
|
+
readonly default: import("@typespec/compiler").CallableMessage<["operation", "version"]>;
|
|
16
|
+
};
|
|
17
|
+
'query-method-needs-nxgt-emitter': {
|
|
18
|
+
readonly default: import("@typespec/compiler").CallableMessage<["operation"]>;
|
|
19
|
+
};
|
|
20
|
+
'openapi3-missing': {
|
|
21
|
+
readonly default: "The emitter @nxgt/typespec runs @typespec/openapi3, which is not installed: add it beside @nxgt/typespec.";
|
|
22
|
+
};
|
|
14
23
|
'duplicate-status-reply': {
|
|
15
24
|
readonly default: import("@typespec/compiler").CallableMessage<["operation", "status"]>;
|
|
16
25
|
};
|
package/dist/lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;+EA0Ef,CAAC"}
|
package/dist/operation-ids.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the interface's resource: `create` in `Users` is `createUser` (`verbs.ts`).
|
|
6
6
|
*/
|
|
7
7
|
import { type DecoratorContext, type Interface, type Namespace, type Operation, type Program } from '@typespec/compiler';
|
|
8
|
-
import { type OperationIdsOptions } from './resource';
|
|
8
|
+
import { type OperationIdsOptions } from './resource.js';
|
|
9
9
|
/**
|
|
10
10
|
* Marks the interface or the namespace; its ids are set once the program is
|
|
11
11
|
* checked. On a template, TypeSpec runs it on each instance, which
|
package/dist/query-method.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ import type { DecoratorContext, Operation, Program } from '@typespec/compiler';
|
|
|
8
8
|
export declare function queryMethod(context: DecoratorContext, target: Operation): void;
|
|
9
9
|
/** Marked with `@queryMethod`. */
|
|
10
10
|
export declare function isQueryMethod(program: Program, operation: Operation): boolean;
|
|
11
|
-
/**
|
|
11
|
+
/** The operations marked with `@queryMethod`, each once. */
|
|
12
|
+
export declare function queryMethods(program: Program): Operation[];
|
|
13
|
+
/**
|
|
14
|
+
* Each marked operation is a `POST`, as the emitter sends it, and is emitted
|
|
15
|
+
* by `@nxgt/typespec`: `@typespec/openapi3` alone would write the `POST`.
|
|
16
|
+
*/
|
|
12
17
|
export declare function validateQueryMethods(program: Program): void;
|
|
13
18
|
//# sourceMappingURL=query-method.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-method.d.ts","sourceRoot":"","sources":["../src/query-method.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAK/E,wBAAgB,WAAW,CAC1B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,SAAS,GACf,IAAI,CAIN;AAED,kCAAkC;AAClC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAE7E;AAED,
|
|
1
|
+
{"version":3,"file":"query-method.d.ts","sourceRoot":"","sources":["../src/query-method.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAK/E,wBAAgB,WAAW,CAC1B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,SAAS,GACf,IAAI,CAIN;AAED,kCAAkC;AAClC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAE7E;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,CAE1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmB3D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document's text with its queries moved. The format is the text's:
|
|
3
|
+
* `@typespec/openapi3` writes YAML whatever the file is named, unless
|
|
4
|
+
* `file-type` says JSON. Line endings stay as written: `new-line: crlf`
|
|
5
|
+
* reaches here already applied.
|
|
6
|
+
*/
|
|
7
|
+
export declare function withQueryOperations(content: string): string;
|
|
8
|
+
//# sourceMappingURL=query-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-operations.d.ts","sourceRoot":"","sources":["../src/query-operations.ts"],"names":[],"mappings":"AAoCA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAe3D"}
|
package/dist/resource.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* them, layered from the library's, the namespaces', and the interface's.
|
|
5
5
|
*/
|
|
6
6
|
import type { Operation, Program } from '@typespec/compiler';
|
|
7
|
-
import { type Grammar } from './verbs';
|
|
7
|
+
import { type Grammar } from './verbs.js';
|
|
8
8
|
/** `@operationIds`' options, as `OperationIdsOptions` declares them. */
|
|
9
9
|
export interface OperationIdsOptions {
|
|
10
10
|
readonly singular?: string;
|
package/docs/README.md
CHANGED
|
@@ -5,6 +5,7 @@ The [package README](../README.md) is the short version.
|
|
|
5
5
|
| Page | Read it when |
|
|
6
6
|
| --- | --- |
|
|
7
7
|
| [Getting started](guide/getting-started.md) | starting a new API project from the `tsp init` template, up to a Hono route |
|
|
8
|
+
| [The emitter](guide/emitter.md) | emitting the spec with `@nxgt/typespec` in `tspconfig.yaml`, or getting a real `QUERY` from a `@queryMethod`, which needs OpenAPI 3.2 |
|
|
8
9
|
| [Request bodies](guide/requests.md) | naming the body of a create, a `PUT` and a `PATCH`: `CreatePostRequest`, `UpdatePostRequest`, `PatchPostRequest` |
|
|
9
10
|
| [Error replies](guide/errors.md) | declaring what an operation answers when it fails |
|
|
10
11
|
| [Pagination](guide/pagination.md) | listing a collection a page at a time |
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# The emitter
|
|
2
|
+
|
|
3
|
+
`@nxgt/typespec` is a TypeSpec emitter as well as a library: it compiles a
|
|
4
|
+
spec to OpenAPI with `@typespec/openapi3`, and writes each `@queryMethod` as a
|
|
5
|
+
real `QUERY` when the document is OpenAPI 3.2.
|
|
6
|
+
|
|
7
|
+
## The smallest setup
|
|
8
|
+
|
|
9
|
+
Install the optional peer the emitter runs, then emit with this package in
|
|
10
|
+
place of `@typespec/openapi3`:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
bun add -d @nxgt/typespec @typespec/openapi3
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
# api/tspconfig.yaml
|
|
18
|
+
emit:
|
|
19
|
+
- '@nxgt/typespec'
|
|
20
|
+
options:
|
|
21
|
+
'@nxgt/typespec':
|
|
22
|
+
openapi-versions: ['3.2.0']
|
|
23
|
+
emitter-output-dir: '{project-root}/../openapi'
|
|
24
|
+
output-file: openapi.yaml
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```tsp
|
|
28
|
+
// api/main.tsp
|
|
29
|
+
import "@typespec/http";
|
|
30
|
+
import "@nxgt/typespec";
|
|
31
|
+
|
|
32
|
+
using Http;
|
|
33
|
+
using Nxgt;
|
|
34
|
+
|
|
35
|
+
@service(#{ title: "Library" })
|
|
36
|
+
@operationIds
|
|
37
|
+
namespace Library;
|
|
38
|
+
|
|
39
|
+
model BookCriteria {
|
|
40
|
+
titles: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@route("/books")
|
|
44
|
+
interface Books {
|
|
45
|
+
@post @queryMethod @route("/search")
|
|
46
|
+
search(@body criteria: BookCriteria): string[]; // searchBooks
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`tsp compile api` writes `openapi.yaml`. The `tsp init` template already emits
|
|
51
|
+
with this emitter, with OpenAPI 3.1 by default and no `@queryMethod`; using
|
|
52
|
+
one requires `openapi-versions: ["3.2.0"]`
|
|
53
|
+
([Getting started](getting-started.md)).
|
|
54
|
+
|
|
55
|
+
## Why an emitter
|
|
56
|
+
|
|
57
|
+
`@typespec/http` 1.17 declares no `QUERY`, so a spec writes a `@post` and
|
|
58
|
+
`@queryMethod` marks it. `@typespec/openapi3` can only emit a `post`. The
|
|
59
|
+
emitter finishes the job the mark started: in OpenAPI 3.2, which has a
|
|
60
|
+
`query` operation, the document says `query`.
|
|
61
|
+
|
|
62
|
+
## What it does
|
|
63
|
+
|
|
64
|
+
It runs `@typespec/openapi3` with the options it was given, the same ones
|
|
65
|
+
under the same names (`openapi-versions`, `emitter-output-dir`,
|
|
66
|
+
`output-file`, `file-type`…), and writes the same files. Then, in each
|
|
67
|
+
OpenAPI 3.2 document, each marked `post` becomes a
|
|
68
|
+
`query` operation, in place in its path item and without `x-nxgt-method`:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
# openapi.yaml
|
|
72
|
+
/books/search:
|
|
73
|
+
query:
|
|
74
|
+
operationId: searchBooks
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
| Case | Result |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| a marked `@post`, `openapi-versions: ['3.2.0']` | a `query` operation |
|
|
80
|
+
| a marked `@post`, any version below 3.2 in `openapi-versions`, or none (the default, 3.0.0) | the error `query-method-needs-openapi-3.2` on each marked operation; nothing is emitted |
|
|
81
|
+
| a marked `@post`, `@typespec/openapi3` in `emit` | the error `query-method-needs-nxgt-emitter` |
|
|
82
|
+
| no marked operation | byte-identical to `@typespec/openapi3`'s, in any version |
|
|
83
|
+
|
|
84
|
+
Both errors, with their fix, are in [troubleshooting](../troubleshooting.md).
|
|
85
|
+
A path item that already has a `query` is left alone. The emitter adds no
|
|
86
|
+
option of its own.
|
|
87
|
+
|
|
88
|
+
Its options are checked with `@typespec/openapi3`'s schema, so a typo is
|
|
89
|
+
`invalid-schema`, as under `@typespec/openapi3`. `tsp compile --dry-run`
|
|
90
|
+
works, `new-line: crlf` is kept, and the document's format (YAML or JSON) is
|
|
91
|
+
read from its text, not from the file name.
|
|
92
|
+
|
|
93
|
+
**The default output folder changes with the emitter.** With
|
|
94
|
+
`emitter-output-dir` unset, the files go to `tsp-output/@nxgt/typespec`,
|
|
95
|
+
where `@typespec/openapi3` wrote `tsp-output/@typespec/openapi3`. Set
|
|
96
|
+
`emitter-output-dir` (the template does) to keep a path.
|
|
97
|
+
|
|
98
|
+
`@typespec/openapi3` is loaded only when emitting, so a spec that only
|
|
99
|
+
imports the library, `tsp compile --no-emit`, does not need it installed.
|
|
100
|
+
|
|
101
|
+
## What follows downstream
|
|
102
|
+
|
|
103
|
+
| Step | What it does with the `query` operation |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| `@nxgt/openapi-codegen` | generates `method: 'query'` in the `operations` table |
|
|
106
|
+
| `@nxgt/openapi-hono` | serves it with `.query(path, handler)` |
|
|
107
|
+
| `@nxgt/httpyz` client | sends `QUERY`; its `cache()` and retries treat it like a `GET`, keyed by its body |
|
|
108
|
+
|
|
109
|
+
A hand-written OpenAPI document may still carry a `post` with
|
|
110
|
+
`x-nxgt-method: query`, which the generator marks `queryMethod: true`; a
|
|
111
|
+
TypeSpec spec no longer emits one.
|
|
112
|
+
|
|
113
|
+
The handler of the 3.2 case, wired as the fixture's spec does:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { Hono } from 'hono';
|
|
117
|
+
import { createRoutes } from './generated/hono';
|
|
118
|
+
|
|
119
|
+
const app = new Hono();
|
|
120
|
+
createRoutes(app, { validateResponses: true }).query('/books/search', (c) =>
|
|
121
|
+
c.json(
|
|
122
|
+
{
|
|
123
|
+
items: [],
|
|
124
|
+
total: c.req.valid('json').titles.length,
|
|
125
|
+
page: 1,
|
|
126
|
+
pageSize: 20,
|
|
127
|
+
pageCount: 0,
|
|
128
|
+
},
|
|
129
|
+
200,
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const reply = await app.request('/books/search', {
|
|
134
|
+
method: 'QUERY',
|
|
135
|
+
body: JSON.stringify({ titles: ['Dune', 'Emma'] }),
|
|
136
|
+
headers: { 'content-type': 'application/json' },
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## A QUERY on the wire
|
|
141
|
+
|
|
142
|
+
A real `QUERY` is not a `POST`, so the path from the browser to the handler
|
|
143
|
+
has to accept the method:
|
|
144
|
+
|
|
145
|
+
- **The server's HTTP stack.** Recent Node and Bun accept `QUERY`, and Hono
|
|
146
|
+
routes it. Check the runtime and any framework or adapter between the
|
|
147
|
+
socket and Hono.
|
|
148
|
+
- **Proxies, gateways and CDNs.** Some refuse a method they do not know, or
|
|
149
|
+
do not cache it. If one in front of the service does, take off
|
|
150
|
+
`@queryMethod` and use a `@post`, which goes through everything.
|
|
151
|
+
- **CORS.** `QUERY` is not a CORS-safelisted method, so a browser always sends
|
|
152
|
+
a preflight, and the server must list `QUERY` in `Access-Control-Allow-Methods`.
|
|
153
|
+
|
|
154
|
+
## Without the emitter
|
|
155
|
+
|
|
156
|
+
The library, its decorators and the linter do not depend on the emitter, but
|
|
157
|
+
a spec that uses `@queryMethod` must emit with it: `@typespec/openapi3` alone
|
|
158
|
+
reports `query-method-needs-nxgt-emitter`. More on the decorator, its checks
|
|
159
|
+
and its errors, in [Operation ids](operation-ids.md#a-query-in-openapi-32).
|
package/docs/guide/errors.md
CHANGED
|
@@ -8,9 +8,9 @@ spec names them instead of describing them again.
|
|
|
8
8
|
```yaml
|
|
9
9
|
# api/tspconfig.yaml
|
|
10
10
|
emit:
|
|
11
|
-
- '@typespec
|
|
11
|
+
- '@nxgt/typespec'
|
|
12
12
|
options:
|
|
13
|
-
'@typespec
|
|
13
|
+
'@nxgt/typespec':
|
|
14
14
|
openapi-versions: ['3.1.0']
|
|
15
15
|
emitter-output-dir: '{project-root}/../openapi'
|
|
16
16
|
output-file: openapi.yaml
|
|
@@ -38,14 +38,18 @@ network, fails before anything is written
|
|
|
38
38
|
| File | What it holds |
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| `package.json` | the compiler, `@typespec/http`, `@typespec/openapi`, `@typespec/openapi3`, `@nxgt/typespec` and `@nxgt/openapi-codegen`, at their latest versions |
|
|
41
|
-
| `tspconfig.yaml` | the linter's recommended rules, and OpenAPI 3.1 written to `openapi/openapi.yaml` |
|
|
41
|
+
| `tspconfig.yaml` | the linter's recommended rules, and OpenAPI 3.1 written to `openapi/openapi.yaml` by the emitter `@nxgt/typespec` |
|
|
42
42
|
| `main.tsp` | the service, marked with `@operationIds`, and a `Users` resource |
|
|
43
43
|
| `openapi-codegen.config.ts` | the generator's input and output, with the Hono routes on |
|
|
44
44
|
| `README.md` | the commands below, and the scripts to add |
|
|
45
45
|
| `.gitignore` | `node_modules/`, and TypeSpec's default output |
|
|
46
46
|
|
|
47
|
-
`tspconfig.yaml` turns the linter on and emits OpenAPI 3.1
|
|
48
|
-
`@nxgt/
|
|
47
|
+
`tspconfig.yaml` turns the linter on and emits OpenAPI 3.1 with
|
|
48
|
+
`@nxgt/typespec`, which runs `@typespec/openapi3` and reads the same options.
|
|
49
|
+
`@nxgt/openapi-codegen` reads 3.1 (it refuses 3.0, the default of
|
|
50
|
+
`@typespec/openapi3`). The template has no `@queryMethod`; using one requires
|
|
51
|
+
`openapi-versions: ["3.2.0"]`, as 3.1 is an error beside it
|
|
52
|
+
([The emitter](emitter.md)):
|
|
49
53
|
|
|
50
54
|
```yaml
|
|
51
55
|
# tspconfig.yaml
|
|
@@ -53,9 +57,9 @@ linter:
|
|
|
53
57
|
extends:
|
|
54
58
|
- "@nxgt/typespec/recommended"
|
|
55
59
|
emit:
|
|
56
|
-
- "@typespec
|
|
60
|
+
- "@nxgt/typespec"
|
|
57
61
|
options:
|
|
58
|
-
"@typespec
|
|
62
|
+
"@nxgt/typespec":
|
|
59
63
|
emitter-output-dir: "{project-root}/openapi"
|
|
60
64
|
openapi-versions:
|
|
61
65
|
- 3.1.0
|
package/docs/guide/linter.md
CHANGED
|
@@ -11,12 +11,12 @@ Extend the ruleset in `tspconfig.yaml`, beside the emitter:
|
|
|
11
11
|
```yaml
|
|
12
12
|
# api/tspconfig.yaml
|
|
13
13
|
emit:
|
|
14
|
-
- '@typespec
|
|
14
|
+
- '@nxgt/typespec'
|
|
15
15
|
linter:
|
|
16
16
|
extends:
|
|
17
17
|
- '@nxgt/typespec/recommended'
|
|
18
18
|
options:
|
|
19
|
-
'@typespec
|
|
19
|
+
'@nxgt/typespec':
|
|
20
20
|
openapi-versions: ['3.1.0']
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -116,7 +116,7 @@ tells a cache, a proxy or a retry that the request is safe. An operation
|
|
|
116
116
|
| Verb | Sent with |
|
|
117
117
|
| --- | --- |
|
|
118
118
|
| `list`, `read`, `find`, `count`, `get` | `GET` or `HEAD` |
|
|
119
|
-
| `search`, `query` | `GET`, `POST`, or a `POST` marked [`@queryMethod`](#a-query-
|
|
119
|
+
| `search`, `query` | `GET`, `POST`, or a `POST` marked [`@queryMethod`](#a-query-in-openapi-32), for criteria too large for a query string |
|
|
120
120
|
| `create`, `createMany` | `POST` |
|
|
121
121
|
| `update`, `updateMany` | `PUT` or `PATCH` |
|
|
122
122
|
| `patch` | `PATCH` |
|
|
@@ -171,7 +171,7 @@ Not checked:
|
|
|
171
171
|
whatever it says;
|
|
172
172
|
- an operation `@operationIds` does not name.
|
|
173
173
|
|
|
174
|
-
## A QUERY
|
|
174
|
+
## A QUERY in OpenAPI 3.2
|
|
175
175
|
|
|
176
176
|
`QUERY` is the HTTP method for a safe request with a body, and
|
|
177
177
|
`@typespec/http` 1.17 declares only `GET`, `PUT`, `POST`, `PATCH`, `DELETE`
|
|
@@ -199,21 +199,24 @@ interface Users {
|
|
|
199
199
|
}
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
With the emitter `@nxgt/typespec` and OpenAPI 3.2 the document gets a real
|
|
203
|
+
`QUERY`, the only version that has one:
|
|
204
204
|
|
|
205
205
|
```yaml
|
|
206
206
|
/users/search:
|
|
207
|
-
|
|
207
|
+
query:
|
|
208
208
|
operationId: searchUsers
|
|
209
|
-
x-nxgt-method: query
|
|
210
209
|
```
|
|
211
210
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
`@
|
|
216
|
-
|
|
211
|
+
Anything else is an error, not a `POST` with a mark: an older version in
|
|
212
|
+
`openapi-versions` (or none, which defaults to 3.0) is `query-method-needs-openapi-3.2`, and the plain
|
|
213
|
+
`@typespec/openapi3` emitter is `query-method-needs-nxgt-emitter`
|
|
214
|
+
([troubleshooting](../troubleshooting.md)). `@nxgt/openapi-codegen`
|
|
215
|
+
generates `method: 'query'` from it
|
|
216
|
+
([TypeSpec](https://github.com/softistx/nxgt-http/blob/develop/packages/openapi-codegen/docs/guide/typespec.md)).
|
|
217
|
+
The emitter and what a real `QUERY` needs are in [The emitter](emitter.md).
|
|
218
|
+
When `@typespec/http` declares `QUERY`, the decorator is what changes, not
|
|
219
|
+
your spec ([roadmap](../roadmap.md#later)).
|
|
217
220
|
|
|
218
221
|
| Case | Result |
|
|
219
222
|
| --- | --- |
|
|
@@ -223,12 +226,12 @@ spec ([roadmap](../roadmap.md#later)).
|
|
|
223
226
|
| marked and not a `@post` | the error `query-method-not-post` |
|
|
224
227
|
|
|
225
228
|
```text
|
|
226
|
-
error @nxgt/typespec/query-method-not-post: list is marked @queryMethod and sent with GET: a
|
|
229
|
+
error @nxgt/typespec/query-method-not-post: list is marked @queryMethod and sent with GET: @queryMethod marks a @post, which @nxgt/typespec writes as a QUERY in OpenAPI 3.2. Make it a @post.
|
|
227
230
|
```
|
|
228
231
|
|
|
229
232
|
A search that answers an array also meets the linter's `list-returns-page`;
|
|
230
|
-
return a `Page<Item>`, as `search`
|
|
231
|
-
(`Page<
|
|
233
|
+
return a `Page<Item>`, as `search` above could
|
|
234
|
+
(`Page<User> | BadRequest`).
|
|
232
235
|
|
|
233
236
|
## The resource
|
|
234
237
|
|
package/docs/roadmap.md
CHANGED
|
@@ -16,22 +16,33 @@ Nothing in progress.
|
|
|
16
16
|
|
|
17
17
|
## Later
|
|
18
18
|
|
|
19
|
-
- **A
|
|
20
|
-
`
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
- **A `QUERY` without a mark.** A real `QUERY` is done: the emitter
|
|
20
|
+
`@nxgt/typespec` writes a `@queryMethod` as a `query` operation in OpenAPI
|
|
21
|
+
3.2. What is left is a native `@query`-like verb, once `@typespec/http`
|
|
22
|
+
declares `QUERY`, so a spec stops needing `@post @queryMethod` and does not
|
|
23
|
+
otherwise change.
|
|
23
24
|
- **`ETag` and conditional requests.** `ETag`, with `If-None-Match` and
|
|
24
25
|
`If-Match`, once the `@nxgt/*` packages send one the same way. The
|
|
25
26
|
optimistic lock is the body's `version` today (`Versioned`).
|
|
26
27
|
|
|
27
28
|
## Shipped
|
|
28
29
|
|
|
30
|
+
### 0.13.0
|
|
31
|
+
|
|
32
|
+
- **The emitter `@nxgt/typespec`.** `emit: ["@nxgt/typespec"]` runs
|
|
33
|
+
`@typespec/openapi3` with the same options and files, and in an OpenAPI 3.2
|
|
34
|
+
document writes each `@queryMethod` as a real `query` operation, which
|
|
35
|
+
`@nxgt/openapi-codegen` generates as `method: 'query'` and
|
|
36
|
+
`@nxgt/openapi-hono` serves. A marked operation with an older version, or
|
|
37
|
+
with plain `@typespec/openapi3`, is an error. `@typespec/openapi3` is an optional peer, and the
|
|
38
|
+
`tsp init` template emits with the new emitter.
|
|
39
|
+
|
|
29
40
|
### 0.12.0
|
|
30
41
|
|
|
31
42
|
- **`@queryMethod`, a `QUERY` sent as a `POST`.** The decorator marks a
|
|
32
43
|
`@post` with `x-nxgt-method: query`, which `@nxgt/openapi-codegen` reads,
|
|
33
|
-
and `search` and `query` accept it: a safe request with a body,
|
|
34
|
-
|
|
44
|
+
and `search` and `query` accept it: a safe request with a body, with every
|
|
45
|
+
server, proxy and `fetch`. On anything but a `@post` it is the error
|
|
35
46
|
`query-method-not-post`.
|
|
36
47
|
|
|
37
48
|
### 0.11.0
|
package/docs/troubleshooting.md
CHANGED
|
@@ -293,7 +293,7 @@ Or silence that one operation with a reason:
|
|
|
293
293
|
@post @route("/find") findById(@body id: uuid): User;
|
|
294
294
|
```
|
|
295
295
|
|
|
296
|
-
## `list is marked @queryMethod and sent with GET: a
|
|
296
|
+
## `list is marked @queryMethod and sent with GET: @queryMethod marks a @post, which @nxgt/typespec writes as a QUERY in OpenAPI 3.2. Make it a @post.`
|
|
297
297
|
|
|
298
298
|
**When:** an error, `query-method-not-post`: an operation marked
|
|
299
299
|
`@queryMethod` is sent with a method other than `POST`. The method may be
|
|
@@ -306,9 +306,10 @@ interface Users {
|
|
|
306
306
|
}
|
|
307
307
|
```
|
|
308
308
|
|
|
309
|
-
**Why:** `@queryMethod` stands for a `QUERY`
|
|
310
|
-
|
|
311
|
-
|
|
309
|
+
**Why:** `@queryMethod` stands for a `QUERY` that `@typespec/http` cannot
|
|
310
|
+
declare, so the spec writes a `@post` and the emitter writes the `QUERY`
|
|
311
|
+
([The emitter](guide/emitter.md)); on a `GET`, a `PUT` or a `DELETE` it has
|
|
312
|
+
nothing to stand for.
|
|
312
313
|
|
|
313
314
|
**Fix:** make it a `@post`, with the criteria in the body:
|
|
314
315
|
|
|
@@ -317,7 +318,62 @@ has nothing to stand for.
|
|
|
317
318
|
```
|
|
318
319
|
|
|
319
320
|
Or drop `@queryMethod`: a `GET` needs no mark. More, in
|
|
320
|
-
[Operation ids](guide/operation-ids.md#a-query-
|
|
321
|
+
[Operation ids](guide/operation-ids.md#a-query-in-openapi-32).
|
|
322
|
+
|
|
323
|
+
## `search is marked @queryMethod: only OpenAPI 3.2 has a QUERY operation, and openapi-versions asks for 3.1.0. Emit 3.2 only, or take off @queryMethod.`
|
|
324
|
+
|
|
325
|
+
**When:** `tsp compile` with the emitter `@nxgt/typespec`; the error
|
|
326
|
+
`query-method-needs-openapi-3.2` on each marked operation. Nothing is emitted.
|
|
327
|
+
|
|
328
|
+
**Why:** OpenAPI 3.1 and older have no `QUERY` operation, and the emitter
|
|
329
|
+
does not turn the operation into a `POST`. `openapi-versions` holds a version
|
|
330
|
+
below 3.2, or is unset, which means 3.0.0; the message names the first such
|
|
331
|
+
version.
|
|
332
|
+
|
|
333
|
+
**Fix:** emit 3.2 only, or take off `@queryMethod` and use a plain `@post`
|
|
334
|
+
or `@get`:
|
|
335
|
+
|
|
336
|
+
```yaml
|
|
337
|
+
options:
|
|
338
|
+
'@nxgt/typespec':
|
|
339
|
+
openapi-versions: ['3.2.0']
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
An `openapi-versions` with 3.2 beside an older version fails the same way:
|
|
343
|
+
list only 3.2. More, in [The emitter](guide/emitter.md).
|
|
344
|
+
|
|
345
|
+
## `search is marked @queryMethod: emit with @nxgt/typespec, which writes it as a QUERY; @typespec/openapi3 would write a POST.`
|
|
346
|
+
|
|
347
|
+
**When:** `tsp compile` with `@typespec/openapi3` in `emit`; the error
|
|
348
|
+
`query-method-needs-nxgt-emitter` on each marked operation. Since 0.13.0; in
|
|
349
|
+
0.12.0 this compiled to a `post` with `x-nxgt-method: query`.
|
|
350
|
+
|
|
351
|
+
**Why:** only the emitter `@nxgt/typespec` writes a `@queryMethod` as a
|
|
352
|
+
`QUERY`.
|
|
353
|
+
|
|
354
|
+
**Fix:** emit with it, and ask for 3.2:
|
|
355
|
+
|
|
356
|
+
```yaml
|
|
357
|
+
emit:
|
|
358
|
+
- '@nxgt/typespec'
|
|
359
|
+
options:
|
|
360
|
+
'@nxgt/typespec':
|
|
361
|
+
openapi-versions: ['3.2.0']
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## `The emitter @nxgt/typespec runs @typespec/openapi3, which is not installed: add it beside @nxgt/typespec.`
|
|
365
|
+
|
|
366
|
+
**When:** `tsp compile` with `@nxgt/typespec` in `emit`; the error
|
|
367
|
+
`openapi3-missing`. Nothing is emitted.
|
|
368
|
+
|
|
369
|
+
**Why:** `@typespec/openapi3` is an optional peer of `@nxgt/typespec`, loaded
|
|
370
|
+
only when the spec is emitted, so installing the library does not install it.
|
|
371
|
+
|
|
372
|
+
**Fix:**
|
|
373
|
+
|
|
374
|
+
```sh
|
|
375
|
+
bun add -d @typespec/openapi3
|
|
376
|
+
```
|
|
321
377
|
|
|
322
378
|
## `findById is sent with QUERY, where its verb find is sent with GET or HEAD`
|
|
323
379
|
|
|
@@ -642,7 +698,9 @@ using OpenAPI;
|
|
|
642
698
|
|
|
643
699
|
**When:** you generate from what `tsp compile` emitted.
|
|
644
700
|
|
|
645
|
-
**Why:** `@typespec/openapi3`
|
|
701
|
+
**Why:** `@typespec/openapi3`, and so `@nxgt/typespec` which runs it, emits
|
|
702
|
+
OpenAPI 3.0 by default.
|
|
646
703
|
|
|
647
704
|
**Fix:** in `tspconfig.yaml`, set `openapi-versions: ['3.1.0']` or
|
|
648
|
-
`['3.2.0']` under the `@typespec
|
|
705
|
+
`['3.2.0']` under the options of the emitter you use, `@nxgt/typespec`
|
|
706
|
+
or `@typespec/openapi3`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/typespec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "bun run ../../build.ts",
|
|
38
38
|
"fixtures": "bun run test/generate.ts",
|
|
39
|
-
"test": "bun run fixtures && bun test src",
|
|
39
|
+
"test": "bun run ../../scripts/check-dist-fresh.ts . && bun run fixtures && bun test src",
|
|
40
40
|
"typecheck": "bun run fixtures && tsc --noEmit",
|
|
41
41
|
"fixtures:typespec": "bun run test/generate.ts --accept"
|
|
42
42
|
},
|
|
@@ -45,15 +45,24 @@
|
|
|
45
45
|
"src/index.ts"
|
|
46
46
|
]
|
|
47
47
|
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"yaml": "^2.9.0"
|
|
50
|
+
},
|
|
48
51
|
"peerDependencies": {
|
|
49
52
|
"@typespec/compiler": "^1.16.0",
|
|
50
53
|
"@typespec/http": "^1.16.0",
|
|
51
54
|
"@typespec/openapi": "^1.16.0",
|
|
52
|
-
"typescript": "^6.0.3 || ^7.0.0"
|
|
55
|
+
"typescript": "^6.0.3 || ^7.0.0",
|
|
56
|
+
"@typespec/openapi3": "^1.16.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"@typespec/openapi3": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
53
62
|
},
|
|
54
63
|
"devDependencies": {
|
|
55
|
-
"@nxgt/openapi-codegen": "^0.9.
|
|
56
|
-
"@nxgt/openapi-hono": "^0.3.
|
|
64
|
+
"@nxgt/openapi-codegen": "^0.9.2",
|
|
65
|
+
"@nxgt/openapi-hono": "^0.3.3",
|
|
57
66
|
"@types/bun": "^1.4.0",
|
|
58
67
|
"@typespec/compiler": "1.17.0",
|
|
59
68
|
"@typespec/http": "1.17.0",
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"libraries": [
|
|
7
7
|
"@typespec/http",
|
|
8
8
|
"@typespec/openapi",
|
|
9
|
+
"@typespec/openapi3",
|
|
9
10
|
"@nxgt/typespec",
|
|
10
11
|
"@nxgt/openapi-codegen"
|
|
11
12
|
],
|
|
@@ -15,9 +16,9 @@
|
|
|
15
16
|
}
|
|
16
17
|
},
|
|
17
18
|
"emitters": {
|
|
18
|
-
"@typespec
|
|
19
|
+
"@nxgt/typespec": {
|
|
19
20
|
"selected": true,
|
|
20
|
-
"label": "OpenAPI 3.1 document",
|
|
21
|
+
"label": "OpenAPI 3.1 document (@typespec/openapi3; in 3.2, a @queryMethod is a QUERY)",
|
|
21
22
|
"options": {
|
|
22
23
|
"emitter-output-dir": "{project-root}/openapi",
|
|
23
24
|
"openapi-versions": ["3.1.0"],
|