swaggie 2.1.4 → 2.2.0

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 CHANGED
@@ -543,4 +543,5 @@ function error(e) {
543
543
  <a href="https://www.britishcouncil.org"><img alt="British Council" src="./docs/public/used-in/bc-logo.png" /></a>
544
544
  <a href="https://kpmg.com/"><img alt="KPMG" src="./docs/public/used-in/kpmg-logo.png" /></a>
545
545
  <a href="https://klarna.com/"><img alt="Klarna" src="./docs/public/used-in/klarna-logo.png" /></a>
546
+ <a href="https://cribl.io/"><img alt="Cribl" src="./docs/public/used-in/cribl-logo.png" /></a>
546
547
  </div>
package/dist/cli.js CHANGED
@@ -131,12 +131,18 @@ const options = program.opts();
131
131
 
132
132
  _index.runCodeGenerator.call(void 0, options ).then(complete, error);
133
133
 
134
- function complete([code, opts]) {
135
- if (opts.out) {
136
- const from = typeof opts.src === 'string' ? `from ${_picocolors.bold.call(void 0, opts.src)} ` : '';
137
- console.info(_picocolors.cyan.call(void 0, `Api ${from}code generated into ${_picocolors.bold.call(void 0, opts.out)}`));
138
- } else {
139
- console.log(code);
134
+ function complete(result) {
135
+ const results = Array.isArray(result[0])
136
+ ? (result )
137
+ : [result ];
138
+
139
+ for (const [code, opts] of results) {
140
+ if (opts.out) {
141
+ const from = typeof opts.src === 'string' ? `from ${_picocolors.bold.call(void 0, opts.src)} ` : '';
142
+ console.info(_picocolors.cyan.call(void 0, `Api ${from}code generated into ${_picocolors.bold.call(void 0, opts.out)}`));
143
+ } else {
144
+ console.log(code);
145
+ }
140
146
  }
141
147
 
142
148
  process.exit(0);
package/dist/index.js CHANGED
@@ -3,23 +3,47 @@
3
3
 
4
4
  var _gen = require('./gen'); var _gen2 = _interopRequireDefault(_gen);
5
5
 
6
+
7
+
8
+
9
+
10
+
11
+
12
+
6
13
  var _utils = require('./utils');
7
14
  var _templateValidator = require('./utils/templateValidator');
8
15
  var _swagger = require('./swagger');
9
16
 
10
17
  /**
11
18
  * Runs the whole code generation process.
12
- * @returns `CodeGenResult`
19
+ * When the config file contains an array of configs, returns `BatchCodeGenResult`
20
+ * (an array of results, one per entry, fail-fast on first error).
21
+ * Otherwise returns a single `CodeGenResult`.
13
22
  **/
14
- async function runCodeGenerator(options) {
23
+ async function runCodeGenerator(
24
+ options
25
+ ) {
15
26
  try {
16
27
  verifyOptions(options);
17
- const opts = await applyConfigFile(options);
18
- const spec = await _utils.loadSpecDocument.call(void 0, opts.src);
28
+ const optsOrArray = await applyConfigFile(options);
29
+
30
+ if (Array.isArray(optsOrArray)) {
31
+ const results = [];
32
+ for (const opts of optsOrArray) {
33
+ verifyEntryOptions(opts);
34
+ const spec = await _utils.loadSpecDocument.call(void 0, opts.src);
35
+ const verifiedSpec = _utils.verifyDocumentSpec.call(void 0, spec);
36
+ const code = await gen(verifiedSpec, opts);
37
+ results.push([code, opts]);
38
+ }
39
+ return results;
40
+ }
41
+
42
+ const spec = await _utils.loadSpecDocument.call(void 0, optsOrArray.src);
19
43
  const verifiedSpec = _utils.verifyDocumentSpec.call(void 0, spec);
20
- const code = await gen(verifiedSpec, opts);
44
+ const code = await gen(verifiedSpec, optsOrArray);
21
45
 
22
- return [code, opts];
46
+ return [code, optsOrArray];
23
47
  } catch (e) {
24
48
  return Promise.reject(e);
25
49
  }
@@ -64,6 +88,82 @@ function verifyOptions(options) {
64
88
  }
65
89
  }
66
90
 
91
+ /**
92
+ * Validates options that apply to each individual entry in an array config.
93
+ * Covers the same constraints as `verifyOptions` but scoped to a single
94
+ * fully-resolved `AppOptions` entry (after config merging and defaults).
95
+ */
96
+ function verifyEntryOptions(opts) {
97
+ if (!opts.src) {
98
+ throw new Error('Each config entry must have "src" set');
99
+ }
100
+ if (!!opts.mocks !== !!opts.testingFramework) {
101
+ throw new Error('--mocks and --testingFramework must be used together');
102
+ }
103
+ if (opts.mocks && !opts.out) {
104
+ throw new Error(
105
+ '"mocks" requires "out" to be set, since the mock file needs to import the generated client'
106
+ );
107
+ }
108
+ if (opts.hooksOut && !opts.out) {
109
+ throw new Error('"hooksOut" requires "out" to be set');
110
+ }
111
+ if (opts.clientSetup && !opts.out) {
112
+ throw new Error('"clientSetup" requires "out" to be set');
113
+ }
114
+ if (opts.forceSetup && !opts.clientSetup) {
115
+ throw new Error('"forceSetup" requires "clientSetup" to be set');
116
+ }
117
+ if (opts.hooksOut) {
118
+ const tpl = opts.template;
119
+ const isL2 =
120
+ (typeof tpl === 'string' && _templateValidator.isL2Template.call(void 0, tpl)) ||
121
+ (Array.isArray(tpl) && typeof tpl[0] === 'string' && _templateValidator.isL2Template.call(void 0, tpl[0]));
122
+ if (!isL2) {
123
+ throw new Error(
124
+ '"hooksOut" requires an L2 template (swr, tsq). ' +
125
+ 'Reactive hooks are only generated for L2 template pairs.'
126
+ );
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Throws if any per-entry-only keys are present as top-level defaults in a
133
+ * multi-config file. These keys must live inside each entry under "configs".
134
+ */
135
+ function verifyTopLevelDefaults(configUrl, defaults) {
136
+ const blocked = ['src', 'out', 'hooksOut', 'mocks', 'clientSetup'];
137
+ for (const key of blocked) {
138
+ if (key in defaults) {
139
+ throw new Error(
140
+ `"${key}" cannot be a top-level default in multi-config file "${configUrl}". ` +
141
+ `Set it inside each entry under "configs" instead.`
142
+ );
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Throws if any file-path CLI flags are combined with a multi-config file.
149
+ * Each entry in "configs" must define its own output paths.
150
+ */
151
+ function verifyOptionsForArrayConfig(options) {
152
+ const blocked = [
153
+ ['out', '--out'],
154
+ ['hooksOut', '--hooksOut'],
155
+ ['mocks', '--mocks'],
156
+ ['clientSetup', '--clientSetup'],
157
+ ];
158
+ for (const [key, flag] of blocked) {
159
+ if (options[key]) {
160
+ throw new Error(
161
+ `${flag} cannot be used with a multi-config file. Set "${key}" in each entry under "configs" instead.`
162
+ );
163
+ }
164
+ }
165
+ }
166
+
67
167
  function gen(spec, options) {
68
168
  if (options.generationMode === 'full') {
69
169
  _templateValidator.validateTemplate.call(void 0, options.template);
@@ -76,25 +176,49 @@ function gen(spec, options) {
76
176
  async function applyConfigFile(
77
177
  options
78
178
  ) {
179
+ if (!options.config) {
180
+ return prepareAppOptions(options );
181
+ }
182
+
183
+ const configUrl = options.config;
184
+ let configContents;
185
+ let parsedConfig;
186
+
79
187
  try {
80
- if (!options.config) {
81
- return prepareAppOptions(options );
82
- }
188
+ configContents = await readFile(configUrl);
189
+ parsedConfig = JSON.parse(configContents);
190
+ } catch (_e) {
191
+ return Promise.reject(
192
+ new Error('Could not correctly load config file. It does not exist or you cannot access it')
193
+ );
194
+ }
83
195
 
84
- const configUrl = options.config;
85
- const configContents = await readFile(configUrl);
86
- const parsedConfig = JSON.parse(configContents);
87
- if (!parsedConfig || parsedConfig.length < 1) {
88
- throw new Error(
89
- `Could not correctly parse config file from "${configUrl}". Is it a valid JSON file?`
90
- );
91
- }
92
- return prepareAppOptions({ ...parsedConfig, ...options });
93
- } catch (e) {
196
+ if (!parsedConfig || typeof parsedConfig !== 'object') {
94
197
  return Promise.reject(
95
198
  new Error('Could not correctly load config file. It does not exist or you cannot access it')
96
199
  );
97
200
  }
201
+
202
+ if ('configs' in (parsedConfig )) {
203
+ const { configs: entries, ...topLevelDefaults } = parsedConfig
204
+
205
+
206
+ ;
207
+ if (!Array.isArray(entries) || entries.length < 1) {
208
+ return Promise.reject(
209
+ new Error(
210
+ `Config file "${configUrl}" has a "configs" key but it is not a non-empty array. Provide at least one config entry.`
211
+ )
212
+ );
213
+ }
214
+ verifyTopLevelDefaults(configUrl, topLevelDefaults);
215
+ verifyOptionsForArrayConfig(options);
216
+ return entries.map((entry) =>
217
+ prepareAppOptions({ ...topLevelDefaults, ...entry, ...options })
218
+ );
219
+ }
220
+
221
+ return prepareAppOptions({ ...parsedConfig, ...options } );
98
222
  } exports.applyConfigFile = applyConfigFile;
99
223
 
100
224
  function readFile(filePath) {
@@ -103,7 +227,7 @@ function readFile(filePath) {
103
227
  });
104
228
  }
105
229
 
106
-
230
+ ;
107
231
 
108
232
  /**
109
233
  * CLI options are flat, but within the app we use nested objects.
package/dist/types.d.ts CHANGED
@@ -171,6 +171,11 @@ export interface AppOptions extends ClientOptions {
171
171
  mocks?: string;
172
172
  testingFramework?: TestingFramework;
173
173
  }
174
+ export type CodeGenResult = [string, AppOptions];
175
+ /**
176
+ * Result of a batch run — one entry per config in the array.
177
+ */
178
+ export type BatchCodeGenResult = CodeGenResult[];
174
179
  /**
175
180
  * Local type that represent Operation as understood by Swaggie
176
181
  **/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swaggie",
3
- "version": "2.1.4",
3
+ "version": "2.2.0",
4
4
  "description": "Generate a fully typed TypeScript API client from your OpenAPI 3 spec",
5
5
  "author": {
6
6
  "name": "Piotr Dabrowski",