diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 73bc3ab31..0f089bceb 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -38,6 +38,7 @@ Use `.github/prompts/*.prompt.md` for guided workflows: - Avoid risky renames or moves of core stack paths used by downstream merges - Keep changes minimal and merge-friendly for downstream projects - Flag security or mergeability risks explicitly in reviews +- Every new or modified function must have a JSDoc header: one-line description, `@param` for each argument, `@returns` for any non-void return value (always include `@returns` for async functions to document the resolved value) ## Architecture and modularity diff --git a/CLAUDE.md b/CLAUDE.md index e42a27b0a..e369a58cd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,6 +51,7 @@ The `.claude/` folder contains embedded settings, skills, and agents that are av - Avoid risky renames or moves of core stack paths used by downstream merges - Keep changes minimal and merge-friendly for downstream projects - Flag security or mergeability risks explicitly in reviews +- Every new or modified function must have a JSDoc header: one-line description, `@param` for each argument, `@returns` for any non-void return value (always include `@returns` for async functions to document the resolved value) ## Available embedded skills diff --git a/ERRORS.md b/ERRORS.md index feb2e64e1..076086975 100644 --- a/ERRORS.md +++ b/ERRORS.md @@ -12,3 +12,5 @@ Use this file as a compact memory of recurring AI mistakes. ## Entries - [2026-02-19] Vuetify 3 typography: computed/CSS media-query responsive headings -> use Vuetify responsive classes (example: `text-h5 text-sm-h4`) +- [2026-02-22] functions: new or modified functions without JSDoc header -> always add JSDoc (description + `@param` for each arg + `@returns` for non-void return values and all async functions) +- [2026-02-22] tests: never patch code to pass a test -> if a test is wrong, fix the test; if logic needs refactoring, refactor it diff --git a/src/lib/helpers/tests/theme.spec.js b/src/lib/helpers/tests/theme.spec.js index eb9b5ddc1..4e6da12e6 100644 --- a/src/lib/helpers/tests/theme.spec.js +++ b/src/lib/helpers/tests/theme.spec.js @@ -8,20 +8,18 @@ describe('Theme Helpers', () => { delete window.matchMedia; }); - it('should return true when theme is explicitly true', () => { - expect(isDark(true)).toBe(true); + it('should return true when theme is dark', () => { + expect(isDark('dark')).toBe(true); }); - it('should return false when theme is explicitly false', () => { - expect(isDark(false)).toBe(false); + it('should return false when theme is light', () => { + expect(isDark('light')).toBe(false); }); - it('should return false when theme is undefined', () => { + it('should return false for unknown or missing theme (light by default)', () => { expect(isDark(undefined)).toBe(false); - }); - - it('should return false when theme is null', () => { expect(isDark(null)).toBe(false); + expect(isDark('')).toBe(false); }); it('should detect auto dark mode from system preferences (dark)', () => { diff --git a/src/lib/helpers/theme.js b/src/lib/helpers/theme.js index 4031a0ac9..4489477b1 100644 --- a/src/lib/helpers/theme.js +++ b/src/lib/helpers/theme.js @@ -1,19 +1,20 @@ /** * @desc Function to return actual theme - * @param {String} option in config - * @return {Boolean} dark value + * @param {String} theme - Theme option from config ('dark', 'light', or 'auto') + * @returns {Boolean} true if dark mode is active, false otherwise */ export const isDark = (theme) => { if (theme === 'auto') { return !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); } - return !!theme; + return theme === 'dark'; }; /** * @desc Function to return custom css object - * @param {String} String, section, card, video - * @return {Object} object in config { background: ... } + * @param {String} kind - Style section key (e.g. 'section', 'card', 'video') + * @param {Object} object - Config object containing the style definitions + * @returns {Object} object in config { background: ... } */ export const style = (kind, object) => { const style = {}; @@ -41,7 +42,7 @@ export const style = (kind, object) => { /** * @desc Helper to convert hex color to RGB string * @param {String} hex - Hex color (e.g. #RRGGBB) - * @return {String} RGB string (e.g. "255,255,255") + * @returns {String} RGB string (e.g. "255,255,255") */ const hexToRgb = (hex) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); @@ -53,7 +54,7 @@ const hexToRgb = (hex) => { * @param {String} hex - Hex color (e.g. #RRGGBB) * @param {Number} amount - Amount to adjust (-1 to 1, or 0-100 for legacy percent mode) * @param {String} output - 'rgb' for RGB string, 'hex' for hex string. Default: 'rgb' - * @return {String} RGB string (e.g. "255,255,255") or hex string (e.g. "#ffffff") + * @returns {String} RGB string (e.g. "255,255,255") or hex string (e.g. "#ffffff") */ const adjustColor = (hex, amount, output = 'rgb') => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); @@ -97,7 +98,7 @@ const adjustColor = (hex, amount, output = 'rgb') => { * @param {String} options.border - 'all', 'bottom', 'top', or 'none'. Default: 'all' * @param {Boolean|String} options.glowBorder - false, true (static gradient), or 'animated' (rotating). Default: false * @param {Object} options.extras - Additional CSS properties to merge - * @return {Object} CSS style object with liquid glass effect + * @returns {Object} CSS style object with liquid glass effect */ export const liquidGlassStyle = ({ vuetifyTheme, @@ -208,7 +209,7 @@ export const liquidGlassStyle = ({ * @desc Generate overlap style for container (slides up into previous section) * @param {Boolean|String|Object} overlap - true (defaults), string ('30vh'), or { mobile: '20vh', desktop: '40vh' } * @param {Object} display - Vuetify display object ($vuetify.display) - * @return {Object} Style object with margin-top, position and z-index + * @returns {Object} Style object with margin-top, position and z-index */ export const overlapStyle = (overlap, display) => { if (!overlap) return {}; @@ -235,7 +236,7 @@ export const overlapStyle = (overlap, display) => { * @desc Helper to lighten a hex color * @param {String} hex - Hex color (e.g. #RRGGBB) * @param {Number} percent - Percentage to lighten (0-100) - * @return {String} Hex color string + * @returns {String} Hex color string */ export const lightenColor = (hex, percent) => adjustColor(hex, percent, 'hex'); diff --git a/src/lib/helpers/tools.js b/src/lib/helpers/tools.js index db78b4463..9ea4beb6d 100644 --- a/src/lib/helpers/tools.js +++ b/src/lib/helpers/tools.js @@ -4,8 +4,8 @@ /** * @desc Function to evaluate numbers of release from last release - * @param {String} 2.3.4 - * @return {String} 23 + * @param {String} release - Version string (e.g. '2.3.4' or 'v2.3.4') + * @returns {Array} Array of version number parts */ export const releasesNumber = (release) => { const numbers = release[0] === 'v' ? release.substr(1).split('.') : release.split('.'); // get numbers last release @@ -19,7 +19,7 @@ export const releasesNumber = (release) => { * @param {Int} page * @param {Int} perPage * @param {String} search - * @return {String} server-items-length + * @returns {String} Pagination request string */ export const pageRequest = (page, perPage, search) => { let request = `${page - 1}&${perPage}`; @@ -29,9 +29,9 @@ export const pageRequest = (page, perPage, search) => { /** * @desc Function get a dynamic total count from dataTable - * @param {Array} array of items - * @param {Object} Object options from vuetify dataTable - * @return {String} server-items-length + * @param {Array} items - Array of items from the current page + * @param {Object} options - Options object from Vuetify dataTable + * @returns {number} server items length */ export const serverItemsLength = (items, options) => items.length === options.itemsPerPage ? options.page * options.itemsPerPage + options.itemsPerPage : options.page * options.itemsPerPage; diff --git a/src/lib/middlewares/model.js b/src/lib/middlewares/model.js index 1b9318d33..c68cb6ecf 100644 --- a/src/lib/middlewares/model.js +++ b/src/lib/middlewares/model.js @@ -4,10 +4,10 @@ import _ from 'lodash'; /** - * @desc Function to clean object (pick from model, remove null / undefined) - * @param {Object} data - * @param {[String]} model - * @return {Object} result + * @desc Function to clean object (pick from model, remove null values) + * @param {Object} data - Source object to clean + * @param {Array} model - Array of keys to pick from data + * @returns {Object} Cleaned object with only model keys and non-null values */ const clean = (data, model) => _.omitBy(_.pick(data, model), _.isNull);