@nxgt/typespec 0.11.0 → 0.13.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 +80 -10
- package/dist/emitter.d.ts +12 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/http-operations.d.ts +9 -0
- package/dist/http-operations.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +231 -55
- package/dist/index.js.map +12 -8
- package/dist/lib.d.ts +13 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/one-reply-per-status.d.ts +1 -5
- package/dist/one-reply-per-status.d.ts.map +1 -1
- package/dist/query-method.d.ts +18 -0
- package/dist/query-method.d.ts.map +1 -0
- package/dist/query-operations.d.ts +8 -0
- package/dist/query-operations.d.ts.map +1 -0
- package/dist/verb-methods.d.ts.map +1 -1
- package/dist/verbs.d.ts +2 -2
- 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 +62 -5
- package/docs/roadmap.md +23 -4
- package/docs/troubleshooting.md +102 -2
- package/lib/main.tsp +1 -0
- package/lib/query-method.tsp +26 -0
- package/package.json +16 -7
- package/templates/scaffolding.json +3 -2
package/dist/index.js.map
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/one-reply-per-status.ts", "../src/lib.ts", "../src/operation-ids.ts", "../src/verbs.ts", "../src/resource.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
|
-
"/**\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
|
|
6
|
-
"
|
|
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
|
+
"/**\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'}: @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",
|
|
7
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",
|
|
8
|
-
"/**\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. `QUERY
|
|
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",
|
|
9
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",
|
|
10
|
-
"/**\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/** 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
|
+
"/**\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",
|
|
11
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",
|
|
12
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",
|
|
13
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",
|
|
14
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",
|
|
15
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",
|
|
16
|
-
"/**\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 { validateVerbMethods } from './verb-methods';\n\nexport { $lib } from './lib';\nexport { $linter } from './linter';\n\nexport function $onValidate(program: Program): void {\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 },\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"
|
|
17
21
|
],
|
|
18
|
-
"mappings": "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",
|
|
19
|
-
"debugId": "
|
|
22
|
+
"mappings": "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",
|
|
23
|
+
"debugId": "3B14A4A66C69185964756E2164756E21",
|
|
20
24
|
"names": []
|
|
21
25
|
}
|
package/dist/lib.d.ts
CHANGED
|
@@ -8,11 +8,23 @@ export declare const $lib: import("@typespec/compiler").TypeSpecLibrary<{
|
|
|
8
8
|
'verb-method-mismatch': {
|
|
9
9
|
readonly default: import("@typespec/compiler").CallableMessage<["operation", "method", "verb", "expected"]>;
|
|
10
10
|
};
|
|
11
|
+
'query-method-not-post': {
|
|
12
|
+
readonly default: import("@typespec/compiler").CallableMessage<["operation", "method"]>;
|
|
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
|
+
};
|
|
11
23
|
'duplicate-status-reply': {
|
|
12
24
|
readonly default: import("@typespec/compiler").CallableMessage<["operation", "status"]>;
|
|
13
25
|
};
|
|
14
26
|
'merged-status-reply': {
|
|
15
27
|
readonly default: import("@typespec/compiler").CallableMessage<["operation", "status"]>;
|
|
16
28
|
};
|
|
17
|
-
}, Record<string, any>, "operationIds" | "operationIdsOptions">;
|
|
29
|
+
}, Record<string, any>, "queryMethod" | "operationIds" | "operationIdsOptions">;
|
|
18
30
|
//# sourceMappingURL=lib.d.ts.map
|
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"}
|
|
@@ -8,10 +8,6 @@
|
|
|
8
8
|
* Bodies of different content types are one reply, negotiated, and pass.
|
|
9
9
|
*/
|
|
10
10
|
import { type Program } from '@typespec/compiler';
|
|
11
|
-
/**
|
|
12
|
-
* Checks each operation of each service, as the emitter sees it, once: a
|
|
13
|
-
* service nested in another is listed in both. The services' own
|
|
14
|
-
* diagnostics are the emitter's to report.
|
|
15
|
-
*/
|
|
11
|
+
/** Checks each operation of each service, as the emitter sees it, once. */
|
|
16
12
|
export declare function validateOneReplyPerStatus(program: Program): void;
|
|
17
13
|
//# sourceMappingURL=one-reply-per-status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"one-reply-per-status.d.ts","sourceRoot":"","sources":["../src/one-reply-per-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"one-reply-per-status.d.ts","sourceRoot":"","sources":["../src/one-reply-per-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAqC9D,2EAA2E;AAC3E,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAehE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@queryMethod`: a `POST` that is a `QUERY`, a safe request with its
|
|
3
|
+
* criteria in the body. `@typespec/http` declares no `QUERY` yet, so the
|
|
4
|
+
* operation is sent as a `POST` and the document marks it,
|
|
5
|
+
* `x-nxgt-method: query`, for `@nxgt/openapi-codegen`.
|
|
6
|
+
*/
|
|
7
|
+
import type { DecoratorContext, Operation, Program } from '@typespec/compiler';
|
|
8
|
+
export declare function queryMethod(context: DecoratorContext, target: Operation): void;
|
|
9
|
+
/** Marked with `@queryMethod`. */
|
|
10
|
+
export declare function isQueryMethod(program: Program, operation: Operation): boolean;
|
|
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
|
+
*/
|
|
17
|
+
export declare function validateQueryMethods(program: Program): void;
|
|
18
|
+
//# sourceMappingURL=query-method.d.ts.map
|
|
@@ -0,0 +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,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verb-methods.d.ts","sourceRoot":"","sources":["../src/verb-methods.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"verb-methods.d.ts","sourceRoot":"","sources":["../src/verb-methods.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAclD,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsB1D"}
|
package/dist/verbs.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ export declare const VERBS: Readonly<Record<string, Grammar>>;
|
|
|
15
15
|
/**
|
|
16
16
|
* The HTTP methods each of the library's verbs is sent with: a read is a
|
|
17
17
|
* `GET` (or a `HEAD`), a search may carry its criteria in a `POST` body, a
|
|
18
|
-
* bulk delete its ids. `QUERY
|
|
19
|
-
*
|
|
18
|
+
* bulk delete its ids. A `QUERY`, a `POST` marked `@queryMethod`, is
|
|
19
|
+
* a search too.
|
|
20
20
|
*/
|
|
21
21
|
export declare const METHODS: Readonly<Record<string, readonly string[]>>;
|
|
22
22
|
/**
|
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
|
|