Browse Source

Lint JavaScript (#667)

* Add standard task for linting JavaScript

* Lint JavaScript

* Pin govuk-frontend to v4.0.1
pull/670/head
Paul Robert Lloyd 3 years ago committed by GitHub
parent
commit
adb32a1ed8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      app/frontend/application.js
  2. 6
      app/frontend/controllers/accessible_autocomplete_controller.js
  3. 6
      app/frontend/controllers/application.js
  4. 10
      app/frontend/controllers/conditional_filter_controller.js
  5. 40
      app/frontend/controllers/conditional_question_controller.js
  6. 6
      app/frontend/controllers/filter_layout_controller.js
  7. 8
      app/frontend/controllers/govukfrontend_controller.js
  8. 26
      app/frontend/controllers/index.js
  9. 39
      app/frontend/controllers/numeric_question_controller.js
  10. 26
      app/frontend/modules/filter_toggle.js
  11. 12
      babel.config.js
  12. 7
      lib/tasks/lint.rake
  13. 8
      package.json
  14. 34
      webpack.config.js
  15. 951
      yarn.lock

29
app/frontend/application.js

@ -1,22 +1,23 @@
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
// present in this directory. You're encouraged to place your actual application
// logic in a relevant structure within app/javascript and only use these pack
// files to reference that code so it'll be compiled.
// Polyfills for IE
import "@webcomponents/webcomponentsjs"
import "core-js/stable"
import "regenerator-runtime/runtime"
import "@stimulus/polyfills"
import "custom-event-polyfill"
import "intersection-observer"
import '@webcomponents/webcomponentsjs'
import 'core-js/stable'
import 'regenerator-runtime/runtime'
import '@stimulus/polyfills'
import 'custom-event-polyfill'
import 'intersection-observer'
//
import GOVUKFrontend from 'govuk-frontend'
import GOVUKPrototypeComponents from 'govuk-prototype-components'
import './styles/application.scss'
import './controllers'
require.context("govuk-frontend/govuk/assets")
import GOVUKFrontend from "govuk-frontend"
import GOVUKPrototypeComponents from "govuk-prototype-components"
import "./styles/application.scss"
import "./controllers"
require.context('govuk-frontend/govuk/assets')
GOVUKFrontend.initAll()
GOVUKPrototypeComponents.initAll()

6
app/frontend/controllers/accessible_autocomplete_controller.js

@ -1,9 +1,9 @@
import { Controller } from "@hotwired/stimulus"
import accessibleAutocomplete from "accessible-autocomplete"
import { Controller } from '@hotwired/stimulus'
import accessibleAutocomplete from 'accessible-autocomplete'
import 'accessible-autocomplete/dist/accessible-autocomplete.min.css'
export default class extends Controller {
connect() {
connect () {
accessibleAutocomplete.enhanceSelectElement({
defaultValue: '',
selectElement: this.element

6
app/frontend/controllers/application.js

@ -1,10 +1,10 @@
import { Application } from "@hotwired/stimulus"
import { Application } from '@hotwired/stimulus'
const application = Application.start()
// Configure Stimulus development experience
application.warnings = true
application.debug = false
window.Stimulus = application
application.debug = false
window.Stimulus = application
export { application }

10
app/frontend/controllers/conditional_filter_controller.js

@ -1,13 +1,13 @@
import { Controller } from "@hotwired/stimulus"
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
initialize() {
initialize () {
this.clearIfHidden()
}
clearIfHidden() {
if(this.element.style["display"] == "none") {
this.element.value = ""
clearIfHidden () {
if (this.element.style.display === 'none') {
this.element.value = ''
}
}
}

40
app/frontend/controllers/conditional_question_controller.js

@ -1,36 +1,36 @@
import { Controller } from "@hotwired/stimulus"
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
initialize() {
initialize () {
this.displayConditional()
}
displayConditional() {
if(this.element.checked) {
let selectedValue = this.element.value
let conditional_for = JSON.parse(this.element.dataset.info)
Object.entries(conditional_for).map(([targetQuestion, conditions]) => {
if(conditions.map(String).includes(String(selectedValue))) {
displayConditional () {
if (this.element.checked) {
const selectedValue = this.element.value
const conditionalFor = JSON.parse(this.element.dataset.info)
Object.entries(conditionalFor).forEach(([targetQuestion, conditions]) => {
if (!conditions.map(String).includes(String(selectedValue))) {
const textNumericInput = document.getElementById(`case-log-${targetQuestion.replaceAll('_', '-')}-field`)
if (textNumericInput == null) {
const dateInputs = [1, 2, 3].map((idx) => {
return document.getElementById(`case_log_${targetQuestion}_${idx}i`)
})
this.clearDateInputs(dateInputs)
} else {
const textNumericInput = document.getElementById(`case-log-${targetQuestion.replaceAll("_","-")}-field`)
if (textNumericInput == null) {
const dateInputs = [1,2,3].map((idx) => {
return document.getElementById(`case_log_${targetQuestion}_${idx}i`)
})
this.clearDateInputs(dateInputs)
} else {
this.clearTextNumericInput(textNumericInput)
this.clearTextNumericInput(textNumericInput)
}
}
})
}
}
clearTextNumericInput(input) {
input.value = ""
clearTextNumericInput (input) {
input.value = ''
}
clearDateInputs(inputs) {
inputs.forEach((input) => { input.value = "" })
clearDateInputs (inputs) {
inputs.forEach((input) => { input.value = '' })
}
}

6
app/frontend/controllers/filter_layout_controller.js

@ -1,8 +1,8 @@
import { Controller } from "@hotwired/stimulus";
import { FilterToggle } from "../modules/filter_toggle.js"
import { Controller } from '@hotwired/stimulus'
import { FilterToggle } from '../modules/filter_toggle.js'
export default class extends Controller {
connect() {
connect () {
const filterToggle = new FilterToggle({
bigModeMediaQuery: '(min-width: 48.0625em)',
closeButton: {

8
app/frontend/controllers/govukfrontend_controller.js

@ -1,9 +1,9 @@
import GOVUKFrontend from "govuk-frontend";
import GOVUKPrototypeComponents from "govuk-prototype-components"
import { Controller } from "@hotwired/stimulus";
import GOVUKFrontend from 'govuk-frontend'
import GOVUKPrototypeComponents from 'govuk-prototype-components'
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
connect() {
connect () {
GOVUKFrontend.initAll()
GOVUKPrototypeComponents.initAll()
}

26
app/frontend/controllers/index.js

@ -1,22 +1,22 @@
// Load all the controllers within this directory and all subdirectories.
// Controller files must be named *_controller.js.
import { application } from "./application"
import { application } from './application'
import AccessibleAutocompleteController from "./accessible_autocomplete_controller.js"
application.register("accessible-autocomplete", AccessibleAutocompleteController)
import AccessibleAutocompleteController from './accessible_autocomplete_controller.js'
import ConditionalFilterController from "./conditional_filter_controller.js"
application.register("conditional-filter", ConditionalFilterController)
import ConditionalFilterController from './conditional_filter_controller.js'
import ConditionalQuestionController from "./conditional_question_controller.js"
application.register("conditional-question", ConditionalQuestionController)
import ConditionalQuestionController from './conditional_question_controller.js'
import GovukfrontendController from "./govukfrontend_controller.js"
application.register("govukfrontend", GovukfrontendController)
import GovukfrontendController from './govukfrontend_controller.js'
import NumericQuestionController from "./numeric_question_controller.js"
application.register("numeric-question", NumericQuestionController)
import NumericQuestionController from './numeric_question_controller.js'
import FilterLayoutController from "./filter_layout_controller.js"
application.register("filter-layout", FilterLayoutController)
import FilterLayoutController from './filter_layout_controller.js'
application.register('accessible-autocomplete', AccessibleAutocompleteController)
application.register('conditional-filter', ConditionalFilterController)
application.register('conditional-question', ConditionalQuestionController)
application.register('govukfrontend', GovukfrontendController)
application.register('numeric-question', NumericQuestionController)
application.register('filter-layout', FilterLayoutController)

39
app/frontend/controllers/numeric_question_controller.js

@ -1,27 +1,26 @@
import { Controller } from "@hotwired/stimulus"
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
connect() {
const affectedField = this.element.dataset.target;
const targetQuestion = affectedField.split("case-log-")[1].split("-field")[0]
const div = document.getElementById(targetQuestion + "_div");
div.style.display = "block";
connect () {
const affectedField = this.element.dataset.target
const targetQuestion = affectedField.split('case-log-')[1].split('-field')[0]
const div = document.getElementById(targetQuestion + '_div')
div.style.display = 'block'
}
calculateFields() {
const affectedField = this.element.dataset.target;
const fieldsToAdd = JSON.parse(this.element.dataset.calculated).map(x => `case-log-${x.replaceAll("_","-")}-field`);
const valuesToAdd = fieldsToAdd.map(x => getFieldValue(x)).filter(x => x);
const newValue = valuesToAdd.map(x => parseFloat(x)).reduce((a, b) => a + b, 0).toFixed(2);
const elementToUpdate = document.getElementById(affectedField);
elementToUpdate.value = newValue;
calculateFields () {
const affectedField = this.element.dataset.target
const fieldsToAdd = JSON.parse(this.element.dataset.calculated).map(x => `case-log-${x.replaceAll('_', '-')}-field`)
const valuesToAdd = fieldsToAdd.map(x => getFieldValue(x)).filter(x => x)
const newValue = valuesToAdd.map(x => parseFloat(x)).reduce((a, b) => a + b, 0).toFixed(2)
const elementToUpdate = document.getElementById(affectedField)
elementToUpdate.value = newValue
}
}
const getFieldValue = (field) => {
const elementFieldToAdd = document.getElementById(field)
if (elementFieldToAdd) {
return elementFieldToAdd.value
}
let getFieldValue = (field) => {
const elementFieldToAdd= document.getElementById(field)
if (elementFieldToAdd) {
return elementFieldToAdd.value
}
return document.getElementById(`${field}-error`).value
return document.getElementById(`${field}-error`).value
}

26
app/frontend/modules/filter_toggle.js

@ -25,7 +25,7 @@ export class FilterToggle {
}
enableSmallMode () {
this.options.filter.container.setAttribute("tabindex", "-1")
this.options.filter.container.setAttribute('tabindex', '-1')
this.hideMenu()
this.addMenuButton()
this.addCloseButton()
@ -33,8 +33,8 @@ export class FilterToggle {
addCloseButton () {
if (this.options.closeButton) {
this.closeButton = document.createElement("button")
this.closeButton.classList.add("app-filter__close")
this.closeButton = document.createElement('button')
this.closeButton.classList.add('app-filter__close')
this.closeButton.innerText = this.options.closeButton.text
this.closeButton.type = 'button'
this.closeButton.addEventListener('click', this.onCloseClick.bind(this))
@ -56,13 +56,13 @@ export class FilterToggle {
}
addMenuButton () {
this.menuButton = document.createElement("button")
this.menuButton.setAttribute("aria-expanded", "false")
this.menuButton.setAttribute("aria-has-popup", "true")
this.menuButton.classList.add("govuk-button", this.options.toggleButton.classes, "app-filter-toggle__button")
this.menuButton = document.createElement('button')
this.menuButton.setAttribute('aria-expanded', 'false')
this.menuButton.setAttribute('aria-has-popup', 'true')
this.menuButton.classList.add('govuk-button', this.options.toggleButton.classes, 'app-filter-toggle__button')
this.menuButton.innerText = this.options.toggleButton.showText
this.menuButton.type = "button"
this.menuButton.addEventListener("click", this.onMenuButtonClick.bind(this))
this.menuButton.type = 'button'
this.menuButton.addEventListener('click', this.onMenuButtonClick.bind(this))
this.options.toggleButton.container.prepend(this.menuButton)
}
@ -76,18 +76,18 @@ export class FilterToggle {
hideMenu () {
if (this.menuButton) {
this.menuButton.setAttribute("aria-expanded", "false")
this.menuButton.setAttribute('aria-expanded', 'false')
this.menuButton.innerText = this.options.toggleButton.showText
}
this.options.filter.container.setAttribute("hidden", true)
this.options.filter.container.setAttribute('hidden', true)
}
showMenu () {
if (this.menuButton) {
this.menuButton.setAttribute("aria-expanded", "true")
this.menuButton.setAttribute('aria-expanded', 'true')
this.menuButton.innerText = this.options.toggleButton.hideText
}
this.options.filter.container.removeAttribute("hidden")
this.options.filter.container.removeAttribute('hidden')
}
onMenuButtonClick () {

12
babel.config.js

@ -1,9 +1,9 @@
module.exports = function(api) {
var validEnv = ['development', 'test', 'production']
var currentEnv = api.env()
var isDevelopmentEnv = api.env('development')
var isProductionEnv = api.env('production')
var isTestEnv = api.env('test')
module.exports = function (api) {
const validEnv = ['development', 'test', 'production']
const currentEnv = api.env()
const isDevelopmentEnv = api.env('development')
const isProductionEnv = api.env('production')
const isTestEnv = api.env('test')
if (!validEnv.includes(currentEnv)) {
throw new Error(

7
lib/tasks/lint.rake

@ -8,10 +8,15 @@ task erblint: :environment do
sh "bundle exec erblint --lint-all"
end
desc "Run Standard"
task standard: :environment do
sh "yarn standard"
end
desc "Run Stylelint"
task stylelint: :environment do
sh "yarn stylelint app/frontend/styles"
end
desc "Run all the linters"
task lint: %i[rubocop erblint stylelint]
task lint: %i[rubocop erblint standard stylelint]

8
package.json

@ -20,7 +20,7 @@
"css-loader": "^6.7.1",
"custom-event-polyfill": "^1.0.7",
"file-loader": "^6.2.0",
"govuk-frontend": "^4.0.1",
"govuk-frontend": "4.0.1",
"govuk-prototype-components": "^0.1.5",
"html5shiv": "^3.7.3",
"intersection-observer": "^0.12.0",
@ -36,6 +36,7 @@
"version": "0.1.0",
"devDependencies": {
"are-you-es5": "^2.1.2",
"standard": "^17.0.0",
"stylelint": "^14.7.1",
"stylelint-config-gds": "^0.2.0"
},
@ -51,6 +52,11 @@
"last 1 safari version"
]
},
"standard": {
"ignore": [
"app/frontend/vendor/*.js"
]
},
"stylelint": {
"extends": "stylelint-config-gds/scss"
},

34
webpack.config.js

@ -1,18 +1,18 @@
const path = require("path")
const webpack = require("webpack")
const path = require('node:path')
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts')
const CopyPlugin = require("copy-webpack-plugin");
const CopyPlugin = require('copy-webpack-plugin')
const mode = process.env.NODE_ENV === 'development' ? 'development' : 'production'
module.exports = {
mode,
devtool: "source-map",
devtool: 'source-map',
entry: {
application: [
"./app/frontend/application.js",
'./app/frontend/application.js'
]
},
module: {
@ -24,9 +24,9 @@ module.exports = {
path.resolve(__dirname, 'node_modules/@stimulus/polyfills'),
path.resolve(__dirname, 'node_modules/@rails/actioncable'),
path.resolve(__dirname, 'node_modules/chartjs'),
path.resolve(__dirname, 'app/frontend'),
path.resolve(__dirname, 'app/frontend')
],
use: ['babel-loader'],
use: ['babel-loader']
},
{
test: /\.(png|jpe?g|gif|eot|woff|woff2|ttf|svg|ico)$/i,
@ -34,9 +34,9 @@ module.exports = {
},
{
test: /\.(scss|css)/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
],
]
},
resolve: {
alias: {
@ -46,11 +46,11 @@ module.exports = {
modules: ['node_modules', 'node_modules/govuk-frontend/govuk']
},
output: {
filename: "[name].js",
filename: '[name].js',
// we must set publicPath to an empty value to override the default of
// auto which doesn't work in IE11
publicPath: '',
path: path.resolve(__dirname, "app/assets/builds"),
path: path.resolve(__dirname, 'app/assets/builds')
},
plugins: [
new RemoveEmptyScriptsPlugin(),
@ -58,12 +58,12 @@ module.exports = {
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
new CopyPlugin({
patterns: [
{ from: "node_modules/govuk-frontend/govuk/assets/images", to: "images" },
{ from: "node_modules/govuk-frontend/govuk/assets/fonts", to: "fonts" },
{ from: "node_modules/html5shiv/dist/html5shiv.min.js", to: "vendor" },
{ from: "app/frontend/vendor/outerHTML.js", to: "vendor" },
{ from: "app/frontend/vendor/polyfill-output-value.js", to: "vendor" }
],
{ from: 'node_modules/govuk-frontend/govuk/assets/images', to: 'images' },
{ from: 'node_modules/govuk-frontend/govuk/assets/fonts', to: 'fonts' },
{ from: 'node_modules/html5shiv/dist/html5shiv.min.js', to: 'vendor' },
{ from: 'app/frontend/vendor/outerHTML.js', to: 'vendor' },
{ from: 'app/frontend/vendor/polyfill-output-value.js', to: 'vendor' }
]
})
]
}

951
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save