diff --git a/.changeset/gentle-berries-decide.md b/.changeset/gentle-berries-decide.md new file mode 100644 index 0000000000..643b1f0287 --- /dev/null +++ b/.changeset/gentle-berries-decide.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css": patch +--- + +**Added:** all `Value` subtype now correctly implement the `(Partially)Resovable` interfaces. diff --git a/.changeset/pretty-waves-peel.md b/.changeset/pretty-waves-peel.md new file mode 100644 index 0000000000..53efec6556 --- /dev/null +++ b/.changeset/pretty-waves-peel.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css": minor +--- + +**Breaking:** `Image.partiallyResolve()` and `Shape.partiallyResolve()` functions has been replaced by instance methods of the same name. diff --git a/docs/review/api/alfa-css.api.md b/docs/review/api/alfa-css.api.md index 44f90a0db7..25cc41cdab 100644 --- a/docs/review/api/alfa-css.api.md +++ b/docs/review/api/alfa-css.api.md @@ -27,6 +27,7 @@ export type Angle = Angle.Calculated | Angle. // @public (undocumented) export namespace Angle { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Calculated extends Dimension.Calculated<"angle"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -45,7 +46,7 @@ export namespace Angle { } // (undocumented) export type Canonical = Fixed<"deg">; - // Warning: (ae-forgotten-export) The symbol "Resolvable" needs to be exported by the entry point index.d.ts + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Fixed extends Dimension.Fixed<"angle", U> implements Resolvable, Comparable> { // (undocumented) equals(value: unknown): value is this; @@ -97,6 +98,7 @@ export type AnglePercentage = AnglePercentage // @public (undocumented) export namespace AnglePercentage { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Calculated extends Dimension.Calculated<"angle-percentage"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -211,7 +213,8 @@ export namespace Box { } // Warning: (ae-forgotten-export) The symbol "BasicShape" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "PartiallyResolvable" needs to be exported by the entry point index.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "Circle" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Circle" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal // // @public (undocumented) export class Circle extends BasicShape<"circle", Value.HasCalculation<[R, P]>> implements Resolvable, PartiallyResolvable { @@ -397,6 +400,8 @@ export namespace Dimension { // Warning: (ae-forgotten-export) The symbol "Type" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DBase" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DCanonicalUnit" needs to be exported by the entry point index.d.ts + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal export abstract class Calculated extends Numeric.Calculated implements Resolvable, unknown>, PartiallyResolvable { protected constructor(math: Numeric.ToMath, type: T); // (undocumented) @@ -414,6 +419,7 @@ export namespace Dimension { } // Warning: (ae-forgotten-export) The symbol "Numeric_2" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DUnit" needs to be exported by the entry point index.d.ts + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal export abstract class Fixed extends Numeric.Fixed implements Resolvable, unknown>, Convertible, Comparable> { protected constructor(value: number, unit: U, type: T); // (undocumented) @@ -457,6 +463,9 @@ export namespace Dimension { export function isFixed(value: unknown): value is Fixed; } +// Warning: (ae-incompatible-release-tags) The symbol "Ellipse" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Ellipse" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class Ellipse extends BasicShape<"ellipse", Value.HasCalculation<[R, P]>> implements Resolvable, PartiallyResolvable { // (undocumented) @@ -663,8 +672,11 @@ export namespace HSL { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Image" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Image" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) -export class Image extends Value<"image", Value.HasCalculation<[I]>> { +export class Image extends Value<"image", Value.HasCalculation<[I]>> implements Resolvable, PartiallyResolvable { // (undocumented) equals(value: unknown): value is this; // (undocumented) @@ -674,6 +686,8 @@ export class Image extends Value<"ima // (undocumented) static of(image: I): Image; // (undocumented) + partiallyResolve(resolver: Image.PartialResolver): Image.PartiallyResolved; + // (undocumented) resolve(resolver: Image.Resolver): Image.Canonical; // (undocumented) toJSON(): Image.JSON; @@ -693,8 +707,6 @@ export namespace Image { image: URL.JSON | Gradient.JSON; } // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Image) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Image; // (undocumented) export type PartialResolver = URL.Resolver & Gradient.PartialResolver; @@ -706,6 +718,8 @@ export namespace Image { // Warning: (ae-forgotten-export) The symbol "Corner_2" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "HasCalculation" needs to be exported by the entry point index.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "Inset" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Inset" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal // // @public (undocumented) export class Inset extends BasicShape<"inset", HasCalculation> implements Resolvable, PartiallyResolvable { @@ -777,6 +791,7 @@ export type Integer = Integer.Calculated | Integer.Fixed; // @public (undocumented) export namespace Integer { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Calculated extends Numeric.Calculated<"number"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -797,6 +812,7 @@ export namespace Integer { } // (undocumented) export type Canonical = Fixed; + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Fixed extends Numeric.Fixed<"number"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -837,6 +853,8 @@ export namespace Integer { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Keyword" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) export class Keyword extends Value<"keyword", false> implements Resolvable, never> { // (undocumented) @@ -876,6 +894,7 @@ export type Length = Length.Calculated | Le // @public (undocumented) export namespace Length { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Calculated extends Dimension.Calculated<"length"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -894,6 +913,7 @@ export namespace Length { } // (undocumented) export type Canonical = Fixed<"px">; + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal export class Fixed extends Dimension.Fixed<"length", U> implements Resolvable, Comparable> { // (undocumented) equals(value: unknown): value is this; @@ -956,6 +976,8 @@ export type LengthPercentage = LengthPercen // @public (undocumented) export namespace LengthPercentage { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal export class Calculated extends Dimension.Calculated<"length-percentage"> implements Resolvable, PartiallyResolvable { // (undocumented) equals(value: unknown): value is this; @@ -1017,6 +1039,9 @@ export namespace Lexer { export function lex(input: string): Slice; } +// Warning: (ae-incompatible-release-tags) The symbol "List" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "List" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class List extends Value<"list", Value.HasCalculation<[V]>> implements Iterable_2, Resolvable>, Resolvable.Resolver>, PartiallyResolvable>, Resolvable.PartialResolver> { // (undocumented) @@ -1148,6 +1173,7 @@ namespace Math_2 { export { Math_2 as Math } // Warning: (ae-forgotten-export) The symbol "Function_3" needs to be exported by the entry point index.d.ts +// Warning: (ae-incompatible-release-tags) The symbol "Matrix" is marked as @public, but its signature references "Resolvable" which is marked as @internal // // @public (undocumented) export class Matrix extends Function_3<"matrix", false> implements Resolvable { @@ -1295,6 +1321,7 @@ type Number_2 = Number_2.Calculated | Number_2.Fixed; // @public (undocumented) namespace Number_2 { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal class Calculated extends Numeric.Calculated<"number"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -1315,6 +1342,7 @@ namespace Number_2 { } // (undocumented) type Canonical = Fixed; + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal class Fixed extends Numeric.Fixed<"number"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; @@ -1359,6 +1387,7 @@ export type Numeric = Numeric.Calculated< // @public (undocumented) export namespace Numeric { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal export abstract class Calculated extends Value implements Resolvable, never> { // Warning: (ae-incompatible-release-tags) The symbol "__constructor" is marked as @public, but its signature references "Numeric" which is marked as @internal protected constructor(math: ToMath, type: T); @@ -1393,6 +1422,7 @@ export namespace Numeric { math: Serializable.ToJSON>; } } + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal export abstract class Fixed extends Value implements Resolvable, never>, Comparable { protected constructor(value: number, type: T); // (undocumented) @@ -1443,11 +1473,21 @@ export namespace Numeric { // @public (undocumented) export type Parser = Parser_2, V, string>; +// Warning: (ae-internal-missing-underscore) The name "PartiallyResolvable" should be prefixed with an underscore because the declaration is marked as @internal +// +// @internal +export interface PartiallyResolvable, in R> { + // (undocumented) + partiallyResolve(resolver?: R): V; +} + // @public (undocumented) export type Percentage = Percentage.Calculated | Percentage.Fixed; // @public (undocumented) export namespace Percentage { + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "Resolvable" which is marked as @internal + // Warning: (ae-incompatible-release-tags) The symbol "Calculated" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal export class Calculated extends Numeric.Calculated<"percentage", H, "percentage"> implements Resolvable>, PartiallyResolvable, PartialResolver> { // (undocumented) equals(value: unknown): value is this; @@ -1458,7 +1498,7 @@ export namespace Percentage { // (undocumented) partiallyResolve(): PartiallyResolved; // (undocumented) - resolve(): Canonical; + resolve(): Fixed; // (undocumented) resolve(resolver: Resolver): T; // (undocumented) @@ -1471,8 +1511,10 @@ export namespace Percentage { } } // (undocumented) - export type Canonical = Fixed; + export type Canonical = Fixed<"percentage">; // Warning: (ae-forgotten-export) The symbol "Canonicals" needs to be exported by the entry point index.d.ts + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "Resolvable" which is marked as @internal + // Warning: (ae-incompatible-release-tags) The symbol "Fixed" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal export class Fixed extends Numeric.Fixed<"percentage", "percentage" | H, "percentage"> implements Resolvable>, PartiallyResolvable, PartialResolver> { // (undocumented) equals(value: unknown): value is this; @@ -1521,6 +1563,8 @@ export namespace Percentage { }; } +// Warning: (ae-incompatible-release-tags) The symbol "Perspective" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) export class Perspective extends Function_3<"perspective", Value.HasCalculation<[D]>> implements Resolvable { // (undocumented) @@ -1556,6 +1600,9 @@ export namespace Perspective { parse: Parser_2, Perspective>, string, []>; } +// Warning: (ae-incompatible-release-tags) The symbol "Polygon" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Polygon" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class Polygon extends BasicShape<"polygon", Value.HasCalculation<[V]>> implements Resolvable, PartiallyResolvable { // (undocumented) @@ -1610,6 +1657,9 @@ export namespace Polygon { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Position" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Position" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class Position = Position.Component, VC extends Position.Component = Position.Component> extends Value<"position", Value.HasCalculation<[HC, VC]>> implements Resolvable, Position.Resolver>, PartiallyResolvable, Position.PartialResolver> { // (undocumented) @@ -1662,6 +1712,9 @@ export namespace Position { } } +// Warning: (ae-incompatible-release-tags) The symbol "Radius" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Radius" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class Radius extends BasicShape<"radius", Value.HasCalculation<[R]>> implements Resolvable, PartiallyResolvable { // (undocumented) @@ -1714,8 +1767,10 @@ export namespace Radius { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Rectangle" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public @deprecated (undocumented) -export class Rectangle extends BasicShape<"rectangle", Value.HasCalculation<[O, O, O, O]>> { +export class Rectangle extends BasicShape<"rectangle", Value.HasCalculation<[O, O, O, O]>> implements Resolvable { // (undocumented) get bottom(): O; // (undocumented) @@ -1773,6 +1828,25 @@ export namespace Rectangle { parse: Parser; } +// Warning: (ae-internal-missing-underscore) The name "Resolvable" should be prefixed with an underscore because the declaration is marked as @internal +// +// @internal (undocumented) +export interface Resolvable, in R> { + // (undocumented) + resolve(resolver?: R): V; +} + +// @internal (undocumented) +export namespace Resolvable { + export type PartiallyResolved = V extends PartiallyResolvable ? U : never; + export type PartialResolver = UnionToIntersection, never> ? never : V extends PartiallyResolvable, infer R> ? R : never>; + export type Resolved = V extends Resolvable ? U : never; + export type Resolver = UnionToIntersection, never> ? never : V extends Resolvable, infer R> ? R : never>; + // (undocumented) + export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; + {}; +} + // @public (undocumented) export class RGB, A extends Number_2.Canonical | Percentage.Canonical = Number_2.Canonical | Percentage.Fixed<"percentage">> extends Format<"rgb"> { // (undocumented) @@ -1822,6 +1896,8 @@ export namespace RGB { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Rotate" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) export class Rotate extends Function_3<"rotate", false> implements Resolvable { // (undocumented) @@ -1867,6 +1943,8 @@ export namespace Rotate { parse: Parser_2, Rotate, string, []>; } +// Warning: (ae-incompatible-release-tags) The symbol "Scale" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) export class Scale extends Function_3<"scale", false> implements Resolvable { // (undocumented) @@ -1906,6 +1984,8 @@ export namespace Scale { parse: Parser_2, Scale, string, []>; } +// Warning: (ae-incompatible-release-tags) The symbol "Shadow" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) export class Shadow extends Value<"shadow", Value.HasCalculation<[H, V, B, S, C]>> implements Resolvable { // (undocumented) @@ -1968,8 +2048,11 @@ export namespace Shadow { export type Resolver = Length.Resolver; } +// Warning: (ae-incompatible-release-tags) The symbol "Shape" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Shape" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) -export class Shape extends Value<"shape", Value.HasCalculation<[S]>> { +export class Shape extends Value<"shape", Value.HasCalculation<[S]>> implements Resolvable, PartiallyResolvable { // (undocumented) get box(): B; // (undocumented) @@ -1981,6 +2064,8 @@ export class Shape(shape: S, box: B): Shape; // (undocumented) + partiallyResolve(resolver: Shape.PartialResolver): Shape.PartiallyResolved; + // (undocumented) resolve(resolver: Shape.Resolver): Shape.Canonical; // (undocumented) get shape(): S; @@ -2024,8 +2109,6 @@ export namespace Shape { shape: Basic.JSON; } // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Shape) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Shape; // (undocumented) export type PartialResolver = Basic.PartialResolver; @@ -2033,9 +2116,10 @@ export namespace Shape { export type Resolver = Basic.Resolver; const // (undocumented) parse: Parser>; - {}; } +// Warning: (ae-incompatible-release-tags) The symbol "Skew" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) export class Skew extends Function_3<"skew", false> implements Resolvable { // (undocumented) @@ -2073,6 +2157,8 @@ export namespace Skew { parse: Parser_2, Skew, string, []>; } +// Warning: (ae-incompatible-release-tags) The symbol "String" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) class String_2 extends Value<"string", false> implements Resolvable { // (undocumented) @@ -2922,6 +3008,9 @@ export namespace Transform { parseList: Parser>; } +// Warning: (ae-incompatible-release-tags) The symbol "Translate" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Translate" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class Translate extends Function_3<"translate", Value.HasCalculation<[X, Y, Z]>> implements Resolvable, PartiallyResolvable { // (undocumented) @@ -2971,6 +3060,9 @@ export namespace Translate { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Tuple" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Tuple" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public (undocumented) export class Tuple> extends Value<"tuple", Value.HasCalculation> implements Resolvable>, Tuple.Resolver>, PartiallyResolvable>, Tuple.PartialResolver> { // (undocumented) @@ -3002,11 +3094,15 @@ export namespace Tuple { // (undocumented) values: Serializable.ToJSON; } + // Warning: (ae-incompatible-release-tags) The symbol "PartiallyResolved" is marked as @public, but its signature references "Resolvable" which is marked as @internal + // // (undocumented) export type PartiallyResolved> = T extends [ infer Head extends Value, ...infer Tail extends Array ] ? [Resolvable.PartiallyResolved, ...PartiallyResolved] : []; + // Warning: (ae-incompatible-release-tags) The symbol "PartialResolver" is marked as @public, but its signature references "Resolvable" which is marked as @internal + // // (undocumented) export type PartialResolver> = T extends Array ? Resolvable.PartialResolver : never; // @internal @@ -3072,8 +3168,10 @@ export namespace Unit { export type Time = "s" | "ms"; } +// Warning: (ae-incompatible-release-tags) The symbol "URL" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// // @public (undocumented) -export class URL extends Value<"url", false> { +export class URL extends Value<"url", false> implements Resolvable { // (undocumented) equals(value: unknown): value is this; // (undocumented) @@ -3107,6 +3205,9 @@ export namespace URL { parse: Parser; } +// Warning: (ae-incompatible-release-tags) The symbol "Value" is marked as @public, but its signature references "Resolvable" which is marked as @internal +// Warning: (ae-incompatible-release-tags) The symbol "Value" is marked as @public, but its signature references "PartiallyResolvable" which is marked as @internal +// // @public export abstract class Value implements Equatable, Hashable, Serializable>, Resolvable, Resolvable.Resolver>, PartiallyResolvable, Resolvable.PartialResolver> { protected constructor(type: T, hasCalculation: CALC); diff --git a/docs/review/api/alfa-style.api.md b/docs/review/api/alfa-style.api.md index 3e19a66435..006f52590b 100644 --- a/docs/review/api/alfa-style.api.md +++ b/docs/review/api/alfa-style.api.md @@ -35,6 +35,7 @@ import { Percentage } from '@siteimprove/alfa-css'; import { Position } from '@siteimprove/alfa-css'; import { Predicate } from '@siteimprove/alfa-predicate'; import { Rectangle } from '@siteimprove/alfa-css'; +import type { Resolvable } from '@siteimprove/alfa-css'; import { Rotate } from '@siteimprove/alfa-css'; import { Serializable } from '@siteimprove/alfa-json'; import { Shadow } from '@siteimprove/alfa-css'; @@ -136,7 +137,7 @@ export namespace Longhands { readonly "border-end-start-radius": Longhand, Tuple<[horizontal: LengthPercentage, vertical: LengthPercentage]>>; readonly "border-image-outset": Longhand>; readonly "border-image-repeat": Longhand; - readonly "border-image-slice": Longhand; + readonly "border-image-slice": Longhand | Tuple<[top: Number_2.Fixed | Percentage.Canonical, right: Number_2.Fixed | Percentage.Canonical, bottom: Number_2.Fixed | Percentage.Canonical, left: Number_2.Fixed | Percentage.Canonical, fill: Keyword<"fill">]>>; readonly "border-image-source": Longhand>; readonly "border-image-width": Longhand, right: Number_2.Fixed | LengthPercentage | Keyword<"auto">, bottom: Number_2.Fixed | LengthPercentage | Keyword<"auto">, left: Number_2.Fixed | LengthPercentage | Keyword<"auto">]>>; readonly "border-inline-end-color": Longhand; @@ -163,14 +164,14 @@ export namespace Longhands { readonly "clip-path": Longhand | Shape, URL | Keyword<"none"> | Shape>; readonly clip: Longhand | Shape, Keyword<"border-box">>, Keyword<"auto"> | Shape, Keyword<"border-box">>>; readonly color: Longhand; - readonly cursor: Longhand>, Keyword<"auto"> | Keyword<"none"> | Keyword<"default"> | Keyword<"context-menu"> | Keyword<"help"> | Keyword<"pointer"> | Keyword<"progress"> | Keyword<"wait"> | Keyword<"cell"> | Keyword<"crosshair"> | Keyword<"text"> | Keyword<"vertical-text"> | Keyword<"alias"> | Keyword<"copy"> | Keyword<"move"> | Keyword<"no-drop"> | Keyword<"not-allowed"> | Keyword<"grab"> | Keyword<"grabbing"> | Keyword<"e-resize"> | Keyword<"n-resize"> | Keyword<"ne-resize"> | Keyword<"nw-resize"> | Keyword<"s-resize"> | Keyword<"se-resize"> | Keyword<"sw-resize"> | Keyword<"w-resize"> | Keyword<"ew-resize"> | Keyword<"ns-resize"> | Keyword<"nesw-resize"> | Keyword<"nwse-resize"> | Keyword<"col-resize"> | Keyword<"row-resize"> | Keyword<"all-scroll"> | Keyword<"zoom-in"> | Keyword<"zoom-out">]>, Tuple<[List>, Keyword<"auto"> | Keyword<"none"> | Keyword<"default"> | Keyword<"context-menu"> | Keyword<"help"> | Keyword<"pointer"> | Keyword<"progress"> | Keyword<"wait"> | Keyword<"cell"> | Keyword<"crosshair"> | Keyword<"text"> | Keyword<"vertical-text"> | Keyword<"alias"> | Keyword<"copy"> | Keyword<"move"> | Keyword<"no-drop"> | Keyword<"not-allowed"> | Keyword<"grab"> | Keyword<"grabbing"> | Keyword<"e-resize"> | Keyword<"n-resize"> | Keyword<"ne-resize"> | Keyword<"nw-resize"> | Keyword<"s-resize"> | Keyword<"se-resize"> | Keyword<"sw-resize"> | Keyword<"w-resize"> | Keyword<"ew-resize"> | Keyword<"ns-resize"> | Keyword<"nesw-resize"> | Keyword<"nwse-resize"> | Keyword<"col-resize"> | Keyword<"row-resize"> | Keyword<"all-scroll"> | Keyword<"zoom-in"> | Keyword<"zoom-out">]>>; + readonly cursor: Longhand>, Keyword<"auto"> | Keyword<"none"> | Keyword<"default"> | Keyword<"context-menu"> | Keyword<"help"> | Keyword<"pointer"> | Keyword<"progress"> | Keyword<"wait"> | Keyword<"cell"> | Keyword<"crosshair"> | Keyword<"text"> | Keyword<"vertical-text"> | Keyword<"alias"> | Keyword<"copy"> | Keyword<"move"> | Keyword<"no-drop"> | Keyword<"not-allowed"> | Keyword<"grab"> | Keyword<"grabbing"> | Keyword<"e-resize"> | Keyword<"n-resize"> | Keyword<"ne-resize"> | Keyword<"nw-resize"> | Keyword<"s-resize"> | Keyword<"se-resize"> | Keyword<"sw-resize"> | Keyword<"w-resize"> | Keyword<"ew-resize"> | Keyword<"ns-resize"> | Keyword<"nesw-resize"> | Keyword<"nwse-resize"> | Keyword<"col-resize"> | Keyword<"row-resize"> | Keyword<"all-scroll"> | Keyword<"zoom-in"> | Keyword<"zoom-out">]>, Tuple<[List>, Keyword<"auto"> | Keyword<"none"> | Keyword<"default"> | Keyword<"context-menu"> | Keyword<"help"> | Keyword<"pointer"> | Keyword<"progress"> | Keyword<"wait"> | Keyword<"cell"> | Keyword<"crosshair"> | Keyword<"text"> | Keyword<"vertical-text"> | Keyword<"alias"> | Keyword<"copy"> | Keyword<"move"> | Keyword<"no-drop"> | Keyword<"not-allowed"> | Keyword<"grab"> | Keyword<"grabbing"> | Keyword<"e-resize"> | Keyword<"n-resize"> | Keyword<"ne-resize"> | Keyword<"nw-resize"> | Keyword<"s-resize"> | Keyword<"se-resize"> | Keyword<"sw-resize"> | Keyword<"w-resize"> | Keyword<"ew-resize"> | Keyword<"ns-resize"> | Keyword<"nesw-resize"> | Keyword<"nwse-resize"> | Keyword<"col-resize"> | Keyword<"row-resize"> | Keyword<"all-scroll"> | Keyword<"zoom-in"> | Keyword<"zoom-out">]>>; readonly display: Longhand | Keyword<"inline"> | Keyword<"run-in">, inside: Keyword<"flow"> | Keyword<"flow-root"> | Keyword<"table"> | Keyword<"flex"> | Keyword<"grid"> | Keyword<"ruby">]> | Tuple<[outside: Keyword<"block"> | Keyword<"inline"> | Keyword<"run-in">, inside: Keyword<"flow"> | Keyword<"flow-root"> | Keyword<"table"> | Keyword<"flex"> | Keyword<"grid"> | Keyword<"ruby">, listitem: Keyword<"list-item">]> | Tuple<[outside: Keyword<"table-row-group"> | Keyword<"table-header-group"> | Keyword<"table-footer-group"> | Keyword<"table-row"> | Keyword<"table-cell"> | Keyword<"table-column-group"> | Keyword<"table-column"> | Keyword<"table-caption"> | Keyword<"ruby-base"> | Keyword<"ruby-text"> | Keyword<"ruby-base-container"> | Keyword<"ruby-text-container">, inside: Keyword<"flow"> | Keyword<"flow-root"> | Keyword<"table"> | Keyword<"flex"> | Keyword<"grid"> | Keyword<"ruby">]> | Tuple<[Keyword<"none"> | Keyword<"contents">]>, Tuple<[outside: Keyword<"block"> | Keyword<"inline"> | Keyword<"run-in">, inside: Keyword<"flow"> | Keyword<"flow-root"> | Keyword<"table"> | Keyword<"flex"> | Keyword<"grid"> | Keyword<"ruby">]> | Tuple<[outside: Keyword<"block"> | Keyword<"inline"> | Keyword<"run-in">, inside: Keyword<"flow"> | Keyword<"flow-root"> | Keyword<"table"> | Keyword<"flex"> | Keyword<"grid"> | Keyword<"ruby">, listitem: Keyword<"list-item">]> | Tuple<[outside: Keyword<"table-row-group"> | Keyword<"table-header-group"> | Keyword<"table-footer-group"> | Keyword<"table-row"> | Keyword<"table-cell"> | Keyword<"table-column-group"> | Keyword<"table-column"> | Keyword<"table-caption"> | Keyword<"ruby-base"> | Keyword<"ruby-text"> | Keyword<"ruby-base-container"> | Keyword<"ruby-text-container">, inside: Keyword<"flow"> | Keyword<"flow-root"> | Keyword<"table"> | Keyword<"flex"> | Keyword<"grid"> | Keyword<"ruby">]> | Tuple<[Keyword<"none"> | Keyword<"contents">]>>; readonly "flex-direction": Longhand, Keyword.ToKeywords<"row" | "row-reverse" | "column" | "column-reverse">>; readonly "flex-wrap": Longhand, Keyword.ToKeywords<"nowrap" | "wrap" | "wrap-reverse">>; readonly float: Longhand, Keyword.ToKeywords<"none" | "left" | "right">>; readonly "font-family": Longhand | Keyword<"sans-serif"> | Keyword<"cursive"> | Keyword<"fantasy"> | Keyword<"monospace">>, List | Keyword<"sans-serif"> | Keyword<"cursive"> | Keyword<"fantasy"> | Keyword<"monospace">>>; readonly "font-size": Longhand | Keyword<"xx-small"> | Keyword<"x-small"> | Keyword<"small"> | Keyword<"large"> | Keyword<"x-large"> | Keyword<"xx-large"> | Keyword<"xxx-large"> | Keyword<"larger"> | Keyword<"smaller">, Length>; - readonly "font-stretch": Longhand | Percentage.Calculated>; + readonly "font-stretch": Longhand | Percentage.Fixed>; readonly "font-style": Longhand, Keyword.ToKeywords<"normal" | "italic" | "oblique">>; readonly "font-variant-caps": Longhand, Keyword.ToKeywords<"normal" | "small-caps" | "all-small-caps" | "petite-caps" | "all-petite-caps" | "unicase" | "titling-caps">>; readonly "font-variant-east-asian": Longhand; @@ -216,7 +217,7 @@ export namespace Longhands { readonly "vertical-align": Longhand | Keyword<"bottom"> | Keyword<"sub"> | Keyword<"super"> | Keyword<"baseline"> | Keyword<"text-top"> | Keyword<"text-bottom"> | Keyword<"middle">), Length | (Keyword<"top"> | Keyword<"bottom"> | Keyword<"sub"> | Keyword<"super"> | Keyword<"baseline"> | Keyword<"text-top"> | Keyword<"text-bottom"> | Keyword<"middle">)>; readonly visibility: Longhand, Keyword.ToKeywords<"hidden" | "collapse" | "visible">>; readonly "white-space": Longhand, Keyword.ToKeywords<"nowrap" | "normal" | "pre" | "pre-wrap" | "break-spaces" | "pre-line">>; - readonly width: Longhand, Length | Percentage.Canonical | Keyword<"auto">>; + readonly width: Longhand, LengthPercentage | Keyword<"auto">>; readonly "word-spacing": Longhand, Length>; }; // (undocumented) @@ -420,6 +421,8 @@ export class Value implements Functor, Applicative, Monad, // (undocumented) static of(value: T, source?: Option): Value; // (undocumented) + resolve(this: Value, resolver?: Resolvable.Resolver): Value>; + // (undocumented) some(predicate: Predicate]>): boolean; // (undocumented) get source(): Option; diff --git a/packages/alfa-css/src/value/image/gradient/linear/corner.ts b/packages/alfa-css/src/value/image/gradient/linear/corner.ts index 1b66f2438b..1385a273c8 100644 --- a/packages/alfa-css/src/value/image/gradient/linear/corner.ts +++ b/packages/alfa-css/src/value/image/gradient/linear/corner.ts @@ -3,6 +3,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { type Parser as CSSParser, Token } from "../../../../syntax"; +import { Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; import { Position } from "./position"; @@ -12,7 +13,10 @@ const { map, either, pair, option, right } = Parser; /** * @internal */ -export class Corner extends Value<"corner", false> { +export class Corner + extends Value<"corner", false> + implements Resolvable +{ public static of( vertical: Position.Vertical, horizontal: Position.Horizontal, diff --git a/packages/alfa-css/src/value/image/gradient/linear/side.ts b/packages/alfa-css/src/value/image/gradient/linear/side.ts index c15f6588bd..3f0a17a4ec 100644 --- a/packages/alfa-css/src/value/image/gradient/linear/side.ts +++ b/packages/alfa-css/src/value/image/gradient/linear/side.ts @@ -3,6 +3,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { Token } from "../../../../syntax"; +import { Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; import { Position } from "./position"; @@ -12,7 +13,10 @@ const { map, option, right } = Parser; /** * @internal */ -export class Side extends Value<"side", false> { +export class Side + extends Value<"side", false> + implements Resolvable +{ public static of(side: Position.Vertical | Position.Horizontal): Side { return new Side(side); } diff --git a/packages/alfa-css/src/value/image/gradient/radial/circle.ts b/packages/alfa-css/src/value/image/gradient/radial/circle.ts index 96bb450e67..740668573a 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/circle.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/circle.ts @@ -5,6 +5,7 @@ import { Parser as CSSParser, Token } from "../../../../syntax"; import { Keyword } from "../../../keyword"; import { Length } from "../../../numeric"; +import { Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; /** @@ -12,10 +13,10 @@ import { Value } from "../../../value"; * * @internal */ -export class Circle extends Value< - "circle", - Value.HasCalculation<[R]> -> { +export class Circle + extends Value<"circle", Value.HasCalculation<[R]>> + implements Resolvable +{ public static of(radius: R): Circle { return new Circle(radius); } diff --git a/packages/alfa-css/src/value/image/gradient/radial/extent.ts b/packages/alfa-css/src/value/image/gradient/radial/extent.ts index 414f4c5427..f1782b0b95 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/extent.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/extent.ts @@ -5,6 +5,7 @@ import { Err, Result } from "@siteimprove/alfa-result"; import { Parser as CSSParser, Token } from "../../../../syntax"; import { Keyword } from "../../../keyword"; +import { Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; const { map } = Parser; @@ -12,7 +13,10 @@ const { map } = Parser; /** * @internal */ -export class Extent extends Value<"extent", false> { +export class Extent + extends Value<"extent", false> + implements Resolvable +{ public static of( shape: Extent.Shape = Extent.Shape.Circle, size: Extent.Size = Extent.Size.FarthestCorner, diff --git a/packages/alfa-css/src/value/image/image.ts b/packages/alfa-css/src/value/image/image.ts index 37c6167eb3..a5e302341d 100644 --- a/packages/alfa-css/src/value/image/image.ts +++ b/packages/alfa-css/src/value/image/image.ts @@ -3,6 +3,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { Selective } from "@siteimprove/alfa-selective"; import type { Parser as CSSParser } from "../../syntax"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; @@ -16,10 +17,12 @@ const { map, either } = Parser; * * @public */ -export class Image extends Value< - "image", - Value.HasCalculation<[I]> -> { +export class Image + extends Value<"image", Value.HasCalculation<[I]>> + implements + Resolvable, + PartiallyResolvable +{ public static of(image: I): Image { return new Image(image); } @@ -39,6 +42,17 @@ export class Image extends Value< return new Image(this._image.resolve(resolver)); } + public partiallyResolve( + resolver: Image.PartialResolver, + ): Image.PartiallyResolved { + return Image.of( + Selective.of(this._image) + .if(URL.isURL, (url) => url.resolve()) + .else((gradient) => gradient.partiallyResolve(resolver)) + .get(), + ); + } + public equals(value: unknown): value is this { return value instanceof Image && value._image.equals(this._image); } @@ -77,18 +91,6 @@ export namespace Image { export type PartialResolver = URL.Resolver & Gradient.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver, - ): (value: Image) => PartiallyResolved { - return (value) => - Image.of( - Selective.of(value.image) - .if(URL.isURL, (url) => url.resolve()) - .else((gradient) => gradient.partiallyResolve(resolver)) - .get(), - ); - } - export function isImage( value: unknown, ): value is Image { diff --git a/packages/alfa-css/src/value/image/url.ts b/packages/alfa-css/src/value/image/url.ts index 7fa6bf4fbf..a0367f9a3d 100644 --- a/packages/alfa-css/src/value/image/url.ts +++ b/packages/alfa-css/src/value/image/url.ts @@ -2,6 +2,7 @@ import { Hash } from "@siteimprove/alfa-hash"; import { Parser } from "@siteimprove/alfa-parser"; import { Function, type Parser as CSSParser, Token } from "../../syntax"; +import { Resolvable } from "../resolvable"; import { Value } from "../value"; @@ -12,7 +13,7 @@ const { map, either } = Parser; * * @public */ -export class URL extends Value<"url", false> { +export class URL extends Value<"url", false> implements Resolvable { public static of(url: string): URL { return new URL(url); } diff --git a/packages/alfa-css/src/value/index.ts b/packages/alfa-css/src/value/index.ts index 19cc17ad11..dc5541133e 100644 --- a/packages/alfa-css/src/value/index.ts +++ b/packages/alfa-css/src/value/index.ts @@ -5,6 +5,7 @@ export * from "./image"; export * from "./keyword"; export * from "./numeric"; export * from "./position"; +export * from "./resolvable"; export * from "./shadow"; export * from "./shape"; export * from "./string"; diff --git a/packages/alfa-css/src/value/numeric/percentage.ts b/packages/alfa-css/src/value/numeric/percentage.ts index 31f9a21d60..2509bece6a 100644 --- a/packages/alfa-css/src/value/numeric/percentage.ts +++ b/packages/alfa-css/src/value/numeric/percentage.ts @@ -52,7 +52,7 @@ export type Percentage = * @public */ export namespace Percentage { - export type Canonical = Fixed; + export type Canonical = Fixed<"percentage">; export type PartiallyResolved = Fixed; @@ -80,13 +80,13 @@ export namespace Percentage { return true; } - public resolve(): Canonical; + public resolve(): Fixed; public resolve(resolver: Resolver): T; public resolve( resolver?: Resolver, - ): Canonical | T { + ): Fixed | T { const percentage = Fixed.of( this._math .resolve() diff --git a/packages/alfa-css/src/value/shape/rectangle.ts b/packages/alfa-css/src/value/shape/rectangle.ts index 0cc0ae7ace..e339a2e269 100644 --- a/packages/alfa-css/src/value/shape/rectangle.ts +++ b/packages/alfa-css/src/value/shape/rectangle.ts @@ -5,6 +5,7 @@ import { Comma, Function, type Parser as CSSParser, Token } from "../../syntax"; import { Keyword } from "../keyword"; import { Length } from "../numeric"; +import { Resolvable } from "../resolvable"; import { Value } from "../value"; import { BasicShape } from "./basic-shape"; @@ -18,8 +19,11 @@ const { either, map, option, separatedList } = Parser; * @deprecated Deprecated as of CSS Masking Module Level 1 */ export class Rectangle< - O extends Length | Rectangle.Auto = Length | Rectangle.Auto, -> extends BasicShape<"rectangle", Value.HasCalculation<[O, O, O, O]>> { + O extends Length | Rectangle.Auto = Length | Rectangle.Auto, + > + extends BasicShape<"rectangle", Value.HasCalculation<[O, O, O, O]>> + implements Resolvable +{ public static of( top: O, right: O, diff --git a/packages/alfa-css/src/value/shape/shape.ts b/packages/alfa-css/src/value/shape/shape.ts index ee79c58533..b1024da7a8 100644 --- a/packages/alfa-css/src/value/shape/shape.ts +++ b/packages/alfa-css/src/value/shape/shape.ts @@ -3,6 +3,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { Err, Result } from "@siteimprove/alfa-result"; import { Selective } from "@siteimprove/alfa-selective"; import { Slice } from "@siteimprove/alfa-slice"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { type Parser as CSSParser, Token } from "../../syntax"; @@ -22,9 +23,14 @@ const { either } = Parser; * @public */ export class Shape< - S extends Shape.Basic = Shape.Basic, - B extends Box.Geometry = Box.Geometry, -> extends Value<"shape", Value.HasCalculation<[S]>> { + S extends Shape.Basic = Shape.Basic, + B extends Box.Geometry = Box.Geometry, + > + extends Value<"shape", Value.HasCalculation<[S]>> + implements + Resolvable, + PartiallyResolvable +{ public static of< S extends Shape.Basic = Shape.Basic, B extends Box.Geometry = Box.Geometry, @@ -53,6 +59,15 @@ export class Shape< return new Shape(this._shape.resolve(resolver), this._box); } + public partiallyResolve( + resolver: Shape.PartialResolver, + ): Shape.PartiallyResolved { + return Shape.of( + Shape.Basic.partiallyResolve(resolver)(this._shape), + this._box, + ); + } + public equals(value: Shape): boolean; public equals(value: unknown): value is this; @@ -93,7 +108,7 @@ export namespace Shape { */ export type Basic = Circle | Ellipse | Inset | Polygon | Rectangle; - namespace Basic { + export namespace Basic { export type Canonical = | Circle.Canonical | Ellipse.Canonical @@ -161,13 +176,6 @@ export namespace Shape { export type PartialResolver = Basic.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver, - ): (value: Shape) => PartiallyResolved { - return (value) => - Shape.of(Basic.partiallyResolve(resolver)(value.shape), value.box); - } - /** * @remarks * This does not parse the deprecated `rect()` shape. diff --git a/packages/alfa-style/src/property/background-color.ts b/packages/alfa-style/src/property/background-color.ts index a590505a5c..4922f696cd 100644 --- a/packages/alfa-style/src/property/background-color.ts +++ b/packages/alfa-style/src/property/background-color.ts @@ -10,6 +10,9 @@ export type Specified = Color; type Computed = Color.Canonical; /** + * @remarks + * This is used by the shorthand parser for background. + * * @internal */ export const parse = Color.parse; @@ -26,5 +29,5 @@ export default Longhand.of( Percentage.of(0), ), parse, - (value) => value.map((color) => color.resolve()), + (value) => value.resolve(), ); diff --git a/packages/alfa-style/src/property/background-image.ts b/packages/alfa-style/src/property/background-image.ts index a6eb6d1079..9349fef7fe 100644 --- a/packages/alfa-style/src/property/background-image.ts +++ b/packages/alfa-style/src/property/background-image.ts @@ -41,7 +41,9 @@ export default Longhand.of( value.map((images) => images.map((image) => Selective.of(image) - .if(Image.isImage, Image.partiallyResolve(Resolver.length(style))) + .if(Image.isImage, (image) => + image.partiallyResolve(Resolver.length(style)), + ) .get(), ), ), diff --git a/packages/alfa-style/src/property/border-image-outset.ts b/packages/alfa-style/src/property/border-image-outset.ts index b2f1b184ad..15643c8ad2 100644 --- a/packages/alfa-style/src/property/border-image-outset.ts +++ b/packages/alfa-style/src/property/border-image-outset.ts @@ -63,15 +63,5 @@ export const parse = map( export default Longhand.of( Tuple.of(Number.of(0), Number.of(0), Number.of(0), Number.of(0)), parse, - (value, style) => - value.map(({ values: [t, r, b, l] }) => { - const resolver = resolve(style); - return Tuple.of(resolver(t), resolver(r), resolver(b), resolver(l)); - }), + (value, style) => value.resolve(Resolver.length(style)), ); - -function resolve(style: Style): (specified: Specified.Item) => Computed.Item { - const resolver = Resolver.length(style); - return (specified) => - Length.isLength(specified) ? specified.resolve(resolver) : specified; -} diff --git a/packages/alfa-style/src/property/border-image-slice.ts b/packages/alfa-style/src/property/border-image-slice.ts index a16c2fdb7f..33b44493ca 100644 --- a/packages/alfa-style/src/property/border-image-slice.ts +++ b/packages/alfa-style/src/property/border-image-slice.ts @@ -23,9 +23,9 @@ type ImageSlice = NoFill | WithFill; /** * @internal */ -export type Specified = ImageSlice; +export type Specified = ImageSlice>; -type Computed = Specified; +type Computed = ImageSlice; const parseItem = filter( either(Number.parse, Percentage.parse), @@ -111,5 +111,5 @@ export default Longhand.of( Percentage.of(1), ), parse, - (value) => value, + (value) => value.resolve(), ); diff --git a/packages/alfa-style/src/property/border-image-source.ts b/packages/alfa-style/src/property/border-image-source.ts index 41376a77a2..3153fe6834 100644 --- a/packages/alfa-style/src/property/border-image-source.ts +++ b/packages/alfa-style/src/property/border-image-source.ts @@ -29,7 +29,9 @@ export default Longhand.of( (value, style) => value.map((image) => Selective.of(image) - .if(Image.isImage, Image.partiallyResolve(Resolver.length(style))) + .if(Image.isImage, (image) => + image.partiallyResolve(Resolver.length(style)), + ) .get(), ), ); diff --git a/packages/alfa-style/src/property/border-top-color.ts b/packages/alfa-style/src/property/border-top-color.ts index 48767ccfc2..27d9c1c40c 100644 --- a/packages/alfa-style/src/property/border-top-color.ts +++ b/packages/alfa-style/src/property/border-top-color.ts @@ -10,6 +10,9 @@ export type Specified = Color; type Computed = Color.Canonical; /** + * @remarks + * This is used by the shorthand + * * @internal */ export const parse = Color.parse; @@ -19,5 +22,5 @@ export const parse = Color.parse; * @internal */ export default Longhand.of(Color.current, parse, (value) => - value.map((color) => color.resolve()), + value.resolve(), ); diff --git a/packages/alfa-style/src/property/border-top-left-radius.ts b/packages/alfa-style/src/property/border-top-left-radius.ts index 8829347e9d..e2e71e4def 100644 --- a/packages/alfa-style/src/property/border-top-left-radius.ts +++ b/packages/alfa-style/src/property/border-top-left-radius.ts @@ -10,13 +10,6 @@ type Specified = Tuple< [horizontal: LengthPercentage, vertical: LengthPercentage] >; -/** - * @remarks - * TODO: percentages resolve relative to the dimensions of the containing block, - * which we do not handle. - * This results in length-percentage calculations leaking to computed - * values, which is a bit annoying. - */ type Computed = Tuple< [ horizontal: LengthPercentage.PartiallyResolved, @@ -42,8 +35,6 @@ export default Longhand.of( parse, (value, style) => value.map(({ values: [h, v] }) => - // Percentages are relative to the size of the border box, which we don't - // really handle currently. Tuple.of( LengthPercentage.partiallyResolve(Resolver.length(style))(h), LengthPercentage.partiallyResolve(Resolver.length(style))(v), diff --git a/packages/alfa-style/src/property/box-shadow.ts b/packages/alfa-style/src/property/box-shadow.ts index 8a64060213..ed391dd791 100644 --- a/packages/alfa-style/src/property/box-shadow.ts +++ b/packages/alfa-style/src/property/box-shadow.ts @@ -19,6 +19,5 @@ const parseList = List.parseCommaSeparated(Shadow.parse()); export default Longhand.of( Keyword.of("none"), either(Keyword.parse("none"), parseList), - (boxShadow, style) => - boxShadow.map((value) => value.resolve(Resolver.length(style))), + (value, style) => value.resolve(Resolver.length(style)), ); diff --git a/packages/alfa-style/src/property/color.ts b/packages/alfa-style/src/property/color.ts index 20f119c1c4..c4c81ab321 100644 --- a/packages/alfa-style/src/property/color.ts +++ b/packages/alfa-style/src/property/color.ts @@ -13,7 +13,7 @@ type Computed = Color.Canonical; export default Longhand.of( Color.system("canvastext"), Color.parse, - (value) => value.map((color) => color.resolve()), + (value) => value.resolve(), { inherits: true, }, diff --git a/packages/alfa-style/src/property/cursor.ts b/packages/alfa-style/src/property/cursor.ts index c62fdb7b03..7d5f562246 100644 --- a/packages/alfa-style/src/property/cursor.ts +++ b/packages/alfa-style/src/property/cursor.ts @@ -57,7 +57,11 @@ namespace Specified { type Specified = Tuple<[List, Specified.Builtin]>; -type Computed = Specified; +type Computed = Tuple<[List, Specified.Builtin]>; + +namespace Computed { + export type Custom = URL | Tuple<[URL, Number.Canonical, Number.Canonical]>; +} const parseBuiltin = Keyword.parse( "auto", @@ -124,6 +128,6 @@ const parse = map( export default Longhand.of( Tuple.of(List.of([], ","), Keyword.of("auto")), parse, - (value) => value, + (value) => value.resolve(), { inherits: true }, ); diff --git a/packages/alfa-style/src/property/outline-color.ts b/packages/alfa-style/src/property/outline-color.ts index d66468a332..2161b8ea7f 100644 --- a/packages/alfa-style/src/property/outline-color.ts +++ b/packages/alfa-style/src/property/outline-color.ts @@ -13,12 +13,5 @@ type Computed = Color.Canonical | Keyword<"invert">; export default Longhand.of( Keyword.of("invert"), Color.parse, - (outlineColor) => - outlineColor.map((color) => { - if (color.type === "keyword" && color.value === "invert") { - return color; - } - - return color.resolve(); - }), + (value) => value.resolve(), ); diff --git a/packages/alfa-style/src/property/outline-offset.ts b/packages/alfa-style/src/property/outline-offset.ts index 4760ed5635..c55ec273cd 100644 --- a/packages/alfa-style/src/property/outline-offset.ts +++ b/packages/alfa-style/src/property/outline-offset.ts @@ -13,6 +13,5 @@ type Computed = Length.Canonical; export default Longhand.of( Length.of(0, "px"), Length.parse, - (value, style) => - value.map((offset) => offset.resolve(Resolver.length(style))), + (value, style) => value.resolve(Resolver.length(style)), ); diff --git a/packages/alfa-style/src/property/text-decoration-color.ts b/packages/alfa-style/src/property/text-decoration-color.ts index 9e9bb5d530..757724ffc4 100644 --- a/packages/alfa-style/src/property/text-decoration-color.ts +++ b/packages/alfa-style/src/property/text-decoration-color.ts @@ -6,8 +6,6 @@ type Specified = Color; type Computed = Color.Canonical; -const parse = Color.parse; - /** * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-color} * @@ -15,6 +13,6 @@ const parse = Color.parse; */ export default Longhand.of( Color.current, - parse, - (textDecorationColor) => textDecorationColor.map((color) => color.resolve()), + Color.parse, + (value) => value.resolve(), ); diff --git a/packages/alfa-style/src/property/text-decoration-thickness.ts b/packages/alfa-style/src/property/text-decoration-thickness.ts index 53baf95805..23759dd3a1 100644 --- a/packages/alfa-style/src/property/text-decoration-thickness.ts +++ b/packages/alfa-style/src/property/text-decoration-thickness.ts @@ -1,13 +1,10 @@ import { Keyword, LengthPercentage, type Token } from "@siteimprove/alfa-css"; import { Parser } from "@siteimprove/alfa-parser"; -import { Selective } from "@siteimprove/alfa-selective"; import type { Slice } from "@siteimprove/alfa-slice"; import { Longhand } from "../longhand"; import { Resolver } from "../resolver"; -import type { Computed as FontSize } from "./font-size"; - const { either } = Parser; type Specified = LengthPercentage | Keyword<"auto"> | Keyword<"from-font">; @@ -22,24 +19,16 @@ const parse = either, Specified, string>( LengthPercentage.parse, ); +const longhand: Longhand = Longhand.of( + Keyword.of("auto"), + parse, + (value, style) => + value.resolve( + Resolver.lengthPercentage(style.computed("font-size").value, style), + ), +); /** * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-thickness} * @internal */ -export default Longhand.of( - Keyword.of("auto"), - parse, - (thickness, style) => - thickness.map((value) => { - // We need the type assertion to help TS break a circular type reference: - // this -> style.computed -> Longhands.Name -> Longhands.longhands -> this. - const fontSize = style.computed("font-size").value as FontSize; - - return Selective.of(value) - .if( - LengthPercentage.isLengthPercentage, - LengthPercentage.resolve(Resolver.lengthPercentage(fontSize, style)), - ) - .get(); - }), -); +export default longhand; diff --git a/packages/alfa-style/src/property/text-indent.ts b/packages/alfa-style/src/property/text-indent.ts index cdaede903e..cd1e1b4ae2 100644 --- a/packages/alfa-style/src/property/text-indent.ts +++ b/packages/alfa-style/src/property/text-indent.ts @@ -5,14 +5,6 @@ import { Resolver } from "../resolver"; type Specified = LengthPercentage; -/** - * @remarks - * TODO: percentages resolve relative to the dimensions of the containing block, - * which we do not handle. - * This results in length-percentage calculations leaking to computed - * values, which is a bit annoying. - * - */ type Computed = LengthPercentage.PartiallyResolved; /** diff --git a/packages/alfa-style/src/property/text-shadow.ts b/packages/alfa-style/src/property/text-shadow.ts index c0feafa893..4549037d75 100644 --- a/packages/alfa-style/src/property/text-shadow.ts +++ b/packages/alfa-style/src/property/text-shadow.ts @@ -21,7 +21,6 @@ const parseList = List.parseCommaSeparated( export default Longhand.of( Keyword.of("none"), either(Keyword.parse("none"), parseList), - (textShadow, style) => - textShadow.map((value) => value.resolve(Resolver.length(style))), + (value, style) => value.resolve(Resolver.length(style)), { inherits: true }, ); diff --git a/packages/alfa-style/src/property/width.ts b/packages/alfa-style/src/property/width.ts index 344d179064..1302e92caf 100644 --- a/packages/alfa-style/src/property/width.ts +++ b/packages/alfa-style/src/property/width.ts @@ -1,19 +1,17 @@ -import { Keyword, Length, Percentage } from "@siteimprove/alfa-css"; +import { Keyword, LengthPercentage } from "@siteimprove/alfa-css"; import { Parser } from "@siteimprove/alfa-parser"; +import { Selective } from "@siteimprove/alfa-selective"; import { Longhand } from "../longhand"; import { Resolver } from "../resolver"; const { either } = Parser; -type Specified = Keyword<"auto"> | Length | Percentage; +type Specified = Keyword<"auto"> | LengthPercentage; -type Computed = Keyword<"auto"> | Length.Canonical | Percentage.Canonical; +type Computed = Keyword<"auto"> | LengthPercentage.PartiallyResolved; -const parse = either( - Keyword.parse("auto"), - either(Length.parse, Percentage.parse), -); +const parse = either(Keyword.parse("auto"), LengthPercentage.parse); /** * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/width} @@ -23,15 +21,12 @@ export default Longhand.of( Keyword.of("auto"), parse, (width, style) => - width.map((width) => { - switch (width.type) { - case "keyword": - return width; - case "percentage": - return width.resolve(); - - case "length": - return width.resolve(Resolver.length(style)); - } - }), + width.map((width) => + Selective.of(width) + .if( + LengthPercentage.isLengthPercentage, + LengthPercentage.partiallyResolve(Resolver.length(style)), + ) + .get(), + ), ); diff --git a/packages/alfa-style/src/property/word-spacing.ts b/packages/alfa-style/src/property/word-spacing.ts index 35b3a41bf0..fccdbd8e45 100644 --- a/packages/alfa-style/src/property/word-spacing.ts +++ b/packages/alfa-style/src/property/word-spacing.ts @@ -1,7 +1,6 @@ import { Keyword } from "@siteimprove/alfa-css"; import { Length } from "@siteimprove/alfa-css/src/value/numeric"; import { Parser } from "@siteimprove/alfa-parser"; -import { Selective } from "@siteimprove/alfa-selective"; import { Longhand } from "../longhand"; import { Resolver } from "../resolver"; @@ -21,15 +20,12 @@ const parse = either(Keyword.parse("normal"), Length.parse); export default Longhand.of( Length.of(0, "px"), parse, - (wordSpacing, style) => - wordSpacing.map((wordSpacing) => - Selective.of(wordSpacing) - .if(Length.isLength, (spacing) => - spacing.resolve(Resolver.length(style)), - ) - .else(() => Length.of(0, "px")) - .get(), - ), + (value, style) => + value + .resolve(Resolver.length(style)) + .map((wordSpacing) => + Keyword.isKeyword(wordSpacing) ? Length.of(0, "px") : wordSpacing, + ), { inherits: true, }, diff --git a/packages/alfa-style/src/value.ts b/packages/alfa-style/src/value.ts index 87cb46900b..4094f4fe1e 100644 --- a/packages/alfa-style/src/value.ts +++ b/packages/alfa-style/src/value.ts @@ -1,4 +1,5 @@ import { Applicative } from "@siteimprove/alfa-applicative"; +import type { Resolvable, Value as CSSValue } from "@siteimprove/alfa-css"; import { Declaration } from "@siteimprove/alfa-dom"; import { Equatable } from "@siteimprove/alfa-equatable"; import { Functor } from "@siteimprove/alfa-functor"; @@ -46,6 +47,16 @@ export class Value return new Value(mapper(this._value, this._source), this._source); } + public resolve( + this: Value, + resolver?: Resolvable.Resolver, + ): Value> { + return new Value( + this._value.resolve(resolver) as Resolvable.Resolved, + this._source, + ); + } + public apply(mapper: Value>): Value { return mapper.map((mapper) => mapper(this._value)); }