@testchimp/playwright 0.2.19 → 0.2.21

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.
@@ -0,0 +1,384 @@
1
+ "use strict";
2
+ /**
3
+ * Smart-smoke: config merge, suite walk, related-tests load, selection sidecar.
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getBranchName = exports.SMART_SMOKE_SELECTION_FILENAME = exports.SMART_SMOKE_SKIP_REASON = void 0;
10
+ exports.isTruthyEnv = isTruthyEnv;
11
+ exports.normalizeTag = normalizeTag;
12
+ exports.resolveSmartSmokeConfig = resolveSmartSmokeConfig;
13
+ exports.readSmartSmokeUseFromConfig = readSmartSmokeUseFromConfig;
14
+ exports.folderPathSegments = folderPathSegments;
15
+ exports.locatorFromDerived = locatorFromDerived;
16
+ exports.normalizeLocator = normalizeLocator;
17
+ exports.locatorKey = locatorKey;
18
+ exports.locatorsEqual = locatorsEqual;
19
+ exports.collectSuiteCandidates = collectSuiteCandidates;
20
+ exports.findPlansRoot = findPlansRoot;
21
+ exports.loadRelatedTests = loadRelatedTests;
22
+ exports.getSmartSmokeSelectionFilePath = getSmartSmokeSelectionFilePath;
23
+ exports.writeSmartSmokeSelectionFile = writeSmartSmokeSelectionFile;
24
+ exports.invalidateSmartSmokeSelectionCache = invalidateSmartSmokeSelectionCache;
25
+ exports.loadSmartSmokeSelectionLookup = loadSmartSmokeSelectionLookup;
26
+ exports.readSmartSmokeSelectionFile = readSmartSmokeSelectionFile;
27
+ exports.unlinkSmartSmokeSelectionFile = unlinkSmartSmokeSelectionFile;
28
+ exports.unionLocators = unionLocators;
29
+ exports.isLocatorSelected = isLocatorSelected;
30
+ exports.resolveSkipReasonFromAnnotations = resolveSkipReasonFromAnnotations;
31
+ exports.maybeSkipForSmartSmoke = maybeSkipForSmartSmoke;
32
+ exports.toWireLocator = toWireLocator;
33
+ exports.fromWireLocator = fromWireLocator;
34
+ const fs_1 = __importDefault(require("fs"));
35
+ const path_1 = __importDefault(require("path"));
36
+ const utils_1 = require("./utils");
37
+ Object.defineProperty(exports, "getBranchName", { enumerable: true, get: function () { return utils_1.getBranchName; } });
38
+ exports.SMART_SMOKE_SKIP_REASON = 'smart-smoke';
39
+ exports.SMART_SMOKE_SELECTION_FILENAME = '.testchimp-smart-smoke-selection.json';
40
+ function isTruthyEnv(value) {
41
+ if (value == null)
42
+ return false;
43
+ const v = String(value).trim().toLowerCase();
44
+ return v === 'true' || v === '1';
45
+ }
46
+ function normalizeTag(tag) {
47
+ const t = String(tag || '').trim();
48
+ if (!t)
49
+ return '';
50
+ return t.startsWith('@') ? t.toLowerCase() : `@${t.toLowerCase()}`;
51
+ }
52
+ /** Env field → use field → fallback (warn + 20% suite % when no size constraint). */
53
+ function resolveSmartSmokeConfig(useOpts, env = process.env) {
54
+ const enabled = isTruthyEnv(env.TESTCHIMP_SMART_SMOKE_ENABLED);
55
+ const use = useOpts || {};
56
+ const maxTestsEnv = env.TESTCHIMP_SMART_SMOKE_MAX_TESTS?.trim();
57
+ const suitePctEnv = env.TESTCHIMP_SMART_SMOKE_SUITE_PERCENTAGE?.trim();
58
+ const timeEnv = env.TESTCHIMP_SMART_SMOKE_MAX_TIME_BUDGET_MINS?.trim();
59
+ const tagsEnv = env.TESTCHIMP_SMART_SMOKE_INCLUDE_TAGS?.trim();
60
+ const relatedOnlyEnv = env.TESTCHIMP_SMART_SMOKE_RELATED_TESTS_ONLY;
61
+ let maxTests;
62
+ if (maxTestsEnv) {
63
+ const n = parseInt(maxTestsEnv, 10);
64
+ if (Number.isFinite(n) && n > 0)
65
+ maxTests = n;
66
+ }
67
+ else if (typeof use.maxTests === 'number' && use.maxTests > 0) {
68
+ maxTests = use.maxTests;
69
+ }
70
+ let suitePercentage;
71
+ if (suitePctEnv) {
72
+ const n = Number(suitePctEnv);
73
+ if (Number.isFinite(n) && n > 0)
74
+ suitePercentage = n;
75
+ }
76
+ else if (typeof use.suitePercentage === 'number' && use.suitePercentage > 0) {
77
+ suitePercentage = use.suitePercentage;
78
+ }
79
+ let maxTimeBudgetMins;
80
+ if (timeEnv) {
81
+ const n = parseInt(timeEnv, 10);
82
+ if (Number.isFinite(n) && n > 0)
83
+ maxTimeBudgetMins = n;
84
+ }
85
+ else if (typeof use.maxTimeBudgetMins === 'number' && use.maxTimeBudgetMins > 0) {
86
+ maxTimeBudgetMins = use.maxTimeBudgetMins;
87
+ }
88
+ let includeTags = [];
89
+ if (tagsEnv) {
90
+ includeTags = tagsEnv.split(',').map((t) => t.trim()).filter(Boolean);
91
+ }
92
+ else if (Array.isArray(use.includeTags)) {
93
+ includeTags = [...use.includeTags];
94
+ }
95
+ const relatedTestsOnly = relatedOnlyEnv != null && String(relatedOnlyEnv).trim() !== ''
96
+ ? isTruthyEnv(relatedOnlyEnv)
97
+ : Boolean(use.relatedTestsOnly);
98
+ let usedDefaultSuitePercentage = false;
99
+ if (enabled &&
100
+ !relatedTestsOnly &&
101
+ maxTests == null &&
102
+ suitePercentage == null &&
103
+ maxTimeBudgetMins == null) {
104
+ suitePercentage = 20;
105
+ usedDefaultSuitePercentage = true;
106
+ }
107
+ return {
108
+ enabled,
109
+ maxTests,
110
+ suitePercentage,
111
+ maxTimeBudgetMins,
112
+ includeTags,
113
+ relatedTestsOnly,
114
+ usedDefaultSuitePercentage,
115
+ };
116
+ }
117
+ function readSmartSmokeUseFromConfig(config) {
118
+ const projects = config.projects || [];
119
+ for (const p of projects) {
120
+ const use = p.use;
121
+ const raw = use?.testchimpSmartSmoke;
122
+ if (raw && typeof raw === 'object') {
123
+ return raw;
124
+ }
125
+ }
126
+ return undefined;
127
+ }
128
+ function folderPathSegments(folderPath) {
129
+ if (Array.isArray(folderPath)) {
130
+ return folderPath.map((s) => String(s || '').trim()).filter((s) => s && s !== '.');
131
+ }
132
+ const norm = (0, utils_1.normalizeManifestFolderPath)(String(folderPath || ''));
133
+ if (!norm)
134
+ return [];
135
+ return norm.split('/').filter(Boolean);
136
+ }
137
+ function locatorFromDerived(paths) {
138
+ return {
139
+ folderPath: folderPathSegments(paths.folderPath),
140
+ fileName: paths.fileName,
141
+ testSuite: Array.isArray(paths.suitePath) ? [...paths.suitePath] : [],
142
+ testName: paths.testName,
143
+ };
144
+ }
145
+ function normalizeLocator(raw) {
146
+ const folder = raw.folder_path ??
147
+ (Array.isArray(raw.folderPath) ? raw.folderPath : folderPathSegments(raw.folderPath));
148
+ return {
149
+ folderPath: folderPathSegments(folder),
150
+ fileName: raw.file_name ?? raw.fileName ?? '',
151
+ testSuite: raw.test_suite ?? raw.testSuite ?? [],
152
+ testName: raw.test_name ?? raw.testName ?? '',
153
+ };
154
+ }
155
+ function locatorKey(loc) {
156
+ const n = normalizeLocator(loc);
157
+ const folder = Array.isArray(n.folderPath) ? n.folderPath : folderPathSegments(n.folderPath);
158
+ const suite = Array.isArray(n.testSuite) ? n.testSuite : [];
159
+ return [
160
+ folder.join('/'),
161
+ n.fileName || '',
162
+ suite.join('\u0001'),
163
+ n.testName || '',
164
+ ].join('\0');
165
+ }
166
+ function locatorsEqual(a, b) {
167
+ return locatorKey(a) === locatorKey(b);
168
+ }
169
+ function collectSuiteCandidates(suite, testsFolder, rootDir, includeTags) {
170
+ const wanted = new Set(includeTags.map(normalizeTag).filter(Boolean));
171
+ const suiteCandidates = [];
172
+ const taggedTests = [];
173
+ const seen = new Set();
174
+ const seenTagged = new Set();
175
+ const visit = (s) => {
176
+ for (const test of s.tests) {
177
+ const paths = (0, utils_1.derivePaths)(test, testsFolder, rootDir, false);
178
+ const loc = locatorFromDerived(paths);
179
+ const key = locatorKey(loc);
180
+ if (!seen.has(key)) {
181
+ seen.add(key);
182
+ suiteCandidates.push(loc);
183
+ }
184
+ if (wanted.size > 0 && testMatchesTags(test, wanted) && !seenTagged.has(key)) {
185
+ seenTagged.add(key);
186
+ taggedTests.push(loc);
187
+ }
188
+ }
189
+ for (const child of s.suites) {
190
+ visit(child);
191
+ }
192
+ };
193
+ visit(suite);
194
+ return { suiteCandidates, taggedTests };
195
+ }
196
+ function testMatchesTags(test, wantedNormalized) {
197
+ const tags = test.tags;
198
+ if (!Array.isArray(tags) || tags.length === 0)
199
+ return false;
200
+ for (const t of tags) {
201
+ if (wantedNormalized.has(normalizeTag(t)))
202
+ return true;
203
+ }
204
+ return false;
205
+ }
206
+ function findPlansRoot(startDir) {
207
+ let dir = path_1.default.resolve(startDir);
208
+ for (let i = 0; i < 40; i++) {
209
+ if (fs_1.default.existsSync(path_1.default.join(dir, '.testchimp-plans'))) {
210
+ return dir;
211
+ }
212
+ const plansDir = path_1.default.join(dir, 'plans');
213
+ if (fs_1.default.existsSync(plansDir) && fs_1.default.statSync(plansDir).isDirectory()) {
214
+ // Prefer mapped plans root (marker inside plans/) over a bare folder name match.
215
+ if (fs_1.default.existsSync(path_1.default.join(plansDir, '.testchimp-plans'))) {
216
+ return plansDir;
217
+ }
218
+ // Fallback: conventional plans/ directory when marker is absent.
219
+ return plansDir;
220
+ }
221
+ const parent = path_1.default.dirname(dir);
222
+ if (parent === dir)
223
+ break;
224
+ dir = parent;
225
+ }
226
+ return undefined;
227
+ }
228
+ /**
229
+ * Load related-tests.json for the current branch under plans/smart-smoke/<branch>/.
230
+ * Branch path segments are kept literally (nested dirs for `/` in branch names).
231
+ */
232
+ function loadRelatedTests(plansRoot, branchName) {
233
+ if (!plansRoot || !branchName?.trim())
234
+ return [];
235
+ const filePath = path_1.default.join(plansRoot, 'smart-smoke', ...branchName.split(/[/\\]+/), 'related-tests.json');
236
+ try {
237
+ const raw = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
238
+ const list = Array.isArray(raw)
239
+ ? raw
240
+ : Array.isArray(raw.relatedTests)
241
+ ? raw.relatedTests
242
+ : Array.isArray(raw.related_tests)
243
+ ? raw.related_tests
244
+ : [];
245
+ return list
246
+ .filter((x) => x != null && typeof x === 'object')
247
+ .map(normalizeLocator);
248
+ }
249
+ catch {
250
+ return [];
251
+ }
252
+ }
253
+ function getSmartSmokeSelectionFilePath(projectRootDir = process.cwd()) {
254
+ return ((0, utils_1.getEnvVar)('TESTCHIMP_SMART_SMOKE_SELECTION_FILE') ||
255
+ path_1.default.join(projectRootDir, exports.SMART_SMOKE_SELECTION_FILENAME));
256
+ }
257
+ function writeSmartSmokeSelectionFile(projectRootDir, payload) {
258
+ const filePath = getSmartSmokeSelectionFilePath(projectRootDir);
259
+ fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
260
+ fs_1.default.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');
261
+ invalidateSmartSmokeSelectionCache();
262
+ return filePath;
263
+ }
264
+ let selectionCache = null;
265
+ function invalidateSmartSmokeSelectionCache() {
266
+ selectionCache = null;
267
+ }
268
+ /**
269
+ * Load selection sidecar once per worker (re-read only when mtime changes).
270
+ * Returns undefined when smart-smoke is not active for this process.
271
+ */
272
+ function loadSmartSmokeSelectionLookup(projectRootDir = process.cwd()) {
273
+ // Env is the source of truth for "is this run smart-smoke" — ignore stale sidecars
274
+ // left behind when a previous run crashed before onEnd unlink.
275
+ if (!isTruthyEnv(process.env.TESTCHIMP_SMART_SMOKE_ENABLED)) {
276
+ return undefined;
277
+ }
278
+ const filePath = getSmartSmokeSelectionFilePath(projectRootDir);
279
+ try {
280
+ const st = fs_1.default.statSync(filePath);
281
+ if (selectionCache &&
282
+ selectionCache.filePath === filePath &&
283
+ selectionCache.mtimeMs === st.mtimeMs) {
284
+ return { selection: selectionCache.selection, keySet: selectionCache.keySet };
285
+ }
286
+ const parsed = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
287
+ if (!parsed || !Array.isArray(parsed.selectedTests) || !parsed.enabled) {
288
+ selectionCache = null;
289
+ return undefined;
290
+ }
291
+ const selection = {
292
+ ...parsed,
293
+ selectedTests: parsed.selectedTests.map(normalizeLocator),
294
+ };
295
+ const keySet = new Set(selection.selectedTests.map((t) => locatorKey(t)));
296
+ selectionCache = { filePath, mtimeMs: st.mtimeMs, selection, keySet };
297
+ return { selection, keySet };
298
+ }
299
+ catch {
300
+ selectionCache = null;
301
+ return undefined;
302
+ }
303
+ }
304
+ function readSmartSmokeSelectionFile(projectRootDir = process.cwd()) {
305
+ return loadSmartSmokeSelectionLookup(projectRootDir)?.selection;
306
+ }
307
+ function unlinkSmartSmokeSelectionFile(filePath) {
308
+ if (!filePath)
309
+ return;
310
+ try {
311
+ fs_1.default.unlinkSync(filePath);
312
+ }
313
+ catch {
314
+ // ignore
315
+ }
316
+ invalidateSmartSmokeSelectionCache();
317
+ }
318
+ /** Client-side must_include when related-tests-only or API unavailable. */
319
+ function unionLocators(...lists) {
320
+ const map = new Map();
321
+ for (const list of lists) {
322
+ for (const loc of list) {
323
+ const n = normalizeLocator(loc);
324
+ map.set(locatorKey(n), n);
325
+ }
326
+ }
327
+ return [...map.values()];
328
+ }
329
+ function isLocatorSelected(paths, selected, keySet) {
330
+ const key = locatorKey(locatorFromDerived(paths));
331
+ if (keySet)
332
+ return keySet.has(key);
333
+ return selected.some((s) => locatorKey(s) === key);
334
+ }
335
+ function resolveSkipReasonFromAnnotations(annotations, playwrightSkipMessage) {
336
+ if (!annotations?.length && !playwrightSkipMessage)
337
+ return undefined;
338
+ for (const a of annotations || []) {
339
+ if (a.type === 'skip-reason' && a.description?.trim()) {
340
+ return a.description.trim();
341
+ }
342
+ }
343
+ for (const a of annotations || []) {
344
+ if ((a.type === 'skip' || a.type === 'fix') && a.description?.trim()) {
345
+ return a.description.trim();
346
+ }
347
+ }
348
+ const msg = playwrightSkipMessage?.trim();
349
+ return msg || undefined;
350
+ }
351
+ function maybeSkipForSmartSmoke(testInfo) {
352
+ const rootDir = testInfo.project?.rootDir ?? process.cwd();
353
+ const lookup = loadSmartSmokeSelectionLookup(rootDir);
354
+ if (!lookup)
355
+ return;
356
+ const testsFolder = (0, utils_1.getEnvVar)('TESTCHIMP_TESTS_FOLDER') || 'tests';
357
+ const paths = (0, utils_1.derivePathsFromTestInfo)(testInfo, testsFolder, rootDir);
358
+ if (isLocatorSelected(paths, lookup.selection.selectedTests, lookup.keySet))
359
+ return;
360
+ testInfo.annotations.push({ type: 'skip-reason', description: exports.SMART_SMOKE_SKIP_REASON });
361
+ testInfo.skip(true, exports.SMART_SMOKE_SKIP_REASON);
362
+ }
363
+ function toWireLocator(loc) {
364
+ const n = normalizeLocator(loc);
365
+ return {
366
+ folder_path: n.folderPath || [],
367
+ file_name: n.fileName || '',
368
+ test_suite: n.testSuite || [],
369
+ test_name: n.testName || '',
370
+ };
371
+ }
372
+ function fromWireLocator(raw) {
373
+ return normalizeLocator({
374
+ folder_path: raw.folder_path,
375
+ folderPath: raw.folderPath,
376
+ file_name: raw.file_name,
377
+ fileName: raw.fileName,
378
+ test_suite: raw.test_suite,
379
+ testSuite: raw.testSuite,
380
+ test_name: raw.test_name,
381
+ testName: raw.testName,
382
+ });
383
+ }
384
+ //# sourceMappingURL=smart-smoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-smoke.js","sourceRoot":"","sources":["../src/smart-smoke.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;AAwDH,kCAIC;AAED,oCAIC;AAGD,0DAqEC;AAED,kEAUC;AAED,gDAOC;AAED,gDAOC;AAED,4CAUC;AAED,gCAUC;AAED,sCAEC;AAED,wDAgCC;AAWD,sCAoBC;AAMD,4CAkBC;AAED,wEAKC;AAED,oEASC;AAWD,gFAEC;AAMD,sEAkCC;AAED,kEAIC;AAED,sEAQC;AAGD,sCASC;AAED,8CAQC;AAED,4EAiBC;AAED,wDAaC;AAED,sCAQC;AAED,0CAWC;AAjcD,4CAAoB;AACpB,gDAAwB;AAExB,mCAQiB;AAwbR,8FA7bP,qBAAa,OA6bO;AAtbT,QAAA,uBAAuB,GAAG,aAAa,CAAC;AACxC,QAAA,8BAA8B,GAAG,uCAAuC,CAAC;AAwCtF,SAAgB,WAAW,CAAC,KAAgC;IAC1D,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7C,OAAO,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC;AACnC,CAAC;AAED,SAAgB,YAAY,CAAC,GAAW;IACtC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAClB,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;AACrE,CAAC;AAED,qFAAqF;AACrF,SAAgB,uBAAuB,CACrC,OAAkD,EAClD,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,OAAO,IAAI,EAAE,CAAC;IAE1B,MAAM,WAAW,GAAG,GAAG,CAAC,+BAA+B,EAAE,IAAI,EAAE,CAAC;IAChE,MAAM,WAAW,GAAG,GAAG,CAAC,sCAAsC,EAAE,IAAI,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,GAAG,CAAC,0CAA0C,EAAE,IAAI,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,GAAG,CAAC,kCAAkC,EAAE,IAAI,EAAE,CAAC;IAC/D,MAAM,cAAc,GAAG,GAAG,CAAC,wCAAwC,CAAC;IAEpE,IAAI,QAA4B,CAAC;IACjC,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,QAAQ,GAAG,CAAC,CAAC;IAChD,CAAC;SAAM,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAChE,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC1B,CAAC;IAED,IAAI,eAAmC,CAAC;IACxC,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,eAAe,GAAG,CAAC,CAAC;IACvD,CAAC;SAAM,IAAI,OAAO,GAAG,CAAC,eAAe,KAAK,QAAQ,IAAI,GAAG,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QAC9E,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC;IACxC,CAAC;IAED,IAAI,iBAAqC,CAAC;IAC1C,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,iBAAiB,GAAG,CAAC,CAAC;IACzD,CAAC;SAAM,IAAI,OAAO,GAAG,CAAC,iBAAiB,KAAK,QAAQ,IAAI,GAAG,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC;QAClF,iBAAiB,GAAG,GAAG,CAAC,iBAAiB,CAAC;IAC5C,CAAC;IAED,IAAI,WAAW,GAAa,EAAE,CAAC;IAC/B,IAAI,OAAO,EAAE,CAAC;QACZ,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxE,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1C,WAAW,GAAG,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,gBAAgB,GAAG,cAAc,IAAI,IAAI,IAAI,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QACrF,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC;QAC7B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAElC,IAAI,0BAA0B,GAAG,KAAK,CAAC;IACvC,IACE,OAAO;QACP,CAAC,gBAAgB;QACjB,QAAQ,IAAI,IAAI;QAChB,eAAe,IAAI,IAAI;QACvB,iBAAiB,IAAI,IAAI,EACzB,CAAC;QACD,eAAe,GAAG,EAAE,CAAC;QACrB,0BAA0B,GAAG,IAAI,CAAC;IACpC,CAAC;IAED,OAAO;QACL,OAAO;QACP,QAAQ;QACR,eAAe;QACf,iBAAiB;QACjB,WAAW;QACX,gBAAgB;QAChB,0BAA0B;KAC3B,CAAC;AACJ,CAAC;AAED,SAAgB,2BAA2B,CAAC,MAAkB;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,GAAG,GAAI,CAAuC,CAAC,GAAG,CAAC;QACzD,MAAM,GAAG,GAAG,GAAG,EAAE,mBAAmB,CAAC;QACrC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACnC,OAAO,GAAoC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,kBAAkB,CAAC,UAAyC;IAC1E,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,IAAI,GAAG,IAAA,mCAA2B,EAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC;IACnE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,SAAgB,kBAAkB,CAAC,KAAmB;IACpD,OAAO;QACL,UAAU,EAAE,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC;QAChD,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;QACrE,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC;AACJ,CAAC;AAED,SAAgB,gBAAgB,CAAC,GAAoB;IACnD,MAAM,MAAM,GACV,GAAG,CAAC,WAAW;QACf,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAgC,CAAC,CAAC,CAAC;IAC9G,OAAO;QACL,UAAU,EAAE,kBAAkB,CAAC,MAAM,CAAC;QACtC,QAAQ,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE;QAC7C,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,IAAI,EAAE;QAChD,QAAQ,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE;KAC9C,CAAC;AACJ,CAAC;AAED,SAAgB,UAAU,CAAC,GAAoB;IAC7C,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC7F,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,OAAO;QACL,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAChB,CAAC,CAAC,QAAQ,IAAI,EAAE;QAChB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;QACpB,CAAC,CAAC,QAAQ,IAAI,EAAE;KACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAgB,aAAa,CAAC,CAAkB,EAAE,CAAkB;IAClE,OAAO,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAgB,sBAAsB,CACpC,KAAY,EACZ,WAAmB,EACnB,OAAe,EACf,WAAqB;IAErB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,MAAM,eAAe,GAAsB,EAAE,CAAC;IAC9C,MAAM,WAAW,GAAsB,EAAE,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAErC,MAAM,KAAK,GAAG,CAAC,CAAQ,EAAE,EAAE;QACzB,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,IAAA,mBAAW,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;YACD,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7E,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACpB,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7B,KAAK,CAAC,KAAK,CAAC,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,KAAK,CAAC,CAAC;IACb,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,eAAe,CAAC,IAAc,EAAE,gBAA6B;IACpE,MAAM,IAAI,GAAI,IAA4B,CAAC,IAAI,CAAC;IAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5D,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACzD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,aAAa,CAAC,QAAgB;IAC5C,IAAI,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,IAAI,YAAE,CAAC,UAAU,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC;YACtD,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACnE,iFAAiF;YACjF,IAAI,YAAE,CAAC,UAAU,CAAC,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC;gBAC3D,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,iEAAiE;YACjE,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,GAAG,cAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,SAA6B,EAAE,UAA8B;IAC5F,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAC1G,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAY,CAAC;QACrE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAC7B,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,KAAK,CAAC,OAAO,CAAE,GAAkC,CAAC,YAAY,CAAC;gBAC/D,CAAC,CAAE,GAAmC,CAAC,YAAY;gBACnD,CAAC,CAAC,KAAK,CAAC,OAAO,CAAE,GAAmC,CAAC,aAAa,CAAC;oBACjE,CAAC,CAAE,GAAoC,CAAC,aAAa;oBACrD,CAAC,CAAC,EAAE,CAAC;QACX,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,CAAC,EAAwB,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAC;aACvE,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAgB,8BAA8B,CAAC,iBAAyB,OAAO,CAAC,GAAG,EAAE;IACnF,OAAO,CACL,IAAA,iBAAS,EAAC,sCAAsC,CAAC;QACjD,cAAI,CAAC,IAAI,CAAC,cAAc,EAAE,sCAA8B,CAAC,CAC1D,CAAC;AACJ,CAAC;AAED,SAAgB,4BAA4B,CAC1C,cAAsB,EACtB,OAAgC;IAEhC,MAAM,QAAQ,GAAG,8BAA8B,CAAC,cAAc,CAAC,CAAC;IAChE,YAAE,CAAC,SAAS,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACrE,kCAAkC,EAAE,CAAC;IACrC,OAAO,QAAQ,CAAC;AAClB,CAAC;AASD,IAAI,cAAc,GAA+B,IAAI,CAAC;AAEtD,SAAgB,kCAAkC;IAChD,cAAc,GAAG,IAAI,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,SAAgB,6BAA6B,CAC3C,iBAAyB,OAAO,CAAC,GAAG,EAAE;IAEtC,mFAAmF;IACnF,+DAA+D;IAC/D,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,EAAE,CAAC;QAC5D,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,QAAQ,GAAG,8BAA8B,CAAC,cAAc,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACjC,IACE,cAAc;YACd,cAAc,CAAC,QAAQ,KAAK,QAAQ;YACpC,cAAc,CAAC,OAAO,KAAK,EAAE,CAAC,OAAO,EACrC,CAAC;YACD,OAAO,EAAE,SAAS,EAAE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC;QAChF,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA4B,CAAC;QACxF,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvE,cAAc,GAAG,IAAI,CAAC;YACtB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,SAAS,GAA4B;YACzC,GAAG,MAAM;YACT,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC;SAC1D,CAAC;QACF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1E,cAAc,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QACtE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,cAAc,GAAG,IAAI,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAgB,2BAA2B,CACzC,iBAAyB,OAAO,CAAC,GAAG,EAAE;IAEtC,OAAO,6BAA6B,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC;AAClE,CAAC;AAED,SAAgB,6BAA6B,CAAC,QAAmC;IAC/E,IAAI,CAAC,QAAQ;QAAE,OAAO;IACtB,IAAI,CAAC;QACH,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IACD,kCAAkC,EAAE,CAAC;AACvC,CAAC;AAED,2EAA2E;AAC3E,SAAgB,aAAa,CAAC,GAAG,KAA0B;IACzD,MAAM,GAAG,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAChC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,SAAgB,iBAAiB,CAC/B,KAAmB,EACnB,QAA2B,EAC3B,MAAoB;IAEpB,MAAM,GAAG,GAAG,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,SAAgB,gCAAgC,CAC9C,WAAuE,EACvE,qBAA8B;IAE9B,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,qBAAqB;QAAE,OAAO,SAAS,CAAC;IACrE,KAAK,MAAM,CAAC,IAAI,WAAW,IAAI,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;YACtD,OAAO,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,WAAW,IAAI,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;YACrE,OAAO,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,qBAAqB,EAAE,IAAI,EAAE,CAAC;IAC1C,OAAO,GAAG,IAAI,SAAS,CAAC;AAC1B,CAAC;AAED,SAAgB,sBAAsB,CAAC,QAItC;IACC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3D,MAAM,MAAM,GAAG,6BAA6B,CAAC,OAAO,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,MAAM,WAAW,GAAG,IAAA,iBAAS,EAAC,wBAAwB,CAAC,IAAI,OAAO,CAAC;IACnE,MAAM,KAAK,GAAG,IAAA,+BAAuB,EAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACtE,IAAI,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO;IACpF,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,+BAAuB,EAAE,CAAC,CAAC;IACzF,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,+BAAuB,CAAC,CAAC;AAC/C,CAAC;AAED,SAAgB,aAAa,CAAC,GAAoB;IAChD,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE;QAC/B,SAAS,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;QAC3B,UAAU,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE;QAC7B,SAAS,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;KAC5B,CAAC;AACJ,CAAC;AAED,SAAgB,eAAe,CAAC,GAA4B;IAC1D,OAAO,gBAAgB,CAAC;QACtB,WAAW,EAAE,GAAG,CAAC,WAAmC;QACpD,UAAU,EAAE,GAAG,CAAC,UAA2C;QAC3D,SAAS,EAAE,GAAG,CAAC,SAA+B;QAC9C,QAAQ,EAAE,GAAG,CAAC,QAA8B;QAC5C,UAAU,EAAE,GAAG,CAAC,UAAkC;QAClD,SAAS,EAAE,GAAG,CAAC,SAAiC;QAChD,SAAS,EAAE,GAAG,CAAC,SAA+B;QAC9C,QAAQ,EAAE,GAAG,CAAC,QAA8B;KAC7C,CAAC,CAAC;AACL,CAAC"}
@@ -33,6 +33,8 @@ export declare class TestChimpReporter implements Reporter {
33
33
  /** Path we wrote for this run; unlinked in onEnd when write succeeded. */
34
34
  private batchInvocationFileWrittenPath;
35
35
  private shouldUnlinkBatchInvocationFile;
36
+ /** Smart-smoke selection sidecar written in onBegin; unlinked in onEnd. */
37
+ private smartSmokeSelectionFilePath;
36
38
  private testsFolder;
37
39
  private testExecutions;
38
40
  private testRetryInfo;
@@ -54,7 +56,7 @@ export declare class TestChimpReporter implements Reporter {
54
56
  /** Idempotency: same journey execution id must not POST journey_execution_end twice (CI + platform + finally). */
55
57
  private exploreChimpJourneyEndSentIds;
56
58
  constructor(options?: TestChimpReporterOptions);
57
- onBegin(config: FullConfig, suite: Suite): void;
59
+ onBegin(config: FullConfig, suite: Suite): Promise<void>;
58
60
  private loadJobManifest;
59
61
  /**
60
62
  * Resolve jobId from the platform manifest.
@@ -90,6 +92,12 @@ export declare class TestChimpReporter implements Reporter {
90
92
  onEnd(result: FullResult): Promise<void>;
91
93
  /** Align ExploreChimp workers with suite batch id (env then file); same path as {@link readTestChimpBatchInvocationId}. */
92
94
  private writeSuiteBatchInvocationFileForExploreChimp;
95
+ /**
96
+ * When TESTCHIMP_SMART_SMOKE_ENABLED, select a subset and write a sidecar for workers.
97
+ * When disabled, remove any leftover sidecar so a prior crashed run cannot skip the suite.
98
+ */
99
+ private maybeRunSmartSmokeSelection;
100
+ private naiveLocalSuiteSlice;
93
101
  private unlinkSuiteBatchInvocationFileIfWritten;
94
102
  private getTestKey;
95
103
  private platformFinalizeTestEnd;
@@ -1 +1 @@
1
- {"version":3,"file":"testchimp-reporter.d.ts","sourceRoot":"","sources":["../src/testchimp-reporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testchimp-reporter.d.ts","sourceRoot":"","sources":["../src/testchimp-reporter.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,7 @@ const utils_1 = require("./utils");
14
14
  const index_1 = require("./explorechimp/index");
15
15
  const analytics_step_screen_state_registry_1 = require("./explorechimp/analytics-step-screen-state-registry");
16
16
  const capture_1 = require("./api-coverage/capture");
17
+ const smart_smoke_1 = require("./smart-smoke");
17
18
  const path_1 = __importDefault(require("path"));
18
19
  function resolveDurationMs(reportedDurationMs, startedAtMillis, completedAtMillis) {
19
20
  if (typeof reportedDurationMs === 'number' &&
@@ -47,6 +48,8 @@ class TestChimpReporter {
47
48
  /** Path we wrote for this run; unlinked in onEnd when write succeeded. */
48
49
  this.batchInvocationFileWrittenPath = null;
49
50
  this.shouldUnlinkBatchInvocationFile = false;
51
+ /** Smart-smoke selection sidecar written in onBegin; unlinked in onEnd. */
52
+ this.smartSmokeSelectionFilePath = null;
50
53
  this.testsFolder = '';
51
54
  // Track test executions (keyed by test ID + attempt, e.g. "testId_attempt_0", "testId_attempt_1").
52
55
  // In platform mode we keep all attempts until test_end so the job detail we send includes full retryAttemptLogs.
@@ -95,7 +98,7 @@ class TestChimpReporter {
95
98
  executionMode
96
99
  };
97
100
  }
98
- onBegin(config, suite) {
101
+ async onBegin(config, suite) {
99
102
  this.config = config;
100
103
  this.batchInvocationId = (0, utils_1.getEnvVar)('TESTCHIMP_BATCH_INVOCATION_ID', this.options.batchInvocationId) || (0, utils_1.generateUUID)();
101
104
  this.writeSuiteBatchInvocationFileForExploreChimp();
@@ -121,6 +124,7 @@ class TestChimpReporter {
121
124
  if (!apiKey && this.options.executionMode !== 'repair') {
122
125
  console.warn('[TestChimp] Missing TESTCHIMP_API_KEY. Reporting disabled.');
123
126
  this.isEnabled = false;
127
+ await this.maybeRunSmartSmokeSelection(suite, null);
124
128
  return;
125
129
  }
126
130
  this.apiClient = new api_client_1.TestChimpApiClient(backendUrl, apiKey || 'local-repair', projectId || '', this.options.verbose);
@@ -157,6 +161,7 @@ class TestChimpReporter {
157
161
  }
158
162
  // Scan suite to understand retry configuration
159
163
  this.scanTestRetries(suite);
164
+ await this.maybeRunSmartSmokeSelection(suite, this.apiClient);
160
165
  }
161
166
  loadJobManifest() {
162
167
  const manifestPath = (0, utils_1.getEnvVar)('TESTCHIMP_JOB_MANIFEST_PATH') ||
@@ -245,11 +250,16 @@ class TestChimpReporter {
245
250
  buildFinalJobDetailForPlatform(test, result, testName, currentSteps) {
246
251
  const status = this.mapStatus(result.status);
247
252
  const jobDetail = this.buildJobDetailFromAttempts(test.id, testName, result.retry, true, status, result.error?.message);
253
+ const annotations = (0, annotations_1.collectPlaywrightAnnotations)(test, result);
254
+ const skipReason = status === types_1.SmartTestExecutionStatus.SMART_TEST_EXECUTION_SKIPPED
255
+ ? (0, smart_smoke_1.resolveSkipReasonFromAnnotations)(annotations, result.error?.message)
256
+ : undefined;
248
257
  return {
249
258
  ...jobDetail,
250
259
  steps: [...currentSteps],
251
260
  pwError: this.toPlaywrightError(result.error),
252
- annotations: (0, annotations_1.collectPlaywrightAnnotations)(test, result),
261
+ annotations,
262
+ skipReason,
253
263
  };
254
264
  }
255
265
  onTestBegin(test, result) {
@@ -648,6 +658,8 @@ class TestChimpReporter {
648
658
  }
649
659
  finally {
650
660
  this.unlinkSuiteBatchInvocationFileIfWritten();
661
+ (0, smart_smoke_1.unlinkSmartSmokeSelectionFile)(this.smartSmokeSelectionFilePath);
662
+ this.smartSmokeSelectionFilePath = null;
651
663
  }
652
664
  }
653
665
  // ============================================================================
@@ -669,6 +681,96 @@ class TestChimpReporter {
669
681
  this.shouldUnlinkBatchInvocationFile = false;
670
682
  }
671
683
  }
684
+ /**
685
+ * When TESTCHIMP_SMART_SMOKE_ENABLED, select a subset and write a sidecar for workers.
686
+ * When disabled, remove any leftover sidecar so a prior crashed run cannot skip the suite.
687
+ */
688
+ async maybeRunSmartSmokeSelection(suite, apiClient) {
689
+ const rootDir = this.config?.rootDir || process.cwd();
690
+ const useOpts = (0, smart_smoke_1.readSmartSmokeUseFromConfig)(this.config);
691
+ const smoke = (0, smart_smoke_1.resolveSmartSmokeConfig)(useOpts);
692
+ if (!smoke.enabled) {
693
+ (0, smart_smoke_1.unlinkSmartSmokeSelectionFile)((0, smart_smoke_1.getSmartSmokeSelectionFilePath)(rootDir));
694
+ return;
695
+ }
696
+ if (smoke.usedDefaultSuitePercentage) {
697
+ console.warn('[TestChimp] Smart-smoke: no size constraint from env or use.testchimpSmartSmoke — defaulting to suitePercentage=20');
698
+ }
699
+ const branchName = (0, utils_1.getBranchName)();
700
+ const plansRoot = (0, smart_smoke_1.findPlansRoot)(rootDir);
701
+ if (!plansRoot) {
702
+ console.warn(`[TestChimp] Smart-smoke: could not find plans root (.testchimp-plans or plans/) under ${rootDir}; related-tests.json will be empty`);
703
+ }
704
+ else if (!branchName) {
705
+ console.warn('[TestChimp] Smart-smoke: branch name unresolved (set TESTCHIMP_BRANCH_NAME); related-tests.json will be empty');
706
+ }
707
+ const relatedTests = (0, smart_smoke_1.loadRelatedTests)(plansRoot, branchName);
708
+ const { suiteCandidates, taggedTests } = (0, smart_smoke_1.collectSuiteCandidates)(suite, this.testsFolder, rootDir, smoke.includeTags);
709
+ const mustInclude = (0, smart_smoke_1.unionLocators)(relatedTests, taggedTests);
710
+ let selected;
711
+ if (smoke.relatedTestsOnly) {
712
+ selected = (0, smart_smoke_1.unionLocators)(relatedTests);
713
+ console.log(`[TestChimp] Smart-smoke related-tests-only: ${selected.length} test(s) from related-tests.json (branch=${branchName || '(unknown)'})`);
714
+ }
715
+ else if (apiClient) {
716
+ try {
717
+ // Phase-1 server only uses suite_candidates when must_include is empty — omit otherwise
718
+ // to avoid large POST bodies on big suites.
719
+ const resp = await apiClient.selectSmartSmokeTests({
720
+ related_tests: relatedTests.map(smart_smoke_1.toWireLocator),
721
+ include_tags: smoke.includeTags,
722
+ tagged_tests: taggedTests.map(smart_smoke_1.toWireLocator),
723
+ suite_candidates: mustInclude.length === 0 ? suiteCandidates.map(smart_smoke_1.toWireLocator) : [],
724
+ max_time_budget_mins: smoke.maxTimeBudgetMins,
725
+ max_tests: smoke.maxTests,
726
+ suite_percentage: smoke.suitePercentage,
727
+ branch_name: branchName,
728
+ environment: this.options.environment || undefined,
729
+ });
730
+ selected = (resp.selectedTests || []).map((r) => (0, smart_smoke_1.fromWireLocator)(r));
731
+ console.log(`[TestChimp] Smart-smoke selection API returned ${selected.length} test(s) (candidates=${suiteCandidates.length}, related=${relatedTests.length}, tagged=${taggedTests.length})`);
732
+ }
733
+ catch (e) {
734
+ selected = mustInclude;
735
+ console.warn(`[TestChimp] Smart-smoke selection API failed; falling back to related∪tagged (${selected.length}):`, e);
736
+ if (selected.length === 0 && suiteCandidates.length > 0) {
737
+ selected = this.naiveLocalSuiteSlice(suiteCandidates, smoke);
738
+ console.warn(`[TestChimp] Smart-smoke local naive slice: ${selected.length} of ${suiteCandidates.length}`);
739
+ }
740
+ }
741
+ }
742
+ else {
743
+ selected = mustInclude;
744
+ if (selected.length === 0 && suiteCandidates.length > 0) {
745
+ selected = this.naiveLocalSuiteSlice(suiteCandidates, smoke);
746
+ }
747
+ console.warn(`[TestChimp] Smart-smoke: no API client; local selection ${selected.length} test(s)`);
748
+ }
749
+ if (selected.length === 0) {
750
+ console.warn('[TestChimp] Smart-smoke: selection is empty — all tests will be skipped. Check related-tests.json / tags / budget.');
751
+ }
752
+ try {
753
+ this.smartSmokeSelectionFilePath = (0, smart_smoke_1.writeSmartSmokeSelectionFile)(rootDir, {
754
+ enabled: true,
755
+ selectedTests: selected,
756
+ relatedTestsOnly: smoke.relatedTestsOnly,
757
+ branchName,
758
+ });
759
+ console.log(`[TestChimp] Smart-smoke selection written: ${this.smartSmokeSelectionFilePath} (${selected.length} test(s))`);
760
+ }
761
+ catch (e) {
762
+ console.error('[TestChimp] Smart-smoke: failed to write selection file:', e);
763
+ this.smartSmokeSelectionFilePath = null;
764
+ }
765
+ }
766
+ naiveLocalSuiteSlice(suiteCandidates, smoke) {
767
+ const pct = smoke.suitePercentage ?? 20;
768
+ let n = Math.max(1, Math.ceil(suiteCandidates.length * (pct / 100)));
769
+ if (smoke.maxTests != null && smoke.maxTests > 0) {
770
+ n = Math.min(n, smoke.maxTests);
771
+ }
772
+ return suiteCandidates.slice(0, n);
773
+ }
672
774
  unlinkSuiteBatchInvocationFileIfWritten() {
673
775
  if (!this.shouldUnlinkBatchInvocationFile || !this.batchInvocationFileWrittenPath)
674
776
  return;
@@ -882,6 +984,9 @@ class TestChimpReporter {
882
984
  const executionContext = (0, execution_context_1.buildExecutionDeviceContext)(test);
883
985
  const completedAtMillis = Date.now();
884
986
  const annotations = (0, annotations_1.collectPlaywrightAnnotations)(test, result);
987
+ const skipReason = status === types_1.SmartTestExecutionStatus.SMART_TEST_EXECUTION_SKIPPED
988
+ ? (0, smart_smoke_1.resolveSkipReasonFromAnnotations)(annotations, result.error?.message)
989
+ : undefined;
885
990
  const report = {
886
991
  folderPath: paths.folderPath,
887
992
  fileName: paths.fileName,
@@ -900,6 +1005,7 @@ class TestChimpReporter {
900
1005
  executionContext,
901
1006
  gitCommitSha,
902
1007
  annotations,
1008
+ skipReason,
903
1009
  },
904
1010
  startedAtMillis: execution.startedAt,
905
1011
  completedAtMillis,