From 0a79484309f51c239fddc5043ebdcaeaa70af419 Mon Sep 17 00:00:00 2001 From: Hao Phan Date: Mon, 11 Apr 2022 11:39:31 +0300 Subject: [PATCH] upgrade webpack to v5, setup ESLint --- .eslintignore | 1 + .eslintrc | 19 +++++ package.json | 8 ++- src/actions/pagination.js | 2 +- src/actions/search.js | 3 +- src/components/activefilters/activefilters.js | 2 +- src/components/facets/facets.js | 1 - src/components/filters/filters.js | 2 +- .../hierarchicalfacets/hierarchicalfacets.js | 1 - src/components/loadmore/loadmore.js | 2 +- src/components/searchfield/searchfield.js | 3 +- src/reducers/autocomplete.js | 70 +++++++++---------- src/reducers/filters.js | 36 +++++----- src/reducers/search.js | 4 +- src/reducers/segmentedsearch.js | 7 +- src/util/handlebars.js | 4 +- src/util/history.js | 12 ++-- webpack.config.js | 7 ++ 18 files changed, 106 insertions(+), 78 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..c5c1507 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +/test/** \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..cbd61d1 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,19 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es2021": true + }, + "parser": "@babel/eslint-parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module", + "allowImportExportEverywhere": true + }, + "extends": "eslint:recommended", + "rules": { + "no-eval": ["error"], + "no-trailing-spaces": "error", + "no-irregular-whitespace": "off" + } +} diff --git a/package.json b/package.json index d757622..8363bc3 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "scripts": { "test": "./node_modules/mocha/bin/mocha --recursive --require @babel/register --require ignore-styles", "build": "npm run test && ./node_modules/webpack-cli/bin/cli.js", - "watch": "./node_modules/webpack-cli/bin/cli.js --watch" + "watch": "./node_modules/webpack-cli/bin/cli.js --watch", + "eslint-fix": "npx eslint --fix src/**" }, "repository": { "type": "git", @@ -50,12 +51,15 @@ "devDependencies": { "@babel/cli": "^7.12.1", "@babel/core": "^7.12.3", + "@babel/eslint-parser": "^7.17.0", "@babel/preset-env": "^7.12.1", "@babel/register": "^7.12.1", "assert": "^2.0.0", "autoprefixer": "^9.8.0", "babel-loader": "^8.1.0", "css-loader": "^3.5.3", + "eslint": "^8.13.0", + "eslint-webpack-plugin": "^3.1.1", "esm": "^3.2.22", "ignore-styles": "^5.0.1", "mini-css-extract-plugin": "^0.9.0", @@ -66,7 +70,7 @@ "sass-loader": "^10.2.1", "terser-webpack-plugin": "^3.0.2", "uglify-js": "^3.11.5", - "webpack": "^4.44.2", + "webpack": "^5.72.0", "webpack-cli": "^3.3.11" } } diff --git a/src/actions/pagination.js b/src/actions/pagination.js index 9fd9f97..6309bff 100644 --- a/src/actions/pagination.js +++ b/src/actions/pagination.js @@ -1,4 +1,4 @@ -import { setHistory, HISTORY_PARAMETERS } from '../util/history'; +import {setHistory, HISTORY_PARAMETERS} from '../util/history'; export const SET_PAGE = 'SET_PAGE'; diff --git a/src/actions/search.js b/src/actions/search.js index ccb40ac..715854d 100644 --- a/src/actions/search.js +++ b/src/actions/search.js @@ -1,4 +1,3 @@ -/* global window */ import { WARMUP_QUERY_PREFIX } from '../index'; import { setHistory, HISTORY_PARAMETERS } from '../util/history'; import { sendSearchStats } from '../util/analytics'; @@ -62,7 +61,7 @@ export function search(client, keyword, onResultsScrollTo, appendResults, isHist } } -export function searchFetchStart(keyword) { +export function searchFetchStart() { return { type: SEARCH_FETCH_START } diff --git a/src/components/activefilters/activefilters.js b/src/components/activefilters/activefilters.js index ac5b404..d8ab676 100644 --- a/src/components/activefilters/activefilters.js +++ b/src/components/activefilters/activefilters.js @@ -124,7 +124,7 @@ export default class ActiveFilters { const clearAll = container.querySelector('[data-clearall]'); if (clearAll) { - clearAll.addEventListener('click', (e) => this.reduxStore.dispatch(clearSelected(true))); + clearAll.addEventListener('click', () => this.reduxStore.dispatch(clearSelected(true))); } } diff --git a/src/components/facets/facets.js b/src/components/facets/facets.js index 1971c03..b5e2f23 100644 --- a/src/components/facets/facets.js +++ b/src/components/facets/facets.js @@ -2,7 +2,6 @@ import './facets.scss'; import handlebars from 'handlebars'; import { FACETS_TEMPLATE } from './templates'; import { toggleFacetFilter } from '../../actions/filters'; -import { search } from '../../actions/search'; import { observeStoreByKey } from '../../store'; import { validateContainer } from '../../util/dom'; import {createFilterObject} from "../filters/filterstateobserver"; diff --git a/src/components/filters/filters.js b/src/components/filters/filters.js index e14c98a..82e0988 100644 --- a/src/components/filters/filters.js +++ b/src/components/filters/filters.js @@ -203,7 +203,7 @@ export default class Filters { // Clear button const button = container.querySelector('button'); if (button) { - button.addEventListener('click', (e) => this.reduxStore.dispatch(setRangeFilter(this.conf.field, null, null))); + button.addEventListener('click', () => this.reduxStore.dispatch(setRangeFilter(this.conf.field, null, null))); } } diff --git a/src/components/hierarchicalfacets/hierarchicalfacets.js b/src/components/hierarchicalfacets/hierarchicalfacets.js index 248f888..0da5a77 100644 --- a/src/components/hierarchicalfacets/hierarchicalfacets.js +++ b/src/components/hierarchicalfacets/hierarchicalfacets.js @@ -2,7 +2,6 @@ import './hierarchicalfacets.scss'; import handlebars from 'handlebars'; import { FACETS_TEMPLATE, SUB_HIERARCHICAL_FACETS_TEMPLATE } from './templates'; import { toggleHierarchicalFacetFilter } from '../../actions/filters'; -import { search } from '../../actions/search'; import { observeStoreByKey } from '../../store'; import { validateContainer } from '../../util/dom'; import {createFilterObject} from "../filters/filterstateobserver"; diff --git a/src/components/loadmore/loadmore.js b/src/components/loadmore/loadmore.js index cf4b607..7970176 100644 --- a/src/components/loadmore/loadmore.js +++ b/src/components/loadmore/loadmore.js @@ -54,7 +54,7 @@ export default class LoadMore { if (this.conf.type === LOAD_MORE_TYPE.BUTTON) { const button = container.querySelector('button'); if (button) { - button.onclick = (e) => this.loadMore(); + button.onclick = () => this.loadMore(); } } diff --git a/src/components/searchfield/searchfield.js b/src/components/searchfield/searchfield.js index 7fdea77..5c6046e 100644 --- a/src/components/searchfield/searchfield.js +++ b/src/components/searchfield/searchfield.js @@ -1,4 +1,3 @@ -/* global window */ import './searchfield.scss'; import { SEARCHFIELD_TEMPLATE } from './templates'; import handlebars from 'handlebars'; @@ -126,7 +125,7 @@ export default class SearchField { this.field.onkeypress = (e) => this.onkeypress(e); this.field.onkeyup = (e) => this.onkeyup(e); this.field.onfocus = (e) => this.onfocus(e); - this.field.onblur = (e) => setTimeout(() => this.onblur(), 200); // Possible search button onclick event first + this.field.onblur = () => setTimeout(() => this.onblur(), 200); // Possible search button onclick event first // Event listeners to the possible search button if (container.querySelector('button')) { diff --git a/src/reducers/autocomplete.js b/src/reducers/autocomplete.js index 98a6649..3aa7023 100644 --- a/src/reducers/autocomplete.js +++ b/src/reducers/autocomplete.js @@ -33,7 +33,7 @@ const initialState = { export default function searchsuggestions(state = initialState, action) { switch (action.type) { - case AUTOCOMPLETE_FETCH_START: + case AUTOCOMPLETE_FETCH_START: { // Add to pending requests let addPendingReq = [...state.pendingRequests]; if (addPendingReq.indexOf(action.jsonKey) === -1) { @@ -44,23 +44,23 @@ export default function searchsuggestions(state = initialState, action) { pendingRequests: addPendingReq, dropRendering: false }); + } - - case AUTOCOMPLETE_SUGGESTIONS_CLEAR: + case AUTOCOMPLETE_SUGGESTIONS_CLEAR: { return Object.assign({}, state, { suggestions: [], activeSuggestionIndex: null }); + } - case AUTOCOMPLETE_CUSTOM_FIELDS_CLEAR: + case AUTOCOMPLETE_CUSTOM_FIELDS_CLEAR: { return Object.assign({}, state, { customFields: [], activeSuggestionIndex: null }); + } - - case AUTOCOMPLETE_SUGGESTIONS_RESULTS: - + case AUTOCOMPLETE_SUGGESTIONS_RESULTS: { // Remove suggestion from pending requests let removePendingSuggestion = [...state.pendingRequests]; if (removePendingSuggestion.indexOf(SUGGESTIONS_JSON_KEY) !== -1) { @@ -74,9 +74,9 @@ export default function searchsuggestions(state = initialState, action) { activeSuggestionIndex: null, visible: true }); + } - - case AUTOCOMPLETE_CUSTOM_FIELDS_RESULTS: + case AUTOCOMPLETE_CUSTOM_FIELDS_RESULTS: { // Remove suggestion from pending requests let removePendingCustomFields = [...state.pendingRequests]; @@ -90,16 +90,16 @@ export default function searchsuggestions(state = initialState, action) { activeSuggestionIndex: null, visible: true }); + } - - case AUTOCOMPLETE_SEARCH_CLEAR: + case AUTOCOMPLETE_SEARCH_CLEAR: { return Object.assign({}, state, { searchResults: {}, searchResultsStats: {} }); + } - - case AUTOCOMPLETE_SEARCH_RESULTS: + case AUTOCOMPLETE_SEARCH_RESULTS: { const nextSearchResults = Object.assign({}, state.searchResults); nextSearchResults[action.jsonKey] = action.results.hits; const nextSearchResultsStats = Object.assign({}, state.searchResultsStats); @@ -133,43 +133,45 @@ export default function searchsuggestions(state = initialState, action) { visible: true, appendResults: action.appendResults === true }); + } - - case AUTOCOMPLETE_HIDE: + case AUTOCOMPLETE_HIDE: { return Object.assign({}, state, { visible: false, activeSuggestionIndex: null }); + } - case AUTOCOMPLETE_HIDE_AND_DROP_RENDERING: + case AUTOCOMPLETE_HIDE_AND_DROP_RENDERING: { return Object.assign({}, state, { dropRendering: true, visible: false, activeSuggestionIndex: null }); + } - - case AUTOCOMPLETE_SHOW: + case AUTOCOMPLETE_SHOW: { return Object.assign({}, state, { visible: true }); + } - - case HIDE_AUTOMATICALLY: + case HIDE_AUTOMATICALLY: { return Object.assign({}, state, { hideAutomatically: action.hideAutomatically }); + } - - case SET_ACTIVE_SUGGESTION: + case SET_ACTIVE_SUGGESTION: { return Object.assign({}, state, { activeSuggestionIndex: action.index, setSuggestionToSearchField: action.setSuggestionToSearchField }); + } - case KEYBOARD_EVENT: - let nextActiveSuggestion = state.activeSuggestionIndex; + case KEYBOARD_EVENT: { + let nextActiveSuggestion = state.activeSuggestionIndex; let setSuggestionToSearchField = true; if (state.suggestions.length && state.customFields.length) { @@ -181,22 +183,17 @@ export default function searchsuggestions(state = initialState, action) { if (action.direction === ARROW_DOWN) { if (nextActiveSuggestion === null && state[source].length > 0) { nextActiveSuggestion = 0; - } - else if (nextActiveSuggestion === state[source].length-1) { + } else if (nextActiveSuggestion === state[source].length - 1) { nextActiveSuggestion = null; - } - else { + } else { nextActiveSuggestion = nextActiveSuggestion + 1; } - } - else if (action.direction === ARROW_UP) { + } else if (action.direction === ARROW_UP) { if (nextActiveSuggestion === null && state[source].length > 0) { - nextActiveSuggestion = state[source].length-1; - } - else if (nextActiveSuggestion === 0) { + nextActiveSuggestion = state[source].length - 1; + } else if (nextActiveSuggestion === 0) { nextActiveSuggestion = null; - } - else { + } else { nextActiveSuggestion = nextActiveSuggestion - 1; } } @@ -205,8 +202,9 @@ export default function searchsuggestions(state = initialState, action) { return Object.assign({}, state, { visible: true, activeSuggestionIndex: nextActiveSuggestion, - setSuggestionToSearchField: true + setSuggestionToSearchField: setSuggestionToSearchField }); + } default: return state; diff --git a/src/reducers/filters.js b/src/reducers/filters.js index b3f88de..acba767 100644 --- a/src/reducers/filters.js +++ b/src/reducers/filters.js @@ -102,7 +102,7 @@ const updateHierarchicalFacetState = function(activeHierarchicalFacetState, inde export default function filters(state = initialState, action) { switch (action.type) { - case REGISTER_FILTER: + case REGISTER_FILTER: { let nextAllAvailableFilters = state.allAvailableFilters.slice(); // Range filter. Construct object. Use labelShort if available @@ -121,9 +121,9 @@ export default function filters(state = initialState, action) { return Object.assign({}, state, { allAvailableFilters: nextAllAvailableFilters }); + } - - case TOGGLE_FILTER: + case TOGGLE_FILTER: { let nextActive = Object.assign({}, state.activeFilters); // Remove filter @@ -140,9 +140,9 @@ export default function filters(state = initialState, action) { refreshSearch: action.refreshSearch === false ? false : true, targetFacetGroup: null }); + } - - case SET_RANGE_FILTER: + case SET_RANGE_FILTER: { let nextActiveRanges = Object.assign({}, state.activeRangeFilters); nextActiveRanges[action.field] = {}; if (action.from !== null) { @@ -158,10 +158,9 @@ export default function filters(state = initialState, action) { activeRangeFilters: nextActiveRanges, refreshSearch: true }); + } - - - case CLEAR_SELECTED_FILTERS_AND_FACETS: + case CLEAR_SELECTED_FILTERS_AND_FACETS: { return Object.assign({}, state, { activeFacets: {}, activeFilters: {}, @@ -170,23 +169,23 @@ export default function filters(state = initialState, action) { activeRangeFilters: {}, refreshSearch: action.refreshSearch === false ? false : true }); + } - - case SET_ACTIVE_FILTERS: + case SET_ACTIVE_FILTERS: { return Object.assign({}, state, { activeFilters: action.json || {}, refreshSearch: false }); + } - - case SET_ACTIVE_FACETS: + case SET_ACTIVE_FACETS: { return Object.assign({}, state, { activeFacets: action.json || {}, refreshSearch: false }); + } - - case TOGGLE_FACET_FILTER: + case TOGGLE_FACET_FILTER: { let nextActiveFacets = Object.assign({}, state.activeFacets); if (!nextActiveFacets[action.field]) { @@ -201,23 +200,23 @@ export default function filters(state = initialState, action) { else { nextActiveFacets[action.field][action.value] = 'true'; } - nextActiveFacets['v'] = !nextActiveFacets['v'] ? 1 : nextActiveFacets['v']+1; + nextActiveFacets['v'] = !nextActiveFacets['v'] ? 1 : nextActiveFacets['v'] + 1; return Object.assign({}, state, { activeFacets: nextActiveFacets, refreshSearch: action.refreshSearch === false ? false : true, targetFacetGroup: action.field }); + } - - case TOGGLE_HIERARCHICAL_FACET_FILTER: + case TOGGLE_HIERARCHICAL_FACET_FILTER: { let nextActiveHierarchicalFacets = Object.assign({}, state.activeHierarchicalFacets); let nextIndeterminateHierarchicalFacets = state.indeterminateHierarchicalFacets.slice(); const newFacetStates = updateHierarchicalFacetState(nextActiveHierarchicalFacets, nextIndeterminateHierarchicalFacets, action); nextActiveHierarchicalFacets = newFacetStates.activeHierarchicalFacetState; nextIndeterminateHierarchicalFacets = newFacetStates.indeterminateHierarchicalFacets; - nextActiveHierarchicalFacets['v'] = !nextActiveHierarchicalFacets['v'] ? 1 : nextActiveHierarchicalFacets['v']+1; + nextActiveHierarchicalFacets['v'] = !nextActiveHierarchicalFacets['v'] ? 1 : nextActiveHierarchicalFacets['v'] + 1; return Object.assign({}, state, { activeHierarchicalFacets: nextActiveHierarchicalFacets, @@ -225,6 +224,7 @@ export default function filters(state = initialState, action) { refreshSearch: action.refreshSearch === false ? false : true, targetFacetGroup: action.field }); + } default: return state diff --git a/src/reducers/search.js b/src/reducers/search.js index 2b49f12..72c7bd7 100644 --- a/src/reducers/search.js +++ b/src/reducers/search.js @@ -5,7 +5,6 @@ import { SEARCH_RESULTS, CLEAR_SEARCH_RESULTS, SET_SEARCH_RESULTS_PAGE_URL, - SEARCH_BY_COMPONENT } from '../actions/search'; const initialState = { @@ -37,7 +36,7 @@ export default function search(state = initialState, action) { dropReturningResults: false }); - case SEARCH_RESULTS: + case SEARCH_RESULTS: { if (!state.started) { console.log('WARNING: AddSearch UI not started with the start() function'); } @@ -66,6 +65,7 @@ export default function search(state = initialState, action) { loading: false, callBy: action.requestBy }); + } case SET_SEARCH_RESULTS_PAGE_URL: return Object.assign({}, state, { diff --git a/src/reducers/segmentedsearch.js b/src/reducers/segmentedsearch.js index b914ac0..7587185 100644 --- a/src/reducers/segmentedsearch.js +++ b/src/reducers/segmentedsearch.js @@ -11,7 +11,7 @@ const initialState = { export default function segmentedsearch(state = initialState, action) { switch (action.type) { - case SEGMENTED_SEARCH_START: + case SEGMENTED_SEARCH_START: { let addPendingSegments = [...state.pendingSegments]; if (addPendingSegments.indexOf(action.jsonKey) === -1) { addPendingSegments.push(action.jsonKey); @@ -20,9 +20,9 @@ export default function segmentedsearch(state = initialState, action) { pendingSegments: addPendingSegments, dropReturningResults: false }); + } - - case SEGMENTED_SEARCH_RESULTS: + case SEGMENTED_SEARCH_RESULTS: { if (action.keyword.indexOf(WARMUP_QUERY_PREFIX) === 0 || state.dropReturningResults === true) { return state; } @@ -40,6 +40,7 @@ export default function segmentedsearch(state = initialState, action) { return Object.assign({}, state, segment, { pendingSegments: removePendingSegments }); + } case CLEAR_SEGMENTED_SEARCH_RESULTS: return Object.assign({}, { diff --git a/src/util/handlebars.js b/src/util/handlebars.js index f2b6609..87d572e 100644 --- a/src/util/handlebars.js +++ b/src/util/handlebars.js @@ -67,7 +67,9 @@ export function registerDefaultHelpers() { return currencyFormatter.format(price); } } - catch(err) {} + catch(err) { + // empty + } return (price/100) + ' ' + currency; }); diff --git a/src/util/history.js b/src/util/history.js index 3e48fe8..1e004d2 100644 --- a/src/util/history.js +++ b/src/util/history.js @@ -1,6 +1,4 @@ -/* global window, history */ import { WARMUP_QUERY_PREFIX, MATCH_ALL_QUERY } from '../index'; -import { search } from '../actions/search'; import { setKeyword } from '../actions/keyword'; import { setPage } from '../actions/pagination'; import { setActiveFilters, setActiveFacets } from '../actions/filters'; @@ -96,7 +94,7 @@ function doSetHistory(parameter, value) { export function getQueryParam(url, param) { - const name = param.replace(/[\[\]]/g, "\\$&"); + const name = param.replace(/[\[\]]/g, "\\$&"); // eslint-disable-line const regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"); const results = regex.exec(url); if (!results) return null; @@ -112,7 +110,7 @@ export function initFromURL(client, reduxStore, createFilterObjectFunction, sear handleURLParams(client, reduxStore, qs, createFilterObjectFunction, searchFunction, false, baseFilters); // Browser back button. Re-handle URL - window.onpopstate = (e) => { + window.onpopstate = () => { const qs = queryParamsToObject(window.location.href); handleURLParams(client, reduxStore, qs, createFilterObjectFunction, searchFunction, hasMatchAllQuery, baseFilters); } @@ -221,7 +219,7 @@ export function objectToQueryParams(obj) { let qs = ''; for (let key in obj) { - if (obj.hasOwnProperty(key)) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { if (qs !== '') { qs = qs + '&'; } @@ -243,7 +241,9 @@ export function urlParamToJSON(urlParameter) { try { return JSON.parse(urlParameter); } - catch(error) {} + catch(error) { + // empty + } return null; } diff --git a/webpack.config.js b/webpack.config.js index 24227dc..02db147 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,6 +4,7 @@ const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const webpack = require('webpack'); const PACKAGE = require('./package.json'); const banner = PACKAGE.name + ' ' + PACKAGE.version; +const ESLintPlugin = require('eslint-webpack-plugin'); module.exports = { entry: './index.js', @@ -18,6 +19,7 @@ module.exports = { minimizer: [new TerserJSPlugin({extractComments: false}), new OptimizeCssAssetsPlugin({})], }, plugins: [ + new ESLintPlugin({}), new MiniCssExtractPlugin({ filename: 'addsearch-search-ui.min.css' }), @@ -25,6 +27,11 @@ module.exports = { banner: banner }) ], + resolve: { + alias: { + handlebars: 'handlebars/dist/handlebars.min.js' + } + }, module: { rules: [ {