@necessarylion/adonis-autoswagger 0.0.1 → 0.0.3
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 -4
- package/dist/autoswagger.js +19 -16
- package/dist/parsers.d.ts +11 -1
- package/dist/parsers.js +72 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,11 +13,13 @@ Adonis AutoSwagger <br />
|
|
|
13
13
|
## 💻️ Install
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
pnpm i adonis-autoswagger #using pnpm
|
|
16
|
+
pnpm i @necessarylion/adonis-autoswagger #using pnpm
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
*This is a fork of [adonis-autoswagger](https://github.com/ad-on-is/adonis-autoswagger) with some additional features.*
|
|
22
|
+
|
|
21
23
|
## ⭐️ Features
|
|
22
24
|
|
|
23
25
|
- Creates **paths** automatically based on `routes.ts`
|
|
@@ -76,7 +78,7 @@ In your `routes.ts`
|
|
|
76
78
|
## 6️⃣ for AdonisJS v6
|
|
77
79
|
|
|
78
80
|
```js
|
|
79
|
-
import AutoSwagger from "adonis-autoswagger";
|
|
81
|
+
import AutoSwagger from "@necessarylion/adonis-autoswagger";
|
|
80
82
|
import swagger from "#config/swagger";
|
|
81
83
|
// returns swagger in YAML
|
|
82
84
|
router.get("/swagger", async () => {
|
|
@@ -94,7 +96,7 @@ router.get("/docs", async () => {
|
|
|
94
96
|
## 5️⃣ for AdonisJS v5
|
|
95
97
|
|
|
96
98
|
```js
|
|
97
|
-
import AutoSwagger from "adonis-autoswagger";
|
|
99
|
+
import AutoSwagger from "@necessarylion/adonis-autoswagger";
|
|
98
100
|
import swagger from "Config/swagger";
|
|
99
101
|
// returns swagger in YAML
|
|
100
102
|
Route.get("/swagger", async () => {
|
|
@@ -456,6 +458,71 @@ Generates responses and requestBody based on your simple Controller-Annotation (
|
|
|
456
458
|
|
|
457
459
|
## Schemas
|
|
458
460
|
|
|
461
|
+
### Validators
|
|
462
|
+
|
|
463
|
+
Automatically generates swagger schema-descriptions based on your validators.
|
|
464
|
+
|
|
465
|
+
#### Adding example values
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
export const adminLogin = vine.compile(
|
|
469
|
+
vine.object({
|
|
470
|
+
email: vine.string().trim().example('admin@laconcept.de'),
|
|
471
|
+
password: vine.string().trim().example('password'),
|
|
472
|
+
})
|
|
473
|
+
)
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
##### Create custom validators with vine
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
// start/validators/example.ts
|
|
480
|
+
|
|
481
|
+
import vine, { VineNumber, VineString, VineNativeEnum } from '@vinejs/vine'
|
|
482
|
+
import { EnumLike } from '@vinejs/vine/types'
|
|
483
|
+
|
|
484
|
+
type Options = {
|
|
485
|
+
example: any
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
declare module '@vinejs/vine' {
|
|
489
|
+
interface VineString {
|
|
490
|
+
example(example: string): this
|
|
491
|
+
}
|
|
492
|
+
interface VineNumber {
|
|
493
|
+
example(example: number): this
|
|
494
|
+
}
|
|
495
|
+
interface VineNativeEnum<Values extends EnumLike> {
|
|
496
|
+
example(example: string): this
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export const exampleRule = vine.createRule((_: unknown, opt: Options) => {
|
|
501
|
+
return opt.example
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
VineString.macro('example', function (this: VineString, example: string) {
|
|
505
|
+
return this.use(exampleRule({ example }))
|
|
506
|
+
})
|
|
507
|
+
VineNumber.macro('example', function (this: VineNumber, example: number) {
|
|
508
|
+
return this.use(exampleRule({ example }))
|
|
509
|
+
})
|
|
510
|
+
VineNativeEnum.macro('example', function (this: VineNativeEnum<any>, example: string) {
|
|
511
|
+
return this.use(exampleRule({ example }))
|
|
512
|
+
})
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
##### Import in `adonisrc.ts` preloads
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
preloads: [
|
|
519
|
+
() => import('#start/routes'),
|
|
520
|
+
() => import('#start/kernel'),
|
|
521
|
+
() => import('#start/sentry'),
|
|
522
|
+
() => import('#start/validators/example.ts'),
|
|
523
|
+
],
|
|
524
|
+
```
|
|
525
|
+
|
|
459
526
|
### Models
|
|
460
527
|
|
|
461
528
|
Automatically generates swagger schema-descriptions based on your models
|
|
@@ -464,7 +531,16 @@ Automatically generates swagger schema-descriptions based on your models
|
|
|
464
531
|
|
|
465
532
|
### Interfaces
|
|
466
533
|
|
|
467
|
-
Instead of using `param: any` you can now use custom interfaces `param: UserDetails`. The interfaces files need to be located at `app/Interfaces/`
|
|
534
|
+
Instead of using `param: any` you can now use custom interfaces `param: UserDetails`. The interfaces files need to be located at `app/Interfaces/` or `app/interfaces/`
|
|
535
|
+
|
|
536
|
+
```ts
|
|
537
|
+
export interface UserDetails {
|
|
538
|
+
// @example(John Doe)
|
|
539
|
+
name: string;
|
|
540
|
+
// @example(johndoe@example.com)
|
|
541
|
+
email: string;
|
|
542
|
+
}
|
|
543
|
+
```
|
|
468
544
|
|
|
469
545
|
### Enums
|
|
470
546
|
|
package/dist/autoswagger.js
CHANGED
|
@@ -279,22 +279,23 @@ class AutoSwagger {
|
|
|
279
279
|
description: "The resource has been created",
|
|
280
280
|
},
|
|
281
281
|
},
|
|
282
|
-
securitySchemes:
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
282
|
+
securitySchemes: this.options.securitySchemes
|
|
283
|
+
? this.options.securitySchemes
|
|
284
|
+
: {
|
|
285
|
+
BearerAuth: {
|
|
286
|
+
type: "http",
|
|
287
|
+
scheme: "bearer",
|
|
288
|
+
},
|
|
289
|
+
BasicAuth: {
|
|
290
|
+
type: "http",
|
|
291
|
+
scheme: "basic",
|
|
292
|
+
},
|
|
293
|
+
ApiKeyAuth: {
|
|
294
|
+
type: "apiKey",
|
|
295
|
+
in: "header",
|
|
296
|
+
name: "X-API-Key",
|
|
297
|
+
},
|
|
295
298
|
},
|
|
296
|
-
...this.options.securitySchemes,
|
|
297
|
-
},
|
|
298
299
|
schemas: this.schemas,
|
|
299
300
|
},
|
|
300
301
|
paths: {},
|
|
@@ -675,10 +676,12 @@ class AutoSwagger {
|
|
|
675
676
|
}
|
|
676
677
|
let schema = {
|
|
677
678
|
type: "object",
|
|
678
|
-
required: parsed.required,
|
|
679
679
|
properties: parsed.props,
|
|
680
680
|
description: name + " (Model)",
|
|
681
681
|
};
|
|
682
|
+
if (parsed.required.length > 0) {
|
|
683
|
+
schema['required'] = parsed.required;
|
|
684
|
+
}
|
|
682
685
|
models[name] = schema;
|
|
683
686
|
}
|
|
684
687
|
return models;
|
package/dist/parsers.d.ts
CHANGED
|
@@ -52,7 +52,17 @@ export declare class ValidatorParser {
|
|
|
52
52
|
validatorToObject(validator: VineValidator<any, any>): Promise<any>;
|
|
53
53
|
parsePropsAndMeta(obj: any, testObj: any, validator: VineValidator<any, any>): Promise<any>;
|
|
54
54
|
objToTest(obj: any): {};
|
|
55
|
-
parseSchema(json: any, refs: any): {
|
|
55
|
+
parseSchema(json: any, refs: any): {
|
|
56
|
+
properties: {};
|
|
57
|
+
};
|
|
58
|
+
getType(type: string): string;
|
|
59
|
+
getMetaFromValidations(validations: any, refs: any): {
|
|
60
|
+
minimum?: number;
|
|
61
|
+
maximum?: number;
|
|
62
|
+
enum?: any;
|
|
63
|
+
pattern?: string;
|
|
64
|
+
example?: any;
|
|
65
|
+
};
|
|
56
66
|
}
|
|
57
67
|
export declare class InterfaceParser {
|
|
58
68
|
exampleGenerator: ExampleGenerator;
|
package/dist/parsers.js
CHANGED
|
@@ -110,7 +110,7 @@ class CommentParser {
|
|
|
110
110
|
return h;
|
|
111
111
|
}
|
|
112
112
|
if (line.startsWith("@paramPath")) {
|
|
113
|
-
required =
|
|
113
|
+
required = true;
|
|
114
114
|
}
|
|
115
115
|
if (line.startsWith("@paramQuery")) {
|
|
116
116
|
required = false;
|
|
@@ -688,7 +688,7 @@ class ValidatorParser {
|
|
|
688
688
|
// console.dir(json, { depth: null });
|
|
689
689
|
const obj = {
|
|
690
690
|
type: "object",
|
|
691
|
-
|
|
691
|
+
...this.parseSchema(validator.toJSON()["schema"]["schema"], validator.toJSON()["refs"]),
|
|
692
692
|
};
|
|
693
693
|
// console.dir(obj, { depth: null });
|
|
694
694
|
const testObj = this.objToTest(obj["properties"]);
|
|
@@ -779,54 +779,84 @@ class ValidatorParser {
|
|
|
779
779
|
}
|
|
780
780
|
parseSchema(json, refs) {
|
|
781
781
|
const obj = {};
|
|
782
|
+
const required = [];
|
|
782
783
|
for (const p of json["properties"]) {
|
|
783
|
-
let meta =
|
|
784
|
-
for (const v of p["validations"]) {
|
|
785
|
-
if (refs[v["ruleFnId"]].options?.example) {
|
|
786
|
-
meta = { ...meta, example: refs[v["ruleFnId"]].options.example };
|
|
787
|
-
}
|
|
788
|
-
if (refs[v["ruleFnId"]].options?.min) {
|
|
789
|
-
meta = { ...meta, minimum: refs[v["ruleFnId"]].options.min };
|
|
790
|
-
}
|
|
791
|
-
if (refs[v["ruleFnId"]].options?.max) {
|
|
792
|
-
meta = { ...meta, maximum: refs[v["ruleFnId"]].options.max };
|
|
793
|
-
}
|
|
794
|
-
if (refs[v["ruleFnId"]].options?.choices) {
|
|
795
|
-
meta = { ...meta, choices: refs[v["ruleFnId"]].options.choices };
|
|
796
|
-
}
|
|
797
|
-
if (refs[v["ruleFnId"]].options?.toString().includes("/")) {
|
|
798
|
-
meta = { ...meta, pattern: refs[v["ruleFnId"]].options.toString() };
|
|
799
|
-
}
|
|
800
|
-
}
|
|
784
|
+
let meta = this.getMetaFromValidations(p["validations"], refs);
|
|
801
785
|
// console.dir(p, { depth: null });
|
|
802
786
|
// console.dir(validations, { depth: null });
|
|
803
787
|
// console.log(min, max, choices, regex);
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
788
|
+
const type = p["type"];
|
|
789
|
+
const field = p["fieldName"];
|
|
790
|
+
if (type === "object") {
|
|
791
|
+
console.log(field, p);
|
|
792
|
+
obj[field] = { type: "object", ...this.parseSchema(p, refs) };
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
// if array
|
|
796
|
+
if (type === "array") {
|
|
797
|
+
if (p["each"]["type"] === "object") {
|
|
798
|
+
obj[field] = {
|
|
809
799
|
type: "array",
|
|
810
|
-
items:
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
800
|
+
items: {
|
|
801
|
+
type: "object",
|
|
802
|
+
...this.parseSchema(p["each"], refs),
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
const meta = this.getMetaFromValidations(p["each"]["validations"], refs);
|
|
808
|
+
obj[field] = {
|
|
809
|
+
type: "array",
|
|
810
|
+
items: {
|
|
811
|
+
type: this.getType(p["each"]["type"]),
|
|
812
|
+
...meta,
|
|
813
|
+
example: meta.example ?? meta.minimum ?? this.exampleGenerator.exampleByType("number"),
|
|
814
|
+
},
|
|
825
815
|
};
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
obj[field] = {
|
|
820
|
+
type: this.getType(type),
|
|
821
|
+
example: meta.example ?? meta.minimum ?? this.exampleGenerator.exampleByType("number"),
|
|
822
|
+
...meta,
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
826
|
if (!p["isOptional"])
|
|
827
|
-
|
|
827
|
+
required.push(p["fieldName"]);
|
|
828
828
|
}
|
|
829
|
-
|
|
829
|
+
const res = { properties: obj };
|
|
830
|
+
if (required.length > 0)
|
|
831
|
+
res["required"] = required;
|
|
832
|
+
return res;
|
|
833
|
+
}
|
|
834
|
+
getType(type) {
|
|
835
|
+
if (type == 'literal') {
|
|
836
|
+
return 'string';
|
|
837
|
+
}
|
|
838
|
+
return type;
|
|
839
|
+
}
|
|
840
|
+
getMetaFromValidations(validations, refs) {
|
|
841
|
+
let meta = {};
|
|
842
|
+
for (const v of validations) {
|
|
843
|
+
if (refs[v["ruleFnId"]].options?.example) {
|
|
844
|
+
meta = { ...meta, example: refs[v["ruleFnId"]].options.example };
|
|
845
|
+
}
|
|
846
|
+
if (refs[v["ruleFnId"]].options?.min) {
|
|
847
|
+
meta = { ...meta, minimum: refs[v["ruleFnId"]].options.min };
|
|
848
|
+
}
|
|
849
|
+
if (refs[v["ruleFnId"]].options?.max) {
|
|
850
|
+
meta = { ...meta, maximum: refs[v["ruleFnId"]].options.max };
|
|
851
|
+
}
|
|
852
|
+
if (refs[v["ruleFnId"]].options?.choices) {
|
|
853
|
+
meta = { ...meta, enum: refs[v["ruleFnId"]].options.choices };
|
|
854
|
+
}
|
|
855
|
+
if (refs[v["ruleFnId"]].options?.toString().includes("/")) {
|
|
856
|
+
meta = { ...meta, pattern: refs[v["ruleFnId"]].options.toString() };
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return meta;
|
|
830
860
|
}
|
|
831
861
|
}
|
|
832
862
|
exports.ValidatorParser = ValidatorParser;
|