From ce7eb1436a41313d0a91d9fce94992421225f534 Mon Sep 17 00:00:00 2001 From: Dion Hulse Date: Sun, 26 Apr 2026 02:01:57 +0000 Subject: [PATCH] style: apply ESLint/Prettier auto-fixes and merge duplicate imports Runs wp-scripts lint-js --fix on the JS sources, resolving 42 of 57 lint issues (mostly Prettier formatting and missing curly braces). Also merges duplicate @wordpress/editor imports in MultiAuthorPlugin.js. Remaining errors require non-trivial structural decisions (experimental WP APIs, JSDoc types, browser globals) and are left for follow-up. Nightshift-Task: lint-fix Nightshift-Ref: https://github.com/marcus/nightshift --- src/components/MultiAuthorPlugin.js | 100 +++++++++++++++++++++------- tests/js/MultiAuthorPlugin.test.js | 84 +++++++++++++++++------ 2 files changed, 140 insertions(+), 44 deletions(-) diff --git a/src/components/MultiAuthorPlugin.js b/src/components/MultiAuthorPlugin.js index 6733abc..ab5268f 100644 --- a/src/components/MultiAuthorPlugin.js +++ b/src/components/MultiAuthorPlugin.js @@ -1,8 +1,10 @@ import { useState, useEffect, useCallback } from '@wordpress/element'; -import { PluginDocumentSettingPanel } from '@wordpress/editor'; +import { + PluginDocumentSettingPanel, + store as editorStore, +} from '@wordpress/editor'; import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; -import { store as editorStore } from '@wordpress/editor'; import { __, sprintf } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; import { @@ -22,6 +24,10 @@ const NAMESPACE = '/multi-author-posts/v1'; /** * A single co-author row. + * @param root0 + * @param root0.author + * @param root0.canManage + * @param root0.onRemove */ function AuthorCard( { author, canManage, onRemove } ) { return ( @@ -44,7 +50,10 @@ function AuthorCard( { author, canManage, onRemove } ) { onClick={ () => onRemove( author.id ) } aria-label={ /* translators: %s: author display name */ - sprintf( __( 'Remove %s', 'multi-author-posts' ), author.name ) + sprintf( + __( 'Remove %s', 'multi-author-posts' ), + author.name + ) } > { __( 'Remove', 'multi-author-posts' ) } @@ -56,6 +65,9 @@ function AuthorCard( { author, canManage, onRemove } ) { /** * User search + direct-add UI (shown only when the current user can manage co-authors). + * @param root0 + * @param root0.postId + * @param root0.onAdd */ function DirectAdd( { postId, onAdd } ) { const [ search, setSearch ] = useState( '' ); @@ -71,7 +83,9 @@ function DirectAdd( { postId, onAdd } ) { setIsSearching( true ); const controller = new AbortController(); apiFetch( { - path: `${ NAMESPACE }/posts/${ postId }/suggested-authors?search=${ encodeURIComponent( search ) }`, + path: `${ NAMESPACE }/posts/${ postId }/suggested-authors?search=${ encodeURIComponent( + search + ) }`, signal: controller.signal, } ) .then( ( data ) => { @@ -104,7 +118,10 @@ function DirectAdd( { postId, onAdd } ) { label={ __( 'Add existing author', 'multi-author-posts' ) } value={ search } onChange={ setSearch } - placeholder={ __( 'Search by name or email…', 'multi-author-posts' ) } + placeholder={ __( + 'Search by name or email…', + 'multi-author-posts' + ) } /> { isSearching && } { suggestions.length > 0 && ( @@ -119,7 +136,12 @@ function DirectAdd( { postId, onAdd } ) { width={ 28 } height={ 28 } /> - + + + { isActive && ( - ) } @@ -263,13 +309,14 @@ export default function MultiAuthorPlugin() { // Post author and any existing co-author share the same management trust. // The REST API enforces the same rule server-side. const canManage = - !! currentUserId && ( - currentUserId === postAuthorId || - coAuthors.some( ( a ) => a.id === currentUserId ) - ); + !! currentUserId && + ( currentUserId === postAuthorId || + coAuthors.some( ( a ) => a.id === currentUserId ) ); useEffect( () => { - if ( ! postId ) return; + if ( ! postId ) { + return; + } setIsLoading( true ); apiFetch( { path: `${ NAMESPACE }/posts/${ postId }/co-authors` } ) .then( ( data ) => { @@ -299,14 +346,19 @@ export default function MultiAuthorPlugin() { .catch( ( err ) => setError( err?.message ?? - __( 'Could not remove co-author.', 'multi-author-posts' ) + __( + 'Could not remove co-author.', + 'multi-author-posts' + ) ) ); }, [ postId ] ); - if ( ! postId ) return null; + if ( ! postId ) { + return null; + } return ( selector( ( storeName ) => { const map = { @@ -76,20 +83,26 @@ describe( 'MultiAuthorPlugin', () => { it( 'renders the Co-Authors panel heading', async () => { render( ); await waitFor( () => - expect( screen.getByRole( 'heading', { name: /co-authors/i } ) ).toBeInTheDocument() + expect( + screen.getByRole( 'heading', { name: /co-authors/i } ) + ).toBeInTheDocument() ); } ); it( 'shows "No co-authors yet" when the list is empty', async () => { render( ); await waitFor( () => - expect( screen.getByText( /no co-authors yet/i ) ).toBeInTheDocument() + expect( + screen.getByText( /no co-authors yet/i ) + ).toBeInTheDocument() ); } ); it( 'renders co-author names after loading', async () => { apiFetch.mockImplementation( ( { path } ) => { - if ( path.includes( '/invite' ) ) return Promise.resolve( { active: false } ); + if ( path.includes( '/invite' ) ) { + return Promise.resolve( { active: false } ); + } return Promise.resolve( [ CO_AUTHOR ] ); } ); @@ -111,7 +124,11 @@ describe( 'MultiAuthorPlugin', () => { it( 'shows "active" state with Regenerate / Revoke when invite exists', async () => { apiFetch.mockImplementation( ( { path } ) => { if ( path.includes( '/invite' ) ) { - return Promise.resolve( { active: true, created: 1000, expires: 2000 } ); + return Promise.resolve( { + active: true, + created: 1000, + expires: 2000, + } ); } return Promise.resolve( [] ); } ); @@ -119,16 +136,22 @@ describe( 'MultiAuthorPlugin', () => { render( ); await waitFor( () => expect( - screen.getByRole( 'button', { name: /regenerate invite link/i } ) + screen.getByRole( 'button', { + name: /regenerate invite link/i, + } ) ).toBeInTheDocument() ); - expect( screen.getByRole( 'button', { name: /revoke/i } ) ).toBeInTheDocument(); + expect( + screen.getByRole( 'button', { name: /revoke/i } ) + ).toBeInTheDocument(); } ); it( 'reveals the plaintext URL exactly once, after generate', async () => { apiFetch.mockImplementation( ( { path, method } ) => { if ( path.includes( '/invite' ) && method === 'POST' ) { - return Promise.resolve( { invite_url: 'http://example.com/?map_invite=plain' } ); + return Promise.resolve( { + invite_url: 'http://example.com/?map_invite=plain', + } ); } if ( path.includes( '/invite' ) ) { return Promise.resolve( { active: false } ); @@ -146,7 +169,9 @@ describe( 'MultiAuthorPlugin', () => { ); await act( async () => { - await user.click( screen.getByRole( 'button', { name: /generate invite link/i } ) ); + await user.click( + screen.getByRole( 'button', { name: /generate invite link/i } ) + ); } ); expect( @@ -160,19 +185,30 @@ describe( 'MultiAuthorPlugin', () => { render( ); await waitFor( () => // Co-authors list loads - expect( screen.queryByText( /no co-authors yet/i ) ).toBeInTheDocument() + expect( + screen.queryByText( /no co-authors yet/i ) + ).toBeInTheDocument() ); - expect( screen.queryByRole( 'button', { name: /generate invite link/i } ) ).toBeNull(); + expect( + screen.queryByRole( 'button', { name: /generate invite link/i } ) + ).toBeNull(); expect( screen.queryByRole( 'searchbox' ) ).toBeNull(); } ); it( 'shows management controls to a co-author of the post', async () => { const CO_AUTHOR_ID = 99; - setupUseSelect( { currentUserId: CO_AUTHOR_ID, postAuthorId: AUTHOR_ID } ); + setupUseSelect( { + currentUserId: CO_AUTHOR_ID, + postAuthorId: AUTHOR_ID, + } ); apiFetch.mockImplementation( ( { path } ) => { - if ( path.includes( '/invite' ) ) return Promise.resolve( { active: false } ); - return Promise.resolve( [ { id: CO_AUTHOR_ID, name: 'Me', avatar: 'x' } ] ); + if ( path.includes( '/invite' ) ) { + return Promise.resolve( { active: false } ); + } + return Promise.resolve( [ + { id: CO_AUTHOR_ID, name: 'Me', avatar: 'x' }, + ] ); } ); render( ); @@ -186,8 +222,12 @@ describe( 'MultiAuthorPlugin', () => { it( 'calls DELETE when Remove button is clicked', async () => { apiFetch.mockImplementation( ( { path, method } ) => { - if ( method === 'DELETE' ) return Promise.resolve( {} ); - if ( path.includes( '/invite' ) ) return Promise.resolve( { active: false } ); + if ( method === 'DELETE' ) { + return Promise.resolve( {} ); + } + if ( path.includes( '/invite' ) ) { + return Promise.resolve( { active: false } ); + } return Promise.resolve( [ CO_AUTHOR ] ); } ); @@ -199,13 +239,17 @@ describe( 'MultiAuthorPlugin', () => { ); await act( async () => { - await user.click( screen.getByRole( 'button', { name: /remove jane doe/i } ) ); + await user.click( + screen.getByRole( 'button', { name: /remove jane doe/i } ) + ); } ); expect( apiFetch ).toHaveBeenCalledWith( expect.objectContaining( { method: 'DELETE', - path: expect.stringContaining( `/co-authors/${ CO_AUTHOR.id }` ), + path: expect.stringContaining( + `/co-authors/${ CO_AUTHOR.id }` + ), } ) ); } );