swaggie 2.2.1 → 2.3.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 +15 -0
- package/dist/gen/genMocks.js +14 -18
- package/dist/gen/genOperations.js +34 -5
- package/dist/index.js +39 -0
- package/dist/types.d.ts +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -396,6 +396,21 @@ Sometimes an API spec marks a parameter as required, but your client handles it
|
|
|
396
396
|
- `"optional"` — the parameter becomes optional regardless of what the spec says
|
|
397
397
|
- `"required"` — the parameter is always required (generally better to just fix the spec)
|
|
398
398
|
|
|
399
|
+
### Excluding Operations
|
|
400
|
+
|
|
401
|
+
Use `exclude` to drop entire operations from the generated output by tag or `operationId` — without modifying the spec. Types used exclusively by excluded operations are pruned automatically. Both fields support `*` and `?` wildcards.
|
|
402
|
+
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"exclude": {
|
|
406
|
+
"tags": ["admin", "internal"],
|
|
407
|
+
"operationIds": ["deleteAccount", "admin*"]
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
See the [full documentation](https://yhnavein.github.io/swaggie/guide/advanced#excluding-operations) for details and examples.
|
|
413
|
+
|
|
399
414
|
### Code Quality
|
|
400
415
|
|
|
401
416
|
Swaggie's output is functional but not always perfectly formatted, since it uses a templating engine internally. It is strongly recommended to run the output through a formatter to ensure consistent style across regenerations.
|
package/dist/gen/genMocks.js
CHANGED
|
@@ -48,10 +48,7 @@ const MOCK_FILE_HEADER = `\
|
|
|
48
48
|
const template = options.template;
|
|
49
49
|
|
|
50
50
|
if (template === 'ng1') {
|
|
51
|
-
throw new Error(
|
|
52
|
-
'Mock generation is not supported for the "ng1" template. ' +
|
|
53
|
-
'Use "ng2", "axios", "fetch", "xior", "swr", or "tsq" instead.'
|
|
54
|
-
);
|
|
51
|
+
throw new Error('Mock generation is not supported for the "ng1" template');
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
const isNg2 = template === 'ng2';
|
|
@@ -254,28 +251,34 @@ interface MockSWRReturn {
|
|
|
254
251
|
data: unknown;
|
|
255
252
|
/** Whether to return a loading state (default: false) */
|
|
256
253
|
isLoading?: boolean;
|
|
254
|
+
/** Whether to return a validating state (default: false) */
|
|
255
|
+
isValidating?: boolean;
|
|
257
256
|
/** Whether to return an error (default: undefined) */
|
|
258
257
|
error?: Error | undefined | null;
|
|
258
|
+
/** The mutate function to return (default: empty mock) */
|
|
259
|
+
mutate?: KeyedMutator<any>;
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
interface MockSWRMutationReturn {
|
|
262
263
|
/** The data to return from the mock */
|
|
263
|
-
data
|
|
264
|
+
data?: unknown;
|
|
264
265
|
/** Whether to return a mutating state (default: false) */
|
|
265
266
|
isMutating?: boolean;
|
|
266
267
|
/** Whether to return an error (default: undefined) */
|
|
267
268
|
error?: Error | undefined | null;
|
|
269
|
+
/** The trigger function to return (default: empty mock) */
|
|
270
|
+
trigger?: (...args: unknown[]) => Promise<unknown>;
|
|
271
|
+
/** The reset function to return (default: empty mock) */
|
|
272
|
+
reset?: () => void;
|
|
268
273
|
}
|
|
269
274
|
|
|
270
275
|
/** Augments a spy with a \`mockSWR\` shorthand for useSWR query hooks. */
|
|
271
276
|
function withMockSWR<Fn extends (...args: never[]) => unknown>(spy: ${ref}.SpiedFunction<Fn>) {
|
|
272
277
|
return Object.assign(spy, {
|
|
273
|
-
mockSWR({
|
|
278
|
+
mockSWR({ ...rest }: MockSWRReturn) {
|
|
274
279
|
spy.mockReturnValue({
|
|
275
280
|
...defaultSWRReturn,
|
|
276
|
-
|
|
277
|
-
isLoading: isLoading ?? false,
|
|
278
|
-
error: error ?? undefined,
|
|
281
|
+
...rest,
|
|
279
282
|
} as ReturnType<Fn>);
|
|
280
283
|
},
|
|
281
284
|
});
|
|
@@ -284,17 +287,10 @@ function withMockSWR<Fn extends (...args: never[]) => unknown>(spy: ${ref}.Spied
|
|
|
284
287
|
/** Augments a spy with a \`mockSWRMutation\` shorthand for useSWRMutation hooks. */
|
|
285
288
|
function withMockSWRMutation<Fn extends (...args: never[]) => unknown>(spy: ${ref}.SpiedFunction<Fn>) {
|
|
286
289
|
return Object.assign(spy, {
|
|
287
|
-
mockSWRMutation({
|
|
288
|
-
data,
|
|
289
|
-
isMutating,
|
|
290
|
-
error,
|
|
291
|
-
}: MockSWRMutationReturn) {
|
|
290
|
+
mockSWRMutation({ ...rest }: MockSWRMutationReturn) {
|
|
292
291
|
spy.mockReturnValue({
|
|
293
292
|
...defaultSWRMutationReturn,
|
|
294
|
-
|
|
295
|
-
isMutating: isMutating ?? false,
|
|
296
|
-
error: error ?? undefined,
|
|
297
|
-
data,
|
|
293
|
+
...rest,
|
|
298
294
|
} as ReturnType<Fn>);
|
|
299
295
|
},
|
|
300
296
|
});
|
|
@@ -255,6 +255,18 @@ function prepareClient(
|
|
|
255
255
|
ops = ops.filter((op) => !op.deprecated);
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
if (_optionalChain([options, 'access', _2 => _2.exclude, 'optionalAccess', _3 => _3.tags, 'optionalAccess', _4 => _4.length])) {
|
|
259
|
+
ops = ops.filter(
|
|
260
|
+
(op) => !_optionalChain([op, 'access', _5 => _5.tags, 'optionalAccess', _6 => _6.some, 'call', _7 => _7((t) => options.exclude.tags.some((p) => matchesPattern(t, p)))])
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (_optionalChain([options, 'access', _8 => _8.exclude, 'optionalAccess', _9 => _9.operationIds, 'optionalAccess', _10 => _10.length])) {
|
|
265
|
+
ops = ops.filter(
|
|
266
|
+
(op) => !options.exclude.operationIds.some((p) => matchesPattern(_nullishCoalesce(op.operationId, () => ( '')), p))
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
258
270
|
return ops.map((op) => {
|
|
259
271
|
const operationContext = `${op.method.toUpperCase()} ${op.path} (${op.operationId || 'unknown operationId'})`;
|
|
260
272
|
|
|
@@ -295,9 +307,9 @@ function prepareClient(
|
|
|
295
307
|
|
|
296
308
|
const headers = getParams(op.parameters , options, ['header']);
|
|
297
309
|
// Some libraries need explicit Content-Type for request bodies.
|
|
298
|
-
if (_optionalChain([body, 'optionalAccess',
|
|
310
|
+
if (_optionalChain([body, 'optionalAccess', _11 => _11.contentType]) === 'urlencoded') {
|
|
299
311
|
upsertFixedHeader(headers, 'Content-Type', 'application/x-www-form-urlencoded');
|
|
300
|
-
} else if (_optionalChain([body, 'optionalAccess',
|
|
312
|
+
} else if (_optionalChain([body, 'optionalAccess', _12 => _12.contentType]) === 'json' && _templateValidator.getL1Template.call(void 0, options.template) === 'fetch') {
|
|
301
313
|
upsertFixedHeader(headers, 'Content-Type', 'application/json');
|
|
302
314
|
}
|
|
303
315
|
|
|
@@ -485,10 +497,10 @@ function prepareUrl(path) {
|
|
|
485
497
|
type: _swagger.getParameterType.call(void 0, p, options),
|
|
486
498
|
optional: p.required === undefined || p.required === null ? true : !p.required,
|
|
487
499
|
original: p,
|
|
488
|
-
jsDoc: _optionalChain([p, 'access',
|
|
500
|
+
jsDoc: _optionalChain([p, 'access', _13 => _13.description, 'optionalAccess', _14 => _14.trim, 'call', _15 => _15()]),
|
|
489
501
|
}));
|
|
490
502
|
|
|
491
|
-
if (_optionalChain([options, 'access',
|
|
503
|
+
if (_optionalChain([options, 'access', _16 => _16.modifiers, 'optionalAccess', _17 => _17.parameters])) {
|
|
492
504
|
for (const [name, modifier] of Object.entries(options.modifiers.parameters)) {
|
|
493
505
|
const paramIndex = result.findIndex(
|
|
494
506
|
(p) => p.original.in !== 'path' && (p.originalName === name || p.name === name)
|
|
@@ -539,7 +551,7 @@ function getRequestBody(
|
|
|
539
551
|
let reqBody;
|
|
540
552
|
if ('$ref' in rawReqBody) {
|
|
541
553
|
const refName = rawReqBody.$ref.replace('#/components/requestBodies/', '');
|
|
542
|
-
const resolved = _optionalChain([components, 'optionalAccess',
|
|
554
|
+
const resolved = _optionalChain([components, 'optionalAccess', _18 => _18.requestBodies, 'optionalAccess', _19 => _19[refName]]);
|
|
543
555
|
if (!resolved || '$ref' in resolved) {
|
|
544
556
|
console.error(`RequestBody $ref '${rawReqBody.$ref}' not found in components/requestBodies`);
|
|
545
557
|
return null;
|
|
@@ -673,6 +685,23 @@ function getL1HttpTypeImport(template) {
|
|
|
673
685
|
}
|
|
674
686
|
}
|
|
675
687
|
|
|
688
|
+
/**
|
|
689
|
+
* Matches a value against a pattern that may contain `*` (any sequence of
|
|
690
|
+
* characters) or `?` (any single character). Falls back to exact equality for
|
|
691
|
+
* patterns that contain neither wildcard (fast path).
|
|
692
|
+
*/
|
|
693
|
+
function matchesPattern(value, pattern) {
|
|
694
|
+
if (!pattern.includes('*') && !pattern.includes('?')) {
|
|
695
|
+
return value === pattern;
|
|
696
|
+
}
|
|
697
|
+
const regex = new RegExp(
|
|
698
|
+
'^' +
|
|
699
|
+
pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.') +
|
|
700
|
+
'$'
|
|
701
|
+
);
|
|
702
|
+
return regex.test(value);
|
|
703
|
+
} exports.matchesPattern = matchesPattern;
|
|
704
|
+
|
|
676
705
|
function upsertFixedHeader(headers, headerName, value) {
|
|
677
706
|
const headerIndex = headers.findIndex(
|
|
678
707
|
(header) => header.originalName.toLowerCase() === headerName.toLowerCase()
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ var _gen = require('./gen'); var _gen2 = _interopRequireDefault(_gen);
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
var _utils = require('./utils');
|
|
14
15
|
var _templateValidator = require('./utils/templateValidator');
|
|
15
16
|
var _swagger = require('./swagger');
|
|
@@ -86,6 +87,7 @@ function verifyOptions(options) {
|
|
|
86
87
|
);
|
|
87
88
|
}
|
|
88
89
|
}
|
|
90
|
+
verifyExcludeOptions(options.exclude);
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
/**
|
|
@@ -126,6 +128,43 @@ function verifyEntryOptions(opts) {
|
|
|
126
128
|
);
|
|
127
129
|
}
|
|
128
130
|
}
|
|
131
|
+
verifyExcludeOptions(opts.exclude);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Returns true when a pattern looks like a regex (starts with `/` or contains
|
|
136
|
+
* regex-specific metacharacters that are not our supported wildcards).
|
|
137
|
+
* Our supported wildcards are `*` and `?` only.
|
|
138
|
+
*/
|
|
139
|
+
function isRegexPattern(pattern) {
|
|
140
|
+
if (pattern.startsWith('/')) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
// Characters that are regex metacharacters but are NOT our supported wildcards
|
|
144
|
+
const regexOnlyChars = /[\\^$.|+()[\]{}]/;
|
|
145
|
+
return regexOnlyChars.test(pattern);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Throws if any pattern in `exclude.tags` or `exclude.operationIds` looks like
|
|
150
|
+
* a regex. Only plain strings and * / ? wildcards are supported.
|
|
151
|
+
*/
|
|
152
|
+
function verifyExcludeOptions(exclude) {
|
|
153
|
+
if (!exclude) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const allPatterns = [
|
|
157
|
+
...(_nullishCoalesce(exclude.tags, () => ( []))).map((p) => ['exclude.tags', p]),
|
|
158
|
+
...(_nullishCoalesce(exclude.operationIds, () => ( []))).map((p) => ['exclude.operationIds', p]),
|
|
159
|
+
];
|
|
160
|
+
for (const [field, pattern] of allPatterns) {
|
|
161
|
+
if (isRegexPattern(pattern)) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Invalid pattern "${pattern}" in ${field}: regex patterns are not supported. ` +
|
|
164
|
+
'Use plain strings or wildcard patterns with * and ? only.'
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
129
168
|
}
|
|
130
169
|
|
|
131
170
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -4,6 +4,18 @@ interface QueryParamsSerializationOptions {
|
|
|
4
4
|
arrayFormat?: ArrayFormat;
|
|
5
5
|
queryParamsAsObject?: boolean | number;
|
|
6
6
|
}
|
|
7
|
+
export interface ExcludeOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Exclude operations whose first tag matches any of these values.
|
|
10
|
+
* Supports * (any sequence of characters) and ? (any single character) wildcards.
|
|
11
|
+
*/
|
|
12
|
+
tags?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Exclude operations whose operationId matches any of these values.
|
|
15
|
+
* Supports * (any sequence of characters) and ? (any single character) wildcards.
|
|
16
|
+
*/
|
|
17
|
+
operationIds?: string[];
|
|
18
|
+
}
|
|
7
19
|
export interface ClientOptions {
|
|
8
20
|
/**
|
|
9
21
|
* Path or URL to the Swagger specification file (JSON or YAML).
|
|
@@ -106,6 +118,8 @@ export interface ClientOptions {
|
|
|
106
118
|
[key: string]: 'optional' | 'required' | 'ignore';
|
|
107
119
|
};
|
|
108
120
|
};
|
|
121
|
+
/** Excludes specific operations from code generation by tag or operationId */
|
|
122
|
+
exclude?: ExcludeOptions;
|
|
109
123
|
}
|
|
110
124
|
export interface CliOptions extends Omit<FullAppOptions, 'enumNamesStyle'> {
|
|
111
125
|
allowDots?: boolean;
|