From a2f3a485d5e02993c0f35762cd9d80a6ce4ced5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=BDiga=20Ham?= Date: Tue, 24 Sep 2024 18:05:41 +0100 Subject: [PATCH] feat(axe.d.ts): add nodeSerializer typings (#4551) This API was added in pr #4093, but TS definitions were never added. For simplicity I'm using SerialDqElement in the API. We could introduce a generic for the custom serialized type (T extends SerialDqElement), but it's hard to consistently use it everywhere (AxeReporter, NodeSerializer.dqElmToSpec). I also fixed DqElement.mergeSpecs which is needed to implement a custom node serializer: it exists on the constructor and not on the individual instances --- axe.d.ts | 27 +++++++++++++++++++++++---- typings/axe-core/axe-core-tests.ts | 13 +++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/axe.d.ts b/axe.d.ts index 47bca29ff0..5c65935400 100644 --- a/axe.d.ts +++ b/axe.d.ts @@ -342,6 +342,9 @@ declare namespace axe { interface DqElement extends SerialDqElement { element: Element; toJSON(): SerialDqElement; + } + interface DqElementConstructor { + new (elm: Element, options?: { absolutePaths?: boolean }): DqElement; mergeSpecs( childSpec: SerialDqElement, parentSpec: SerialDqElement @@ -405,6 +408,24 @@ declare namespace axe { boundingClientRect: DOMRect; } + interface CustomNodeSerializer { + toSpec: (dqElm: DqElement) => T; + mergeSpecs: (nodeSpec: T, parentFrameSpec: T) => T; + } + + interface NodeSerializer { + update: (serializer: CustomNodeSerializer) => void; + toSpec: (node: Element | VirtualNode) => SerialDqElement; + dqElmToSpec: ( + dqElm: DqElement | SerialDqElement, + options?: RunOptions + ) => SerialDqElement; + mergeSpecs: ( + nodeSpec: SerialDqElement, + parentFrameSpec: SerialDqElement + ) => SerialDqElement; + } + interface Utils { getFrameContexts: ( context?: ElementContext, @@ -423,15 +444,13 @@ declare namespace axe { selector: unknown ) => selector is LabelledShadowDomSelector; - DqElement: new ( - elm: Element, - options?: { absolutePaths?: boolean } - ) => DqElement; + DqElement: DqElementConstructor; uuid: ( options?: { random?: Uint8Array | Array }, buf?: Uint8Array | Array, offset?: number ) => string | Uint8Array | Array; + nodeSerializer: NodeSerializer; } interface Aria { diff --git a/typings/axe-core/axe-core-tests.ts b/typings/axe-core/axe-core-tests.ts index 43a1286ff0..f0734e2240 100644 --- a/typings/axe-core/axe-core-tests.ts +++ b/typings/axe-core/axe-core-tests.ts @@ -450,6 +450,19 @@ if (axe.utils.isLabelledShadowDomSelector(unknownContext)) { } else if (axe.utils.isContextSpec(unknownContext)) { let context: axe.ContextSpec = unknownContext; } +axe.utils.nodeSerializer.update({ + toSpec(dqElm: axe.DqElement) { + return dqElm.toJSON(); + }, + mergeSpecs(childSpec: axe.SerialDqElement, parentSpec: axe.SerialDqElement) { + return axe.utils.DqElement.mergeSpecs(childSpec, parentSpec); + } +}); +const spec2: axe.SerialDqElement = axe.utils.nodeSerializer.toSpec(element); +const spec3: axe.SerialDqElement = axe.utils.nodeSerializer.dqElmToSpec( + dqElement, + options +); // Commons axe.commons.aria.getRoleType('img');