@apiquest/fracture 1.0.2 → 1.0.4
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 +119 -0
- package/bin/cli.js +2 -2
- package/dist/CollectionRunner.js +3 -3
- package/dist/ScriptEngine.js +4 -4
- package/dist/cli/plugin-commands.d.ts.map +1 -1
- package/dist/cli/plugin-commands.js +2 -1
- package/dist/cli/plugin-commands.js.map +1 -1
- package/package.json +55 -50
- package/src/CollectionAnalyzer.ts +102 -102
- package/src/CollectionRunner.ts +1423 -1423
- package/src/CollectionRunner.types.ts +9 -9
- package/src/CollectionValidator.ts +289 -289
- package/src/ConsoleReporter.ts +143 -143
- package/src/CookieJar.ts +258 -258
- package/src/DagScheduler.ts +439 -439
- package/src/Logger.ts +85 -85
- package/src/PluginLoader.ts +126 -126
- package/src/PluginManager.ts +208 -208
- package/src/PluginResolver.ts +154 -154
- package/src/QuestAPI.ts +764 -764
- package/src/QuestAPI.types.ts +33 -33
- package/src/QuestTestAPI.ts +164 -164
- package/src/RequestFilter.ts +224 -224
- package/src/ScriptEngine.ts +219 -219
- package/src/ScriptValidator.ts +428 -428
- package/src/TaskGraph.ts +598 -598
- package/src/TestCounter.ts +109 -109
- package/src/VariableResolver.ts +114 -114
- package/src/cli/index.ts +480 -480
- package/src/cli/plugin-commands.ts +342 -341
- package/src/cli/plugin-discovery.ts +44 -44
- package/src/index.ts +24 -24
- package/src/utils.ts +52 -52
- package/tsconfig.json +20 -20
- package/tsconfig.test.json +5 -5
- package/vitest.config.ts +22 -22
- package/dist/ExecutionTree.d.ts +0 -77
- package/dist/ExecutionTree.d.ts.map +0 -1
- package/dist/ExecutionTree.js +0 -265
- package/dist/ExecutionTree.js.map +0 -1
- package/dist/fracture/src/CollectionAnalyzer.d.ts +0 -17
- package/dist/fracture/src/CollectionAnalyzer.d.ts.map +0 -1
- package/dist/fracture/src/CollectionAnalyzer.js +0 -70
- package/dist/fracture/src/CollectionAnalyzer.js.map +0 -1
- package/dist/fracture/src/CollectionRunner.d.ts +0 -39
- package/dist/fracture/src/CollectionRunner.d.ts.map +0 -1
- package/dist/fracture/src/CollectionRunner.js +0 -802
- package/dist/fracture/src/CollectionRunner.js.map +0 -1
- package/dist/fracture/src/CollectionRunner.types.d.ts +0 -8
- package/dist/fracture/src/CollectionRunner.types.d.ts.map +0 -1
- package/dist/fracture/src/CollectionRunner.types.js +0 -2
- package/dist/fracture/src/CollectionRunner.types.js.map +0 -1
- package/dist/fracture/src/CollectionValidator.d.ts +0 -14
- package/dist/fracture/src/CollectionValidator.d.ts.map +0 -1
- package/dist/fracture/src/CollectionValidator.js +0 -145
- package/dist/fracture/src/CollectionValidator.js.map +0 -1
- package/dist/fracture/src/ConsoleReporter.d.ts +0 -24
- package/dist/fracture/src/ConsoleReporter.d.ts.map +0 -1
- package/dist/fracture/src/ConsoleReporter.js +0 -123
- package/dist/fracture/src/ConsoleReporter.js.map +0 -1
- package/dist/fracture/src/CookieJar.d.ts +0 -70
- package/dist/fracture/src/CookieJar.d.ts.map +0 -1
- package/dist/fracture/src/CookieJar.js +0 -233
- package/dist/fracture/src/CookieJar.js.map +0 -1
- package/dist/fracture/src/ExecutionTree.d.ts +0 -77
- package/dist/fracture/src/ExecutionTree.d.ts.map +0 -1
- package/dist/fracture/src/ExecutionTree.js +0 -258
- package/dist/fracture/src/ExecutionTree.js.map +0 -1
- package/dist/fracture/src/Logger.d.ts +0 -25
- package/dist/fracture/src/Logger.d.ts.map +0 -1
- package/dist/fracture/src/Logger.js +0 -78
- package/dist/fracture/src/Logger.js.map +0 -1
- package/dist/fracture/src/PluginLoader.d.ts +0 -23
- package/dist/fracture/src/PluginLoader.d.ts.map +0 -1
- package/dist/fracture/src/PluginLoader.js +0 -102
- package/dist/fracture/src/PluginLoader.js.map +0 -1
- package/dist/fracture/src/PluginManager.d.ts +0 -64
- package/dist/fracture/src/PluginManager.d.ts.map +0 -1
- package/dist/fracture/src/PluginManager.js +0 -162
- package/dist/fracture/src/PluginManager.js.map +0 -1
- package/dist/fracture/src/PluginResolver.d.ts +0 -35
- package/dist/fracture/src/PluginResolver.d.ts.map +0 -1
- package/dist/fracture/src/PluginResolver.js +0 -128
- package/dist/fracture/src/PluginResolver.js.map +0 -1
- package/dist/fracture/src/QuestAPI.d.ts +0 -9
- package/dist/fracture/src/QuestAPI.d.ts.map +0 -1
- package/dist/fracture/src/QuestAPI.js +0 -679
- package/dist/fracture/src/QuestAPI.js.map +0 -1
- package/dist/fracture/src/QuestAPI.types.d.ts +0 -35
- package/dist/fracture/src/QuestAPI.types.d.ts.map +0 -1
- package/dist/fracture/src/QuestAPI.types.js +0 -3
- package/dist/fracture/src/QuestAPI.types.js.map +0 -1
- package/dist/fracture/src/QuestTestAPI.d.ts +0 -12
- package/dist/fracture/src/QuestTestAPI.d.ts.map +0 -1
- package/dist/fracture/src/QuestTestAPI.js +0 -133
- package/dist/fracture/src/QuestTestAPI.js.map +0 -1
- package/dist/fracture/src/ScriptEngine.d.ts +0 -21
- package/dist/fracture/src/ScriptEngine.d.ts.map +0 -1
- package/dist/fracture/src/ScriptEngine.js +0 -183
- package/dist/fracture/src/ScriptEngine.js.map +0 -1
- package/dist/fracture/src/ScriptValidator.d.ts +0 -68
- package/dist/fracture/src/ScriptValidator.d.ts.map +0 -1
- package/dist/fracture/src/ScriptValidator.js +0 -351
- package/dist/fracture/src/ScriptValidator.js.map +0 -1
- package/dist/fracture/src/TestCounter.d.ts +0 -18
- package/dist/fracture/src/TestCounter.d.ts.map +0 -1
- package/dist/fracture/src/TestCounter.js +0 -82
- package/dist/fracture/src/TestCounter.js.map +0 -1
- package/dist/fracture/src/VariableResolver.d.ts +0 -20
- package/dist/fracture/src/VariableResolver.d.ts.map +0 -1
- package/dist/fracture/src/VariableResolver.js +0 -100
- package/dist/fracture/src/VariableResolver.js.map +0 -1
- package/dist/fracture/src/cli/index.d.ts +0 -3
- package/dist/fracture/src/cli/index.d.ts.map +0 -1
- package/dist/fracture/src/cli/index.js +0 -347
- package/dist/fracture/src/cli/index.js.map +0 -1
- package/dist/fracture/src/cli/plugin-commands.d.ts +0 -6
- package/dist/fracture/src/cli/plugin-commands.d.ts.map +0 -1
- package/dist/fracture/src/cli/plugin-commands.js +0 -263
- package/dist/fracture/src/cli/plugin-commands.js.map +0 -1
- package/dist/fracture/src/cli/plugin-discovery.d.ts +0 -11
- package/dist/fracture/src/cli/plugin-discovery.d.ts.map +0 -1
- package/dist/fracture/src/cli/plugin-discovery.js +0 -64
- package/dist/fracture/src/cli/plugin-discovery.js.map +0 -1
- package/dist/fracture/src/index.d.ts +0 -13
- package/dist/fracture/src/index.d.ts.map +0 -1
- package/dist/fracture/src/index.js +0 -17
- package/dist/fracture/src/index.js.map +0 -1
- package/dist/fracture/src/utils.d.ts +0 -28
- package/dist/fracture/src/utils.d.ts.map +0 -1
- package/dist/fracture/src/utils.js +0 -48
- package/dist/fracture/src/utils.js.map +0 -1
- package/dist/plugin-auth/src/apikey-auth.d.ts +0 -3
- package/dist/plugin-auth/src/apikey-auth.d.ts.map +0 -1
- package/dist/plugin-auth/src/apikey-auth.js +0 -73
- package/dist/plugin-auth/src/apikey-auth.js.map +0 -1
- package/dist/plugin-auth/src/basic-auth.d.ts +0 -3
- package/dist/plugin-auth/src/basic-auth.d.ts.map +0 -1
- package/dist/plugin-auth/src/basic-auth.js +0 -61
- package/dist/plugin-auth/src/basic-auth.js.map +0 -1
- package/dist/plugin-auth/src/bearer-auth.d.ts +0 -3
- package/dist/plugin-auth/src/bearer-auth.d.ts.map +0 -1
- package/dist/plugin-auth/src/bearer-auth.js +0 -49
- package/dist/plugin-auth/src/bearer-auth.js.map +0 -1
- package/dist/plugin-auth/src/helpers.d.ts +0 -3
- package/dist/plugin-auth/src/helpers.d.ts.map +0 -1
- package/dist/plugin-auth/src/helpers.js +0 -8
- package/dist/plugin-auth/src/helpers.js.map +0 -1
- package/dist/plugin-auth/src/index.d.ts +0 -10
- package/dist/plugin-auth/src/index.d.ts.map +0 -1
- package/dist/plugin-auth/src/index.js +0 -25
- package/dist/plugin-auth/src/index.js.map +0 -1
- package/dist/plugin-auth/src/oauth2-auth.d.ts +0 -35
- package/dist/plugin-auth/src/oauth2-auth.d.ts.map +0 -1
- package/dist/plugin-auth/src/oauth2-auth.js +0 -266
- package/dist/plugin-auth/src/oauth2-auth.js.map +0 -1
- package/dist/plugin-http/src/index.d.ts +0 -4
- package/dist/plugin-http/src/index.d.ts.map +0 -1
- package/dist/plugin-http/src/index.js +0 -266
- package/dist/plugin-http/src/index.js.map +0 -1
- package/dist/plugin-vault-file/src/index.d.ts +0 -67
- package/dist/plugin-vault-file/src/index.d.ts.map +0 -1
- package/dist/plugin-vault-file/src/index.js +0 -171
- package/dist/plugin-vault-file/src/index.js.map +0 -1
- package/dist/types.d.ts +0 -374
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -13
- package/dist/types.js.map +0 -1
package/src/RequestFilter.ts
CHANGED
|
@@ -1,224 +1,224 @@
|
|
|
1
|
-
import type { Collection, CollectionItem, Folder, Request, PathType } from '@apiquest/types';
|
|
2
|
-
|
|
3
|
-
export interface FilterOptions {
|
|
4
|
-
filter?: string;
|
|
5
|
-
excludeDeps?: boolean;
|
|
6
|
-
pruneEmptyFolders?: boolean; // Default: true
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface ItemWithPath {
|
|
10
|
-
item: CollectionItem;
|
|
11
|
-
path: PathType;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class RequestFilter {
|
|
15
|
-
/**
|
|
16
|
-
* Filter collection removing non-matching requests and empty folders
|
|
17
|
-
* Returns filtered copy or original if no filtering
|
|
18
|
-
*/
|
|
19
|
-
static filterCollection(collection: Collection, options: FilterOptions): Collection {
|
|
20
|
-
if (options.filter === undefined) {
|
|
21
|
-
return collection;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const filterSet = this.getFilterSet(collection, options);
|
|
25
|
-
if (filterSet === null) {
|
|
26
|
-
return collection;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const pruneEmpty = options.pruneEmptyFolders !== false;
|
|
30
|
-
|
|
31
|
-
// Clone collection and filter items
|
|
32
|
-
const filtered: Collection = {
|
|
33
|
-
...collection,
|
|
34
|
-
items: this.filterItems(collection.items, filterSet, pruneEmpty)
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
return filtered;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Recursively filter items keeping only requests in filterSet
|
|
42
|
-
* Optionally prune empty folders
|
|
43
|
-
*/
|
|
44
|
-
private static filterItems(
|
|
45
|
-
items: CollectionItem[],
|
|
46
|
-
filterSet: Set<string>,
|
|
47
|
-
pruneEmpty: boolean
|
|
48
|
-
): CollectionItem[] {
|
|
49
|
-
const filtered: CollectionItem[] = [];
|
|
50
|
-
|
|
51
|
-
for (const item of items) {
|
|
52
|
-
if (item.type === 'request') {
|
|
53
|
-
if (filterSet.has(item.id)) {
|
|
54
|
-
filtered.push(item);
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
// Folder: recursively filter children
|
|
58
|
-
const filteredChildren = this.filterItems(item.items, filterSet, pruneEmpty);
|
|
59
|
-
|
|
60
|
-
if (!pruneEmpty || filteredChildren.length > 0) {
|
|
61
|
-
filtered.push({
|
|
62
|
-
...item,
|
|
63
|
-
items: filteredChildren
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return filtered;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Get set of request IDs to execute
|
|
74
|
-
* Returns null if no filtering needed
|
|
75
|
-
*/
|
|
76
|
-
private static getFilterSet(collection: Collection, options: FilterOptions): Set<string> | null {
|
|
77
|
-
if (options.filter === undefined) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Collect requests matching filter
|
|
82
|
-
const matchingIds = new Set<string>();
|
|
83
|
-
try {
|
|
84
|
-
const filterRegex = new RegExp(options.filter);
|
|
85
|
-
|
|
86
|
-
// Walk collection structure and match paths
|
|
87
|
-
this.collectMatchingRequests(collection.items, 'collection:/', filterRegex, matchingIds);
|
|
88
|
-
} catch (error) {
|
|
89
|
-
// Invalid regex - no filtering
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (options.excludeDeps !== true) {
|
|
94
|
-
return this.includeDependencies(collection, matchingIds);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return matchingIds;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Build path with proper type prefix (same logic as TaskGraph.buildPath)
|
|
102
|
-
*/
|
|
103
|
-
private static buildPath(parent: string, name: string, type: 'folder' | 'request'): PathType {
|
|
104
|
-
// If parent is collection:/
|
|
105
|
-
if (parent === 'collection:/') {
|
|
106
|
-
return `${type}:/${name}` as PathType;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Remove type prefix from parent path
|
|
110
|
-
const basePath = parent.replace(/^(folder|request):\//, '');
|
|
111
|
-
return `${type}:/${basePath}/${name}` as PathType;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Collect requests matching path filter (regex)
|
|
116
|
-
* Matches against both folder and request paths
|
|
117
|
-
* If a folder matches, all requests in that folder are included
|
|
118
|
-
*/
|
|
119
|
-
private static collectMatchingRequests(
|
|
120
|
-
items: CollectionItem[],
|
|
121
|
-
parentPath: string,
|
|
122
|
-
filterRegex: RegExp,
|
|
123
|
-
result: Set<string>
|
|
124
|
-
): void {
|
|
125
|
-
for (const item of items) {
|
|
126
|
-
if (item.type === 'folder') {
|
|
127
|
-
const folderPath = this.buildPath(parentPath, item.name, 'folder');
|
|
128
|
-
const folderMatches = filterRegex.test(folderPath);
|
|
129
|
-
|
|
130
|
-
if (folderMatches) {
|
|
131
|
-
// Folder matches - include ALL requests in this folder
|
|
132
|
-
this.collectAllRequests(item.items, result);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Always recurse to children
|
|
136
|
-
this.collectMatchingRequests(item.items, folderPath, filterRegex, result);
|
|
137
|
-
} else {
|
|
138
|
-
// Request
|
|
139
|
-
const requestPath = this.buildPath(parentPath, item.name, 'request');
|
|
140
|
-
const requestMatches = filterRegex.test(requestPath);
|
|
141
|
-
|
|
142
|
-
if (requestMatches) {
|
|
143
|
-
result.add(item.id);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Collect all requests from items (helper for when folder matches)
|
|
151
|
-
*/
|
|
152
|
-
private static collectAllRequests(items: CollectionItem[], result: Set<string>): void {
|
|
153
|
-
for (const item of items) {
|
|
154
|
-
if (item.type === 'request') {
|
|
155
|
-
result.add(item.id);
|
|
156
|
-
} else {
|
|
157
|
-
this.collectAllRequests(item.items, result);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Include dependencies by walking collection and resolving dependsOn
|
|
164
|
-
*/
|
|
165
|
-
private static includeDependencies(
|
|
166
|
-
collection: Collection,
|
|
167
|
-
matchingIds: Set<string>
|
|
168
|
-
): Set<string> {
|
|
169
|
-
const result = new Set<string>();
|
|
170
|
-
const depMap = new Map<string, string[]>();
|
|
171
|
-
|
|
172
|
-
// Build dependency map
|
|
173
|
-
this.buildDependencyMap(collection.items, depMap);
|
|
174
|
-
|
|
175
|
-
// Resolve dependencies recursively
|
|
176
|
-
for (const requestId of matchingIds) {
|
|
177
|
-
this.resolveDependencies(requestId, depMap, result);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return result;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Build map of request/folder ID -> dependencies
|
|
185
|
-
*/
|
|
186
|
-
private static buildDependencyMap(
|
|
187
|
-
items: CollectionItem[],
|
|
188
|
-
depMap: Map<string, string[]>
|
|
189
|
-
): void {
|
|
190
|
-
for (const item of items) {
|
|
191
|
-
if (item.type === 'request') {
|
|
192
|
-
depMap.set(item.id, item.dependsOn ?? []);
|
|
193
|
-
} else {
|
|
194
|
-
// Folders can also have dependencies
|
|
195
|
-
const folder = item;
|
|
196
|
-
const folderDeps = folder.dependsOn;
|
|
197
|
-
if (folderDeps !== undefined && folderDeps.length > 0) {
|
|
198
|
-
depMap.set(folder.id, folderDeps);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Recurse to children
|
|
202
|
-
this.buildDependencyMap(folder.items, depMap);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Recursively resolve dependencies for a request/folder
|
|
209
|
-
*/
|
|
210
|
-
private static resolveDependencies(
|
|
211
|
-
itemId: string,
|
|
212
|
-
depMap: Map<string, string[]>,
|
|
213
|
-
result: Set<string>
|
|
214
|
-
): void {
|
|
215
|
-
result.add(itemId);
|
|
216
|
-
|
|
217
|
-
const deps = depMap.get(itemId) ?? [];
|
|
218
|
-
for (const depId of deps) {
|
|
219
|
-
if (!result.has(depId)) {
|
|
220
|
-
this.resolveDependencies(depId, depMap, result);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
1
|
+
import type { Collection, CollectionItem, Folder, Request, PathType } from '@apiquest/types';
|
|
2
|
+
|
|
3
|
+
export interface FilterOptions {
|
|
4
|
+
filter?: string;
|
|
5
|
+
excludeDeps?: boolean;
|
|
6
|
+
pruneEmptyFolders?: boolean; // Default: true
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ItemWithPath {
|
|
10
|
+
item: CollectionItem;
|
|
11
|
+
path: PathType;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class RequestFilter {
|
|
15
|
+
/**
|
|
16
|
+
* Filter collection removing non-matching requests and empty folders
|
|
17
|
+
* Returns filtered copy or original if no filtering
|
|
18
|
+
*/
|
|
19
|
+
static filterCollection(collection: Collection, options: FilterOptions): Collection {
|
|
20
|
+
if (options.filter === undefined) {
|
|
21
|
+
return collection;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const filterSet = this.getFilterSet(collection, options);
|
|
25
|
+
if (filterSet === null) {
|
|
26
|
+
return collection;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const pruneEmpty = options.pruneEmptyFolders !== false;
|
|
30
|
+
|
|
31
|
+
// Clone collection and filter items
|
|
32
|
+
const filtered: Collection = {
|
|
33
|
+
...collection,
|
|
34
|
+
items: this.filterItems(collection.items, filterSet, pruneEmpty)
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return filtered;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Recursively filter items keeping only requests in filterSet
|
|
42
|
+
* Optionally prune empty folders
|
|
43
|
+
*/
|
|
44
|
+
private static filterItems(
|
|
45
|
+
items: CollectionItem[],
|
|
46
|
+
filterSet: Set<string>,
|
|
47
|
+
pruneEmpty: boolean
|
|
48
|
+
): CollectionItem[] {
|
|
49
|
+
const filtered: CollectionItem[] = [];
|
|
50
|
+
|
|
51
|
+
for (const item of items) {
|
|
52
|
+
if (item.type === 'request') {
|
|
53
|
+
if (filterSet.has(item.id)) {
|
|
54
|
+
filtered.push(item);
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
// Folder: recursively filter children
|
|
58
|
+
const filteredChildren = this.filterItems(item.items, filterSet, pruneEmpty);
|
|
59
|
+
|
|
60
|
+
if (!pruneEmpty || filteredChildren.length > 0) {
|
|
61
|
+
filtered.push({
|
|
62
|
+
...item,
|
|
63
|
+
items: filteredChildren
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return filtered;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get set of request IDs to execute
|
|
74
|
+
* Returns null if no filtering needed
|
|
75
|
+
*/
|
|
76
|
+
private static getFilterSet(collection: Collection, options: FilterOptions): Set<string> | null {
|
|
77
|
+
if (options.filter === undefined) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Collect requests matching filter
|
|
82
|
+
const matchingIds = new Set<string>();
|
|
83
|
+
try {
|
|
84
|
+
const filterRegex = new RegExp(options.filter);
|
|
85
|
+
|
|
86
|
+
// Walk collection structure and match paths
|
|
87
|
+
this.collectMatchingRequests(collection.items, 'collection:/', filterRegex, matchingIds);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
// Invalid regex - no filtering
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (options.excludeDeps !== true) {
|
|
94
|
+
return this.includeDependencies(collection, matchingIds);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return matchingIds;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Build path with proper type prefix (same logic as TaskGraph.buildPath)
|
|
102
|
+
*/
|
|
103
|
+
private static buildPath(parent: string, name: string, type: 'folder' | 'request'): PathType {
|
|
104
|
+
// If parent is collection:/
|
|
105
|
+
if (parent === 'collection:/') {
|
|
106
|
+
return `${type}:/${name}` as PathType;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Remove type prefix from parent path
|
|
110
|
+
const basePath = parent.replace(/^(folder|request):\//, '');
|
|
111
|
+
return `${type}:/${basePath}/${name}` as PathType;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Collect requests matching path filter (regex)
|
|
116
|
+
* Matches against both folder and request paths
|
|
117
|
+
* If a folder matches, all requests in that folder are included
|
|
118
|
+
*/
|
|
119
|
+
private static collectMatchingRequests(
|
|
120
|
+
items: CollectionItem[],
|
|
121
|
+
parentPath: string,
|
|
122
|
+
filterRegex: RegExp,
|
|
123
|
+
result: Set<string>
|
|
124
|
+
): void {
|
|
125
|
+
for (const item of items) {
|
|
126
|
+
if (item.type === 'folder') {
|
|
127
|
+
const folderPath = this.buildPath(parentPath, item.name, 'folder');
|
|
128
|
+
const folderMatches = filterRegex.test(folderPath);
|
|
129
|
+
|
|
130
|
+
if (folderMatches) {
|
|
131
|
+
// Folder matches - include ALL requests in this folder
|
|
132
|
+
this.collectAllRequests(item.items, result);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Always recurse to children
|
|
136
|
+
this.collectMatchingRequests(item.items, folderPath, filterRegex, result);
|
|
137
|
+
} else {
|
|
138
|
+
// Request
|
|
139
|
+
const requestPath = this.buildPath(parentPath, item.name, 'request');
|
|
140
|
+
const requestMatches = filterRegex.test(requestPath);
|
|
141
|
+
|
|
142
|
+
if (requestMatches) {
|
|
143
|
+
result.add(item.id);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Collect all requests from items (helper for when folder matches)
|
|
151
|
+
*/
|
|
152
|
+
private static collectAllRequests(items: CollectionItem[], result: Set<string>): void {
|
|
153
|
+
for (const item of items) {
|
|
154
|
+
if (item.type === 'request') {
|
|
155
|
+
result.add(item.id);
|
|
156
|
+
} else {
|
|
157
|
+
this.collectAllRequests(item.items, result);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Include dependencies by walking collection and resolving dependsOn
|
|
164
|
+
*/
|
|
165
|
+
private static includeDependencies(
|
|
166
|
+
collection: Collection,
|
|
167
|
+
matchingIds: Set<string>
|
|
168
|
+
): Set<string> {
|
|
169
|
+
const result = new Set<string>();
|
|
170
|
+
const depMap = new Map<string, string[]>();
|
|
171
|
+
|
|
172
|
+
// Build dependency map
|
|
173
|
+
this.buildDependencyMap(collection.items, depMap);
|
|
174
|
+
|
|
175
|
+
// Resolve dependencies recursively
|
|
176
|
+
for (const requestId of matchingIds) {
|
|
177
|
+
this.resolveDependencies(requestId, depMap, result);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Build map of request/folder ID -> dependencies
|
|
185
|
+
*/
|
|
186
|
+
private static buildDependencyMap(
|
|
187
|
+
items: CollectionItem[],
|
|
188
|
+
depMap: Map<string, string[]>
|
|
189
|
+
): void {
|
|
190
|
+
for (const item of items) {
|
|
191
|
+
if (item.type === 'request') {
|
|
192
|
+
depMap.set(item.id, item.dependsOn ?? []);
|
|
193
|
+
} else {
|
|
194
|
+
// Folders can also have dependencies
|
|
195
|
+
const folder = item;
|
|
196
|
+
const folderDeps = folder.dependsOn;
|
|
197
|
+
if (folderDeps !== undefined && folderDeps.length > 0) {
|
|
198
|
+
depMap.set(folder.id, folderDeps);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Recurse to children
|
|
202
|
+
this.buildDependencyMap(folder.items, depMap);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Recursively resolve dependencies for a request/folder
|
|
209
|
+
*/
|
|
210
|
+
private static resolveDependencies(
|
|
211
|
+
itemId: string,
|
|
212
|
+
depMap: Map<string, string[]>,
|
|
213
|
+
result: Set<string>
|
|
214
|
+
): void {
|
|
215
|
+
result.add(itemId);
|
|
216
|
+
|
|
217
|
+
const deps = depMap.get(itemId) ?? [];
|
|
218
|
+
for (const depId of deps) {
|
|
219
|
+
if (!result.has(depId)) {
|
|
220
|
+
this.resolveDependencies(depId, depMap, result);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|