Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(@wordpress/dom): improve accuracy of jsdoc #16352

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 19 additions & 35 deletions packages/dom/README.md
Expand Up @@ -52,7 +52,7 @@ _Parameters_

_Returns_

- `?Node`: Offset parent.
- `(Element|null)`: Offset parent.

<a name="getRectangleFromRange" href="#getRectangleFromRange">#</a> **getRectangleFromRange**

Expand All @@ -68,15 +68,15 @@ _Returns_

<a name="getScrollContainer" href="#getScrollContainer">#</a> **getScrollContainer**

Given a DOM node, finds the closest scrollable container node.
Given a DOM element, finds the closest scrollable container element.

_Parameters_

- _node_ `Element`: Node from which to start.
- _element_ `Element`: Element from which to start.

_Returns_

- `?Element`: Scrollable container node, if found.
- `(Element|undefined)`: Scrollable container node, if found.

<a name="insertAfter" href="#insertAfter">#</a> **insertAfter**

Expand All @@ -85,12 +85,8 @@ the latter.

_Parameters_

- _newNode_ `Element`: Node to be inserted.
- _referenceNode_ `Element`: Node after which to perform the insertion.

_Returns_

- `void`:
- _newNode_ `Node`: Node to be inserted.
- _referenceNode_ `Node`: Node after which to perform the insertion.

<a name="isEntirelySelected" href="#isEntirelySelected">#</a> **isEntirelySelected**

Expand All @@ -99,7 +95,7 @@ Returns true if there is no possibility of selection.

_Parameters_

- _element_ `Element`: The element to check.
- _element_ `HTMLElement`: The element to check.

_Returns_

Expand All @@ -111,7 +107,7 @@ Check whether the selection is horizontally at the edge of the container.

_Parameters_

- _container_ `Element`: Focusable element.
- _container_ `HTMLElement`: Focusable element.
- _isReverse_ `boolean`: Set to true to check left, false for right.

_Returns_
Expand Down Expand Up @@ -139,7 +135,7 @@ Check whether the selection is vertically at the edge of the container.

_Parameters_

- _container_ `Element`: Focusable element.
- _container_ `HTMLElement`: Focusable element.
- _isReverse_ `boolean`: Set to true to check top, false for bottom.

_Returns_
Expand All @@ -152,7 +148,7 @@ Places the caret at start or end of a given element.

_Parameters_

- _container_ `Element`: Focusable element.
- _container_ `(HTMLElement|undefined)`: Focusable element.
- _isReverse_ `boolean`: True for end, false for start.

<a name="placeCaretAtVerticalEdge" href="#placeCaretAtVerticalEdge">#</a> **placeCaretAtVerticalEdge**
Expand All @@ -161,7 +157,7 @@ Places the caret at the top or bottom of a given element.

_Parameters_

- _container_ `Element`: Focusable element.
- _container_ `(HTMLElement|undefined)`: Focusable element.
- _isReverse_ `boolean`: True for bottom, false for top.
- _rect_ `[DOMRect]`: The rectangle to position the caret with.
- _mayUseScroll_ `[boolean]`: True to allow scrolling, false to disallow.
Expand All @@ -172,37 +168,29 @@ Given a DOM node, removes it from the DOM.

_Parameters_

- _node_ `Element`: Node to be removed.

_Returns_

- `void`:
- _node_ `Node`: Node to be removed.

<a name="replace" href="#replace">#</a> **replace**

Given two DOM nodes, replaces the former with the latter in the DOM.

_Parameters_

- _processedNode_ `Element`: Node to be removed.
- _newNode_ `Element`: Node to be inserted in its place.

_Returns_

- `void`:
- _processedNode_ `Node`: Node to be removed.
- _newNode_ `Node`: Node to be inserted in its place.

<a name="replaceTag" href="#replaceTag">#</a> **replaceTag**

Replaces the given node with a new node with the given tag name.

_Parameters_

- _node_ `Element`: The node to replace
- _tagName_ `string`: The new tag name.
- _node_ `Node`: The node to replace.
- _tagName_ `T`: The new tag name.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure the documentation generator is prepared for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is generated by this part of the JSDoc which is not to be found in the JSDoc standard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'l defer this to @aduth but I was under the impression that we were not following the core jsdoc standard to the letter, but instead the one that is picked up by the language service (i.e. tsdoc)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we want to have any hope of achieving tsc types checking (#18838), we'll need to target the TypeScript syntax extensions. Even something such as sharing types across files (import) would not be straight-forward otherwise.

We'll need some clarity and guidelines around how this is rolled out, though. I've included it in the agenda for tomorrow's #core-js meeting:

https://docs.google.com/document/d/1TJ06NiyLzThsplXdEhya51C13WE62nHN71kt997hXHw/edit#heading=h.quypt74go9w8

For example, some of the more advanced syntax like intersection types (often used for makeshift type inheritence) are both explicitly unsupported in JSDoc and flagged as invalid syntax by eslint-plugin-jsdoc (more specifically, jsdoctypeparser, related issue). Some of this is rather open-ended on whether it should be parsed correctly [1] [2], but in the meantime we'll need to decide whether to use it, and how to work around potential interoperability issues.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the context of where this is coming from. Though, if we want to merge this particular PR before the changes that need to happen to our linting/docs tooling, we need to use the JSDoc syntax at the moment and revisit later.


_Returns_

- `Element`: The new node.
- `null`: The new node.

<a name="unwrap" href="#unwrap">#</a> **unwrap**

Expand All @@ -212,18 +200,14 @@ _Parameters_

- _node_ `Node`: The node to unwrap.

_Returns_

- `void`:

<a name="wrap" href="#wrap">#</a> **wrap**

Wraps the given node with a new node with the given tag name.

_Parameters_

- _newNode_ `Element`: The node to insert.
- _referenceNode_ `Element`: The node to wrap.
- _newNode_ `Node`: The node to insert.
- _referenceNode_ `Node`: The node to wrap.


<!-- END TOKEN(Autogenerated API docs) -->
Expand Down
73 changes: 35 additions & 38 deletions packages/dom/src/dom.js
Expand Up @@ -64,9 +64,9 @@ function isSelectionForward( selection ) {
* horizontal position by default. Set `onlyVertical` to true to check only
* vertically.
*
* @param {Element} container Focusable element.
* @param {boolean} isReverse Set to true to check left, false to check right.
* @param {boolean} onlyVertical Set to true to check only vertical position.
* @param {HTMLElement} container Focusable element.
* @param {boolean} isReverse Set to true to check left, false to check right.
* @param {boolean} onlyVertical Set to true to check only vertical position.
*
* @return {boolean} True if at the edge, false if not.
*/
Expand Down Expand Up @@ -169,8 +169,8 @@ function isEdge( container, isReverse, onlyVertical ) {
/**
* Check whether the selection is horizontally at the edge of the container.
*
* @param {Element} container Focusable element.
* @param {boolean} isReverse Set to true to check left, false for right.
* @param {HTMLElement} container Focusable element.
* @param {boolean} isReverse Set to true to check left, false for right.
*
* @return {boolean} True if at the horizontal edge, false if not.
*/
Expand All @@ -181,7 +181,7 @@ export function isHorizontalEdge( container, isReverse ) {
/**
* Check whether the selection is vertically at the edge of the container.
*
* @param {Element} container Focusable element.
* @param {HTMLElement} container Focusable element.
* @param {boolean} isReverse Set to true to check top, false for bottom.
*
* @return {boolean} True if at the vertical edge, false if not.
Expand Down Expand Up @@ -255,8 +255,8 @@ export function computeCaretRect() {
/**
* Places the caret at start or end of a given element.
*
* @param {Element} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
* @param {HTMLElement|undefined} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
*/
export function placeCaretAtHorizontalEdge( container, isReverse ) {
if ( ! container ) {
Expand Down Expand Up @@ -364,10 +364,10 @@ function hiddenCaretRangeFromPoint( doc, x, y, container ) {
/**
* Places the caret at the top or bottom of a given element.
*
* @param {Element} container Focusable element.
* @param {boolean} isReverse True for bottom, false for top.
* @param {DOMRect} [rect] The rectangle to position the caret with.
* @param {boolean} [mayUseScroll=true] True to allow scrolling, false to disallow.
* @param {HTMLElement|undefined} container Focusable element.
* @param {boolean} isReverse True for bottom, false for top.
* @param {DOMRect} [rect] The rectangle to position the caret with.
* @param {boolean} [mayUseScroll=true] True to allow scrolling, false to disallow.
*/
export function placeCaretAtVerticalEdge( container, isReverse, rect, mayUseScroll = true ) {
if ( ! container ) {
Expand Down Expand Up @@ -484,7 +484,7 @@ export function documentHasSelection() {
* Check whether the contents of the element have been entirely selected.
* Returns true if there is no possibility of selection.
*
* @param {Element} element The element to check.
* @param {HTMLElement} element The element to check.
*
* @return {boolean} True if entirely selected, false if not.
*/
Expand Down Expand Up @@ -529,28 +529,28 @@ export function isEntirelySelected( element ) {
}

/**
* Given a DOM node, finds the closest scrollable container node.
* Given a DOM element, finds the closest scrollable container element.
*
* @param {Element} node Node from which to start.
* @param {Element} element Element from which to start.
*
* @return {?Element} Scrollable container node, if found.
* @return {Element|undefined} Scrollable container node, if found.
*/
export function getScrollContainer( node ) {
if ( ! node ) {
export function getScrollContainer( element ) {
Copy link
Contributor Author

@dsifford dsifford Jun 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to element since it expects an Element and not a Node

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to element since it expects an Element and not a Node

Technically Element implements the Node interface, so every element is a node (reference). But for clarity's sake, I'd agree with your assessment 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. But clientHeight and scrollHeight are only available on the Element interface so only an Element would be valid to pass into this function.

if ( ! element ) {
return;
}

// Scrollable if scrollable height exceeds displayed...
if ( node.scrollHeight > node.clientHeight ) {
if ( element.scrollHeight > element.clientHeight ) {
// ...except when overflow is defined to be hidden or visible
const { overflowY } = window.getComputedStyle( node );
const { overflowY } = window.getComputedStyle( element );
if ( /(auto|scroll)/.test( overflowY ) ) {
return node;
return element;
}
}

// Continue traversing
return getScrollContainer( node.parentNode );
return getScrollContainer( element.parentElement );
}

/**
Expand All @@ -562,7 +562,7 @@ export function getScrollContainer( node ) {
*
* @param {Node} node Node from which to find offset parent.
*
* @return {?Node} Offset parent.
* @return {Element|null} Offset parent.
*/
export function getOffsetParent( node ) {
// Cannot retrieve computed style or offset parent only anything other than
Expand Down Expand Up @@ -590,9 +590,8 @@ export function getOffsetParent( node ) {
/**
* Given two DOM nodes, replaces the former with the latter in the DOM.
*
* @param {Element} processedNode Node to be removed.
* @param {Element} newNode Node to be inserted in its place.
* @return {void}
* @param {Node} processedNode Node to be removed.
* @param {Node} newNode Node to be inserted in its place.
*/
export function replace( processedNode, newNode ) {
insertAfter( newNode, processedNode.parentNode );
Expand All @@ -602,8 +601,7 @@ export function replace( processedNode, newNode ) {
/**
* Given a DOM node, removes it from the DOM.
*
* @param {Element} node Node to be removed.
* @return {void}
* @param {Node} node Node to be removed.
*/
export function remove( node ) {
node.parentNode.removeChild( node );
Expand All @@ -613,9 +611,8 @@ export function remove( node ) {
* Given two DOM nodes, inserts the former in the DOM as the next sibling of
* the latter.
*
* @param {Element} newNode Node to be inserted.
* @param {Element} referenceNode Node after which to perform the insertion.
* @return {void}
* @param {Node} newNode Node to be inserted.
* @param {Node} referenceNode Node after which to perform the insertion.
*/
export function insertAfter( newNode, referenceNode ) {
referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling );
Expand All @@ -625,8 +622,6 @@ export function insertAfter( newNode, referenceNode ) {
* Unwrap the given node. This means any child nodes are moved to the parent.
*
* @param {Node} node The node to unwrap.
*
* @return {void}
*/
export function unwrap( node ) {
const parent = node.parentNode;
Expand All @@ -638,13 +633,15 @@ export function unwrap( node ) {
parent.removeChild( node );
}

// eslint-disable-next-line valid-jsdoc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this will need to be updated, since we no longer use valid-jsdoc but rather eslint-plugin-jsdoc (which has its own validity rule).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sorry about that. What's left to be done here? Forgot I had this PR open. (We can close this if it's too far behind)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sorry about that. What's left to be done here? Forgot I had this PR open. (We can close this if it's too far behind)

I was going to ask the same 😄 It seems in pretty good shape otherwise, it would be good to get in. This one caught my eye though. There could also be some other more-recent changes to account for. Could do for a rebase.

/**
* Replaces the given node with a new node with the given tag name.
*
* @param {Element} node The node to replace
* @param {string} tagName The new tag name.
* @template {keyof HTMLElementTagNameMap} T
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the location of where the JSDoc will improve autocompletion and catch typos.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the location of where the JSDoc will improve autocompletion and catch typos.

But it's not valid JSDoc ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not valid per eslint I guess.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the @template tag to be found? I don't see it anywhere in the standard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an extension of jsdoc that is used by the javascript/typescript language service (LSP) that is used by most editors.

You can find more on it here

* @param {Node} node The node to replace.
* @param {T} tagName The new tag name.
*
* @return {Element} The new node.
* @return {HTMLElementTagNameMap[T]} The new node.
*/
export function replaceTag( node, tagName ) {
const newNode = node.ownerDocument.createElement( tagName );
Expand All @@ -661,8 +658,8 @@ export function replaceTag( node, tagName ) {
/**
* Wraps the given node with a new node with the given tag name.
*
* @param {Element} newNode The node to insert.
* @param {Element} referenceNode The node to wrap.
* @param {Node} newNode The node to insert.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to Node because it only uses Node-based methods/properties

* @param {Node} referenceNode The node to wrap.
*/
export function wrap( newNode, referenceNode ) {
referenceNode.parentNode.insertBefore( newNode, referenceNode );
Expand Down
4 changes: 2 additions & 2 deletions packages/dom/src/focusable.js
Expand Up @@ -35,7 +35,7 @@ const SELECTOR = [
* Returns true if the specified element is visible (i.e. neither display: none
* nor visibility: hidden).
*
* @param {Element} element DOM element to test.
* @param {HTMLElement} element DOM element to test.
*
* @return {boolean} Whether element is visible.
*/
Expand Down Expand Up @@ -69,7 +69,7 @@ function isValidFocusableArea( element ) {
/**
* Returns all focusable elements within a given context.
*
* @param {Element} context Element in which to search.
* @param {ParentNode} context Element in which to search.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ParentNode isn't a valid type as far as I can tell. It would be Node I believe?

*
* @return {Element[]} Focusable elements.
*/
Expand Down