import { Rule , Diagnostic } from "@siteimprove/alfa-act" ; import { Node } from "@siteimprove/alfa-aria" ; import { Element , Namespace } from "@siteimprove/alfa-dom" ; import { Predicate } from "@siteimprove/alfa-predicate" ; import { Err , Ok } from "@siteimprove/alfa-result" ; import { Criterion } from "@siteimprove/alfa-wcag" ; import { Page } from "@siteimprove/alfa-web" ; import { expectation } from "../common/expectation" ; import { hasNonEmptyAccessibleName , hasRole , isIgnored , referenceSameResource , } from "../common/predicate" ; import { Group } from "../common/group" ; import { normalize } from "../common/normalize" ; import { Question } from "../common/question" ; import { Scope } from "../tags" ; const { isElement , hasNamespace } = Element ; const { and , not } = Predicate ; export default Rule . Atomic . of < Page , Group < Element > , Question . Metadata > ( { uri : "https://alfa.siteimprove.com/rules/sia-r41" , requirements : [ Criterion . of ( "2.4.9" ) ] , tags : [ Scope . Component ] , evaluate ( { device , document , response } ) { return { applicability ( ) { return document . descendants ( { flattened : true , nested : true } ) . filter ( isElement ) . filter ( and ( hasNamespace ( Namespace . HTML , Namespace . SVG ) , hasRole ( device , ( role ) => role . is ( "link" ) ) , not ( isIgnored ( device ) ) , hasNonEmptyAccessibleName ( device ) ) ) . groupBy ( ( element ) => element . root ( ) ) . flatMap ( ( elements ) => elements . groupBy ( ( element ) => Node . from ( element , device ) . name . map ( ( name ) => normalize ( name . value ) ) ) ) . filter ( ( elements ) => elements . size > 1 ) . map ( Group . of ) . values ( ) ; } , expectations ( target ) { const embedSameResource = [ ... target ] . every ( ( element , i , elements ) => { return ( i === 0 || referenceSameResource ( response . url ) ( element , elements [ i - 1 ] ) ) ; } ) ; return { 1 : expectation ( embedSameResource , ( ) => Outcomes . ResolveSameResource , ( ) => Question . of ( "reference-equivalent-resources" , target , Diagnostic . of ( `Do the links resolve to equivalent resources?` ) ) . map ( ( embedEquivalentResources ) => expectation ( embedEquivalentResources , ( ) => Outcomes . ResolveEquivalentResource , ( ) => Outcomes . ResolveDifferentResource ) ) ) , } ; } , } ; } , } ) ; export namespace Outcomes { export const ResolveSameResource = Ok . of ( Diagnostic . of ( `The links resolve to the same resource` ) ) ; export const ResolveEquivalentResource = Ok . of ( Diagnostic . of ( `The links resolve to equivalent resources` ) ) ; export const ResolveDifferentResource = Err . of ( Diagnostic . of ( `The links do not resolve to the same or equivalent resources` ) ) ; }