@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 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
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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,7 @@
1
+ interface RunCliParams {
2
+ arguments_: readonly string[];
3
+ cwd: string;
4
+ writeError: (output: string) => void;
5
+ }
6
+ export declare function runCli({ arguments_, cwd, writeError }: RunCliParams): Promise<number>;
7
+ export {};
@@ -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
@@ -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,2 @@
1
+ import type { PlaywrightFlakePatternViolation } from "../playwrightFlakeLinter";
2
+ export declare function compareViolations(first: PlaywrightFlakePatternViolation, second: PlaywrightFlakePatternViolation): number;
@@ -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":"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"}
@@ -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"}