oip-common 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.
Files changed (50) hide show
  1. package/ng-package.json +12 -1
  2. package/package.json +19 -16
  3. package/src/helpers/date.helper.ts +2 -2
  4. package/templates/api.ejs +30 -0
  5. package/templates/data-contract-jsdoc.ejs +37 -0
  6. package/templates/data-contracts.ejs +52 -0
  7. package/templates/enum-data-contract.ejs +12 -0
  8. package/templates/http-client.ejs +245 -0
  9. package/templates/interface-data-contract.ejs +10 -0
  10. package/templates/object-field-jsdoc.ejs +28 -0
  11. package/templates/procedure-call.ejs +100 -0
  12. package/templates/route-docs.ejs +29 -0
  13. package/templates/route-name.ejs +42 -0
  14. package/templates/route-type.ejs +23 -0
  15. package/templates/route-types.ejs +18 -0
  16. package/templates/type-data-contract.ejs +15 -0
  17. package/src/assets/demo/data/products-small.json +0 -124
  18. package/src/assets/demo/images/blocks/hero/hero-1.png +0 -0
  19. package/src/assets/demo/images/blocks/logos/hyper.svg +0 -3
  20. package/src/assets/demo/images/product/bamboo-watch.jpg +0 -0
  21. package/src/assets/demo/images/product/black-watch.jpg +0 -0
  22. package/src/assets/demo/images/product/blue-band.jpg +0 -0
  23. package/src/assets/demo/images/product/blue-t-shirt.jpg +0 -0
  24. package/src/assets/demo/images/product/bracelet.jpg +0 -0
  25. package/src/assets/demo/images/product/brown-purse.jpg +0 -0
  26. package/src/assets/demo/images/product/chakra-bracelet.jpg +0 -0
  27. package/src/assets/demo/images/product/galaxy-earrings.jpg +0 -0
  28. package/src/assets/demo/images/product/game-controller.jpg +0 -0
  29. package/src/assets/demo/images/product/gaming-set.jpg +0 -0
  30. package/src/assets/demo/images/product/gold-phone-case.jpg +0 -0
  31. package/src/assets/demo/images/product/green-earbuds.jpg +0 -0
  32. package/src/assets/demo/images/product/green-t-shirt.jpg +0 -0
  33. package/src/assets/demo/images/product/grey-t-shirt.jpg +0 -0
  34. package/src/assets/demo/images/product/headphones.jpg +0 -0
  35. package/src/assets/demo/images/product/light-green-t-shirt.jpg +0 -0
  36. package/src/assets/demo/images/product/lime-band.jpg +0 -0
  37. package/src/assets/demo/images/product/mini-speakers.jpg +0 -0
  38. package/src/assets/demo/images/product/painted-phone-case.jpg +0 -0
  39. package/src/assets/demo/images/product/pink-band.jpg +0 -0
  40. package/src/assets/demo/images/product/pink-purse.jpg +0 -0
  41. package/src/assets/demo/images/product/product-placeholder.svg +0 -10
  42. package/src/assets/demo/images/product/purple-band.jpg +0 -0
  43. package/src/assets/demo/images/product/purple-gemstone-necklace.jpg +0 -0
  44. package/src/assets/demo/images/product/purple-t-shirt.jpg +0 -0
  45. package/src/assets/demo/images/product/shoes.jpg +0 -0
  46. package/src/assets/demo/images/product/sneakers.jpg +0 -0
  47. package/src/assets/demo/images/product/teal-t-shirt.jpg +0 -0
  48. package/src/assets/demo/images/product/yellow-earbuds.jpg +0 -0
  49. package/src/assets/demo/images/product/yoga-mat.jpg +0 -0
  50. package/src/assets/demo/images/product/yoga-set.jpg +0 -0
package/ng-package.json CHANGED
@@ -4,5 +4,16 @@
4
4
  "lib": {
5
5
  "entryFile": "src/public-api.ts"
6
6
  },
7
- "assets": [{ "input": "src/assets", "glob": "**/*", "output": "assets" }]
7
+ "assets": [
8
+ {
9
+ "input": "./src/assets",
10
+ "glob": "**/*",
11
+ "output": "assets"
12
+ },
13
+ {
14
+ "input": "./templates",
15
+ "glob": "**/*",
16
+ "output": "templates"
17
+ }
18
+ ]
8
19
  }
package/package.json CHANGED
@@ -1,16 +1,19 @@
1
- {
2
- "name": "oip-common",
3
- "version": "0.0.1",
4
- "description": "A template for cross-platform web applications",
5
- "main": "index.js",
6
- "scripts": {
7
- "pub": "npm publish"
8
- },
9
- "keywords": ["oip", "template"],
10
- "author": "Igor Tyulyakov aka g101k",
11
- "license": "MIT",
12
- "repository": {
13
- "type": "git",
14
- "url": "https://github.com/g10101k/Oip"
15
- }
16
- }
1
+ {
2
+ "name": "oip-common",
3
+ "version": "0.0.3",
4
+ "description": "A template for cross-platform web applications based on sakai-ng and primeNG",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "pub": "npm publish"
8
+ },
9
+ "keywords": [
10
+ "oip",
11
+ "template"
12
+ ],
13
+ "author": "Igor Tyulyakov aka g101k",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/g10101k/Oip.git"
18
+ }
19
+ }
@@ -60,7 +60,7 @@ export function convertToPrimeNgDateFormat(dateformat: string): string {
60
60
  }
61
61
 
62
62
  /**
63
- * Преобразовать все свойства объекта со строковыми датами в даты
63
+ * Convert all properties of an object with string dates to Date objects
64
64
  * @param obj
65
65
  */
66
66
  export function restoreDates(obj: any) {
@@ -86,7 +86,7 @@ export function restoreDates(obj: any) {
86
86
  }
87
87
 
88
88
  /**
89
- * Проверить, является ли строка датой в ISO формате
89
+ * Check if a string is a date in ISO format
90
90
  * @param str
91
91
  */
92
92
  export function isIsoDate(str: string) {
@@ -0,0 +1,30 @@
1
+ <%
2
+ const { utils, route, config, modelTypes } = it;
3
+ const { _, pascalCase, require } = utils;
4
+ const apiClassName = pascalCase(route.moduleName);
5
+ const routes = route.routes;
6
+ const dataContracts = _.map(modelTypes, "name");
7
+ %>
8
+
9
+ <% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import type { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
10
+
11
+ import { HttpClient, RequestParams, ContentType, HttpResponse } from "./<%~ config.fileNames.httpClient %>";
12
+ <% if (dataContracts.length) { %>
13
+ import { <%~ dataContracts.join(", ") %> } from "./<%~ config.fileNames.dataContracts %>"
14
+ <% } %>
15
+ import { Injectable } from "@angular/core";
16
+
17
+ @Injectable()
18
+ export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
19
+ <% if(config.singleHttpClient) { %>
20
+ http: HttpClient<SecurityDataType>;
21
+
22
+ constructor (http: HttpClient<SecurityDataType>) {
23
+ this.http = http;
24
+ }
25
+ <% } %>
26
+
27
+ <% for (const route of routes) { %>
28
+ <%~ includeFile('./procedure-call.ejs', { ...it, route }) %>
29
+ <% } %>
30
+ }
@@ -0,0 +1,37 @@
1
+ <%
2
+ const { data, utils } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+
5
+ const stringify = (value) => _.isObject(value) ? JSON.stringify(value) : _.isString(value) ? `"${value}"` : value
6
+
7
+ const jsDocLines = _.compact([
8
+ data.title,
9
+ data.description && formatDescription(data.description),
10
+ !_.isUndefined(data.deprecated) && data.deprecated && '@deprecated',
11
+ !_.isUndefined(data.format) && `@format ${data.format}`,
12
+ !_.isUndefined(data.minimum) && `@min ${data.minimum}`,
13
+ !_.isUndefined(data.multipleOf) && `@multipleOf ${data.multipleOf}`,
14
+ !_.isUndefined(data.exclusiveMinimum) && `@exclusiveMin ${data.exclusiveMinimum}`,
15
+ !_.isUndefined(data.maximum) && `@max ${data.maximum}`,
16
+ !_.isUndefined(data.minLength) && `@minLength ${data.minLength}`,
17
+ !_.isUndefined(data.maxLength) && `@maxLength ${data.maxLength}`,
18
+ !_.isUndefined(data.exclusiveMaximum) && `@exclusiveMax ${data.exclusiveMaximum}`,
19
+ !_.isUndefined(data.maxItems) && `@maxItems ${data.maxItems}`,
20
+ !_.isUndefined(data.minItems) && `@minItems ${data.minItems}`,
21
+ !_.isUndefined(data.uniqueItems) && `@uniqueItems ${data.uniqueItems}`,
22
+ !_.isUndefined(data.default) && `@default ${stringify(data.default)}`,
23
+ !_.isUndefined(data.pattern) && `@pattern ${data.pattern}`,
24
+ !_.isUndefined(data.example) && `@example ${stringify(data.example)}`
25
+ ]).join('\n').split('\n');
26
+ %>
27
+ <% if (jsDocLines.every(_.isEmpty)) { %>
28
+ <% } else if (jsDocLines.length === 1) { %>
29
+ /** <%~ jsDocLines[0] %> */
30
+ <% } else if (jsDocLines.length) { %>
31
+ /**
32
+ <% for (jsDocLine of jsDocLines) { %>
33
+ * <%~ jsDocLine %>
34
+
35
+ <% } %>
36
+ */
37
+ <% } %>
@@ -0,0 +1,52 @@
1
+ <%
2
+ const { modelTypes, utils, config } = it;
3
+ const { formatDescription, require, _, Ts } = utils;
4
+
5
+
6
+ const buildGenerics = (contract) => {
7
+ if (!contract.genericArgs || !contract.genericArgs.length) return '';
8
+
9
+ return '<' + contract.genericArgs.map(({ name, default: defaultType, extends: extendsType }) => {
10
+ return [
11
+ name,
12
+ extendsType && `extends ${extendsType}`,
13
+ defaultType && `= ${defaultType}`,
14
+ ].join('')
15
+ }).join(',') + '>'
16
+ }
17
+
18
+ const dataContractTemplates = {
19
+ enum: (contract) => {
20
+ return `enum ${contract.name} {\r\n${contract.content} \r\n }`;
21
+ },
22
+ interface: (contract) => {
23
+ return `interface ${contract.name}${buildGenerics(contract)} {\r\n${contract.content}}\r\n\r\n`;
24
+ },
25
+ type: (contract) => {
26
+ return `type ${contract.name}${buildGenerics(contract)} = ${contract.content}`;
27
+ },
28
+ }
29
+ %>
30
+
31
+ <% if (config.internalTemplateOptions.addUtilRequiredKeysType) { %>
32
+ type <%~ config.Ts.CodeGenKeyword.UtilRequiredKeys %><T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
33
+ <% } %>
34
+
35
+ <% for (const contract of modelTypes) {
36
+ if (contract.typeIdentifier === 'interface' && contract.rawContent && Array.isArray(contract.rawContent)) {
37
+ contract.rawContent.forEach((prop) => {
38
+ if (prop.format ==='date-time') {
39
+ prop.field = prop.field.replace(': string', ': Date');
40
+ }
41
+ })
42
+ let customContent = '';
43
+ contract.rawContent.forEach((prop) => {
44
+ if (prop.description) customContent += `/** ${prop.description} */ \r\n`;
45
+ customContent += `${prop.field};\r\n`;
46
+ })
47
+ contract.content = customContent;
48
+ }
49
+ %>
50
+ <%~ includeFile('./data-contract-jsdoc.ejs', { ...it, data: { ...contract, ...contract.typeData } }) %>
51
+ <%~ contract.internal ? '' : 'export'%> <%~ (dataContractTemplates[contract.typeIdentifier] || dataContractTemplates.type)(contract) %>
52
+ <% } %>
@@ -0,0 +1,12 @@
1
+ <%
2
+ const { contract, utils, config } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+ const { name, $content } = contract;
5
+ %>
6
+ <% if (config.generateUnionEnums) { %>
7
+ export type <%~ name %> = <%~ _.map($content, ({ value }) => value).join(" | ") %>
8
+ <% } else { %>
9
+ export enum <%~ name %> {
10
+ <%~ _.map($content, ({ key, value }) => `${key} = ${value}`).join(",\n") %>
11
+ }
12
+ <% } %>
@@ -0,0 +1,245 @@
1
+ <%
2
+ const { apiConfig, generateResponses, config } = it;
3
+ %>
4
+
5
+ import { SecurityService } from "oip-common";
6
+ import { LayoutService } from "oip-common";
7
+ import { inject, Injectable } from "@angular/core";
8
+
9
+ export type QueryParamsType = Record<string | number, any>;
10
+ export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
11
+
12
+ export interface FullRequestParams extends Omit<RequestInit, "body"> {
13
+ /** set parameter to `true` for call `securityWorker` for this request */
14
+ secure?: boolean;
15
+ /** request path */
16
+ path: string;
17
+ /** content type of request body */
18
+ type?: ContentType;
19
+ /** query params */
20
+ query?: QueryParamsType;
21
+ /** format of response (i.e. response.json() -> format: "json") */
22
+ format?: ResponseFormat;
23
+ /** request body */
24
+ body?: unknown;
25
+ /** base url */
26
+ baseUrl?: string;
27
+ /** request cancellation token */
28
+ cancelToken?: CancelToken;
29
+ }
30
+
31
+ export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">
32
+
33
+
34
+ export interface ApiConfig<SecurityDataType = unknown> {
35
+ baseUrl?: string;
36
+ baseApiParams?: Omit<RequestParams, "baseUrl" | "cancelToken" | "signal">;
37
+ securityWorker?: (securityData: SecurityDataType | null) => Promise<RequestParams | void> | RequestParams | void;
38
+ customFetch?: typeof fetch;
39
+ }
40
+
41
+ export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
42
+ data: D;
43
+ error: E;
44
+ }
45
+
46
+ type CancelToken = Symbol | string | number;
47
+
48
+ export enum ContentType {
49
+ Json = "application/json",
50
+ FormData = "multipart/form-data",
51
+ UrlEncoded = "application/x-www-form-urlencoded",
52
+ Text = "text/plain",
53
+ }
54
+
55
+ @Injectable({ providedIn: 'root' })
56
+ export class HttpClient<SecurityDataType = unknown> {
57
+ protected securityService = inject(SecurityService);
58
+ protected layoutService = inject(LayoutService);
59
+ public baseUrl: string = "<%~ apiConfig.baseUrl %>";
60
+ private securityData: SecurityDataType | null = null;
61
+ private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"] =
62
+ (securityData) => ({
63
+ headers: {
64
+ "Accept-language": this.layoutService.language()
65
+ ? this.layoutService.language()
66
+ : 'en',
67
+ "X-Timezone": this.layoutService.timeZone(),
68
+ Authorization: `Bearer ${securityData}`,
69
+ },
70
+ });
71
+ private abortControllers = new Map<CancelToken, AbortController>();
72
+ private customFetch = (...fetchParams: Parameters<typeof fetch>) => fetch(...fetchParams);
73
+
74
+ private baseApiParams: RequestParams = {
75
+ credentials: 'same-origin',
76
+ headers: {},
77
+ redirect: 'follow',
78
+ referrerPolicy: 'no-referrer',
79
+ }
80
+
81
+ constructor() {
82
+ this.securityService.getAccessToken().subscribe((token) => {
83
+ this.securityData = token;
84
+ });
85
+ }
86
+
87
+ public setSecurityData = (data: SecurityDataType | null) => {
88
+ this.securityData = data;
89
+ }
90
+
91
+ protected encodeQueryParam(key: string, value: any) {
92
+ const encodedKey = encodeURIComponent(key);
93
+ return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
94
+ }
95
+
96
+ protected addQueryParam(query: QueryParamsType, key: string) {
97
+ return this.encodeQueryParam(key, query[key]);
98
+ }
99
+
100
+ protected addArrayQueryParam(query: QueryParamsType, key: string) {
101
+ const value = query[key];
102
+ return value.map((v: any) => this.encodeQueryParam(key, v)).join("&");
103
+ }
104
+
105
+ protected toQueryString(rawQuery?: QueryParamsType): string {
106
+ const query = rawQuery || {};
107
+ const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
108
+ return keys
109
+ .map((key) =>
110
+ Array.isArray(query[key])
111
+ ? this.addArrayQueryParam(query, key)
112
+ : this.addQueryParam(query, key),
113
+ )
114
+ .join("&");
115
+ }
116
+
117
+ protected addQueryParams(rawQuery?: QueryParamsType): string {
118
+ const queryString = this.toQueryString(rawQuery);
119
+ return queryString ? `?${queryString}` : "";
120
+ }
121
+
122
+ private contentFormatters: Record<ContentType, (input: any) => any> = {
123
+ [ContentType.Json]: (input:any) => input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input,
124
+ [ContentType.Text]: (input:any) => input !== null && typeof input !== "string" ? JSON.stringify(input) : input,
125
+ [ContentType.FormData]: (input: any) =>
126
+ Object.keys(input || {}).reduce((formData, key) => {
127
+ const property = input[key];
128
+ formData.append(
129
+ key,
130
+ property instanceof Blob ?
131
+ property :
132
+ typeof property === "object" && property !== null ?
133
+ JSON.stringify(property) :
134
+ `${property}`
135
+ );
136
+ return formData;
137
+ }, new FormData()),
138
+ [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
139
+ }
140
+
141
+ protected mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams {
142
+ return {
143
+ ...this.baseApiParams,
144
+ ...params1,
145
+ ...(params2 || {}),
146
+ headers: {
147
+ ...(this.baseApiParams.headers || {}),
148
+ ...(params1.headers || {}),
149
+ ...((params2 && params2.headers) || {}),
150
+ },
151
+ };
152
+ }
153
+
154
+ protected createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => {
155
+ if (this.abortControllers.has(cancelToken)) {
156
+ const abortController = this.abortControllers.get(cancelToken);
157
+ if (abortController) {
158
+ return abortController.signal;
159
+ }
160
+ return void 0;
161
+ }
162
+
163
+ const abortController = new AbortController();
164
+ this.abortControllers.set(cancelToken, abortController);
165
+ return abortController.signal;
166
+ }
167
+
168
+ public abortRequest = (cancelToken: CancelToken) => {
169
+ const abortController = this.abortControllers.get(cancelToken)
170
+
171
+ if (abortController) {
172
+ abortController.abort();
173
+ this.abortControllers.delete(cancelToken);
174
+ }
175
+ }
176
+
177
+ public request = async <T = any, E = any>({
178
+ body,
179
+ secure,
180
+ path,
181
+ type,
182
+ query,
183
+ format,
184
+ baseUrl,
185
+ cancelToken,
186
+ ...params
187
+ <% if (config.unwrapResponseData) { %>
188
+ }: FullRequestParams): Promise<T> => {
189
+ <% } else { %>
190
+ }: FullRequestParams): Promise<HttpResponse<T, E>> => {
191
+ <% } %>
192
+ const secureParams = ((typeof secure === 'boolean' ? secure : this.baseApiParams.secure) && this.securityWorker && await this.securityWorker(this.securityData)) || {};
193
+ const requestParams = this.mergeRequestParams(params, secureParams);
194
+ const queryString = query && this.toQueryString(query);
195
+ const payloadFormatter = this.contentFormatters[type || ContentType.Json];
196
+ let responseFormat = format || requestParams.format;
197
+
198
+ return this.customFetch(
199
+ `${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`,
200
+ {
201
+ ...requestParams,
202
+ headers: {
203
+ ...(requestParams.headers || {}),
204
+ ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),
205
+ },
206
+ signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null,
207
+ body: typeof body === "undefined" || body === null ? null : payloadFormatter(body),
208
+ }
209
+ ).then(async (response) => {
210
+ const r = response.clone() as HttpResponse<T, E>;
211
+ r.data = (null as unknown) as T;
212
+ r.error = (null as unknown) as E;
213
+
214
+ if (typeof E !== undefined && responseFormat === undefined)
215
+ responseFormat = 'json';
216
+
217
+ const data = !responseFormat ? r : await response[responseFormat]()
218
+ .then((data) => {
219
+ if (r.ok) {
220
+ r.data = data;
221
+ } else {
222
+ r.error = data;
223
+ }
224
+ return r;
225
+ })
226
+ .catch((e) => {
227
+ r.error = e;
228
+ return r;
229
+ });
230
+
231
+ if (cancelToken) {
232
+ this.abortControllers.delete(cancelToken);
233
+ }
234
+
235
+ <% if (!config.disableThrowOnError) { %>
236
+ if (!response.ok) throw data;
237
+ <% } %>
238
+ <% if (config.unwrapResponseData) { %>
239
+ return data.data;
240
+ <% } else { %>
241
+ return data;
242
+ <% } %>
243
+ });
244
+ };
245
+ }
@@ -0,0 +1,10 @@
1
+ <%
2
+ const { contract, utils } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+ %>
5
+ export interface <%~ contract.name %> {
6
+ <% for (const field of contract.$content) { %>
7
+ <%~ includeFile('./object-field-jsdoc.ejs', { ...it, field }) %>
8
+ <%~ field.name %><%~ field.isRequired ? '' : '?' %>: <%~ field.value %><%~ field.isNullable ? ' | null' : ''%>;
9
+ <% } %>
10
+ }
@@ -0,0 +1,28 @@
1
+ <%
2
+ const { field, utils } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+
5
+ const comments = _.uniq(
6
+ _.compact([
7
+ field.title,
8
+ field.description,
9
+ field.deprecated && ` * @deprecated`,
10
+ !_.isUndefined(field.format) && `@format ${field.format}`,
11
+ !_.isUndefined(field.minimum) && `@min ${field.minimum}`,
12
+ !_.isUndefined(field.maximum) && `@max ${field.maximum}`,
13
+ !_.isUndefined(field.pattern) && `@pattern ${field.pattern}`,
14
+ !_.isUndefined(field.example) &&
15
+ `@example ${_.isObject(field.example) ? JSON.stringify(field.example) : field.example}`,
16
+ ]).reduce((acc, comment) => [...acc, ...comment.split(/\n/g)], []),
17
+ );
18
+ %>
19
+ <% if (comments.length === 1) { %>
20
+ /** <%~ comments[0] %> */
21
+ <% } else if (comments.length) { %>
22
+ /**
23
+ <% comments.forEach(comment => { %>
24
+ * <%~ comment %>
25
+
26
+ <% }) %>
27
+ */
28
+ <% } %>
@@ -0,0 +1,100 @@
1
+ <%
2
+ const { utils, route, config } = it;
3
+ const { requestBodyInfo, responseBodyInfo, specificArgNameResolver } = route;
4
+ const { _, getInlineParseContent, getParseContent, parseSchema, getComponentByRef, require } = utils;
5
+ const { parameters, path, method, payload, query, formData, security, requestParams } = route.request;
6
+ const { type, errorType, contentTypes } = route.response;
7
+ const { HTTP_CLIENT, RESERVED_REQ_PARAMS_ARG_NAMES } = config.constants;
8
+ const routeDocs = includeFile("./route-docs", { config, route, utils });
9
+ const queryName = (query && query.name) || "query";
10
+ const pathParams = _.values(parameters);
11
+ const pathParamsNames = _.map(pathParams, "name");
12
+
13
+ const isFetchTemplate = config.httpClientType === HTTP_CLIENT.FETCH;
14
+
15
+ const requestConfigParam = {
16
+ name: specificArgNameResolver.resolve(RESERVED_REQ_PARAMS_ARG_NAMES),
17
+ optional: true,
18
+ type: "RequestParams",
19
+ defaultValue: "{}",
20
+ }
21
+
22
+ const argToTmpl = ({ name, optional, type, defaultValue }) => `${name}${!defaultValue && optional ? '?' : ''}: ${type}${defaultValue ? ` = ${defaultValue}` : ''}`;
23
+
24
+ const rawWrapperArgs = config.extractRequestParams ?
25
+ _.compact([
26
+ requestParams && {
27
+ name: pathParams.length ? `{ ${_.join(pathParamsNames, ", ")}, ...${queryName} }` : queryName,
28
+ optional: false,
29
+ type: getInlineParseContent(requestParams),
30
+ },
31
+ ...(!requestParams ? pathParams : []),
32
+ payload,
33
+ requestConfigParam,
34
+ ]) :
35
+ _.compact([
36
+ ...pathParams,
37
+ query,
38
+ payload,
39
+ requestConfigParam,
40
+ ])
41
+
42
+ const wrapperArgs = _
43
+ // Sort by optionality
44
+ .sortBy(rawWrapperArgs, [o => o.optional])
45
+ .map(argToTmpl)
46
+ .join(', ')
47
+
48
+ // RequestParams["type"]
49
+ const requestContentKind = {
50
+ "JSON": "ContentType.Json",
51
+ "URL_ENCODED": "ContentType.UrlEncoded",
52
+ "FORM_DATA": "ContentType.FormData",
53
+ "TEXT": "ContentType.Text",
54
+ }
55
+ // RequestParams["format"]
56
+ const responseContentKind = {
57
+ "JSON": '"json"',
58
+ "IMAGE": '"blob"',
59
+ "FORM_DATA": isFetchTemplate ? '"formData"' : '"document"'
60
+ }
61
+
62
+ const bodyTmpl = _.get(payload, "name") || null;
63
+ const queryTmpl = (query != null && queryName) || null;
64
+ const bodyContentKindTmpl = requestContentKind[requestBodyInfo.contentKind] || null;
65
+ const responseFormatTmpl = responseContentKind[responseBodyInfo.success && responseBodyInfo.success.schema && responseBodyInfo.success.schema.contentKind] || null;
66
+ const securityTmpl = security ? 'true' : null;
67
+
68
+ const describeReturnType = () => {
69
+ if (!config.toJS) return "";
70
+
71
+ switch(config.httpClientType) {
72
+ case HTTP_CLIENT.AXIOS: {
73
+ return `Promise<AxiosResponse<${type}>>`
74
+ }
75
+ default: {
76
+ return `Promise<HttpResponse<${type}, ${errorType}>`
77
+ }
78
+ }
79
+ }
80
+
81
+ %>
82
+ /**
83
+ <%~ routeDocs.description %>
84
+
85
+ *<% /* Here you can add some other JSDoc tags */ %>
86
+
87
+ <%~ routeDocs.lines %>
88
+
89
+ */
90
+ <%~ route.routeName.usage %> = (<%~ wrapperArgs %>)<%~ config.toJS ? `: ${describeReturnType()}` : "" %> =>
91
+ <%~ config.singleHttpClient ? 'this.http.request' : 'this.request' %><<%~ type %>, <%~ errorType %>>({
92
+ path: `<%~ path %>`,
93
+ method: '<%~ _.upperCase(method) %>',
94
+ <%~ queryTmpl ? `query: ${queryTmpl},` : '' %>
95
+ <%~ bodyTmpl ? `body: ${bodyTmpl},` : '' %>
96
+ <%~ securityTmpl ? `secure: ${securityTmpl},` : '' %>
97
+ <%~ bodyContentKindTmpl ? `type: ${bodyContentKindTmpl},` : '' %>
98
+ <%~ responseFormatTmpl ? `format: ${responseFormatTmpl},` : '' %>
99
+ ...<%~ _.get(requestConfigParam, "name") %>,
100
+ })
@@ -0,0 +1,29 @@
1
+ <%
2
+ const { config, route, utils } = it;
3
+ const { _, formatDescription, fmtToJSDocLine, pascalCase, require } = utils;
4
+ const { raw, request, routeName } = route;
5
+
6
+ const jsDocDescription = raw.summary ?
7
+ ` * @description ${formatDescription(raw.summary, true)}` :
8
+ fmtToJSDocLine('No description', { eol: false });
9
+ const jsDocLines = _.compact([
10
+ _.size(raw.tags) && ` * @tags ${raw.tags.join(", ")}`,
11
+ ` * @name ${_.camelCase(routeName.usage)}`,
12
+ ` * @request ${_.upperCase(request.method)}:${raw.route}`,
13
+ raw.deprecated && ` * @deprecated`,
14
+ routeName.duplicate && ` * @originalName ${routeName.original}`,
15
+ routeName.duplicate && ` * @duplicate`,
16
+ request.security && ` * @secure`,
17
+ ...(config.generateResponses && raw.responsesTypes.length
18
+ ? raw.responsesTypes.map(
19
+ ({ type, status, description, isSuccess }) =>
20
+ ` * @response \`${status}\` \`${_.replace(_.replace(type, /\/\*/g, "\\*"), /\*\//g, "*\\")}\` ${description}`,
21
+ )
22
+ : []),
23
+ ]).map(str => str.trimEnd()).join("\n");
24
+
25
+ return {
26
+ description: jsDocDescription,
27
+ lines: jsDocLines,
28
+ }
29
+ %>
@@ -0,0 +1,42 @@
1
+ <%
2
+ const { routeInfo, utils } = it;
3
+ const {
4
+ operationId,
5
+ method,
6
+ route,
7
+ moduleName,
8
+ responsesTypes,
9
+ description,
10
+ tags,
11
+ summary,
12
+ pathArgs,
13
+ } = routeInfo;
14
+ const { _, fmtToJSDocLine, require } = utils;
15
+
16
+ const methodAliases = {
17
+ get: (pathName, hasPathInserts) => _.camelCase(`${pathName}`),
18
+ post: (pathName, hasPathInserts) => _.camelCase(`${pathName}`),
19
+ put: (pathName, hasPathInserts) => _.camelCase(`${pathName}`),
20
+ patch: (pathName, hasPathInserts) => _.camelCase(`${pathName}`),
21
+ delete: (pathName, hasPathInserts) => _.camelCase(`${pathName}`),
22
+ };
23
+
24
+ const createCustomOperationId = (method, route, moduleName) => {
25
+ const hasPathInserts = /\{(\w){1,}\}$/g.test(route);
26
+ const splittedRouteBySlash = _.compact(_.replace(route, /\{(\w){1,}\}/g, "").split("/"));
27
+ const routeParts = (splittedRouteBySlash.length > 1
28
+ ? splittedRouteBySlash.splice(1)
29
+ : splittedRouteBySlash
30
+ ).join("_");
31
+ return routeParts.length > 3 && methodAliases[method]
32
+ ? methodAliases[method](routeParts, hasPathInserts)
33
+ : _.camelCase(_.lowerCase(method) + "_" + [moduleName].join("_")) || "index";
34
+ };
35
+
36
+ if (operationId)
37
+ return _.camelCase(operationId);
38
+ if (route === "/")
39
+ return _.camelCase(`${_.lowerCase(method)}Root`);
40
+
41
+ return createCustomOperationId(method, route, moduleName);
42
+ %>
@@ -0,0 +1,23 @@
1
+ <%
2
+ const { route, utils, config } = it;
3
+ const { _, pascalCase, require } = utils;
4
+ const { query, payload, pathParams, headers } = route.request;
5
+
6
+ const routeDocs = includeFile("./route-docs", { config, route, utils });
7
+ const routeNamespace = pascalCase(route.routeName.usage);
8
+
9
+ %>
10
+
11
+ /**
12
+ <%~ routeDocs.description %>
13
+
14
+ <%~ routeDocs.lines %>
15
+
16
+ */
17
+ export namespace <%~ routeNamespace %> {
18
+ export type RequestParams = <%~ (pathParams && pathParams.type) || '{}' %>;
19
+ export type RequestQuery = <%~ (query && query.type) || '{}' %>;
20
+ export type RequestBody = <%~ (payload && payload.type) || 'never' %>;
21
+ export type RequestHeaders = <%~ (headers && headers.type) || '{}' %>;
22
+ export type ResponseBody = <%~ route.response.type %>;
23
+ }
@@ -0,0 +1,18 @@
1
+ <%
2
+ const { utils, config, route, modelTypes } = it;
3
+ const { _, pascalCase } = utils;
4
+ const { routes, moduleName } = route;
5
+ const dataContracts = config.modular ? _.map(modelTypes, "name") : [];
6
+
7
+ %>
8
+ <% if (dataContracts.length) { %>
9
+ import { <%~ dataContracts.join(", ") %> } from "./<%~ config.fileNames.dataContracts %>"
10
+ <% } %>
11
+
12
+ export namespace <%~ pascalCase(moduleName) %> {
13
+ <% for (const route of routes) { %>
14
+
15
+ <%~ includeFile('./route-type.ejs', { ...it, route }) %>
16
+
17
+ <% } %>
18
+ }
@@ -0,0 +1,15 @@
1
+ <%
2
+ const { contract, utils } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+
5
+ %>
6
+ <% if (contract.$content.length) { %>
7
+ export type <%~ contract.name %> = {
8
+ <% for (const field of contract.$content) { %>
9
+ <%~ includeFile('./object-field-jsdoc.ejs', { ...it, field }) %>
10
+ <%~ field.field %>;
11
+ <% } %>
12
+ }<%~ utils.isNeedToAddNull(contract) ? ' | null' : ''%>
13
+ <% } else { %>
14
+ export type <%~ contract.name %> = Record<string, any>;
15
+ <% } %>
@@ -1,124 +0,0 @@
1
- {
2
- "data": [
3
- {
4
- "id": "1000",
5
- "code": "f230fh0g3",
6
- "name": "Bamboo Watch",
7
- "description": "Product Description",
8
- "image": "bamboo-watch.jpg",
9
- "price": 65,
10
- "category": "Accessories",
11
- "quantity": 24,
12
- "inventoryStatus": "INSTOCK",
13
- "rating": 5
14
- },
15
- {
16
- "id": "1001",
17
- "code": "nvklal433",
18
- "name": "Black Watch",
19
- "description": "Product Description",
20
- "image": "black-watch.jpg",
21
- "price": 72,
22
- "category": "Accessories",
23
- "quantity": 61,
24
- "inventoryStatus": "INSTOCK",
25
- "rating": 4
26
- },
27
- {
28
- "id": "1002",
29
- "code": "zz21cz3c1",
30
- "name": "Blue Band",
31
- "description": "Product Description",
32
- "image": "blue-band.jpg",
33
- "price": 79,
34
- "category": "Fitness",
35
- "quantity": 2,
36
- "inventoryStatus": "LOWSTOCK",
37
- "rating": 3
38
- },
39
- {
40
- "id": "1003",
41
- "code": "244wgerg2",
42
- "name": "Blue T-Shirt",
43
- "description": "Product Description",
44
- "image": "blue-t-shirt.jpg",
45
- "price": 29,
46
- "category": "Clothing",
47
- "quantity": 25,
48
- "inventoryStatus": "INSTOCK",
49
- "rating": 5
50
- },
51
- {
52
- "id": "1004",
53
- "code": "h456wer53",
54
- "name": "Bracelet",
55
- "description": "Product Description",
56
- "image": "bracelet.jpg",
57
- "price": 15,
58
- "category": "Accessories",
59
- "quantity": 73,
60
- "inventoryStatus": "INSTOCK",
61
- "rating": 4
62
- },
63
- {
64
- "id": "1005",
65
- "code": "av2231fwg",
66
- "name": "Brown Purse",
67
- "description": "Product Description",
68
- "image": "brown-purse.jpg",
69
- "price": 120,
70
- "category": "Accessories",
71
- "quantity": 0,
72
- "inventoryStatus": "OUTOFSTOCK",
73
- "rating": 4
74
- },
75
- {
76
- "id": "1006",
77
- "code": "bib36pfvm",
78
- "name": "Chakra Bracelet",
79
- "description": "Product Description",
80
- "image": "chakra-bracelet.jpg",
81
- "price": 32,
82
- "category": "Accessories",
83
- "quantity": 5,
84
- "inventoryStatus": "LOWSTOCK",
85
- "rating": 3
86
- },
87
- {
88
- "id": "1007",
89
- "code": "mbvjkgip5",
90
- "name": "Galaxy Earrings",
91
- "description": "Product Description",
92
- "image": "galaxy-earrings.jpg",
93
- "price": 34,
94
- "category": "Accessories",
95
- "quantity": 23,
96
- "inventoryStatus": "INSTOCK",
97
- "rating": 5
98
- },
99
- {
100
- "id": "1008",
101
- "code": "vbb124btr",
102
- "name": "Game Controller",
103
- "description": "Product Description",
104
- "image": "game-controller.jpg",
105
- "price": 99,
106
- "category": "Electronics",
107
- "quantity": 2,
108
- "inventoryStatus": "LOWSTOCK",
109
- "rating": 4
110
- },
111
- {
112
- "id": "1009",
113
- "code": "cm230f032",
114
- "name": "Gaming Set",
115
- "description": "Product Description",
116
- "image": "gaming-set.jpg",
117
- "price": 299,
118
- "category": "Electronics",
119
- "quantity": 63,
120
- "inventoryStatus": "INSTOCK",
121
- "rating": 3
122
- }
123
- ]
124
- }
@@ -1,3 +0,0 @@
1
- <svg width="48" height="50" viewBox="0 0 48 50" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" clip-rule="evenodd" d="M33.1548 9.65956L23.9913 4.86169L5.54723 14.5106L0.924465 12.0851L23.9913 0L37.801 7.23403L33.1548 9.65956ZM23.9931 19.3085L42.4255 9.65955L47.0717 12.0851L23.9931 24.1595L10.1952 16.9361L14.8297 14.5106L23.9931 19.3085ZM4.6345 25.8937L0 23.4681V37.9149L23.0669 50V45.1489L4.6345 35.4894V25.8937ZM18.4324 28.2658L0 18.6169V13.7658L23.0669 25.8403V40.2977L18.4324 37.8615V28.2658ZM38.7301 23.468V18.6169L24.9205 25.8403V49.9999L29.555 47.5743V28.2659L38.7301 23.468ZM43.3546 35.4892V16.1914L48.0008 13.7659V37.9148L34.1912 45.1488V40.2977L43.3546 35.4892Z" fill="#616161"/>
3
- </svg>
@@ -1,10 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg width="300px" height="200px" viewBox="0 0 300 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <title>Artboard</title>
4
- <g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
5
- <rect id="Rectangle" fill="#F8F9FA" x="0" y="0" width="300" height="200"></rect>
6
- <g id="image" transform="translate(110.000000, 70.000000)" fill="#BABABC" fill-rule="nonzero">
7
- <path d="M75,0 L5,0 C2.23857625,0 0,2.23857625 0,5 L0,55 C0,57.7614237 2.23857625,60 5,60 L75,60 C77.7614237,60 80,57.7614237 80,55 L80,5 C80,2.23857625 77.7614237,0 75,0 Z M20,10 C25.5228475,10 30,14.4771525 30,20 C30,25.5228475 25.5228475,30 20,30 C14.4771525,30 10,25.5228475 10,20 C10,14.4771525 14.4771525,10 20,10 Z M70,40 L70,50 L10,50 L10,40 L18.55,35.7 C19.4648753,35.2524957 20.5351247,35.2524957 21.45,35.7 L30,40 L53.65,21.1 C54.4866298,20.4991452 55.6133702,20.4991452 56.45,21.1 L70,30 L70,40 Z" id="Shape"></path>
8
- </g>
9
- </g>
10
- </svg>