Skip to content

Commit

Permalink
Merge pull request #3770 from alphagov/module-eslint-rules
Browse files Browse the repository at this point in the history
Upgrade ESLint configuration for ES2015 (without classes)
  • Loading branch information
colinrotherham committed Jun 8, 2023
2 parents f087913 + 96b19ad commit c11dfc0
Show file tree
Hide file tree
Showing 37 changed files with 351 additions and 359 deletions.
11 changes: 6 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ module.exports = {
// Ignore `govuk-frontend` exports as they require auto-generated files
'import/no-unresolved': ['error', { ignore: ['govuk-frontend'] }],
'n/no-missing-import': ['error', { allowModules: ['govuk-frontend'] }],
'n/no-missing-require': ['error', { allowModules: ['govuk-frontend'] }]
'n/no-missing-require': ['error', { allowModules: ['govuk-frontend'] }],

// Automatically use template strings
'no-useless-concat': 'error',
'prefer-template': 'error'
},
settings: {
jsdoc: {
Expand Down Expand Up @@ -127,10 +131,7 @@ module.exports = {

// Ignore paths to example modules
'import/no-unresolved': 'off',
'n/no-missing-import': 'off',

// Allow `var` in example code
'no-var': 'off'
'n/no-missing-import': 'off'
}
}
],
Expand Down
6 changes: 3 additions & 3 deletions docs/contributing/coding-standards/js.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Example.prototype.init = function () {
}

// Code goes here
var $module = this.$module
const $module = this.$module
}

export default Example
Expand Down Expand Up @@ -117,10 +117,10 @@ When initialising an object, use the `new` keyword.

```mjs
// Bad
var myExample1 = Example()
const myExample1 = Example()

// Good
var myExample2 = new Example()
const myExample2 = new Example()
```

## Modules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
{% block bodyEnd %}
<script type="module" src="/javascripts/all.min.js"></script>
<script type="module">
var $scope = document.getElementById('scoped')
const $scope = document.getElementById('scoped')
window.GOVUKFrontend.initAll({
scope: $scope
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,13 @@ notes: >-
</div>

<script type="module">
var acceptButton = document.querySelector('.js-cookies-button-accept')
var rejectButton = document.querySelector('.js-cookies-button-reject')
const acceptButton = document.querySelector('.js-cookies-button-accept')
const rejectButton = document.querySelector('.js-cookies-button-reject')
var acceptedBanner = document.querySelector('.js-cookies-accepted')
var rejectedBanner = document.querySelector('.js-cookies-rejected')
var questionBanner = document.querySelector('.js-question-banner')
var cookieBanner = document.querySelector('.js-cookies-banner')
const acceptedBanner = document.querySelector('.js-cookies-accepted')
const rejectedBanner = document.querySelector('.js-cookies-rejected')
const questionBanner = document.querySelector('.js-question-banner')
const cookieBanner = document.querySelector('.js-cookies-banner')
function showBanner(banner) {
questionBanner.setAttribute('hidden', 'hidden')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ notes: >-
have to take care of the 'Hide' button to make progressive enhancement in
the example functional #}
<script type="module">
var hideButton = document.querySelector('.js-hide')
var cookieBanner = document.querySelector(".govuk-cookie-banner")
const hideButton = document.querySelector('.js-hide')
const cookieBanner = document.querySelector(".govuk-cookie-banner")
if (hideButton) {
hideButton.addEventListener('click', function(event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ notes: >-
have to take care of the 'Hide' button to make progressive enhancement in
the example functional #}
<script type="module">
var hideButton = document.querySelector('.js-hide')
var cookieBanner = document.querySelector(".govuk-cookie-banner")
var confirmationBanner = document.querySelector('.js-confirmation-banner')
const hideButton = document.querySelector('.js-hide')
const cookieBanner = document.querySelector(".govuk-cookie-banner")
const confirmationBanner = document.querySelector('.js-confirmation-banner')
if (confirmationBanner) {
// Shift focus to the confirmation banner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ export default (app) => {

// If any of the date inputs error apply a general error.
const expiryNamePrefix = 'expiry'
const expiryErrors = Object.values(errors).filter(error => error.id.includes(expiryNamePrefix + '-'))
const expiryErrors = Object.values(errors).filter(error => error.id.includes(`${expiryNamePrefix}-`))
if (expiryErrors.length) {
const firstExpiryErrorId = expiryErrors[0].id
// Get the first error message and merge it into a single error message.
errors[expiryNamePrefix] = {
id: expiryNamePrefix,
href: '#' + firstExpiryErrorId,
href: `#${firstExpiryErrorId}`,
value: '',
text: ''
}
Expand All @@ -60,7 +60,7 @@ export default (app) => {
let errorSummary = Object.values(errors)
if (expiryErrors) {
// Remove all other errors from the summary so we only have one message that links to the expiry input.
errorSummary = errorSummary.filter(error => !error.id.includes(expiryNamePrefix + '-'))
errorSummary = errorSummary.filter(error => !error.id.includes(`${expiryNamePrefix}-`))
}

response.render('./full-page-examples/passport-details/index', {
Expand Down
22 changes: 11 additions & 11 deletions packages/govuk-frontend/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
excludedFiles: ['**/*.test.mjs'],
parser: '@typescript-eslint/parser',
parserOptions: {
// Note: Allow ES6 for import/export syntax
// Note: Allow ES2015 for import/export syntax
ecmaVersion: '2015',
project: [resolve(__dirname, 'tsconfig.json')]
},
Expand All @@ -23,23 +23,23 @@ module.exports = {
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:es-x/restrict-to-es5'
'plugin:es-x/restrict-to-es2015'
],
env: {
browser: true
},
rules: {
// Allow unknown `.prototype` members until ES6 classes
// Allow unknown `.prototype` members until ES2015 classes
'@typescript-eslint/no-unsafe-member-access': 'off',

// Allow `this` alias until arrow functions supported
'@typescript-eslint/no-this-alias': 'off',

// Rollup transpiles modules into other formats
'es-x/no-modules': 'off',

// Allow `var` until let/const supported
'no-var': 'off',
// Check type support for template string implicit `.toString()`
'@typescript-eslint/restrict-template-expressions': [
'error',
{
allowBoolean: true,
allowNumber: true
}
],

// JSDoc blocks are mandatory
'jsdoc/require-jsdoc': [
Expand Down
40 changes: 20 additions & 20 deletions packages/govuk-frontend/src/govuk/all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,63 +24,63 @@ function initAll (config) {

// Allow the user to initialise GOV.UK Frontend in only certain sections of the page
// Defaults to the entire document if nothing is set.
var $scope = config.scope instanceof HTMLElement ? config.scope : document
const $scope = config.scope instanceof HTMLElement ? config.scope : document

var $accordions = $scope.querySelectorAll('[data-module="govuk-accordion"]')
$accordions.forEach(function ($accordion) {
const $accordions = $scope.querySelectorAll('[data-module="govuk-accordion"]')
$accordions.forEach(($accordion) => {
new Accordion($accordion, config.accordion).init()
})

var $buttons = $scope.querySelectorAll('[data-module="govuk-button"]')
$buttons.forEach(function ($button) {
const $buttons = $scope.querySelectorAll('[data-module="govuk-button"]')
$buttons.forEach(($button) => {
new Button($button, config.button).init()
})

var $characterCounts = $scope.querySelectorAll('[data-module="govuk-character-count"]')
$characterCounts.forEach(function ($characterCount) {
const $characterCounts = $scope.querySelectorAll('[data-module="govuk-character-count"]')
$characterCounts.forEach(($characterCount) => {
new CharacterCount($characterCount, config.characterCount).init()
})

var $checkboxes = $scope.querySelectorAll('[data-module="govuk-checkboxes"]')
$checkboxes.forEach(function ($checkbox) {
const $checkboxes = $scope.querySelectorAll('[data-module="govuk-checkboxes"]')
$checkboxes.forEach(($checkbox) => {
new Checkboxes($checkbox).init()
})

var $details = $scope.querySelectorAll('[data-module="govuk-details"]')
$details.forEach(function ($detail) {
const $details = $scope.querySelectorAll('[data-module="govuk-details"]')
$details.forEach(($detail) => {
new Details($detail).init()
})

// Find first error summary module to enhance.
var $errorSummary = $scope.querySelector('[data-module="govuk-error-summary"]')
const $errorSummary = $scope.querySelector('[data-module="govuk-error-summary"]')
if ($errorSummary) {
new ErrorSummary($errorSummary, config.errorSummary).init()
}

// Find first header module to enhance.
var $header = $scope.querySelector('[data-module="govuk-header"]')
const $header = $scope.querySelector('[data-module="govuk-header"]')
if ($header) {
new Header($header).init()
}

var $notificationBanners = $scope.querySelectorAll('[data-module="govuk-notification-banner"]')
$notificationBanners.forEach(function ($notificationBanner) {
const $notificationBanners = $scope.querySelectorAll('[data-module="govuk-notification-banner"]')
$notificationBanners.forEach(($notificationBanner) => {
new NotificationBanner($notificationBanner, config.notificationBanner).init()
})

var $radios = $scope.querySelectorAll('[data-module="govuk-radios"]')
$radios.forEach(function ($radio) {
const $radios = $scope.querySelectorAll('[data-module="govuk-radios"]')
$radios.forEach(($radio) => {
new Radios($radio).init()
})

// Find first skip link module to enhance.
var $skipLink = $scope.querySelector('[data-module="govuk-skip-link"]')
const $skipLink = $scope.querySelector('[data-module="govuk-skip-link"]')
if ($skipLink) {
new SkipLink($skipLink).init()
}

var $tabs = $scope.querySelectorAll('[data-module="govuk-tabs"]')
$tabs.forEach(function ($tabs) {
const $tabs = $scope.querySelectorAll('[data-module="govuk-tabs"]')
$tabs.forEach(($tabs) => {
new Tabs($tabs).init()
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @returns {string | null} Attribute value
*/
export function closestAttributeValue ($element, attributeName) {
var $closestElementWithAttribute = $element.closest('[' + attributeName + ']')
const $closestElementWithAttribute = $element.closest(`[${attributeName}]`)
return $closestElementWithAttribute
? $closestElementWithAttribute.getAttribute(attributeName)
: null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
*
* {@link https://github.com/alphagov/govuk-frontend/releases}
*/
export var version = 'development'
export const version = 'development'
32 changes: 16 additions & 16 deletions packages/govuk-frontend/src/govuk/common/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
* @returns {string} Unique ID
*/
export function generateUniqueID () {
var d = new Date().getTime()
let d = new Date().getTime()
if (typeof window.performance !== 'undefined' && typeof window.performance.now === 'function') {
d += window.performance.now() // use high-precision timer if available
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0
const r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
Expand All @@ -48,10 +48,10 @@ export function mergeConfigs (/* configObject1, configObject2, ...configObjects
* @param {{ [key: string]: unknown }} configObject - Deeply nested object
* @returns {{ [key: string]: unknown }} Flattened object with dot-separated keys
*/
var flattenObject = function (configObject) {
const flattenObject = function (configObject) {
// Prepare an empty return object
/** @type {{ [key: string]: unknown }} */
var flattenedObject = {}
const flattenedObject = {}

/**
* Our flattening function, this is called recursively for each level of
Expand All @@ -61,16 +61,16 @@ export function mergeConfigs (/* configObject1, configObject2, ...configObjects
* @param {Partial<{ [key: string]: unknown }>} obj - Object to flatten
* @param {string} [prefix] - Optional dot-separated prefix
*/
var flattenLoop = function (obj, prefix) {
const flattenLoop = function (obj, prefix) {
// Loop through keys...
for (var key in obj) {
for (const key in obj) {
// Check to see if this is a prototypical key/value,
// if it is, skip it.
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
continue
}
var value = obj[key]
var prefixedKey = prefix ? prefix + '.' + key : key
const value = obj[key]
const prefixedKey = prefix ? `${prefix}.${key}` : key
if (typeof value === 'object') {
// If the value is a nested object, recurse over that too
flattenLoop(value, prefixedKey)
Expand All @@ -88,15 +88,15 @@ export function mergeConfigs (/* configObject1, configObject2, ...configObjects

// Start with an empty object as our base
/** @type {{ [key: string]: unknown }} */
var formattedConfigObject = {}
const formattedConfigObject = {}

// Loop through each of the remaining passed objects and push their keys
// one-by-one into configObject. Any duplicate keys will override the existing
// key with the new value.
for (var i = 0; i < arguments.length; i++) {
for (let i = 0; i < arguments.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- Ignore mismatch between arguments types
var obj = flattenObject(arguments[i])
for (var key in obj) {
const obj = flattenObject(arguments[i])
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
formattedConfigObject[key] = obj[key]
}
Expand Down Expand Up @@ -128,11 +128,11 @@ export function extractConfigByNamespace (configObject, namespace) {
}

/** @type {{ [key: string]: unknown }} */
var newObject = {}
const newObject = {}

for (var key in configObject) {
for (const key in configObject) {
// Split the key into parts, using . as our namespace separator
var keyParts = key.split('.')
const keyParts = key.split('.')
// Check if the first namespace matches the configured namespace
if (Object.prototype.hasOwnProperty.call(configObject, key) && keyParts[0] === namespace) {
// Remove the first item (the namespace) from the parts array,
Expand All @@ -141,7 +141,7 @@ export function extractConfigByNamespace (configObject, namespace) {
keyParts.shift()
}
// Join the remaining parts back together
var newKey = keyParts.join('.')
const newKey = keyParts.join('.')
// Add them to our new object
newObject[newKey] = configObject[key]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function normaliseString (value) {
return value
}

var trimmedValue = value.trim()
const trimmedValue = value.trim()

if (trimmedValue === 'true') {
return true
Expand Down Expand Up @@ -48,9 +48,9 @@ export function normaliseString (value) {
*/
export function normaliseDataset (dataset) {
/** @type {{ [key: string]: unknown }} */
var out = {}
const out = {}

for (var key in dataset) {
for (const key in dataset) {
out[key] = normaliseString(dataset[key])
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('normaliseString', () => {

it('normalises strings that represent very big positive numbers to numbers', () => {
const biggestNumber = Number.MAX_SAFE_INTEGER + 1
expect(normaliseString(biggestNumber.toString())).toEqual(biggestNumber)
expect(normaliseString(`${biggestNumber}`)).toEqual(biggestNumber)
})

it('does not normalise strings that contain numbers', () => {
Expand Down
Loading

0 comments on commit c11dfc0

Please sign in to comment.