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

Various JSDoc + type checking fixes (for v4.4.0 only) #2997

Merged
merged 6 commits into from
Nov 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions jsdoc.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ module.exports = {
source: {
includePattern: '.+\\.m?js$',
excludePattern: '.+\\.test.m?js$'
},
templates: {
cleverLinks: true
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've not used @see or @link yet to other areas of the code but we're ready for it now

}
}
20 changes: 13 additions & 7 deletions src/govuk/all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ import Tabs from './components/tabs/tabs.mjs'
* Use the `data-module` attributes to find, instantiate and init all of the
* components provided as part of GOV.UK Frontend.
*
* @param {object} [config] - Config
* @param {HTMLElement} [config.scope=document] - Scope to query for components
* @param {object} [config.accordion] - Accordion config
* @param {object} [config.button] - Button config
* @param {object} [config.characterCount] - Character Count config
* @param {object} [config.errorSummary] - Error Summary config
* @param {object} [config.notificationBanner] - Notification Banner config
* @param {Config} [config] - Config for all components
*/
function initAll (config) {
config = typeof config !== 'undefined' ? config : {}
Expand Down Expand Up @@ -103,3 +97,15 @@ export {
SkipLink,
Tabs
}

/**
* Config for all components
*
* @typedef {object} Config
* @property {HTMLElement} [scope=document] - Scope to query for components
* @property {import('./components/accordion/accordion.mjs').AccordionConfig} [accordion] - Accordion config
* @property {import('./components/button/button.mjs').ButtonConfig} [button] - Button config
* @property {import('./components/character-count/character-count.mjs').CharacterCountConfig} [characterCount] - Character Count config
* @property {import('./components/error-summary/error-summary.mjs').ErrorSummaryConfig} [errorSummary] - Error Summary config
* @property {import('./components/notification-banner/notification-banner.mjs').NotificationBannerConfig} [notificationBanner] - Notification Banner config
*/
Comment on lines +101 to +111
Copy link
Member

Choose a reason for hiding this comment

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

Oh yeah, we were so focused on the individual components that all was completely neglected 😬 Good spot! 🙌🏻

20 changes: 15 additions & 5 deletions src/govuk/components/accordion/accordion.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import '../../vendor/polyfills/String/prototype/trim.mjs'
import { normaliseDataset } from '../../common/normalise-dataset.mjs'

/**
* @constant
* @type {AccordionTranslations}
* @see Default value for {@link AccordionConfig.i18n}
* @default
*/
var TRANSLATIONS_DEFAULT = {
var ACCORDION_TRANSLATIONS = {
hideAllSections: 'Hide all sections',
hideSection: 'Hide',
hideSectionAriaLabel: 'Hide this section',
Expand All @@ -31,17 +34,15 @@ var TRANSLATIONS_DEFAULT = {
*
* @class
* @param {HTMLElement} $module - HTML element to use for accordion
* @param {object} config - Accordion config
* @param {AccordionTranslations} config.i18n - Translations
* @param {AccordionConfig} [config] - Accordion config
*/
function Accordion ($module, config) {
this.$module = $module
this.$sections = $module.querySelectorAll('.govuk-accordion__section')
this.$showAllButton = ''
this.browserSupportsSessionStorage = helper.checkForSessionStorage()

var defaultConfig = {
i18n: TRANSLATIONS_DEFAULT
i18n: ACCORDION_TRANSLATIONS
}
this.config = mergeConfigs(
defaultConfig,
Expand Down Expand Up @@ -404,6 +405,15 @@ Accordion.prototype.getButtonPunctuationEl = function () {
export default Accordion

/**
* Accordion config
*
* @typedef {object} AccordionConfig
* @property {AccordionTranslations} [i18n = ACCORDION_TRANSLATIONS] - See constant {@link ACCORDION_TRANSLATIONS}
*/

/**
* Accordion translations
*
* @typedef {object} AccordionTranslations
*
* Messages used by the component for the labels of its buttons. This includes
Expand Down
14 changes: 10 additions & 4 deletions src/govuk/components/button/button.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ var DEBOUNCE_TIMEOUT_IN_SECONDS = 1
*
* @class
* @param {HTMLElement} $module - The element this component controls
* @param {object} config - Button config
* @param {boolean} [config.preventDoubleClick=false] -
* Prevent accidental double clicks on submit buttons from submitting forms
* multiple times.
* @param {ButtonConfig} config - Button config
*/
function Button ($module, config) {
if (!$module) {
Expand Down Expand Up @@ -93,3 +90,12 @@ Button.prototype.debounce = function (event) {
}

export default Button

/**
* Button config
*
* @typedef {object} ButtonConfig
* @property {boolean} [preventDoubleClick = false] -
* Prevent accidental double clicks on submit buttons from submitting forms
* multiple times.
*/
59 changes: 44 additions & 15 deletions src/govuk/components/character-count/character-count.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'

/**
* @constant
* @type {CharacterCountTranslations}
* @see Default value for {@link CharacterCountConfig.i18n}
* @default
*/
var TRANSLATIONS_DEFAULT = {
var CHARACTER_COUNT_TRANSLATIONS = {
// Characters
charactersUnderLimit: {
one: 'You have %{count} character remaining',
Expand Down Expand Up @@ -48,13 +51,7 @@ var TRANSLATIONS_DEFAULT = {
*
* @class
* @param {HTMLElement} $module - The element this component controls
* @param {object} config - Character count config
* @param {number} config.maxlength - The maximum number of characters. If maxwords is provided, the maxlength option will be ignored.
* @param {number} config.maxwords - The maximum number of words. If maxwords is provided, the maxlength option will be ignored.
* @param {number} [config.threshold=0] - The percentage value of the limit at
* which point the count message is displayed. If this attribute is set, the
* count message will be hidden by default.
* @param {CharacterCountTranslations} [config.i18n = DEFAULT_TRANSLATIONS]
* @param {CharacterCountConfig} [config] - Character count config
*/
function CharacterCount ($module, config) {
if (!$module) {
Expand All @@ -63,7 +60,7 @@ function CharacterCount ($module, config) {

var defaultConfig = {
threshold: 0,
i18n: TRANSLATIONS_DEFAULT
i18n: CHARACTER_COUNT_TRANSLATIONS
}

// Read config set using dataset ('data-' values)
Expand Down Expand Up @@ -376,12 +373,44 @@ CharacterCount.prototype.isOverThreshold = function () {
export default CharacterCount

/**
* Character count config
*
* @typedef {CharacterCountConfigWithMaxLength | CharacterCountConfigWithMaxWords} CharacterCountConfig
*/

/**
* Character count config (with maximum number of characters)
*
* @typedef {object} CharacterCountConfigWithMaxLength
* @property {number} [maxlength] - The maximum number of characters.
* If maxwords is provided, the maxlength option will be ignored.
* @property {number} [threshold = 0] - The percentage value of the limit at
* which point the count message is displayed. If this attribute is set, the
* count message will be hidden by default.
* @property {CharacterCountTranslations} [i18n = CHARACTER_COUNT_TRANSLATIONS] - See constant {@link CHARACTER_COUNT_TRANSLATIONS}
*/

/**
* Character count config (with maximum number of words)
*
* @typedef {object} CharacterCountConfigWithMaxWords
* @property {number} [maxwords] - The maximum number of words. If maxwords is
* provided, the maxlength option will be ignored.
* @property {number} [threshold = 0] - The percentage value of the limit at
* which point the count message is displayed. If this attribute is set, the
* count message will be hidden by default.
* @property {CharacterCountTranslations} [i18n = CHARACTER_COUNT_TRANSLATIONS] - See constant {@link CHARACTER_COUNT_TRANSLATIONS}
*/

/**
* Character count translations
*
* @typedef {object} CharacterCountTranslations
*
* Messages shown to users as they type. It provides feedback on how many words
* or characters they have remaining or if they are over the limit. This also
* includes a message used as an accessible description for the textarea.
* @property {PluralisedTranslation} [charactersUnderLimit] - Message displayed
* @property {TranslationPluralForms} [charactersUnderLimit] - Message displayed
* when the number of characters is under the configured maximum, `maxlength`.
* This message is displayed visually and through assistive technologies. The
* component will replace the `%{count}` placeholder with the number of
Expand All @@ -390,13 +419,13 @@ export default CharacterCount
* @property {string} [charactersAtLimit] - Message displayed when the number of
* characters reaches the configured maximum, `maxlength`. This message is
* displayed visually and through assistive technologies.
* @property {PluralisedTranslation} [charactersOverLimit] - Message displayed
* @property {TranslationPluralForms} [charactersOverLimit] - Message displayed
* when the number of characters is over the configured maximum, `maxlength`.
* This message is displayed visually and through assistive technologies. The
* component will replace the `%{count}` placeholder with the number of
* remaining characters. This is a [pluralised list of
* messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).
* @property {PluralisedTranslation} [wordsUnderLimit] - Message displayed when
* @property {TranslationPluralForms} [wordsUnderLimit] - Message displayed when
* the number of words is under the configured maximum, `maxlength`. This
* message is displayed visually and through assistive technologies. The
* component will replace the `%{count}` placeholder with the number of
Expand All @@ -405,13 +434,13 @@ export default CharacterCount
* @property {string} [wordsAtLimit] - Message displayed when the number of
* words reaches the configured maximum, `maxlength`. This message is
* displayed visually and through assistive technologies.
* @property {PluralisedTranslation} [wordsOverLimit] - Message displayed when
* @property {TranslationPluralForms} [wordsOverLimit] - Message displayed when
* the number of words is over the configured maximum, `maxlength`. This
* message is displayed visually and through assistive technologies. The
* component will replace the `%{count}` placeholder with the number of
* remaining words. This is a [pluralised list of
* messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).
* @property {PluralisedTranslation} [textareaDescription] - Message made
* @property {TranslationPluralForms} [textareaDescription] - Message made
* available to assistive technologies, if none is already present in the
* HTML, to describe that the component accepts only a limited amount of
* content. It is visible on the page when JavaScript is unavailable. The
Expand All @@ -420,5 +449,5 @@ export default CharacterCount
*/

/**
* @typedef {import('../../i18n.mjs').PluralisedTranslation} PluralisedTranslation
* @typedef {import('../../i18n.mjs').TranslationPluralForms} TranslationPluralForms
*/
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ describe('Character count', () => {

await renderAndInitialise(page, 'character-count', {
nunjucksParams: examples.default,
config: {
javascriptConfig: {
// Override maxlength to 10
maxlength: 10
},
Expand Down
17 changes: 10 additions & 7 deletions src/govuk/components/character-count/character-count.unit.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ describe('CharacterCount', () => {
describe('JavaScript configuration', () => {
it('overrides the default translation keys', () => {
const component = new CharacterCount(document.createElement('div'), {
i18n: { charactersUnderLimit: { one: 'Custom text. Count: %{count}' } },
'i18n.charactersOverLimit.other': 'Different custom text. Count: %{count}'
i18n: { charactersUnderLimit: { one: 'Custom text. Count: %{count}' } }
})

expect(component.formatCountMessage(1, 'characters')).toEqual('Custom text. Count: 1')
expect(component.formatCountMessage(-10, 'characters')).toEqual('Different custom text. Count: 10')
// Other keys remain untouched
expect(component.formatCountMessage(10, 'characters')).toEqual('You have 10 characters remaining')
})

it('uses specific keys for when limit is reached', () => {
const component = new CharacterCount(document.createElement('div'), {
i18n: { charactersAtLimit: 'Custom text.' },
'i18n.wordsAtLimit': 'Different custom text.'
i18n: {
charactersAtLimit: 'Custom text.',
wordsAtLimit: 'Different custom text.'
}
})

expect(component.formatCountMessage(0, 'characters')).toEqual('Custom text.')
Expand Down Expand Up @@ -101,12 +101,15 @@ describe('CharacterCount', () => {

const component = new CharacterCount($div, {
i18n: {
charactersUnderLimitOne: 'Different custom text. Count: %{count}'
charactersUnderLimit: {
one: 'Different custom text. Count: %{count}'
}
}
})
expect(component.formatCountMessage(1, 'characters')).toEqual('Custom text. Count: 1')
// Other keys remain untouched
expect(component.formatCountMessage(10, 'characters')).toEqual('You have 10 characters remaining')
expect(component.formatCountMessage(-10, 'characters')).toEqual('You have 10 characters too many')
expect(component.formatCountMessage(0, 'characters')).toEqual('You have 0 characters remaining')
})
})
})
Expand Down
11 changes: 9 additions & 2 deletions src/govuk/components/error-summary/error-summary.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
*
* @class
* @param {HTMLElement} $module - The element this component controls
* @param {object} config - Error summary config
* @param {boolean} [config.disableAutoFocus=false] - If set to `true` the error summary will not be focussed when the page loads.
* @param {ErrorSummaryConfig} config - Error summary config
*/
function ErrorSummary ($module, config) {
// Some consuming code may not be passing a module,
Expand Down Expand Up @@ -201,3 +200,11 @@ ErrorSummary.prototype.getAssociatedLegendOrLabel = function ($input) {
}

export default ErrorSummary

/**
* Error summary config
*
* @typedef {object} ErrorSummaryConfig
* @property {boolean} [disableAutoFocus = false] -
* If set to `true` the error summary will not be focussed when the page loads.
*/
18 changes: 12 additions & 6 deletions src/govuk/components/notification-banner/notification-banner.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ import { normaliseDataset } from '../../common/normalise-dataset.mjs'
*
* @class
* @param {HTMLElement} $module - HTML element to use for notification banner
* @param {object} config - Error summary config
* @param {boolean} [config.disableAutoFocus=false] -
* If set to `true` the notification banner will not be focussed when the page
* loads. This only applies if the component has a `role` of `alert` – in
* other cases the component will not be focused on page load, regardless of
* this option.
* @param {NotificationBannerConfig} config - Notification banner config
*/
function NotificationBanner ($module, config) {
this.$module = $module
Expand Down Expand Up @@ -77,3 +72,14 @@ NotificationBanner.prototype.setFocus = function () {
}

export default NotificationBanner

/**
* Notification banner config
*
* @typedef {object} NotificationBannerConfig
* @property {boolean} [disableAutoFocus = false] -
* If set to `true` the notification banner will not be focussed when the page
* loads. This only applies if the component has a `role` of `alert` – in
* other cases the component will not be focused on page load, regardless of
* this option.
*/
23 changes: 14 additions & 9 deletions src/govuk/i18n.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
*
* @class
* @private
* @param {object} translations - Key-value pairs of the translation strings to use.
* @param {object} config - Configuration options for the function.
* @param {TranslationsFlattened} translations - Key-value pairs of the translation strings to use.
* @param {object} [config] - Configuration options for the function.
* @param {string} config.locale - An overriding locale for the PluralRules functionality.
*/
export function I18n (translations, config) {
config = config || {}

// Make list of translations available throughout function
this.translations = translations || {}

// The locale to use for PluralRules and NumberFormat
this.locale = config.locale || document.documentElement.lang || 'en'
this.locale = (config && config.locale) || document.documentElement.lang || 'en'
}

/**
Expand Down Expand Up @@ -261,7 +259,7 @@ I18n.prototype.getPluralRulesForLocale = function () {
* Spanish: European Portuguese (pt-PT), Italian (it), Spanish (es)
* Welsh: Welsh (cy)
*
* @type {Object<string, string[]>}
* @type {Object<PluralRuleName, string[]>}
*/
I18n.pluralRulesMap = {
arabic: ['ar'],
Expand Down Expand Up @@ -360,16 +358,23 @@ I18n.pluralRules = {
*/

/**
* Associates translated messages to plural type they correspond to.
* Translated message by plural rule they correspond to.
*
* Allows to group pluralised messages under a single key when passing
* translations to a component's constructor
*
* @typedef {object} PluralisedTranslation
* @property {string} other - General plural form
* @typedef {object} TranslationPluralForms
* @property {string} [other] - General plural form
* @property {string} [zero] - Plural form used with 0
* @property {string} [one] - Plural form used with 1
* @property {string} [two] - Plural form used with 2
* @property {string} [few] - Plural form used for a few
* @property {string} [many] - Plural form used for many
*/

/**
* Translated messages (flattened)
*
* @private
* @typedef {Object<string, string> | {}} TranslationsFlattened
*/
Loading