@compassdigital/sdk.typescript 3.0.0-beta.8 → 3.0.0-rc.1

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 (226) hide show
  1. package/README.md +121 -8
  2. package/bin/gen.js +484 -0
  3. package/bin/index.js +3 -0
  4. package/gen.ts +99 -41
  5. package/lib/base.d.ts +134 -9
  6. package/lib/base.d.ts.map +1 -1
  7. package/lib/base.js +293 -48
  8. package/lib/base.js.map +1 -1
  9. package/lib/index.d.ts +592 -337
  10. package/lib/index.d.ts.map +1 -1
  11. package/lib/index.js +544 -245
  12. package/lib/index.js.map +1 -1
  13. package/lib/interface/announcement.d.ts.map +1 -0
  14. package/lib/interface/announcement.js +4 -0
  15. package/lib/interface/announcement.js.map +1 -0
  16. package/lib/interface/brand.d.ts.map +1 -0
  17. package/lib/interface/brand.js +4 -0
  18. package/lib/interface/brand.js.map +1 -0
  19. package/lib/{calendar.d.ts → interface/calendar.d.ts} +4 -1
  20. package/lib/interface/calendar.d.ts.map +1 -0
  21. package/lib/interface/calendar.js +4 -0
  22. package/lib/interface/calendar.js.map +1 -0
  23. package/lib/interface/config.d.ts.map +1 -0
  24. package/lib/interface/config.js +4 -0
  25. package/lib/interface/config.js.map +1 -0
  26. package/lib/interface/datalake.d.ts.map +1 -0
  27. package/lib/interface/datalake.js +4 -0
  28. package/lib/interface/datalake.js.map +1 -0
  29. package/lib/interface/delivery.d.ts.map +1 -0
  30. package/lib/interface/delivery.js +4 -0
  31. package/lib/interface/delivery.js.map +1 -0
  32. package/lib/interface/dh.d.ts.map +1 -0
  33. package/lib/interface/dh.js +4 -0
  34. package/lib/interface/dh.js.map +1 -0
  35. package/lib/interface/email.d.ts +21 -0
  36. package/lib/interface/email.d.ts.map +1 -0
  37. package/lib/interface/email.js +4 -0
  38. package/lib/interface/email.js.map +1 -0
  39. package/lib/interface/file.d.ts.map +1 -0
  40. package/lib/interface/file.js +4 -0
  41. package/lib/interface/file.js.map +1 -0
  42. package/lib/{kds.d.ts → interface/kds.d.ts} +1 -0
  43. package/lib/interface/kds.d.ts.map +1 -0
  44. package/lib/interface/kds.js +4 -0
  45. package/lib/interface/kds.js.map +1 -0
  46. package/lib/{location.d.ts → interface/location.d.ts} +50 -20
  47. package/lib/interface/location.d.ts.map +1 -0
  48. package/lib/interface/location.js +4 -0
  49. package/lib/interface/location.js.map +1 -0
  50. package/lib/interface/logger.d.ts.map +1 -0
  51. package/lib/interface/logger.js +4 -0
  52. package/lib/interface/logger.js.map +1 -0
  53. package/lib/interface/loyalty.d.ts.map +1 -0
  54. package/lib/interface/loyalty.js +4 -0
  55. package/lib/interface/loyalty.js.map +1 -0
  56. package/lib/interface/mealplan.d.ts.map +1 -0
  57. package/lib/interface/mealplan.js +4 -0
  58. package/lib/interface/mealplan.js.map +1 -0
  59. package/lib/interface/menu.d.ts +448 -0
  60. package/lib/interface/menu.d.ts.map +1 -0
  61. package/lib/interface/menu.js +4 -0
  62. package/lib/interface/menu.js.map +1 -0
  63. package/lib/interface/message.d.ts.map +1 -0
  64. package/lib/interface/message.js +4 -0
  65. package/lib/interface/message.js.map +1 -0
  66. package/lib/{order.d.ts → interface/order.d.ts} +11 -4
  67. package/lib/interface/order.d.ts.map +1 -0
  68. package/lib/interface/order.js +4 -0
  69. package/lib/interface/order.js.map +1 -0
  70. package/lib/{partner.d.ts → interface/partner.d.ts} +243 -4
  71. package/lib/interface/partner.d.ts.map +1 -0
  72. package/lib/interface/partner.js +4 -0
  73. package/lib/interface/partner.js.map +1 -0
  74. package/lib/{payment.d.ts → interface/payment.d.ts} +1 -0
  75. package/lib/interface/payment.d.ts.map +1 -0
  76. package/lib/interface/payment.js +4 -0
  77. package/lib/interface/payment.js.map +1 -0
  78. package/lib/{promo.d.ts → interface/promo.d.ts} +1 -0
  79. package/lib/interface/promo.d.ts.map +1 -0
  80. package/lib/interface/promo.js +4 -0
  81. package/lib/interface/promo.js.map +1 -0
  82. package/lib/{report.d.ts → interface/report.d.ts} +2 -0
  83. package/lib/interface/report.d.ts.map +1 -0
  84. package/lib/interface/report.js +4 -0
  85. package/lib/interface/report.js.map +1 -0
  86. package/lib/interface/schedule.d.ts.map +1 -0
  87. package/lib/interface/schedule.js +4 -0
  88. package/lib/interface/schedule.js.map +1 -0
  89. package/lib/{shoppingcart.d.ts → interface/shoppingcart.d.ts} +10 -1
  90. package/lib/interface/shoppingcart.d.ts.map +1 -0
  91. package/lib/interface/shoppingcart.js +4 -0
  92. package/lib/interface/shoppingcart.js.map +1 -0
  93. package/lib/interface/task.d.ts.map +1 -0
  94. package/lib/interface/task.js +4 -0
  95. package/lib/interface/task.js.map +1 -0
  96. package/lib/{user.d.ts → interface/user.d.ts} +19 -0
  97. package/lib/interface/user.d.ts.map +1 -0
  98. package/lib/interface/user.js +4 -0
  99. package/lib/interface/user.js.map +1 -0
  100. package/lib/interface/vote.d.ts.map +1 -0
  101. package/lib/interface/vote.js +4 -0
  102. package/lib/interface/vote.js.map +1 -0
  103. package/manifest.json +4 -0
  104. package/package.json +15 -5
  105. package/src/base.ts +315 -35
  106. package/src/index.ts +2630 -988
  107. package/src/{announcement.ts → interface/announcement.ts} +2 -0
  108. package/src/{brand.ts → interface/brand.ts} +2 -0
  109. package/src/{calendar.ts → interface/calendar.ts} +7 -1
  110. package/src/{config.ts → interface/config.ts} +2 -0
  111. package/src/{datalake.ts → interface/datalake.ts} +2 -0
  112. package/src/{delivery.ts → interface/delivery.ts} +2 -0
  113. package/src/{dh.ts → interface/dh.ts} +2 -0
  114. package/src/interface/email.ts +30 -0
  115. package/src/{file.ts → interface/file.ts} +2 -0
  116. package/src/{kds.ts → interface/kds.ts} +4 -0
  117. package/src/{location.ts → interface/location.ts} +76 -35
  118. package/src/{logger.ts → interface/logger.ts} +2 -0
  119. package/src/{loyalty.ts → interface/loyalty.ts} +2 -0
  120. package/src/{mealplan.ts → interface/mealplan.ts} +2 -0
  121. package/src/interface/menu.ts +649 -0
  122. package/src/{message.ts → interface/message.ts} +2 -0
  123. package/src/{order.ts → interface/order.ts} +21 -6
  124. package/src/{partner.ts → interface/partner.ts} +291 -5
  125. package/src/{payment.ts → interface/payment.ts} +4 -0
  126. package/src/{promo.ts → interface/promo.ts} +3 -0
  127. package/src/{report.ts → interface/report.ts} +4 -0
  128. package/src/{schedule.ts → interface/schedule.ts} +2 -0
  129. package/src/{shoppingcart.ts → interface/shoppingcart.ts} +14 -1
  130. package/src/{task.ts → interface/task.ts} +2 -0
  131. package/src/{user.ts → interface/user.ts} +34 -1
  132. package/src/{vote.ts → interface/vote.ts} +2 -0
  133. package/template.ejs +3 -3
  134. package/test/client.test.ts +192 -0
  135. package/test/gen.test.ts +22 -0
  136. package/lib/announcement.d.ts.map +0 -1
  137. package/lib/announcement.js +0 -3
  138. package/lib/announcement.js.map +0 -1
  139. package/lib/brand.d.ts.map +0 -1
  140. package/lib/brand.js +0 -3
  141. package/lib/brand.js.map +0 -1
  142. package/lib/calendar.d.ts.map +0 -1
  143. package/lib/calendar.js +0 -3
  144. package/lib/calendar.js.map +0 -1
  145. package/lib/config.d.ts.map +0 -1
  146. package/lib/config.js +0 -3
  147. package/lib/config.js.map +0 -1
  148. package/lib/datalake.d.ts.map +0 -1
  149. package/lib/datalake.js +0 -3
  150. package/lib/datalake.js.map +0 -1
  151. package/lib/delivery.d.ts.map +0 -1
  152. package/lib/delivery.js +0 -3
  153. package/lib/delivery.js.map +0 -1
  154. package/lib/dh.d.ts.map +0 -1
  155. package/lib/dh.js +0 -3
  156. package/lib/dh.js.map +0 -1
  157. package/lib/email.d.ts +0 -5
  158. package/lib/email.d.ts.map +0 -1
  159. package/lib/email.js +0 -3
  160. package/lib/email.js.map +0 -1
  161. package/lib/file.d.ts.map +0 -1
  162. package/lib/file.js +0 -3
  163. package/lib/file.js.map +0 -1
  164. package/lib/kds.d.ts.map +0 -1
  165. package/lib/kds.js +0 -3
  166. package/lib/kds.js.map +0 -1
  167. package/lib/location.d.ts.map +0 -1
  168. package/lib/location.js +0 -3
  169. package/lib/location.js.map +0 -1
  170. package/lib/logger.d.ts.map +0 -1
  171. package/lib/logger.js +0 -3
  172. package/lib/logger.js.map +0 -1
  173. package/lib/loyalty.d.ts.map +0 -1
  174. package/lib/loyalty.js +0 -3
  175. package/lib/loyalty.js.map +0 -1
  176. package/lib/mealplan.d.ts.map +0 -1
  177. package/lib/mealplan.js +0 -3
  178. package/lib/mealplan.js.map +0 -1
  179. package/lib/message.d.ts.map +0 -1
  180. package/lib/message.js +0 -3
  181. package/lib/message.js.map +0 -1
  182. package/lib/order.d.ts.map +0 -1
  183. package/lib/order.js +0 -3
  184. package/lib/order.js.map +0 -1
  185. package/lib/partner.d.ts.map +0 -1
  186. package/lib/partner.js +0 -3
  187. package/lib/partner.js.map +0 -1
  188. package/lib/payment.d.ts.map +0 -1
  189. package/lib/payment.js +0 -3
  190. package/lib/payment.js.map +0 -1
  191. package/lib/promo.d.ts.map +0 -1
  192. package/lib/promo.js +0 -3
  193. package/lib/promo.js.map +0 -1
  194. package/lib/report.d.ts.map +0 -1
  195. package/lib/report.js +0 -3
  196. package/lib/report.js.map +0 -1
  197. package/lib/schedule.d.ts.map +0 -1
  198. package/lib/schedule.js +0 -3
  199. package/lib/schedule.js.map +0 -1
  200. package/lib/shoppingcart.d.ts.map +0 -1
  201. package/lib/shoppingcart.js +0 -3
  202. package/lib/shoppingcart.js.map +0 -1
  203. package/lib/task.d.ts.map +0 -1
  204. package/lib/task.js +0 -3
  205. package/lib/task.js.map +0 -1
  206. package/lib/user.d.ts.map +0 -1
  207. package/lib/user.js +0 -3
  208. package/lib/user.js.map +0 -1
  209. package/lib/vote.d.ts.map +0 -1
  210. package/lib/vote.js +0 -3
  211. package/lib/vote.js.map +0 -1
  212. package/src/email.ts +0 -4
  213. /package/lib/{announcement.d.ts → interface/announcement.d.ts} +0 -0
  214. /package/lib/{brand.d.ts → interface/brand.d.ts} +0 -0
  215. /package/lib/{config.d.ts → interface/config.d.ts} +0 -0
  216. /package/lib/{datalake.d.ts → interface/datalake.d.ts} +0 -0
  217. /package/lib/{delivery.d.ts → interface/delivery.d.ts} +0 -0
  218. /package/lib/{dh.d.ts → interface/dh.d.ts} +0 -0
  219. /package/lib/{file.d.ts → interface/file.d.ts} +0 -0
  220. /package/lib/{logger.d.ts → interface/logger.d.ts} +0 -0
  221. /package/lib/{loyalty.d.ts → interface/loyalty.d.ts} +0 -0
  222. /package/lib/{mealplan.d.ts → interface/mealplan.d.ts} +0 -0
  223. /package/lib/{message.d.ts → interface/message.d.ts} +0 -0
  224. /package/lib/{schedule.d.ts → interface/schedule.d.ts} +0 -0
  225. /package/lib/{task.d.ts → interface/task.d.ts} +0 -0
  226. /package/lib/{vote.d.ts → interface/vote.d.ts} +0 -0
package/README.md CHANGED
@@ -8,33 +8,146 @@ Compass Digital Labs TypeScript SDK
8
8
  $ npm install --save @compassdigital/sdk.typescript@latest
9
9
  ```
10
10
 
11
+ ## Example Server Usage
12
+
13
+ ``` typescript
14
+ import Provider from "@compassdigital/provider";
15
+ import { GetTaskRequest, GetTaskResponse } from "@compassdigital/sdk.typescript/interface/task";
16
+
17
+ const provider = new Provider({ type: "payment" });
18
+
19
+ provider.on<GetTaskRequest, GetTaskResponse>("get_task", function (req, next): void {
20
+ // ...
21
+ })
22
+ ```
23
+
11
24
  ## Example Client Usage
12
25
 
26
+ **Instanciate Client:**
27
+
13
28
  ``` typescript
14
29
  import { ServiceClient } from "@compassdigital/sdk.typescript";
15
30
 
16
31
  const api = new ServiceClient({ stage: "dev" });
32
+ ```
17
33
 
18
- async function main() {
19
- const task = await api.get_task(task_id);
34
+ **Basic Request:**
35
+
36
+ ``` typescript
37
+ const task = await api.get_task(id);
38
+ ```
39
+
40
+ **Request Options:**
41
+
42
+ * These options may be passed to any request.
43
+
44
+ ``` typescript
45
+ interface RequestOptions {
46
+ // environment to make requests to
47
+ stage?: string;
48
+ // authentication token
49
+ token?: string;
50
+ // additional headers
51
+ headers?: Record<string, string>;
52
+ // log all requests and responses
53
+ debug?: boolean;
54
+ // the number of times to retry a request
55
+ retry?: number;
56
+ // make requests against this base url
57
+ // note: the stage property is ignored if base_url is set
58
+ base_url?: string;
59
+ // intercept outgoing http requests
60
+ intercept?: InterceptFn;
20
61
  }
21
62
  ```
22
63
 
23
- ## Example Server Usage
64
+ * The `RequestOptions` can be provided to the `ServiceClient` constructor or at the request call site.
65
+ * The options provided at the call site will overide options passed to the constructor.
24
66
 
25
67
  ``` typescript
26
- import Provider from "@compassdigital/provider";
27
- import { GetTaskRequest, GetTaskResponse } from "@compassdigital/sdk.typescript/task";
28
68
 
29
- const provider = new Provider({ type: "payment" });
69
+ const api = new ServiceClient({
70
+ token: "<token>",
71
+ retry: 2,
72
+ })
30
73
 
31
- provider.on<GetTaskRequest, GetTaskResponse>("get_task", function (req, next): void {
32
- // ...
74
+ const location = await api.get_location(id, {
75
+ token: "<token>",
76
+ retry: 2,
33
77
  })
34
78
  ```
35
79
 
80
+ **Error Handling:**
81
+
82
+ * non-200 responses are rejected with a `ServiceError`.
83
+
84
+ ``` typescript
85
+ try {
86
+ const shoppingcart = await api.get_shoppingcart(id);
87
+ } catch (err) {
88
+ // Since the error type is `unknown` we must type assert before
89
+ // accessing the properties.
90
+ if (err instanceof ServiceError) {
91
+ console.log(err.status, err.code, err.message);
92
+ }
93
+
94
+ // There are helpers for accessing the status and code
95
+ if (ServiceError.code(err) === 400.31) {
96
+ console.log("Failed to get menu");
97
+ }
98
+ }
99
+ ```
100
+
101
+ * There is a `ignore` convenience method for ignoring specific status & error codes.
102
+
103
+ ``` typescript
104
+ const issue: OrderIssue = { items: [] };
105
+ await api.post_order_issue(id, issue).ignore(400.18, 400.21);
106
+ ```
107
+
108
+ * There is a `combine` convenience method for returning an object which contains the response or error.
109
+
110
+ ``` typescript
111
+ const res = await api.get_task(id).combine();
112
+
113
+ if (res.ok) {
114
+ console.log("task", res.data);
115
+ } else {
116
+ console.log("error", res.err);
117
+ }
118
+ ```
119
+
120
+ **Testing:**
121
+
122
+ * You can register an `intercept` function which will recieve all request.
123
+
124
+ ``` typescript
125
+
126
+ import {
127
+ ServiceClient,
128
+ RequestData,
129
+ ResponseData,
130
+ FetchFn,
131
+ } from "@compassdigital/sdk.typescript";
132
+
133
+ async function intercept(req: RequestData, fetch: FetchFn): Promise<ResponseData> {
134
+ expect(req.name).toBe("get_shoppingcart");
135
+ return { ok: true, status: 200, body: JSON.stringify({}) }
136
+ }
137
+
138
+ const api = new ServiceClient({ intercept });
139
+ ```
140
+
36
141
  ## Code Gen
37
142
 
38
143
  1. Add new services to `manifest.json`.
39
144
  2. Run `npm run gen`.
40
145
 
146
+ ## Ad-Hoc Code Gen
147
+
148
+ If you need types for a service you're working on and the sdk hasn't been updated yet, then
149
+ you can generate local types from your swagger.
150
+
151
+ ```
152
+ $ sdk.typescript --swagger ./swagger.json --service my_service > types/my_service.d.ts
153
+ ```
package/bin/gen.js ADDED
@@ -0,0 +1,484 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
+ if (ar || !(i in from)) {
41
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
+ ar[i] = from[i];
43
+ }
44
+ }
45
+ return to.concat(ar || Array.prototype.slice.call(from));
46
+ };
47
+ var __importDefault = (this && this.__importDefault) || function (mod) {
48
+ return (mod && mod.__esModule) ? mod : { "default": mod };
49
+ };
50
+ exports.__esModule = true;
51
+ exports.CodeGenerator = void 0;
52
+ var fs_1 = __importDefault(require("fs"));
53
+ var openapi_ts_1 = require("@icholy/openapi-ts");
54
+ var prettier_1 = __importDefault(require("prettier"));
55
+ var path_1 = __importDefault(require("path"));
56
+ var ejs_1 = __importDefault(require("ejs"));
57
+ var yargs_1 = __importDefault(require("yargs/yargs"));
58
+ var helpers_1 = require("yargs/helpers");
59
+ /**
60
+ * This is a mapping between "${method} ${path}" and the default
61
+ * operationId.
62
+ */
63
+ var operationIDs = {
64
+ "get /location/group/{id}/deliverydestination": "get_location_group_deliverydestinations",
65
+ "get /location/search": "get_location_search",
66
+ "get /promo": "get_promos",
67
+ "get /schedule": "get_schedules",
68
+ "get /brand": "get_brands",
69
+ "get /announcement/resource": "get_resources",
70
+ "get /order/location/brand/{id}": "get_order_location_brand"
71
+ };
72
+ var CodeGenerator = /** @class */ (function () {
73
+ function CodeGenerator() {
74
+ this.imports = [];
75
+ this.methods = [];
76
+ }
77
+ CodeGenerator.prototype.manifest = function (manifest) {
78
+ return __awaiter(this, void 0, void 0, function () {
79
+ var _i, _a, service, code_1, filename_1, code, filename;
80
+ return __generator(this, function (_b) {
81
+ switch (_b.label) {
82
+ case 0:
83
+ // generate service types
84
+ return [4 /*yield*/, fs_1["default"].promises.mkdir(path_1["default"].join("src", "interface"), { recursive: true })];
85
+ case 1:
86
+ // generate service types
87
+ _b.sent();
88
+ _i = 0, _a = manifest.services;
89
+ _b.label = 2;
90
+ case 2:
91
+ if (!(_i < _a.length)) return [3 /*break*/, 6];
92
+ service = _a[_i];
93
+ console.log("reading: " + service.swagger);
94
+ return [4 /*yield*/, this.service(service, false)];
95
+ case 3:
96
+ code_1 = _b.sent();
97
+ filename_1 = path_1["default"].join("src", "interface", service.name + ".ts");
98
+ return [4 /*yield*/, fs_1["default"].promises.writeFile(filename_1, code_1)];
99
+ case 4:
100
+ _b.sent();
101
+ _b.label = 5;
102
+ case 5:
103
+ _i++;
104
+ return [3 /*break*/, 2];
105
+ case 6: return [4 /*yield*/, this.client()];
106
+ case 7:
107
+ code = _b.sent();
108
+ filename = path_1["default"].join("src", "index.ts");
109
+ return [4 /*yield*/, fs_1["default"].promises.writeFile(filename, code)];
110
+ case 8:
111
+ _b.sent();
112
+ return [2 /*return*/];
113
+ }
114
+ });
115
+ });
116
+ };
117
+ CodeGenerator.prototype.client = function () {
118
+ var _a;
119
+ var _b;
120
+ return __awaiter(this, void 0, void 0, function () {
121
+ var print, imports, _i, _c, _import, _d, _e, _f, path_2, names, template;
122
+ return __generator(this, function (_g) {
123
+ print = new openapi_ts_1.Printer();
124
+ // "do not modify" warning
125
+ print.comment("THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY");
126
+ print.blank();
127
+ imports = {};
128
+ for (_i = 0, _c = this.imports; _i < _c.length; _i++) {
129
+ _import = _c[_i];
130
+ (_a = imports[_b = _import.path]) !== null && _a !== void 0 ? _a : (imports[_b] = []);
131
+ imports[_import.path].push(_import.name);
132
+ }
133
+ for (_d = 0, _e = Object.entries(imports); _d < _e.length; _d++) {
134
+ _f = _e[_d], path_2 = _f[0], names = _f[1];
135
+ print["import"](path_2, names);
136
+ print.blank();
137
+ }
138
+ template = fs_1["default"].readFileSync("template.ejs", "utf-8");
139
+ print.raw(ejs_1["default"].render(template, { methods: this.methods }));
140
+ return [2 /*return*/, prettier_1["default"].format(print.code(), { parser: "typescript", printWidth: 100 })];
141
+ });
142
+ });
143
+ };
144
+ CodeGenerator.prototype.service = function (service, ambient) {
145
+ return __awaiter(this, void 0, void 0, function () {
146
+ var print, doc, details;
147
+ return __generator(this, function (_a) {
148
+ switch (_a.label) {
149
+ case 0:
150
+ print = new openapi_ts_1.Printer();
151
+ return [4 /*yield*/, (0, openapi_ts_1.load)(service.swagger)];
152
+ case 1:
153
+ doc = _a.sent();
154
+ details = (0, openapi_ts_1.analyse)(doc);
155
+ this.transform(details, print, service, ambient);
156
+ return [2 /*return*/, prettier_1["default"].format(print.code(), { parser: "typescript", printWidth: 100 })];
157
+ }
158
+ });
159
+ });
160
+ };
161
+ /**
162
+ * Add an import that the client will need.
163
+ */
164
+ CodeGenerator.prototype.addImport = function (service, name) {
165
+ this.imports.push({
166
+ name: name,
167
+ path: "./interface/" + service.name
168
+ });
169
+ };
170
+ /**
171
+ * Generate typescript code from the document details.
172
+ */
173
+ CodeGenerator.prototype.transform = function (doc, print, service, ambient) {
174
+ // "do not modify" warning
175
+ print.comment("THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY");
176
+ print.blank();
177
+ // declaration if it's ambient
178
+ if (ambient) {
179
+ print.raw("declare module \"@compassdigital/sdk.typescript/interface/" + service.name + "\" {");
180
+ }
181
+ // definitions
182
+ for (var _i = 0, _a = Object.entries(doc.definitions); _i < _a.length; _i++) {
183
+ var _b = _a[_i], name_1 = _b[0], schema = _b[1];
184
+ print.schema(schema, name_1);
185
+ print.blank();
186
+ }
187
+ // routes
188
+ for (var _c = 0, _d = doc.operations; _c < _d.length; _c++) {
189
+ var op = _d[_c];
190
+ var params = op.params, path_3 = op.path;
191
+ for (var _e = 0, _f = params.skipped; _e < _f.length; _e++) {
192
+ var skipped = _f[_e];
193
+ console.warn("SKIPPED", skipped);
194
+ }
195
+ // add missing path parameters
196
+ for (var _g = 0, _h = this.findPathParams(path_3); _g < _h.length; _g++) {
197
+ var name_2 = _h[_g];
198
+ if (!params.path.properties[name_2]) {
199
+ params.path.setProperty(name_2, new openapi_ts_1.Schema("string", {
200
+ required: true,
201
+ description: "TODO: add parameter to swagger.json"
202
+ }));
203
+ }
204
+ }
205
+ // make all path parameters required and valid path types.
206
+ for (var _j = 0, _k = Object.values(params.path.properties); _j < _k.length; _j++) {
207
+ var param = _k[_j];
208
+ if (!param.required) {
209
+ param.required = true;
210
+ if (param.description) {
211
+ param.description += "; ";
212
+ }
213
+ param.description += "TODO: mark parameter as required in swagger";
214
+ }
215
+ if (param.isRef() || param.type === "object") {
216
+ if (param.description) {
217
+ param.description += "; ";
218
+ }
219
+ param.description += "TODO: cannot use " + param.type + " as path parameter";
220
+ param.type = "string";
221
+ }
222
+ }
223
+ // add nocache query parameter if x-cache-control is specified
224
+ if (this.hasCacheControl(op) && !params.query.properties["nocache"]) {
225
+ params.query.setProperty("nocache", new openapi_ts_1.Schema("boolean"));
226
+ }
227
+ var name_3 = this.inferName(op, service);
228
+ var comment = op.method.toUpperCase() + " " + path_3;
229
+ if (op.obj.summary) {
230
+ comment += " - " + op.obj.summary;
231
+ }
232
+ print.comment(comment);
233
+ print.blank();
234
+ // path parameters
235
+ if (!params.path.isEmpty()) {
236
+ var pathT = name_3.pascal + "Path";
237
+ print.schema(params.path, pathT);
238
+ print.blank();
239
+ }
240
+ // query parameters
241
+ var queryT = name_3.pascal + "Query";
242
+ if (!params.query.isEmpty()) {
243
+ this.addImport(service, queryT);
244
+ print.schema(params.query, queryT);
245
+ print.blank();
246
+ }
247
+ // body
248
+ var bodyT = name_3.pascal + "Body";
249
+ if (!params.body.isEmpty()) {
250
+ this.addImport(service, bodyT);
251
+ print.schema(params.body, bodyT);
252
+ print.blank();
253
+ }
254
+ // response
255
+ var responseT = name_3.pascal + "Response";
256
+ this.addImport(service, responseT);
257
+ print.schema(params.response, responseT);
258
+ print.blank();
259
+ // server request
260
+ var requestT = name_3.pascal + "Request";
261
+ print.schema(this.toRequestSchema(name_3, op), requestT);
262
+ print.blank();
263
+ // method parameters
264
+ var method = {
265
+ comment: comment,
266
+ name: name_3.snake,
267
+ params: [],
268
+ args: ["\"" + service.name + "\"", "\"" + name_3.snake + "\"", "\"" + op.method + "\""],
269
+ response: responseT
270
+ };
271
+ // turn the path into a template string and add the
272
+ // corresponding method parameters.
273
+ var pathexpr = "`" + path_3 + "`";
274
+ for (var _l = 0, _m = this.findPathParams(path_3); _l < _m.length; _l++) {
275
+ var name_4 = _m[_l];
276
+ var schema = params.path.properties[name_4];
277
+ method.params.push({
278
+ name: name_4,
279
+ type: openapi_ts_1.Printer.type(schema),
280
+ required: true,
281
+ description: schema.description
282
+ });
283
+ pathexpr = pathexpr.replace("{" + name_4 + "}", "${" + name_4 + "}");
284
+ }
285
+ method.args.push(pathexpr);
286
+ // if there's a body, make that a parameter too.
287
+ if (!params.body.isEmpty()) {
288
+ method.params.push({
289
+ name: "body",
290
+ type: bodyT,
291
+ required: true,
292
+ description: params.body.description
293
+ });
294
+ method.args.push("body");
295
+ }
296
+ else {
297
+ method.args.push("null");
298
+ }
299
+ // build the options type.
300
+ var options = new openapi_ts_1.Schema("empty");
301
+ if (!params.query.isEmpty()) {
302
+ var query = new openapi_ts_1.Schema(queryT);
303
+ if (params.query.hasRequired()) {
304
+ query.required = true;
305
+ options.required = true;
306
+ }
307
+ options.setProperty("query", query);
308
+ }
309
+ options.merge(new openapi_ts_1.Schema("RequestOptions"));
310
+ method.params.push({
311
+ name: "options",
312
+ type: openapi_ts_1.Printer.type(options),
313
+ required: options.required,
314
+ description: "additional request options"
315
+ });
316
+ method.args.push("options");
317
+ this.methods.push(method);
318
+ }
319
+ // close declaration
320
+ if (ambient) {
321
+ print.raw("}");
322
+ }
323
+ };
324
+ /**
325
+ * Infer the operation name from the method and parameter.
326
+ * These are a bunch of dirty hacks to make the generated names consistent.
327
+ */
328
+ CodeGenerator.prototype.inferName = function (op, service) {
329
+ var method = op.method, path = op.path;
330
+ var path_segments = [];
331
+ // use the operationId from our collection if we have one.
332
+ // TODO: update the swagger.json definitions so we don't need to do this.
333
+ var operationID = operationIDs[op.method + " " + op.path];
334
+ if (!operationID) {
335
+ operationID = op.obj.operationId;
336
+ }
337
+ if (operationID) {
338
+ var parts_1 = operationID.split("_");
339
+ if (parts_1.length > 1) {
340
+ // replace common operationId values with the canonical ones.
341
+ if (parts_1[0] === "create") {
342
+ parts_1[0] = "post";
343
+ }
344
+ if (parts_1[0] === "update") {
345
+ parts_1[0] = "put";
346
+ }
347
+ if (parts_1[0] === "remove") {
348
+ parts_1[0] = "delete";
349
+ }
350
+ if (parts_1[0] === "find") {
351
+ parts_1[0] = "get";
352
+ }
353
+ if (!(0, openapi_ts_1.isMethod)(parts_1[0])) {
354
+ parts_1.unshift(method);
355
+ }
356
+ if (parts_1[0] === method) {
357
+ parts_1.shift(); // remove the method
358
+ if (!parts_1[0].startsWith(service.name)) {
359
+ parts_1.unshift(service.name);
360
+ }
361
+ path_segments = parts_1;
362
+ }
363
+ }
364
+ if (parts_1.length > 1 && parts_1[0] === method) {
365
+ parts_1.shift(); // remove the method
366
+ if (!parts_1[0].startsWith(service.name)) {
367
+ parts_1.unshift(service.name);
368
+ }
369
+ path_segments = parts_1;
370
+ }
371
+ }
372
+ // combined the path & method into a name.
373
+ if (path_segments.length === 0) {
374
+ if (path.endsWith(".json")) {
375
+ path = path.slice(0, -5);
376
+ }
377
+ path_segments = path.split("/").filter(function (segment) {
378
+ return segment != "" && !segment.includes("{");
379
+ });
380
+ }
381
+ var parts = __spreadArray([method.toLowerCase()], path_segments, true);
382
+ return {
383
+ snake: parts.join("_"),
384
+ pascal: parts.map(function (s) { return s.charAt(0).toUpperCase() + s.substr(1); }).join('')
385
+ };
386
+ };
387
+ /**
388
+ * Check if the any response has caching enabled.
389
+ */
390
+ CodeGenerator.prototype.hasCacheControl = function (op) {
391
+ var _a;
392
+ var responses = Object.values((_a = op.obj.responses) !== null && _a !== void 0 ? _a : {});
393
+ return responses.some(function (response) { return "x-cache-control" in response; });
394
+ };
395
+ /**
396
+ * Find all the path parameter names.
397
+ */
398
+ CodeGenerator.prototype.findPathParams = function (path) {
399
+ var matches = path.matchAll(/{[^}]*}/g);
400
+ return Array.from(matches).map(function (match) {
401
+ return match[0].slice(1, -1);
402
+ });
403
+ };
404
+ /**
405
+ * Create a Response type by combining the Query, Path, and Body types.
406
+ */
407
+ CodeGenerator.prototype.toRequestSchema = function (name, details) {
408
+ var request = new openapi_ts_1.Schema("empty");
409
+ if (!details.params.body.isEmpty()) {
410
+ var body = new openapi_ts_1.Schema(name.pascal + "Body");
411
+ body.required = true;
412
+ request.setProperty("body", body);
413
+ }
414
+ if (!details.params.query.isEmpty()) {
415
+ request.merge(new openapi_ts_1.Schema(name.pascal + "Query"));
416
+ }
417
+ if (!details.params.path.isEmpty()) {
418
+ request.merge(new openapi_ts_1.Schema(name.pascal + "Path"));
419
+ }
420
+ return request;
421
+ };
422
+ return CodeGenerator;
423
+ }());
424
+ exports.CodeGenerator = CodeGenerator;
425
+ /**
426
+ * Main entry point.
427
+ */
428
+ function main() {
429
+ return __awaiter(this, void 0, void 0, function () {
430
+ var argv, data, manifest, gen, gen, code;
431
+ return __generator(this, function (_a) {
432
+ switch (_a.label) {
433
+ case 0:
434
+ argv = (0, yargs_1["default"])((0, helpers_1.hideBin)(process.argv))
435
+ .options("manifest", {
436
+ type: "string",
437
+ description: "manifest.json file to generate sdk from"
438
+ })
439
+ .options("swagger", {
440
+ type: "string",
441
+ description: "swagger.json file to generate interfaces from"
442
+ })
443
+ .options("service", {
444
+ type: "string",
445
+ description: "service name for generated interfaces"
446
+ })
447
+ .options("ambient", {
448
+ type: "boolean",
449
+ description: "wrap the types in a declare module directive",
450
+ "default": true
451
+ }).argv;
452
+ if (!argv.manifest) return [3 /*break*/, 3];
453
+ return [4 /*yield*/, fs_1["default"].promises.readFile(argv.manifest, "utf-8")];
454
+ case 1:
455
+ data = _a.sent();
456
+ manifest = JSON.parse(data);
457
+ gen = new CodeGenerator();
458
+ return [4 /*yield*/, gen.manifest(manifest)];
459
+ case 2:
460
+ _a.sent();
461
+ return [2 /*return*/];
462
+ case 3:
463
+ if (!(argv.swagger || argv.service)) return [3 /*break*/, 5];
464
+ if (!argv.swagger) {
465
+ throw new Error("--swagger must be provided with --service");
466
+ }
467
+ if (!argv.service) {
468
+ throw new Error("--service must be provided with --swagger");
469
+ }
470
+ gen = new CodeGenerator();
471
+ return [4 /*yield*/, gen.service({
472
+ name: argv.service,
473
+ swagger: argv.swagger
474
+ }, argv.ambient)];
475
+ case 4:
476
+ code = _a.sent();
477
+ console.log(code);
478
+ return [2 /*return*/];
479
+ case 5: return [2 /*return*/];
480
+ }
481
+ });
482
+ });
483
+ }
484
+ main()["catch"](function (err) { return console.error(err.message); });
package/bin/index.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require("./gen");