@clipboard-health/playwright-flake-linter 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -0
- package/package.json +32 -0
- package/src/bin/cli.d.ts +2 -0
- package/src/bin/cli.js +26 -0
- package/src/bin/cli.js.map +1 -0
- package/src/bin/runCli.d.ts +7 -0
- package/src/bin/runCli.js +29 -0
- package/src/bin/runCli.js.map +1 -0
- package/src/index.d.ts +3 -0
- package/src/index.js +11 -0
- package/src/index.js.map +1 -0
- package/src/lib/internal/violations.d.ts +2 -0
- package/src/lib/internal/violations.js +16 -0
- package/src/lib/internal/violations.js.map +1 -0
- package/src/lib/playwrightFlakeLinter.d.ts +47 -0
- package/src/lib/playwrightFlakeLinter.js +640 -0
- package/src/lib/playwrightFlakeLinter.js.map +1 -0
- package/src/lib/projectLinter.d.ts +11 -0
- package/src/lib/projectLinter.js +55 -0
- package/src/lib/projectLinter.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @clipboard-health/playwright-flake-linter
|
|
2
|
+
|
|
3
|
+
Shared, configurable TypeScript AST checks for Playwright flake anti-patterns.
|
|
4
|
+
The rule implementation lives in this package; consuming repositories provide
|
|
5
|
+
only their paths, helper names, mechanism names, and justified exceptions.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --save-dev @clipboard-health/playwright-flake-linter
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
TypeScript is a runtime dependency because the checker uses the compiler API;
|
|
14
|
+
`glob` provides the repository-standard source discovery used by `embedex`.
|
|
15
|
+
Both are actively maintained, commercially compatible (Apache-2.0 and ISC),
|
|
16
|
+
already standardized in this monorepo, and the CLI is not included in
|
|
17
|
+
application bundles.
|
|
18
|
+
|
|
19
|
+
## Configure
|
|
20
|
+
|
|
21
|
+
Create `playwright-flake-lint.config.mjs` at the repository root:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
export default {
|
|
25
|
+
scanRoots: ["playwright"],
|
|
26
|
+
hardenedIdentityHelperNames: ["generateRandomUserEmail"],
|
|
27
|
+
identityHelperMinimumLengths: {
|
|
28
|
+
generateRandomAlphaNumericString: 24,
|
|
29
|
+
generateRandomString: 26,
|
|
30
|
+
},
|
|
31
|
+
retryHelperNames: ["retry"],
|
|
32
|
+
specificRequestMatcherNames: ["isMatchingRequest"],
|
|
33
|
+
transientClassifierNamePatterns: ["^isRetryable", "retryClassification"],
|
|
34
|
+
undiscriminatingRetryHelperNames: ["retryUntilPassOrTimeout", "toPass"],
|
|
35
|
+
sharedReadinessMechanisms: [
|
|
36
|
+
{
|
|
37
|
+
name: "Home Health response readiness",
|
|
38
|
+
filePathPattern: "playwright/e2e/homeHealth/.*\\.spec\\.ts$",
|
|
39
|
+
directCallNames: ["waitForResponse"],
|
|
40
|
+
sharedHelperNames: ["waitForHomeHealthResponse"],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The mobile repository can use its own genuine names without changing a rule:
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
export default {
|
|
50
|
+
scanRoots: ["playwright"],
|
|
51
|
+
identityHelperMinimumLengths: {
|
|
52
|
+
mobileRandomSuffix: 32,
|
|
53
|
+
},
|
|
54
|
+
retryHelperNames: ["retryMobileAction"],
|
|
55
|
+
specificRequestMatcherNames: ["matchesMobileRequest"],
|
|
56
|
+
transientClassifierNamePatterns: ["^isTransientMobile"],
|
|
57
|
+
sharedReadinessMechanisms: [
|
|
58
|
+
{
|
|
59
|
+
name: "BottomSheet readiness",
|
|
60
|
+
filePathPattern: "playwright/e2e/sheets/.*\\.spec\\.ts$",
|
|
61
|
+
directCallNames: ["waitForResponse"],
|
|
62
|
+
sharedHelperNames: ["waitForBottomSheet"],
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
All pattern fields are JavaScript regular-expression source strings. Optional
|
|
69
|
+
configuration:
|
|
70
|
+
|
|
71
|
+
| Field | Purpose |
|
|
72
|
+
| ---------------------------------- | ------------------------------------------------------------------- |
|
|
73
|
+
| `allowlist` | Reason-required repository exceptions by rule and file pattern |
|
|
74
|
+
| `hardenedIdentityHelperNames` | Identity helpers that are safe without a length argument |
|
|
75
|
+
| `identityHelperMinimumLengths` | Repository random-helper names and their safe minimum lengths |
|
|
76
|
+
| `identityNamePattern` | Names treated as parallel-worker-sensitive identities |
|
|
77
|
+
| `responseWaitCallNames` | Repository response-wait utility names |
|
|
78
|
+
| `retryHelperNames` | Retry utilities whose callbacks must classify transient failures |
|
|
79
|
+
| `sharedReadinessMechanisms` | File/mechanism registry mapping direct gates to shared helpers |
|
|
80
|
+
| `specificRequestMatcherNames` | Delegated helpers that fully discriminate a response request |
|
|
81
|
+
| `specFilePattern` | Files where fixed-sleep checks apply |
|
|
82
|
+
| `transientClassifierNamePatterns` | Classifier names accepted inside retry callbacks |
|
|
83
|
+
| `undiscriminatingRetryHelperNames` | Utilities that inherently retry any failure and are always rejected |
|
|
84
|
+
|
|
85
|
+
`sharedReadinessMechanisms[].name` is the diagnostic label, so repositories can
|
|
86
|
+
use their native terminology such as `Dialog` or `BottomSheet`.
|
|
87
|
+
|
|
88
|
+
## Wire into CI
|
|
89
|
+
|
|
90
|
+
Add the executable to the repository's existing verification chain:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"scripts": {
|
|
95
|
+
"architecture:check": "existing-checks && playwright-flake-lint"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Use a non-default config location with
|
|
101
|
+
`playwright-flake-lint --config path/to/config.mjs`.
|
|
102
|
+
|
|
103
|
+
## Rules
|
|
104
|
+
|
|
105
|
+
| Rule ID | Anti-pattern | Required alternative |
|
|
106
|
+
| ---------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
107
|
+
| `fixed-sleep` | `waitForTimeout` or `setTimeout` delays in specs | Rubric B2: use a deterministic readiness signal |
|
|
108
|
+
| `response-wait` | Status/`.ok()` response predicates without specific request data | Rubric B2: match method, URL, and a discriminating request predicate |
|
|
109
|
+
| `retry-classification` | Retry utilities invoked without transient-only classification | Rubric B1: classify transient failures and fail fast otherwise |
|
|
110
|
+
| `test-data-identity` | Low-entropy identities or bypasses of hardened random helpers | Rubric A2: use configured hardened or UUID-backed identities |
|
|
111
|
+
| `shared-readiness` | Per-spec readiness gates where a shared mechanism helper exists | Rubric A1: use or extend the configured shared helper |
|
|
112
|
+
|
|
113
|
+
## Allowlisting
|
|
114
|
+
|
|
115
|
+
Prefer fixing a violation. A justified inline exception must immediately
|
|
116
|
+
precede the violating statement and include a reason:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// flake-lint-allow fixed-sleep -- The timer fixture verifies elapsed product time.
|
|
120
|
+
await page.waitForTimeout(100);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
A repository-level exception also requires a reason:
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
export default {
|
|
127
|
+
scanRoots: ["playwright"],
|
|
128
|
+
allowlist: [
|
|
129
|
+
{
|
|
130
|
+
ruleId: "fixed-sleep",
|
|
131
|
+
filePathPattern: "playwright/e2e/legacy/timer\\.spec\\.ts$",
|
|
132
|
+
reason: "The timer fixture verifies elapsed product time.",
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Comments or config entries without a non-empty reason do not suppress a
|
|
139
|
+
violation.
|
|
140
|
+
|
|
141
|
+
## Future shared rules
|
|
142
|
+
|
|
143
|
+
The existing per-repository Dialog/query-list checks are a candidate for this
|
|
144
|
+
package. Their component-name difference (`Dialog` in admin and `BottomSheet`
|
|
145
|
+
in mobile) belongs in repository config when that rule is migrated; this
|
|
146
|
+
package does not change those checks yet.
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clipboard-health/playwright-flake-linter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared configurable checks for Playwright flake anti-patterns.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"flaky-tests",
|
|
7
|
+
"lint",
|
|
8
|
+
"playwright",
|
|
9
|
+
"testing"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/ClipboardHealth/core-utils.git",
|
|
15
|
+
"directory": "packages/playwright-flake-linter"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"playwright-flake-lint": "./src/bin/cli.js"
|
|
19
|
+
},
|
|
20
|
+
"type": "commonjs",
|
|
21
|
+
"main": "./src/index.js",
|
|
22
|
+
"typings": "./src/index.d.ts",
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"glob": "13.0.6",
|
|
28
|
+
"tslib": "2.8.1",
|
|
29
|
+
"typescript": "5.9.3"
|
|
30
|
+
},
|
|
31
|
+
"types": "./src/index.d.ts"
|
|
32
|
+
}
|
package/src/bin/cli.d.ts
ADDED
package/src/bin/cli.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const runCli_1 = require("./runCli");
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const exitCode = await (0, runCli_1.runCli)({
|
|
8
|
+
arguments_: process.argv.slice(2),
|
|
9
|
+
cwd: process.cwd(),
|
|
10
|
+
writeError: (output) => {
|
|
11
|
+
process.stderr.write(output);
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
process.exitCode = exitCode;
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
process.stderr.write(`${getErrorMessage(error)}\n`);
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function getErrorMessage(error) {
|
|
22
|
+
return error instanceof Error ? error.message : String(error);
|
|
23
|
+
}
|
|
24
|
+
// eslint-disable-next-line unicorn/prefer-top-level-await -- the published CLI is CommonJS
|
|
25
|
+
void main();
|
|
26
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../../packages/playwright-flake-linter/src/bin/cli.ts"],"names":[],"mappings":";;;AAEA,qCAAkC;AAElC,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAA,eAAM,EAAC;YAC5B,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACjC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE;gBACrB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC;SACF,CAAC,CAAC;QACH,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,2FAA2F;AAC3F,KAAK,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runCli = runCli;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
|
+
const projectLinter_1 = require("../lib/projectLinter");
|
|
7
|
+
const DEFAULT_CONFIG_FILE_NAME = "playwright-flake-lint.config.mjs";
|
|
8
|
+
async function runCli({ arguments_, cwd, writeError }) {
|
|
9
|
+
const configFilePath = node_path_1.default.resolve(cwd, getConfigFilePath(arguments_));
|
|
10
|
+
const config = await (0, projectLinter_1.loadPlaywrightFlakeLinterConfig)({ configFilePath });
|
|
11
|
+
const violations = await (0, projectLinter_1.lintPlaywrightProject)({ config, cwd });
|
|
12
|
+
for (const violation of violations) {
|
|
13
|
+
writeError(`${violation.filePath}:${violation.line}:${violation.column} ` +
|
|
14
|
+
`[${violation.ruleId}] ${violation.message}. ` +
|
|
15
|
+
`For a justified exception, add // flake-lint-allow ` +
|
|
16
|
+
`${violation.ruleId} -- <reason>.\n`);
|
|
17
|
+
}
|
|
18
|
+
return violations.length === 0 ? 0 : 1;
|
|
19
|
+
}
|
|
20
|
+
function getConfigFilePath(arguments_) {
|
|
21
|
+
if (arguments_.length === 0) {
|
|
22
|
+
return DEFAULT_CONFIG_FILE_NAME;
|
|
23
|
+
}
|
|
24
|
+
if (arguments_.length === 2 && arguments_[0] === "--config" && arguments_[1] !== undefined) {
|
|
25
|
+
return arguments_[1];
|
|
26
|
+
}
|
|
27
|
+
throw new Error("Usage: playwright-flake-lint [--config <config-file-path>]");
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=runCli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runCli.js","sourceRoot":"","sources":["../../../../../packages/playwright-flake-linter/src/bin/runCli.ts"],"names":[],"mappings":";;;;AAAA,kEAA6B;AAE7B,wDAA8F;AAE9F,MAAM,wBAAwB,GAAG,kCAAkC,CAAC;AAQ7D,KAAK,iBAAiB,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAgB;IACxE,MAAM,cAAc,GAAG,mBAAI,CAAC,OAAO,CAAC,GAAG,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,MAAM,IAAA,+CAA+B,EAAC,EAAE,cAAc,EAAE,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,MAAM,IAAA,qCAAqB,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAEhE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,UAAU,CACR,GAAG,SAAS,CAAC,QAAQ,IAAI,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,MAAM,GAAG;YAC5D,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,OAAO,IAAI;YAC9C,qDAAqD;YACrD,GAAG,SAAS,CAAC,MAAM,iBAAiB,CACvC,CAAC;IACJ,CAAC;IAED,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,iBAAiB,CAAC,UAA6B;IACtD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,wBAAwB,CAAC;IAClC,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC3F,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;AAChF,CAAC"}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { PlaywrightFlakeLinterAllowlistEntry, PlaywrightFlakeLinterConfig, PlaywrightFlakePatternViolation, PlaywrightFlakeRuleId, SharedReadinessMechanism, } from "./lib/playwrightFlakeLinter";
|
|
2
|
+
export { definePlaywrightFlakeLinterConfig, findPlaywrightFlakePatternViolations, PLAYWRIGHT_FLAKE_RULE_IDS, } from "./lib/playwrightFlakeLinter";
|
|
3
|
+
export { lintPlaywrightProject, loadPlaywrightFlakeLinterConfig } from "./lib/projectLinter";
|
package/src/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadPlaywrightFlakeLinterConfig = exports.lintPlaywrightProject = exports.PLAYWRIGHT_FLAKE_RULE_IDS = exports.findPlaywrightFlakePatternViolations = exports.definePlaywrightFlakeLinterConfig = void 0;
|
|
4
|
+
var playwrightFlakeLinter_1 = require("./lib/playwrightFlakeLinter");
|
|
5
|
+
Object.defineProperty(exports, "definePlaywrightFlakeLinterConfig", { enumerable: true, get: function () { return playwrightFlakeLinter_1.definePlaywrightFlakeLinterConfig; } });
|
|
6
|
+
Object.defineProperty(exports, "findPlaywrightFlakePatternViolations", { enumerable: true, get: function () { return playwrightFlakeLinter_1.findPlaywrightFlakePatternViolations; } });
|
|
7
|
+
Object.defineProperty(exports, "PLAYWRIGHT_FLAKE_RULE_IDS", { enumerable: true, get: function () { return playwrightFlakeLinter_1.PLAYWRIGHT_FLAKE_RULE_IDS; } });
|
|
8
|
+
var projectLinter_1 = require("./lib/projectLinter");
|
|
9
|
+
Object.defineProperty(exports, "lintPlaywrightProject", { enumerable: true, get: function () { return projectLinter_1.lintPlaywrightProject; } });
|
|
10
|
+
Object.defineProperty(exports, "loadPlaywrightFlakeLinterConfig", { enumerable: true, get: function () { return projectLinter_1.loadPlaywrightFlakeLinterConfig; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/playwright-flake-linter/src/index.ts"],"names":[],"mappings":";;;AAOA,qEAIqC;AAHnC,0IAAA,iCAAiC,OAAA;AACjC,6IAAA,oCAAoC,OAAA;AACpC,kIAAA,yBAAyB,OAAA;AAE3B,qDAA6F;AAApF,sHAAA,qBAAqB,OAAA;AAAE,gIAAA,+BAA+B,OAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compareViolations = compareViolations;
|
|
4
|
+
function compareViolations(first, second) {
|
|
5
|
+
return (compareStrings({ first: first.filePath, second: second.filePath }) ||
|
|
6
|
+
first.line - second.line ||
|
|
7
|
+
first.column - second.column ||
|
|
8
|
+
compareStrings({ first: first.ruleId, second: second.ruleId }));
|
|
9
|
+
}
|
|
10
|
+
function compareStrings({ first, second }) {
|
|
11
|
+
if (first === second) {
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
return first < second ? -1 : 1;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=violations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violations.js","sourceRoot":"","sources":["../../../../../../packages/playwright-flake-linter/src/lib/internal/violations.ts"],"names":[],"mappings":";;;AAEA,2BACE,KAAsC,EACtC,MAAuC;IAEvC,OAAO,CACL,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI;QACxB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;QAC5B,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAC/D,CAAC;AACJ,CAAC;AAOD,SAAS,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,EAAwB;IAC7D,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare const PLAYWRIGHT_FLAKE_RULE_IDS: readonly ["fixed-sleep", "response-wait", "retry-classification", "test-data-identity", "shared-readiness"];
|
|
2
|
+
export type PlaywrightFlakeRuleId = (typeof PLAYWRIGHT_FLAKE_RULE_IDS)[number];
|
|
3
|
+
export interface PlaywrightFlakeLinterAllowlistEntry {
|
|
4
|
+
filePathPattern: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
ruleId: PlaywrightFlakeRuleId;
|
|
7
|
+
}
|
|
8
|
+
export interface SharedReadinessMechanism {
|
|
9
|
+
directCallNames: readonly string[];
|
|
10
|
+
filePathPattern: string;
|
|
11
|
+
name: string;
|
|
12
|
+
sharedHelperNames: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export interface PlaywrightFlakeLinterConfig {
|
|
15
|
+
allowlist?: readonly PlaywrightFlakeLinterAllowlistEntry[];
|
|
16
|
+
hardenedIdentityHelperNames?: readonly string[];
|
|
17
|
+
identityHelperMinimumLengths?: Readonly<Record<string, number>>;
|
|
18
|
+
identityNamePattern?: string;
|
|
19
|
+
responseWaitCallNames?: readonly string[];
|
|
20
|
+
retryHelperNames?: readonly string[];
|
|
21
|
+
scanRoots: readonly string[];
|
|
22
|
+
sharedReadinessMechanisms?: readonly SharedReadinessMechanism[];
|
|
23
|
+
specificRequestMatcherNames?: readonly string[];
|
|
24
|
+
specFilePattern?: string;
|
|
25
|
+
transientClassifierNamePatterns?: readonly string[];
|
|
26
|
+
undiscriminatingRetryHelperNames?: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
export interface PlaywrightFlakePatternViolation {
|
|
29
|
+
column: number;
|
|
30
|
+
filePath: string;
|
|
31
|
+
line: number;
|
|
32
|
+
message: string;
|
|
33
|
+
ruleId: PlaywrightFlakeRuleId;
|
|
34
|
+
}
|
|
35
|
+
interface FindPlaywrightFlakePatternViolationsParams {
|
|
36
|
+
config: PlaywrightFlakeLinterConfig;
|
|
37
|
+
filePath: string;
|
|
38
|
+
source: string;
|
|
39
|
+
}
|
|
40
|
+
interface ParsePlaywrightFlakeLinterConfigParams {
|
|
41
|
+
sourceDescription: string;
|
|
42
|
+
value: unknown;
|
|
43
|
+
}
|
|
44
|
+
export declare function definePlaywrightFlakeLinterConfig(config: PlaywrightFlakeLinterConfig): PlaywrightFlakeLinterConfig;
|
|
45
|
+
export declare function parsePlaywrightFlakeLinterConfig({ sourceDescription, value, }: ParsePlaywrightFlakeLinterConfigParams): PlaywrightFlakeLinterConfig;
|
|
46
|
+
export declare function findPlaywrightFlakePatternViolations({ config, filePath, source, }: FindPlaywrightFlakePatternViolationsParams): PlaywrightFlakePatternViolation[];
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PLAYWRIGHT_FLAKE_RULE_IDS = void 0;
|
|
4
|
+
exports.definePlaywrightFlakeLinterConfig = definePlaywrightFlakeLinterConfig;
|
|
5
|
+
exports.parsePlaywrightFlakeLinterConfig = parsePlaywrightFlakeLinterConfig;
|
|
6
|
+
exports.findPlaywrightFlakePatternViolations = findPlaywrightFlakePatternViolations;
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
9
|
+
const typescript_1 = tslib_1.__importDefault(require("typescript"));
|
|
10
|
+
const violations_1 = require("./internal/violations");
|
|
11
|
+
exports.PLAYWRIGHT_FLAKE_RULE_IDS = [
|
|
12
|
+
"fixed-sleep",
|
|
13
|
+
"response-wait",
|
|
14
|
+
"retry-classification",
|
|
15
|
+
"test-data-identity",
|
|
16
|
+
"shared-readiness",
|
|
17
|
+
];
|
|
18
|
+
const PLAYWRIGHT_FLAKE_RULE_ID_SET = new Set(exports.PLAYWRIGHT_FLAKE_RULE_IDS);
|
|
19
|
+
const ALLOWLIST_PREFIX = "flake-lint-allow";
|
|
20
|
+
const DEFAULT_IDENTITY_NAME_PATTERN = "(address|email|identifier|license|message|name|phone|street|suffix|title|id$)";
|
|
21
|
+
const DEFAULT_RESPONSE_WAIT_CALL_NAMES = ["waitForResponse"];
|
|
22
|
+
const DEFAULT_SPECIFIC_REQUEST_MATCHER_NAMES = ["isMatchingRequest"];
|
|
23
|
+
const DEFAULT_SPEC_FILE_PATTERN = String.raw `\.spec\.[cm]?[jt]sx?$`;
|
|
24
|
+
const DEFAULT_TRANSIENT_CLASSIFIER_NAME_PATTERNS = ["^isRetryable", "retryClassification"];
|
|
25
|
+
const RULE_MESSAGES = {
|
|
26
|
+
"fixed-sleep": "Fixed sleep anti-pattern (rubric B2). Replace waitForTimeout/setTimeout delays with a deterministic readiness signal",
|
|
27
|
+
"response-wait": "Undiscriminating response-wait anti-pattern (rubric B2). Match the request method, URL, and a discriminating request predicate",
|
|
28
|
+
"retry-classification": "Undiscriminating retry anti-pattern (rubric B1). Retry only failures classified as transient and fail fast for genuine failures",
|
|
29
|
+
"test-data-identity": "Low-entropy parallel-worker identity collision anti-pattern (rubric A2). Use a configured hardened random helper or UUID-backed identity",
|
|
30
|
+
};
|
|
31
|
+
function definePlaywrightFlakeLinterConfig(config) {
|
|
32
|
+
validateConfig(config);
|
|
33
|
+
return config;
|
|
34
|
+
}
|
|
35
|
+
function parsePlaywrightFlakeLinterConfig({ sourceDescription, value, }) {
|
|
36
|
+
if (!isPlaywrightFlakeLinterConfig(value)) {
|
|
37
|
+
throw new Error(`Invalid Playwright flake linter config at ${sourceDescription}.`);
|
|
38
|
+
}
|
|
39
|
+
return definePlaywrightFlakeLinterConfig(value);
|
|
40
|
+
}
|
|
41
|
+
function findPlaywrightFlakePatternViolations({ config, filePath, source, }) {
|
|
42
|
+
validateConfig(config);
|
|
43
|
+
const normalizedFilePath = normalizeFilePath(filePath);
|
|
44
|
+
const sourceFile = typescript_1.default.createSourceFile(normalizedFilePath, source, typescript_1.default.ScriptTarget.Latest, true, getScriptKind(normalizedFilePath));
|
|
45
|
+
const violations = [];
|
|
46
|
+
const isSpecFile = new RegExp(config.specFilePattern ?? DEFAULT_SPEC_FILE_PATTERN).test(normalizedFilePath);
|
|
47
|
+
const sharedReadinessMechanisms = getMatchingSharedReadinessMechanisms({
|
|
48
|
+
config,
|
|
49
|
+
filePath: normalizedFilePath,
|
|
50
|
+
});
|
|
51
|
+
function addViolation({ message, node, ruleId }) {
|
|
52
|
+
if (hasInlineAllowlistComment({
|
|
53
|
+
node,
|
|
54
|
+
ruleId,
|
|
55
|
+
source,
|
|
56
|
+
sourceFile,
|
|
57
|
+
}) ||
|
|
58
|
+
isAllowlistedByConfig({
|
|
59
|
+
config,
|
|
60
|
+
filePath: normalizedFilePath,
|
|
61
|
+
ruleId,
|
|
62
|
+
})) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
66
|
+
violations.push({
|
|
67
|
+
column: position.character + 1,
|
|
68
|
+
filePath: normalizedFilePath,
|
|
69
|
+
line: position.line + 1,
|
|
70
|
+
message,
|
|
71
|
+
ruleId,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function visit(node) {
|
|
75
|
+
if (typescript_1.default.isCallExpression(node)) {
|
|
76
|
+
if (isSpecFile && isFixedSleepCall(node)) {
|
|
77
|
+
addViolation({
|
|
78
|
+
message: RULE_MESSAGES["fixed-sleep"],
|
|
79
|
+
node,
|
|
80
|
+
ruleId: "fixed-sleep",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (isConfiguredCall({
|
|
84
|
+
callExpression: node,
|
|
85
|
+
names: getResponseWaitCallNames(config),
|
|
86
|
+
}) &&
|
|
87
|
+
hasUndiscriminatingResponsePredicate({
|
|
88
|
+
callExpression: node,
|
|
89
|
+
specificRequestMatcherNames: config.specificRequestMatcherNames ?? DEFAULT_SPECIFIC_REQUEST_MATCHER_NAMES,
|
|
90
|
+
})) {
|
|
91
|
+
addViolation({
|
|
92
|
+
message: RULE_MESSAGES["response-wait"],
|
|
93
|
+
node,
|
|
94
|
+
ruleId: "response-wait",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
for (const mechanism of sharedReadinessMechanisms) {
|
|
98
|
+
if (!mechanism.directCallNames.includes(getCallName(node) ?? "")) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
addViolation({
|
|
102
|
+
message: getSharedReadinessMessage(mechanism),
|
|
103
|
+
node,
|
|
104
|
+
ruleId: "shared-readiness",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (isUndiscriminatingRetryCall({ callExpression: node, config })) {
|
|
108
|
+
addViolation({
|
|
109
|
+
message: RULE_MESSAGES["retry-classification"],
|
|
110
|
+
node,
|
|
111
|
+
ruleId: "retry-classification",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (isLowEntropyTestDataIdentityCall({ callExpression: node, config })) {
|
|
115
|
+
addViolation({
|
|
116
|
+
message: RULE_MESSAGES["test-data-identity"],
|
|
117
|
+
node,
|
|
118
|
+
ruleId: "test-data-identity",
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
typescript_1.default.forEachChild(node, visit);
|
|
123
|
+
}
|
|
124
|
+
visit(sourceFile);
|
|
125
|
+
return violations.toSorted(violations_1.compareViolations);
|
|
126
|
+
}
|
|
127
|
+
function validateConfig(config) {
|
|
128
|
+
if (config.scanRoots.length === 0 ||
|
|
129
|
+
config.scanRoots.some((scanRoot) => scanRoot.trim().length === 0)) {
|
|
130
|
+
throw new Error("Playwright flake linter config requires at least one scan root.");
|
|
131
|
+
}
|
|
132
|
+
for (const allowlistEntry of config.allowlist ?? []) {
|
|
133
|
+
if (allowlistEntry.reason.trim().length === 0) {
|
|
134
|
+
throw new Error("Every Playwright flake linter allowlist reason must be non-empty.");
|
|
135
|
+
}
|
|
136
|
+
validatePattern({
|
|
137
|
+
label: "allowlist file path",
|
|
138
|
+
pattern: allowlistEntry.filePathPattern,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
validateOptionalPattern({
|
|
142
|
+
label: "spec file",
|
|
143
|
+
pattern: config.specFilePattern,
|
|
144
|
+
});
|
|
145
|
+
validateOptionalPattern({
|
|
146
|
+
label: "identity name",
|
|
147
|
+
pattern: config.identityNamePattern,
|
|
148
|
+
});
|
|
149
|
+
for (const pattern of config.transientClassifierNamePatterns ?? []) {
|
|
150
|
+
validatePattern({ label: "transient classifier name", pattern });
|
|
151
|
+
}
|
|
152
|
+
for (const [helperName, minimumLength] of Object.entries(config.identityHelperMinimumLengths ?? {})) {
|
|
153
|
+
if (helperName.trim().length === 0 || !Number.isInteger(minimumLength) || minimumLength <= 0) {
|
|
154
|
+
throw new Error("Identity helper minimum lengths require a non-empty helper name and positive integer.");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const mechanism of config.sharedReadinessMechanisms ?? []) {
|
|
158
|
+
if (mechanism.name.trim().length === 0 ||
|
|
159
|
+
mechanism.directCallNames.length === 0 ||
|
|
160
|
+
mechanism.sharedHelperNames.length === 0) {
|
|
161
|
+
throw new Error("Shared readiness mechanisms require a name, direct call, and shared helper.");
|
|
162
|
+
}
|
|
163
|
+
validatePattern({
|
|
164
|
+
label: `${mechanism.name} file path`,
|
|
165
|
+
pattern: mechanism.filePathPattern,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function validateOptionalPattern({ label, pattern }) {
|
|
170
|
+
if (pattern !== undefined) {
|
|
171
|
+
validatePattern({ label, pattern });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function validatePattern({ label, pattern }) {
|
|
175
|
+
try {
|
|
176
|
+
new RegExp(pattern).test("");
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
throw new Error(`Invalid ${label} pattern: ${pattern}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function isFixedSleepCall(callExpression) {
|
|
183
|
+
const { expression } = callExpression;
|
|
184
|
+
const isQualifiedSetTimeout = typescript_1.default.isPropertyAccessExpression(expression) &&
|
|
185
|
+
expression.name.text === "setTimeout" &&
|
|
186
|
+
typescript_1.default.isIdentifier(expression.expression) &&
|
|
187
|
+
["globalThis", "self", "window"].includes(expression.expression.text);
|
|
188
|
+
return ((typescript_1.default.isPropertyAccessExpression(expression) && expression.name.text === "waitForTimeout") ||
|
|
189
|
+
isQualifiedSetTimeout ||
|
|
190
|
+
(typescript_1.default.isIdentifier(expression) && expression.text === "setTimeout"));
|
|
191
|
+
}
|
|
192
|
+
function hasUndiscriminatingResponsePredicate({ callExpression, specificRequestMatcherNames, }) {
|
|
193
|
+
const predicate = resolveFunctionLike({
|
|
194
|
+
expression: callExpression.arguments[0],
|
|
195
|
+
referenceNode: callExpression,
|
|
196
|
+
});
|
|
197
|
+
if (predicate === undefined) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
const responseParameter = predicate.parameters[0]?.name;
|
|
201
|
+
if (responseParameter === undefined || !typescript_1.default.isIdentifier(responseParameter)) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
const responseName = responseParameter.text;
|
|
205
|
+
let checksStatus = false;
|
|
206
|
+
let delegatesSpecificRequestMatching = false;
|
|
207
|
+
let checksMethod = false;
|
|
208
|
+
let checksUrl = false;
|
|
209
|
+
let checksDiscriminatingRequestProperty = false;
|
|
210
|
+
function visitResultDependency(node) {
|
|
211
|
+
if (typescript_1.default.isCallExpression(node)) {
|
|
212
|
+
checksStatus ||= isDirectResponseCall({
|
|
213
|
+
callExpression: node,
|
|
214
|
+
methodNames: ["ok", "status"],
|
|
215
|
+
responseName,
|
|
216
|
+
});
|
|
217
|
+
delegatesSpecificRequestMatching ||=
|
|
218
|
+
typescript_1.default.isIdentifier(node.expression) &&
|
|
219
|
+
specificRequestMatcherNames.includes(node.expression.text);
|
|
220
|
+
checksUrl ||= isDirectResponseCall({
|
|
221
|
+
callExpression: node,
|
|
222
|
+
methodNames: ["url"],
|
|
223
|
+
responseName,
|
|
224
|
+
});
|
|
225
|
+
checksMethod ||= isResponseRequestCall({
|
|
226
|
+
callExpression: node,
|
|
227
|
+
methodNames: ["method"],
|
|
228
|
+
responseName,
|
|
229
|
+
});
|
|
230
|
+
checksDiscriminatingRequestProperty ||=
|
|
231
|
+
isResponseRequestCall({
|
|
232
|
+
callExpression: node,
|
|
233
|
+
methodNames: ["headerValue", "postData", "postDataJSON", "resourceType"],
|
|
234
|
+
responseName,
|
|
235
|
+
}) || isDynamicResponseUrlMatch({ callExpression: node, responseName });
|
|
236
|
+
}
|
|
237
|
+
if (typescript_1.default.isPropertyAccessExpression(node) && node.name.text === "searchParams") {
|
|
238
|
+
checksDiscriminatingRequestProperty = true;
|
|
239
|
+
}
|
|
240
|
+
typescript_1.default.forEachChild(node, visitResultDependency);
|
|
241
|
+
}
|
|
242
|
+
for (const resultNode of getPredicateResultDependencies(predicate)) {
|
|
243
|
+
visitResultDependency(resultNode);
|
|
244
|
+
}
|
|
245
|
+
if (!checksStatus) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
return (!delegatesSpecificRequestMatching &&
|
|
249
|
+
(!checksMethod || !checksUrl || !checksDiscriminatingRequestProperty));
|
|
250
|
+
}
|
|
251
|
+
function isDirectResponseCall({ callExpression, methodNames, responseName, }) {
|
|
252
|
+
const { expression } = callExpression;
|
|
253
|
+
return (typescript_1.default.isPropertyAccessExpression(expression) &&
|
|
254
|
+
methodNames.includes(expression.name.text) &&
|
|
255
|
+
typescript_1.default.isIdentifier(expression.expression) &&
|
|
256
|
+
expression.expression.text === responseName);
|
|
257
|
+
}
|
|
258
|
+
function isResponseRequestCall({ callExpression, methodNames, responseName, }) {
|
|
259
|
+
const { expression } = callExpression;
|
|
260
|
+
if (!typescript_1.default.isPropertyAccessExpression(expression) ||
|
|
261
|
+
!methodNames.includes(expression.name.text) ||
|
|
262
|
+
!typescript_1.default.isCallExpression(expression.expression)) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
return isDirectResponseCall({
|
|
266
|
+
callExpression: expression.expression,
|
|
267
|
+
methodNames: ["request"],
|
|
268
|
+
responseName,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function isDynamicResponseUrlMatch({ callExpression, responseName, }) {
|
|
272
|
+
const { expression } = callExpression;
|
|
273
|
+
return (typescript_1.default.isPropertyAccessExpression(expression) &&
|
|
274
|
+
["endsWith", "includes", "startsWith"].includes(expression.name.text) &&
|
|
275
|
+
typescript_1.default.isCallExpression(expression.expression) &&
|
|
276
|
+
isDirectResponseCall({
|
|
277
|
+
callExpression: expression.expression,
|
|
278
|
+
methodNames: ["url"],
|
|
279
|
+
responseName,
|
|
280
|
+
}) &&
|
|
281
|
+
callExpression.arguments.some(typescript_1.default.isTemplateExpression));
|
|
282
|
+
}
|
|
283
|
+
function getPredicateResultDependencies(predicate) {
|
|
284
|
+
if (predicate.body === undefined) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
const predicateBody = predicate.body;
|
|
288
|
+
if (!typescript_1.default.isBlock(predicateBody)) {
|
|
289
|
+
return [predicateBody];
|
|
290
|
+
}
|
|
291
|
+
const dependencies = [];
|
|
292
|
+
const initializerByName = new Map();
|
|
293
|
+
function visit(node) {
|
|
294
|
+
if (node !== predicate && typescript_1.default.isFunctionLike(node)) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (typescript_1.default.isVariableDeclaration(node) &&
|
|
298
|
+
typescript_1.default.isIdentifier(node.name) &&
|
|
299
|
+
node.initializer !== undefined) {
|
|
300
|
+
initializerByName.set(node.name.text, node.initializer);
|
|
301
|
+
}
|
|
302
|
+
if (typescript_1.default.isReturnStatement(node) && node.expression !== undefined) {
|
|
303
|
+
dependencies.push(node.expression);
|
|
304
|
+
addGoverningConditions({
|
|
305
|
+
boundary: predicateBody,
|
|
306
|
+
dependencies,
|
|
307
|
+
node,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
typescript_1.default.forEachChild(node, visit);
|
|
311
|
+
}
|
|
312
|
+
visit(predicateBody);
|
|
313
|
+
let dependencyIndex = 0;
|
|
314
|
+
while (dependencyIndex < dependencies.length) {
|
|
315
|
+
const dependency = dependencies[dependencyIndex];
|
|
316
|
+
dependencyIndex += 1;
|
|
317
|
+
if (dependency === undefined) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
addReferencedInitializers({
|
|
321
|
+
dependencies,
|
|
322
|
+
initializerByName,
|
|
323
|
+
node: dependency,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return dependencies;
|
|
327
|
+
}
|
|
328
|
+
function addReferencedInitializers({ dependencies, initializerByName, node, }) {
|
|
329
|
+
if (typescript_1.default.isIdentifier(node)) {
|
|
330
|
+
const initializer = initializerByName.get(node.text);
|
|
331
|
+
if (initializer !== undefined && !dependencies.includes(initializer)) {
|
|
332
|
+
dependencies.push(initializer);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
typescript_1.default.forEachChild(node, (childNode) => {
|
|
336
|
+
addReferencedInitializers({
|
|
337
|
+
dependencies,
|
|
338
|
+
initializerByName,
|
|
339
|
+
node: childNode,
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function addGoverningConditions({ boundary, dependencies, node, }) {
|
|
344
|
+
let ancestor = node.parent;
|
|
345
|
+
while (ancestor !== undefined && ancestor !== boundary) {
|
|
346
|
+
if (typescript_1.default.isIfStatement(ancestor)) {
|
|
347
|
+
dependencies.push(ancestor.expression);
|
|
348
|
+
}
|
|
349
|
+
ancestor = ancestor.parent;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function resolveFunctionLike({ expression, referenceNode, }) {
|
|
353
|
+
if (expression === undefined) {
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
if (typescript_1.default.isArrowFunction(expression) || typescript_1.default.isFunctionExpression(expression)) {
|
|
357
|
+
return expression;
|
|
358
|
+
}
|
|
359
|
+
if (!typescript_1.default.isIdentifier(expression)) {
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
let scope = referenceNode.parent;
|
|
363
|
+
while (scope !== undefined) {
|
|
364
|
+
if (typescript_1.default.isBlock(scope) || typescript_1.default.isSourceFile(scope)) {
|
|
365
|
+
const declaration = findFunctionLikeInStatements({
|
|
366
|
+
functionName: expression.text,
|
|
367
|
+
statements: scope.statements,
|
|
368
|
+
});
|
|
369
|
+
if (declaration !== undefined) {
|
|
370
|
+
return declaration;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
scope = scope.parent;
|
|
374
|
+
}
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
function findFunctionLikeInStatements({ functionName, statements, }) {
|
|
378
|
+
for (const statement of statements) {
|
|
379
|
+
if (typescript_1.default.isFunctionDeclaration(statement) && statement.name?.text === functionName) {
|
|
380
|
+
return statement;
|
|
381
|
+
}
|
|
382
|
+
if (!typescript_1.default.isVariableStatement(statement)) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
386
|
+
if (typescript_1.default.isIdentifier(declaration.name) &&
|
|
387
|
+
declaration.name.text === functionName &&
|
|
388
|
+
declaration.initializer !== undefined &&
|
|
389
|
+
(typescript_1.default.isArrowFunction(declaration.initializer) ||
|
|
390
|
+
typescript_1.default.isFunctionExpression(declaration.initializer))) {
|
|
391
|
+
return declaration.initializer;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
function isUndiscriminatingRetryCall({ callExpression, config, }) {
|
|
398
|
+
const callName = getCallName(callExpression);
|
|
399
|
+
if (callName === undefined) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
if ((config.undiscriminatingRetryHelperNames ?? []).includes(callName)) {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
if (!(config.retryHelperNames ?? []).includes(callName)) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
const callback = resolveFunctionLike({
|
|
409
|
+
expression: callExpression.arguments[0],
|
|
410
|
+
referenceNode: callExpression,
|
|
411
|
+
});
|
|
412
|
+
if (callback === undefined) {
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
const classifierPatterns = (config.transientClassifierNamePatterns ?? DEFAULT_TRANSIENT_CLASSIFIER_NAME_PATTERNS).map((pattern) => new RegExp(pattern));
|
|
416
|
+
return !usesTransientClassifierToGovernRetry({
|
|
417
|
+
callback,
|
|
418
|
+
classifierPatterns,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
function usesTransientClassifierToGovernRetry({ callback, classifierPatterns, }) {
|
|
422
|
+
if (callback.body === undefined || !typescript_1.default.isBlock(callback.body)) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
const bailParameter = callback.parameters[0]?.name;
|
|
426
|
+
if (bailParameter === undefined || !typescript_1.default.isIdentifier(bailParameter)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
const bailParameterName = bailParameter.text;
|
|
430
|
+
const dependencies = [];
|
|
431
|
+
const initializerByName = new Map();
|
|
432
|
+
const callbackBody = callback.body;
|
|
433
|
+
function visit(node) {
|
|
434
|
+
if (node !== callback && typescript_1.default.isFunctionLike(node)) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (typescript_1.default.isVariableDeclaration(node) &&
|
|
438
|
+
typescript_1.default.isIdentifier(node.name) &&
|
|
439
|
+
node.initializer !== undefined) {
|
|
440
|
+
initializerByName.set(node.name.text, node.initializer);
|
|
441
|
+
}
|
|
442
|
+
if (typescript_1.default.isCallExpression(node) &&
|
|
443
|
+
typescript_1.default.isIdentifier(node.expression) &&
|
|
444
|
+
node.expression.text === bailParameterName) {
|
|
445
|
+
addGoverningConditions({
|
|
446
|
+
boundary: callbackBody,
|
|
447
|
+
dependencies,
|
|
448
|
+
node,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
typescript_1.default.forEachChild(node, visit);
|
|
452
|
+
}
|
|
453
|
+
visit(callbackBody);
|
|
454
|
+
for (const dependency of dependencies) {
|
|
455
|
+
addReferencedInitializers({
|
|
456
|
+
dependencies,
|
|
457
|
+
initializerByName,
|
|
458
|
+
node: dependency,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return dependencies.some((dependency) => containsClassifierReference({
|
|
462
|
+
classifierPatterns,
|
|
463
|
+
node: dependency,
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
466
|
+
function containsClassifierReference({ classifierPatterns, node, }) {
|
|
467
|
+
if (typescript_1.default.isIdentifier(node) && classifierPatterns.some((pattern) => pattern.test(node.text))) {
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
return node.getChildren().some((childNode) => containsClassifierReference({
|
|
471
|
+
classifierPatterns,
|
|
472
|
+
node: childNode,
|
|
473
|
+
}));
|
|
474
|
+
}
|
|
475
|
+
function isLowEntropyTestDataIdentityCall({ callExpression, config, }) {
|
|
476
|
+
const identityOwnerName = findIdentityContextName(callExpression);
|
|
477
|
+
if (identityOwnerName === undefined ||
|
|
478
|
+
!new RegExp(config.identityNamePattern ?? DEFAULT_IDENTITY_NAME_PATTERN, "i").test(identityOwnerName)) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
const callName = getCallName(callExpression);
|
|
482
|
+
if (callName !== undefined && (config.hardenedIdentityHelperNames ?? []).includes(callName)) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
if (isLowEntropyBuiltInIdentitySource(callExpression)) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
if (callName === undefined || !(callName in (config.identityHelperMinimumLengths ?? {}))) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const [lengthArgument] = callExpression.arguments;
|
|
492
|
+
if (lengthArgument === undefined || !typescript_1.default.isNumericLiteral(lengthArgument)) {
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
const minimumLength = config.identityHelperMinimumLengths?.[callName];
|
|
496
|
+
return minimumLength !== undefined && Number(lengthArgument.text) < minimumLength;
|
|
497
|
+
}
|
|
498
|
+
function isLowEntropyBuiltInIdentitySource(callExpression) {
|
|
499
|
+
const { expression } = callExpression;
|
|
500
|
+
return (typescript_1.default.isPropertyAccessExpression(expression) &&
|
|
501
|
+
((expression.expression.getText() === "Date" && expression.name.text === "now") ||
|
|
502
|
+
(expression.expression.getText() === "Math" && expression.name.text === "random")));
|
|
503
|
+
}
|
|
504
|
+
function findIdentityContextName(node) {
|
|
505
|
+
let ancestor = node.parent;
|
|
506
|
+
while (ancestor !== undefined) {
|
|
507
|
+
if (typescript_1.default.isVariableDeclaration(ancestor) && typescript_1.default.isIdentifier(ancestor.name)) {
|
|
508
|
+
return ancestor.name.text;
|
|
509
|
+
}
|
|
510
|
+
if (typescript_1.default.isPropertyAssignment(ancestor)) {
|
|
511
|
+
return ancestor.name.getText();
|
|
512
|
+
}
|
|
513
|
+
if (typescript_1.default.isCallExpression(ancestor) &&
|
|
514
|
+
typescript_1.default.isPropertyAccessExpression(ancestor.expression) &&
|
|
515
|
+
ancestor.expression.name.text === "fill") {
|
|
516
|
+
return collectStringLiteralText(ancestor);
|
|
517
|
+
}
|
|
518
|
+
if (typescript_1.default.isStatement(ancestor)) {
|
|
519
|
+
return undefined;
|
|
520
|
+
}
|
|
521
|
+
ancestor = ancestor.parent;
|
|
522
|
+
}
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
525
|
+
function collectStringLiteralText(node) {
|
|
526
|
+
const stringValues = [];
|
|
527
|
+
function visit(descendant) {
|
|
528
|
+
if (typescript_1.default.isStringLiteralLike(descendant)) {
|
|
529
|
+
stringValues.push(descendant.text);
|
|
530
|
+
}
|
|
531
|
+
typescript_1.default.forEachChild(descendant, visit);
|
|
532
|
+
}
|
|
533
|
+
visit(node);
|
|
534
|
+
return stringValues.join(" ");
|
|
535
|
+
}
|
|
536
|
+
function hasInlineAllowlistComment({ node, ruleId, source, sourceFile, }) {
|
|
537
|
+
const allowlistPattern = new RegExp(`${ALLOWLIST_PREFIX}\\s+${escapeRegExp(ruleId)}\\s+--\\s+\\S`);
|
|
538
|
+
let currentNode = node;
|
|
539
|
+
while (currentNode !== undefined && currentNode !== sourceFile) {
|
|
540
|
+
const leadingCommentRanges = typescript_1.default.getLeadingCommentRanges(source, currentNode.getFullStart()) ?? [];
|
|
541
|
+
if (leadingCommentRanges.some((range) => allowlistPattern.test(source.slice(range.pos, range.end)))) {
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
if (typescript_1.default.isStatement(currentNode)) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
currentNode = currentNode.parent;
|
|
548
|
+
}
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
function isAllowlistedByConfig({ config, filePath, ruleId }) {
|
|
552
|
+
return (config.allowlist ?? []).some((entry) => entry.ruleId === ruleId && new RegExp(entry.filePathPattern).test(filePath));
|
|
553
|
+
}
|
|
554
|
+
function getMatchingSharedReadinessMechanisms({ config, filePath, }) {
|
|
555
|
+
return (config.sharedReadinessMechanisms ?? []).filter((mechanism) => new RegExp(mechanism.filePathPattern).test(filePath));
|
|
556
|
+
}
|
|
557
|
+
function getSharedReadinessMessage(mechanism) {
|
|
558
|
+
return (`Per-spec ${mechanism.name} gate anti-pattern (rubric A1 shared-helper rule). ` +
|
|
559
|
+
`Use or extend ${mechanism.sharedHelperNames.join(" or ")}`);
|
|
560
|
+
}
|
|
561
|
+
function getResponseWaitCallNames(config) {
|
|
562
|
+
return config.responseWaitCallNames ?? DEFAULT_RESPONSE_WAIT_CALL_NAMES;
|
|
563
|
+
}
|
|
564
|
+
function isConfiguredCall({ callExpression, names }) {
|
|
565
|
+
const callName = getCallName(callExpression);
|
|
566
|
+
return callName !== undefined && names.includes(callName);
|
|
567
|
+
}
|
|
568
|
+
function getCallName(callExpression) {
|
|
569
|
+
const { expression } = callExpression;
|
|
570
|
+
if (typescript_1.default.isIdentifier(expression)) {
|
|
571
|
+
return expression.text;
|
|
572
|
+
}
|
|
573
|
+
if (typescript_1.default.isPropertyAccessExpression(expression)) {
|
|
574
|
+
return expression.name.text;
|
|
575
|
+
}
|
|
576
|
+
return undefined;
|
|
577
|
+
}
|
|
578
|
+
function getScriptKind(filePath) {
|
|
579
|
+
return filePath.endsWith("x") ? typescript_1.default.ScriptKind.TSX : typescript_1.default.ScriptKind.TS;
|
|
580
|
+
}
|
|
581
|
+
function normalizeFilePath(filePath) {
|
|
582
|
+
return filePath.replaceAll(node_path_1.default.sep, "/");
|
|
583
|
+
}
|
|
584
|
+
function isPlaywrightFlakeLinterConfig(value) {
|
|
585
|
+
if (!isRecord(value) || !isStringArray(value["scanRoots"])) {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
return (isOptionalString(value["specFilePattern"]) &&
|
|
589
|
+
isOptionalString(value["identityNamePattern"]) &&
|
|
590
|
+
isOptionalStringArray(value["hardenedIdentityHelperNames"]) &&
|
|
591
|
+
isOptionalStringArray(value["responseWaitCallNames"]) &&
|
|
592
|
+
isOptionalStringArray(value["retryHelperNames"]) &&
|
|
593
|
+
isOptionalStringArray(value["specificRequestMatcherNames"]) &&
|
|
594
|
+
isOptionalStringArray(value["transientClassifierNamePatterns"]) &&
|
|
595
|
+
isOptionalStringArray(value["undiscriminatingRetryHelperNames"]) &&
|
|
596
|
+
isOptionalNumberRecord(value["identityHelperMinimumLengths"]) &&
|
|
597
|
+
isOptionalAllowlist(value["allowlist"]) &&
|
|
598
|
+
isOptionalSharedReadinessMechanisms(value["sharedReadinessMechanisms"]));
|
|
599
|
+
}
|
|
600
|
+
function isOptionalAllowlist(value) {
|
|
601
|
+
return (value === undefined ||
|
|
602
|
+
(Array.isArray(value) &&
|
|
603
|
+
value.every((entry) => isRecord(entry) &&
|
|
604
|
+
typeof entry["filePathPattern"] === "string" &&
|
|
605
|
+
typeof entry["reason"] === "string" &&
|
|
606
|
+
isPlaywrightFlakeRuleId(entry["ruleId"]))));
|
|
607
|
+
}
|
|
608
|
+
function isOptionalSharedReadinessMechanisms(value) {
|
|
609
|
+
return (value === undefined ||
|
|
610
|
+
(Array.isArray(value) &&
|
|
611
|
+
value.every((mechanism) => isRecord(mechanism) &&
|
|
612
|
+
isStringArray(mechanism["directCallNames"]) &&
|
|
613
|
+
typeof mechanism["filePathPattern"] === "string" &&
|
|
614
|
+
typeof mechanism["name"] === "string" &&
|
|
615
|
+
isStringArray(mechanism["sharedHelperNames"]))));
|
|
616
|
+
}
|
|
617
|
+
function isPlaywrightFlakeRuleId(value) {
|
|
618
|
+
return typeof value === "string" && PLAYWRIGHT_FLAKE_RULE_ID_SET.has(value);
|
|
619
|
+
}
|
|
620
|
+
function isOptionalNumberRecord(value) {
|
|
621
|
+
return (value === undefined ||
|
|
622
|
+
(isRecord(value) &&
|
|
623
|
+
Object.values(value).every((entry) => typeof entry === "number" && Number.isFinite(entry))));
|
|
624
|
+
}
|
|
625
|
+
function isOptionalString(value) {
|
|
626
|
+
return value === undefined || typeof value === "string";
|
|
627
|
+
}
|
|
628
|
+
function isOptionalStringArray(value) {
|
|
629
|
+
return value === undefined || isStringArray(value);
|
|
630
|
+
}
|
|
631
|
+
function isStringArray(value) {
|
|
632
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
633
|
+
}
|
|
634
|
+
function isRecord(value) {
|
|
635
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
636
|
+
}
|
|
637
|
+
function escapeRegExp(value) {
|
|
638
|
+
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`);
|
|
639
|
+
}
|
|
640
|
+
//# sourceMappingURL=playwrightFlakeLinter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwrightFlakeLinter.js","sourceRoot":"","sources":["../../../../../packages/playwright-flake-linter/src/lib/playwrightFlakeLinter.ts"],"names":[],"mappings":";;;;;;;AAAA,kEAA6B;AAE7B,oEAA4B;AAE5B,sDAA0D;AAE7C,QAAA,yBAAyB,GAAG;IACvC,aAAa;IACb,eAAe;IACf,sBAAsB;IACtB,oBAAoB;IACpB,kBAAkB;CACV,CAAC;AACX,MAAM,4BAA4B,GAAwB,IAAI,GAAG,CAAC,QAAA,yBAAyB,CAAC,CAAC;AAwC7F,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAC5C,MAAM,6BAA6B,GACjC,+EAA+E,CAAC;AAClF,MAAM,gCAAgC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC7D,MAAM,sCAAsC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AACrE,MAAM,yBAAyB,GAAG,MAAM,CAAC,GAAG,CAAA,uBAAuB,CAAC;AACpE,MAAM,0CAA0C,GAAG,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;AAC3F,MAAM,aAAa,GACjB;IACE,aAAa,EACX,sHAAsH;IACxH,eAAe,EACb,gIAAgI;IAClI,sBAAsB,EACpB,iIAAiI;IACnI,oBAAoB,EAClB,0IAA0I;CAC7I,CAAC;AAmBJ,2CACE,MAAmC;IAEnC,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,0CAAiD,EAC/C,iBAAiB,EACjB,KAAK,GACkC;IACvC,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6CAA6C,iBAAiB,GAAG,CAAC,CAAC;IACrF,CAAC;IAED,OAAO,iCAAiC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED,8CAAqD,EACnD,MAAM,EACN,QAAQ,EACR,MAAM,GACqC;IAC3C,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,oBAAE,CAAC,gBAAgB,CACpC,kBAAkB,EAClB,MAAM,EACN,oBAAE,CAAC,YAAY,CAAC,MAAM,EACtB,IAAI,EACJ,aAAa,CAAC,kBAAkB,CAAC,CAClC,CAAC;IACF,MAAM,UAAU,GAAsC,EAAE,CAAC;IACzD,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,IAAI,yBAAyB,CAAC,CAAC,IAAI,CACrF,kBAAkB,CACnB,CAAC;IACF,MAAM,yBAAyB,GAAG,oCAAoC,CAAC;QACrE,MAAM;QACN,QAAQ,EAAE,kBAAkB;KAC7B,CAAC,CAAC;IAEH,SAAS,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAsB;QACjE,IACE,yBAAyB,CAAC;YACxB,IAAI;YACJ,MAAM;YACN,MAAM;YACN,UAAU;SACX,CAAC;YACF,qBAAqB,CAAC;gBACpB,MAAM;gBACN,QAAQ,EAAE,kBAAkB;gBAC5B,MAAM;aACP,CAAC,EACF,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,UAAU,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QACrF,UAAU,CAAC,IAAI,CAAC;YACd,MAAM,EAAE,QAAQ,CAAC,SAAS,GAAG,CAAC;YAC9B,QAAQ,EAAE,kBAAkB;YAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC;YACvB,OAAO;YACP,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED,SAAS,KAAK,CAAC,IAAa;QAC1B,IAAI,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,IAAI,UAAU,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,YAAY,CAAC;oBACX,OAAO,EAAE,aAAa,CAAC,aAAa,CAAC;oBACrC,IAAI;oBACJ,MAAM,EAAE,aAAa;iBACtB,CAAC,CAAC;YACL,CAAC;YAED,IACE,gBAAgB,CAAC;gBACf,cAAc,EAAE,IAAI;gBACpB,KAAK,EAAE,wBAAwB,CAAC,MAAM,CAAC;aACxC,CAAC;gBACF,oCAAoC,CAAC;oBACnC,cAAc,EAAE,IAAI;oBACpB,2BAA2B,EACzB,MAAM,CAAC,2BAA2B,IAAI,sCAAsC;iBAC/E,CAAC,EACF,CAAC;gBACD,YAAY,CAAC;oBACX,OAAO,EAAE,aAAa,CAAC,eAAe,CAAC;oBACvC,IAAI;oBACJ,MAAM,EAAE,eAAe;iBACxB,CAAC,CAAC;YACL,CAAC;YAED,KAAK,MAAM,SAAS,IAAI,yBAAyB,EAAE,CAAC;gBAClD,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;oBACjE,SAAS;gBACX,CAAC;gBAED,YAAY,CAAC;oBACX,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC;oBAC7C,IAAI;oBACJ,MAAM,EAAE,kBAAkB;iBAC3B,CAAC,CAAC;YACL,CAAC;YAED,IAAI,2BAA2B,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;gBAClE,YAAY,CAAC;oBACX,OAAO,EAAE,aAAa,CAAC,sBAAsB,CAAC;oBAC9C,IAAI;oBACJ,MAAM,EAAE,sBAAsB;iBAC/B,CAAC,CAAC;YACL,CAAC;YAED,IAAI,gCAAgC,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;gBACvE,YAAY,CAAC;oBACX,OAAO,EAAE,aAAa,CAAC,oBAAoB,CAAC;oBAC5C,IAAI;oBACJ,MAAM,EAAE,oBAAoB;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,oBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,CAAC;IAClB,OAAO,UAAU,CAAC,QAAQ,CAAC,8BAAiB,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,MAAmC;IACzD,IACE,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAC7B,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,EACjE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IAED,KAAK,MAAM,cAAc,IAAI,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QACpD,IAAI,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACvF,CAAC;QAED,eAAe,CAAC;YACd,KAAK,EAAE,qBAAqB;YAC5B,OAAO,EAAE,cAAc,CAAC,eAAe;SACxC,CAAC,CAAC;IACL,CAAC;IAED,uBAAuB,CAAC;QACtB,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,MAAM,CAAC,eAAe;KAChC,CAAC,CAAC;IACH,uBAAuB,CAAC;QACtB,KAAK,EAAE,eAAe;QACtB,OAAO,EAAE,MAAM,CAAC,mBAAmB;KACpC,CAAC,CAAC;IAEH,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,+BAA+B,IAAI,EAAE,EAAE,CAAC;QACnE,eAAe,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CACtD,MAAM,CAAC,4BAA4B,IAAI,EAAE,CAC1C,EAAE,CAAC;QACF,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;YAC7F,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,yBAAyB,IAAI,EAAE,EAAE,CAAC;QAC/D,IACE,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAClC,SAAS,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC;YACtC,SAAS,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,EACxC,CAAC;YACD,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QAED,eAAe,CAAC;YACd,KAAK,EAAE,GAAG,SAAS,CAAC,IAAI,YAAY;YACpC,OAAO,EAAE,SAAS,CAAC,eAAe;SACnC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAOD,SAAS,uBAAuB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAiC;IAChF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAOD,SAAS,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAyB;IAChE,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,WAAW,KAAK,aAAa,OAAO,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,cAAiC;IACzD,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;IACtC,MAAM,qBAAqB,GACzB,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC;QACzC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY;QACrC,oBAAE,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC;QACtC,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAExE,OAAO,CACL,CAAC,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,CAAC;QACxF,qBAAqB;QACrB,CAAC,oBAAE,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,CAAC,CAClE,CAAC;AACJ,CAAC;AAOD,SAAS,oCAAoC,CAAC,EAC5C,cAAc,EACd,2BAA2B,GACgB;IAC3C,MAAM,SAAS,GAAG,mBAAmB,CAAC;QACpC,UAAU,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;QACvC,aAAa,EAAE,cAAc;KAC9B,CAAC,CAAC;IAEH,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,iBAAiB,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAExD,IAAI,iBAAiB,KAAK,SAAS,IAAI,CAAC,oBAAE,CAAC,YAAY,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC;IAC5C,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,gCAAgC,GAAG,KAAK,CAAC;IAC7C,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,mCAAmC,GAAG,KAAK,CAAC;IAEhD,SAAS,qBAAqB,CAAC,IAAa;QAC1C,IAAI,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,YAAY,KAAK,oBAAoB,CAAC;gBACpC,cAAc,EAAE,IAAI;gBACpB,WAAW,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;gBAC7B,YAAY;aACb,CAAC,CAAC;YACH,gCAAgC;gBAC9B,oBAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;oBAChC,2BAA2B,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAC7D,SAAS,KAAK,oBAAoB,CAAC;gBACjC,cAAc,EAAE,IAAI;gBACpB,WAAW,EAAE,CAAC,KAAK,CAAC;gBACpB,YAAY;aACb,CAAC,CAAC;YACH,YAAY,KAAK,qBAAqB,CAAC;gBACrC,cAAc,EAAE,IAAI;gBACpB,WAAW,EAAE,CAAC,QAAQ,CAAC;gBACvB,YAAY;aACb,CAAC,CAAC;YACH,mCAAmC;gBACjC,qBAAqB,CAAC;oBACpB,cAAc,EAAE,IAAI;oBACpB,WAAW,EAAE,CAAC,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,CAAC;oBACxE,YAAY;iBACb,CAAC,IAAI,yBAAyB,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,oBAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC7E,mCAAmC,GAAG,IAAI,CAAC;QAC7C,CAAC;QAED,oBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,MAAM,UAAU,IAAI,8BAA8B,CAAC,SAAS,CAAC,EAAE,CAAC;QACnE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,CAAC,gCAAgC;QACjC,CAAC,CAAC,YAAY,IAAI,CAAC,SAAS,IAAI,CAAC,mCAAmC,CAAC,CACtE,CAAC;AACJ,CAAC;AAQD,SAAS,oBAAoB,CAAC,EAC5B,cAAc,EACd,WAAW,EACX,YAAY,GACO;IACnB,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;IAEtC,OAAO,CACL,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC;QACzC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1C,oBAAE,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC;QACtC,UAAU,CAAC,UAAU,CAAC,IAAI,KAAK,YAAY,CAC5C,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,EAC7B,cAAc,EACd,WAAW,EACX,YAAY,GACO;IACnB,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;IAEtC,IACE,CAAC,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC;QAC1C,CAAC,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3C,CAAC,oBAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,UAAU,CAAC,EAC3C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,oBAAoB,CAAC;QAC1B,cAAc,EAAE,UAAU,CAAC,UAAU;QACrC,WAAW,EAAE,CAAC,SAAS,CAAC;QACxB,YAAY;KACb,CAAC,CAAC;AACL,CAAC;AAOD,SAAS,yBAAyB,CAAC,EACjC,cAAc,EACd,YAAY,GACoB;IAChC,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;IAEtC,OAAO,CACL,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC;QACzC,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QACrE,oBAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,UAAU,CAAC;QAC1C,oBAAoB,CAAC;YACnB,cAAc,EAAE,UAAU,CAAC,UAAU;YACrC,WAAW,EAAE,CAAC,KAAK,CAAC;YACpB,YAAY;SACb,CAAC;QACF,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,oBAAE,CAAC,oBAAoB,CAAC,CACvD,CAAC;AACJ,CAAC;AAED,SAAS,8BAA8B,CAAC,SAAqC;IAC3E,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAC;IAErC,IAAI,CAAC,oBAAE,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,aAAa,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,YAAY,GAAc,EAAE,CAAC;IACnC,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE3D,SAAS,KAAK,CAAC,IAAa;QAC1B,IAAI,IAAI,KAAK,SAAS,IAAI,oBAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YAClD,OAAO;QACT,CAAC;QAED,IACE,oBAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC;YAC9B,oBAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1B,IAAI,CAAC,WAAW,KAAK,SAAS,EAC9B,CAAC;YACD,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,oBAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAChE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACnC,sBAAsB,CAAC;gBACrB,QAAQ,EAAE,aAAa;gBACvB,YAAY;gBACZ,IAAI;aACL,CAAC,CAAC;QACL,CAAC;QAED,oBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,CAAC;IAErB,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,OAAO,eAAe,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC;QAC7C,MAAM,UAAU,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;QACjD,eAAe,IAAI,CAAC,CAAC;QAErB,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,SAAS;QACX,CAAC;QAED,yBAAyB,CAAC;YACxB,YAAY;YACZ,iBAAiB;YACjB,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAQD,SAAS,yBAAyB,CAAC,EACjC,YAAY,EACZ,iBAAiB,EACjB,IAAI,GAC4B;IAChC,IAAI,oBAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErD,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACrE,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,oBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE;QAClC,yBAAyB,CAAC;YACxB,YAAY;YACZ,iBAAiB;YACjB,IAAI,EAAE,SAAS;SAChB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAQD,SAAS,sBAAsB,CAAC,EAC9B,QAAQ,EACR,YAAY,EACZ,IAAI,GACyB;IAC7B,IAAI,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;IAE3B,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACvD,IAAI,oBAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACzC,CAAC;QAED,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC7B,CAAC;AACH,CAAC;AAOD,SAAS,mBAAmB,CAAC,EAC3B,UAAU,EACV,aAAa,GACa;IAC1B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,oBAAE,CAAC,eAAe,CAAC,UAAU,CAAC,IAAI,oBAAE,CAAC,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1E,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,oBAAE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,KAAK,GAAwB,aAAa,CAAC,MAAM,CAAC;IAEtD,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,oBAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,oBAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,WAAW,GAAG,4BAA4B,CAAC;gBAC/C,YAAY,EAAE,UAAU,CAAC,IAAI;gBAC7B,UAAU,EAAE,KAAK,CAAC,UAAU;aAC7B,CAAC,CAAC;YAEH,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,WAAW,CAAC;YACrB,CAAC;QACH,CAAC;QAED,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAOD,SAAS,4BAA4B,CAAC,EACpC,YAAY,EACZ,UAAU,GACyB;IACnC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,oBAAE,CAAC,qBAAqB,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;YACjF,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,oBAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,SAAS;QACX,CAAC;QAED,KAAK,MAAM,WAAW,IAAI,SAAS,CAAC,eAAe,CAAC,YAAY,EAAE,CAAC;YACjE,IACE,oBAAE,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC;gBACjC,WAAW,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY;gBACtC,WAAW,CAAC,WAAW,KAAK,SAAS;gBACrC,CAAC,oBAAE,CAAC,eAAe,CAAC,WAAW,CAAC,WAAW,CAAC;oBAC1C,oBAAE,CAAC,oBAAoB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,EACnD,CAAC;gBACD,OAAO,WAAW,CAAC,WAAW,CAAC;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAOD,SAAS,2BAA2B,CAAC,EACnC,cAAc,EACd,MAAM,GAC4B;IAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE7C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,mBAAmB,CAAC;QACnC,UAAU,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;QACvC,aAAa,EAAE,cAAc;KAC9B,CAAC,CAAC;IAEH,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,kBAAkB,GAAG,CACzB,MAAM,CAAC,+BAA+B,IAAI,0CAA0C,CACrF,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,oCAAoC,CAAC;QAC3C,QAAQ;QACR,kBAAkB;KACnB,CAAC,CAAC;AACL,CAAC;AAOD,SAAS,oCAAoC,CAAC,EAC5C,QAAQ,EACR,kBAAkB,GACyB;IAC3C,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,oBAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAEnD,IAAI,aAAa,KAAK,SAAS,IAAI,CAAC,oBAAE,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,iBAAiB,GAAG,aAAa,CAAC,IAAI,CAAC;IAC7C,MAAM,YAAY,GAAc,EAAE,CAAC;IACnC,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC3D,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC;IAEnC,SAAS,KAAK,CAAC,IAAa;QAC1B,IAAI,IAAI,KAAK,QAAQ,IAAI,oBAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,OAAO;QACT,CAAC;QAED,IACE,oBAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC;YAC9B,oBAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAC1B,IAAI,CAAC,WAAW,KAAK,SAAS,EAC9B,CAAC;YACD,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1D,CAAC;QAED,IACE,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACzB,oBAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,iBAAiB,EAC1C,CAAC;YACD,sBAAsB,CAAC;gBACrB,QAAQ,EAAE,YAAY;gBACtB,YAAY;gBACZ,IAAI;aACL,CAAC,CAAC;QACL,CAAC;QAED,oBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,CAAC;IAEpB,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;QACtC,yBAAyB,CAAC;YACxB,YAAY;YACZ,iBAAiB;YACjB,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CACtC,2BAA2B,CAAC;QAC1B,kBAAkB;QAClB,IAAI,EAAE,UAAU;KACjB,CAAC,CACH,CAAC;AACJ,CAAC;AAOD,SAAS,2BAA2B,CAAC,EACnC,kBAAkB,EAClB,IAAI,GAC8B;IAClC,IAAI,oBAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC3F,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAC3C,2BAA2B,CAAC;QAC1B,kBAAkB;QAClB,IAAI,EAAE,SAAS;KAChB,CAAC,CACH,CAAC;AACJ,CAAC;AAOD,SAAS,gCAAgC,CAAC,EACxC,cAAc,EACd,MAAM,GACiC;IACvC,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAC;IAElE,IACE,iBAAiB,KAAK,SAAS;QAC/B,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,mBAAmB,IAAI,6BAA6B,EAAE,GAAG,CAAC,CAAC,IAAI,CAChF,iBAAiB,CAClB,EACD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE7C,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5F,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,iCAAiC,CAAC,cAAc,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACzF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC;IAElD,IAAI,cAAc,KAAK,SAAS,IAAI,CAAC,oBAAE,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,CAAC;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,CAAC,4BAA4B,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEtE,OAAO,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC;AACpF,CAAC;AAED,SAAS,iCAAiC,CAAC,cAAiC;IAC1E,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;IAEtC,OAAO,CACL,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC;QACzC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC;YAC7E,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CACrF,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAa;IAC5C,IAAI,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;IAE3B,OAAO,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,oBAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,IAAI,oBAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzE,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5B,CAAC;QAED,IAAI,oBAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,CAAC;QAED,IACE,oBAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC;YAC7B,oBAAE,CAAC,0BAA0B,CAAC,QAAQ,CAAC,UAAU,CAAC;YAClD,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EACxC,CAAC;YACD,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,oBAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAa;IAC7C,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,SAAS,KAAK,CAAC,UAAmB;QAChC,IAAI,oBAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;YACvC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAED,oBAAE,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AASD,SAAS,yBAAyB,CAAC,EACjC,IAAI,EACJ,MAAM,EACN,MAAM,EACN,UAAU,GACsB;IAChC,MAAM,gBAAgB,GAAG,IAAI,MAAM,CACjC,GAAG,gBAAgB,OAAO,YAAY,CAAC,MAAM,CAAC,eAAe,CAC9D,CAAC;IACF,IAAI,WAAW,GAAwB,IAAI,CAAC;IAE5C,OAAO,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,UAAU,EAAE,CAAC;QAC/D,MAAM,oBAAoB,GACxB,oBAAE,CAAC,uBAAuB,CAAC,MAAM,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC;QAEvE,IACE,oBAAoB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAClC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAC1D,EACD,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,oBAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC;IACnC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAQD,SAAS,qBAAqB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAA+B;IACtF,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAClC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CACvF,CAAC;AACJ,CAAC;AAOD,SAAS,oCAAoC,CAAC,EAC5C,MAAM,EACN,QAAQ,GACmC;IAC3C,OAAO,CAAC,MAAM,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CACnE,IAAI,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CACrD,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAAC,SAAmC;IACpE,OAAO,CACL,YAAY,SAAS,CAAC,IAAI,qDAAqD;QAC/E,iBAAiB,SAAS,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAC5D,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAmC;IACnE,OAAO,MAAM,CAAC,qBAAqB,IAAI,gCAAgC,CAAC;AAC1E,CAAC;AAOD,SAAS,gBAAgB,CAAC,EAAE,cAAc,EAAE,KAAK,EAA0B;IACzE,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE7C,OAAO,QAAQ,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,WAAW,CAAC,cAAiC;IACpD,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC;IAEtC,IAAI,oBAAE,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,OAAO,UAAU,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,IAAI,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAE,CAAC,UAAU,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,QAAQ,CAAC,UAAU,CAAC,mBAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAc;IACnD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,gBAAgB,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC1C,gBAAgB,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC9C,qBAAqB,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC3D,qBAAqB,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACrD,qBAAqB,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChD,qBAAqB,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC3D,qBAAqB,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAC/D,qBAAqB,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAChE,sBAAsB,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC7D,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACvC,mCAAmC,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,CACxE,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAc;IAEd,OAAO,CACL,KAAK,KAAK,SAAS;QACnB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACnB,KAAK,CAAC,KAAK,CACT,CAAC,KAAc,EAAE,EAAE,CACjB,QAAQ,CAAC,KAAK,CAAC;gBACf,OAAO,KAAK,CAAC,iBAAiB,CAAC,KAAK,QAAQ;gBAC5C,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,QAAQ;gBACnC,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAC3C,CAAC,CACL,CAAC;AACJ,CAAC;AAED,SAAS,mCAAmC,CAC1C,KAAc;IAEd,OAAO,CACL,KAAK,KAAK,SAAS;QACnB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACnB,KAAK,CAAC,KAAK,CACT,CAAC,SAAkB,EAAE,EAAE,CACrB,QAAQ,CAAC,SAAS,CAAC;gBACnB,aAAa,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;gBAC3C,OAAO,SAAS,CAAC,iBAAiB,CAAC,KAAK,QAAQ;gBAChD,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,QAAQ;gBACrC,aAAa,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAChD,CAAC,CACL,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,4BAA4B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAc;IAEd,OAAO,CACL,KAAK,KAAK,SAAS;QACnB,CAAC,QAAQ,CAAC,KAAK,CAAC;YACd,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAC9F,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC;AAC1D,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc;IAC3C,OAAO,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,UAAU,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAAG,CAAA,KAAK,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PlaywrightFlakeLinterConfig, PlaywrightFlakePatternViolation } from "./playwrightFlakeLinter";
|
|
2
|
+
interface LintPlaywrightProjectParams {
|
|
3
|
+
config: PlaywrightFlakeLinterConfig;
|
|
4
|
+
cwd: string;
|
|
5
|
+
}
|
|
6
|
+
interface LoadPlaywrightFlakeLinterConfigParams {
|
|
7
|
+
configFilePath: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function lintPlaywrightProject({ config, cwd, }: LintPlaywrightProjectParams): Promise<PlaywrightFlakePatternViolation[]>;
|
|
10
|
+
export declare function loadPlaywrightFlakeLinterConfig({ configFilePath, }: LoadPlaywrightFlakeLinterConfigParams): Promise<PlaywrightFlakeLinterConfig>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lintPlaywrightProject = lintPlaywrightProject;
|
|
4
|
+
exports.loadPlaywrightFlakeLinterConfig = loadPlaywrightFlakeLinterConfig;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
8
|
+
const node_url_1 = require("node:url");
|
|
9
|
+
const glob_1 = require("glob");
|
|
10
|
+
const violations_1 = require("./internal/violations");
|
|
11
|
+
const playwrightFlakeLinter_1 = require("./playwrightFlakeLinter");
|
|
12
|
+
const SOURCE_FILE_PATTERN = "*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}";
|
|
13
|
+
async function lintPlaywrightProject({ config, cwd, }) {
|
|
14
|
+
const filePaths = await findSourceFiles({ config, cwd });
|
|
15
|
+
const nestedViolations = await Promise.all(filePaths.map(async (filePath) => (0, playwrightFlakeLinter_1.findPlaywrightFlakePatternViolations)({
|
|
16
|
+
config,
|
|
17
|
+
filePath: node_path_1.default.relative(cwd, filePath),
|
|
18
|
+
source: await (0, promises_1.readFile)(filePath, "utf8"),
|
|
19
|
+
})));
|
|
20
|
+
return nestedViolations.flat().toSorted(violations_1.compareViolations);
|
|
21
|
+
}
|
|
22
|
+
async function loadPlaywrightFlakeLinterConfig({ configFilePath, }) {
|
|
23
|
+
const importedModule = await Promise.resolve(`${`${(0, node_url_1.pathToFileURL)(node_path_1.default.resolve(configFilePath)).href}?loaded=${Date.now()}`}`).then(s => tslib_1.__importStar(require(s)));
|
|
24
|
+
return (0, playwrightFlakeLinter_1.parsePlaywrightFlakeLinterConfig)({
|
|
25
|
+
sourceDescription: configFilePath,
|
|
26
|
+
value: getDefaultExport(importedModule),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function findSourceFiles({ config, cwd }) {
|
|
30
|
+
const patterns = config.scanRoots.flatMap((scanRoot) => [
|
|
31
|
+
normalizeGlobPath(scanRoot),
|
|
32
|
+
node_path_1.default.posix.join(normalizeGlobPath(scanRoot), "**", SOURCE_FILE_PATTERN),
|
|
33
|
+
]);
|
|
34
|
+
const filePaths = await (0, glob_1.glob)(patterns, {
|
|
35
|
+
absolute: true,
|
|
36
|
+
cwd,
|
|
37
|
+
nodir: true,
|
|
38
|
+
});
|
|
39
|
+
return filePaths.filter(isSourceFile);
|
|
40
|
+
}
|
|
41
|
+
function normalizeGlobPath(filePath) {
|
|
42
|
+
return filePath.replaceAll(node_path_1.default.sep, "/");
|
|
43
|
+
}
|
|
44
|
+
function isSourceFile(filePath) {
|
|
45
|
+
return /\.[cm]?[jt]sx?$/.test(filePath);
|
|
46
|
+
}
|
|
47
|
+
function getDefaultExport(importedModule) {
|
|
48
|
+
if (typeof importedModule !== "object" ||
|
|
49
|
+
importedModule === null ||
|
|
50
|
+
Array.isArray(importedModule)) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
return Reflect.get(importedModule, "default");
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=projectLinter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectLinter.js","sourceRoot":"","sources":["../../../../../packages/playwright-flake-linter/src/lib/projectLinter.ts"],"names":[],"mappings":";;;;;AAAA,+CAA4C;AAC5C,kEAA6B;AAC7B,uCAAyC;AAEzC,+BAA4B;AAE5B,sDAA0D;AAK1D,mEAGiC;AAEjC,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AAWzD,KAAK,gCAAgC,EAC1C,MAAM,EACN,GAAG,GACyB;IAC5B,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACzD,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,GAAG,CACxC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAC/B,IAAA,4DAAoC,EAAC;QACnC,MAAM;QACN,QAAQ,EAAE,mBAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;QACtC,MAAM,EAAE,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,MAAM,CAAC;KACzC,CAAC,CACH,CACF,CAAC;IAEF,OAAO,gBAAgB,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,8BAAiB,CAAC,CAAC;AAC7D,CAAC;AAEM,KAAK,0CAA0C,EACpD,cAAc,GACwB;IACtC,MAAM,cAAc,GAAY,yBAC9B,GAAG,IAAA,wBAAa,EAAC,mBAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,+CAC3E,CAAC;IAEF,OAAO,IAAA,wDAAgC,EAAC;QACtC,iBAAiB,EAAE,cAAc;QACjC,KAAK,EAAE,gBAAgB,CAAC,cAAc,CAAC;KACxC,CAAC,CAAC;AACL,CAAC;AAOD,KAAK,UAAU,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,EAAyB;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;QACtD,iBAAiB,CAAC,QAAQ,CAAC;QAC3B,mBAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,mBAAmB,CAAC;KACxE,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,IAAA,WAAI,EAAC,QAAQ,EAAE;QACrC,QAAQ,EAAE,IAAI;QACd,GAAG;QACH,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,OAAO,QAAQ,CAAC,UAAU,CAAC,mBAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB;IACpC,OAAO,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,gBAAgB,CAAC,cAAuB;IAC/C,IACE,OAAO,cAAc,KAAK,QAAQ;QAClC,cAAc,KAAK,IAAI;QACvB,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAC7B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC"}
|