From 336ccbb41ca2857284e741cb9cbd5ca8f55ad609 Mon Sep 17 00:00:00 2001 From: michalsnik Date: Fri, 4 Jan 2019 15:31:55 +0100 Subject: [PATCH 1/3] Reimplement use-v-on-exact rule --- lib/rules/use-v-on-exact.js | 146 +++++++++++++++++---- lib/rules/valid-v-on.js | 70 +--------- lib/utils/key-aliases.json | 68 ++++++++++ tests/lib/rules/use-v-on-exact.js | 209 ++++++++++++++++++++++++++++-- 4 files changed, 392 insertions(+), 101 deletions(-) create mode 100644 lib/utils/key-aliases.json diff --git a/lib/rules/use-v-on-exact.js b/lib/rules/use-v-on-exact.js index 0dafad708..f9defd885 100644 --- a/lib/rules/use-v-on-exact.js +++ b/lib/rules/use-v-on-exact.js @@ -9,9 +9,100 @@ // ------------------------------------------------------------------------------ const utils = require('../utils') +const keyAliases = require('../utils/key-aliases.json') + +const KEY_MODIFIERS = new Set([ + 'ctrl', 'shift', 'alt', 'meta', 'left', 'right', 'middle', 'esc', 'tab', + 'enter', 'space', 'up', 'left', 'right', 'down', 'delete' +]) + +// https://www.w3.org/TR/uievents-key/ +const KEY_ALIASES = new Set(keyAliases) // ------------------------------------------------------------------------------ -// Rule Definition +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Finds and returns all keys for event directives + * + * @param {Array} attributes Element attributes + * @returns {Array} + */ +function getEventDirectives (attributes) { + return attributes + .filter(attribute => + attribute.directive && + attribute.key.name === 'on' + ) + .map(attribute => ({ + name: attribute.key.argument, + node: attribute.key, + modifiers: attribute.key.modifiers + })) +} + +function isKeyModifier (modifier) { + return ( + KEY_MODIFIERS.has(modifier) || + // keyCode + Number.isInteger(parseInt(modifier, 10)) || + // keyAlias (an Unicode character) + Array.from(modifier).length === 1 || + // keyAlias (special keys) + KEY_ALIASES.has(modifier) + ) +} + +function hasKeyModifier (modifiers) { + return modifiers.some(isKeyModifier) +} + +function groupEvents (events) { + return events.reduce((acc, event) => { + if (acc[event.name]) { + acc[event.name].push(event) + } else { + acc[event.name] = [event] + } + + return acc + }, {}) +} + +function getKeyModifiersString (modifiers) { + return modifiers.filter(isKeyModifier).sort().join(',') +} + +function hasConflictedModifiers (baseEvent, event) { + if ( + event.node === baseEvent.node || + event.modifiers.includes('exact') + ) return false + + const eventModifiers = getKeyModifiersString(event.modifiers) + const baseEventModifiers = getKeyModifiersString(baseEvent.modifiers) + + return ( + baseEvent.modifiers.length >= 1 && + baseEventModifiers !== eventModifiers && + baseEventModifiers.indexOf(eventModifiers) > -1 + ) +} + +function findConflictedEvents (events) { + return events.reduce((acc, event) => { + return [ + ...acc, + ...events + .filter(evt => !acc.find(e => evt === e)) // No duplicates + .filter(hasConflictedModifiers.bind(null, event)) + ] + }, []) +} + +// ------------------------------------------------------------------------------ +// Rule details // ------------------------------------------------------------------------------ module.exports = { @@ -35,31 +126,36 @@ module.exports = { create (context) { return utils.defineTemplateBodyVisitor(context, { VStartTag (node) { - if (node.attributes.length > 1) { - const groups = node.attributes - .map(item => item.key) - .filter(item => item && item.type === 'VDirectiveKey' && item.name === 'on') - .reduce((rv, item) => { - (rv[item.argument] = rv[item.argument] || []).push(item) - return rv - }, {}) - - const directives = Object.keys(groups).map(key => groups[key]) - // const directives = Object.values(groups) // Uncomment after node 6 is dropped - .filter(item => item.length > 1) - for (const group of directives) { - if (group.some(item => item.modifiers.length > 0)) { // check if there are directives with modifiers - const invalid = group.filter(item => item.modifiers.length === 0) - for (const node of invalid) { - context.report({ - node, - loc: node.loc, - message: "Consider to use '.exact' modifier." - }) - } - } - } + if (node.attributes.length === 0) return + + const isCustomComponent = utils.isCustomComponent(node.parent) + let events = getEventDirectives(node.attributes) + + if (isCustomComponent) { + // For components consider only events with `native` modifier + events = events.filter(event => event.modifiers.includes('native')) } + + const grouppedEvents = groupEvents(events) + + Object.keys(grouppedEvents).forEach(eventName => { + const eventsInGroup = grouppedEvents[eventName] + const hasEventWithKeyModifier = eventsInGroup.some(event => + hasKeyModifier(event.modifiers) + ) + + if (!hasEventWithKeyModifier) return + + const conflictedEvents = findConflictedEvents(eventsInGroup) + + conflictedEvents.forEach(e => { + context.report({ + node: e.node, + loc: e.node.loc, + message: "Consider to use '.exact' modifier." + }) + }) + }) } }) } diff --git a/lib/rules/valid-v-on.js b/lib/rules/valid-v-on.js index 333739053..76034844d 100644 --- a/lib/rules/valid-v-on.js +++ b/lib/rules/valid-v-on.js @@ -10,6 +10,7 @@ // ------------------------------------------------------------------------------ const utils = require('../utils') +const keyAliases = require('../utils/key-aliases.json') // ------------------------------------------------------------------------------ // Helpers @@ -24,74 +25,7 @@ const VERB_MODIFIERS = new Set([ 'stop', 'prevent' ]) // https://www.w3.org/TR/uievents-key/ -const KEY_ALIASES = new Set([ - 'unidentified', 'alt', 'alt-graph', 'caps-lock', 'control', 'fn', 'fn-lock', - 'meta', 'num-lock', 'scroll-lock', 'shift', 'symbol', 'symbol-lock', 'hyper', - 'super', 'enter', 'tab', 'arrow-down', 'arrow-left', 'arrow-right', - 'arrow-up', 'end', 'home', 'page-down', 'page-up', 'backspace', 'clear', - 'copy', 'cr-sel', 'cut', 'delete', 'erase-eof', 'ex-sel', 'insert', 'paste', - 'redo', 'undo', 'accept', 'again', 'attn', 'cancel', 'context-menu', 'escape', - 'execute', 'find', 'help', 'pause', 'select', 'zoom-in', 'zoom-out', - 'brightness-down', 'brightness-up', 'eject', 'log-off', 'power', - 'print-screen', 'hibernate', 'standby', 'wake-up', 'all-candidates', - 'alphanumeric', 'code-input', 'compose', 'convert', 'dead', 'final-mode', - 'group-first', 'group-last', 'group-next', 'group-previous', 'mode-change', - 'next-candidate', 'non-convert', 'previous-candidate', 'process', - 'single-candidate', 'hangul-mode', 'hanja-mode', 'junja-mode', 'eisu', - 'hankaku', 'hiragana', 'hiragana-katakana', 'kana-mode', 'kanji-mode', - 'katakana', 'romaji', 'zenkaku', 'zenkaku-hankaku', 'f1', 'f2', 'f3', 'f4', - 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'soft1', 'soft2', 'soft3', - 'soft4', 'channel-down', 'channel-up', 'close', 'mail-forward', 'mail-reply', - 'mail-send', 'media-close', 'media-fast-forward', 'media-pause', - 'media-play-pause', 'media-record', 'media-rewind', 'media-stop', - 'media-track-next', 'media-track-previous', 'new', 'open', 'print', 'save', - 'spell-check', 'key11', 'key12', 'audio-balance-left', 'audio-balance-right', - 'audio-bass-boost-down', 'audio-bass-boost-toggle', 'audio-bass-boost-up', - 'audio-fader-front', 'audio-fader-rear', 'audio-surround-mode-next', - 'audio-treble-down', 'audio-treble-up', 'audio-volume-down', - 'audio-volume-up', 'audio-volume-mute', 'microphone-toggle', - 'microphone-volume-down', 'microphone-volume-up', 'microphone-volume-mute', - 'speech-correction-list', 'speech-input-toggle', 'launch-application1', - 'launch-application2', 'launch-calendar', 'launch-contacts', 'launch-mail', - 'launch-media-player', 'launch-music-player', 'launch-phone', - 'launch-screen-saver', 'launch-spreadsheet', 'launch-web-browser', - 'launch-web-cam', 'launch-word-processor', 'browser-back', - 'browser-favorites', 'browser-forward', 'browser-home', 'browser-refresh', - 'browser-search', 'browser-stop', 'app-switch', 'call', 'camera', - 'camera-focus', 'end-call', 'go-back', 'go-home', 'headset-hook', - 'last-number-redial', 'notification', 'manner-mode', 'voice-dial', 't-v', - 't-v3-d-mode', 't-v-antenna-cable', 't-v-audio-description', - 't-v-audio-description-mix-down', 't-v-audio-description-mix-up', - 't-v-contents-menu', 't-v-data-service', 't-v-input', 't-v-input-component1', - 't-v-input-component2', 't-v-input-composite1', 't-v-input-composite2', - 't-v-input-h-d-m-i1', 't-v-input-h-d-m-i2', 't-v-input-h-d-m-i3', - 't-v-input-h-d-m-i4', 't-v-input-v-g-a1', 't-v-media-context', 't-v-network', - 't-v-number-entry', 't-v-power', 't-v-radio-service', 't-v-satellite', - 't-v-satellite-b-s', 't-v-satellite-c-s', 't-v-satellite-toggle', - 't-v-terrestrial-analog', 't-v-terrestrial-digital', 't-v-timer', - 'a-v-r-input', 'a-v-r-power', 'color-f0-red', 'color-f1-green', - 'color-f2-yellow', 'color-f3-blue', 'color-f4-grey', 'color-f5-brown', - 'closed-caption-toggle', 'dimmer', 'display-swap', 'd-v-r', 'exit', - 'favorite-clear0', 'favorite-clear1', 'favorite-clear2', 'favorite-clear3', - 'favorite-recall0', 'favorite-recall1', 'favorite-recall2', - 'favorite-recall3', 'favorite-store0', 'favorite-store1', 'favorite-store2', - 'favorite-store3', 'guide', 'guide-next-day', 'guide-previous-day', 'info', - 'instant-replay', 'link', 'list-program', 'live-content', 'lock', - 'media-apps', 'media-last', 'media-skip-backward', 'media-skip-forward', - 'media-step-backward', 'media-step-forward', 'media-top-menu', 'navigate-in', - 'navigate-next', 'navigate-out', 'navigate-previous', 'next-favorite-channel', - 'next-user-profile', 'on-demand', 'pairing', 'pin-p-down', 'pin-p-move', - 'pin-p-toggle', 'pin-p-up', 'play-speed-down', 'play-speed-reset', - 'play-speed-up', 'random-toggle', 'rc-low-battery', 'record-speed-next', - 'rf-bypass', 'scan-channels-toggle', 'screen-mode-next', 'settings', - 'split-screen-toggle', 's-t-b-input', 's-t-b-power', 'subtitle', 'teletext', - 'video-mode-next', 'wink', 'zoom-toggle', 'audio-volume-down', - 'audio-volume-up', 'audio-volume-mute', 'browser-back', 'browser-forward', - 'channel-down', 'channel-up', 'context-menu', 'eject', 'end', 'enter', 'home', - 'media-fast-forward', 'media-play', 'media-play-pause', 'media-record', - 'media-rewind', 'media-stop', 'media-next-track', 'media-pause', - 'media-previous-track', 'power', 'unidentified' -]) +const KEY_ALIASES = new Set(keyAliases) function isValidModifier (modifier, customModifiers) { return ( diff --git a/lib/utils/key-aliases.json b/lib/utils/key-aliases.json new file mode 100644 index 000000000..49de3b3d8 --- /dev/null +++ b/lib/utils/key-aliases.json @@ -0,0 +1,68 @@ +[ + "unidentified", "alt", "alt-graph", "caps-lock", "control", "fn", "fn-lock", + "meta", "num-lock", "scroll-lock", "shift", "symbol", "symbol-lock", "hyper", + "super", "enter", "tab", "arrow-down", "arrow-left", "arrow-right", + "arrow-up", "end", "home", "page-down", "page-up", "backspace", "clear", + "copy", "cr-sel", "cut", "delete", "erase-eof", "ex-sel", "insert", "paste", + "redo", "undo", "accept", "again", "attn", "cancel", "context-menu", "escape", + "execute", "find", "help", "pause", "select", "zoom-in", "zoom-out", + "brightness-down", "brightness-up", "eject", "log-off", "power", + "print-screen", "hibernate", "standby", "wake-up", "all-candidates", + "alphanumeric", "code-input", "compose", "convert", "dead", "final-mode", + "group-first", "group-last", "group-next", "group-previous", "mode-change", + "next-candidate", "non-convert", "previous-candidate", "process", + "single-candidate", "hangul-mode", "hanja-mode", "junja-mode", "eisu", + "hankaku", "hiragana", "hiragana-katakana", "kana-mode", "kanji-mode", + "katakana", "romaji", "zenkaku", "zenkaku-hankaku", "f1", "f2", "f3", "f4", + "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "soft1", "soft2", "soft3", + "soft4", "channel-down", "channel-up", "close", "mail-forward", "mail-reply", + "mail-send", "media-close", "media-fast-forward", "media-pause", + "media-play-pause", "media-record", "media-rewind", "media-stop", + "media-track-next", "media-track-previous", "new", "open", "print", "save", + "spell-check", "key11", "key12", "audio-balance-left", "audio-balance-right", + "audio-bass-boost-down", "audio-bass-boost-toggle", "audio-bass-boost-up", + "audio-fader-front", "audio-fader-rear", "audio-surround-mode-next", + "audio-treble-down", "audio-treble-up", "audio-volume-down", + "audio-volume-up", "audio-volume-mute", "microphone-toggle", + "microphone-volume-down", "microphone-volume-up", "microphone-volume-mute", + "speech-correction-list", "speech-input-toggle", "launch-application1", + "launch-application2", "launch-calendar", "launch-contacts", "launch-mail", + "launch-media-player", "launch-music-player", "launch-phone", + "launch-screen-saver", "launch-spreadsheet", "launch-web-browser", + "launch-web-cam", "launch-word-processor", "browser-back", + "browser-favorites", "browser-forward", "browser-home", "browser-refresh", + "browser-search", "browser-stop", "app-switch", "call", "camera", + "camera-focus", "end-call", "go-back", "go-home", "headset-hook", + "last-number-redial", "notification", "manner-mode", "voice-dial", "t-v", + "t-v3-d-mode", "t-v-antenna-cable", "t-v-audio-description", + "t-v-audio-description-mix-down", "t-v-audio-description-mix-up", + "t-v-contents-menu", "t-v-data-service", "t-v-input", "t-v-input-component1", + "t-v-input-component2", "t-v-input-composite1", "t-v-input-composite2", + "t-v-input-h-d-m-i1", "t-v-input-h-d-m-i2", "t-v-input-h-d-m-i3", + "t-v-input-h-d-m-i4", "t-v-input-v-g-a1", "t-v-media-context", "t-v-network", + "t-v-number-entry", "t-v-power", "t-v-radio-service", "t-v-satellite", + "t-v-satellite-b-s", "t-v-satellite-c-s", "t-v-satellite-toggle", + "t-v-terrestrial-analog", "t-v-terrestrial-digital", "t-v-timer", + "a-v-r-input", "a-v-r-power", "color-f0-red", "color-f1-green", + "color-f2-yellow", "color-f3-blue", "color-f4-grey", "color-f5-brown", + "closed-caption-toggle", "dimmer", "display-swap", "d-v-r", "exit", + "favorite-clear0", "favorite-clear1", "favorite-clear2", "favorite-clear3", + "favorite-recall0", "favorite-recall1", "favorite-recall2", + "favorite-recall3", "favorite-store0", "favorite-store1", "favorite-store2", + "favorite-store3", "guide", "guide-next-day", "guide-previous-day", "info", + "instant-replay", "link", "list-program", "live-content", "lock", + "media-apps", "media-last", "media-skip-backward", "media-skip-forward", + "media-step-backward", "media-step-forward", "media-top-menu", "navigate-in", + "navigate-next", "navigate-out", "navigate-previous", "next-favorite-channel", + "next-user-profile", "on-demand", "pairing", "pin-p-down", "pin-p-move", + "pin-p-toggle", "pin-p-up", "play-speed-down", "play-speed-reset", + "play-speed-up", "random-toggle", "rc-low-battery", "record-speed-next", + "rf-bypass", "scan-channels-toggle", "screen-mode-next", "settings", + "split-screen-toggle", "s-t-b-input", "s-t-b-power", "subtitle", "teletext", + "video-mode-next", "wink", "zoom-toggle", "audio-volume-down", + "audio-volume-up", "audio-volume-mute", "browser-back", "browser-forward", + "channel-down", "channel-up", "context-menu", "eject", "end", "enter", "home", + "media-fast-forward", "media-play", "media-play-pause", "media-record", + "media-rewind", "media-stop", "media-next-track", "media-pause", + "media-previous-track", "power", "unidentified" +] diff --git a/tests/lib/rules/use-v-on-exact.js b/tests/lib/rules/use-v-on-exact.js index e93a46601..89abc5622 100644 --- a/tests/lib/rules/use-v-on-exact.js +++ b/tests/lib/rules/use-v-on-exact.js @@ -36,9 +36,6 @@ ruleTester.run('use-v-on-exact', rule, { { code: `` }, - { - code: `` - }, { code: `` }, @@ -49,7 +46,25 @@ ruleTester.run('use-v-on-exact', rule, { code: `` }, { - code: `` + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` }, { code: `` @@ -59,17 +74,195 @@ ruleTester.run('use-v-on-exact', rule, { }, { code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` } ], invalid: [ { - code: ``, - errors: ["Consider to use '.exact' modifier."] + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 4 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 }, + { message: "Consider to use '.exact' modifier.", line: 4 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 4 }, + { message: "Consider to use '.exact' modifier.", line: 5 }, + { message: "Consider to use '.exact' modifier.", line: 6 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 4 }, + { message: "Consider to use '.exact' modifier.", line: 5 }, + { message: "Consider to use '.exact' modifier.", line: 6 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 4 }, + { message: "Consider to use '.exact' modifier.", line: 5 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 4 } + ] + }, + { + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 } + ] }, { - code: ``, - errors: ["Consider to use '.exact' modifier."] + code: ``, + errors: [ + { message: "Consider to use '.exact' modifier.", line: 3 }, + { message: "Consider to use '.exact' modifier.", line: 4 } + ] } ] }) From 39dfc6cf064106616acc30431efc4bb71dea982f Mon Sep 17 00:00:00 2001 From: michalsnik Date: Fri, 4 Jan 2019 15:42:40 +0100 Subject: [PATCH 2/3] Document methods in use-v-on-exact --- lib/rules/use-v-on-exact.js | 44 +++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/rules/use-v-on-exact.js b/lib/rules/use-v-on-exact.js index f9defd885..cb7ed724a 100644 --- a/lib/rules/use-v-on-exact.js +++ b/lib/rules/use-v-on-exact.js @@ -26,8 +26,8 @@ const KEY_ALIASES = new Set(keyAliases) /** * Finds and returns all keys for event directives * - * @param {Array} attributes Element attributes - * @returns {Array} + * @param {array} attributes Element attributes + * @returns {array[object]} [{ name, node, modifiers }] */ function getEventDirectives (attributes) { return attributes @@ -42,6 +42,12 @@ function getEventDirectives (attributes) { })) } +/** + * Checks whether given modifier is KEY + * + * @param {string} modifier + * @returns {boolean} + */ function isKeyModifier (modifier) { return ( KEY_MODIFIERS.has(modifier) || @@ -54,10 +60,24 @@ function isKeyModifier (modifier) { ) } +/** + * Checks whether given any of provided modifiers + * has KEY modifier + * + * @param {array} modifiers + * @returns {boolean} + */ function hasKeyModifier (modifiers) { return modifiers.some(isKeyModifier) } +/** + * Groups all events in object, + * with keys represinting each event name + * + * @param {array} events + * @returns {object} { click: [], keypress: [] } + */ function groupEvents (events) { return events.reduce((acc, event) => { if (acc[event.name]) { @@ -70,10 +90,24 @@ function groupEvents (events) { }, {}) } +/** + * Creates alphabetically sorted string with key modifiers + * + * @param {array[string]} modifiers + * @returns {string} e.g. "alt,ctrl,del,shift" + */ function getKeyModifiersString (modifiers) { return modifiers.filter(isKeyModifier).sort().join(',') } +/** + * Compares two events based on their modifiers + * to detect possible event leakeage + * + * @param {object} baseEvent + * @param {object} event + * @returns {boolean} + */ function hasConflictedModifiers (baseEvent, event) { if ( event.node === baseEvent.node || @@ -90,6 +124,12 @@ function hasConflictedModifiers (baseEvent, event) { ) } +/** + * Searches for events that might conflict with each other + * + * @param {array} events + * @returns {array} conflicted events, without duplicates + */ function findConflictedEvents (events) { return events.reduce((acc, event) => { return [ From 49709537c7c91a8ece95428c8c4c3bfd1556087f Mon Sep 17 00:00:00 2001 From: michalsnik Date: Sat, 5 Jan 2019 00:02:03 +0100 Subject: [PATCH 3/3] Check only system modifiers --- lib/rules/use-v-on-exact.js | 41 +++++--------- tests/lib/rules/use-v-on-exact.js | 89 +++++++++++++++++-------------- 2 files changed, 62 insertions(+), 68 deletions(-) diff --git a/lib/rules/use-v-on-exact.js b/lib/rules/use-v-on-exact.js index cb7ed724a..3e110ec2a 100644 --- a/lib/rules/use-v-on-exact.js +++ b/lib/rules/use-v-on-exact.js @@ -9,15 +9,8 @@ // ------------------------------------------------------------------------------ const utils = require('../utils') -const keyAliases = require('../utils/key-aliases.json') -const KEY_MODIFIERS = new Set([ - 'ctrl', 'shift', 'alt', 'meta', 'left', 'right', 'middle', 'esc', 'tab', - 'enter', 'space', 'up', 'left', 'right', 'down', 'delete' -]) - -// https://www.w3.org/TR/uievents-key/ -const KEY_ALIASES = new Set(keyAliases) +const SYSTEM_MODIFIERS = new Set(['ctrl', 'shift', 'alt', 'meta']) // ------------------------------------------------------------------------------ // Helpers @@ -43,32 +36,24 @@ function getEventDirectives (attributes) { } /** - * Checks whether given modifier is KEY + * Checks whether given modifier is system one * * @param {string} modifier * @returns {boolean} */ -function isKeyModifier (modifier) { - return ( - KEY_MODIFIERS.has(modifier) || - // keyCode - Number.isInteger(parseInt(modifier, 10)) || - // keyAlias (an Unicode character) - Array.from(modifier).length === 1 || - // keyAlias (special keys) - KEY_ALIASES.has(modifier) - ) +function isSystemModifier (modifier) { + return SYSTEM_MODIFIERS.has(modifier) } /** * Checks whether given any of provided modifiers - * has KEY modifier + * has system modifier * * @param {array} modifiers * @returns {boolean} */ -function hasKeyModifier (modifiers) { - return modifiers.some(isKeyModifier) +function hasSystemModifier (modifiers) { + return modifiers.some(isSystemModifier) } /** @@ -91,13 +76,13 @@ function groupEvents (events) { } /** - * Creates alphabetically sorted string with key modifiers + * Creates alphabetically sorted string with system modifiers * * @param {array[string]} modifiers * @returns {string} e.g. "alt,ctrl,del,shift" */ -function getKeyModifiersString (modifiers) { - return modifiers.filter(isKeyModifier).sort().join(',') +function getSystemModifiersString (modifiers) { + return modifiers.filter(isSystemModifier).sort().join(',') } /** @@ -114,8 +99,8 @@ function hasConflictedModifiers (baseEvent, event) { event.modifiers.includes('exact') ) return false - const eventModifiers = getKeyModifiersString(event.modifiers) - const baseEventModifiers = getKeyModifiersString(baseEvent.modifiers) + const eventModifiers = getSystemModifiersString(event.modifiers) + const baseEventModifiers = getSystemModifiersString(baseEvent.modifiers) return ( baseEvent.modifiers.length >= 1 && @@ -181,7 +166,7 @@ module.exports = { Object.keys(grouppedEvents).forEach(eventName => { const eventsInGroup = grouppedEvents[eventName] const hasEventWithKeyModifier = eventsInGroup.some(event => - hasKeyModifier(event.modifiers) + hasSystemModifier(event.modifiers) ) if (!hasEventWithKeyModifier) return diff --git a/tests/lib/rules/use-v-on-exact.js b/tests/lib/rules/use-v-on-exact.js index 89abc5622..be90196b1 100644 --- a/tests/lib/rules/use-v-on-exact.js +++ b/tests/lib/rules/use-v-on-exact.js @@ -82,10 +82,52 @@ ruleTester.run('use-v-on-exact', rule, { code: `` }, { - code: `` + code: `` }, { - code: `` + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` }, { code: `` @@ -176,7 +218,7 @@ ruleTester.run('use-v-on-exact', rule, { code: ``, errors: [ @@ -186,46 +228,13 @@ ruleTester.run('use-v-on-exact', rule, { { code: ``, errors: [ - { message: "Consider to use '.exact' modifier.", line: 4 }, - { message: "Consider to use '.exact' modifier.", line: 5 }, - { message: "Consider to use '.exact' modifier.", line: 6 } - ] - }, - { - code: ``, - errors: [ - { message: "Consider to use '.exact' modifier.", line: 4 }, - { message: "Consider to use '.exact' modifier.", line: 5 }, - { message: "Consider to use '.exact' modifier.", line: 6 } - ] - }, - { - code: ``, - errors: [ - { message: "Consider to use '.exact' modifier.", line: 4 }, - { message: "Consider to use '.exact' modifier.", line: 5 } + { message: "Consider to use '.exact' modifier.", line: 4 } ] }, {