import { Equatable } from "@siteimprove/alfa-equatable" ; import { Serializable } from "@siteimprove/alfa-json" ; import { Parser } from "@siteimprove/alfa-parser" ; import { Slice } from "@siteimprove/alfa-slice" ; import * as json from "@siteimprove/alfa-json" ; import { Token } from "./token" ; const { map , right , pair , delimited , option , either } = Parser ; /**
 *  https public export class Nth implements Iterable < Token > , Equatable , Serializable { public static of ( step , offset = 0 ) { return new Nth ( step | 0 , offset | 0 ) ; } private readonly _step : number ; private readonly _offset : number ; private constructor ( step , offset ) { this . _step = step ; this . _offset = offset ; } public get step ( ) : number { return this . _step ; } public get offset ( ) : number { return this . _offset ; } remarks public matches ( index ) { if ( this . _step === 0 ) { return this . _offset === ( index | 0 ) ; } const n = ( ( index | 0 ) - this . _offset ) / this . _step ; return n >= 0 && n === ( n | 0 ) ; } public for ( n ) { return this . _step * ( n | 0 ) + this . _offset ; } public * indices ( ) { for ( let n = 0 ; ; n ++ ) { yield this . for ( n ) ; } } public * [ Symbol . iterator ] ( ) { if ( this . _step !== 0 ) { yield Token . Dimension . of ( this . _step , "n" , true , this . _step < 0 ) ; } if ( this . _offset !== 0 ) { yield Token . Number . of ( this . _offset , true , this . _offset < 0 || this . _step !== 0 ) ; } } public equals ( value ) { return ( value instanceof Nth && value . _step === this . _step && value . _offset === this . _offset ) ; } public toJSON ( ) { return { step : this . _step , offset : this . _offset , } ; } public toString ( ) { return this . _step === 0 ? `${ this . _offset }` : `${ this . _step }n+${ this . _offset };` ; } } public export namespace Nth { export interface JSON { [ key ] : json . JSON ; step : number ; offset : number ; } remarks The An+B syntax isn't really meant for the tokens produced by the CSS lexer
     * and so the resulting parser ends up being quite complex.
     *
     *  https export const parse = either ( map ( Token . parseIdent ( ( ident ) => ident . value === "odd" || ident . value === "even" ) , ( ident ) => Nth . of ( 2 , ident . value === "even" ? 0 : 1 ) ) , map ( Token . parseNumber ( ( number ) => number . isInteger ) , ( number ) => Nth . of ( 0 , number . value ) ) , map ( Token . parseDimension ( ( dimension ) => dimension . isInteger && /^n-\d+$/ . test ( dimension . unit ) ) , ( dimension ) => Nth . of ( dimension . value , + dimension . unit . slice ( 1 ) ) ) , right ( option ( Token . parseDelim ( "+" ) ) , map ( Token . parseIdent ( ( ident ) => /^n-\d+$/ . test ( ident . value ) ) , ( ident ) => Nth . of ( 1 , + ident . value . slice ( 1 ) ) ) ) , map ( Token . parseIdent ( ( ident ) => /^-n-\d+$/ . test ( ident . value ) ) , ( ident ) => Nth . of ( - 1 , + ident . value . slice ( 2 ) ) ) , map ( pair ( either ( map ( Token . parseDimension ( ( dimension ) => dimension . isInteger && dimension . unit === "n" ) , ( dimension ) => dimension . value ) , map ( right ( option ( Token . parseDelim ( "+" ) ) , Token . parseIdent ( "n" ) ) , ( ) => 1 ) , map ( Token . parseIdent ( "-n" ) , ( ) => - 1 ) ) , option ( either ( map ( pair ( delimited ( option ( Token . parseWhitespace ) , option ( either ( map ( Token . parseDelim ( "+" ) , ( ) => 1 ) , map ( Token . parseDelim ( "-" ) , ( ) => - 1 ) ) ) ) , Token . parseNumber ( ( number ) => number . isInteger && ! number . isSigned ) ) , ( [ sign , number ] ) => sign . getOr ( 1 ) * number . value ) , delimited ( option ( Token . parseWhitespace ) , map ( Token . parseNumber ( ( number ) => number . isInteger ) , ( number ) => number . value ) ) ) ) ) , ( [ step , offset ] ) => Nth . of ( step , offset . getOr ( 0 ) ) ) , map ( pair ( either ( map ( Token . parseDimension ( ( dimension ) => dimension . isInteger && dimension . unit === "n-" ) , ( dimension ) => dimension . value ) , map ( right ( option ( Token . parseDelim ( "+" ) ) , Token . parseIdent ( "n-" ) ) , ( ) => 1 ) , map ( Token . parseIdent ( "-n-" ) , ( ) => - 1 ) ) , delimited ( option ( Token . parseWhitespace ) , map ( Token . parseNumber ( ( number ) => number . isInteger && ! number . isSigned ) , ( number ) => number . value ) ) ) , ( [ step , offset ] ) => Nth . of ( step , - 1 * offset ) ) ) ; }