@necessarylion/adonis-autoswagger 0.0.4 → 0.0.5

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.
Files changed (40) hide show
  1. package/dist/adonis_helpers.d.ts +21 -0
  2. package/dist/{adonishelpers.js → adonis_helpers.js} +17 -2
  3. package/dist/auto_swagger.d.ts +28 -0
  4. package/dist/{autoswagger.js → auto_swagger.js} +43 -394
  5. package/dist/example.d.ts +47 -0
  6. package/dist/example.js +48 -1
  7. package/dist/file.d.ts +44 -0
  8. package/dist/file.js +93 -0
  9. package/dist/helpers.d.ts +11 -2
  10. package/dist/helpers.js +11 -25
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +2 -2
  13. package/dist/parsers/comment_parser.d.ts +10 -0
  14. package/dist/parsers/comment_parser.js +417 -0
  15. package/dist/parsers/enum_parser.d.ts +5 -0
  16. package/dist/parsers/enum_parser.js +51 -0
  17. package/dist/parsers/helpers.d.ts +13 -0
  18. package/dist/parsers/helpers.js +38 -0
  19. package/dist/parsers/index.d.ts +6 -0
  20. package/dist/parsers/index.js +22 -0
  21. package/dist/parsers/interface_parser.d.ts +13 -0
  22. package/dist/parsers/interface_parser.js +249 -0
  23. package/dist/parsers/model_parser.d.ts +11 -0
  24. package/dist/parsers/model_parser.js +234 -0
  25. package/dist/parsers/route_parser.d.ts +10 -0
  26. package/dist/parsers/route_parser.js +46 -0
  27. package/dist/parsers/validator_parser.d.ts +7 -0
  28. package/dist/parsers/validator_parser.js +192 -0
  29. package/dist/schema.d.ts +46 -0
  30. package/dist/schema.js +266 -0
  31. package/dist/types.d.ts +16 -17
  32. package/dist/ui.d.ts +31 -0
  33. package/dist/ui.js +157 -0
  34. package/package.json +2 -2
  35. package/dist/adonishelpers.d.ts +0 -6
  36. package/dist/autoswagger.d.ts +0 -30
  37. package/dist/parsers.d.ts +0 -83
  38. package/dist/parsers.js +0 -1142
  39. /package/dist/{scalarCustomCss.d.ts → scalar_custom_css.d.ts} +0 -0
  40. /package/dist/{scalarCustomCss.js → scalar_custom_css.js} +0 -0
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.InterfaceParser = void 0;
7
+ const example_1 = __importDefault(require("../example"));
8
+ class InterfaceParser {
9
+ exampleGenerator;
10
+ snakeCase;
11
+ schemas = {};
12
+ constructor(snakeCase, schemas = {}) {
13
+ this.snakeCase = snakeCase;
14
+ this.exampleGenerator = new example_1.default({});
15
+ this.schemas = schemas;
16
+ }
17
+ objToExample(obj) {
18
+ let example = {};
19
+ Object.entries(obj).map(([key, value]) => {
20
+ if (typeof value === "object") {
21
+ example[key] = this.objToExample(value);
22
+ }
23
+ else {
24
+ example[key] = this.exampleGenerator.exampleByType(value);
25
+ if (example[key] === null) {
26
+ example[key] = this.exampleGenerator.exampleByField(key);
27
+ }
28
+ }
29
+ });
30
+ return example;
31
+ }
32
+ parseProps(obj) {
33
+ const newObject = {};
34
+ Object.entries(obj).map(([field, value]) => {
35
+ if (typeof value === "object") {
36
+ newObject[field.replaceAll("?", "")] = {
37
+ type: "object",
38
+ nullable: field.includes("?"),
39
+ properties: this.parseProps(value),
40
+ example: this.objToExample(value),
41
+ };
42
+ }
43
+ else {
44
+ newObject[field.replaceAll("?", "")] = {
45
+ ...this.parseType(value, field),
46
+ };
47
+ }
48
+ });
49
+ return newObject;
50
+ }
51
+ getInheritedProperties(baseType) {
52
+ if (this.schemas[baseType]?.properties) {
53
+ return {
54
+ properties: this.schemas[baseType].properties,
55
+ required: this.schemas[baseType].required || [],
56
+ };
57
+ }
58
+ const cleanType = baseType
59
+ .split("/")
60
+ .pop()
61
+ ?.replace(".ts", "")
62
+ ?.replace(/^[#@]/, "");
63
+ if (!cleanType)
64
+ return { properties: {}, required: [] };
65
+ if (this.schemas[cleanType]?.properties) {
66
+ return {
67
+ properties: this.schemas[cleanType].properties,
68
+ required: this.schemas[cleanType].required || [],
69
+ };
70
+ }
71
+ const variations = [
72
+ cleanType,
73
+ `#models/${cleanType}`,
74
+ cleanType.replace(/Model$/, ""),
75
+ `${cleanType}Model`,
76
+ ];
77
+ for (const variation of variations) {
78
+ if (this.schemas[variation]?.properties) {
79
+ return {
80
+ properties: this.schemas[variation].properties,
81
+ required: this.schemas[variation].required || [],
82
+ };
83
+ }
84
+ }
85
+ return { properties: {}, required: [] };
86
+ }
87
+ parseInterfaces(fileContent) {
88
+ fileContent = fileContent
89
+ .replace(/\t/g, "")
90
+ .replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "");
91
+ let currentInterface = null;
92
+ const interfaces = {};
93
+ const interfaceDefinitions = new Map();
94
+ const lines = fileContent.split("\n");
95
+ for (let i = 0; i < lines.length; i++) {
96
+ const line = lines[i].trim();
97
+ const isDefault = line.startsWith("export default interface");
98
+ if (line.startsWith("interface") ||
99
+ line.startsWith("export interface") ||
100
+ isDefault) {
101
+ const splittedLine = line.split(/\s+/);
102
+ const index = line.endsWith("}")
103
+ ? splittedLine.length - 1
104
+ : splittedLine.length - 2;
105
+ const name = splittedLine[index].split(/[{\s]/)[0];
106
+ const extendedTypes = this.#parseExtends(line);
107
+ interfaceDefinitions.set(name, {
108
+ extends: extendedTypes,
109
+ properties: {},
110
+ required: [],
111
+ startLine: i,
112
+ examples: {},
113
+ });
114
+ currentInterface = name;
115
+ continue;
116
+ }
117
+ if (currentInterface && line === "}") {
118
+ currentInterface = null;
119
+ continue;
120
+ }
121
+ if (currentInterface &&
122
+ line &&
123
+ !line.startsWith("//") &&
124
+ !line.startsWith("/*") &&
125
+ !line.startsWith("*")) {
126
+ const definition = interfaceDefinitions.get(currentInterface);
127
+ if (definition) {
128
+ const previousLine = i > 0 ? lines[i - 1].trim() : "";
129
+ const isRequired = previousLine.includes("@required");
130
+ // extract example value from comment @example(john)
131
+ const example = previousLine.match(/@example\((.*)\)/)?.[1];
132
+ const [prop, type] = line.split(":").map((s) => s.trim());
133
+ if (prop && type) {
134
+ const cleanProp = prop.replace("?", "");
135
+ definition.properties[cleanProp] = type.replace(";", "");
136
+ if (isRequired || !prop.includes("?")) {
137
+ definition.required.push(cleanProp);
138
+ }
139
+ if (example)
140
+ definition.examples[cleanProp] = example;
141
+ }
142
+ }
143
+ }
144
+ }
145
+ for (const [name, definition] of interfaceDefinitions) {
146
+ let allProperties = {};
147
+ let requiredFields = new Set(definition.required);
148
+ for (const baseType of definition.extends) {
149
+ const baseSchema = this.schemas[baseType];
150
+ if (baseSchema) {
151
+ if (baseSchema.properties) {
152
+ Object.assign(allProperties, baseSchema.properties);
153
+ }
154
+ if (baseSchema.required) {
155
+ baseSchema.required.forEach((field) => requiredFields.add(field));
156
+ }
157
+ }
158
+ }
159
+ Object.assign(allProperties, definition.properties);
160
+ const parsedProperties = {};
161
+ for (const [key, value] of Object.entries(allProperties)) {
162
+ if (typeof value === "object" && value !== null && "type" in value) {
163
+ parsedProperties[key] = value;
164
+ }
165
+ else {
166
+ parsedProperties[key] = this.parseType(value, key);
167
+ }
168
+ if (definition.examples[key]) {
169
+ parsedProperties[key].example = definition.examples[key];
170
+ }
171
+ }
172
+ const schema = {
173
+ type: "object",
174
+ properties: parsedProperties,
175
+ required: Array.from(requiredFields),
176
+ description: `${name}${definition.extends.length
177
+ ? ` extends ${definition.extends.join(", ")}`
178
+ : ""} (Interface)`,
179
+ };
180
+ if (schema.required.length === 0) {
181
+ delete schema.required;
182
+ }
183
+ interfaces[name] = schema;
184
+ }
185
+ return interfaces;
186
+ }
187
+ #parseExtends(line) {
188
+ const matches = line.match(/extends\s+([^{]+)/);
189
+ if (!matches)
190
+ return [];
191
+ return matches[1]
192
+ .split(",")
193
+ .map((type) => type.trim())
194
+ .map((type) => {
195
+ const cleanType = type.split("/").pop();
196
+ return cleanType?.replace(/\.ts$/, "") || type;
197
+ });
198
+ }
199
+ parseType(type, field) {
200
+ if (typeof type === "object" && type !== null && "type" in type) {
201
+ return type;
202
+ }
203
+ let isArray = false;
204
+ if (typeof type === "string" && type.includes("[]")) {
205
+ type = type.replace("[]", "");
206
+ isArray = true;
207
+ }
208
+ if (typeof type === "string") {
209
+ type = type.replace(/[;\r\n]/g, "").trim();
210
+ }
211
+ let property = { type: type };
212
+ let notRequired = field.includes("?");
213
+ property.nullable = notRequired;
214
+ if (typeof type === "string" && type.toLowerCase() === "datetime") {
215
+ property.type = "string";
216
+ property.format = "date-time";
217
+ property.example = "2021-03-23T16:13:08.489+01:00";
218
+ }
219
+ else if (typeof type === "string" && type.toLowerCase() === "date") {
220
+ property.type = "string";
221
+ property.format = "date";
222
+ property.example = "2021-03-23";
223
+ }
224
+ else {
225
+ const standardTypes = ["string", "number", "boolean", "integer"];
226
+ if (typeof type === "string" &&
227
+ !standardTypes.includes(type.toLowerCase())) {
228
+ delete property.type;
229
+ property.$ref = `#/components/schemas/${type}`;
230
+ }
231
+ else {
232
+ if (typeof type === "string") {
233
+ property.type = type.toLowerCase();
234
+ }
235
+ property.example =
236
+ this.exampleGenerator.exampleByType(type) ||
237
+ this.exampleGenerator.exampleByField(field);
238
+ }
239
+ }
240
+ if (isArray) {
241
+ return {
242
+ type: "array",
243
+ items: property,
244
+ };
245
+ }
246
+ return property;
247
+ }
248
+ }
249
+ exports.InterfaceParser = InterfaceParser;
@@ -0,0 +1,11 @@
1
+ import ExampleGenerator from "../example";
2
+ export declare class ModelParser {
3
+ exampleGenerator: ExampleGenerator;
4
+ snakeCase: boolean;
5
+ constructor(snakeCase: boolean);
6
+ parseModelProperties(fileContent: string): {
7
+ name: string;
8
+ props: Record<string, any>;
9
+ required: any[];
10
+ };
11
+ }
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ModelParser = void 0;
7
+ const lodash_1 = require("lodash");
8
+ const helpers_1 = require("./helpers");
9
+ const example_1 = __importDefault(require("../example"));
10
+ const types_1 = require("../types");
11
+ class ModelParser {
12
+ exampleGenerator;
13
+ snakeCase;
14
+ constructor(snakeCase) {
15
+ this.snakeCase = snakeCase;
16
+ this.exampleGenerator = new example_1.default({});
17
+ }
18
+ parseModelProperties(fileContent) {
19
+ let props = {};
20
+ let required = [];
21
+ // remove empty lines
22
+ fileContent = fileContent
23
+ .replace(/\t/g, "")
24
+ .replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "");
25
+ const lines = fileContent.split("\n");
26
+ let softDelete = false;
27
+ let name = "";
28
+ lines.forEach((line, index) => {
29
+ line = line.trim();
30
+ // skip comments
31
+ if (line.startsWith("export default class")) {
32
+ name = line.split(" ")[3];
33
+ }
34
+ if (line.includes("@swagger-softdelete") ||
35
+ line.includes("SoftDeletes")) {
36
+ softDelete = true;
37
+ }
38
+ if (line.startsWith("//") ||
39
+ line.startsWith("/*") ||
40
+ line.startsWith("*") ||
41
+ line.startsWith("public static ") ||
42
+ line.startsWith("private static ") ||
43
+ line.startsWith("static "))
44
+ return;
45
+ if (index > 0 && lines[index - 1].includes("serializeAs: null"))
46
+ return;
47
+ if (index > 0 && lines[index - 1].includes("@no-swagger"))
48
+ return;
49
+ if (!line.startsWith("public ") &&
50
+ !line.startsWith("public get") &&
51
+ !line.includes("declare "))
52
+ return;
53
+ let splittedLine = [];
54
+ if (line.includes("declare ")) {
55
+ splittedLine = line.split("declare ");
56
+ }
57
+ if (line.startsWith("public ")) {
58
+ if (line.startsWith("public get")) {
59
+ splittedLine = line.split("public get");
60
+ let splittedLine2 = splittedLine[1].replace(/;/g, "").split(":");
61
+ }
62
+ else {
63
+ splittedLine = line.split("public ");
64
+ }
65
+ }
66
+ let splittedLine2 = splittedLine[1].replace(/;/g, "").split(":");
67
+ let field = splittedLine2[0];
68
+ let type = splittedLine2[1] || "";
69
+ type = type.trim();
70
+ let enums = [];
71
+ let format = "";
72
+ let keyprops = {};
73
+ let example = null;
74
+ if (index > 0 && lines[index - 1].includes("@enum")) {
75
+ const line = lines[index - 1];
76
+ let enumsFromLine = (0, helpers_1.getBetweenBrackets)(line, "enum");
77
+ if (enumsFromLine !== "") {
78
+ enums = enumsFromLine.split(",");
79
+ example = enums[0];
80
+ }
81
+ }
82
+ if (index > 0 && lines[index - 1].includes("@format")) {
83
+ const line = lines[index - 1];
84
+ let formatFromLine = (0, helpers_1.getBetweenBrackets)(line, "format");
85
+ if (formatFromLine !== "") {
86
+ format = formatFromLine;
87
+ }
88
+ }
89
+ if (index > 0 && lines[index - 1].includes("@example")) {
90
+ const line = lines[index - 1];
91
+ let match = line.match(/example\(([^()]*)\)/g);
92
+ if (match !== null) {
93
+ const exampleFromLine = match[0].replace("example(", "").replace(")", "");
94
+ example = exampleFromLine;
95
+ if (type === "number") {
96
+ example = parseInt(exampleFromLine);
97
+ }
98
+ }
99
+ }
100
+ if (index > 0 && lines[index - 1].includes("@required")) {
101
+ required.push(field);
102
+ }
103
+ if (index > 0 && lines[index - 1].includes("@props")) {
104
+ const line = lines[index - 1].replace("@props", "props");
105
+ const json = (0, helpers_1.getBetweenBrackets)(line, "props");
106
+ if ((0, helpers_1.isJSONString)(json)) {
107
+ keyprops = JSON.parse(json);
108
+ }
109
+ }
110
+ if (typeof type === "undefined") {
111
+ type = "string";
112
+ format = "";
113
+ }
114
+ field = field.trim();
115
+ type = type.trim();
116
+ //TODO: make oneOf
117
+ if (type.includes(" | ")) {
118
+ const types = type.split(" | ");
119
+ type = types.filter((t) => t !== "null")[0];
120
+ }
121
+ field = field.replace("()", "");
122
+ field = field.replace("get ", "");
123
+ type = type.replace("{", "").trim();
124
+ if (this.snakeCase) {
125
+ field = (0, lodash_1.snakeCase)(field);
126
+ }
127
+ let indicator = "type";
128
+ if (example === null) {
129
+ example = "string";
130
+ }
131
+ // if relation to another model
132
+ if (type.includes("typeof")) {
133
+ splittedLine = type.split("typeof ");
134
+ type = "#/components/schemas/" + splittedLine[1].slice(0, -1);
135
+ indicator = "$ref";
136
+ }
137
+ else {
138
+ if (types_1.standardTypes.includes(type.toLowerCase())) {
139
+ type = type.toLowerCase();
140
+ }
141
+ else {
142
+ // assume its a custom interface
143
+ indicator = "$ref";
144
+ type = "#/components/schemas/" + type;
145
+ }
146
+ }
147
+ type = type.trim();
148
+ let isArray = false;
149
+ if (line.includes("HasMany") ||
150
+ line.includes("ManyToMany") ||
151
+ line.includes("HasManyThrough") ||
152
+ type.includes("[]")) {
153
+ isArray = true;
154
+ if (type.slice(type.length - 2, type.length) === "[]") {
155
+ type = type.split("[]")[0];
156
+ }
157
+ }
158
+ if (example === null || example === "string") {
159
+ example =
160
+ this.exampleGenerator.exampleByField(field) ||
161
+ this.exampleGenerator.exampleByType(type);
162
+ }
163
+ if (type === "datetime") {
164
+ indicator = "type";
165
+ type = "string";
166
+ format = "date-time";
167
+ }
168
+ if (type === "date") {
169
+ indicator = "type";
170
+ type = "string";
171
+ format = "date";
172
+ }
173
+ if (type === "uuid") {
174
+ indicator = "type";
175
+ type = "string";
176
+ format = "uuid";
177
+ }
178
+ if (field === "email") {
179
+ indicator = "type";
180
+ type = "string";
181
+ format = "email";
182
+ }
183
+ if (field === "password") {
184
+ indicator = "type";
185
+ type = "string";
186
+ format = "password";
187
+ }
188
+ if (enums.length > 0) {
189
+ indicator = "type";
190
+ type = "string";
191
+ }
192
+ if (type === "any") {
193
+ indicator = "$ref";
194
+ type = "#/components/schemas/Any";
195
+ }
196
+ let prop = {};
197
+ if (type === "integer" || type === "number") {
198
+ if (example === null || example === "string") {
199
+ example = Math.floor(Math.random() * 1000);
200
+ }
201
+ }
202
+ if (type === "boolean") {
203
+ example = true;
204
+ }
205
+ prop[indicator] = type;
206
+ prop["example"] = example;
207
+ // if array
208
+ if (isArray) {
209
+ props[field] = { type: "array", items: prop };
210
+ }
211
+ else {
212
+ props[field] = prop;
213
+ if (format !== "") {
214
+ props[field]["format"] = format;
215
+ }
216
+ }
217
+ Object.entries(keyprops).map(([key, value]) => {
218
+ props[field][key] = value;
219
+ });
220
+ if (enums.length > 0) {
221
+ props[field]["enum"] = enums;
222
+ }
223
+ });
224
+ if (softDelete) {
225
+ props["deleted_at"] = {
226
+ type: "string",
227
+ format: "date-time",
228
+ example: "2021-03-23T16:13:08.489+01:00",
229
+ };
230
+ }
231
+ return { name: name, props: props, required: required };
232
+ }
233
+ }
234
+ exports.ModelParser = ModelParser;
@@ -0,0 +1,10 @@
1
+ import type { options } from "../types";
2
+ export declare class RouteParser {
3
+ options: options;
4
+ constructor(options: options);
5
+ extractInfos(path: string): {
6
+ tags: string[];
7
+ parameters: Record<string, any>;
8
+ pattern: string;
9
+ };
10
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RouteParser = void 0;
4
+ class RouteParser {
5
+ options;
6
+ constructor(options) {
7
+ this.options = options;
8
+ }
9
+ /*
10
+ extract path-variables, tags and the uri-pattern
11
+ */
12
+ extractInfos(path) {
13
+ let parameters = {};
14
+ let pattern = "";
15
+ let tags = [];
16
+ let required;
17
+ const split = path.split("/");
18
+ if (split.length > this.options.tagIndex) {
19
+ tags = [split[this.options.tagIndex].toUpperCase()];
20
+ }
21
+ split.forEach((part) => {
22
+ if (part.startsWith(":")) {
23
+ required = !part.endsWith("?");
24
+ const param = part.replace(":", "").replace("?", "");
25
+ part = "{" + param + "}";
26
+ parameters = {
27
+ ...parameters,
28
+ [param]: {
29
+ in: "path",
30
+ name: param,
31
+ schema: {
32
+ type: "string",
33
+ },
34
+ required: required,
35
+ },
36
+ };
37
+ }
38
+ pattern += "/" + part;
39
+ });
40
+ if (pattern.endsWith("/")) {
41
+ pattern = pattern.slice(0, -1);
42
+ }
43
+ return { tags, parameters, pattern };
44
+ }
45
+ }
46
+ exports.RouteParser = RouteParser;
@@ -0,0 +1,7 @@
1
+ import ExampleGenerator from "../example";
2
+ export declare class ValidatorParser {
3
+ #private;
4
+ exampleGenerator: ExampleGenerator;
5
+ constructor();
6
+ validatorToObject(validator: any): Promise<Record<string, any>>;
7
+ }