@nxgt/typespec 0.13.1 → 0.14.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/README.md CHANGED
@@ -339,7 +339,8 @@ model Place {
339
339
  Each is an OpenAPI component named as in GraphQL (`Latitude`, `URL`), with a
340
340
  `format`, a pattern or bounds approximating the rule, and `x-nxgt-scalar`
341
341
  naming it. The exact rules (checksums, ISO and IANA lists) are outside the
342
- pattern. TypeSpec's own `url` takes any scheme; `httpUrl` takes `http:` and
342
+ pattern; [`@nxgt/openapi-codegen`](https://github.com/softistx/nxgt-http/blob/develop/packages/openapi-codegen/docs/guide/options.md#scalars)'s
343
+ `scalars: 'exact'` checks them with the schemas of `@nxgt/zod`. TypeSpec's own `url` takes any scheme; `httpUrl` takes `http:` and
343
344
  `https:`. Every scalar by category, in
344
345
  [Scalars](docs/guide/scalars.md); the ids, the addresses and the columns, in
345
346
  [Scalars and columns](docs/guide/columns.md).
@@ -539,6 +540,28 @@ with a reason, or for one operation with
539
540
  `#suppress "@nxgt/typespec/<rule>" "<reason>"`. More, with a failing and a
540
541
  passing example of each rule, in [Linter](docs/guide/linter.md).
541
542
 
543
+ ### Shared responses, headers and path servers
544
+
545
+ Three decorators, written by the emitter `@nxgt/typespec` (with
546
+ `@typespec/openapi3` in `emit` each is `shared-needs-nxgt-emitter`):
547
+
548
+ ```tsp
549
+ @sharedResponse @error
550
+ model Unauthorized {
551
+ @sharedHeader("NoStore") @header("cache-control") cacheControl: "no-store";
552
+ @statusCode code: 401;
553
+ message: string;
554
+ }
555
+
556
+ @route("/users")
557
+ @pathServer("https://users.example.com", "Users")
558
+ @get op listUsers(): { @body users: string[] } | Unauthorized;
559
+ ```
560
+
561
+ `Unauthorized` is emitted once under `components.responses`, its header once
562
+ under `components.headers`, a `$ref` at each use, and `/users` alone gets
563
+ `servers`. More, in [The emitter](docs/guide/emitter.md#shared-responses-shared-headers-and-path-servers).
564
+
542
565
  ## API
543
566
 
544
567
  ### Decorators
@@ -546,6 +569,9 @@ passing example of each rule, in [Linter](docs/guide/linter.md).
546
569
  | Decorator | On | What it does |
547
570
  | --- | --- | --- |
548
571
  | `@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 |
572
+ | `@sharedResponse(name?)` | a response model | emits the response once under `components.responses`, a `$ref` at each use; needs the emitter `@nxgt/typespec` |
573
+ | `@sharedHeader(name?)` | a `@header` property of a response | emits the header once under `components.headers`, a `$ref` at each use; needs the emitter `@nxgt/typespec` |
574
+ | `@pathServer(url, description?, parameters?)` | an operation | `servers` on its path item, with `@server`'s variables; the other paths keep the document's; needs the emitter `@nxgt/typespec` |
549
575
  | `@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` |
550
576
 
551
577
  `OperationIdsOptions` is `#{ singular?: string, plural?: string, verbs?: Record<"singular" | "plural"> }`:
@@ -572,6 +598,14 @@ overrides verbs, on a namespace or an interface.
572
598
  | `query-method-not-post` | error: an operation marked `@queryMethod` is not a `@post` |
573
599
  | `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
600
  | `query-method-needs-nxgt-emitter` | error: `@typespec/openapi3` is in `emit` beside a `@queryMethod` |
601
+ | `shared-component-conflict` | error: two `@sharedResponse` or two `@sharedHeader` of one name differ; the first is the component, the other stays inline |
602
+ | `shared-response-merged` | error: operations sharing a route reply one status with different responses, one a `@sharedResponse` |
603
+ | `path-server-missing-variable` | error: a `{name}` of a `@pathServer` URL has no property in its parameters |
604
+ | `path-server-invalid-variable` | error: a `@pathServer` variable is not a string, a string enum or a union of strings |
605
+ | `shared-header-misplaced` | error: `@sharedHeader` on a request header or a body property |
606
+ | `invalid-component-name` | error: the name given to `@sharedResponse` or `@sharedHeader` has a character OpenAPI does not allow in a component name |
607
+ | `path-server-conflict` | error: two `@pathServer` of one path give one URL a different description or variables |
608
+ | `shared-needs-nxgt-emitter` | error: `@typespec/openapi3` is in `emit` beside a `@sharedResponse`, `@sharedHeader` or `@pathServer` |
575
609
  | `openapi3-missing` | error: the emitter `@nxgt/typespec` runs `@typespec/openapi3`, which is not installed |
576
610
 
577
611
  ### Linter rules
@@ -733,6 +767,7 @@ envelope and the rate limit's headers.
733
767
  template, the files it writes, and the steps from the spec to a Hono route;
734
768
  - [The emitter](docs/guide/emitter.md): `@nxgt/typespec` in `tspconfig.yaml`,
735
769
  a `@queryMethod` as a real `QUERY` in OpenAPI 3.2, and what that needs;
770
+ shared responses and headers under `components`, and `servers` on a path;
736
771
  - [Error replies](docs/guide/errors.md): the envelope, each response, the
737
772
  aliases by verb, and what the generator makes of them;
738
773
  - [Pagination](docs/guide/pagination.md): offset and cursor pages, and
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@sharedResponse`, `@sharedHeader` and `@pathServer`: what the spec asks
3
+ * to be emitted once under `components`, or on one path item. A header and
4
+ * an operation carry their mark (`marks.ts`) until `shared-components.ts`
5
+ * rewrites the emitted document; a response is marked at emit time
6
+ * (`response-marks.ts`).
7
+ */
8
+ import { type DecoratorContext, type Model, type ModelProperty, type Operation, type Program } from '@typespec/compiler';
9
+ export declare function sharedResponse(context: DecoratorContext, target: Model, name?: string): void;
10
+ export declare function sharedHeader(context: DecoratorContext, target: ModelProperty, name?: string): void;
11
+ export declare function pathServer(context: DecoratorContext, target: Operation, url: string, description?: string, parameters?: Model): void;
12
+ /**
13
+ * Each marked target must be emitted by `@nxgt/typespec`: `@typespec/openapi3`
14
+ * would write the copies, or drop the servers, without a word.
15
+ */
16
+ export declare function validateComponents(program: Program): void;
17
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACN,KAAK,gBAAgB,EAErB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,MAAM,oBAAoB,CAAC;AAuB5B,wBAAgB,cAAc,CAC7B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,KAAK,EACb,IAAI,CAAC,EAAE,MAAM,GACX,IAAI,CAKN;AAED,wBAAgB,YAAY,CAC3B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GACX,IAAI,CAMN;AAED,wBAAgB,UAAU,CACzB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,KAAK,GAChB,IAAI,CA+BN;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqBzD"}
@@ -0,0 +1,7 @@
1
+ export type Document = Record<string, unknown>;
2
+ /**
3
+ * The text with `rewrite` applied to its document, and left as it was when
4
+ * `rewrite` says nothing changed.
5
+ */
6
+ export declare function rewriteDocument(content: string, rewrite: (document: Document) => boolean): string;
7
+ //# sourceMappingURL=document-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-text.d.ts","sourceRoot":"","sources":["../src/document-text.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,GACtC,MAAM,CAeR"}
package/dist/emitter.d.ts CHANGED
@@ -2,7 +2,9 @@
2
2
  * The emitter `@nxgt/typespec`: `@typespec/openapi3`, with its options,
3
3
  * checked by its own schema, and its files, and each `POST` marked
4
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
5
+ * (`query-operations.ts`), and what `@sharedResponse`, `@sharedHeader` and
6
+ * `@pathServer` ask: components emitted once, servers on a path item
7
+ * (`shared-components.ts`). Only 3.2 has a `QUERY`: a marked operation with
6
8
  * an older version asked for is an error, and nothing is emitted.
7
9
  * `@typespec/openapi3` is loaded only here, so a spec that only imports the
8
10
  * library does not need it.
@@ -1 +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"}
1
+ {"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAGN,KAAK,WAAW,EAGhB,MAAM,oBAAoB,CAAC;AAkG5B,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCjE"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@
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 { pathServer, sharedHeader, sharedResponse } from './components.js';
10
11
  import { operationIds } from './operation-ids.js';
11
12
  import { queryMethod } from './query-method.js';
12
13
  export { $onEmit } from './emitter.js';
@@ -16,7 +17,10 @@ export declare function $onValidate(program: Program): void;
16
17
  export declare const $decorators: {
17
18
  Nxgt: {
18
19
  operationIds: typeof operationIds;
20
+ pathServer: typeof pathServer;
19
21
  queryMethod: typeof queryMethod;
22
+ sharedHeader: typeof sharedHeader;
23
+ sharedResponse: typeof sharedResponse;
20
24
  };
21
25
  };
22
26
  //# sourceMappingURL=index.d.ts.map
@@ -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,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"}
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;AAClD,OAAO,EACN,UAAU,EACV,YAAY,EACZ,cAAc,EAEd,MAAM,cAAc,CAAC;AAEtB,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,CAQlD;AAED,eAAO,MAAM,WAAW;;;;;;;;CAQvB,CAAC"}