11import { refuse , type SelectorArgumentRefusal } from './argument-refusal.ts' ;
22
3+ import { IS_PREDICATES , type IsPredicate } from '@agent-device/contracts/is-predicate' ;
34import type { Platform , PublicPlatform } from '@agent-device/kernel/device' ;
45import type { SnapshotState } from '@agent-device/kernel/snapshot' ;
56import { isPositiveFiniteRect } from '@agent-device/kernel/rect' ;
@@ -12,23 +13,15 @@ import {
1213import { isNodeEditable , isNodeVisible } from './node.ts' ;
1314import { tryParseSelectorChain } from './parse.ts' ;
1415
15- export type IsPredicate =
16- | 'visible'
17- | 'hidden'
18- | 'exists'
19- | 'editable'
20- | 'selected'
21- | 'focused'
22- | 'text' ;
16+ export type { IsPredicate } from '@agent-device/contracts/is-predicate' ;
2317
2418// Module-private since `checkIsPredicate` became the admission API: a caller that tests the
2519// vocabulary without going through admission is how the case-normalization drift started.
2620function isSupportedPredicate ( input : string ) : input is IsPredicate {
27- return [ 'visible' , 'hidden' , 'exists' , 'editable' , 'selected' , 'focused' , 'text' ] . includes ( input ) ;
21+ return ( IS_PREDICATES as readonly string [ ] ) . includes ( input ) ;
2822}
2923
30- export const IS_PREDICATE_REQUIRED_MESSAGE =
31- 'is requires predicate: visible|hidden|exists|editable|selected|focused|text' ;
24+ export const IS_PREDICATE_REQUIRED_MESSAGE = `is requires predicate: ${ IS_PREDICATES . join ( '|' ) } ` ;
3225
3326/**
3427 * The one `is` predicate admission check. Three call sites used to state this rule
@@ -67,7 +60,7 @@ export function normalizeIsPositionals(positionals: string[]): string[] {
6760}
6861
6962export function evaluateIsPredicate ( params : {
70- predicate : Exclude < IsPredicate , 'exists' > ;
63+ predicate : Exclude < IsPredicate , 'exists' | 'absent' > ;
7164 node : SnapshotState [ 'nodes' ] [ number ] ;
7265 nodes : SnapshotState [ 'nodes' ] ;
7366 expectedText ?: string ;
@@ -102,6 +95,8 @@ export function evaluateIsPredicate(params: {
10295 case 'text' :
10396 pass = actualText === ( expectedText ?? '' ) ;
10497 break ;
98+ default :
99+ return assertNever ( predicate ) ;
105100 }
106101 const details =
107102 predicate === 'text'
@@ -115,6 +110,10 @@ export function evaluateIsPredicate(params: {
115110 return { pass, actualText, details } ;
116111}
117112
113+ function assertNever ( value : never ) : never {
114+ throw new Error ( `Unhandled is predicate: ${ String ( value ) } ` ) ;
115+ }
116+
118117function isAssertionVisible (
119118 node : SnapshotState [ 'nodes' ] [ number ] ,
120119 visibility : SnapshotVisibility ,
0 commit comments