From 84fcd740595fec653384f2c05fd8079695bd2bb8 Mon Sep 17 00:00:00 2001 From: Hamza Date: Tue, 12 May 2026 16:16:30 +0200 Subject: [PATCH 1/5] chore(lint): fix JSDoc warnings in services and utils Add missing @param descriptions, fix mismatched param names, and remove disallowed `any` type tag in JSDoc for circles, validate, addressbookUtils, and matchTypes. AI-assisted: Claude Code (Claude Opus 4.7) Signed-off-by: Hamza --- src/services/circles.d.ts | 7 +++---- src/services/circles.ts | 9 ++++----- src/services/validate.js | 5 ++++- src/utils/addressbookUtils.js | 6 ++++-- src/utils/matchTypes.d.ts | 4 ++-- src/utils/matchTypes.ts | 4 ++-- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/services/circles.d.ts b/src/services/circles.d.ts index c8a8859736..0f789dcc37 100644 --- a/src/services/circles.d.ts +++ b/src/services/circles.d.ts @@ -35,8 +35,8 @@ export declare const getCircle: (circleId: string) => Promise * Create a new circle * * @param {string} name the circle name - * @param personal - * @param local + * @param {boolean} personal whether the circle is personal + * @param {boolean} local whether the circle is local * @return {object} */ export declare const createCircle: (name: string, personal: boolean, local: boolean) => Promise @@ -52,8 +52,7 @@ export declare const deleteCircle: (circleId: string) => Promise * * @param {string} circleId the circle id * @param {CircleEditType} type the edit type - * @param {any} data the data - * @param value + * @param value the new value * @return {object} */ export declare const editCircle: (circleId: string, type: CircleEditType, value: any) => Promise diff --git a/src/services/circles.ts b/src/services/circles.ts index d833200f51..07f4e9e8f8 100644 --- a/src/services/circles.ts +++ b/src/services/circles.ts @@ -39,7 +39,7 @@ export async function getCircles() { /** * Get a specific circle * - * @param circleId + * @param circleId the circle id * @return */ export async function getCircle(circleId: string) { @@ -51,8 +51,8 @@ export async function getCircle(circleId: string) { * Create a new circle * * @param name the circle name - * @param personal - * @param local + * @param personal whether the circle is personal + * @param local whether the circle is local * @return */ export async function createCircle(name: string, personal: boolean, local: boolean) { @@ -80,8 +80,7 @@ export async function deleteCircle(circleId: string) { * * @param circleId the circle id * @param type the edit type - * @param data the data - * @param value + * @param value the new value * @return */ export async function editCircle(circleId: string, type: CircleEditType, value: any) { diff --git a/src/services/validate.js b/src/services/validate.js index c6f0d22023..44c8cbdf66 100644 --- a/src/services/validate.js +++ b/src/services/validate.js @@ -7,7 +7,10 @@ import Contact from '../models/contact.js' import checks from './checks/index.js' /** - * @param contact + * Run all repair checks on a contact and apply fixes when needed. + * + * @param {Contact} contact the contact to validate + * @return {boolean} true if a non-silent fix was applied */ export default function(contact) { let result = false diff --git a/src/utils/addressbookUtils.js b/src/utils/addressbookUtils.js index dd9a193ef2..c0f4f88c51 100644 --- a/src/utils/addressbookUtils.js +++ b/src/utils/addressbookUtils.js @@ -12,7 +12,7 @@ import usePrincipalsStore from '../store/principals.js' * * Withing each group, addressbooks are sorted by the number of contacts, from highest to lowest * - * @param {Array} addressbooks + * @param {Array} addressbooks the addressbooks to sort * @return {Array} */ export function sortAddressbooks(addressbooks) { @@ -43,8 +43,10 @@ export function sortAddressbooks(addressbooks) { } /** + * Return the priority group of an addressbook. * - * @param ab + * @param {object} ab the addressbook + * @return {number} the priority group (lower is higher priority) */ function getPriorityGroup(ab) { const principalsStore = usePrincipalsStore() diff --git a/src/utils/matchTypes.d.ts b/src/utils/matchTypes.d.ts index 90de6f571b..b1de3df299 100644 --- a/src/utils/matchTypes.d.ts +++ b/src/utils/matchTypes.d.ts @@ -5,8 +5,8 @@ /** * Match a list of types against the available types * - * @param selectedTypes - * @param options + * @param selectedTypes the selected types + * @param options the available type options */ export declare function matchTypes(selectedTypes: Array, options: Array<{ id: string diff --git a/src/utils/matchTypes.ts b/src/utils/matchTypes.ts index d5f3e862be..0fe7816e6a 100644 --- a/src/utils/matchTypes.ts +++ b/src/utils/matchTypes.ts @@ -6,8 +6,8 @@ /** * Match a list of types against the available types * - * @param selectedTypes - * @param options + * @param selectedTypes the selected types + * @param options the available type options */ export function matchTypes(selectedTypes: Array, options: Array<{ id: string, name: string }>) { const items = options.map((option) => { From 9f48787b514ce7479e1a1c3aa627b5fcdb7138c5 Mon Sep 17 00:00:00 2001 From: Hamza Date: Tue, 12 May 2026 16:20:12 +0200 Subject: [PATCH 2/5] chore(lint): fix JSDoc warnings in store, models, and components Add missing @param descriptions/types, drop spurious destructuring root entries (data.addressbook.x, root0) in favor of a single destructuring parent, and escape the inline @mentions reference in CircleDetails. AI-assisted: Claude Code (Claude Opus 4.7) Signed-off-by: Hamza --- .../AppNavigation/GroupNavigationItem.vue | 2 +- src/components/CircleDetails.vue | 4 +-- src/models/circle.ts | 8 +++--- src/models/member.ts | 4 +-- src/store/addressbooks.js | 27 +++++-------------- src/store/circles.js | 5 ++-- src/store/contacts.js | 14 ++++------ 7 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/components/AppNavigation/GroupNavigationItem.vue b/src/components/AppNavigation/GroupNavigationItem.vue index 162728691b..334190b1d2 100644 --- a/src/components/AppNavigation/GroupNavigationItem.vue +++ b/src/components/AppNavigation/GroupNavigationItem.vue @@ -249,7 +249,7 @@ export default { * Open mailto: for contacts in a group * * @param {object} group of contacts to be emailed - * @param {string} mode + * @param {string} mode the recipient header to use (to, cc, bcc) */ emailGroup(group, mode = 'to') { const emails = [] diff --git a/src/components/CircleDetails.vue b/src/components/CircleDetails.vue index fc551aaed3..050605fb2d 100644 --- a/src/components/CircleDetails.vue +++ b/src/components/CircleDetails.vue @@ -680,10 +680,10 @@ export default { }, /** - * Autocomplete @mentions on the description + * Autocomplete `@mentions` on the description * * @param {string} search the search term - * @param {Function} callback callback to be called with results array + * @param {(results: object[]) => void} callback callback to be called with results array */ onAutocomplete(search, callback) { // TODO: implement autocompletion. Disabled for now diff --git a/src/models/circle.ts b/src/models/circle.ts index a3c24ba0ec..45db478b3e 100644 --- a/src/models/circle.ts +++ b/src/models/circle.ts @@ -17,7 +17,7 @@ export default class Circle { /** * Creates an instance of Circle * - * @param data + * @param data the raw circle data */ constructor(data: object) { this.updateData(data) @@ -26,7 +26,7 @@ export default class Circle { /** * Update inner circle data, owner and initiator * - * @param data + * @param data the raw circle data */ updateData(data: any) { if (typeof data !== 'object') { @@ -158,7 +158,7 @@ export default class Circle { /** * Add a member to this circle * - * @param member + * @param member the member to add */ addMember(member: Member) { if (member.constructor.name !== Member.name) { @@ -175,7 +175,7 @@ export default class Circle { /** * Remove a member from this circle * - * @param member + * @param member the member to remove */ deleteMember(member: Member) { if (member.constructor.name !== Member.name) { diff --git a/src/models/member.ts b/src/models/member.ts index f7f427df88..f7c3dc87ba 100644 --- a/src/models/member.ts +++ b/src/models/member.ts @@ -16,8 +16,8 @@ export default class Member { /** * Creates an instance of Member * - * @param data - * @param circle + * @param data the raw member data + * @param circle the circle this member belongs to */ constructor(data: any, circle: Circle) { if (typeof data !== 'object') { diff --git a/src/store/addressbooks.js b/src/store/addressbooks.js index f9600ca083..977934a240 100644 --- a/src/store/addressbooks.js +++ b/src/store/addressbooks.js @@ -228,7 +228,7 @@ const mutations = { /** * Needed to track indirect state changes for addressbook sorting * - * @param state + * @param {object} state the store state */ resortAddressbooks(state) { state.addressbooks = sortAddressbooks(state.addressbooks) @@ -348,13 +348,9 @@ const actions = { * Rename a Addressbook * * @param {object} context the store mutations Current context + * @param {object} data destructuring object * @param {object} data.addressbook the addressbook to rename * @param {string} data.newName the new name of the addressbook - * @param data.addressbook.addressbook - * @param data.addressbook.newName - * @param root0 - * @param root0.addressbook - * @param root0.newName * @return {Promise} */ async renameAddressbook(context, { addressbook, newName }) { @@ -371,7 +367,7 @@ const actions = { * * @param {object} context the store mutations * @param {object} importDetails = { vcf, addressbook } - * @param importDetails.addressbook + * @param {object} importDetails.addressbook the addressbook * @return {Promise} */ async getContactsFromAddressBook(context, { addressbook }) { @@ -426,11 +422,12 @@ const actions = { }, /** + * Import contacts into an addressbook * * @param {object} context the store mutations * @param {object} importDetails = { vcf, addressbook } - * @param importDetails.vcf - * @param importDetails.addressbook + * @param {string} importDetails.vcf the vcf data + * @param {object} importDetails.addressbook the target addressbook */ async importContactsIntoAddressbook(context, { vcf, addressbook }) { const contacts = parseVcf(vcf, addressbook) @@ -515,22 +512,12 @@ const actions = { * Share Adressbook with User or Group * * @param {object} context the store mutations Current context + * @param {object} data destructuring object * @param {object} data.addressbook the addressbook * @param {string} data.user the userId * @param {string} data.displayName the displayName * @param {string} data.uri the sharing principalScheme uri * @param {boolean} data.isGroup is this a group ? - * @param data.addressbook.addressbook - * @param data.addressbook.user - * @param data.addressbook.displayName - * @param data.addressbook.uri - * @param data.addressbook.isGroup - * @param root0 - * @param root0.addressbook - * @param root0.user - * @param root0.displayName - * @param root0.uri - * @param root0.isGroup */ async shareAddressbook(context, { addressbook, user, displayName, uri, isGroup }) { // Share addressbook with entered group or user diff --git a/src/store/circles.js b/src/store/circles.js index 0fefd16583..f04aa6807b 100644 --- a/src/store/circles.js +++ b/src/store/circles.js @@ -258,8 +258,9 @@ const actions = { * Delete a member from a circle * * @param {object} context the store mutations Current context - * @param {Member} member the member to remove - * @param {boolean} [leave] leave the circle instead of removing the member + * @param {object} data destructuring object + * @param {Member} data.member the member to remove + * @param {boolean} [data.leave] leave the circle instead of removing the member */ async deleteMemberFromCircle(context, { member, leave = false }) { const circleId = member.circle.id diff --git a/src/store/contacts.js b/src/store/contacts.js index 26fc8597a2..9e9e56b7d3 100644 --- a/src/store/contacts.js +++ b/src/store/contacts.js @@ -224,10 +224,8 @@ const mutations = { * * @param {object} state the store data * @param {object} data destructuring object - * @param data.contact - * @param {Contact} contact the contact to update - * @param {object} addressbook the addressbook to set - * @param data.addressbook + * @param {Contact} data.contact the contact to update + * @param {object} data.addressbook the addressbook to set */ updateContactAddressbook(state, { contact, addressbook }) { if (state.contacts[contact.key] && contact instanceof Contact) { @@ -260,10 +258,8 @@ const mutations = { * * @param {object} state the store data * @param {object} data destructuring object - * @param data.contact - * @param {Contact} contact the contact to update - * @param {string} etag the contact etag - * @param data.etag + * @param {Contact} data.contact the contact to update + * @param {string} data.etag the contact etag */ updateContactEtag(state, { contact, etag }) { if (state.contacts[contact.key] && contact instanceof Contact) { @@ -466,7 +462,7 @@ const actions = { * @param {object} data destructuring object * @param {Contact} data.contact the contact to fetch * @param {string} data.etag the contact etag to override in case of conflict - * @param data.forceReFetch + * @param {boolean} data.forceReFetch force re-fetching the contact data * @return {Promise} */ async fetchFullContact(context, { contact, etag = '', forceReFetch = false }) { From c737a3556deb330b0c92c14ec67a26197e995aa2 Mon Sep 17 00:00:00 2001 From: Hamza Date: Tue, 12 May 2026 16:27:42 +0200 Subject: [PATCH 3/5] chore(lint): add explicit emits declarations Declare emitted events on components that emit without listing them in the emits option, silencing vue/require-explicit-emits. AI-assisted: Claude Code (Claude Opus 4.7) Signed-off-by: Hamza --- src/components/AppContent/ContactsContent.vue | 2 ++ src/components/AppNavigation/ContactsSettings.vue | 2 ++ src/components/AppNavigation/GroupNavigationItem.vue | 2 ++ src/components/ContactDetails/ContactDetailsAvatar.vue | 2 ++ src/components/ContactsList/Merging.vue | 2 ++ src/components/EntityPicker/EntityBubble.vue | 2 ++ src/components/EntityPicker/EntityPicker.vue | 2 ++ src/components/EntityPicker/NewCircleIntro.vue | 2 ++ src/components/Properties/PropertyActions.vue | 2 ++ src/components/Properties/PropertyDateTime.vue | 2 ++ src/components/Properties/PropertyGroups.vue | 2 ++ src/views/Processing/AddToGroupView.vue | 2 ++ src/views/Processing/ImportView.vue | 2 ++ 13 files changed, 26 insertions(+) diff --git a/src/components/AppContent/ContactsContent.vue b/src/components/AppContent/ContactsContent.vue index ea7788e347..8c43578c39 100644 --- a/src/components/AppContent/ContactsContent.vue +++ b/src/components/AppContent/ContactsContent.vue @@ -97,6 +97,8 @@ export default { }, }, + emits: ['new-contact'], + data() { return { searchQuery: '', diff --git a/src/components/AppNavigation/ContactsSettings.vue b/src/components/AppNavigation/ContactsSettings.vue index 5e2099613f..c1186de1c9 100644 --- a/src/components/AppNavigation/ContactsSettings.vue +++ b/src/components/AppNavigation/ContactsSettings.vue @@ -74,6 +74,8 @@ export default { }, }, + emits: ['update:open', 'clicked', 'file-loaded'], + data() { return { allowSocialSync: loadState('contacts', 'allowSocialSync') !== 'no', diff --git a/src/components/AppNavigation/GroupNavigationItem.vue b/src/components/AppNavigation/GroupNavigationItem.vue index 334190b1d2..219c16e0b4 100644 --- a/src/components/AppNavigation/GroupNavigationItem.vue +++ b/src/components/AppNavigation/GroupNavigationItem.vue @@ -130,6 +130,8 @@ export default { }, }, + emits: ['updateRouteState'], + data() { return { newGroupName: '', diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue index 6a3725383b..84905f3bb4 100644 --- a/src/components/ContactDetails/ContactDetailsAvatar.vue +++ b/src/components/ContactDetails/ContactDetailsAvatar.vue @@ -173,6 +173,8 @@ export default { }, }, + emits: ['update-local-contact'], + data() { return { opened: false, diff --git a/src/components/ContactsList/Merging.vue b/src/components/ContactsList/Merging.vue index 8d2a75aaef..c7cbfe579e 100644 --- a/src/components/ContactsList/Merging.vue +++ b/src/components/ContactsList/Merging.vue @@ -193,6 +193,8 @@ export default { }, }, + emits: ['finished'], + data() { return { bus: mitt(), diff --git a/src/components/EntityPicker/EntityBubble.vue b/src/components/EntityPicker/EntityBubble.vue index 4253ad2325..5d95cb3b98 100644 --- a/src/components/EntityPicker/EntityBubble.vue +++ b/src/components/EntityPicker/EntityBubble.vue @@ -72,6 +72,8 @@ export default { }, }, + emits: ['delete'], + setup() { return { ShareType, diff --git a/src/components/EntityPicker/EntityPicker.vue b/src/components/EntityPicker/EntityPicker.vue index 6b3d745e00..94c9c82f88 100644 --- a/src/components/EntityPicker/EntityPicker.vue +++ b/src/components/EntityPicker/EntityPicker.vue @@ -223,6 +223,8 @@ export default { }, }, + emits: ['update:selection', 'close', 'submit', 'search'], + data() { return { canInviteGuests: !!window?.OCA?.Guests?.openGuestDialog, diff --git a/src/components/EntityPicker/NewCircleIntro.vue b/src/components/EntityPicker/NewCircleIntro.vue index 6bd9cbc0c8..7e88d814c4 100644 --- a/src/components/EntityPicker/NewCircleIntro.vue +++ b/src/components/EntityPicker/NewCircleIntro.vue @@ -90,6 +90,8 @@ export default { }, }, + emits: ['close', 'submit'], + data() { return { circleName: '', diff --git a/src/components/Properties/PropertyActions.vue b/src/components/Properties/PropertyActions.vue index a80772c99b..2ce4000629 100644 --- a/src/components/Properties/PropertyActions.vue +++ b/src/components/Properties/PropertyActions.vue @@ -47,6 +47,8 @@ export default { }, }, + emits: ['delete'], + methods: { deleteProperty() { this.$emit('delete') diff --git a/src/components/Properties/PropertyDateTime.vue b/src/components/Properties/PropertyDateTime.vue index 0c4890cf47..00bdfc9df2 100644 --- a/src/components/Properties/PropertyDateTime.vue +++ b/src/components/Properties/PropertyDateTime.vue @@ -107,6 +107,8 @@ export default { }, }, + emits: ['update:value'], + data() { return { // input type following DatePicker docs diff --git a/src/components/Properties/PropertyGroups.vue b/src/components/Properties/PropertyGroups.vue index a7228bf213..e02696e4c0 100644 --- a/src/components/Properties/PropertyGroups.vue +++ b/src/components/Properties/PropertyGroups.vue @@ -95,6 +95,8 @@ export default { }, }, + emits: ['update:value'], + data() { return { localValue: [...this.value].sort(), diff --git a/src/views/Processing/AddToGroupView.vue b/src/views/Processing/AddToGroupView.vue index 58c9a9ce35..853294c990 100644 --- a/src/views/Processing/AddToGroupView.vue +++ b/src/views/Processing/AddToGroupView.vue @@ -58,6 +58,8 @@ export default { }, }, + emits: ['close'], + computed: { progressHeader() { return n( diff --git a/src/views/Processing/ImportView.vue b/src/views/Processing/ImportView.vue index b74f1f1052..8d3a3f2623 100644 --- a/src/views/Processing/ImportView.vue +++ b/src/views/Processing/ImportView.vue @@ -31,6 +31,8 @@ export default { NcButton, }, + emits: ['close'], + computed: { importState() { return this.$store.getters.getImportState From ef575051ce271fd7cc5873d233d6536b9f3f4bc9 Mon Sep 17 00:00:00 2001 From: Hamza Date: Tue, 12 May 2026 16:46:14 +0200 Subject: [PATCH 4/5] chore(lint): remove unused refs and props Drop template refs and props that were declared but never accessed. Cascading cleanups: drop the dead onAvatarClick handler in OrgChart and its now-unused 'that' alias, drop ContactDetailsProperty's contacts and ContactDetails' contacts pass-through, and remove the never-passed desc prop on ReadOnlyContactDetails. For PropertySelect/PropertyText, the value prop is consumed via PropertyMixin so the rule is suppressed with a targeted disable comment. AI-assisted: Claude Code (Claude Opus 4.7) Signed-off-by: Hamza --- src/components/AppContent/ContactsContent.vue | 2 +- .../AppNavigation/Settings/SettingsImportContacts.vue | 1 - src/components/ChartTemplate.vue | 5 ----- src/components/ContactDetails.vue | 9 --------- src/components/ContactDetails/ContactDetailsProperty.vue | 5 ----- src/components/DetailsHeader.vue | 1 - src/components/EntityPicker/EntityPicker.vue | 8 -------- src/components/OrgChart.vue | 3 --- src/components/Properties/PropertyGroups.vue | 6 ------ src/components/Properties/PropertySelect.vue | 1 + src/components/Properties/PropertyText.vue | 1 + src/views/ReadOnlyContactDetails.vue | 6 ------ 12 files changed, 3 insertions(+), 45 deletions(-) diff --git a/src/components/AppContent/ContactsContent.vue b/src/components/AppContent/ContactsContent.vue index 8c43578c39..e8f71906d2 100644 --- a/src/components/AppContent/ContactsContent.vue +++ b/src/components/AppContent/ContactsContent.vue @@ -52,7 +52,7 @@ - + diff --git a/src/components/AppNavigation/Settings/SettingsImportContacts.vue b/src/components/AppNavigation/Settings/SettingsImportContacts.vue index fd6f440d46..fa9c420de7 100644 --- a/src/components/AppNavigation/Settings/SettingsImportContacts.vue +++ b/src/components/AppNavigation/Settings/SettingsImportContacts.vue @@ -14,7 +14,6 @@ diff --git a/src/components/ChartTemplate.vue b/src/components/ChartTemplate.vue index 08d8d719ae..37c10aeeb7 100644 --- a/src/components/ChartTemplate.vue +++ b/src/components/ChartTemplate.vue @@ -56,11 +56,6 @@ export default { type: Object, default: () => {}, }, - - onAvatarClick: { - type: Function, - default: () => {}, - }, }, computed: { diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue index f246c957e5..9db0840dd2 100644 --- a/src/components/ContactDetails.vue +++ b/src/components/ContactDetails.vue @@ -200,7 +200,6 @@