@browserflow-ai/core 0.0.6
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/dist/config-schema.d.ts +354 -0
- package/dist/config-schema.d.ts.map +1 -0
- package/dist/config-schema.js +83 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +107 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/duration.d.ts +39 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +111 -0
- package/dist/duration.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/locator-object.d.ts +556 -0
- package/dist/locator-object.d.ts.map +1 -0
- package/dist/locator-object.js +114 -0
- package/dist/locator-object.js.map +1 -0
- package/dist/lockfile.d.ts +1501 -0
- package/dist/lockfile.d.ts.map +1 -0
- package/dist/lockfile.js +86 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/run-store.d.ts +81 -0
- package/dist/run-store.d.ts.map +1 -0
- package/dist/run-store.js +181 -0
- package/dist/run-store.js.map +1 -0
- package/dist/spec-loader.d.ts +17 -0
- package/dist/spec-loader.d.ts.map +1 -0
- package/dist/spec-loader.js +37 -0
- package/dist/spec-loader.js.map +1 -0
- package/dist/spec-schema.d.ts +1411 -0
- package/dist/spec-schema.d.ts.map +1 -0
- package/dist/spec-schema.js +239 -0
- package/dist/spec-schema.js.map +1 -0
- package/package.json +45 -0
- package/schemas/browserflow.schema.json +220 -0
- package/schemas/lockfile.schema.json +568 -0
- package/schemas/spec-v2.schema.json +413 -0
- package/src/config-schema.test.ts +190 -0
- package/src/config-schema.ts +111 -0
- package/src/config.ts +112 -0
- package/src/duration.test.ts +175 -0
- package/src/duration.ts +128 -0
- package/src/index.ts +136 -0
- package/src/json-schemas.test.ts +374 -0
- package/src/locator-object.test.ts +323 -0
- package/src/locator-object.ts +250 -0
- package/src/lockfile.test.ts +345 -0
- package/src/lockfile.ts +209 -0
- package/src/run-store.test.ts +232 -0
- package/src/run-store.ts +240 -0
- package/src/spec-loader.test.ts +181 -0
- package/src/spec-loader.ts +47 -0
- package/src/spec-schema.test.ts +360 -0
- package/src/spec-schema.ts +347 -0
package/src/config.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration types for BrowserFlow
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generator output format options
|
|
7
|
+
*/
|
|
8
|
+
export type GeneratorOutputFormat = 'playwright-ts' | 'playwright-js' | 'bash';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Browser types supported by Playwright
|
|
12
|
+
*/
|
|
13
|
+
export type BrowserType = 'chromium' | 'firefox' | 'webkit';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Playwright project configuration
|
|
17
|
+
*/
|
|
18
|
+
export interface PlaywrightProject {
|
|
19
|
+
name: string;
|
|
20
|
+
use: {
|
|
21
|
+
browserName?: BrowserType;
|
|
22
|
+
viewport?: { width: number; height: number };
|
|
23
|
+
headless?: boolean;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Playwright configuration options for generated tests
|
|
30
|
+
*/
|
|
31
|
+
export interface PlaywrightConfigOptions {
|
|
32
|
+
/** Test timeout in ms */
|
|
33
|
+
timeout?: number;
|
|
34
|
+
/** Number of retries */
|
|
35
|
+
retries?: number;
|
|
36
|
+
/** Number of workers */
|
|
37
|
+
workers?: number;
|
|
38
|
+
/** Reporter to use */
|
|
39
|
+
reporter?: 'html' | 'list' | 'dot' | 'json';
|
|
40
|
+
/** Projects configuration */
|
|
41
|
+
projects?: PlaywrightProject[];
|
|
42
|
+
/** Web server configuration */
|
|
43
|
+
webServer?: {
|
|
44
|
+
command: string;
|
|
45
|
+
url: string;
|
|
46
|
+
reuseExistingServer?: boolean;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generator configuration
|
|
52
|
+
*/
|
|
53
|
+
export interface GeneratorConfig {
|
|
54
|
+
/** Output format for generated tests */
|
|
55
|
+
outputFormat: GeneratorOutputFormat;
|
|
56
|
+
/** Include baseline screenshot comparisons */
|
|
57
|
+
includeBaselineChecks: boolean;
|
|
58
|
+
/** Directory for baseline screenshots */
|
|
59
|
+
baselinesDir?: string;
|
|
60
|
+
/** Playwright config options */
|
|
61
|
+
playwrightConfig?: PlaywrightConfigOptions;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Review step data
|
|
66
|
+
*/
|
|
67
|
+
export interface ReviewStepData {
|
|
68
|
+
step_index: number;
|
|
69
|
+
status: 'approved' | 'rejected' | 'pending';
|
|
70
|
+
comment?: string;
|
|
71
|
+
tags?: string[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Review data for an exploration
|
|
76
|
+
*/
|
|
77
|
+
export interface ReviewData {
|
|
78
|
+
exploration_id: string;
|
|
79
|
+
reviewer?: string;
|
|
80
|
+
started_at: string;
|
|
81
|
+
updated_at: string;
|
|
82
|
+
steps: ReviewStepData[];
|
|
83
|
+
overall_notes?: string;
|
|
84
|
+
verdict: 'approved' | 'rejected' | 'pending';
|
|
85
|
+
submitted_at?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Generated test output
|
|
90
|
+
*/
|
|
91
|
+
export interface GeneratedTest {
|
|
92
|
+
/** Test file path (relative) */
|
|
93
|
+
path: string;
|
|
94
|
+
/** Test file content */
|
|
95
|
+
content: string;
|
|
96
|
+
/** Spec name this was generated from */
|
|
97
|
+
specName: string;
|
|
98
|
+
/** Exploration ID used */
|
|
99
|
+
explorationId: string;
|
|
100
|
+
/** Generation timestamp */
|
|
101
|
+
generatedAt: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Generated config output
|
|
106
|
+
*/
|
|
107
|
+
export interface GeneratedConfig {
|
|
108
|
+
/** Config file path */
|
|
109
|
+
path: string;
|
|
110
|
+
/** Config file content */
|
|
111
|
+
content: string;
|
|
112
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for duration string parser
|
|
3
|
+
* @see bf-x1q
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from 'bun:test';
|
|
7
|
+
import { parseDuration, formatDuration, isValidDuration } from './duration.js';
|
|
8
|
+
|
|
9
|
+
describe('parseDuration', () => {
|
|
10
|
+
describe('basic units', () => {
|
|
11
|
+
test('parses milliseconds', () => {
|
|
12
|
+
expect(parseDuration('500ms')).toBe(500);
|
|
13
|
+
expect(parseDuration('0ms')).toBe(0);
|
|
14
|
+
expect(parseDuration('1ms')).toBe(1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('parses seconds', () => {
|
|
18
|
+
expect(parseDuration('3s')).toBe(3000);
|
|
19
|
+
expect(parseDuration('1s')).toBe(1000);
|
|
20
|
+
expect(parseDuration('30s')).toBe(30000);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('parses minutes', () => {
|
|
24
|
+
expect(parseDuration('2m')).toBe(120000);
|
|
25
|
+
expect(parseDuration('1m')).toBe(60000);
|
|
26
|
+
expect(parseDuration('5m')).toBe(300000);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('parses hours', () => {
|
|
30
|
+
expect(parseDuration('1h')).toBe(3600000);
|
|
31
|
+
expect(parseDuration('2h')).toBe(7200000);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('combined units', () => {
|
|
36
|
+
test('parses minute and seconds', () => {
|
|
37
|
+
expect(parseDuration('1m30s')).toBe(90000);
|
|
38
|
+
expect(parseDuration('2m15s')).toBe(135000);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('parses hours and minutes', () => {
|
|
42
|
+
expect(parseDuration('1h30m')).toBe(5400000);
|
|
43
|
+
expect(parseDuration('2h45m')).toBe(9900000);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('parses complex combinations', () => {
|
|
47
|
+
expect(parseDuration('1h30m45s')).toBe(5445000);
|
|
48
|
+
expect(parseDuration('1m30s500ms')).toBe(90500);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('numeric input', () => {
|
|
53
|
+
test('treats numeric input as milliseconds', () => {
|
|
54
|
+
expect(parseDuration(500)).toBe(500);
|
|
55
|
+
expect(parseDuration(3000)).toBe(3000);
|
|
56
|
+
expect(parseDuration(0)).toBe(0);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('parses plain number strings as milliseconds', () => {
|
|
60
|
+
expect(parseDuration('500')).toBe(500);
|
|
61
|
+
expect(parseDuration('3000')).toBe(3000);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('whitespace handling', () => {
|
|
66
|
+
test('trims whitespace', () => {
|
|
67
|
+
expect(parseDuration(' 3s ')).toBe(3000);
|
|
68
|
+
expect(parseDuration('\t2m\n')).toBe(120000);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('handles lowercase conversion', () => {
|
|
72
|
+
expect(parseDuration('3S')).toBe(3000);
|
|
73
|
+
expect(parseDuration('2M')).toBe(120000);
|
|
74
|
+
expect(parseDuration('1H')).toBe(3600000);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('error handling', () => {
|
|
79
|
+
test('throws for empty string', () => {
|
|
80
|
+
expect(() => parseDuration('')).toThrow('Duration must be a non-empty string');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('throws for whitespace-only string', () => {
|
|
84
|
+
expect(() => parseDuration(' ')).toThrow('Duration must be a non-empty string');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('throws for invalid format', () => {
|
|
88
|
+
expect(() => parseDuration('3 seconds')).toThrow(/Invalid duration/);
|
|
89
|
+
expect(() => parseDuration('abc')).toThrow(/Invalid duration/);
|
|
90
|
+
expect(() => parseDuration('3x')).toThrow(/Invalid duration/);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('provides helpful error message', () => {
|
|
94
|
+
try {
|
|
95
|
+
parseDuration('invalid');
|
|
96
|
+
} catch (e) {
|
|
97
|
+
expect((e as Error).message).toContain('3s');
|
|
98
|
+
expect((e as Error).message).toContain('2m');
|
|
99
|
+
expect((e as Error).message).toContain('500ms');
|
|
100
|
+
expect((e as Error).message).toContain('1m30s');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('edge cases', () => {
|
|
106
|
+
test('handles fractional values', () => {
|
|
107
|
+
expect(parseDuration('1.5s')).toBe(1500);
|
|
108
|
+
expect(parseDuration('0.5m')).toBe(30000);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('handles zero values', () => {
|
|
112
|
+
expect(parseDuration('0s')).toBe(0);
|
|
113
|
+
expect(parseDuration('0m')).toBe(0);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('formatDuration', () => {
|
|
119
|
+
test('formats milliseconds', () => {
|
|
120
|
+
expect(formatDuration(500)).toBe('500ms');
|
|
121
|
+
expect(formatDuration(0)).toBe('0ms');
|
|
122
|
+
expect(formatDuration(999)).toBe('999ms');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('formats seconds', () => {
|
|
126
|
+
expect(formatDuration(1000)).toBe('1s');
|
|
127
|
+
expect(formatDuration(3000)).toBe('3s');
|
|
128
|
+
expect(formatDuration(30000)).toBe('30s');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('formats minutes', () => {
|
|
132
|
+
expect(formatDuration(60000)).toBe('1m');
|
|
133
|
+
expect(formatDuration(120000)).toBe('2m');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('formats hours', () => {
|
|
137
|
+
expect(formatDuration(3600000)).toBe('1h');
|
|
138
|
+
expect(formatDuration(7200000)).toBe('2h');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('formats combinations', () => {
|
|
142
|
+
expect(formatDuration(90000)).toBe('1m30s');
|
|
143
|
+
expect(formatDuration(5400000)).toBe('1h30m');
|
|
144
|
+
expect(formatDuration(5445000)).toBe('1h30m45s');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('formats sub-second remainders to seconds', () => {
|
|
148
|
+
// formatDuration uses floor, so sub-second parts are dropped
|
|
149
|
+
expect(formatDuration(1500)).toBe('1s');
|
|
150
|
+
expect(formatDuration(90500)).toBe('1m30s');
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('isValidDuration', () => {
|
|
155
|
+
test('returns true for valid durations', () => {
|
|
156
|
+
expect(isValidDuration('3s')).toBe(true);
|
|
157
|
+
expect(isValidDuration('2m')).toBe(true);
|
|
158
|
+
expect(isValidDuration('1h')).toBe(true);
|
|
159
|
+
expect(isValidDuration('500ms')).toBe(true);
|
|
160
|
+
expect(isValidDuration('1m30s')).toBe(true);
|
|
161
|
+
expect(isValidDuration('1h30m')).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('returns false for invalid durations', () => {
|
|
165
|
+
expect(isValidDuration('')).toBe(false);
|
|
166
|
+
expect(isValidDuration('abc')).toBe(false);
|
|
167
|
+
expect(isValidDuration('3 seconds')).toBe(false);
|
|
168
|
+
expect(isValidDuration('3x')).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('returns true for plain number strings', () => {
|
|
172
|
+
expect(isValidDuration('500')).toBe(true);
|
|
173
|
+
expect(isValidDuration('3000')).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
});
|
package/src/duration.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duration string parser
|
|
3
|
+
*
|
|
4
|
+
* Parses human-readable duration strings like "30s", "5m", "1h30m"
|
|
5
|
+
* into milliseconds.
|
|
6
|
+
*
|
|
7
|
+
* @see bf-x1q for implementation task
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const UNITS: Record<string, number> = {
|
|
11
|
+
ms: 1,
|
|
12
|
+
s: 1000,
|
|
13
|
+
m: 60 * 1000,
|
|
14
|
+
h: 60 * 60 * 1000,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Validates a duration string without parsing it.
|
|
19
|
+
*
|
|
20
|
+
* @param input - Duration string to validate
|
|
21
|
+
* @returns true if valid, false otherwise
|
|
22
|
+
*/
|
|
23
|
+
export function isValidDuration(input: string): boolean {
|
|
24
|
+
if (typeof input !== 'string') {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const trimmed = input.trim().toLowerCase();
|
|
29
|
+
if (!trimmed) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Plain number (milliseconds)
|
|
34
|
+
if (/^\d+$/.test(trimmed)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Duration with units
|
|
39
|
+
const regex = /(\d+(?:\.\d+)?)(ms|s|m|h)/g;
|
|
40
|
+
let hasMatch = false;
|
|
41
|
+
|
|
42
|
+
// Check if entire string matches expected pattern
|
|
43
|
+
let lastIndex = 0;
|
|
44
|
+
let match;
|
|
45
|
+
while ((match = regex.exec(trimmed)) !== null) {
|
|
46
|
+
if (match.index !== lastIndex) {
|
|
47
|
+
return false; // Gap in matching
|
|
48
|
+
}
|
|
49
|
+
hasMatch = true;
|
|
50
|
+
lastIndex = regex.lastIndex;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return hasMatch && lastIndex === trimmed.length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parses a duration string into milliseconds.
|
|
58
|
+
*
|
|
59
|
+
* Supported formats:
|
|
60
|
+
* - "30s" -> 30000
|
|
61
|
+
* - "5m" -> 300000
|
|
62
|
+
* - "1h" -> 3600000
|
|
63
|
+
* - "1h30m" -> 5400000
|
|
64
|
+
* - "500ms" -> 500
|
|
65
|
+
* - "500" -> 500 (plain numbers treated as ms)
|
|
66
|
+
*
|
|
67
|
+
* @param input - Duration string to parse
|
|
68
|
+
* @returns Duration in milliseconds
|
|
69
|
+
* @throws Error if format is invalid
|
|
70
|
+
*/
|
|
71
|
+
export function parseDuration(input: string | number): number {
|
|
72
|
+
if (typeof input === 'number') {
|
|
73
|
+
return input;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof input !== 'string' || !input.trim()) {
|
|
77
|
+
throw new Error('Duration must be a non-empty string');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const trimmed = input.trim().toLowerCase();
|
|
81
|
+
|
|
82
|
+
// Plain number (milliseconds)
|
|
83
|
+
if (/^\d+$/.test(trimmed)) {
|
|
84
|
+
return parseInt(trimmed, 10);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let total = 0;
|
|
88
|
+
const regex = /(\d+(?:\.\d+)?)(ms|s|m|h)/g;
|
|
89
|
+
let match;
|
|
90
|
+
let hasMatch = false;
|
|
91
|
+
|
|
92
|
+
while ((match = regex.exec(trimmed)) !== null) {
|
|
93
|
+
hasMatch = true;
|
|
94
|
+
const [, value, unit] = match;
|
|
95
|
+
total += parseFloat(value) * UNITS[unit];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!hasMatch) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Invalid duration "${input}". Use format like "3s", "2m", "500ms", or "1m30s"`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return Math.round(total);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Formats milliseconds into a human-readable duration string.
|
|
109
|
+
*
|
|
110
|
+
* @param ms - Duration in milliseconds
|
|
111
|
+
* @returns Human-readable duration string
|
|
112
|
+
*/
|
|
113
|
+
export function formatDuration(ms: number): string {
|
|
114
|
+
if (ms < 1000) {
|
|
115
|
+
return `${ms}ms`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const hours = Math.floor(ms / 3600000);
|
|
119
|
+
const minutes = Math.floor((ms % 3600000) / 60000);
|
|
120
|
+
const seconds = Math.floor((ms % 60000) / 1000);
|
|
121
|
+
|
|
122
|
+
const parts: string[] = [];
|
|
123
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
124
|
+
if (minutes > 0) parts.push(`${minutes}m`);
|
|
125
|
+
if (seconds > 0) parts.push(`${seconds}s`);
|
|
126
|
+
|
|
127
|
+
return parts.join('') || '0s';
|
|
128
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @browserflow-ai/core - Shared types, schemas, and utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Spec schema and types
|
|
6
|
+
export {
|
|
7
|
+
specSchema,
|
|
8
|
+
specStepSchema,
|
|
9
|
+
stepSchema,
|
|
10
|
+
actionTypeSchema,
|
|
11
|
+
verifyCheckSchema,
|
|
12
|
+
expectedOutcomeSchema,
|
|
13
|
+
highlightRegionSchema,
|
|
14
|
+
maskRegionSchema,
|
|
15
|
+
durationSchema,
|
|
16
|
+
targetSchema,
|
|
17
|
+
preconditionsSchema,
|
|
18
|
+
stateSchema,
|
|
19
|
+
type ActionType,
|
|
20
|
+
type VerifyCheck,
|
|
21
|
+
type HighlightRegion,
|
|
22
|
+
type MaskRegion,
|
|
23
|
+
type SpecStep,
|
|
24
|
+
type LegacySpecStep,
|
|
25
|
+
type ExpectedOutcome,
|
|
26
|
+
type BrowserFlowSpec,
|
|
27
|
+
type Target,
|
|
28
|
+
type State,
|
|
29
|
+
type Preconditions,
|
|
30
|
+
} from './spec-schema.js';
|
|
31
|
+
|
|
32
|
+
// Spec loading and normalization
|
|
33
|
+
export { normalizePreconditions, loadSpec } from './spec-loader.js';
|
|
34
|
+
|
|
35
|
+
// Locator types and resolution
|
|
36
|
+
export {
|
|
37
|
+
type LocatorObject,
|
|
38
|
+
type LocatorStrategy,
|
|
39
|
+
type LocatorStrategyType,
|
|
40
|
+
type LocatorScoping,
|
|
41
|
+
type LocatorProof,
|
|
42
|
+
type DOMFingerprint,
|
|
43
|
+
type BoundingBox,
|
|
44
|
+
type ResolveOptions,
|
|
45
|
+
type LocatorMethod,
|
|
46
|
+
type LocatorArgs,
|
|
47
|
+
type LegacyLocatorObject,
|
|
48
|
+
locatorObjectSchema,
|
|
49
|
+
locatorStrategySchema,
|
|
50
|
+
locatorStrategyTypeSchema,
|
|
51
|
+
locatorScopingSchema,
|
|
52
|
+
locatorProofSchema,
|
|
53
|
+
domFingerprintSchema,
|
|
54
|
+
boundingBoxSchema,
|
|
55
|
+
resolveLocator,
|
|
56
|
+
strategyToLocator,
|
|
57
|
+
resolveLegacyLocator,
|
|
58
|
+
} from './locator-object.js';
|
|
59
|
+
|
|
60
|
+
// Lockfile types
|
|
61
|
+
export {
|
|
62
|
+
type Lockfile,
|
|
63
|
+
type Mask,
|
|
64
|
+
type Assertion,
|
|
65
|
+
type AssertionType,
|
|
66
|
+
type GenerationMetadata,
|
|
67
|
+
type ExplorationReport,
|
|
68
|
+
type ExplorationLockfile,
|
|
69
|
+
type ExplorationStep,
|
|
70
|
+
type StepExecution,
|
|
71
|
+
type OutcomeCheck,
|
|
72
|
+
type ExplorationError,
|
|
73
|
+
lockfileSchema,
|
|
74
|
+
maskSchema,
|
|
75
|
+
assertionSchema,
|
|
76
|
+
assertionTypeSchema,
|
|
77
|
+
generationMetadataSchema,
|
|
78
|
+
validateLockfile,
|
|
79
|
+
computeSpecHash,
|
|
80
|
+
readLockfile,
|
|
81
|
+
writeLockfile,
|
|
82
|
+
} from './lockfile.js';
|
|
83
|
+
|
|
84
|
+
// Duration utilities
|
|
85
|
+
export { parseDuration, formatDuration, isValidDuration } from './duration.js';
|
|
86
|
+
|
|
87
|
+
// Run store utilities
|
|
88
|
+
export {
|
|
89
|
+
type RunDirectoryPaths,
|
|
90
|
+
type RunStore,
|
|
91
|
+
createRunStore,
|
|
92
|
+
createRunId,
|
|
93
|
+
getRunPaths,
|
|
94
|
+
generateExplorationId,
|
|
95
|
+
getScreenshotPath,
|
|
96
|
+
} from './run-store.js';
|
|
97
|
+
|
|
98
|
+
// Configuration types
|
|
99
|
+
export {
|
|
100
|
+
type GeneratorOutputFormat,
|
|
101
|
+
type BrowserType,
|
|
102
|
+
type PlaywrightProject,
|
|
103
|
+
type PlaywrightConfigOptions,
|
|
104
|
+
type GeneratorConfig,
|
|
105
|
+
type ReviewStepData,
|
|
106
|
+
type ReviewData,
|
|
107
|
+
type GeneratedTest,
|
|
108
|
+
type GeneratedConfig,
|
|
109
|
+
} from './config.js';
|
|
110
|
+
|
|
111
|
+
// Browserflow config schema (for browserflow.yaml validation)
|
|
112
|
+
export {
|
|
113
|
+
browserflowConfigSchema,
|
|
114
|
+
browserTypeSchema,
|
|
115
|
+
viewportSchema,
|
|
116
|
+
projectConfigSchema,
|
|
117
|
+
runtimeConfigSchema,
|
|
118
|
+
locatorsConfigSchema,
|
|
119
|
+
explorationConfigSchema,
|
|
120
|
+
reviewConfigSchema,
|
|
121
|
+
outputConfigSchema,
|
|
122
|
+
ciConfigSchema,
|
|
123
|
+
validateBrowserflowConfig,
|
|
124
|
+
parseBrowserflowConfig,
|
|
125
|
+
type BrowserTypeConfig,
|
|
126
|
+
type ViewportConfig,
|
|
127
|
+
type ProjectConfig,
|
|
128
|
+
type RuntimeConfig,
|
|
129
|
+
type LocatorsConfig,
|
|
130
|
+
type ExplorationConfig,
|
|
131
|
+
type ReviewConfig,
|
|
132
|
+
type OutputConfig,
|
|
133
|
+
type CiConfig,
|
|
134
|
+
type BrowserflowConfig,
|
|
135
|
+
} from './config-schema.js';
|
|
136
|
+
|