docfy patch-spec
Patche un document OpenAPI déjà construit, entièrement par analyse statique (ts-morph), sans aucun require() de fichier docs.
Pourquoi ça existe
C'est un moyen manuel, piloté par la CI, de contourner la seule chose que le pipeline runtime de DocfyModule ne peut structurellement pas faire : fonctionner sous le mode de build webpack: true du CLI NestJS (voir Le plugin CLI pour l'alternative automatique recommandée, qui calcule cette même analyse à chaque build au lieu d'une étape séparée). patch-spec contourne le mur webpack en faisant correspondre par chemin + méthode HTTP, calculé de la même façon que check/coverage/lint le font déjà, au lieu d'avoir besoin de la référence de classe du contrôleur en direct.
Usage
npx nestjs-docfy patch-spec --spec <path-or-url> [options]# Patch a running app's served document
npx nestjs-docfy patch-spec --spec http://localhost:3000/api-json --out openapi.json
# Patch a file already written to disk
npx nestjs-docfy patch-spec --spec dist/openapi.json --out dist/openapi.jsonOptions
| Option | Default | Description |
|---|---|---|
--spec <path|url> | (required) | A local openapi.json, or a URL (e.g. a running app's /api-json) |
--out <path> | stdout | Where to write the patched document |
--root <path> | . | Project root directory |
--tsconfig <path> | auto-detected | Path to tsconfig.json |
--pattern <glob> | **/*.controller.ts | Glob pattern to find controllers |
--format <format> | ts | Format de fichier docs à rechercher : ts ou js |
--quiet | false | Suppress all output except errors |
Ce qui est fusionné
Rapproché par chemin + méthode HTTP avec le document de base :
ApiTags→ fusionné danstags(ne retire jamais les tags déjà présents dans le document de base)ApiOperation({ summary, description, deprecated })→ écrase ces champsApiResponse({ status, description, schema, example, examples })→ fusionné par code de statut (les autres codes de statut restent intacts) ; quand aucunschema/typen'est donné, retombe sur le type de retour résolu de la méthode, la même inférence DTO/class-validator/interface quegeneratefait déjà, y compris unoneOfde$refquand le type de retour est une union d'au moins 2 DTO/entités nommés (par ex.Promise<UserDto | AdminDto>)ApiBody({ schema, examples })→ fixerequestBody, avec le même repli sur le type résolu du paramètre@Body(), y compris la même gestion union →oneOf(examplen'est volontairement pas lu ici, car le vrai typeApiBodyOptionsde@nestjs/swaggern'a queexamples, contrairement àApiResponse, qui supporte les deux)ApiBearerAuth()→ ajouté àsecurityApiParam/ApiQuery/ApiHeader→ fusionnés dansparameterspar nom + emplacement : un paramètre réellement nouveau est ajouté, mais un qui existe déjà (par ex.@nestjs/swaggergénère automatiquement une entrée nuerequired: truepar simple réflexion pour tout argument décoré avec@Query()/@Param()) voit ses champs superposés, pas remplacés.enumest lu depuis un littéral de tableau (enum: ['a', 'b']) ou une référence à unenumTS, y compris importé d'un autre fichier (enum: Role), et letypedu schéma est inféré commenumberquand chaque valeur résolue est numérique,stringsinon
What this does not do
Cette commande est volontairement limitée, pas une réimplémentation complète de la sémantique des décorateurs de @nestjs/swagger : anyOf (aucune construction TS ne correspond naturellement à « n'importe lequel de » comme une union type mappe naturellement sur oneOf), links/callbacks (@nestjs/swagger lui-même n'a aucune option de décorateur pour l'un ou l'autre), et tout argument de décorateur qui n'est pas un littéral (une variable, un appel de fonction, un spread) sont laissés tels quels plutôt que devinés. Il vaut mieux laisser un champ tel que le document de base l'avait déjà que d'y patcher quelque chose de faux. Un type de retour union ou un payload @Body() ne devient un oneOf que quand chaque branche résout vers un DTO/une entité nommé. Les routes qu'un fichier docs documente mais qui n'existent pas dans --spec sont signalées comme avertissements, jamais silencieusement ignorées ni en erreur.