@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.
Files changed (168) hide show
  1. package/README.md +119 -0
  2. package/bin/cli.js +2 -2
  3. package/dist/CollectionRunner.js +3 -3
  4. package/dist/ScriptEngine.js +4 -4
  5. package/dist/cli/plugin-commands.d.ts.map +1 -1
  6. package/dist/cli/plugin-commands.js +2 -1
  7. package/dist/cli/plugin-commands.js.map +1 -1
  8. package/package.json +55 -50
  9. package/src/CollectionAnalyzer.ts +102 -102
  10. package/src/CollectionRunner.ts +1423 -1423
  11. package/src/CollectionRunner.types.ts +9 -9
  12. package/src/CollectionValidator.ts +289 -289
  13. package/src/ConsoleReporter.ts +143 -143
  14. package/src/CookieJar.ts +258 -258
  15. package/src/DagScheduler.ts +439 -439
  16. package/src/Logger.ts +85 -85
  17. package/src/PluginLoader.ts +126 -126
  18. package/src/PluginManager.ts +208 -208
  19. package/src/PluginResolver.ts +154 -154
  20. package/src/QuestAPI.ts +764 -764
  21. package/src/QuestAPI.types.ts +33 -33
  22. package/src/QuestTestAPI.ts +164 -164
  23. package/src/RequestFilter.ts +224 -224
  24. package/src/ScriptEngine.ts +219 -219
  25. package/src/ScriptValidator.ts +428 -428
  26. package/src/TaskGraph.ts +598 -598
  27. package/src/TestCounter.ts +109 -109
  28. package/src/VariableResolver.ts +114 -114
  29. package/src/cli/index.ts +480 -480
  30. package/src/cli/plugin-commands.ts +342 -341
  31. package/src/cli/plugin-discovery.ts +44 -44
  32. package/src/index.ts +24 -24
  33. package/src/utils.ts +52 -52
  34. package/tsconfig.json +20 -20
  35. package/tsconfig.test.json +5 -5
  36. package/vitest.config.ts +22 -22
  37. package/dist/ExecutionTree.d.ts +0 -77
  38. package/dist/ExecutionTree.d.ts.map +0 -1
  39. package/dist/ExecutionTree.js +0 -265
  40. package/dist/ExecutionTree.js.map +0 -1
  41. package/dist/fracture/src/CollectionAnalyzer.d.ts +0 -17
  42. package/dist/fracture/src/CollectionAnalyzer.d.ts.map +0 -1
  43. package/dist/fracture/src/CollectionAnalyzer.js +0 -70
  44. package/dist/fracture/src/CollectionAnalyzer.js.map +0 -1
  45. package/dist/fracture/src/CollectionRunner.d.ts +0 -39
  46. package/dist/fracture/src/CollectionRunner.d.ts.map +0 -1
  47. package/dist/fracture/src/CollectionRunner.js +0 -802
  48. package/dist/fracture/src/CollectionRunner.js.map +0 -1
  49. package/dist/fracture/src/CollectionRunner.types.d.ts +0 -8
  50. package/dist/fracture/src/CollectionRunner.types.d.ts.map +0 -1
  51. package/dist/fracture/src/CollectionRunner.types.js +0 -2
  52. package/dist/fracture/src/CollectionRunner.types.js.map +0 -1
  53. package/dist/fracture/src/CollectionValidator.d.ts +0 -14
  54. package/dist/fracture/src/CollectionValidator.d.ts.map +0 -1
  55. package/dist/fracture/src/CollectionValidator.js +0 -145
  56. package/dist/fracture/src/CollectionValidator.js.map +0 -1
  57. package/dist/fracture/src/ConsoleReporter.d.ts +0 -24
  58. package/dist/fracture/src/ConsoleReporter.d.ts.map +0 -1
  59. package/dist/fracture/src/ConsoleReporter.js +0 -123
  60. package/dist/fracture/src/ConsoleReporter.js.map +0 -1
  61. package/dist/fracture/src/CookieJar.d.ts +0 -70
  62. package/dist/fracture/src/CookieJar.d.ts.map +0 -1
  63. package/dist/fracture/src/CookieJar.js +0 -233
  64. package/dist/fracture/src/CookieJar.js.map +0 -1
  65. package/dist/fracture/src/ExecutionTree.d.ts +0 -77
  66. package/dist/fracture/src/ExecutionTree.d.ts.map +0 -1
  67. package/dist/fracture/src/ExecutionTree.js +0 -258
  68. package/dist/fracture/src/ExecutionTree.js.map +0 -1
  69. package/dist/fracture/src/Logger.d.ts +0 -25
  70. package/dist/fracture/src/Logger.d.ts.map +0 -1
  71. package/dist/fracture/src/Logger.js +0 -78
  72. package/dist/fracture/src/Logger.js.map +0 -1
  73. package/dist/fracture/src/PluginLoader.d.ts +0 -23
  74. package/dist/fracture/src/PluginLoader.d.ts.map +0 -1
  75. package/dist/fracture/src/PluginLoader.js +0 -102
  76. package/dist/fracture/src/PluginLoader.js.map +0 -1
  77. package/dist/fracture/src/PluginManager.d.ts +0 -64
  78. package/dist/fracture/src/PluginManager.d.ts.map +0 -1
  79. package/dist/fracture/src/PluginManager.js +0 -162
  80. package/dist/fracture/src/PluginManager.js.map +0 -1
  81. package/dist/fracture/src/PluginResolver.d.ts +0 -35
  82. package/dist/fracture/src/PluginResolver.d.ts.map +0 -1
  83. package/dist/fracture/src/PluginResolver.js +0 -128
  84. package/dist/fracture/src/PluginResolver.js.map +0 -1
  85. package/dist/fracture/src/QuestAPI.d.ts +0 -9
  86. package/dist/fracture/src/QuestAPI.d.ts.map +0 -1
  87. package/dist/fracture/src/QuestAPI.js +0 -679
  88. package/dist/fracture/src/QuestAPI.js.map +0 -1
  89. package/dist/fracture/src/QuestAPI.types.d.ts +0 -35
  90. package/dist/fracture/src/QuestAPI.types.d.ts.map +0 -1
  91. package/dist/fracture/src/QuestAPI.types.js +0 -3
  92. package/dist/fracture/src/QuestAPI.types.js.map +0 -1
  93. package/dist/fracture/src/QuestTestAPI.d.ts +0 -12
  94. package/dist/fracture/src/QuestTestAPI.d.ts.map +0 -1
  95. package/dist/fracture/src/QuestTestAPI.js +0 -133
  96. package/dist/fracture/src/QuestTestAPI.js.map +0 -1
  97. package/dist/fracture/src/ScriptEngine.d.ts +0 -21
  98. package/dist/fracture/src/ScriptEngine.d.ts.map +0 -1
  99. package/dist/fracture/src/ScriptEngine.js +0 -183
  100. package/dist/fracture/src/ScriptEngine.js.map +0 -1
  101. package/dist/fracture/src/ScriptValidator.d.ts +0 -68
  102. package/dist/fracture/src/ScriptValidator.d.ts.map +0 -1
  103. package/dist/fracture/src/ScriptValidator.js +0 -351
  104. package/dist/fracture/src/ScriptValidator.js.map +0 -1
  105. package/dist/fracture/src/TestCounter.d.ts +0 -18
  106. package/dist/fracture/src/TestCounter.d.ts.map +0 -1
  107. package/dist/fracture/src/TestCounter.js +0 -82
  108. package/dist/fracture/src/TestCounter.js.map +0 -1
  109. package/dist/fracture/src/VariableResolver.d.ts +0 -20
  110. package/dist/fracture/src/VariableResolver.d.ts.map +0 -1
  111. package/dist/fracture/src/VariableResolver.js +0 -100
  112. package/dist/fracture/src/VariableResolver.js.map +0 -1
  113. package/dist/fracture/src/cli/index.d.ts +0 -3
  114. package/dist/fracture/src/cli/index.d.ts.map +0 -1
  115. package/dist/fracture/src/cli/index.js +0 -347
  116. package/dist/fracture/src/cli/index.js.map +0 -1
  117. package/dist/fracture/src/cli/plugin-commands.d.ts +0 -6
  118. package/dist/fracture/src/cli/plugin-commands.d.ts.map +0 -1
  119. package/dist/fracture/src/cli/plugin-commands.js +0 -263
  120. package/dist/fracture/src/cli/plugin-commands.js.map +0 -1
  121. package/dist/fracture/src/cli/plugin-discovery.d.ts +0 -11
  122. package/dist/fracture/src/cli/plugin-discovery.d.ts.map +0 -1
  123. package/dist/fracture/src/cli/plugin-discovery.js +0 -64
  124. package/dist/fracture/src/cli/plugin-discovery.js.map +0 -1
  125. package/dist/fracture/src/index.d.ts +0 -13
  126. package/dist/fracture/src/index.d.ts.map +0 -1
  127. package/dist/fracture/src/index.js +0 -17
  128. package/dist/fracture/src/index.js.map +0 -1
  129. package/dist/fracture/src/utils.d.ts +0 -28
  130. package/dist/fracture/src/utils.d.ts.map +0 -1
  131. package/dist/fracture/src/utils.js +0 -48
  132. package/dist/fracture/src/utils.js.map +0 -1
  133. package/dist/plugin-auth/src/apikey-auth.d.ts +0 -3
  134. package/dist/plugin-auth/src/apikey-auth.d.ts.map +0 -1
  135. package/dist/plugin-auth/src/apikey-auth.js +0 -73
  136. package/dist/plugin-auth/src/apikey-auth.js.map +0 -1
  137. package/dist/plugin-auth/src/basic-auth.d.ts +0 -3
  138. package/dist/plugin-auth/src/basic-auth.d.ts.map +0 -1
  139. package/dist/plugin-auth/src/basic-auth.js +0 -61
  140. package/dist/plugin-auth/src/basic-auth.js.map +0 -1
  141. package/dist/plugin-auth/src/bearer-auth.d.ts +0 -3
  142. package/dist/plugin-auth/src/bearer-auth.d.ts.map +0 -1
  143. package/dist/plugin-auth/src/bearer-auth.js +0 -49
  144. package/dist/plugin-auth/src/bearer-auth.js.map +0 -1
  145. package/dist/plugin-auth/src/helpers.d.ts +0 -3
  146. package/dist/plugin-auth/src/helpers.d.ts.map +0 -1
  147. package/dist/plugin-auth/src/helpers.js +0 -8
  148. package/dist/plugin-auth/src/helpers.js.map +0 -1
  149. package/dist/plugin-auth/src/index.d.ts +0 -10
  150. package/dist/plugin-auth/src/index.d.ts.map +0 -1
  151. package/dist/plugin-auth/src/index.js +0 -25
  152. package/dist/plugin-auth/src/index.js.map +0 -1
  153. package/dist/plugin-auth/src/oauth2-auth.d.ts +0 -35
  154. package/dist/plugin-auth/src/oauth2-auth.d.ts.map +0 -1
  155. package/dist/plugin-auth/src/oauth2-auth.js +0 -266
  156. package/dist/plugin-auth/src/oauth2-auth.js.map +0 -1
  157. package/dist/plugin-http/src/index.d.ts +0 -4
  158. package/dist/plugin-http/src/index.d.ts.map +0 -1
  159. package/dist/plugin-http/src/index.js +0 -266
  160. package/dist/plugin-http/src/index.js.map +0 -1
  161. package/dist/plugin-vault-file/src/index.d.ts +0 -67
  162. package/dist/plugin-vault-file/src/index.d.ts.map +0 -1
  163. package/dist/plugin-vault-file/src/index.js +0 -171
  164. package/dist/plugin-vault-file/src/index.js.map +0 -1
  165. package/dist/types.d.ts +0 -374
  166. package/dist/types.d.ts.map +0 -1
  167. package/dist/types.js +0 -13
  168. package/dist/types.js.map +0 -1
@@ -1,9 +1,9 @@
1
- import type { TestResult } from '@apiquest/types';
2
-
3
- export interface PluginEventTest extends TestResult {
4
- eventName?: string;
5
- }
6
-
7
- export interface ErrorWithPhase extends Error {
8
- phase?: string;
9
- }
1
+ import type { TestResult } from '@apiquest/types';
2
+
3
+ export interface PluginEventTest extends TestResult {
4
+ eventName?: string;
5
+ }
6
+
7
+ export interface ErrorWithPhase extends Error {
8
+ phase?: string;
9
+ }
@@ -1,289 +1,289 @@
1
- import type {
2
- Collection,
3
- CollectionItem,
4
- Request,
5
- Folder,
6
- RuntimeOptions,
7
- ValidationResult,
8
- ValidationError,
9
- } from '@apiquest/types';
10
- import { ScriptType } from '@apiquest/types';
11
- import { ScriptValidator } from './ScriptValidator.js';
12
- import type { PluginManager } from './PluginManager.js';
13
- import { Logger } from './Logger.js';
14
- import { isNullOrWhitespace } from './utils.js';
15
-
16
- /**
17
- * Validates collections and their items (folders/requests) for pre-run validation
18
- */
19
- export class CollectionValidator {
20
- private logger: Logger;
21
-
22
- constructor(
23
- private readonly pluginManager: PluginManager,
24
- baseLogger?: Logger
25
- ) {
26
- this.logger = baseLogger?.createLogger('CollectionValidator') ?? new Logger('CollectionValidator');
27
- }
28
-
29
- /**
30
- * Validate entire collection structure, scripts, and configurations
31
- */
32
- async validateCollection(
33
- collection: Collection,
34
- options: RuntimeOptions,
35
- strictMode: boolean = true
36
- ): Promise<ValidationResult> {
37
- const errors: ValidationError[] = [];
38
-
39
- this.logger.debug(`Validating collection: ${collection.info.name} (strict=${strictMode})`);
40
-
41
- // Get protocol plugin for validation
42
- const protocolPlugin = this.pluginManager.getPlugin(collection.protocol);
43
- if (protocolPlugin === undefined) {
44
- this.logger.warn(`Protocol plugin not loaded for validation: ${collection.protocol}`);
45
- }
46
-
47
- // Helper to recursively validate all items
48
- const validateItem = (item: CollectionItem, path: string): void => {
49
- if (item.type === 'folder') {
50
- const folder = item;
51
-
52
- // Validate folder scripts
53
- if (!isNullOrWhitespace(folder.folderPreScript)) {
54
- errors.push(
55
- ...ScriptValidator.validateScript(
56
- folder.folderPreScript!,
57
- ScriptType.FolderPre,
58
- path,
59
- undefined,
60
- protocolPlugin,
61
- strictMode
62
- )
63
- );
64
- }
65
- if (!isNullOrWhitespace(folder.folderPostScript)) {
66
- errors.push(
67
- ...ScriptValidator.validateScript(
68
- folder.folderPostScript!,
69
- ScriptType.FolderPost,
70
- path,
71
- undefined,
72
- protocolPlugin,
73
- strictMode
74
- )
75
- );
76
- }
77
- if (!isNullOrWhitespace(folder.preRequestScript)) {
78
- errors.push(
79
- ...ScriptValidator.validateScript(
80
- folder.preRequestScript!,
81
- ScriptType.PreRequest,
82
- path,
83
- undefined,
84
- protocolPlugin,
85
- strictMode
86
- )
87
- );
88
- }
89
- if (!isNullOrWhitespace(folder.postRequestScript)) {
90
- errors.push(
91
- ...ScriptValidator.validateScript(
92
- folder.postRequestScript!,
93
- ScriptType.PostRequest,
94
- path,
95
- undefined,
96
- protocolPlugin,
97
- strictMode
98
- )
99
- );
100
- }
101
-
102
- // Validate auth config if present
103
- if (folder.auth !== null && folder.auth !== undefined && folder.auth.type !== 'inherit' && folder.auth.type !== 'none') {
104
- const authPlugin = this.pluginManager.getAuthPlugin(folder.auth.type);
105
- if (authPlugin?.validate !== null && authPlugin?.validate !== undefined) {
106
- const authResult = authPlugin.validate(folder.auth, options);
107
- if (authResult.valid === false && authResult.errors !== null && authResult.errors !== undefined) {
108
- errors.push(...authResult.errors);
109
- }
110
- }
111
- }
112
-
113
- // Recursively validate folder items
114
- for (const child of folder.items) {
115
- const childPath = `${path}/${child.name}`;
116
- validateItem(child, childPath);
117
- }
118
- } else {
119
- // Request validation
120
- const request = item;
121
-
122
- // Validate request scripts
123
- if (!isNullOrWhitespace(request.preRequestScript)) {
124
- errors.push(
125
- ...ScriptValidator.validateScript(
126
- request.preRequestScript!,
127
- ScriptType.PreRequest,
128
- path,
129
- undefined,
130
- protocolPlugin,
131
- strictMode
132
- )
133
- );
134
- }
135
- if (!isNullOrWhitespace(request.postRequestScript)) {
136
- errors.push(
137
- ...ScriptValidator.validateScript(
138
- request.postRequestScript!,
139
- ScriptType.PostRequest,
140
- path,
141
- undefined,
142
- protocolPlugin,
143
- strictMode
144
- )
145
- );
146
- }
147
-
148
- // Validate plugin event scripts
149
- if (request.data.scripts !== null && request.data.scripts !== undefined && Array.isArray(request.data.scripts)) {
150
- // Check for duplicate event scripts (only one script per event type allowed)
151
- const eventCounts = new Map<string, number>();
152
- for (const script of request.data.scripts) {
153
- const count = eventCounts.get(script.event) ?? 0;
154
- eventCounts.set(script.event, count + 1);
155
-
156
- if (count >= 1) {
157
- errors.push({
158
- message: `Request has multiple scripts for event "${script.event}". Only one script per event type is allowed.`,
159
- location: path,
160
- source: 'script'
161
- });
162
- }
163
- }
164
-
165
- // Validate each script
166
- if (protocolPlugin?.events !== null && protocolPlugin?.events !== undefined) {
167
- for (const script of request.data.scripts) {
168
- const eventDef = protocolPlugin.events.find(e => e.name === script.event);
169
- if (eventDef !== null && eventDef !== undefined) {
170
- errors.push(
171
- ...ScriptValidator.validateScript(
172
- script.script,
173
- ScriptType.PluginEvent,
174
- path,
175
- eventDef,
176
- protocolPlugin,
177
- strictMode
178
- )
179
- );
180
- }
181
- }
182
- }
183
- }
184
-
185
- // Validate protocol request via plugin
186
- if (protocolPlugin?.validate !== null && protocolPlugin?.validate !== undefined) {
187
- const protocolResult = protocolPlugin.validate(request, options);
188
- if (protocolResult.valid === false && protocolResult.errors !== null && protocolResult.errors !== undefined) {
189
- errors.push(
190
- ...protocolResult.errors.map(err => ({
191
- ...err,
192
- location: path
193
- }))
194
- );
195
- }
196
- }
197
-
198
- // Validate auth config if present
199
- if (request.auth !== null && request.auth !== undefined && request.auth.type !== 'inherit' && request.auth.type !== 'none') {
200
- const authPlugin = this.pluginManager.getAuthPlugin(request.auth.type);
201
- if (authPlugin?.validate !== null && authPlugin?.validate !== undefined) {
202
- const authResult = authPlugin.validate(request.auth, options);
203
- if (authResult.valid === false && authResult.errors !== null && authResult.errors !== undefined) {
204
- errors.push(
205
- ...authResult.errors.map(err => ({
206
- ...err,
207
- location: path
208
- }))
209
- );
210
- }
211
- }
212
- }
213
- }
214
- };
215
-
216
- // Validate collection-level scripts
217
- if (!isNullOrWhitespace(collection.collectionPreScript)) {
218
- errors.push(
219
- ...ScriptValidator.validateScript(
220
- collection.collectionPreScript!,
221
- ScriptType.CollectionPre,
222
- '/',
223
- undefined,
224
- protocolPlugin,
225
- strictMode
226
- )
227
- );
228
- }
229
- if (!isNullOrWhitespace(collection.collectionPostScript)) {
230
- errors.push(
231
- ...ScriptValidator.validateScript(
232
- collection.collectionPostScript!,
233
- ScriptType.CollectionPost,
234
- '/',
235
- undefined,
236
- protocolPlugin,
237
- strictMode
238
- )
239
- );
240
- }
241
- if (!isNullOrWhitespace(collection.preRequestScript)) {
242
- errors.push(
243
- ...ScriptValidator.validateScript(
244
- collection.preRequestScript!,
245
- ScriptType.PreRequest,
246
- '/',
247
- undefined,
248
- protocolPlugin,
249
- strictMode
250
- )
251
- );
252
- }
253
- if (!isNullOrWhitespace(collection.postRequestScript)) {
254
- errors.push(
255
- ...ScriptValidator.validateScript(
256
- collection.postRequestScript!,
257
- ScriptType.PostRequest,
258
- '/',
259
- undefined,
260
- protocolPlugin,
261
- strictMode
262
- )
263
- );
264
- }
265
-
266
- // Validate collection-level auth
267
- if (collection.auth !== null && collection.auth !== undefined && collection.auth.type !== 'inherit' && collection.auth.type !== 'none') {
268
- const authPlugin = this.pluginManager.getAuthPlugin(collection.auth.type);
269
- if (authPlugin?.validate !== null && authPlugin?.validate !== undefined) {
270
- const authResult = authPlugin.validate(collection.auth, options);
271
- if (authResult.valid === false && authResult.errors !== null && authResult.errors !== undefined) {
272
- errors.push(...authResult.errors);
273
- }
274
- }
275
- }
276
-
277
- // Validate all items recursively
278
- for (const item of collection.items) {
279
- validateItem(item, `/${item.name}`);
280
- }
281
-
282
- this.logger.debug(`Validation completed with ${errors.length} error(s)`);
283
-
284
- return {
285
- valid: errors.length === 0,
286
- errors
287
- };
288
- }
289
- }
1
+ import type {
2
+ Collection,
3
+ CollectionItem,
4
+ Request,
5
+ Folder,
6
+ RuntimeOptions,
7
+ ValidationResult,
8
+ ValidationError,
9
+ } from '@apiquest/types';
10
+ import { ScriptType } from '@apiquest/types';
11
+ import { ScriptValidator } from './ScriptValidator.js';
12
+ import type { PluginManager } from './PluginManager.js';
13
+ import { Logger } from './Logger.js';
14
+ import { isNullOrWhitespace } from './utils.js';
15
+
16
+ /**
17
+ * Validates collections and their items (folders/requests) for pre-run validation
18
+ */
19
+ export class CollectionValidator {
20
+ private logger: Logger;
21
+
22
+ constructor(
23
+ private readonly pluginManager: PluginManager,
24
+ baseLogger?: Logger
25
+ ) {
26
+ this.logger = baseLogger?.createLogger('CollectionValidator') ?? new Logger('CollectionValidator');
27
+ }
28
+
29
+ /**
30
+ * Validate entire collection structure, scripts, and configurations
31
+ */
32
+ async validateCollection(
33
+ collection: Collection,
34
+ options: RuntimeOptions,
35
+ strictMode: boolean = true
36
+ ): Promise<ValidationResult> {
37
+ const errors: ValidationError[] = [];
38
+
39
+ this.logger.debug(`Validating collection: ${collection.info.name} (strict=${strictMode})`);
40
+
41
+ // Get protocol plugin for validation
42
+ const protocolPlugin = this.pluginManager.getPlugin(collection.protocol);
43
+ if (protocolPlugin === undefined) {
44
+ this.logger.warn(`Protocol plugin not loaded for validation: ${collection.protocol}`);
45
+ }
46
+
47
+ // Helper to recursively validate all items
48
+ const validateItem = (item: CollectionItem, path: string): void => {
49
+ if (item.type === 'folder') {
50
+ const folder = item;
51
+
52
+ // Validate folder scripts
53
+ if (!isNullOrWhitespace(folder.folderPreScript)) {
54
+ errors.push(
55
+ ...ScriptValidator.validateScript(
56
+ folder.folderPreScript!,
57
+ ScriptType.FolderPre,
58
+ path,
59
+ undefined,
60
+ protocolPlugin,
61
+ strictMode
62
+ )
63
+ );
64
+ }
65
+ if (!isNullOrWhitespace(folder.folderPostScript)) {
66
+ errors.push(
67
+ ...ScriptValidator.validateScript(
68
+ folder.folderPostScript!,
69
+ ScriptType.FolderPost,
70
+ path,
71
+ undefined,
72
+ protocolPlugin,
73
+ strictMode
74
+ )
75
+ );
76
+ }
77
+ if (!isNullOrWhitespace(folder.preRequestScript)) {
78
+ errors.push(
79
+ ...ScriptValidator.validateScript(
80
+ folder.preRequestScript!,
81
+ ScriptType.PreRequest,
82
+ path,
83
+ undefined,
84
+ protocolPlugin,
85
+ strictMode
86
+ )
87
+ );
88
+ }
89
+ if (!isNullOrWhitespace(folder.postRequestScript)) {
90
+ errors.push(
91
+ ...ScriptValidator.validateScript(
92
+ folder.postRequestScript!,
93
+ ScriptType.PostRequest,
94
+ path,
95
+ undefined,
96
+ protocolPlugin,
97
+ strictMode
98
+ )
99
+ );
100
+ }
101
+
102
+ // Validate auth config if present
103
+ if (folder.auth !== null && folder.auth !== undefined && folder.auth.type !== 'inherit' && folder.auth.type !== 'none') {
104
+ const authPlugin = this.pluginManager.getAuthPlugin(folder.auth.type);
105
+ if (authPlugin?.validate !== null && authPlugin?.validate !== undefined) {
106
+ const authResult = authPlugin.validate(folder.auth, options);
107
+ if (authResult.valid === false && authResult.errors !== null && authResult.errors !== undefined) {
108
+ errors.push(...authResult.errors);
109
+ }
110
+ }
111
+ }
112
+
113
+ // Recursively validate folder items
114
+ for (const child of folder.items) {
115
+ const childPath = `${path}/${child.name}`;
116
+ validateItem(child, childPath);
117
+ }
118
+ } else {
119
+ // Request validation
120
+ const request = item;
121
+
122
+ // Validate request scripts
123
+ if (!isNullOrWhitespace(request.preRequestScript)) {
124
+ errors.push(
125
+ ...ScriptValidator.validateScript(
126
+ request.preRequestScript!,
127
+ ScriptType.PreRequest,
128
+ path,
129
+ undefined,
130
+ protocolPlugin,
131
+ strictMode
132
+ )
133
+ );
134
+ }
135
+ if (!isNullOrWhitespace(request.postRequestScript)) {
136
+ errors.push(
137
+ ...ScriptValidator.validateScript(
138
+ request.postRequestScript!,
139
+ ScriptType.PostRequest,
140
+ path,
141
+ undefined,
142
+ protocolPlugin,
143
+ strictMode
144
+ )
145
+ );
146
+ }
147
+
148
+ // Validate plugin event scripts
149
+ if (request.data.scripts !== null && request.data.scripts !== undefined && Array.isArray(request.data.scripts)) {
150
+ // Check for duplicate event scripts (only one script per event type allowed)
151
+ const eventCounts = new Map<string, number>();
152
+ for (const script of request.data.scripts) {
153
+ const count = eventCounts.get(script.event) ?? 0;
154
+ eventCounts.set(script.event, count + 1);
155
+
156
+ if (count >= 1) {
157
+ errors.push({
158
+ message: `Request has multiple scripts for event "${script.event}". Only one script per event type is allowed.`,
159
+ location: path,
160
+ source: 'script'
161
+ });
162
+ }
163
+ }
164
+
165
+ // Validate each script
166
+ if (protocolPlugin?.events !== null && protocolPlugin?.events !== undefined) {
167
+ for (const script of request.data.scripts) {
168
+ const eventDef = protocolPlugin.events.find(e => e.name === script.event);
169
+ if (eventDef !== null && eventDef !== undefined) {
170
+ errors.push(
171
+ ...ScriptValidator.validateScript(
172
+ script.script,
173
+ ScriptType.PluginEvent,
174
+ path,
175
+ eventDef,
176
+ protocolPlugin,
177
+ strictMode
178
+ )
179
+ );
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ // Validate protocol request via plugin
186
+ if (protocolPlugin?.validate !== null && protocolPlugin?.validate !== undefined) {
187
+ const protocolResult = protocolPlugin.validate(request, options);
188
+ if (protocolResult.valid === false && protocolResult.errors !== null && protocolResult.errors !== undefined) {
189
+ errors.push(
190
+ ...protocolResult.errors.map(err => ({
191
+ ...err,
192
+ location: path
193
+ }))
194
+ );
195
+ }
196
+ }
197
+
198
+ // Validate auth config if present
199
+ if (request.auth !== null && request.auth !== undefined && request.auth.type !== 'inherit' && request.auth.type !== 'none') {
200
+ const authPlugin = this.pluginManager.getAuthPlugin(request.auth.type);
201
+ if (authPlugin?.validate !== null && authPlugin?.validate !== undefined) {
202
+ const authResult = authPlugin.validate(request.auth, options);
203
+ if (authResult.valid === false && authResult.errors !== null && authResult.errors !== undefined) {
204
+ errors.push(
205
+ ...authResult.errors.map(err => ({
206
+ ...err,
207
+ location: path
208
+ }))
209
+ );
210
+ }
211
+ }
212
+ }
213
+ }
214
+ };
215
+
216
+ // Validate collection-level scripts
217
+ if (!isNullOrWhitespace(collection.collectionPreScript)) {
218
+ errors.push(
219
+ ...ScriptValidator.validateScript(
220
+ collection.collectionPreScript!,
221
+ ScriptType.CollectionPre,
222
+ '/',
223
+ undefined,
224
+ protocolPlugin,
225
+ strictMode
226
+ )
227
+ );
228
+ }
229
+ if (!isNullOrWhitespace(collection.collectionPostScript)) {
230
+ errors.push(
231
+ ...ScriptValidator.validateScript(
232
+ collection.collectionPostScript!,
233
+ ScriptType.CollectionPost,
234
+ '/',
235
+ undefined,
236
+ protocolPlugin,
237
+ strictMode
238
+ )
239
+ );
240
+ }
241
+ if (!isNullOrWhitespace(collection.preRequestScript)) {
242
+ errors.push(
243
+ ...ScriptValidator.validateScript(
244
+ collection.preRequestScript!,
245
+ ScriptType.PreRequest,
246
+ '/',
247
+ undefined,
248
+ protocolPlugin,
249
+ strictMode
250
+ )
251
+ );
252
+ }
253
+ if (!isNullOrWhitespace(collection.postRequestScript)) {
254
+ errors.push(
255
+ ...ScriptValidator.validateScript(
256
+ collection.postRequestScript!,
257
+ ScriptType.PostRequest,
258
+ '/',
259
+ undefined,
260
+ protocolPlugin,
261
+ strictMode
262
+ )
263
+ );
264
+ }
265
+
266
+ // Validate collection-level auth
267
+ if (collection.auth !== null && collection.auth !== undefined && collection.auth.type !== 'inherit' && collection.auth.type !== 'none') {
268
+ const authPlugin = this.pluginManager.getAuthPlugin(collection.auth.type);
269
+ if (authPlugin?.validate !== null && authPlugin?.validate !== undefined) {
270
+ const authResult = authPlugin.validate(collection.auth, options);
271
+ if (authResult.valid === false && authResult.errors !== null && authResult.errors !== undefined) {
272
+ errors.push(...authResult.errors);
273
+ }
274
+ }
275
+ }
276
+
277
+ // Validate all items recursively
278
+ for (const item of collection.items) {
279
+ validateItem(item, `/${item.name}`);
280
+ }
281
+
282
+ this.logger.debug(`Validation completed with ${errors.length} error(s)`);
283
+
284
+ return {
285
+ valid: errors.length === 0,
286
+ errors
287
+ };
288
+ }
289
+ }