From 12f18d912e41b06139c2048a6b831531d7ccf097 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 13:21:24 +0100 Subject: [PATCH 01/13] Make partiallyResolvable an instance method --- packages/alfa-css/src/value/resolvable.ts | 30 +++++++++++++++++++++++ packages/alfa-css/src/value/value.ts | 29 ++++++++++++++-------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/packages/alfa-css/src/value/resolvable.ts b/packages/alfa-css/src/value/resolvable.ts index 862ba471f7..c14c247ce6 100644 --- a/packages/alfa-css/src/value/resolvable.ts +++ b/packages/alfa-css/src/value/resolvable.ts @@ -18,6 +18,13 @@ export namespace Resolvable { ? U : never; + /** + * The type of a partially resolved value (usually with percentages left + * untouched). + */ + export type PartiallyResolved = + V extends PartiallyResolvable ? U : never; + /** * @privateRemarks * Somehow, applying `V extends Resolvable ? R : never` @@ -54,4 +61,27 @@ export namespace Resolvable { ? R : never >; + + /** + * The type of the resolver needed to partially resolve a given Value. + */ + export type PartialResolver = UnionToIntersection< + // We first need to remove the `never` resolver from the union, to avoid + // everything collapsing to `unknown`. + V extends PartiallyResolvable, never> + ? never + : V extends PartiallyResolvable, infer R> + ? R + : never + >; +} + +/** + * Partially resolved values may still contain percentages (usually) and + * calculation with percentages. + * + * @internal + */ +export interface PartiallyResolvable, in R> { + partiallyResolve(resolver?: R): V; } diff --git a/packages/alfa-css/src/value/value.ts b/packages/alfa-css/src/value/value.ts index 3fc87817e9..d1ddb3f67f 100644 --- a/packages/alfa-css/src/value/value.ts +++ b/packages/alfa-css/src/value/value.ts @@ -4,9 +4,12 @@ import { Serializable } from "@siteimprove/alfa-json"; import * as json from "@siteimprove/alfa-json"; -import type { Resolvable } from "./resolvable"; +import type { PartiallyResolvable, Resolvable } from "./resolvable"; /** + * Representation of a CSS Value + * + * @remarks * * T: a string representation of the type stored in the value, * e.g. "length", "color", … * * CALC: whether the numeric values in this may include calculation or not. @@ -16,20 +19,22 @@ import type { Resolvable } from "./resolvable"; * * R: a string representation of the type stored in the resolved value. * This differs from T, typically, for dimension-percentage values that * are resolved as dimensions only. + * * PR: a string representation of the type stored in the partially resolved value. * * @public */ -// This is the main Value class that is implemented by all CSS values, with or -// without calculations. export abstract class Value< - T extends string = string, - CALC extends boolean = boolean, - R extends string = T -> implements + T extends string = string, + CALC extends boolean = boolean, + R extends string = T, + PR extends string = R, + > + implements Equatable, Hashable, Serializable>, - Resolvable, Resolvable.Resolver> + Resolvable, Resolvable.Resolver>, + PartiallyResolvable, Resolvable.PartialResolver> { private readonly _type: T; protected readonly _hasCalculation: CALC; @@ -43,12 +48,16 @@ export abstract class Value< return this._type; } - public hasCalculation(): this is Value { + public hasCalculation(): this is Value { return this._hasCalculation; } public abstract resolve(resolver?: unknown): Value; + public partiallyResolve(resolver?: unknown): Value { + return this.resolve(resolver) as unknown as Value; + } + public abstract equals(value: unknown): value is this; public abstract hash(hash: Hash): void; @@ -71,7 +80,7 @@ export namespace Value { export function isValue( value: unknown, - type?: T + type?: T, ): value is Value { return ( value instanceof Value && (type === undefined || value.type === type) From 4126bf051afa8bc4624e03b58fb115aaadd8c849 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 13:45:14 +0100 Subject: [PATCH 02/13] Rework type hints --- .../alfa-css/src/value/numeric/dimension.ts | 58 ++++++++----------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/packages/alfa-css/src/value/numeric/dimension.ts b/packages/alfa-css/src/value/numeric/dimension.ts index 6bead89f9c..8a1f8bb386 100644 --- a/packages/alfa-css/src/value/numeric/dimension.ts +++ b/packages/alfa-css/src/value/numeric/dimension.ts @@ -8,13 +8,6 @@ import type { Resolvable } from "../resolvable"; import { Numeric } from "./numeric"; -/** - * @public - */ -export type Dimension = - | Dimension.Calculated - | Dimension.Fixed[0]>; - /** * @public */ @@ -22,9 +15,9 @@ export namespace Dimension { /** * Dimensions that are the result of a calculation. */ - export abstract class Calculated - extends Numeric.Calculated[0]> - implements Resolvable[0], Dimensions[2]>, unknown> + export abstract class Calculated + extends Numeric.Calculated + implements Resolvable, unknown> { protected constructor(math: Numeric.ToMath, type: T) { super(math, type); @@ -36,7 +29,7 @@ export namespace Dimension { public abstract resolve( resolver?: unknown, - ): Fixed[0], Dimensions[2]>; + ): Fixed; public equals(value: unknown): value is this { return value instanceof Calculated && super.equals(value); @@ -54,12 +47,12 @@ export namespace Dimension { export abstract class Fixed< T extends BaseNumeric.Dimension = BaseNumeric.Dimension, // The actual unit in which the dimension is expressed, e.g px, em, rad, … - U extends Dimensions[1] = Dimensions[1], + U extends DUnit[T] = DUnit[T], > extends Numeric.Fixed implements - Resolvable[0], Dimensions[2]>, unknown>, - Convertible[1]>, + Resolvable, unknown>, + Convertible, Comparable> { protected readonly _unit: U; @@ -80,18 +73,16 @@ export namespace Dimension { /** * {@link https://drafts.csswg.org/css-values/#canonical-unit} */ - public get canonicalUnit(): Dimensions[2] { + public get canonicalUnit(): DCanonicalUnit[T] { // The this.type test does not correctly narrow T, so we need to force typing. - return (this.type === "angle" ? "deg" : "px") as Dimensions[2]; + return (this.type === "angle" ? "deg" : "px") as DCanonicalUnit[T]; } - public abstract hasUnit[1]>( - unit: V, - ): this is Fixed; + public abstract hasUnit(unit: V): this is Fixed; - public abstract withUnit[1]>(unit: V): Fixed; + public abstract withUnit(unit: V): Fixed; - public abstract resolve(resolver?: unknown): Fixed[2]>; + public abstract resolve(resolver?: unknown): Fixed; public equals(value: unknown): value is this { return ( @@ -124,8 +115,8 @@ export namespace Dimension { export namespace Fixed { export interface JSON< - T extends Type = Type, - U extends Dimensions[1] = Dimensions[1], + T extends BaseNumeric.Dimension = BaseNumeric.Dimension, + U extends DUnit[T] = DUnit[T], > extends Numeric.Fixed.JSON { unit: U; } @@ -147,17 +138,14 @@ export namespace Dimension { type Type = BaseNumeric.Dimension | `${BaseNumeric.Dimension}-percentage`; /** - * Helper type to turn a dimension or dimension-percentage type into its + * Helper types to turn a dimension or dimension-percentage type into its * components: - * [base dimension, corresponding unit, canonical unit] */ -type Dimensions = T extends "angle" - ? ["angle", Unit.Angle, "deg"] - : T extends "angle-percentage" - ? ["angle", Unit.Angle, "deg"] - : T extends "length" - ? ["length", Unit.Length, "px"] - : T extends "length-percentage" - ? ["length", Unit.Length, "px"] - : // We currently do not really support other dimensions - never; +type DBase = { + angle: "angle"; + "angle-percentage": "angle"; + length: "length"; + "length-percentage": "length"; +}; +type DUnit = { angle: Unit.Angle; length: Unit.Length }; +type DCanonicalUnit = { angle: "deg"; length: "px" }; From 5f948d3b2c16c6e6405000191c2ea63ae7887991 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 14:03:33 +0100 Subject: [PATCH 03/13] Make partiallyResolve a method in numeric values --- .../src/value/numeric/angle-percentage.ts | 27 ++++-------- .../alfa-css/src/value/numeric/dimension.ts | 12 ++--- .../alfa-css/src/value/numeric/integer.ts | 8 ++++ .../src/value/numeric/length-percentage.ts | 12 +++-- packages/alfa-css/src/value/numeric/number.ts | 8 ++++ .../alfa-css/src/value/numeric/numeric.ts | 18 +++++--- .../alfa-css/src/value/numeric/percentage.ts | 44 ++++++++++--------- 7 files changed, 77 insertions(+), 52 deletions(-) diff --git a/packages/alfa-css/src/value/numeric/angle-percentage.ts b/packages/alfa-css/src/value/numeric/angle-percentage.ts index 9fd7213d8f..202a0a639b 100644 --- a/packages/alfa-css/src/value/numeric/angle-percentage.ts +++ b/packages/alfa-css/src/value/numeric/angle-percentage.ts @@ -6,7 +6,7 @@ import * as Base from "../../calculation/numeric"; import { type Parser as CSSParser, Token } from "../../syntax"; import { Unit } from "../../unit"; -import type { Resolvable } from "../resolvable"; +import type { PartiallyResolvable, Resolvable } from "../resolvable"; import { Dimension } from "./dimension"; import { Angle } from "./angle"; @@ -35,7 +35,7 @@ export namespace AnglePercentage { */ export class Calculated extends Dimension.Calculated<"angle-percentage"> - implements Resolvable + implements Resolvable { public static of(value: Math<"angle-percentage">): Calculated { return new Calculated(value); @@ -49,7 +49,7 @@ export namespace AnglePercentage { return true; } - public resolve(resolver: Resolver): Canonical { + public resolve(): Canonical { return Angle.Fixed.of( this._math // The math expression resolver is only aware of BasePercentage and @@ -57,11 +57,8 @@ export namespace AnglePercentage { // so the resolver here is only aware of Percentage, and we need to // translate back and forth. .resolve({ - percentage: (value) => - Base.Angle.of( - resolver.percentageBase.value, - /* this is "deg"! */ resolver.percentageBase.unit, - ).scale(value.value), + // 100% is always 1 full turn! + percentage: (value) => Base.Angle.of(360, "deg").scale(value.value), }) // Since the expression has been correctly typed, it should always resolve. .getUnsafe(`Could not resolve ${this._math} as an angle`), @@ -85,22 +82,14 @@ export namespace AnglePercentage { | Percentage.Calculated.JSON | Percentage.Fixed.JSON; - // In order to resolve a percentage, we need a base (=100%) - // There are no relative angles, so these are easy to resolve. - export type Resolver = Percentage.Resolver<"angle">; - /** * Fully resolves an angle-percentage, when a full resolver is provided. */ - export function resolve( - resolver: Resolver, - ): (value: AnglePercentage) => Canonical { + export function resolve(): (value: AnglePercentage) => Canonical { return (value) => - // We need to break down the union to help TS find the correct overload - // of each component and correctly narrow the result. Percentage.isPercentage(value) - ? value.resolve(resolver) - : value.resolve(resolver); + ? value.resolve({ percentageBase: Angle.of(360, "deg") }) + : value.resolve(); } export function isAnglePercentage(value: unknown): value is AnglePercentage { diff --git a/packages/alfa-css/src/value/numeric/dimension.ts b/packages/alfa-css/src/value/numeric/dimension.ts index 8a1f8bb386..217a126f5f 100644 --- a/packages/alfa-css/src/value/numeric/dimension.ts +++ b/packages/alfa-css/src/value/numeric/dimension.ts @@ -4,7 +4,7 @@ import { Hash } from "@siteimprove/alfa-hash"; import { Numeric as BaseNumeric } from "../../calculation/numeric"; import { Convertible, Unit } from "../../unit"; -import type { Resolvable } from "../resolvable"; +import type { PartiallyResolvable, Resolvable } from "../resolvable"; import { Numeric } from "./numeric"; @@ -15,15 +15,17 @@ export namespace Dimension { /** * Dimensions that are the result of a calculation. */ - export abstract class Calculated - extends Numeric.Calculated - implements Resolvable, unknown> + export abstract class Calculated + extends Numeric.Calculated + implements + Resolvable, unknown>, + PartiallyResolvable { protected constructor(math: Numeric.ToMath, type: T) { super(math, type); } - public hasCalculation(): this is Calculated { + public hasCalculation(): this is Calculated { return true; } diff --git a/packages/alfa-css/src/value/numeric/integer.ts b/packages/alfa-css/src/value/numeric/integer.ts index 39050cf9b5..52f1c0e9bc 100644 --- a/packages/alfa-css/src/value/numeric/integer.ts +++ b/packages/alfa-css/src/value/numeric/integer.ts @@ -59,6 +59,10 @@ export namespace Integer { ); } + public partiallyResolve(): Canonical { + return this.resolve(); + } + public equals(value: unknown): value is this { return value instanceof Calculated && super.equals(value); } @@ -103,6 +107,10 @@ export namespace Integer { return this; } + public partiallyResolve(): this { + return this; + } + public scale(factor: number): Fixed { return new Fixed(this._value * factor); } diff --git a/packages/alfa-css/src/value/numeric/length-percentage.ts b/packages/alfa-css/src/value/numeric/length-percentage.ts index 31662741fc..fd179ccf45 100644 --- a/packages/alfa-css/src/value/numeric/length-percentage.ts +++ b/packages/alfa-css/src/value/numeric/length-percentage.ts @@ -7,7 +7,7 @@ import * as Base from "../../calculation/numeric"; import { type Parser as CSSParser, Token } from "../../syntax"; import { Unit } from "../../unit"; -import type { Resolvable } from "../resolvable"; +import type { PartiallyResolvable, Resolvable } from "../resolvable"; import { Dimension } from "./dimension"; import { Length } from "./length"; @@ -44,7 +44,9 @@ export namespace LengthPercentage { */ export class Calculated extends Dimension.Calculated<"length-percentage"> - implements Resolvable + implements + Resolvable, + PartiallyResolvable { public static of(value: Math<"length-percentage">): Calculated { return new Calculated(value); @@ -81,6 +83,10 @@ export namespace LengthPercentage { ); } + public partiallyResolve(resolver: PartialResolver): this { + return this; + } + public equals(value: unknown): value is this { return value instanceof Calculated && super.equals(value); } @@ -140,7 +146,7 @@ export namespace LengthPercentage { return (value) => Selective.of(value) .if(Length.isLength, (value) => value.resolve(resolver)) - .if(Percentage.isPercentage, Percentage.partiallyResolve) + .if(Percentage.isPercentage, (value) => value.partiallyResolve()) .get(); } diff --git a/packages/alfa-css/src/value/numeric/number.ts b/packages/alfa-css/src/value/numeric/number.ts index 291e94ab89..3127729fa5 100644 --- a/packages/alfa-css/src/value/numeric/number.ts +++ b/packages/alfa-css/src/value/numeric/number.ts @@ -51,6 +51,10 @@ export namespace Number { ); } + public partiallyResolve(): Canonical { + return this.resolve(); + } + public equals(value: unknown): value is this { return value instanceof Calculated && super.equals(value); } @@ -86,6 +90,10 @@ export namespace Number { return this; } + public partiallyResolve(): this { + return this; + } + public scale(factor: number): Fixed { return new Fixed(this._value * factor); } diff --git a/packages/alfa-css/src/value/numeric/numeric.ts b/packages/alfa-css/src/value/numeric/numeric.ts index baea4f6276..575b031cf6 100644 --- a/packages/alfa-css/src/value/numeric/numeric.ts +++ b/packages/alfa-css/src/value/numeric/numeric.ts @@ -31,8 +31,12 @@ export namespace Numeric { /** * Numerics that are the result of a calculation. */ - export abstract class Calculated - extends Value + export abstract class Calculated< + T extends Type = Type, + R extends Type = T, + PR extends Type = R, + > + extends Value implements Resolvable, never> { protected readonly _math: ToMath; @@ -46,7 +50,7 @@ export namespace Numeric { return this._math; } - public hasCalculation(): this is Calculated { + public hasCalculation(): this is Calculated { return true; } @@ -81,8 +85,12 @@ export namespace Numeric { /** * Numerics that are a fixed (not calculated) value. */ - export abstract class Fixed - extends Value + export abstract class Fixed< + T extends Type = Type, + R extends Type = T, + PR extends Type = R, + > + extends Value implements Resolvable, never>, Comparable { protected readonly _value: number; diff --git a/packages/alfa-css/src/value/numeric/percentage.ts b/packages/alfa-css/src/value/numeric/percentage.ts index 91e553ba02..31f9a21d60 100644 --- a/packages/alfa-css/src/value/numeric/percentage.ts +++ b/packages/alfa-css/src/value/numeric/percentage.ts @@ -10,7 +10,7 @@ import { import { Token } from "../../syntax"; -import { Resolvable } from "../resolvable"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import type { Angle } from "./angle"; import type { Integer } from "./integer"; @@ -54,13 +54,17 @@ export type Percentage = export namespace Percentage { export type Canonical = Fixed; + export type PartiallyResolved = Fixed; + /** * Percentages that are the result of a calculation. * */ export class Calculated - extends Numeric.Calculated<"percentage", H> - implements Resolvable> + extends Numeric.Calculated<"percentage", H, "percentage"> + implements + Resolvable>, + PartiallyResolvable, PartialResolver> { public static of( value: Math<"percentage">, @@ -97,6 +101,15 @@ export namespace Percentage { (resolver.percentageBase.scale(percentage.value) as T); } + public partiallyResolve(): PartiallyResolved { + return Fixed.of( + this._math + .resolve() + // Since the expression has been correctly typed, it should always resolve. + .getUnsafe(`Could not resolve ${this} as a percentage`), + ); + } + public equals(value: unknown): value is this { return value instanceof Calculated && super.equals(value); } @@ -117,8 +130,10 @@ export namespace Percentage { * Percentages that are a fixed (not calculated) value. */ export class Fixed - extends Numeric.Fixed<"percentage", "percentage" | H> - implements Resolvable> + extends Numeric.Fixed<"percentage", "percentage" | H, "percentage"> + implements + Resolvable>, + PartiallyResolvable, PartialResolver> { public static of( value: number | BasePercentage, @@ -147,6 +162,10 @@ export namespace Percentage { (resolver.percentageBase.scale(this._value) as T); } + public partiallyResolve(): PartiallyResolved { + return this; + } + public scale(factor: number): Fixed { return new Fixed(this._value * factor); } @@ -177,21 +196,6 @@ export namespace Percentage { export type PartialResolver = never; - export type PartiallyResolved = Fixed; - - export function partiallyResolve( - value: Percentage, - ): PartiallyResolved { - return isFixed(value) - ? value - : Fixed.of( - value.math - .resolve() - // Since the expression has been correctly typed, it should always resolve. - .getUnsafe(`Could not resolve ${value} as a percentage`), - ); - } - export function isCalculated(value: unknown): value is Calculated { return value instanceof Calculated; } From 1a08d0b2d7d0d096cc19882857fbb4b4145e1554 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 14:06:24 +0100 Subject: [PATCH 04/13] Add changesets --- .changeset/long-plums-join.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/long-plums-join.md diff --git a/.changeset/long-plums-join.md b/.changeset/long-plums-join.md new file mode 100644 index 0000000000..86ea62e18c --- /dev/null +++ b/.changeset/long-plums-join.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css": minor +--- + +**Breaking:** `Angle#resolve()` does not require a resolver anymore, since 100% is always 1 full turn. From b689b67a6c29a3956c6e48e4b284d0308e8e5d05 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 14:10:31 +0100 Subject: [PATCH 05/13] Add changesets --- .changeset/dry-peaches-draw.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/dry-peaches-draw.md diff --git a/.changeset/dry-peaches-draw.md b/.changeset/dry-peaches-draw.md new file mode 100644 index 0000000000..6d6a864230 --- /dev/null +++ b/.changeset/dry-peaches-draw.md @@ -0,0 +1,7 @@ +--- +"@siteimprove/alfa-css": minor +--- + +**Breaking:** Various `Value.partiallyResolve()` functions have been removed. + +Instead, use the corresponding `Value#partiallyResolve()` instance method. From 4b18a71c5f1f52c2d1c724ebda2d05602f4330bb Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 14:16:58 +0100 Subject: [PATCH 06/13] Add changeset --- .changeset/bright-gorillas-travel.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/bright-gorillas-travel.md diff --git a/.changeset/bright-gorillas-travel.md b/.changeset/bright-gorillas-travel.md new file mode 100644 index 0000000000..4a66c1b94b --- /dev/null +++ b/.changeset/bright-gorillas-travel.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css": minor +--- + +**Added:** `Value` now expose a `partiallyResolve()` instance method. From cd194523867a2bb38a88cb3dabefa7d402300288 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 14:17:18 +0100 Subject: [PATCH 07/13] Adapt tests --- .../value/numeric/angle-percentage.spec.ts | 20 ++++++++----------- .../test/value/numeric/percentage.spec.ts | 11 ++++------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts b/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts index ad39855e13..5cdc0ff5b1 100644 --- a/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts +++ b/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts @@ -8,10 +8,6 @@ const parse = parser(AnglePercentage.parse); const parseUnsafe = parserUnsafe(AnglePercentage.parse); const serialize = serializer(AnglePercentage.parse); -const resolver: AnglePercentage.Resolver = { - percentageBase: Angle.of(90, "deg"), -}; - test("parse() accepts angles", (t) => { t.deepEqual(serialize("2rad"), { type: "angle", value: 2, unit: "rad" }); }); @@ -79,7 +75,7 @@ test("parse() rejects math expressions without angles", (t) => { }); test("resolve() returns canonical angles", (t) => { - t.deepEqual(parseUnsafe("1turn").resolve(resolver).toJSON(), { + t.deepEqual(parseUnsafe("1turn").resolve().toJSON(), { type: "angle", value: 360, unit: "deg", @@ -87,7 +83,7 @@ test("resolve() returns canonical angles", (t) => { }); test("resolve() resolves angle calculations", (t) => { - t.deepEqual(parseUnsafe("calc(0.5turn + 90deg)").resolve(resolver).toJSON(), { + t.deepEqual(parseUnsafe("calc(0.5turn + 90deg)").resolve().toJSON(), { type: "angle", value: 270, unit: "deg", @@ -95,25 +91,25 @@ test("resolve() resolves angle calculations", (t) => { }); test("resolve() resolves pure percentages", (t) => { - t.deepEqual(parseUnsafe("50%").resolve(resolver).toJSON(), { + t.deepEqual(parseUnsafe("50%").resolve().toJSON(), { type: "angle", - value: 45, + value: 180, unit: "deg", }); }); test("resolve() resolves percentage calculations", (t) => { - t.deepEqual(parseUnsafe("calc((12% + 9%) * 2)").resolve(resolver).toJSON(), { + t.deepEqual(parseUnsafe("calc((12% + 9%) * 2)").resolve().toJSON(), { type: "angle", - value: 37.8, + value: 77.6, unit: "deg", }); }); test("resolve() resolves mix of angles and percentages", (t) => { - t.deepEqual(parseUnsafe("calc(0.5turn + 10%)").resolve(resolver).toJSON(), { + t.deepEqual(parseUnsafe("calc(0.5turn + 10%)").resolve().toJSON(), { type: "angle", - value: 189, + value: 216, unit: "deg", }); }); diff --git a/packages/alfa-css/test/value/numeric/percentage.spec.ts b/packages/alfa-css/test/value/numeric/percentage.spec.ts index c415d63a0a..b14560719c 100644 --- a/packages/alfa-css/test/value/numeric/percentage.spec.ts +++ b/packages/alfa-css/test/value/numeric/percentage.spec.ts @@ -35,11 +35,8 @@ test("parse() rejects math expressions with only numbers", (t) => { }); test("partiallyResolve() returns a bare percentage", (t) => { - t.deepEqual( - Percentage.partiallyResolve(parseUnsafe("calc((12% + 9%) * 2)")).toJSON(), - { - type: "percentage", - value: 0.42, - }, - ); + t.deepEqual(parseUnsafe("calc((12% + 9%) * 2)").partiallyResolve().toJSON(), { + type: "percentage", + value: 0.42, + }); }); From 2646af2a261fbef11cad6b23010c798427c86a80 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 14:17:31 +0100 Subject: [PATCH 08/13] Add partiallyResolve() method --- .../alfa-css/src/value/collection/list.ts | 17 ++++++++-- .../alfa-css/src/value/collection/tuple.ts | 32 +++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/packages/alfa-css/src/value/collection/list.ts b/packages/alfa-css/src/value/collection/list.ts index 44bb19cb0d..1126ce072b 100644 --- a/packages/alfa-css/src/value/collection/list.ts +++ b/packages/alfa-css/src/value/collection/list.ts @@ -6,7 +6,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { type Parser as CSSParser, Token } from "../../syntax"; -import type { Resolvable } from "../resolvable"; +import type { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; const { delimited, option, map, separatedList } = Parser; @@ -18,7 +18,11 @@ export class List extends Value<"list", Value.HasCalculation<[V]>> implements Iterable, - Resolvable>, Resolvable.Resolver> + Resolvable>, Resolvable.Resolver>, + PartiallyResolvable< + List>, + Resolvable.PartialResolver + > { public static of( values: Iterable, @@ -48,6 +52,15 @@ export class List ); } + public partiallyResolve( + resolver?: Resolvable.PartialResolver, + ): List> { + return this.map( + (value) => + value.partiallyResolve(resolver) as Resolvable.PartiallyResolved, + ); + } + public map(mapper: Mapper): List { return new List(this._values.map(mapper), this._separator); } diff --git a/packages/alfa-css/src/value/collection/tuple.ts b/packages/alfa-css/src/value/collection/tuple.ts index 05bf231cb8..18157b9be7 100644 --- a/packages/alfa-css/src/value/collection/tuple.ts +++ b/packages/alfa-css/src/value/collection/tuple.ts @@ -1,7 +1,7 @@ import { Hash } from "@siteimprove/alfa-hash"; import { Serializable } from "@siteimprove/alfa-json"; -import type { Resolvable } from "../resolvable"; +import type { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; /** @@ -9,7 +9,12 @@ import { Value } from "../value"; */ export class Tuple> extends Value<"tuple", Value.HasCalculation> - implements Resolvable>, Tuple.Resolver> + implements + Resolvable>, Tuple.Resolver>, + PartiallyResolvable< + Tuple>, + Tuple.PartialResolver + > { public static of>(...values: Readonly): Tuple { return new Tuple(values); @@ -32,6 +37,16 @@ export class Tuple> ); } + public partiallyResolve( + resolver?: Tuple.PartialResolver, + ): Tuple> { + return new Tuple>( + this._values.map((value) => + value.resolve(resolver), + ) as Tuple.PartiallyResolved, + ); + } + public equals>(value: Tuple): boolean; public equals(value: unknown): value is this; @@ -94,6 +109,13 @@ export namespace Tuple { ? [Resolvable.Resolved, ...Resolved] : []; + export type PartiallyResolved> = T extends [ + infer Head extends Value, + ...infer Tail extends Array, + ] + ? [Resolvable.PartiallyResolved, ...PartiallyResolved] + : []; + /** * Applying Resolver to all members of a tuple, collapsing them into * a single union @@ -105,4 +127,10 @@ export namespace Tuple { > ? Resolvable.Resolver : never; + + export type PartialResolver> = T extends Array< + infer V extends Value + > + ? Resolvable.PartialResolver + : never; } From 22b4bcfd5635b4fd43c31ba2469ca0b26aed69d7 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 15:27:45 +0100 Subject: [PATCH 09/13] Add partiallyResolve() method to Positions --- .../src/value/image/gradient/radial/radial.ts | 42 ++++---- .../src/value/numeric/angle-percentage.ts | 9 +- .../alfa-css/src/value/position/component.ts | 16 +-- .../alfa-css/src/value/position/position.ts | 101 +++++++++--------- packages/alfa-css/src/value/position/side.ts | 59 +++++----- packages/alfa-css/src/value/shape/circle.ts | 24 ++--- packages/alfa-css/src/value/shape/ellipse.ts | 26 ++--- .../value/numeric/angle-percentage.spec.ts | 28 +++-- packages/alfa-css/test/value/position.spec.ts | 44 ++++---- 9 files changed, 178 insertions(+), 171 deletions(-) diff --git a/packages/alfa-css/src/value/image/gradient/radial/radial.ts b/packages/alfa-css/src/value/image/gradient/radial/radial.ts index 611247ea91..4b07c77d98 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/radial.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/radial.ts @@ -29,17 +29,17 @@ const { map, either, pair, option, left, right, delimited } = Parser; export class Radial< I extends Item = Item, S extends Shape = Shape, - P extends Position = Position + P extends Position = Position, > extends Value<"gradient", Value.HasCalculation<[I, S, P]>> { public static of< I extends Item = Item, S extends Shape = Shape, - P extends Position = Position + P extends Position = Position, >( shape: S, position: P, items: Iterable, - repeats: boolean + repeats: boolean, ): Radial { return new Radial(shape, position, Array.from(items), repeats); } @@ -53,15 +53,15 @@ export class Radial< shape: S, position: P, items: Iterable, - repeats: boolean + repeats: boolean, ) { super( "gradient", Value.hasCalculation( shape, position, - ...items - ) as unknown as Value.HasCalculation<[I, S, P]> + ...items, + ) as unknown as Value.HasCalculation<[I, S, P]>, ); this._shape = shape; this._position = position; @@ -94,7 +94,7 @@ export class Radial< this._shape.resolve(resolver), this._position.resolve(resolver), this._items.map(Item.resolve(resolver)), - this._repeats + this._repeats, ); } @@ -136,7 +136,7 @@ export class Radial< public toString(): string { const args = [`${this._shape} at ${this._position}`, ...this._items].join( - ", " + ", ", ); return `${this._repeats ? "repeating-" : ""}radial-gradient(${args})`; @@ -174,14 +174,14 @@ export namespace Radial { Position.PartialResolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Radial) => PartiallyResolved { return (value) => Radial.of( Shape.partiallyResolve(resolver)(value.shape), - Position.partiallyResolve(resolver)(value.position), + value.position.partiallyResolve(resolver), Iterable.map(value.items, Item.partiallyResolve(resolver)), - value.repeats + value.repeats, ); } @@ -192,7 +192,7 @@ export namespace Radial { const parsePosition = right( delimited(option(Token.parseWhitespace), Keyword.parse("at")), - Position.parse(false /* legacySyntax */) + Position.parse(false /* legacySyntax */), ); /** @@ -209,18 +209,18 @@ export namespace Radial { either( pair( map(Shape.parse, (shape) => Option.of(shape)), - option(delimited(option(Token.parseWhitespace), parsePosition)) + option(delimited(option(Token.parseWhitespace), parsePosition)), ), map( parsePosition, - (position) => [None, Option.of(position)] as const - ) + (position) => [None, Option.of(position)] as const, + ), ), - Comma.parse - ) + Comma.parse, + ), ), - Item.parseList - ) + Item.parseList, + ), ), (result) => { const [fn, [shapeAndPosition, items]] = result; @@ -232,10 +232,10 @@ export namespace Radial { const position = shapeAndPosition .flatMap(([, position]) => position) .getOrElse(() => - Position.of(Keyword.of("center"), Keyword.of("center")) + Position.of(Keyword.of("center"), Keyword.of("center")), ); return Radial.of(shape, position, items, fn.name.startsWith("repeating")); - } + }, ); } diff --git a/packages/alfa-css/src/value/numeric/angle-percentage.ts b/packages/alfa-css/src/value/numeric/angle-percentage.ts index 202a0a639b..c67ac4ad9c 100644 --- a/packages/alfa-css/src/value/numeric/angle-percentage.ts +++ b/packages/alfa-css/src/value/numeric/angle-percentage.ts @@ -85,11 +85,10 @@ export namespace AnglePercentage { /** * Fully resolves an angle-percentage, when a full resolver is provided. */ - export function resolve(): (value: AnglePercentage) => Canonical { - return (value) => - Percentage.isPercentage(value) - ? value.resolve({ percentageBase: Angle.of(360, "deg") }) - : value.resolve(); + export function resolve(value: AnglePercentage): Canonical { + return Percentage.isPercentage(value) + ? value.resolve({ percentageBase: Angle.of(360, "deg") }) + : value.resolve(); } export function isAnglePercentage(value: unknown): value is AnglePercentage { diff --git a/packages/alfa-css/src/value/position/component.ts b/packages/alfa-css/src/value/position/component.ts index 373b3c48ff..3298be997f 100644 --- a/packages/alfa-css/src/value/position/component.ts +++ b/packages/alfa-css/src/value/position/component.ts @@ -17,7 +17,7 @@ export type Component< S extends Keywords.Horizontal | Keywords.Vertical = | Keywords.Horizontal | Keywords.Vertical, - O extends LengthPercentage = LengthPercentage + O extends LengthPercentage = LengthPercentage, > = Keywords.Center | Side; /** @@ -29,7 +29,7 @@ export namespace Component { | Side.Canonical; export type PartiallyResolved< - S extends Keywords.Horizontal | Keywords.Vertical + S extends Keywords.Horizontal | Keywords.Vertical, > = Keywords.Center | Side.PartiallyResolved; export type JSON = Keyword.JSON | Side.JSON; @@ -37,7 +37,7 @@ export namespace Component { export type Resolver = Side.Resolver; export function resolve( - resolver: Resolver + resolver: Resolver, ): (value: Component) => Canonical { return (value) => (Side.isSide(value) ? value.resolve(resolver) : value); } @@ -45,10 +45,10 @@ export namespace Component { export type PartialResolver = Side.PartialResolver; export function partiallyResolve< - S extends Keywords.Horizontal | Keywords.Vertical + S extends Keywords.Horizontal | Keywords.Vertical, >(resolver: PartialResolver): (value: Component) => PartiallyResolved { return (value) => - Side.isSide(value) ? Side.partiallyResolve(resolver)(value) : value; + Side.isSide(value) ? value.partiallyResolve(resolver) : value; } /** @@ -58,7 +58,7 @@ export namespace Component { * @internal */ export function parseOffset< - T extends Keywords.Horizontal | Keywords.Vertical + T extends Keywords.Horizontal | Keywords.Vertical, >(side: T): CSSParser> { return map(LengthPercentage.parse, (value) => Side.of(side, value)); } @@ -69,7 +69,7 @@ export namespace Component { */ export const parseHorizontal = either( parseOffset(Keyword.of("left")), - Side.parseHorizontal + Side.parseHorizontal, ); /** @@ -77,6 +77,6 @@ export namespace Component { */ export const parseVertical = either( parseOffset(Keyword.of("top")), - Side.parseVertical + Side.parseVertical, ); } diff --git a/packages/alfa-css/src/value/position/position.ts b/packages/alfa-css/src/value/position/position.ts index d3cfe36e2e..2eae68b795 100644 --- a/packages/alfa-css/src/value/position/position.ts +++ b/packages/alfa-css/src/value/position/position.ts @@ -4,11 +4,10 @@ import { Err } from "@siteimprove/alfa-result"; import { Slice } from "@siteimprove/alfa-slice"; import { type Parser as CSSParser, Token } from "../../syntax"; -import { Unit } from "../../unit"; import { Keyword } from "../keyword"; import { Length } from "../numeric"; -import { Resolvable } from "../resolvable"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import * as component from "./component"; @@ -32,16 +31,21 @@ export class Position< H extends Position.Keywords.Horizontal = Position.Keywords.Horizontal, V extends Position.Keywords.Vertical = Position.Keywords.Vertical, HC extends Position.Component = Position.Component, - VC extends Position.Component = Position.Component + VC extends Position.Component = Position.Component, > extends Value<"position", Value.HasCalculation<[HC, VC]>> - implements Resolvable, Position.Resolver> + implements + Resolvable, Position.Resolver>, + PartiallyResolvable< + Position.PartiallyResolved, + Position.PartialResolver + > { public static of< H extends Position.Keywords.Horizontal = Position.Keywords.Horizontal, V extends Position.Keywords.Vertical = Position.Keywords.Vertical, HC extends Position.Component = Position.Component, - VC extends Position.Component = Position.Component + VC extends Position.Component = Position.Component, >(horizontal: HC, vertical: VC): Position { return new Position(horizontal, vertical); } @@ -72,7 +76,16 @@ export class Position< Position.Component.resolve({ length: resolver.length, percentageBase: resolver.percentageVBase, - })(this._vertical) + })(this._vertical), + ); + } + + public partiallyResolve( + resolver: Position.PartialResolver, + ): Position.PartiallyResolved { + return new Position( + Position.Component.partiallyResolve(resolver)(this._horizontal), + Position.Component.partiallyResolve(resolver)(this._vertical), ); } @@ -107,12 +120,12 @@ export class Position< export namespace Position { export type Canonical< H extends Keywords.Horizontal = Keywords.Horizontal, - V extends Keywords.Vertical = Keywords.Vertical + V extends Keywords.Vertical = Keywords.Vertical, > = Position, Component.Canonical>; export type PartiallyResolved< H extends Keywords.Horizontal = Keywords.Horizontal, - V extends Keywords.Vertical = Keywords.Vertical + V extends Keywords.Vertical = Keywords.Vertical, > = Position< H, V, @@ -141,19 +154,6 @@ export namespace Position { export type PartialResolver = Component.PartialResolver; - export function partiallyResolve< - H extends Keywords.Horizontal, - V extends Keywords.Vertical - >( - resolver: PartialResolver - ): (value: Position) => PartiallyResolved { - return (value) => - Position.of( - Component.partiallyResolve(resolver)(value.horizontal), - Component.partiallyResolve(resolver)(value.vertical) - ); - } - /** * @remarks * Positions can be declared using either 1, 2, 3, or 4 tokens with the @@ -182,12 +182,12 @@ export namespace Position { */ const mapHV = ([horizontal, vertical]: [ Component, - Component + Component, ]) => Position.of(horizontal, vertical); const mapVH = ([vertical, horizontal]: [ Component, - Component + Component, ]) => Position.of(horizontal, vertical); const { @@ -201,17 +201,17 @@ export namespace Position { map( pair( parseHorizontalKeywordValue, - right(Token.parseWhitespace, parseVerticalKeywordValue) + right(Token.parseWhitespace, parseVerticalKeywordValue), ), - mapHV + mapHV, ), map( pair( parseVerticalKeywordValue, - right(Token.parseWhitespace, parseHorizontalKeywordValue) + right(Token.parseWhitespace, parseHorizontalKeywordValue), ), - mapVH - ) + mapVH, + ), ); // Hh V | H Vv | Vv H | V Hh @@ -220,28 +220,28 @@ export namespace Position { either( pair( parseHorizontalKeywordValue, - right(Token.parseWhitespace, parseVerticalKeyword) + right(Token.parseWhitespace, parseVerticalKeyword), ), pair( parseHorizontalKeyword, - right(Token.parseWhitespace, parseVerticalKeywordValue) - ) + right(Token.parseWhitespace, parseVerticalKeywordValue), + ), ), - mapHV + mapHV, ), map( either( pair( parseVerticalKeywordValue, - right(Token.parseWhitespace, parseHorizontalKeyword) + right(Token.parseWhitespace, parseHorizontalKeyword), ), pair( parseVerticalKeyword, - right(Token.parseWhitespace, parseHorizontalKeywordValue) - ) + right(Token.parseWhitespace, parseHorizontalKeywordValue), + ), ), - mapVH - ) + mapVH, + ), ); // H V | H v | h V | h v | V H = (H | h) (V | v) | V H @@ -250,35 +250,38 @@ export namespace Position { pair( either( parseHorizontalKeyword, - Component.parseOffset(Keyword.of("left")) + Component.parseOffset(Keyword.of("left")), ), right( Token.parseWhitespace, - either(parseVerticalKeyword, Component.parseOffset(Keyword.of("top"))) - ) + either( + parseVerticalKeyword, + Component.parseOffset(Keyword.of("top")), + ), + ), ), - mapHV + mapHV, ), map( pair( parseVerticalKeyword, - right(Token.parseWhitespace, parseHorizontalKeyword) + right(Token.parseWhitespace, parseHorizontalKeyword), ), - mapVH - ) + mapVH, + ), ); // H | V | h const parse1 = either, Position, string>( map(parseHorizontalKeyword, (horizontal) => - Position.of(horizontal, Keyword.of("center")) + Position.of(horizontal, Keyword.of("center")), ), map(parseVerticalKeyword, (vertical) => - Position.of(Keyword.of("center"), vertical) + Position.of(Keyword.of("center"), vertical), ), map(Component.parseOffset(Keyword.of("left")), (horizontal) => - Position.of(horizontal, Keyword.of("center")) - ) + Position.of(horizontal, Keyword.of("center")), + ), ); /** @@ -295,7 +298,7 @@ export namespace Position { parse4, legacySyntax ? parse3 : () => Err.of("Three-value syntax is not allowed"), parse2, - parse1 + parse1, ); } } diff --git a/packages/alfa-css/src/value/position/side.ts b/packages/alfa-css/src/value/position/side.ts index a91a6b62d3..929b27eddc 100644 --- a/packages/alfa-css/src/value/position/side.ts +++ b/packages/alfa-css/src/value/position/side.ts @@ -5,7 +5,7 @@ import { Parser as CSSParser, Token } from "../../syntax"; import { Keyword } from "../keyword"; import { LengthPercentage } from "../numeric"; -import { Resolvable } from "../resolvable"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { Keywords } from "./keywords"; @@ -19,32 +19,34 @@ export class Side< S extends Keywords.Vertical | Keywords.Horizontal = | Keywords.Vertical | Keywords.Horizontal, - O extends LengthPercentage = LengthPercentage + O extends LengthPercentage = LengthPercentage, > extends Value<"side", Value.HasCalculation<[O]>> - implements Resolvable, Side.Resolver> + implements + Resolvable, Side.Resolver>, + PartiallyResolvable, Side.PartialResolver> { public static of( - side: S + side: S, ): Side; public static of< S extends Keywords.Vertical | Keywords.Horizontal, - O extends LengthPercentage + O extends LengthPercentage, >(side: S, offset: O): Side; public static of< S extends Keywords.Vertical | Keywords.Horizontal, - O extends LengthPercentage + O extends LengthPercentage, >(side: S, offset: Option): Side; public static of< S extends Keywords.Vertical | Keywords.Horizontal, - O extends LengthPercentage + O extends LengthPercentage, >(side: S, offset?: O | Option): Side { return new Side( side, - Option.isOption(offset) ? offset : Option.from(offset) + Option.isOption(offset) ? offset : Option.from(offset), ); } @@ -54,7 +56,7 @@ export class Side< private constructor(side: S, offset: Option) { super( "side", - offset.some(Value.hasCalculation) as Value.HasCalculation<[O]> + offset.some(Value.hasCalculation) as Value.HasCalculation<[O]>, ); this._side = side; this._offset = offset; @@ -71,7 +73,16 @@ export class Side< public resolve(resolver: Side.Resolver): Side.Canonical { return new Side( this._side, - this._offset.map(LengthPercentage.resolve(resolver)) + this._offset.map(LengthPercentage.resolve(resolver)), + ); + } + + public partiallyResolve( + resolver: Side.PartialResolver, + ): Side.PartiallyResolved { + return new Side( + this._side, + this._offset.map(LengthPercentage.partiallyResolve(resolver)), ); } @@ -110,7 +121,7 @@ export namespace Side { Side; export type PartiallyResolved< - S extends Keywords.Vertical | Keywords.Horizontal + S extends Keywords.Vertical | Keywords.Horizontal, > = Side; export interface JSON extends Value.JSON<"side"> { @@ -122,16 +133,6 @@ export namespace Side { export type PartialResolver = LengthPercentage.PartialResolver; - export function partiallyResolve< - S extends Keywords.Vertical | Keywords.Horizontal - >(resolver: PartialResolver): (side: Side) => PartiallyResolved { - return (side) => - Side.of( - side.side, - side.offset.map(LengthPercentage.partiallyResolve(resolver)) - ); - } - export function isSide(value: unknown): value is Side { return value instanceof Side; } @@ -140,11 +141,11 @@ export namespace Side { * Parse a side keyword (top/bottom/left/right) or "center" */ function parseKeyword( - parser: CSSParser + parser: CSSParser, ): CSSParser | Side> { return either( Keywords.parseCenter, - map(parser, (side) => Side.of(side) as Side) + map(parser, (side) => Side.of(side) as Side), ); } @@ -152,33 +153,33 @@ export namespace Side { * Parse a side keyword followed by an offset (length-percentage). */ function parseKeywordValue( - parser: CSSParser + parser: CSSParser, ): CSSParser> { return map( pair(parser, right(Token.parseWhitespace, LengthPercentage.parse)), - ([keyword, value]) => Side.of(keyword, value) + ([keyword, value]) => Side.of(keyword, value), ); } export const parseHorizontalKeywordValue = parseKeywordValue( - Keywords.parseHorizontal + Keywords.parseHorizontal, ); export const parseHorizontalKeyword = parseKeyword(Keywords.parseHorizontal); export const parseHorizontal = either( parseHorizontalKeyword, - parseHorizontalKeywordValue + parseHorizontalKeywordValue, ); export const parseVerticalKeywordValue = parseKeywordValue( - Keywords.parseVertical + Keywords.parseVertical, ); export const parseVerticalKeyword = parseKeyword(Keywords.parseVertical); export const parseVertical = either( parseVerticalKeyword, - parseVerticalKeywordValue + parseVerticalKeywordValue, ); } diff --git a/packages/alfa-css/src/value/shape/circle.ts b/packages/alfa-css/src/value/shape/circle.ts index bba4a454fc..b4b0fda8ac 100644 --- a/packages/alfa-css/src/value/shape/circle.ts +++ b/packages/alfa-css/src/value/shape/circle.ts @@ -19,11 +19,11 @@ const { map, option, pair, right } = Parser; */ export class Circle< R extends Radius = Radius, - P extends Position = Position + P extends Position = Position, > extends BasicShape<"circle", Value.HasCalculation<[R, P]>> { public static of( radius: R, - center: P + center: P, ): Circle { return new Circle(radius, center); } @@ -48,7 +48,7 @@ export class Circle< public resolve(resolver: Circle.Resolver): Circle.Canonical { return new Circle( this._radius.resolve(resolver), - this._center.resolve(resolver) + this._center.resolve(resolver), ); } @@ -103,12 +103,12 @@ export namespace Circle { Position.PartialResolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Circle) => PartiallyResolved { return (value) => Circle.of( Radius.PartiallyResolve(resolver)(value.radius), - Position.partiallyResolve(resolver)(value.center) + value.center.partiallyResolve(resolver), ); } @@ -126,16 +126,16 @@ export namespace Circle { option(Token.parseWhitespace), right( Keyword.parse("at"), - right(Token.parseWhitespace, Position.parse()) - ) - ) - ) - ) + right(Token.parseWhitespace, Position.parse()), + ), + ), + ), + ), ), ([_, [radius, center]]) => Circle.of( radius.getOr(Radius.of(Keyword.of("closest-side"))), - center.getOr(Position.of(Keyword.of("center"), Keyword.of("center"))) - ) + center.getOr(Position.of(Keyword.of("center"), Keyword.of("center"))), + ), ); } diff --git a/packages/alfa-css/src/value/shape/ellipse.ts b/packages/alfa-css/src/value/shape/ellipse.ts index 8c27576169..3ea20178d1 100644 --- a/packages/alfa-css/src/value/shape/ellipse.ts +++ b/packages/alfa-css/src/value/shape/ellipse.ts @@ -19,12 +19,12 @@ const { map, option, pair, right } = Parser; */ export class Ellipse< R extends Radius = Radius, - P extends Position = Position + P extends Position = Position, > extends BasicShape<"ellipse", Value.HasCalculation<[R, P]>> { public static of( rx: R, ry: R, - center: P + center: P, ): Ellipse { return new Ellipse(rx, ry, center); } @@ -39,7 +39,7 @@ export class Ellipse< // TS sees the first as Value.HasCalculation<[R, R, P]> Value.hasCalculation(rx, ry, center) as unknown as Value.HasCalculation< [R, P] - > + >, ); this._rx = rx; this._ry = ry; @@ -62,7 +62,7 @@ export class Ellipse< return new Ellipse( this._rx.resolve(resolver), this._ry.resolve(resolver), - this._center.resolve(resolver) + this._center.resolve(resolver), ); } @@ -123,13 +123,13 @@ export namespace Ellipse { Position.PartialResolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Ellipse) => PartiallyResolved { return (value) => Ellipse.of( Radius.PartiallyResolve(resolver)(value.rx), Radius.PartiallyResolve(resolver)(value.ry), - Position.partiallyResolve(resolver)(value.center) + value.center.partiallyResolve(resolver), ); } @@ -147,11 +147,11 @@ export namespace Ellipse { option(Token.parseWhitespace), right( Keyword.parse("at"), - right(Token.parseWhitespace, Position.parse()) - ) - ) - ) - ) + right(Token.parseWhitespace, Position.parse()), + ), + ), + ), + ), ), ([_, [radii, center]]) => { const [rx, ry] = radii.getOr([ @@ -162,8 +162,8 @@ export namespace Ellipse { return Ellipse.of( rx, ry, - center.getOr(Position.of(Keyword.of("center"), Keyword.of("center"))) + center.getOr(Position.of(Keyword.of("center"), Keyword.of("center"))), ); - } + }, ); } diff --git a/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts b/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts index 5cdc0ff5b1..425ed8b9c0 100644 --- a/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts +++ b/packages/alfa-css/test/value/numeric/angle-percentage.spec.ts @@ -91,7 +91,7 @@ test("resolve() resolves angle calculations", (t) => { }); test("resolve() resolves pure percentages", (t) => { - t.deepEqual(parseUnsafe("50%").resolve().toJSON(), { + t.deepEqual(AnglePercentage.resolve(parseUnsafe("50%")).toJSON(), { type: "angle", value: 180, unit: "deg", @@ -99,17 +99,23 @@ test("resolve() resolves pure percentages", (t) => { }); test("resolve() resolves percentage calculations", (t) => { - t.deepEqual(parseUnsafe("calc((12% + 9%) * 2)").resolve().toJSON(), { - type: "angle", - value: 77.6, - unit: "deg", - }); + t.deepEqual( + AnglePercentage.resolve(parseUnsafe("calc((12% + 9%) * 2)")).toJSON(), + { + type: "angle", + value: 151.2, + unit: "deg", + }, + ); }); test("resolve() resolves mix of angles and percentages", (t) => { - t.deepEqual(parseUnsafe("calc(0.5turn + 10%)").resolve().toJSON(), { - type: "angle", - value: 216, - unit: "deg", - }); + t.deepEqual( + AnglePercentage.resolve(parseUnsafe("calc(0.5turn + 10%)")).toJSON(), + { + type: "angle", + value: 216, + unit: "deg", + }, + ); }); diff --git a/packages/alfa-css/test/value/position.spec.ts b/packages/alfa-css/test/value/position.spec.ts index 8cd7378f50..8f91dbc76b 100644 --- a/packages/alfa-css/test/value/position.spec.ts +++ b/packages/alfa-css/test/value/position.spec.ts @@ -422,7 +422,7 @@ test(".resolve() fully resolves positions", (t) => { Length.of(16, "px"), Length.of(0, "px"), Length.of(0, "px"), - Length.of(0, "px") + Length.of(0, "px"), ), percentageHBase: Length.of(10, "px"), percentageVBase: Length.of(20, "px"), @@ -440,38 +440,36 @@ test(".resolve() fully resolves positions", (t) => { side: { type: "keyword", value: "top" }, offset: { type: "length", unit: "px", value: 4 }, }, - } + }, ); }); test(".partiallyResolve() partially resolves positions", (t) => { const actual = Position.parse()( - Lexer.lex("left calc(1em + 1px) top calc(20% + 10%)") + Lexer.lex("left calc(1em + 1px) top calc(20% + 10%)"), ) .map(([, position]) => position) - .getUnsafe(); - - t.deepEqual( - Position.partiallyResolve({ + .getUnsafe() + .partiallyResolve({ length: Length.resolver( Length.of(16, "px"), Length.of(0, "px"), Length.of(0, "px"), - Length.of(0, "px") + Length.of(0, "px"), ), - })(actual).toJSON(), - { - type: "position", - horizontal: { - type: "side", - side: { type: "keyword", value: "left" }, - offset: { type: "length", unit: "px", value: 17 }, - }, - vertical: { - type: "side", - side: { type: "keyword", value: "top" }, - offset: { type: "percentage", value: 0.3 }, - }, - } - ); + }); + + t.deepEqual(actual.toJSON(), { + type: "position", + horizontal: { + type: "side", + side: { type: "keyword", value: "left" }, + offset: { type: "length", unit: "px", value: 17 }, + }, + vertical: { + type: "side", + side: { type: "keyword", value: "top" }, + offset: { type: "percentage", value: 0.3 }, + }, + }); }); From 81edf922b658e7928c7cd96de1d7fa5eff4251a4 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 15:54:21 +0100 Subject: [PATCH 10/13] Add partiallyResolve() method to Shapes --- packages/alfa-css/src/value/color/format.ts | 5 - packages/alfa-css/src/value/shape/circle.ts | 40 ++++--- packages/alfa-css/src/value/shape/ellipse.ts | 42 +++---- packages/alfa-css/src/value/shape/inset.ts | 118 ++++++++++--------- packages/alfa-css/src/value/shape/polygon.ts | 79 +++++++------ packages/alfa-css/src/value/shape/radius.ts | 80 +++++++------ packages/alfa-css/src/value/shape/shape.ts | 17 ++- 7 files changed, 197 insertions(+), 184 deletions(-) diff --git a/packages/alfa-css/src/value/color/format.ts b/packages/alfa-css/src/value/color/format.ts index 2eece1f990..8c4b4e2da5 100644 --- a/packages/alfa-css/src/value/color/format.ts +++ b/packages/alfa-css/src/value/color/format.ts @@ -24,11 +24,6 @@ export abstract class Format this._format = format; } - /** @public */ - public get format(): F { - return this._format; - } - public abstract get red(): Number.Canonical | Percentage.Canonical; public abstract get green(): Number.Canonical | Percentage.Canonical; diff --git a/packages/alfa-css/src/value/shape/circle.ts b/packages/alfa-css/src/value/shape/circle.ts index b4b0fda8ac..c8f91011f2 100644 --- a/packages/alfa-css/src/value/shape/circle.ts +++ b/packages/alfa-css/src/value/shape/circle.ts @@ -5,6 +5,7 @@ import { Function, type Parser as CSSParser, Token } from "../../syntax"; import { Keyword } from "../keyword"; import { Position } from "../position"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { BasicShape } from "./basic-shape"; @@ -17,10 +18,12 @@ const { map, option, pair, right } = Parser; * * @public */ -export class Circle< - R extends Radius = Radius, - P extends Position = Position, -> extends BasicShape<"circle", Value.HasCalculation<[R, P]>> { +export class Circle + extends BasicShape<"circle", Value.HasCalculation<[R, P]>> + implements + Resolvable, + PartiallyResolvable +{ public static of( radius: R, center: P, @@ -52,6 +55,15 @@ export class Circle< ); } + public partiallyResolve( + resolver: Circle.PartialResolver, + ): Circle.PartiallyResolved { + return new Circle( + this._radius.partiallyResolve(resolver), + this._center.partiallyResolve(resolver), + ); + } + public equals(value: Circle): boolean; public equals(value: unknown): value is this; @@ -87,6 +99,11 @@ export class Circle< export namespace Circle { export type Canonical = Circle; + export type PartiallyResolved = Circle< + Radius.PartiallyResolved, + Position.PartiallyResolved + >; + export interface JSON extends BasicShape.JSON<"circle"> { radius: Radius.JSON; center: Position.JSON; @@ -94,24 +111,9 @@ export namespace Circle { export type Resolver = Radius.Resolver & Position.Resolver; - export type PartiallyResolved = Circle< - Radius.PartiallyResolved, - Position.PartiallyResolved - >; - export type PartialResolver = Radius.PartialResolver & Position.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver, - ): (value: Circle) => PartiallyResolved { - return (value) => - Circle.of( - Radius.PartiallyResolve(resolver)(value.radius), - value.center.partiallyResolve(resolver), - ); - } - export function isCircle(value: unknown): value is Circle { return value instanceof Circle; } diff --git a/packages/alfa-css/src/value/shape/ellipse.ts b/packages/alfa-css/src/value/shape/ellipse.ts index 3ea20178d1..b349c33a7f 100644 --- a/packages/alfa-css/src/value/shape/ellipse.ts +++ b/packages/alfa-css/src/value/shape/ellipse.ts @@ -5,6 +5,7 @@ import { Function, type Parser as CSSParser, Token } from "../../syntax"; import { Keyword } from "../keyword"; import { Position } from "../position"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { BasicShape } from "./basic-shape"; @@ -17,10 +18,12 @@ const { map, option, pair, right } = Parser; * * @public */ -export class Ellipse< - R extends Radius = Radius, - P extends Position = Position, -> extends BasicShape<"ellipse", Value.HasCalculation<[R, P]>> { +export class Ellipse + extends BasicShape<"ellipse", Value.HasCalculation<[R, P]>> + implements + Resolvable, + PartiallyResolvable +{ public static of( rx: R, ry: R, @@ -66,6 +69,16 @@ export class Ellipse< ); } + public partiallyResolve( + resolver: Ellipse.PartialResolver, + ): Ellipse.PartiallyResolved { + return new Ellipse( + this._rx.partiallyResolve(resolver), + this._ry.partiallyResolve(resolver), + this._center.partiallyResolve(resolver), + ); + } + public equals(value: Ellipse): boolean; public equals(value: unknown): value is this; @@ -106,6 +119,11 @@ export class Ellipse< export namespace Ellipse { export type Canonical = Ellipse; + export type PartiallyResolved = Ellipse< + Radius.PartiallyResolved, + Position.PartiallyResolved + >; + export interface JSON extends BasicShape.JSON<"ellipse"> { rx: Radius.JSON; ry: Radius.JSON; @@ -114,25 +132,9 @@ export namespace Ellipse { export type Resolver = Radius.Resolver & Position.Resolver; - export type PartiallyResolved = Ellipse< - Radius.PartiallyResolved, - Position.PartiallyResolved - >; - export type PartialResolver = Radius.PartialResolver & Position.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver, - ): (value: Ellipse) => PartiallyResolved { - return (value) => - Ellipse.of( - Radius.PartiallyResolve(resolver)(value.rx), - Radius.PartiallyResolve(resolver)(value.ry), - value.center.partiallyResolve(resolver), - ); - } - export function isEllipse(value: unknown): value is Ellipse { return value instanceof Ellipse; } diff --git a/packages/alfa-css/src/value/shape/inset.ts b/packages/alfa-css/src/value/shape/inset.ts index 7d8dd886c4..d2911ab559 100644 --- a/packages/alfa-css/src/value/shape/inset.ts +++ b/packages/alfa-css/src/value/shape/inset.ts @@ -8,6 +8,7 @@ import { Function, type Parser as CSSParser, Token } from "../../syntax"; import { Keyword } from "../keyword"; import { LengthPercentage } from "../numeric"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { BasicShape } from "./basic-shape"; @@ -22,15 +23,20 @@ const { parseDelim, parseWhitespace } = Token; * @public */ export class Inset< - O extends Inset.Offset = Inset.Offset, - C extends Corner = Corner -> extends BasicShape<"inset", HasCalculation> { + O extends Inset.Offset = Inset.Offset, + C extends Corner = Corner, + > + extends BasicShape<"inset", HasCalculation> + implements + Resolvable, + PartiallyResolvable +{ public static of< O extends Inset.Offset = Inset.Offset, - C extends Corner = Corner + C extends Corner = Corner, >( offsets: readonly [O, O, O, O], - corners: Option + corners: Option, ): Inset { return new Inset(offsets, corners); } @@ -40,14 +46,14 @@ export class Inset< private constructor( offsets: readonly [O, O, O, O], - corners: Option + corners: Option, ) { super( "inset", (Value.hasCalculation(...offsets) || corners.some((corners) => - corners.some(Corner.hasCalculation) - )) as unknown as HasCalculation + corners.some(Corner.hasCalculation), + )) as unknown as HasCalculation, ); this._offsets = offsets; this._corners = corners; @@ -100,7 +106,7 @@ export class Inset< LengthPercentage.Canonical, LengthPercentage.Canonical, LengthPercentage.Canonical, - LengthPercentage.Canonical + LengthPercentage.Canonical, ], this._corners.map( (corners) => @@ -108,9 +114,31 @@ export class Inset< Corner.Canonical, Corner.Canonical, Corner.Canonical, - Corner.Canonical - ] - ) + Corner.Canonical, + ], + ), + ); + } + + public partiallyResolve( + resolver: Inset.PartialResolver, + ): Inset.PartiallyResolved { + return new Inset( + this._offsets.map(LengthPercentage.partiallyResolve(resolver)) as [ + LengthPercentage.PartiallyResolved, + LengthPercentage.PartiallyResolved, + LengthPercentage.PartiallyResolved, + LengthPercentage.PartiallyResolved, + ], + this._corners.map( + (corners) => + corners.map(Corner.partiallyResolve(resolver)) as [ + Corner.PartiallyResolved, + Corner.PartiallyResolved, + Corner.PartiallyResolved, + Corner.PartiallyResolved, + ], + ), ); } @@ -183,6 +211,11 @@ export class Inset< export namespace Inset { export type Canonical = Inset; + export type PartiallyResolved = Inset< + LengthPercentage.PartiallyResolved, + Corner.PartiallyResolved + >; + export interface JSON extends BasicShape.JSON<"inset"> { offsets: Serializable.ToJSON; @@ -193,36 +226,8 @@ export namespace Inset { export type Resolver = LengthPercentage.Resolver; - export type PartiallyResolved = Inset< - LengthPercentage.PartiallyResolved, - Corner.PartiallyResolved - >; - export type PartialResolver = LengthPercentage.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Inset) => PartiallyResolved { - return (value) => - Inset.of( - value.offsets.map(LengthPercentage.partiallyResolve(resolver)) as [ - LengthPercentage.PartiallyResolved, - LengthPercentage.PartiallyResolved, - LengthPercentage.PartiallyResolved, - LengthPercentage.PartiallyResolved - ], - value.corners.map( - (corners) => - corners.map(Corner.partiallyResolve(resolver)) as [ - Corner.PartiallyResolved, - Corner.PartiallyResolved, - Corner.PartiallyResolved, - Corner.PartiallyResolved - ] - ) - ); - } - export function isInset(value: unknown): value is Inset { return value instanceof Inset; } @@ -230,14 +235,14 @@ export namespace Inset { const parseOffsets = map( separatedList(LengthPercentage.parse, option(parseWhitespace), 1, 4), ([top, right = top, bottom = top, left = right]) => - [top, right, bottom, left] as const + [top, right, bottom, left] as const, ); const parseRadius = filter( LengthPercentage.parse, // https://drafts.csswg.org/css-values/#calc-range (value) => value.hasCalculation() || value.value >= 0, - () => "Radius cannot be negative" + () => "Radius cannot be negative", ); const parseRadii = map( @@ -247,7 +252,7 @@ export namespace Inset { topRight = topLeft, bottomRight = topLeft, bottomLeft = topRight, - ]) => [topLeft, topRight, bottomRight, bottomLeft] as const + ]) => [topLeft, topRight, bottomRight, bottomLeft] as const, ); const parseCorners: CSSParser = @@ -255,8 +260,11 @@ export namespace Inset { pair( parseRadii, option( - right(delimited(option(parseWhitespace), parseDelim("/")), parseRadii) - ) + right( + delimited(option(parseWhitespace), parseDelim("/")), + parseRadii, + ), + ), ), ([horizontal, vertical]) => vertical @@ -267,9 +275,9 @@ export namespace Inset { [horizontal[1], vertical[1]], [horizontal[2], vertical[2]], [horizontal[3], vertical[3]], - ] as const + ] as const, ) - .getOr(horizontal) + .getOr(horizontal), ); export const parse: CSSParser = map( @@ -282,13 +290,13 @@ export namespace Inset { option(Token.parseWhitespace), right( Keyword.parse("round"), - right(Token.parseWhitespace, parseCorners) - ) - ) - ) - ) + right(Token.parseWhitespace, parseCorners), + ), + ), + ), + ), ), - ([_, [offsets, corners]]) => Inset.of(offsets, corners) + ([_, [offsets, corners]]) => Inset.of(offsets, corners), ); } @@ -298,12 +306,12 @@ export namespace Inset { */ type HasCalculation< O extends Inset.Offset, - C extends Corner + C extends Corner, > = Value.HasCalculation< [ O, // It seems we can't really spread ...[R1, R2] in a conditional. C extends readonly [infer R extends LengthPercentage, any] ? R : C, - C extends readonly [any, infer R extends LengthPercentage] ? R : C + C extends readonly [any, infer R extends LengthPercentage] ? R : C, ] >; diff --git a/packages/alfa-css/src/value/shape/polygon.ts b/packages/alfa-css/src/value/shape/polygon.ts index 0d8c9779f0..e44f2bdad3 100644 --- a/packages/alfa-css/src/value/shape/polygon.ts +++ b/packages/alfa-css/src/value/shape/polygon.ts @@ -9,6 +9,7 @@ import { Function, type Parser as CSSParser, Token } from "../../syntax"; import { Keyword } from "../keyword"; import { LengthPercentage } from "../numeric"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { BasicShape } from "./basic-shape"; @@ -22,12 +23,17 @@ const { parseComma, parseWhitespace } = Token; * @public */ export class Polygon< - F extends Polygon.Fill = Polygon.Fill, - V extends LengthPercentage = LengthPercentage -> extends BasicShape<"polygon", Value.HasCalculation<[V]>> { + F extends Polygon.Fill = Polygon.Fill, + V extends LengthPercentage = LengthPercentage, + > + extends BasicShape<"polygon", Value.HasCalculation<[V]>> + implements + Resolvable, + PartiallyResolvable +{ public static of< F extends Polygon.Fill = Polygon.Fill, - V extends LengthPercentage = LengthPercentage + V extends LengthPercentage = LengthPercentage, >(fill: Option, vertices: Iterable>): Polygon { return new Polygon(fill, Array.from(vertices)); } @@ -40,8 +46,8 @@ export class Polygon< "polygon", vertices.reduce( (calc, vertex) => calc || Value.hasCalculation(...vertex), - false - ) as unknown as Value.HasCalculation<[V]> + false, + ) as unknown as Value.HasCalculation<[V]>, ); this._fill = fill; this._vertices = vertices; @@ -62,9 +68,24 @@ export class Polygon< (vertex) => // map loses the fact that vertex has exactly two elements. vertex.map( - LengthPercentage.resolve(resolver) - ) as unknown as Polygon.Vertex - ) + LengthPercentage.resolve(resolver), + ) as unknown as Polygon.Vertex, + ), + ); + } + + public partiallyResolve( + resolver: Polygon.PartialResolver, + ): Polygon.PartiallyResolved { + return new Polygon( + this._fill, + this._vertices.map( + (vertex) => + // map loses the fact that vertex has exactly two elements. + vertex.map( + LengthPercentage.partiallyResolve(resolver), + ) as unknown as Polygon.Vertex, + ), ); } @@ -107,16 +128,21 @@ export class Polygon< export namespace Polygon { export type Canonical = Polygon; + export type PartiallyResolved = Polygon< + Fill, + LengthPercentage.PartiallyResolved + >; + export type Fill = Keyword<"nonzero"> | Keyword<"evenodd">; export type Vertex = readonly [ V, - V + V, ]; export interface JSON< F extends Fill = Fill, - V extends LengthPercentage = LengthPercentage + V extends LengthPercentage = LengthPercentage, > extends BasicShape.JSON<"polygon"> { fill: Option.JSON; vertices: Array>>; @@ -124,29 +150,8 @@ export namespace Polygon { export type Resolver = LengthPercentage.Resolver; - export type PartiallyResolved = Polygon< - Fill, - LengthPercentage.PartiallyResolved - >; - export type PartialResolver = LengthPercentage.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Polygon) => PartiallyResolved { - return (value) => - Polygon.of( - value.fill, - value.vertices.map( - (vertex) => - // map loses the fact that vertex has exactly two elements. - vertex.map( - LengthPercentage.partiallyResolve(resolver) - ) as unknown as Polygon.Vertex - ) - ); - } - export function isPolygon(value: unknown): value is Polygon { return value instanceof Polygon; } @@ -154,7 +159,7 @@ export namespace Polygon { const parseVertex = separated( LengthPercentage.parse, parseWhitespace, - LengthPercentage.parse + LengthPercentage.parse, ); export const parse: CSSParser = map( @@ -164,10 +169,10 @@ export namespace Polygon { option(left(Keyword.parse("nonzero", "evenodd"), parseComma)), right( option(parseWhitespace), - separatedList(parseVertex, parseWhitespace) - ) - ) + separatedList(parseVertex, parseWhitespace), + ), + ), ), - ([_, [fill, vertices]]) => Polygon.of(fill, vertices) + ([_, [fill, vertices]]) => Polygon.of(fill, vertices), ); } diff --git a/packages/alfa-css/src/value/shape/radius.ts b/packages/alfa-css/src/value/shape/radius.ts index ebe763a872..91c3a57eb3 100644 --- a/packages/alfa-css/src/value/shape/radius.ts +++ b/packages/alfa-css/src/value/shape/radius.ts @@ -6,6 +6,7 @@ import type { Parser as CSSParser } from "../../syntax"; import { Keyword } from "../keyword"; import { LengthPercentage } from "../numeric"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { BasicShape } from "./basic-shape"; @@ -18,10 +19,15 @@ const { either, filter, map } = Parser; * @public */ export class Radius< - R extends LengthPercentage | Radius.Side = LengthPercentage | Radius.Side -> extends BasicShape<"radius", Value.HasCalculation<[R]>> { + R extends LengthPercentage | Radius.Side = LengthPercentage | Radius.Side, + > + extends BasicShape<"radius", Value.HasCalculation<[R]>> + implements + Resolvable, + PartiallyResolvable +{ public static of( - value: R + value: R, ): Radius { return new Radius(value); } @@ -49,8 +55,32 @@ export class Radius< return new Radius( LengthPercentage.of( Real.clamp(resolved.value, 0, Infinity), - resolved.unit - ) + resolved.unit, + ), + ); + } + + public partiallyResolve( + resolver: Radius.PartialResolver, + ): Radius.PartiallyResolved { + if (Keyword.isKeyword(this._value)) { + // TS lose the fact that if this._value is a Side, then this must be a + // Radius… + return this as Radius; + } + + const resolved = LengthPercentage.partiallyResolve(resolver)(this._value); + + if (resolved.hasCalculation()) { + return Radius.of(resolved); + } + + const clamped = Real.clamp(resolved.value, 0, Infinity); + + return Radius.of( + LengthPercentage.isPercentage(resolved) + ? LengthPercentage.of(clamped) + : LengthPercentage.of(clamped, resolved.unit), ); } @@ -84,44 +114,18 @@ export class Radius< export namespace Radius { export type Canonical = Radius; + export type PartiallyResolved = Radius< + LengthPercentage.PartiallyResolved | Side + >; + export interface JSON extends BasicShape.JSON<"radius"> { value: LengthPercentage.JSON | Keyword.JSON; } export type Resolver = LengthPercentage.Resolver; - export type PartiallyResolved = Radius< - LengthPercentage.PartiallyResolved | Side - >; - export type PartialResolver = LengthPercentage.PartialResolver; - export function PartiallyResolve( - resolver: PartialResolver - ): (value: Radius) => PartiallyResolved { - return (value) => { - if (Keyword.isKeyword(value.value)) { - // TS lose the fact that if this._value is a Side, then this must be a - // Radius… - return value as Radius; - } - - const resolved = LengthPercentage.partiallyResolve(resolver)(value.value); - - if (resolved.hasCalculation()) { - return Radius.of(resolved); - } - - const clamped = Real.clamp(resolved.value, 0, Infinity); - - return Radius.of( - LengthPercentage.isPercentage(resolved) - ? LengthPercentage.of(clamped) - : LengthPercentage.of(clamped, resolved.unit) - ); - }; - } - export type Side = Side.Closest | Side.Farthest; export namespace Side { @@ -146,10 +150,10 @@ export namespace Radius { LengthPercentage.parse, // https://drafts.csswg.org/css-values/#calc-range (value) => value.hasCalculation() || value.value >= 0, - () => "Radius cannot be negative" + () => "Radius cannot be negative", ), - Keyword.parse("closest-side", "farthest-side") + Keyword.parse("closest-side", "farthest-side"), ), - (radius) => Radius.of(radius) + (radius) => Radius.of(radius), ); } diff --git a/packages/alfa-css/src/value/shape/shape.ts b/packages/alfa-css/src/value/shape/shape.ts index cb155415cd..ee79c58533 100644 --- a/packages/alfa-css/src/value/shape/shape.ts +++ b/packages/alfa-css/src/value/shape/shape.ts @@ -23,11 +23,11 @@ const { either } = Parser; */ export class Shape< S extends Shape.Basic = Shape.Basic, - B extends Box.Geometry = Box.Geometry + B extends Box.Geometry = Box.Geometry, > extends Value<"shape", Value.HasCalculation<[S]>> { public static of< S extends Shape.Basic = Shape.Basic, - B extends Box.Geometry = Box.Geometry + B extends Box.Geometry = Box.Geometry, >(shape: S, box: B): Shape { return new Shape(shape, box); } @@ -128,15 +128,12 @@ export namespace Shape { Rectangle.Resolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Basic) => PartiallyResolved { return (value) => Selective.of(value) - .if(Circle.isCircle, Circle.partiallyResolve(resolver)) - .if(Ellipse.isEllipse, Ellipse.partiallyResolve(resolver)) - .if(Inset.isInset, Inset.partiallyResolve(resolver)) - .if(Polygon.isPolygon, Polygon.partiallyResolve(resolver)) - .else((rectangle) => rectangle.resolve(resolver)) + .if(Rectangle.isRectangle, (rectangle) => rectangle.resolve(resolver)) + .else((value) => value.partiallyResolve(resolver)) .get(); } @@ -165,7 +162,7 @@ export namespace Shape { export type PartialResolver = Basic.PartialResolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Shape) => PartiallyResolved { return (value) => Shape.of(Basic.partiallyResolve(resolver)(value.shape), value.box); @@ -176,7 +173,7 @@ export namespace Shape { * This does not parse the deprecated `rect()` shape. */ export const parse: CSSParser> = ( - input + input, ) => { let shape: Circle | Ellipse | Inset | Polygon | undefined; let box: Box.Geometry | undefined; From e96455326c5de7e5e71d97a3d42b8d8e414dd1bf Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Mon, 6 Nov 2023 16:15:16 +0100 Subject: [PATCH 11/13] Add partiallyResolve() method to Images --- .../src/value/image/gradient/gradient.ts | 10 ---- .../src/value/image/gradient/item/hint.ts | 26 +++++---- .../src/value/image/gradient/item/item.ts | 11 +--- .../src/value/image/gradient/item/stop.ts | 43 +++++++------- .../src/value/image/gradient/linear/linear.ts | 54 +++++++++--------- .../value/image/gradient/radial/ellipse.ts | 39 +++++++------ .../src/value/image/gradient/radial/radial.ts | 55 ++++++++++-------- .../src/value/image/gradient/radial/shape.ts | 6 +- packages/alfa-css/src/value/image/image.ts | 10 ++-- .../alfa-css/src/value/transform/transform.ts | 10 ++-- .../alfa-css/src/value/transform/translate.ts | 56 ++++++++++--------- 11 files changed, 163 insertions(+), 157 deletions(-) diff --git a/packages/alfa-css/src/value/image/gradient/gradient.ts b/packages/alfa-css/src/value/image/gradient/gradient.ts index f836b6ccb9..402dd29cbf 100644 --- a/packages/alfa-css/src/value/image/gradient/gradient.ts +++ b/packages/alfa-css/src/value/image/gradient/gradient.ts @@ -38,16 +38,6 @@ export namespace Gradient { export type PartialResolver = Linear.PartialResolver & Radial.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Gradient) => PartiallyResolved { - return (value) => - Selective.of(value) - .if(Linear.isLinear, Linear.partiallyResolve(resolver)) - .else(Radial.partiallyResolve(resolver)) - .get(); - } - /** * {@link https://drafts.csswg.org/css-images/#typedef-gradient} */ diff --git a/packages/alfa-css/src/value/image/gradient/item/hint.ts b/packages/alfa-css/src/value/image/gradient/item/hint.ts index c7410e5d67..8bc8f00997 100644 --- a/packages/alfa-css/src/value/image/gradient/item/hint.ts +++ b/packages/alfa-css/src/value/image/gradient/item/hint.ts @@ -5,6 +5,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { Parser as CSSParser } from "../../../../syntax"; import { LengthPercentage } from "../../../numeric"; +import { PartiallyResolvable, Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; const { map } = Parser; @@ -12,10 +13,12 @@ const { map } = Parser; /** * {@link https://drafts.csswg.org/css-images/#color-transition-hint} */ -export class Hint

extends Value< - "hint", - Value.HasCalculation<[P]> -> { +export class Hint

+ extends Value<"hint", Value.HasCalculation<[P]>> + implements + Resolvable, + PartiallyResolvable +{ public static of

(position: P): Hint

{ return new Hint(position); } @@ -35,6 +38,14 @@ export class Hint

extends Value< return new Hint(LengthPercentage.resolve(resolver)(this._position)); } + public partiallyResolve( + resolver: Hint.PartialResolver, + ): Hint.PartiallyResolved { + return new Hint( + LengthPercentage.partiallyResolve(resolver)(this._position), + ); + } + public equals(value: unknown): value is this { return value instanceof Hint && value._position.equals(this._position); } @@ -68,13 +79,6 @@ export namespace Hint { export type PartialResolver = LengthPercentage.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Hint) => PartiallyResolved { - return (value) => - Hint.of(LengthPercentage.partiallyResolve(resolver)(value.position)); - } - /** * {@link https://drafts.csswg.org/css-images/#typedef-linear-color-hint} */ diff --git a/packages/alfa-css/src/value/image/gradient/item/item.ts b/packages/alfa-css/src/value/image/gradient/item/item.ts index eefed3fb03..711b3e5c7f 100644 --- a/packages/alfa-css/src/value/image/gradient/item/item.ts +++ b/packages/alfa-css/src/value/image/gradient/item/item.ts @@ -26,15 +26,6 @@ export namespace Item { export type PartialResolver = Hint.PartialResolver & Stop.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Item) => PartiallyResolved { - return (value) => - Stop.isStop(value) - ? Stop.partiallyResolve(resolver)(value) - : Hint.partiallyResolve(resolver)(value); - } - // ? , const parse = pair(option(left(Hint.parse, Comma.parse)), Stop.parse); @@ -51,6 +42,6 @@ export namespace Item { } return items; - } + }, ); } diff --git a/packages/alfa-css/src/value/image/gradient/item/stop.ts b/packages/alfa-css/src/value/image/gradient/item/stop.ts index 8aa33c9b58..6217ebadd4 100644 --- a/packages/alfa-css/src/value/image/gradient/item/stop.ts +++ b/packages/alfa-css/src/value/image/gradient/item/stop.ts @@ -6,6 +6,7 @@ import { Parser as CSSParser, Token } from "../../../../syntax"; import { Color } from "../../../color"; import { LengthPercentage } from "../../../numeric"; +import { PartiallyResolvable, Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; const { either, pair, map, left, right } = Parser; @@ -14,12 +15,17 @@ const { either, pair, map, left, right } = Parser; * {@link https://drafts.csswg.org/css-images/#color-stop} */ export class Stop< - C extends Color = Color, - P extends LengthPercentage = LengthPercentage -> extends Value<"stop", Value.HasCalculation<[C, P]>> { + C extends Color = Color, + P extends LengthPercentage = LengthPercentage, + > + extends Value<"stop", Value.HasCalculation<[C, P]>> + implements + Resolvable, + PartiallyResolvable +{ public static of( color: C, - position: Option

= None + position: Option

= None, ): Stop { return new Stop(color, position); } @@ -33,7 +39,7 @@ export class Stop< (Value.hasCalculation(color) || position .map(Value.hasCalculation) - .getOr(false)) as Value.HasCalculation<[C, P]> + .getOr(false)) as Value.HasCalculation<[C, P]>, ); this._color = color; this._position = position; @@ -50,7 +56,16 @@ export class Stop< public resolve(resolver: Stop.Resolver): Stop.Canonical { return new Stop( this._color.resolve(), - this._position.map(LengthPercentage.resolve(resolver)) + this._position.map(LengthPercentage.resolve(resolver)), + ); + } + + public partiallyResolve( + resolver: Stop.PartialResolver, + ): Stop.PartiallyResolved { + return new Stop( + this._color.resolve(), + this._position.map(LengthPercentage.partiallyResolve(resolver)), ); } @@ -98,16 +113,6 @@ export namespace Stop { export type PartialResolver = LengthPercentage.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Stop) => PartiallyResolved { - return (value) => - Stop.of( - value.color.resolve(), - value.position.map(LengthPercentage.partiallyResolve(resolver)) - ); - } - export function isStop(value: unknown): value is Stop { return value instanceof Stop; } @@ -121,15 +126,15 @@ export namespace Stop { (result) => { const [color, position] = result; return Stop.of(color, Option.of(position)); - } + }, ), map( pair(LengthPercentage.parse, right(Token.parseWhitespace, Color.parse)), (result) => { const [position, color] = result; return Stop.of(color, Option.of(position)); - } + }, ), - map(Color.parse, (color) => Stop.of(color)) + map(Color.parse, (color) => Stop.of(color)), ); } diff --git a/packages/alfa-css/src/value/image/gradient/linear/linear.ts b/packages/alfa-css/src/value/image/gradient/linear/linear.ts index 72427c9623..60b4eab818 100644 --- a/packages/alfa-css/src/value/image/gradient/linear/linear.ts +++ b/packages/alfa-css/src/value/image/gradient/linear/linear.ts @@ -3,6 +3,7 @@ import { Iterable } from "@siteimprove/alfa-iterable"; import { Parser } from "@siteimprove/alfa-parser"; import { Comma, Function, type Parser as CSSParser } from "../../../../syntax"; +import { PartiallyResolvable, Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; @@ -18,14 +19,16 @@ const { map, pair, option, left } = Parser; * * @public */ -export class Linear< - I extends Item = Item, - D extends Direction = Direction -> extends Value<"gradient", Value.HasCalculation<[D, I]>> { +export class Linear + extends Value<"gradient", Value.HasCalculation<[D, I]>> + implements + Resolvable, + PartiallyResolvable +{ public static of( direction: D, items: Iterable, - repeats: boolean + repeats: boolean, ): Linear { return new Linear(direction, Array.from(items), repeats); } @@ -61,7 +64,19 @@ export class Linear< return new Linear( this._direction.resolve(), this._items.map(Item.resolve(resolver)), - this._repeats + this._repeats, + ); + } + + public partiallyResolve( + resolver: Linear.PartialResolver, + ): Linear.PartiallyResolved { + return new Linear( + this._direction.resolve(), + Array.from( + Iterable.map(this._items, (item) => item.partiallyResolve(resolver)), + ), + this._repeats, ); } @@ -112,6 +127,11 @@ export class Linear< export namespace Linear { export type Canonical = Linear; + export type PartiallyResolved = Linear< + Item.PartiallyResolved, + Direction.Canonical + >; + export interface JSON extends Value.JSON<"gradient"> { kind: "linear"; direction: Direction.JSON; @@ -121,24 +141,8 @@ export namespace Linear { export type Resolver = Item.Resolver & Direction.Resolver; - export type PartiallyResolved = Linear< - Item.PartiallyResolved, - Direction.Canonical - >; - export type PartialResolver = Item.PartialResolver & Direction.Resolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Linear) => PartiallyResolved { - return (value) => - Linear.of( - value.direction.resolve(), - Iterable.map(value.items, Item.partiallyResolve(resolver)), - value.repeats - ); - } - export function isLinear(value: unknown): value is Linear { return value instanceof Linear; } @@ -151,14 +155,14 @@ export namespace Linear { (fn) => fn.value === "linear-gradient" || fn.value === "repeating-linear-gradient", - pair(option(left(Direction.parse, Comma.parse)), Item.parseList) + pair(option(left(Direction.parse, Comma.parse)), Item.parseList), ), ([fn, [direction, items]]) => { return Linear.of( direction.getOrElse(() => Side.of("bottom")), items, - fn.name.startsWith("repeating") + fn.name.startsWith("repeating"), ); - } + }, ); } diff --git a/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts b/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts index 07d4beb4be..1365d4ab7c 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts @@ -6,6 +6,7 @@ import { Parser as CSSParser, Token } from "../../../../syntax"; import { Keyword } from "../../../keyword"; import { LengthPercentage } from "../../../numeric"; +import { PartiallyResolvable, Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; const { option, separatedList } = Parser; @@ -15,12 +16,15 @@ const { option, separatedList } = Parser; * * @internal */ -export class Ellipse< - R extends LengthPercentage = LengthPercentage -> extends Value<"ellipse", Value.HasCalculation<[R, R]>> { +export class Ellipse + extends Value<"ellipse", Value.HasCalculation<[R, R]>> + implements + Resolvable, + PartiallyResolvable +{ public static of( horizontal: R, - vertical: R + vertical: R, ): Ellipse { return new Ellipse(horizontal, vertical); } @@ -45,7 +49,16 @@ export class Ellipse< public resolve(resolver: Ellipse.Resolver): Ellipse.Canonical { return new Ellipse( LengthPercentage.resolve(resolver)(this._horizontal), - LengthPercentage.resolve(resolver)(this._vertical) + LengthPercentage.resolve(resolver)(this._vertical), + ); + } + + public partiallyResolve( + resolver: Ellipse.PartialResolver, + ): Ellipse.PartiallyResolved { + return new Ellipse( + LengthPercentage.partiallyResolve(resolver)(this._horizontal), + LengthPercentage.partiallyResolve(resolver)(this._vertical), ); } @@ -84,6 +97,8 @@ export class Ellipse< export namespace Ellipse { export type Canonical = Ellipse; + export type PartiallyResolved = Ellipse; + export interface JSON extends Value.JSON<"ellipse"> { horizontal: LengthPercentage.JSON; vertical: LengthPercentage.JSON; @@ -91,20 +106,8 @@ export namespace Ellipse { export type Resolver = LengthPercentage.Resolver; - export type PartiallyResolved = Ellipse; - export type PartialResolver = LengthPercentage.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Ellipse) => PartiallyResolved { - return (value) => - Ellipse.of( - LengthPercentage.partiallyResolve(resolver)(value.horizontal), - LengthPercentage.partiallyResolve(resolver)(value.vertical) - ); - } - export function isEllipse(value: unknown): value is Ellipse { return value instanceof Ellipse; } @@ -115,7 +118,7 @@ export namespace Ellipse { LengthPercentage.parse, option(Token.parseWhitespace), 2, - 2 + 2, ); export const parse: CSSParser = (input) => { diff --git a/packages/alfa-css/src/value/image/gradient/radial/radial.ts b/packages/alfa-css/src/value/image/gradient/radial/radial.ts index 4b07c77d98..61531421e4 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/radial.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/radial.ts @@ -12,6 +12,7 @@ import { import { Keyword } from "../../../keyword"; import { Position } from "../../../position"; +import { PartiallyResolvable, Resolvable } from "../../../resolvable"; import { Value } from "../../../value"; import { Item } from "../item"; @@ -27,10 +28,15 @@ const { map, either, pair, option, left, right, delimited } = Parser; * @public */ export class Radial< - I extends Item = Item, - S extends Shape = Shape, - P extends Position = Position, -> extends Value<"gradient", Value.HasCalculation<[I, S, P]>> { + I extends Item = Item, + S extends Shape = Shape, + P extends Position = Position, + > + extends Value<"gradient", Value.HasCalculation<[I, S, P]>> + implements + Resolvable, + PartiallyResolvable +{ public static of< I extends Item = Item, S extends Shape = Shape, @@ -52,7 +58,7 @@ export class Radial< private constructor( shape: S, position: P, - items: Iterable, + items: Array, repeats: boolean, ) { super( @@ -65,7 +71,7 @@ export class Radial< ); this._shape = shape; this._position = position; - this._items = [...items]; + this._items = items; this._repeats = repeats; } @@ -98,6 +104,19 @@ export class Radial< ); } + public partiallyResolve( + resolver: Radial.PartialResolver, + ): Radial.PartiallyResolved { + return new Radial( + Shape.partiallyResolve(resolver)(this._shape), + this._position.partiallyResolve(resolver), + Array.from( + Iterable.map(this._items, (item) => item.partiallyResolve(resolver)), + ), + this._repeats, + ); + } + public equals(value: Radial): boolean; public equals(value: unknown): value is this; @@ -153,6 +172,12 @@ export namespace Radial { Position.Canonical >; + export type PartiallyResolved = Radial< + Item.PartiallyResolved, + Shape.PartiallyResolved, + Position.PartiallyResolved + >; + export interface JSON extends Value.JSON<"gradient"> { kind: "radial"; shape: Shape.JSON; @@ -163,28 +188,10 @@ export namespace Radial { export type Resolver = Item.Resolver & Shape.Resolver & Position.Resolver; - export type PartiallyResolved = Radial< - Item.PartiallyResolved, - Shape.PartiallyResolved, - Position.PartiallyResolved - >; - export type PartialResolver = Item.PartialResolver & Shape.PartialResolver & Position.PartialResolver; - export function partiallyResolve( - resolver: PartialResolver, - ): (value: Radial) => PartiallyResolved { - return (value) => - Radial.of( - Shape.partiallyResolve(resolver)(value.shape), - value.position.partiallyResolve(resolver), - Iterable.map(value.items, Item.partiallyResolve(resolver)), - value.repeats, - ); - } - /** @public */ export function isRadial(value: unknown): value is Radial { return value instanceof Radial; diff --git a/packages/alfa-css/src/value/image/gradient/radial/shape.ts b/packages/alfa-css/src/value/image/gradient/radial/shape.ts index 9f671e9375..f3cd03cc94 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/shape.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/shape.ts @@ -45,11 +45,11 @@ export namespace Shape { Extent.Resolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Shape) => PartiallyResolved { return (value) => Selective.of(value) - .if(Ellipse.isEllipse, Ellipse.partiallyResolve(resolver)) + .if(Ellipse.isEllipse, (ellipse) => ellipse.partiallyResolve(resolver)) .else((value) => value.resolve(resolver)) .get(); } @@ -57,6 +57,6 @@ export namespace Shape { export const parse = either, Shape, string>( Ellipse.parse, Circle.parse, - Extent.parse + Extent.parse, ); } diff --git a/packages/alfa-css/src/value/image/image.ts b/packages/alfa-css/src/value/image/image.ts index 7fa34951c8..37c6167eb3 100644 --- a/packages/alfa-css/src/value/image/image.ts +++ b/packages/alfa-css/src/value/image/image.ts @@ -78,19 +78,19 @@ export namespace Image { export type PartialResolver = URL.Resolver & Gradient.PartialResolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Image) => PartiallyResolved { return (value) => Image.of( Selective.of(value.image) .if(URL.isURL, (url) => url.resolve()) - .else(Gradient.partiallyResolve(resolver)) - .get() + .else((gradient) => gradient.partiallyResolve(resolver)) + .get(), ); } export function isImage( - value: unknown + value: unknown, ): value is Image { return value instanceof Image; } @@ -100,6 +100,6 @@ export namespace Image { */ export const parse: CSSParser = map( either(URL.parse, Gradient.parse), - Image.of + Image.of, ); } diff --git a/packages/alfa-css/src/value/transform/transform.ts b/packages/alfa-css/src/value/transform/transform.ts index c04b06d871..8aa91d6752 100644 --- a/packages/alfa-css/src/value/transform/transform.ts +++ b/packages/alfa-css/src/value/transform/transform.ts @@ -55,11 +55,11 @@ export namespace Transform { export type PartialResolver = Translate.PartialResolver; export function partiallyResolve( - resolver: PartialResolver + resolver: PartialResolver, ): (value: Transform) => PartiallyResolved { return (value) => Translate.isTranslate(value) - ? Translate.partiallyResolve(resolver)(value) + ? value.partiallyResolve(resolver) : value.resolve(resolver); } @@ -75,7 +75,7 @@ export namespace Transform { x: Number, y: Number, z: Number, - angle: Angle + angle: Angle, ): Rotate { return Rotate.of(x, y, z, angle); } @@ -91,7 +91,7 @@ export namespace Transform { export function translate< X extends LengthPercentage, Y extends LengthPercentage, - Z extends Length + Z extends Length, >(x: X, y: Y, z: Z): Translate { return Translate.of(x, y, z); } @@ -107,7 +107,7 @@ export namespace Transform { Rotate.parse, Scale.parse, Skew.parse, - Translate.parse + Translate.parse, ); /** diff --git a/packages/alfa-css/src/value/transform/translate.ts b/packages/alfa-css/src/value/transform/translate.ts index 559e3e6a06..216ee97633 100644 --- a/packages/alfa-css/src/value/transform/translate.ts +++ b/packages/alfa-css/src/value/transform/translate.ts @@ -8,7 +8,7 @@ import { import { List } from "../collection"; import { Length, LengthPercentage, Numeric } from "../numeric"; -import { Resolvable } from "../resolvable"; +import { PartiallyResolvable, Resolvable } from "../resolvable"; import { Value } from "../value"; import { Function } from "./function"; @@ -21,15 +21,17 @@ const { map, either, parseIf } = Parser; export class Translate< X extends LengthPercentage = LengthPercentage, Y extends LengthPercentage = LengthPercentage, - Z extends Length = Length + Z extends Length = Length, > extends Function<"translate", Value.HasCalculation<[X, Y, Z]>> - implements Resolvable + implements + Resolvable, + PartiallyResolvable { public static of< X extends LengthPercentage = LengthPercentage, Y extends LengthPercentage = LengthPercentage, - Z extends Length = Length + Z extends Length = Length, >(x: X, y: Y, z: Z): Translate { return new Translate(x, y, z); } @@ -61,7 +63,17 @@ export class Translate< return new Translate( LengthPercentage.resolve(resolver)(this._x), LengthPercentage.resolve(resolver)(this._y), - this._z.resolve(resolver) + this._z.resolve(resolver), + ); + } + + public partiallyResolve( + resolver: Translate.PartialResolver, + ): Translate.PartiallyResolved { + return new Translate( + LengthPercentage.partiallyResolve(resolver)(this._x), + LengthPercentage.partiallyResolve(resolver)(this._x), + this._z.resolve(resolver), ); } @@ -127,20 +139,10 @@ export namespace Translate { export type PartialResolver = LengthPercentage.PartialResolver & Length.Resolver; - export function partiallyResolve( - resolver: PartialResolver - ): (value: Translate) => PartiallyResolved { - return (value) => - Translate.of( - LengthPercentage.partiallyResolve(resolver)(value.x), - LengthPercentage.partiallyResolve(resolver)(value.x), - value.z.resolve(resolver) - ); - } export function isTranslate< X extends LengthPercentage, Y extends LengthPercentage, - Z extends Length + Z extends Length, >(value: unknown): value is Translate { return value instanceof Translate; } @@ -155,11 +157,11 @@ export namespace Translate { "translate", map( List.parseCommaSeparated(LengthPercentage.parse, 1, 2), - (list) => list.values - ) + (list) => list.values, + ), ), - ([_, [x, y]]) => Translate.of(x, y ?? _0, _0) + ([_, [x, y]]) => Translate.of(x, y ?? _0, _0), ); /** @@ -167,7 +169,7 @@ export namespace Translate { */ const parseTranslateX = map( CSSFunction.parse("translateX", LengthPercentage.parse), - ([_, x]) => Translate.of(x, _0, _0) + ([_, x]) => Translate.of(x, _0, _0), ); /** @@ -175,7 +177,7 @@ export namespace Translate { */ const parseTranslateY = map( CSSFunction.parse("translateY", LengthPercentage.parse), - ([_, y]) => Translate.of(_0, y, _0) + ([_, y]) => Translate.of(_0, y, _0), ); /** @@ -183,7 +185,7 @@ export namespace Translate { */ const parseTranslateZ: CSSParser = map( CSSFunction.parse("translateZ", Length.parse), - ([_, z]) => Translate.of(_0, _0, z) + ([_, z]) => Translate.of(_0, _0, z), ); /** @@ -196,13 +198,13 @@ export namespace Translate { (values: ReadonlyArray) => Length.isLength(values[2]), map( List.parseCommaSeparated(LengthPercentage.parse, 3, 3), - (list) => list.values + (list) => list.values, ), - () => "The z component of translate3d must be a length" - ) + () => "The z component of translate3d must be a length", + ), ), // The type of z is ensured by parseIf. - ([_, [x, y, z]]) => Translate.of(x, y, z as Length) + ([_, [x, y, z]]) => Translate.of(x, y, z as Length), ); export const parse: CSSParser = either( @@ -210,6 +212,6 @@ export namespace Translate { parseTranslateX, parseTranslateY, parseTranslateZ, - parseTranslate3d + parseTranslate3d, ); } From ed1e85b441d48a7b9241de91a30a4e66eb6297a6 Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Wed, 8 Nov 2023 13:40:42 +0100 Subject: [PATCH 12/13] Add Knip ignore where relevant --- .../calculation/math-expression/function.ts | 20 +- .../src/calculation/math-expression/kind.ts | 26 +-- .../calculation/math-expression/operation.ts | 26 +-- .../src/calculation/numeric/numeric.ts | 2 +- .../src/value/image/gradient/item/hint.ts | 1 + .../src/value/image/gradient/item/stop.ts | 2 + .../src/value/image/gradient/linear/corner.ts | 20 +- .../src/value/image/gradient/linear/linear.ts | 1 + .../src/value/image/gradient/linear/side.ts | 6 +- .../src/value/image/gradient/radial/circle.ts | 2 +- .../value/image/gradient/radial/ellipse.ts | 2 + .../src/value/image/gradient/radial/extent.ts | 12 +- .../src/value/image/gradient/radial/radial.ts | 2 +- .../alfa-css/src/value/shape/basic-shape.ts | 4 +- .../src/common/diagnostic/contrast.ts | 18 +- .../src/common/diagnostic/text-spacing.ts | 16 +- .../common/diagnostic/with-bad-elements.ts | 6 +- .../src/common/diagnostic/with-role.ts | 2 +- packages/alfa-rules/src/deprecated.ts | 12 +- packages/alfa-rules/src/experimental.ts | 6 +- packages/alfa-rules/src/rules.ts | 176 +++++++++--------- packages/alfa-rules/src/tags/version.ts | 4 +- packages/alfa-xpath/src/functions/fn.ts | 2 +- 23 files changed, 189 insertions(+), 179 deletions(-) diff --git a/packages/alfa-css/src/calculation/math-expression/function.ts b/packages/alfa-css/src/calculation/math-expression/function.ts index 54c4fb04f8..29f2442bbf 100644 --- a/packages/alfa-css/src/calculation/math-expression/function.ts +++ b/packages/alfa-css/src/calculation/math-expression/function.ts @@ -19,7 +19,7 @@ const { isValueExpression } = Value; */ export abstract class Function< T extends string = string, - A extends Array = Array + A extends Array = Array, > extends Expression { protected readonly _args: Readonly; protected readonly _kind: Kind; @@ -45,7 +45,7 @@ export abstract class Function< value.type === this.type && value._args.length === this._args.length && value._args.every((arg: Expression, i: number) => - arg.equals(this._args[i]) + arg.equals(this._args[i]), ) ); } @@ -73,7 +73,7 @@ export namespace Function { } public reduce( - resolver: Expression.Resolver + resolver: Expression.Resolver, ): Expression { const reduced = this._args[0].reduce(resolver); @@ -87,7 +87,7 @@ export namespace Function { } } - /** @public */ + /** @public (knip) */ export function isCalculation(value: unknown): value is Calculation { return value instanceof Calculation; } @@ -100,7 +100,7 @@ export namespace Function { // {@see https://drafts.csswg.org/css-values/#determine-the-type-of-a-calculation} const kind = expressions.reduce( (old, cur) => old.flatMap((kind) => kind.add(cur.kind)), - Result.of(first.kind) + Result.of(first.kind), ); return kind.map((kind) => new Max([first, ...expressions], kind)); @@ -111,7 +111,7 @@ export namespace Function { } public reduce( - resolver: Expression.Resolver + resolver: Expression.Resolver, ): Expression { // We know from the guard in Max.of that all args have the same kind. @@ -130,7 +130,7 @@ export namespace Function { if (values.every(isNumber)) { return Value.of( - Number.of(Math.max(...values.map((value) => value.value))) + Number.of(Math.max(...values.map((value) => value.value))), ); } @@ -138,17 +138,17 @@ export namespace Function { values.every( // The unit test is theoretically not needed since reduced angle values // should always be in the canonical unit (no relative angles) - (value) => isAngle(value) && value.hasUnit("deg") + (value) => isAngle(value) && value.hasUnit("deg"), ) ) { return Value.of( - Angle.of(Math.max(...values.map((value) => value.value)), "deg") + Angle.of(Math.max(...values.map((value) => value.value)), "deg"), ); } if (values.every((value) => isLength(value) && value.hasUnit("px"))) { return Value.of( - Length.of(Math.max(...values.map((value) => value.value)), "px") + Length.of(Math.max(...values.map((value) => value.value)), "px"), ); } // reduced contains percentages or relative lengths, we just fall through diff --git a/packages/alfa-css/src/calculation/math-expression/kind.ts b/packages/alfa-css/src/calculation/math-expression/kind.ts index d88f109148..e587851183 100644 --- a/packages/alfa-css/src/calculation/math-expression/kind.ts +++ b/packages/alfa-css/src/calculation/math-expression/kind.ts @@ -30,7 +30,7 @@ export class Kind implements Equatable, Serializable { angle: 0, percentage: 0, }), - None + None, ); private readonly _kinds: Kind.Map; @@ -42,12 +42,12 @@ export class Kind implements Equatable, Serializable { this._hint = hint; } - /** @public */ + /** @public (knip) */ public get kinds(): Kind.Map { return this._kinds; } - /** @public */ + /** @public (knip) */ public get hint(): Option { return this._hint; } @@ -58,7 +58,7 @@ export class Kind implements Equatable, Serializable { public is( kind?: Kind.Base, value: number = 1, - hinted: boolean = kind === "percentage" + hinted: boolean = kind === "percentage", ): boolean { for (const entry of this._kinds) { // this is not the dimension we're looking for, and it has power 0. @@ -107,10 +107,10 @@ export class Kind implements Equatable, Serializable { if ( [a._kinds, b._kinds].some( - (kinds) => kinds.get("percentage").getOr(0) !== 0 + (kinds) => kinds.get("percentage").getOr(0) !== 0, ) && [a._kinds, b._kinds].some((kinds) => - kinds.some((value, kind) => kind !== "percentage" && value !== 0) + kinds.some((value, kind) => kind !== "percentage" && value !== 0), ) ) { for (const hint of ["length", "angle"] as const) { @@ -153,10 +153,10 @@ export class Kind implements Equatable, Serializable { b._kinds.reduce( (kinds, value, kind) => kinds.set(kind, kinds.get(kind).getOr(0) + value), - a._kinds + a._kinds, ), - a._hint - ) + a._hint, + ), ); } @@ -167,9 +167,9 @@ export class Kind implements Equatable, Serializable { return new Kind( this._kinds.reduce( (kinds, value, kind) => kinds.set(kind, -1 * value), - this._kinds + this._kinds, ), - None + None, ); } @@ -182,10 +182,10 @@ export class Kind implements Equatable, Serializable { .set( hint, this._kinds.get(hint).getOr(0) + - this._kinds.get("percentage").getOr(0) + this._kinds.get("percentage").getOr(0), ) .set("percentage", 0), - Option.of(hint) + Option.of(hint), ); } diff --git a/packages/alfa-css/src/calculation/math-expression/operation.ts b/packages/alfa-css/src/calculation/math-expression/operation.ts index 50f5cc22f5..be026308c6 100644 --- a/packages/alfa-css/src/calculation/math-expression/operation.ts +++ b/packages/alfa-css/src/calculation/math-expression/operation.ts @@ -29,7 +29,7 @@ const { isPercentage } = Percentage; */ export abstract class Operation< T extends string = string, - O extends Array = Array + O extends Array = Array, > extends Expression { protected readonly _operands: Readonly; @@ -53,7 +53,7 @@ export abstract class Operation< value._type === this._type && value._operands.length === this._operands.length && value._operands.every((operand: Expression, i: number) => - operand.equals(this._operands[i]) + operand.equals(this._operands[i]), ) ); } @@ -87,7 +87,7 @@ export namespace Operation { protected constructor( type: T, operands: [Expression, Expression], - kind: Kind + kind: Kind, ) { super(type, operands, kind); } @@ -108,10 +108,10 @@ export namespace Operation { } public reduce( - resolver: Expression.Resolver + resolver: Expression.Resolver, ): Expression { const [fst, snd] = this._operands.map((operand) => - operand.reduce(resolver) + operand.reduce(resolver), ); if (Value.isValueExpression(fst) && Value.isValueExpression(snd)) { @@ -154,7 +154,7 @@ export namespace Operation { } } - /** @public */ + /** @public (knip) */ export function isSumExpression(value: unknown): value is Sum { return value instanceof Sum; } @@ -169,10 +169,10 @@ export namespace Operation { } public reduce( - resolver: Expression.Resolver + resolver: Expression.Resolver, ): Expression { const [operand] = this._operands.map((operand) => - operand.reduce(resolver) + operand.reduce(resolver), ); if (Value.isValueExpression(operand)) { @@ -229,10 +229,10 @@ export namespace Operation { } public reduce( - resolver: Expression.Resolver + resolver: Expression.Resolver, ): Expression { const [fst, snd] = this._operands.map((operand) => - operand.reduce(resolver) + operand.reduce(resolver), ); if (Value.isValueExpression(fst) && Value.isValueExpression(snd)) { @@ -276,7 +276,7 @@ export namespace Operation { } } - /** @public */ + /** @public (knip) */ export function isProductExpression(value: unknown): value is Product { return value instanceof Product; } @@ -291,10 +291,10 @@ export namespace Operation { } public reduce( - resolver: Expression.Resolver + resolver: Expression.Resolver, ): Expression { const [operand] = this._operands.map((operand) => - operand.reduce(resolver) + operand.reduce(resolver), ); if (Value.isValueExpression(operand)) { diff --git a/packages/alfa-css/src/calculation/numeric/numeric.ts b/packages/alfa-css/src/calculation/numeric/numeric.ts index 5b6c068ade..ddae66f757 100644 --- a/packages/alfa-css/src/calculation/numeric/numeric.ts +++ b/packages/alfa-css/src/calculation/numeric/numeric.ts @@ -64,7 +64,7 @@ export namespace Numeric { value: number; } - /** @public */ + /** @public (knip) */ export function isNumeric(value: unknown): value is Numeric { return value instanceof Numeric; } diff --git a/packages/alfa-css/src/value/image/gradient/item/hint.ts b/packages/alfa-css/src/value/image/gradient/item/hint.ts index 8bc8f00997..1e36f9ed42 100644 --- a/packages/alfa-css/src/value/image/gradient/item/hint.ts +++ b/packages/alfa-css/src/value/image/gradient/item/hint.ts @@ -30,6 +30,7 @@ export class Hint

this._position = position; } + /** @public (knip) */ public get position(): P { return this._position; } diff --git a/packages/alfa-css/src/value/image/gradient/item/stop.ts b/packages/alfa-css/src/value/image/gradient/item/stop.ts index 6217ebadd4..26f4be42fb 100644 --- a/packages/alfa-css/src/value/image/gradient/item/stop.ts +++ b/packages/alfa-css/src/value/image/gradient/item/stop.ts @@ -49,6 +49,7 @@ export class Stop< return this._color; } + /** @public (knip) */ public get position(): Option

{ return this._position; } @@ -113,6 +114,7 @@ export namespace Stop { export type PartialResolver = LengthPercentage.PartialResolver; + /** @public (knip) */ export function isStop(value: unknown): value is Stop { return value instanceof Stop; } 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 2952d6cf5c..1b66f2438b 100644 --- a/packages/alfa-css/src/value/image/gradient/linear/corner.ts +++ b/packages/alfa-css/src/value/image/gradient/linear/corner.ts @@ -15,7 +15,7 @@ const { map, either, pair, option, right } = Parser; export class Corner extends Value<"corner", false> { public static of( vertical: Position.Vertical, - horizontal: Position.Horizontal + horizontal: Position.Horizontal, ): Corner { return new Corner(vertical, horizontal); } @@ -25,19 +25,19 @@ export class Corner extends Value<"corner", false> { private constructor( vertical: Position.Vertical, - horizontal: Position.Horizontal + horizontal: Position.Horizontal, ) { super("corner", false); this._vertical = vertical; this._horizontal = horizontal; } - /** @public */ + /** @public (knip) */ public get vertical(): Position.Vertical { return this._vertical; } - /** @public */ + /** @public (knip) */ public get horizontal(): Position.Horizontal { return this._horizontal; } @@ -86,7 +86,7 @@ export namespace Corner { const parseCorner = ( side1: CSSParser, - side2: CSSParser + side2: CSSParser, ): CSSParser<[S1, S2]> => pair(side1, right(option(Token.parseWhitespace), side2)); @@ -102,13 +102,13 @@ export namespace Corner { either( map( parseCorner(Position.parseVertical, Position.parseHorizontal), - ([vertical, horizontal]) => Corner.of(vertical, horizontal) + ([vertical, horizontal]) => Corner.of(vertical, horizontal), ), map( parseCorner(Position.parseHorizontal, Position.parseVertical), - ([horizontal, vertical]) => Corner.of(vertical, horizontal) - ) - ) - ) + ([horizontal, vertical]) => Corner.of(vertical, horizontal), + ), + ), + ), ); } diff --git a/packages/alfa-css/src/value/image/gradient/linear/linear.ts b/packages/alfa-css/src/value/image/gradient/linear/linear.ts index 60b4eab818..a36d7ef1e0 100644 --- a/packages/alfa-css/src/value/image/gradient/linear/linear.ts +++ b/packages/alfa-css/src/value/image/gradient/linear/linear.ts @@ -143,6 +143,7 @@ export namespace Linear { export type PartialResolver = Item.PartialResolver & Direction.Resolver; + /** @public (knip) */ export function isLinear(value: unknown): value is Linear { return value instanceof Linear; } 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 25d77c8db0..c15f6588bd 100644 --- a/packages/alfa-css/src/value/image/gradient/linear/side.ts +++ b/packages/alfa-css/src/value/image/gradient/linear/side.ts @@ -24,7 +24,7 @@ export class Side extends Value<"side", false> { this._side = side; } - /** @public */ + /** @public (knip) */ public get side(): Position.Vertical | Position.Horizontal { return this._side; } @@ -70,8 +70,8 @@ export namespace Side { export const parse = map( right( Token.parseIdent("to"), - right(option(Token.parseWhitespace), Position.parse) + right(option(Token.parseWhitespace), Position.parse), ), - (side) => Side.of(side) + (side) => Side.of(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 3c9267a428..96bb450e67 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/circle.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/circle.ts @@ -27,7 +27,7 @@ export class Circle extends Value< this._radius = radius; } - /** @public */ + /** @public (knip) */ public get radius(): R { return this._radius; } diff --git a/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts b/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts index 1365d4ab7c..98ffde2c0f 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/ellipse.ts @@ -38,10 +38,12 @@ export class Ellipse this._vertical = vertical; } + /** @public (knip) */ public get horizontal(): R { return this._horizontal; } + /** @public (knip) */ public get vertical(): R { return this._vertical; } 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 33f69141f6..414f4c5427 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/extent.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/extent.ts @@ -15,7 +15,7 @@ const { map } = Parser; export class Extent extends Value<"extent", false> { public static of( shape: Extent.Shape = Extent.Shape.Circle, - size: Extent.Size = Extent.Size.FarthestCorner + size: Extent.Size = Extent.Size.FarthestCorner, ): Extent { return new Extent(shape, size); } @@ -29,12 +29,12 @@ export class Extent extends Value<"extent", false> { this._size = size; } - /** @public */ + /** @public (knip) */ public get shape(): Extent.Shape { return this._shape; } - /** @public */ + /** @public (knip) */ public get size(): Extent.Size { return this._size; } @@ -99,7 +99,7 @@ export namespace Extent { const parseShape = map( Keyword.parse("circle", "ellipse"), - (keyword) => keyword.value as Extent.Shape + (keyword) => keyword.value as Extent.Shape, ); const parseSize = map( @@ -107,9 +107,9 @@ export namespace Extent { "closest-side", "farthest-side", "closest-corner", - "farthest-corner" + "farthest-corner", ), - (keyword) => keyword.value as Size + (keyword) => keyword.value as Size, ); export const parse: CSSParser = (input) => { diff --git a/packages/alfa-css/src/value/image/gradient/radial/radial.ts b/packages/alfa-css/src/value/image/gradient/radial/radial.ts index 61531421e4..e4edfa5076 100644 --- a/packages/alfa-css/src/value/image/gradient/radial/radial.ts +++ b/packages/alfa-css/src/value/image/gradient/radial/radial.ts @@ -192,7 +192,7 @@ export namespace Radial { Shape.PartialResolver & Position.PartialResolver; - /** @public */ + /** @public (knip) */ export function isRadial(value: unknown): value is Radial { return value instanceof Radial; } diff --git a/packages/alfa-css/src/value/shape/basic-shape.ts b/packages/alfa-css/src/value/shape/basic-shape.ts index bfba2021c9..39d60811aa 100644 --- a/packages/alfa-css/src/value/shape/basic-shape.ts +++ b/packages/alfa-css/src/value/shape/basic-shape.ts @@ -5,7 +5,7 @@ import { Value } from "../value"; */ export abstract class BasicShape< K extends string = string, - CALC extends boolean = boolean + CALC extends boolean = boolean, > extends Value<"basic-shape", CALC> { private readonly _kind: K; protected constructor(kind: K, hasCalculation: CALC) { @@ -13,7 +13,7 @@ export abstract class BasicShape< this._kind = kind; } - /** @public */ + /** @public (knip) */ public get kind(): K { return this._kind; } diff --git a/packages/alfa-rules/src/common/diagnostic/contrast.ts b/packages/alfa-rules/src/common/diagnostic/contrast.ts index e929a50fcf..ae75b7576f 100644 --- a/packages/alfa-rules/src/common/diagnostic/contrast.ts +++ b/packages/alfa-rules/src/common/diagnostic/contrast.ts @@ -18,7 +18,7 @@ export class Contrast extends Diagnostic { public static of( message: string, threshold: number = 4.5, - pairings: Iterable> = [] + pairings: Iterable> = [], ): Contrast { return new Contrast(message, threshold, Array.from(pairings)); } @@ -29,7 +29,7 @@ export class Contrast extends Diagnostic { private constructor( message: string, threshold: number, - pairings: Array> + pairings: Array>, ) { super(message); @@ -84,16 +84,16 @@ export namespace Contrast { } export function isContrast( - value: Diagnostic + value: Diagnostic, ): value is Contrast; export function isContrast( - value: unknown + value: unknown, ): value is Contrast; - /** @public */ + /** @public (knip) */ export function isContrast( - value: unknown + value: unknown, ): value is Contrast { return value instanceof Contrast; } @@ -104,7 +104,7 @@ export namespace Contrast { public static of( color1: [FirstColor, RGB], color2: [SecondColor, RGB], - contrast: number + contrast: number, ): Pairing { return new Pairing(Color.of(...color1), Color.of(...color2), contrast); } @@ -116,7 +116,7 @@ export namespace Contrast { private constructor( color1: Color>, color2: Color>, - contrast: number + contrast: number, ) { this._color1 = color1; this._color2 = color2; @@ -186,7 +186,7 @@ export namespace Contrast { { public static of | SecondColor>( name: N, - value: RGB + value: RGB, ): Color { return new Color(name, value); } diff --git a/packages/alfa-rules/src/common/diagnostic/text-spacing.ts b/packages/alfa-rules/src/common/diagnostic/text-spacing.ts index 9f7eb76faa..4af344221c 100755 --- a/packages/alfa-rules/src/common/diagnostic/text-spacing.ts +++ b/packages/alfa-rules/src/common/diagnostic/text-spacing.ts @@ -19,7 +19,7 @@ export class TextSpacing extends Diagnostic { ratio: number, threshold: number, declaration: Declaration, - owner: Element + owner: Element, ): TextSpacing; public static of( @@ -30,7 +30,7 @@ export class TextSpacing extends Diagnostic { ratio?: number, threshold?: number, declaration?: Declaration, - owner?: Element + owner?: Element, ): Diagnostic { return property === undefined ? Diagnostic.of(message) @@ -42,7 +42,7 @@ export class TextSpacing extends Diagnostic { ratio!, threshold!, declaration!, - owner! + owner!, ); } @@ -64,7 +64,7 @@ export class TextSpacing extends Diagnostic { ratio: number, threshold: number, declaration: Declaration, - owner: Element + owner: Element, ) { super(message); this._property = property; @@ -160,16 +160,16 @@ export namespace TextSpacing { } export function isTextSpacing( - value: Diagnostic + value: Diagnostic, ): value is TextSpacing; export function isTextSpacing( - value: unknown + value: unknown, ): value is TextSpacing; - /** @public */ + /** @public (knip) */ export function isTextSpacing( - value: unknown + value: unknown, ): value is TextSpacing { return value instanceof TextSpacing; } diff --git a/packages/alfa-rules/src/common/diagnostic/with-bad-elements.ts b/packages/alfa-rules/src/common/diagnostic/with-bad-elements.ts index 597df2de09..1aa2078036 100755 --- a/packages/alfa-rules/src/common/diagnostic/with-bad-elements.ts +++ b/packages/alfa-rules/src/common/diagnostic/with-bad-elements.ts @@ -10,7 +10,7 @@ import { Iterable } from "@siteimprove/alfa-iterable"; export class WithBadElements extends Diagnostic implements Iterable { public static of( message: string, - errors: Iterable = [] + errors: Iterable = [], ): WithBadElements { return new WithBadElements(message, Array.from(errors)); } @@ -64,12 +64,12 @@ export namespace WithBadElements { } export function isWithBadElements( - value: Diagnostic + value: Diagnostic, ): value is WithBadElements; export function isWithBadElements(value: unknown): value is WithBadElements; - /** @public */ + /** @public (knip) */ export function isWithBadElements(value: unknown): value is WithBadElements { return value instanceof WithBadElements; } diff --git a/packages/alfa-rules/src/common/diagnostic/with-role.ts b/packages/alfa-rules/src/common/diagnostic/with-role.ts index e5e808b57d..1a30268471 100755 --- a/packages/alfa-rules/src/common/diagnostic/with-role.ts +++ b/packages/alfa-rules/src/common/diagnostic/with-role.ts @@ -66,7 +66,7 @@ export namespace WithRole { export function isWithRole(value: unknown): value is WithRole; - /** @public */ + /** @public (knip) */ export function isWithRole(value: unknown): value is WithRole { return value instanceof WithRole; } diff --git a/packages/alfa-rules/src/deprecated.ts b/packages/alfa-rules/src/deprecated.ts index a587c56fbb..0a4b001cf6 100755 --- a/packages/alfa-rules/src/deprecated.ts +++ b/packages/alfa-rules/src/deprecated.ts @@ -6,10 +6,10 @@ import DR66 from "./sia-dr66/rule"; import DR69 from "./sia-dr69/rule"; export { - /** @public */ DR6, - /** @public */ DR18, - /** @public */ DR34, - /** @public */ DR36, - /** @public */ DR66, - /** @public */ DR69, + /** @public (knip) */ DR6, + /** @public (knip) */ DR18, + /** @public (knip) */ DR34, + /** @public (knip) */ DR36, + /** @public (knip) */ DR66, + /** @public (knip) */ DR69, }; diff --git a/packages/alfa-rules/src/experimental.ts b/packages/alfa-rules/src/experimental.ts index 8680697b6b..1be0d29ab5 100755 --- a/packages/alfa-rules/src/experimental.ts +++ b/packages/alfa-rules/src/experimental.ts @@ -3,4 +3,8 @@ import ER87 from "./sia-er87/rule"; import R82 from "./sia-r82/rule"; import R109 from "./sia-r109/rule"; -export { /** @public */ ER87, /** @public */ R82, /** @public */ R109 }; +export { + /** @public (knip) */ ER87, + /** @public (knip) */ R82, + /** @public (knip) */ R109, +}; diff --git a/packages/alfa-rules/src/rules.ts b/packages/alfa-rules/src/rules.ts index a73693ff41..7eccbe13e7 100644 --- a/packages/alfa-rules/src/rules.ts +++ b/packages/alfa-rules/src/rules.ts @@ -88,92 +88,92 @@ import R96 from "./sia-r96/rule"; import R110 from "./sia-r110/rule"; export { - /** @public */ R1, - /** @public */ R2, - /** @public */ R3, - /** @public */ R4, - /** @public */ R5, - /** @public */ R7, - /** @public */ R8, - /** @public */ R9, - /** @public */ R10, - /** @public */ R11, - /** @public */ R12, - /** @public */ R13, - /** @public */ R14, - /** @public */ R15, - /** @public */ R16, - /** @public */ R17, - /** @public */ R18, - /** @public */ R19, - /** @public */ R20, - /** @public */ R21, - /** @public */ R22, - /** @public */ R23, - /** @public */ R24, - /** @public */ R25, - /** @public */ R26, - /** @public */ R27, - /** @public */ R28, - /** @public */ R29, - /** @public */ R30, - /** @public */ R31, - /** @public */ R32, - /** @public */ R33, - /** @public */ R35, - /** @public */ R37, - /** @public */ R38, - /** @public */ R39, - /** @public */ R40, - /** @public */ R41, - /** @public */ R42, - /** @public */ R43, - /** @public */ R44, - /** @public */ R45, - /** @public */ R46, - /** @public */ R47, - /** @public */ R48, - /** @public */ R49, - /** @public */ R50, - /** @public */ R53, - /** @public */ R54, - /** @public */ R55, - /** @public */ R56, - /** @public */ R57, - /** @public */ R59, - /** @public */ R60, - /** @public */ R61, - /** @public */ R62, - /** @public */ R63, - /** @public */ R64, - /** @public */ R65, - /** @public */ R66, - /** @public */ R67, - /** @public */ R68, - /** @public */ R69, - /** @public */ R70, - /** @public */ R71, - /** @public */ R72, - /** @public */ R73, - /** @public */ R74, - /** @public */ R75, - /** @public */ R76, - /** @public */ R77, - /** @public */ R78, - /** @public */ R79, - /** @public */ R80, - /** @public */ R81, - /** @public */ R83, - /** @public */ R84, - /** @public */ R85, - /** @public */ R86, - /** @public */ R87, - /** @public */ R90, - /** @public */ R91, - /** @public */ R92, - /** @public */ R93, - /** @public */ R94, - /** @public */ R95, - /** @public */ R96, - /** @public */ R110, + /** @public (knip) */ R1, + /** @public (knip) */ R2, + /** @public (knip) */ R3, + /** @public (knip) */ R4, + /** @public (knip) */ R5, + /** @public (knip) */ R7, + /** @public (knip) */ R8, + /** @public (knip) */ R9, + /** @public (knip) */ R10, + /** @public (knip) */ R11, + /** @public (knip) */ R12, + /** @public (knip) */ R13, + /** @public (knip) */ R14, + /** @public (knip) */ R15, + /** @public (knip) */ R16, + /** @public (knip) */ R17, + /** @public (knip) */ R18, + /** @public (knip) */ R19, + /** @public (knip) */ R20, + /** @public (knip) */ R21, + /** @public (knip) */ R22, + /** @public (knip) */ R23, + /** @public (knip) */ R24, + /** @public (knip) */ R25, + /** @public (knip) */ R26, + /** @public (knip) */ R27, + /** @public (knip) */ R28, + /** @public (knip) */ R29, + /** @public (knip) */ R30, + /** @public (knip) */ R31, + /** @public (knip) */ R32, + /** @public (knip) */ R33, + /** @public (knip) */ R35, + /** @public (knip) */ R37, + /** @public (knip) */ R38, + /** @public (knip) */ R39, + /** @public (knip) */ R40, + /** @public (knip) */ R41, + /** @public (knip) */ R42, + /** @public (knip) */ R43, + /** @public (knip) */ R44, + /** @public (knip) */ R45, + /** @public (knip) */ R46, + /** @public (knip) */ R47, + /** @public (knip) */ R48, + /** @public (knip) */ R49, + /** @public (knip) */ R50, + /** @public (knip) */ R53, + /** @public (knip) */ R54, + /** @public (knip) */ R55, + /** @public (knip) */ R56, + /** @public (knip) */ R57, + /** @public (knip) */ R59, + /** @public (knip) */ R60, + /** @public (knip) */ R61, + /** @public (knip) */ R62, + /** @public (knip) */ R63, + /** @public (knip) */ R64, + /** @public (knip) */ R65, + /** @public (knip) */ R66, + /** @public (knip) */ R67, + /** @public (knip) */ R68, + /** @public (knip) */ R69, + /** @public (knip) */ R70, + /** @public (knip) */ R71, + /** @public (knip) */ R72, + /** @public (knip) */ R73, + /** @public (knip) */ R74, + /** @public (knip) */ R75, + /** @public (knip) */ R76, + /** @public (knip) */ R77, + /** @public (knip) */ R78, + /** @public (knip) */ R79, + /** @public (knip) */ R80, + /** @public (knip) */ R81, + /** @public (knip) */ R83, + /** @public (knip) */ R84, + /** @public (knip) */ R85, + /** @public (knip) */ R86, + /** @public (knip) */ R87, + /** @public (knip) */ R90, + /** @public (knip) */ R91, + /** @public (knip) */ R92, + /** @public (knip) */ R93, + /** @public (knip) */ R94, + /** @public (knip) */ R95, + /** @public (knip) */ R96, + /** @public (knip) */ R110, }; diff --git a/packages/alfa-rules/src/tags/version.ts b/packages/alfa-rules/src/tags/version.ts index cc7fe4f983..3ff62708e9 100644 --- a/packages/alfa-rules/src/tags/version.ts +++ b/packages/alfa-rules/src/tags/version.ts @@ -47,9 +47,9 @@ export namespace Version { version: N; } - /** @public */ + /** @public (knip) */ export function isVersion( - value: unknown + value: unknown, ): value is Version { return value instanceof Version; } diff --git a/packages/alfa-xpath/src/functions/fn.ts b/packages/alfa-xpath/src/functions/fn.ts index c11fcac9e2..f6f3eeb44d 100644 --- a/packages/alfa-xpath/src/functions/fn.ts +++ b/packages/alfa-xpath/src/functions/fn.ts @@ -6,7 +6,7 @@ import { Function } from "../function"; export namespace fn { const prefix = "fn"; - /** @public */ + /** @public (knip) */ // This is actually used by some magic in the index. export const root: Function<[Node], Node> = { prefix, From 3a61a3121099d3d35dbc0787de3ea29e9fb9fe1f Mon Sep 17 00:00:00 2001 From: Jean-Yves Moyen Date: Tue, 14 Nov 2023 09:00:52 +0100 Subject: [PATCH 13/13] Extract documentation --- docs/review/api/alfa-css.api.md | 134 +++++++++++++++++------------- docs/review/api/alfa-rules.api.md | 1 - 2 files changed, 77 insertions(+), 58 deletions(-) diff --git a/docs/review/api/alfa-css.api.md b/docs/review/api/alfa-css.api.md index 686b0cc6df..7ad5e5fe07 100644 --- a/docs/review/api/alfa-css.api.md +++ b/docs/review/api/alfa-css.api.md @@ -96,7 +96,7 @@ export type AnglePercentage = AnglePercentage // @public (undocumented) export namespace AnglePercentage { - export class Calculated extends Dimension.Calculated<"angle-percentage"> implements Resolvable { + export class Calculated extends Dimension.Calculated<"angle-percentage"> implements Resolvable { // (undocumented) equals(value: unknown): value is this; // (undocumented) @@ -104,7 +104,7 @@ export namespace AnglePercentage { // (undocumented) static of(value: Math_2<"angle-percentage">): Calculated; // (undocumented) - resolve(resolver: Resolver): Canonical; + resolve(): Canonical; } // (undocumented) export namespace Calculated { @@ -140,9 +140,7 @@ export namespace AnglePercentage { export function of(value: Math_2<"angle-percentage">): Calculated; // (undocumented) export function of(value: Math_2<"percentage">): Percentage.Calculated; - export function resolve(resolver: Resolver): (value: AnglePercentage) => Canonical; - // (undocumented) - export type Resolver = Percentage.Resolver<"angle">; + export function resolve(value: AnglePercentage): Canonical; const // (undocumented) parse: Parser; } @@ -212,9 +210,10 @@ 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 // // @public (undocumented) -export class Circle extends BasicShape<"circle", Value.HasCalculation<[R, P]>> { +export class Circle extends BasicShape<"circle", Value.HasCalculation<[R, P]>> implements Resolvable, PartiallyResolvable { // (undocumented) get center(): P; // (undocumented) @@ -226,6 +225,8 @@ export class Circle ex // (undocumented) static of(radius: R, center: P): Circle; // (undocumented) + partiallyResolve(resolver: Circle.PartialResolver): Circle.PartiallyResolved; + // (undocumented) get radius(): R; // (undocumented) resolve(resolver: Circle.Resolver): Circle.Canonical; @@ -249,8 +250,6 @@ export namespace Circle { radius: Radius.JSON; } // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Circle) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Circle; // (undocumented) export type PartialResolver = Radius.PartialResolver & Position.PartialResolver; @@ -392,22 +391,19 @@ export namespace Declaration { parseList: Parser>; } -// Warning: (ae-forgotten-export) The symbol "Type" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "Dimensions" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export type Dimension = Dimension.Calculated | Dimension.Fixed[0]>; - // @public (undocumented) export namespace Dimension { - export abstract class Calculated extends Numeric.Calculated[0]> implements Resolvable[0], Dimensions[2]>, unknown> { + // 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 + export abstract class Calculated extends Numeric.Calculated implements Resolvable, unknown>, PartiallyResolvable { protected constructor(math: Numeric.ToMath, type: T); // (undocumented) equals(value: unknown): value is this; // (undocumented) - hasCalculation(): this is Calculated; + hasCalculation(): this is Calculated; // (undocumented) - abstract resolve(resolver?: unknown): Fixed[0], Dimensions[2]>; + abstract resolve(resolver?: unknown): Fixed; } // (undocumented) export namespace Calculated { @@ -416,10 +412,11 @@ export namespace Dimension { } } // Warning: (ae-forgotten-export) The symbol "Numeric_2" needs to be exported by the entry point index.d.ts - export abstract class Fixed[1] = Dimensions[1]> extends Numeric.Fixed implements Resolvable[0], Dimensions[2]>, unknown>, Convertible[1]>, Comparable> { + // Warning: (ae-forgotten-export) The symbol "DUnit" needs to be exported by the entry point index.d.ts + export abstract class Fixed extends Numeric.Fixed implements Resolvable, unknown>, Convertible, Comparable> { protected constructor(value: number, unit: U, type: T); // (undocumented) - get canonicalUnit(): Dimensions[2]; + get canonicalUnit(): DCanonicalUnit[T]; // (undocumented) compare(value: Fixed): Comparison; // (undocumented) @@ -429,9 +426,9 @@ export namespace Dimension { // (undocumented) hash(hash: Hash): void; // (undocumented) - abstract hasUnit[1]>(unit: V): this is Fixed; + abstract hasUnit(unit: V): this is Fixed; // (undocumented) - abstract resolve(resolver?: unknown): Fixed[2]>; + abstract resolve(resolver?: unknown): Fixed; // (undocumented) toJSON(): Fixed.JSON; // (undocumented) @@ -441,12 +438,12 @@ export namespace Dimension { // (undocumented) protected readonly _unit: U; // (undocumented) - abstract withUnit[1]>(unit: V): Fixed; + abstract withUnit(unit: V): Fixed; } // (undocumented) export namespace Fixed { // (undocumented) - export interface JSON[1] = Dimensions[1]> extends Numeric.Fixed.JSON { + export interface JSON extends Numeric.Fixed.JSON { // (undocumented) unit: U; } @@ -460,7 +457,7 @@ export namespace Dimension { } // @public (undocumented) -export class Ellipse extends BasicShape<"ellipse", Value.HasCalculation<[R, P]>> { +export class Ellipse extends BasicShape<"ellipse", Value.HasCalculation<[R, P]>> implements Resolvable, PartiallyResolvable { // (undocumented) get center(): P; // (undocumented) @@ -472,6 +469,8 @@ export class Ellipse e // (undocumented) static of(rx: R, ry: R, center: P): Ellipse; // (undocumented) + partiallyResolve(resolver: Ellipse.PartialResolver): Ellipse.PartiallyResolved; + // (undocumented) resolve(resolver: Ellipse.Resolver): Ellipse.Canonical; // (undocumented) get rx(): R; @@ -499,8 +498,6 @@ export namespace Ellipse { ry: Radius.JSON; } // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Ellipse) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Ellipse; // (undocumented) export type PartialResolver = Radius.PartialResolver & Position.PartialResolver; @@ -562,8 +559,6 @@ export namespace Gradient { import Linear = linear.Linear; import Radial = radial.Radial; // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Gradient) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Linear.PartiallyResolved | Radial.PartiallyResolved; // (undocumented) export type PartialResolver = Linear.PartialResolver & Radial.PartialResolver; @@ -712,7 +707,7 @@ export namespace Image { // Warning: (ae-forgotten-export) The symbol "HasCalculation" needs to be exported by the entry point index.d.ts // // @public (undocumented) -export class Inset extends BasicShape<"inset", HasCalculation> { +export class Inset extends BasicShape<"inset", HasCalculation> implements Resolvable, PartiallyResolvable { // (undocumented) get bottom(): O; // (undocumented) @@ -734,6 +729,8 @@ export class Inset PartiallyResolved; - // (undocumented) export type PartiallyResolved = Inset; // (undocumented) export type PartialResolver = LengthPercentage.PartialResolver; @@ -787,6 +782,8 @@ export namespace Integer { // (undocumented) static of(value: Math_2<"number">): Calculated; // (undocumented) + partiallyResolve(): Canonical; + // (undocumented) resolve(): Canonical; // (undocumented) toJSON(): Calculated.JSON; @@ -809,6 +806,8 @@ export namespace Integer { // (undocumented) static of(value: number | Integer_2): Fixed; // (undocumented) + partiallyResolve(): this; + // (undocumented) resolve(): this; // (undocumented) scale(factor: number): Fixed; @@ -956,7 +955,7 @@ export type LengthPercentage = LengthPercen // @public (undocumented) export namespace LengthPercentage { - export class Calculated extends Dimension.Calculated<"length-percentage"> implements Resolvable { + export class Calculated extends Dimension.Calculated<"length-percentage"> implements Resolvable, PartiallyResolvable { // (undocumented) equals(value: unknown): value is this; // (undocumented) @@ -964,6 +963,8 @@ export namespace LengthPercentage { // (undocumented) static of(value: Math_2<"length-percentage">): Calculated; // (undocumented) + partiallyResolve(resolver: PartialResolver): this; + // (undocumented) resolve(resolver: Resolver): Canonical; } // (undocumented) @@ -1016,7 +1017,7 @@ export namespace Lexer { } // @public (undocumented) -export class List extends Value<"list", Value.HasCalculation<[V]>> implements Iterable_2, Resolvable>, Resolvable.Resolver> { +export class List extends Value<"list", Value.HasCalculation<[V]>> implements Iterable_2, Resolvable>, Resolvable.Resolver>, PartiallyResolvable>, Resolvable.PartialResolver> { // (undocumented) [Symbol.iterator](): Iterator; // (undocumented) @@ -1030,6 +1031,8 @@ export class List extends Value<"list", Value.HasCalculation<[V // (undocumented) static of(values: Iterable_2, separator?: string): List; // (undocumented) + partiallyResolve(resolver?: Resolvable.PartialResolver): List>; + // (undocumented) resolve(resolver?: Resolvable.Resolver): List>; // (undocumented) toJSON(): List.JSON; @@ -1053,9 +1056,9 @@ export namespace List { values: Array>; } const // (undocumented) - parseCommaSeparated: >(parseValue: Parser, lower?: number, upper?: number) => Parser>; + parseCommaSeparated: >(parseValue: Parser, lower?: number, upper?: number) => Parser>; const // (undocumented) - parseSpaceSeparated: >(parseValue: Parser, lower?: number, upper?: number) => Parser>; + parseSpaceSeparated: >(parseValue: Parser, lower?: number, upper?: number) => Parser>; } // @public (undocumented) @@ -1297,6 +1300,8 @@ namespace Number_2 { // (undocumented) static of(value: Math_2<"number">): Calculated; // (undocumented) + partiallyResolve(): Canonical; + // (undocumented) resolve(): Canonical; // (undocumented) toJSON(): Calculated.JSON; @@ -1315,6 +1320,8 @@ namespace Number_2 { // (undocumented) static of(value: number | Number_3): Fixed; // (undocumented) + partiallyResolve(): this; + // (undocumented) resolve(): this; // (undocumented) scale(factor: number): Fixed; @@ -1351,13 +1358,13 @@ export type Numeric = Numeric.Calculated< // @public (undocumented) export namespace Numeric { - export abstract class Calculated extends Value implements Resolvable, never> { + 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); // (undocumented) equals(value: unknown): value is this; // (undocumented) - hasCalculation(): this is Calculated; + hasCalculation(): this is Calculated; // (undocumented) hash(hash: Hash): void; // Warning: (ae-incompatible-release-tags) The symbol "math" is marked as @public, but its signature references "Numeric" which is marked as @internal @@ -1385,7 +1392,7 @@ export namespace Numeric { math: Serializable.ToJSON>; } } - export abstract class Fixed extends Value implements Resolvable, never>, Comparable { + export abstract class Fixed extends Value implements Resolvable, never>, Comparable { protected constructor(value: number, type: T); // (undocumented) compare(value: Fixed): Comparison; @@ -1440,7 +1447,7 @@ export type Percentage = Percentage.C // @public (undocumented) export namespace Percentage { - export class Calculated extends Numeric.Calculated<"percentage", H> implements Resolvable> { + export class Calculated extends Numeric.Calculated<"percentage", H, "percentage"> implements Resolvable>, PartiallyResolvable, PartialResolver> { // (undocumented) equals(value: unknown): value is this; // (undocumented) @@ -1448,6 +1455,8 @@ export namespace Percentage { // (undocumented) static of(value: Math_2<"percentage">): Calculated; // (undocumented) + partiallyResolve(): PartiallyResolved; + // (undocumented) resolve(): Canonical; // (undocumented) resolve(resolver: Resolver): T; @@ -1463,12 +1472,14 @@ export namespace Percentage { // (undocumented) export type Canonical = Fixed; // Warning: (ae-forgotten-export) The symbol "Canonicals" needs to be exported by the entry point index.d.ts - export class Fixed extends Numeric.Fixed<"percentage", "percentage" | H> implements Resolvable> { + export class Fixed extends Numeric.Fixed<"percentage", "percentage" | H, "percentage"> implements Resolvable>, PartiallyResolvable, PartialResolver> { // (undocumented) equals(value: unknown): value is this; // (undocumented) static of(value: number | Percentage_2): Fixed; // (undocumented) + partiallyResolve(): PartiallyResolved; + // (undocumented) resolve(): Canonical; // (undocumented) resolve(resolver: Resolver): T; @@ -1500,8 +1511,6 @@ export namespace Percentage { // (undocumented) export function parse(input: Slice): Result<[Slice, Fixed | Calculated], string>; // (undocumented) - export function partiallyResolve(value: Percentage): PartiallyResolved; - // (undocumented) export type PartiallyResolved = Fixed; // (undocumented) export type PartialResolver = never; @@ -1547,7 +1556,7 @@ export namespace Perspective { } // @public (undocumented) -export class Polygon extends BasicShape<"polygon", Value.HasCalculation<[V]>> { +export class Polygon extends BasicShape<"polygon", Value.HasCalculation<[V]>> implements Resolvable, PartiallyResolvable { // (undocumented) equals(value: Polygon): boolean; // (undocumented) @@ -1559,6 +1568,8 @@ export class Polygon(fill: Option, vertices: Iterable_2>): Polygon; // (undocumented) + partiallyResolve(resolver: Polygon.PartialResolver): Polygon.PartiallyResolved; + // (undocumented) resolve(resolver: Polygon.Resolver): Polygon.Canonical; // (undocumented) toJSON(): Polygon.JSON; @@ -1584,8 +1595,6 @@ export namespace Polygon { vertices: Array_2>>; } // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Polygon) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Polygon; // (undocumented) export type PartialResolver = LengthPercentage.PartialResolver; @@ -1601,7 +1610,7 @@ export namespace Polygon { } // @public (undocumented) -export class Position = Position.Component, VC extends Position.Component = Position.Component> extends Value<"position", Value.HasCalculation<[HC, VC]>> implements Resolvable, Position.Resolver> { +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) equals(value: unknown): value is this; // (undocumented) @@ -1611,6 +1620,8 @@ export class Position = Position.Component, VC extends Position.Component = Position.Component>(horizontal: HC, vertical: VC): Position; // (undocumented) + partiallyResolve(resolver: Position.PartialResolver): Position.PartiallyResolved; + // (undocumented) resolve(resolver: Position.Resolver): Position.Canonical; // (undocumented) toJSON(): Position.JSON; @@ -1639,8 +1650,6 @@ export namespace Position { import Side = side.Side; import Component = component.Component; // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Position) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Position, Component_2.PartiallyResolved>; // (undocumented) export type PartialResolver = Component_2.PartialResolver; @@ -1653,7 +1662,7 @@ export namespace Position { } // @public (undocumented) -export class Radius extends BasicShape<"radius", Value.HasCalculation<[R]>> { +export class Radius extends BasicShape<"radius", Value.HasCalculation<[R]>> implements Resolvable, PartiallyResolvable { // (undocumented) equals(value: Radius): boolean; // (undocumented) @@ -1663,6 +1672,8 @@ export class Radius(value: R): Radius; // (undocumented) + partiallyResolve(resolver: Radius.PartialResolver): Radius.PartiallyResolved; + // (undocumented) resolve(resolver: Radius.Resolver): Radius.Canonical; // (undocumented) toJSON(): Radius.JSON; @@ -1684,8 +1695,6 @@ export namespace Radius { value: LengthPercentage.JSON | Keyword.JSON; } // (undocumented) - export function PartiallyResolve(resolver: PartialResolver): (value: Radius) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Radius; // (undocumented) export type PartialResolver = LengthPercentage.PartialResolver; @@ -2913,7 +2922,7 @@ export namespace Transform { } // @public (undocumented) -export class Translate extends Function_3<"translate", Value.HasCalculation<[X, Y, Z]>> implements Resolvable { +export class Translate extends Function_3<"translate", Value.HasCalculation<[X, Y, Z]>> implements Resolvable, PartiallyResolvable { // (undocumented) equals(value: unknown): value is this; // (undocumented) @@ -2921,6 +2930,8 @@ export class Translate(x: X, y: Y, z: Z): Translate; // (undocumented) + partiallyResolve(resolver: Translate.PartialResolver): Translate.PartiallyResolved; + // (undocumented) resolve(resolver: Translate.Resolver): Translate.Canonical; // (undocumented) toJSON(): Translate.JSON; @@ -2950,8 +2961,6 @@ export namespace Translate { z: Length.JSON; } // (undocumented) - export function partiallyResolve(resolver: PartialResolver): (value: Translate) => PartiallyResolved; - // (undocumented) export type PartiallyResolved = Translate; // (undocumented) export type PartialResolver = LengthPercentage.PartialResolver & Length.Resolver; @@ -2962,7 +2971,7 @@ export namespace Translate { } // @public (undocumented) -export class Tuple> extends Value<"tuple", Value.HasCalculation> implements Resolvable>, Tuple.Resolver> { +export class Tuple> extends Value<"tuple", Value.HasCalculation> implements Resolvable>, Tuple.Resolver>, PartiallyResolvable>, Tuple.PartialResolver> { // (undocumented) equals>(value: Tuple): boolean; // (undocumented) @@ -2972,6 +2981,8 @@ export class Tuple> extends Value<"tuple", Value.HasCalcu // (undocumented) static of>(...values: Readonly): Tuple; // (undocumented) + partiallyResolve(resolver?: Tuple.PartialResolver): Tuple>; + // (undocumented) resolve(resolver?: Tuple.Resolver): Tuple>; // (undocumented) toJSON(): Tuple.JSON; @@ -2990,6 +3001,13 @@ export namespace Tuple { // (undocumented) values: Serializable.ToJSON; } + // (undocumented) + export type PartiallyResolved> = T extends [ + infer Head extends Value, + ...infer Tail extends Array + ] ? [Resolvable.PartiallyResolved, ...PartiallyResolved] : []; + // (undocumented) + export type PartialResolver> = T extends Array ? Resolvable.PartialResolver : never; // @internal export type Resolved> = T extends [ infer Head extends Value, @@ -3089,17 +3107,19 @@ export namespace URL { } // @public -export abstract class Value implements Equatable, Hashable, Serializable>, Resolvable, Resolvable.Resolver> { +export abstract class Value implements Equatable, Hashable, Serializable>, Resolvable, Resolvable.Resolver>, PartiallyResolvable, Resolvable.PartialResolver> { protected constructor(type: T, hasCalculation: CALC); // (undocumented) abstract equals(value: unknown): value is this; // (undocumented) - hasCalculation(): this is Value; + hasCalculation(): this is Value; // (undocumented) protected readonly _hasCalculation: CALC; // (undocumented) abstract hash(hash: Hash): void; // (undocumented) + partiallyResolve(resolver?: unknown): Value; + // (undocumented) abstract resolve(resolver?: unknown): Value; // (undocumented) toJSON(): Value.JSON; diff --git a/docs/review/api/alfa-rules.api.md b/docs/review/api/alfa-rules.api.md index f83daf40b6..c9c03aa49a 100644 --- a/docs/review/api/alfa-rules.api.md +++ b/docs/review/api/alfa-rules.api.md @@ -419,7 +419,6 @@ export class Version extends Tag<"version"> { // @public (undocumented) export namespace Version { - // (undocumented) export function isVersion(value: unknown): value is Version; // (undocumented) export interface JSON extends Tag.JSON<"version"> {