Skip to content

Commit 1489ac3

Browse files
committed
Filter: combine inverseTags and inverseFlag
1 parent cf3de40 commit 1489ac3

3 files changed

Lines changed: 93 additions & 19 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [1.29.5] - 2026-02-28
44

5+
- Filter: combine inverseTags and inverseFlag (#192)
56
- Filter: preserve inverse flag filtering with stripFlags (#193)
67
- Types: Update Typescript typings (#194)
78

openapi-format.js

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ async function openapiFilter(oaObj, options) {
381381
// Filter out object matching the inverse "tags"
382382
if (
383383
inverseFilterArray.length > 0 &&
384+
inverseFilterFlags.length === 0 &&
384385
this.key === 'tags' &&
385386
!inverseFilterArray.some(i => node.includes(i)) &&
386387
this.parent.parent !== undefined
@@ -390,7 +391,12 @@ async function openapiFilter(oaObj, options) {
390391
}
391392

392393
// Filter out the top level tags matching the inverse "tags"
393-
if (inverseFilterArray.length > 0 && this.key === 'tags' && this.parent.parent === undefined) {
394+
if (
395+
inverseFilterArray.length > 0 &&
396+
inverseFilterFlags.length === 0 &&
397+
this.key === 'tags' &&
398+
this.parent.parent === undefined
399+
) {
394400
// debugFilterStep = 'Filter - inverse top tags'
395401
node = node.filter(value => inverseFilterArray.includes(value.name));
396402
this.update(node);
@@ -437,6 +443,7 @@ async function openapiFilter(oaObj, options) {
437443
// Keep fields matching the inverseFlags array
438444
if (
439445
inverseFilterFlags.length > 0 &&
446+
inverseFilterArray.length === 0 &&
440447
(this.path[0] === 'tags' || this.path[0] === 'x-tagGroups') &&
441448
this.level === 1
442449
) {
@@ -551,23 +558,36 @@ async function openapiFilter(oaObj, options) {
551558
}
552559
}
553560

554-
// Filter out operations not matching inverseFilterArray
555-
if (inverseFilterArray.length > 0 && this.parent && this.parent.parent && this.parent.parent.key === 'paths') {
556-
if (node.tags === undefined || !inverseFilterArray.some(i => node.tags.includes(i))) {
557-
this.delete();
558-
}
559-
}
560-
561-
// Keep fields matching the inverseFlags
562-
if (inverseFilterFlags.length > 0 && this.path[0] === 'paths' && this.level === 3) {
563-
const itmObj = node;
564-
const matchesInverseFlag = inverseFilterFlags.some(flagKey => {
565-
return itmObj.hasOwnProperty(flagKey);
566-
});
567-
568-
if (!matchesInverseFlag) {
569-
// debugFilterStep = 'Filter - Single field - inverseFlags'
570-
this.remove();
561+
// Filter operations for inverseTags / inverseFlags.
562+
// When both are configured, treat them as a union (keep if either matches).
563+
if (
564+
this.path[0] === 'paths' &&
565+
this.level === 3 &&
566+
this.parent &&
567+
this.parent.parent &&
568+
this.parent.parent.key === 'paths'
569+
) {
570+
const hasInverseTags = inverseFilterArray.length > 0;
571+
const hasInverseFlags = inverseFilterFlags.length > 0;
572+
if (hasInverseTags || hasInverseFlags) {
573+
const operation = node || {};
574+
const matchesInverseTag =
575+
hasInverseTags && Array.isArray(operation.tags)
576+
? inverseFilterArray.some(i => operation.tags.includes(i))
577+
: false;
578+
const matchesInverseFlag = hasInverseFlags
579+
? inverseFilterFlags.some(flagKey => operation.hasOwnProperty(flagKey))
580+
: false;
581+
const shouldKeep =
582+
hasInverseTags && hasInverseFlags
583+
? matchesInverseTag || matchesInverseFlag
584+
: hasInverseTags
585+
? matchesInverseTag
586+
: matchesInverseFlag;
587+
588+
if (!shouldKeep) {
589+
this.delete();
590+
}
571591
}
572592
}
573593

@@ -636,6 +656,25 @@ async function openapiFilter(oaObj, options) {
636656
}
637657
});
638658

659+
// Keep top-level tags that are still referenced by remaining operations.
660+
// Apply this only when inverseTags and inverseFlags are both configured.
661+
// (inverseFlags-only mode should preserve the existing flagged-tag behavior.)
662+
if (Array.isArray(jsonObj.tags) && inverseFilterArray.length > 0 && inverseFilterFlags.length > 0) {
663+
const usedTags = new Set();
664+
if (jsonObj.paths && typeof jsonObj.paths === 'object') {
665+
Object.values(jsonObj.paths).forEach(pathItem => {
666+
if (pathItem && typeof pathItem === 'object') {
667+
Object.values(pathItem).forEach(operation => {
668+
if (operation && typeof operation === 'object' && Array.isArray(operation.tags)) {
669+
operation.tags.forEach(tag => usedTags.add(tag));
670+
}
671+
});
672+
}
673+
});
674+
}
675+
jsonObj.tags = jsonObj.tags.filter(tagObj => tagObj && usedTags.has(tagObj.name));
676+
}
677+
639678
// Calculate comps.meta.total at the end
640679
// comps.meta.total = Object.keys(comps.schemas).length +
641680
// Object.keys(comps.responses).length +

test/yaml-filter-inverse-flags-inverse-tags/output.yaml

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,38 @@ openapi: 3.0.0
22
info:
33
title: API
44
version: 1.0.0
5-
tags: []
5+
tags:
6+
- name: foo
7+
- name: bar
8+
paths:
9+
/foo-op:
10+
get:
11+
operationId: fooOp
12+
tags:
13+
- foo
14+
responses:
15+
'200':
16+
description: ok
17+
content:
18+
application/json:
19+
schema:
20+
$ref: '#/components/schemas/Foo'
21+
/public-op:
22+
get:
23+
operationId: publicOp
24+
tags:
25+
- bar
26+
x-public: true
27+
responses:
28+
'200':
29+
description: ok
30+
content:
31+
application/json:
32+
schema:
33+
$ref: '#/components/schemas/Bar'
34+
components:
35+
schemas:
36+
Foo:
37+
type: object
38+
Bar:
39+
type: object

0 commit comments

Comments
 (0)