eslint-plugin-vuetify
Advanced tools
Comparing version 1.1.0 to 2.0.0-beta.0
@@ -1,7 +0,5 @@ | ||
'use strict' | ||
'use strict'; | ||
module.exports = { | ||
plugins: [ | ||
'vuetify' | ||
], | ||
plugins: ['vuetify'], | ||
rules: { | ||
@@ -11,7 +9,7 @@ 'vue/valid-v-slot': ['error', { | ||
}], | ||
'vuetify/no-deprecated-classes': 'error', | ||
'vuetify/no-deprecated-colors': 'error', | ||
'vuetify/no-deprecated-components': 'error', | ||
'vuetify/no-deprecated-props': 'error', | ||
'vuetify/no-deprecated-classes': 'error' | ||
'vuetify/no-deprecated-props': 'error' | ||
} | ||
} | ||
}; |
@@ -1,2 +0,2 @@ | ||
'use strict' | ||
'use strict'; | ||
@@ -6,5 +6,4 @@ module.exports = { | ||
rules: { | ||
'vuetify/no-legacy-grid': 'error', | ||
'vuetify/grid-unknown-attributes': 'error' | ||
} | ||
} | ||
}; |
@@ -1,8 +0,8 @@ | ||
'use strict' | ||
const path = require('path') | ||
const requireindex = require('requireindex') | ||
'use strict'; | ||
const path = require('path'); | ||
const requireindex = require('requireindex'); | ||
module.exports = { | ||
configs: requireindex(path.join(__dirname, './configs')), | ||
rules: requireindex(path.join(__dirname, './rules')) | ||
} | ||
}; |
@@ -1,20 +0,28 @@ | ||
'use strict' | ||
'use strict'; | ||
const loadModule = require('../util/load-module') | ||
const { hyphenate, classify, getAttributes } = require('../util/helpers') | ||
const { isGridAttribute } = require('../util/grid-attributes') | ||
const { addClass, removeAttr } = require('../util/fixers') | ||
const { | ||
hyphenate, | ||
classify, | ||
getAttributes | ||
} = require('../util/helpers'); | ||
const { | ||
isGridAttribute | ||
} = require('../util/grid-attributes'); | ||
const { | ||
addClass, | ||
removeAttr | ||
} = require('../util/fixers'); | ||
const { | ||
components | ||
} = require('vuetify'); | ||
const VGrid = { | ||
VContainer: loadModule('vuetify/es5/components/VGrid/VContainer').default, | ||
VRow: loadModule('vuetify/es5/components/VGrid/VRow').default, | ||
VCol: loadModule('vuetify/es5/components/VGrid/VCol').default | ||
} | ||
VContainer: components.VContainer, | ||
VRow: components.VRow, | ||
VCol: components.VCol | ||
}; | ||
const tags = Object.keys(VGrid).reduce((t, k) => { | ||
t[classify(k)] = Object.keys(VGrid[k].options.props).map(p => hyphenate(p)).sort() | ||
t[classify(k)] = Object.keys(VGrid[k].props).map(p => hyphenate(p)).sort(); | ||
return t; | ||
}, {}); | ||
return t | ||
}, {}) | ||
// ------------------------------------------------------------------------------ | ||
@@ -33,12 +41,12 @@ // Rule Definition | ||
}, | ||
create (context) { | ||
create(context) { | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
VElement (element) { | ||
const tag = classify(element.rawName) | ||
if (!Object.keys(tags).includes(tag)) return | ||
const attributes = getAttributes(element).filter(({ name }) => { | ||
return !tags[tag].includes(name) && !isGridAttribute(tag, name) | ||
}) | ||
VElement(element) { | ||
const tag = classify(element.rawName); | ||
if (!Object.keys(tags).includes(tag)) return; | ||
const attributes = getAttributes(element).filter(({ | ||
name | ||
}) => { | ||
return !tags[tag].includes(name) && !isGridAttribute(tag, name); | ||
}); | ||
if (attributes.length) { | ||
@@ -52,19 +60,15 @@ context.report({ | ||
message: 'Attributes are no longer converted into classes', | ||
fix (fixer) { | ||
const fixableAttrs = attributes.map(({ node }) => node) | ||
.filter(attr => !attr.directive) | ||
if (!fixableAttrs.length) return | ||
const className = fixableAttrs.map(node => node.key.rawName).join(' ') | ||
return [ | ||
addClass(context, fixer, element, className), | ||
...fixableAttrs.map(removeAttr.bind(this, context, fixer)) | ||
] | ||
fix(fixer) { | ||
const fixableAttrs = attributes.map(({ | ||
node | ||
}) => node).filter(attr => !attr.directive); | ||
if (!fixableAttrs.length) return; | ||
const className = fixableAttrs.map(node => node.key.rawName).join(' '); | ||
return [addClass(context, fixer, element, className), ...fixableAttrs.map(removeAttr.bind(this, context, fixer))]; | ||
} | ||
}) | ||
}); | ||
} | ||
} | ||
}) | ||
}); | ||
} | ||
} | ||
}; |
@@ -1,52 +0,22 @@ | ||
'use strict' | ||
'use strict'; | ||
const { classify, getAttributes } = require('../util/helpers') | ||
const { removeAttr } = require('../util/fixers') | ||
const { getInstalledVuetifyVersion } = require('../util/get-installed-vuetify-version') | ||
// const spacers = { | ||
// 0: 0, | ||
// 1: 1, | ||
// 2: 2, | ||
// 3: 4, | ||
// 4: 6, | ||
// 5: 12 | ||
// } | ||
/** @type {Map<RegExp, (args: string[]) => string> | Map<string, string>} */ | ||
const replacements = new Map([ | ||
// ['shrink', 'flex-grow-0'], | ||
// ['grow', 'flex-shrink-0'], | ||
[/^text-xs-(left|right|center|justify)$/, ([align]) => `text-${align}`], | ||
// ['child-flex', false], | ||
['scroll-y', 'overflow-y-auto'], | ||
['hide-overflow', 'overflow-hidden'], | ||
['show-overflow', 'overflow-visible'], | ||
['no-wrap', 'text-no-wrap'], | ||
['ellipsis', 'text-truncate'], | ||
['left', 'float-left'], | ||
['right', 'float-right'] | ||
// TODO: only run fixer once | ||
// [/([mp][axytblr])-(\d)/, (type, n) => `${type}-${spacers[n]}`] | ||
]) | ||
const replacements = new Map([[/^rounded-(r|l|tr|tl|br|bl)(.*)$/, ([side, rest]) => { | ||
side = { | ||
r: 'e', | ||
l: 's', | ||
tr: 'te', | ||
tl: 'ts', | ||
br: 'be', | ||
bl: 'bs' | ||
}[side]; | ||
return `rounded-${side}${rest}`; | ||
}], [/^border-([rl])(.*)$/, ([side, rest]) => { | ||
side = { | ||
r: 'e', | ||
l: 's' | ||
}[side]; | ||
return `border-${side}${rest}`; | ||
}], [/^text-xs-(left|right|center|justify)$/, ([align]) => `text-${align}`], ['scroll-y', 'overflow-y-auto'], ['hide-overflow', 'overflow-hidden'], ['show-overflow', 'overflow-visible'], ['no-wrap', 'text-no-wrap'], ['ellipsis', 'text-truncate'], ['left', 'float-left'], ['right', 'float-right'], ['display-4', 'text-h1'], ['display-3', 'text-h2'], ['display-2', 'text-h3'], ['display-1', 'text-h4'], ['headline', 'text-h5'], ['title', 'text-h6'], ['subtitle-1', 'text-subtitle-1'], ['subtitle-2', 'text-subtitle-2'], ['body-1', 'text-body-1'], ['body-2', 'text-body-2'], ['caption', 'text-caption'], ['caption', 'text-caption'], ['overline', 'text-overline']]); | ||
if (getInstalledVuetifyVersion() >= '2.3.0') { | ||
replacements | ||
.set('display-4', 'text-h1') | ||
.set('display-3', 'text-h2') | ||
.set('display-2', 'text-h3') | ||
.set('display-1', 'text-h4') | ||
.set('headline', 'text-h5') | ||
.set('title', 'text-h6') | ||
.set('subtitle-1', 'text-subtitle-1') | ||
.set('subtitle-2', 'text-subtitle-2') | ||
.set('body-1', 'text-body-1') | ||
.set('body-2', 'text-body-2') | ||
.set('caption', 'text-caption') | ||
.set('overline', 'text-overline') | ||
} | ||
// These components treat attributes like classes | ||
const gridComponents = ['VContainer', 'VLayout', 'VFlex', 'VSpacer'] | ||
// ------------------------------------------------------------------------------ | ||
@@ -68,91 +38,30 @@ // Rule Definition | ||
}, | ||
create (context) { | ||
create(context) { | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
VElement (element) { | ||
const tag = classify(element.rawName) | ||
if (!gridComponents.includes(tag)) return | ||
getAttributes(element).forEach(attr => { | ||
for (const replacer of replacements) { | ||
if (typeof replacer[0] === 'string' && replacer[0] === attr.name) { | ||
const replacement = replacer[1] | ||
return context.report({ | ||
messageId: 'replacedWith', | ||
data: { | ||
a: attr.name, | ||
b: replacement | ||
}, | ||
node: attr.node, | ||
fix (fixer) { | ||
return fixer.replaceText(attr.node, replacement) | ||
} | ||
}) | ||
} | ||
if (replacer[0] instanceof RegExp) { | ||
const matches = (replacer[0].exec(attr.name) || []).slice(1) | ||
const replace = replacer[1] | ||
if (matches.length && typeof replace === 'function') { | ||
const replacement = replace(matches) | ||
return context.report({ | ||
messageId: 'replacedWith', | ||
data: { | ||
a: attr.name, | ||
b: replacement | ||
}, | ||
node: attr.node, | ||
fix (fixer) { | ||
return fixer.replaceText(attr.node, replacement) | ||
} | ||
}) | ||
} | ||
} | ||
} | ||
// Remove <v-layout row> as it conflicts with <v-row> styles | ||
// https://github.com/vuetifyjs/vuetify/commit/3f435b5a | ||
if (tag === 'VLayout' && attr.name === 'row') { | ||
return context.report({ | ||
node: attr.node, | ||
message: `Don't use "row" on <v-layout>, see https://github.com/vuetifyjs/vuetify/commit/3f435b5a`, | ||
fix (fixer) { | ||
if (!attr.node.directive) return removeAttr(context, fixer, attr.node) | ||
} | ||
}) | ||
} | ||
}) | ||
}, | ||
'VAttribute[key.name="class"]' (node) { | ||
if (!node.value || !node.value.value) return | ||
const classes = node.value.value.split(/\s+/).filter(s => !!s) | ||
const source = context.getSourceCode() | ||
const changed = [] | ||
'VAttribute[key.name="class"]'(node) { | ||
if (!node.value || !node.value.value) return; | ||
const classes = node.value.value.split(/\s+/).filter(s => !!s); | ||
const source = context.getSourceCode(); | ||
const changed = []; | ||
classes.forEach(className => { | ||
for (const replacer of replacements) { | ||
if (typeof replacer[0] === 'string' && replacer[0] === className) { | ||
return changed.push([className, replacer[1]]) | ||
return changed.push([className, replacer[1]]); | ||
} | ||
if (replacer[0] instanceof RegExp) { | ||
const matches = (replacer[0].exec(className) || []).slice(1) | ||
const replace = replacer[1] | ||
const matches = (replacer[0].exec(className) || []).slice(1); | ||
const replace = replacer[1]; | ||
if (matches.length && typeof replace === 'function') { | ||
return changed.push([className, replace(matches)]) | ||
return changed.push([className, replace(matches)]); | ||
} | ||
} | ||
} | ||
}) | ||
}); | ||
changed.forEach(change => { | ||
const idx = node.value.value.indexOf(change[0]) + 1 | ||
const range = [ | ||
node.value.range[0] + idx, | ||
node.value.range[0] + idx + change[0].length | ||
] | ||
const idx = node.value.value.indexOf(change[0]) + 1; | ||
const range = [node.value.range[0] + idx, node.value.range[0] + idx + change[0].length]; | ||
const loc = { | ||
start: source.getLocFromIndex(range[0]), | ||
end: source.getLocFromIndex(range[1]) | ||
} | ||
}; | ||
context.report({ | ||
@@ -165,10 +74,10 @@ loc, | ||
}, | ||
fix (fixer) { | ||
return fixer.replaceTextRange(range, change[1]) | ||
fix(fixer) { | ||
return fixer.replaceTextRange(range, change[1]); | ||
} | ||
}) | ||
}) | ||
}); | ||
}); | ||
} | ||
}) | ||
}); | ||
} | ||
} | ||
}; |
@@ -1,12 +0,13 @@ | ||
'use strict' | ||
'use strict'; | ||
const { hyphenate, classify } = require('../util/helpers') | ||
const { getInstalledVuetifyVersion } = require('../util/get-installed-vuetify-version') | ||
const { | ||
hyphenate, | ||
classify | ||
} = require('../util/helpers'); | ||
const replacements = { | ||
VListTile: 'v-list-item', | ||
VListTileAction: 'v-list-item-action', | ||
VListTileAvatar: 'v-list-item-avatar', | ||
VListTileAvatar: false, | ||
VListTileActionText: 'v-list-item-action-text', | ||
VListTileContent: 'v-list-item-content', | ||
VListTileContent: false, | ||
VListTileTitle: 'v-list-item-title', | ||
@@ -16,12 +17,27 @@ VListTileSubTitle: 'v-list-item-subtitle', | ||
VToolbarSideIcon: 'v-app-bar-nav-icon', | ||
// Possible typos | ||
VListItemSubTitle: 'v-list-item-subtitle', | ||
VListTileSubtitle: 'v-list-item-subtitle' | ||
} | ||
VListTileSubtitle: 'v-list-item-subtitle', | ||
VContent: 'v-main', | ||
VBannerActions: false, | ||
VBannerText: false, | ||
VBottomSheet: false, | ||
VCalendar: false, | ||
VData: false, | ||
VDataIterator: false, | ||
VDataTable: false, | ||
VDatePicker: false, | ||
VOtpInput: false, | ||
VOverflowBtn: false, | ||
VPicker: false, | ||
VSimpleCheckbox: 'v-checkbox-btn', | ||
VSkeletonLoader: false, | ||
VSparkline: false, | ||
VSpeedDial: false, | ||
VStepper: false, | ||
VTimePicker: false, | ||
VTreeview: false, | ||
VVirtualScroll: false | ||
}; | ||
if (getInstalledVuetifyVersion() >= '2.3.0') { | ||
replacements.VContent = 'v-main' | ||
} | ||
// ------------------------------------------------------------------------------ | ||
@@ -44,11 +60,9 @@ // Rule Definition | ||
}, | ||
create (context) { | ||
create(context) { | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
VElement (element) { | ||
const tag = classify(element.rawName) | ||
const tokens = context.parserServices.getTemplateBodyTokenStore() | ||
VElement(element) { | ||
const tag = classify(element.rawName); | ||
const tokens = context.parserServices.getTemplateBodyTokenStore(); | ||
if (Object.prototype.hasOwnProperty.call(replacements, tag)) { | ||
const replacement = replacements[tag] | ||
const replacement = replacements[tag]; | ||
if (replacement) { | ||
@@ -62,15 +76,12 @@ context.report({ | ||
}, | ||
fix (fixer) { | ||
const open = tokens.getFirstToken(element.startTag) | ||
const endTag = element.endTag | ||
fix(fixer) { | ||
const open = tokens.getFirstToken(element.startTag); | ||
const endTag = element.endTag; | ||
if (!endTag) { | ||
return fixer.replaceText(open, `<${replacement}`) | ||
return fixer.replaceText(open, `<${replacement}`); | ||
} | ||
const endTagOpen = tokens.getFirstToken(endTag) | ||
return [ | ||
fixer.replaceText(open, `<${replacement}`), | ||
fixer.replaceText(endTagOpen, `</${replacement}`) | ||
] | ||
const endTagOpen = tokens.getFirstToken(endTag); | ||
return [fixer.replaceText(open, `<${replacement}`), fixer.replaceText(endTagOpen, `</${replacement}`)]; | ||
} | ||
}) | ||
}); | ||
} else { | ||
@@ -80,9 +91,11 @@ context.report({ | ||
messageId: 'removed', | ||
data: { name: hyphenate(tag) } | ||
}) | ||
data: { | ||
name: hyphenate(tag) | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
}) | ||
}); | ||
} | ||
} | ||
}; |
@@ -1,112 +0,805 @@ | ||
'use strict' | ||
'use strict'; | ||
const { hyphenate, classify, mergeDeep } = require('../util/helpers') | ||
const { getInstalledVuetifyVersion } = require('../util/get-installed-vuetify-version') | ||
const { | ||
hyphenate, | ||
classify | ||
} = require('../util/helpers'); | ||
const size = { | ||
maxHeight: false, | ||
maxWidth: false, | ||
minHeight: false, | ||
minWidth: false | ||
}; | ||
const sizes = { | ||
large: { | ||
name: 'size', | ||
value: 'large' | ||
}, | ||
medium: { | ||
name: 'size', | ||
value: 'medium' | ||
}, | ||
small: { | ||
name: 'size', | ||
value: 'small' | ||
}, | ||
xLarge: { | ||
name: 'size', | ||
value: 'x-large' | ||
}, | ||
xSmall: { | ||
name: 'size', | ||
value: 'x-small' | ||
} | ||
}; | ||
const inputs = { | ||
appendOuterIcon: 'append-icon', | ||
backgroundColor: 'bg-color', | ||
box: { | ||
name: 'variant', | ||
value: 'filled' | ||
}, | ||
errorCount: 'max-errors', | ||
filled: { | ||
name: 'variant', | ||
value: 'filled' | ||
}, | ||
flat: false, | ||
fullWidth: false, | ||
height: false, | ||
hideSpinButtons: false, | ||
loaderHeight: false, | ||
outline: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
outlined: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
rounded: false, | ||
shaped: false, | ||
solo: { | ||
name: 'variant', | ||
value: 'solo' | ||
}, | ||
soloInverted: false, | ||
success: false, | ||
successMessages: false, | ||
validateOnBlur: { | ||
name: 'validate-on', | ||
value: 'blur' | ||
}, | ||
value: 'model-value' | ||
}; | ||
const select = { | ||
allowOverflow: false, | ||
attach: { | ||
custom: ':menu-props="{ attach: true }"' | ||
}, | ||
autoSelectFirst: false, | ||
cacheItems: false, | ||
deletableChips: 'closable-chips', | ||
disableLookup: false, | ||
itemColor: { | ||
custom: 'item-props.color' | ||
}, | ||
itemDisabled: { | ||
custom: 'item-props.disabled' | ||
}, | ||
itemText: 'item-title', | ||
searchInput: 'search', | ||
smallChips: false, | ||
valueComparator: false, | ||
filter: 'customFilter', | ||
...inputs | ||
}; | ||
const theme = { | ||
dark: false, | ||
light: false | ||
}; | ||
const link = { | ||
append: false, | ||
exactActiveClass: false, | ||
exactPath: false, | ||
nuxt: false | ||
}; | ||
const overlay = { | ||
hideOverlay: { | ||
name: 'scrim', | ||
value: false | ||
}, | ||
internalActivator: false, | ||
overlayColor: { | ||
name: 'scrim', | ||
value: value => value | ||
}, | ||
overlayOpacity: false, | ||
value: 'model-value', | ||
returnValue: false | ||
}; | ||
const replacements = { | ||
VBtn: { | ||
outline: 'outlined', | ||
flat: 'text', | ||
round: 'rounded' | ||
VAppBar: { | ||
app: false, | ||
clippedLeft: false, | ||
clippedRight: false, | ||
collapseOnScroll: false, | ||
elevateOnScroll: false, | ||
fadeImgOnScroll: false, | ||
fixed: false, | ||
hideOnScroll: false, | ||
invertedScroll: false, | ||
outlined: 'border', | ||
prominent: false, | ||
scrollOffScreen: false, | ||
scrollTarget: false, | ||
scrollThreshold: false, | ||
shaped: false, | ||
short: false, | ||
shrinkOnScroll: false, | ||
tile: false, | ||
width: false, | ||
...theme, | ||
...size | ||
}, | ||
VAlert: { | ||
outline: 'outlined' | ||
border: { | ||
name: 'border', | ||
value: value => ({ | ||
right: 'end', | ||
left: 'start' | ||
})[value] | ||
}, | ||
outline: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
coloredBorder: { | ||
custom: 'border-color' | ||
}, | ||
dismissible: 'closable', | ||
mode: false, | ||
origin: false, | ||
outlined: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
shaped: false, | ||
tile: { | ||
name: 'rounded', | ||
value: 0 | ||
}, | ||
transition: false, | ||
...theme | ||
}, | ||
VAvatar: { | ||
height: { | ||
custom: 'size' | ||
}, | ||
width: { | ||
custom: 'size' | ||
}, | ||
left: 'start', | ||
right: 'end', | ||
...size | ||
}, | ||
VBadge: { | ||
avatar: false, | ||
mode: false, | ||
origin: false, | ||
overlap: false | ||
}, | ||
VBanner: { | ||
app: false, | ||
iconColor: false, | ||
mobileBreakPoint: false, | ||
outlined: false, | ||
shaped: false, | ||
value: false | ||
}, | ||
VBottomNavigation: { | ||
active: { custom: 'value or v-model' } | ||
activeClass: 'selected-class', | ||
app: false, | ||
fixed: false, | ||
hideOnScroll: false, | ||
inputValue: 'model-value', | ||
scrollTarget: false, | ||
scrollThreshold: false, | ||
width: false, | ||
...size | ||
}, | ||
VBreadcrumbs: { | ||
large: false, | ||
...theme | ||
}, | ||
VBreadcrumbsItem: { | ||
link: false, | ||
ripple: false, | ||
...link | ||
}, | ||
VBtn: { | ||
activeClass: 'selected-class', | ||
bottom: { | ||
name: 'location', | ||
value: 'bottom' | ||
}, | ||
depressed: { | ||
name: 'variant', | ||
value: 'depressed' | ||
}, | ||
fab: false, | ||
flat: { | ||
name: 'variant', | ||
value: 'flat' | ||
}, | ||
inputValue: false, | ||
left: { | ||
name: 'location', | ||
value: 'left' | ||
}, | ||
link: false, | ||
outline: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
outlined: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
plain: { | ||
name: 'variant', | ||
value: 'plain' | ||
}, | ||
retainFocusOnClick: false, | ||
right: { | ||
name: 'location', | ||
value: 'right' | ||
}, | ||
round: 'rounded', | ||
shaped: false, | ||
text: { | ||
name: 'variant', | ||
value: 'text' | ||
}, | ||
tile: false, | ||
top: { | ||
name: 'location', | ||
value: 'top' | ||
}, | ||
...link, | ||
...theme, | ||
...sizes | ||
}, | ||
VBtnToggle: { | ||
activeClass: 'selected-class', | ||
backgroundColor: false, | ||
borderless: false, | ||
dense: { | ||
custom: 'density' | ||
}, | ||
shaped: false, | ||
tile: { | ||
name: 'rounded', | ||
value: 0 | ||
}, | ||
value: 'model-value', | ||
valueComparator: false, | ||
...theme | ||
}, | ||
VCard: { | ||
activeClass: false, | ||
loaderHeight: false, | ||
outlined: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
raised: { | ||
name: 'elevation', | ||
value: 8 | ||
}, | ||
shaped: false, | ||
tile: { | ||
name: 'rounded', | ||
value: 0 | ||
}, | ||
...link | ||
}, | ||
VCarousel: { | ||
hideControls: { custom: ':show-arrows="false"' } | ||
activeClass: 'selected-class', | ||
max: false, | ||
multiple: false, | ||
progressColor: { | ||
custom: 'progress="<color>"' | ||
}, | ||
showArrowsOnHover: { | ||
name: 'show-arrows', | ||
value: 'hover' | ||
}, | ||
touchless: false, | ||
valueComparator: false, | ||
vertical: { | ||
name: 'direction', | ||
value: 'vertical' | ||
}, | ||
value: 'model-value', | ||
...theme | ||
}, | ||
VCarouselItem: { | ||
activeClass: 'selected-class', | ||
exact: false, | ||
href: false, | ||
link: false, | ||
replace: false, | ||
ripple: false, | ||
target: false, | ||
to: false, | ||
...link | ||
}, | ||
VCheckbox: { | ||
backgroundColor: false, | ||
errorCount: 'max-errors', | ||
hideSpinButtons: false, | ||
hint: false, | ||
inputValue: 'model-value', | ||
offIcon: 'false-icon', | ||
onIcon: 'true-icon', | ||
offValue: 'false-value', | ||
onValue: 'true-value', | ||
success: false, | ||
successMessages: false, | ||
validateOnBlur: { | ||
name: 'validate-on', | ||
value: 'blur' | ||
} | ||
}, | ||
VChip: { | ||
outline: 'outlined', | ||
selected: 'value' | ||
active: false, | ||
close: 'cloasable', | ||
inputValue: 'model-value', | ||
outline: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
outlined: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
selected: 'value', | ||
textColor: false, | ||
...link | ||
}, | ||
VDataIterator: { | ||
expand: 'showExpand', | ||
contentClass: false, | ||
contentProps: false, | ||
contentTag: false, | ||
disableInitialSort: 'sortBy', | ||
filter: 'customFilter', | ||
pagination: 'options', | ||
totalItems: 'serverItemsLength', | ||
hideActions: 'hideDefaultFooter', | ||
rowsPerPageItems: { custom: 'footer-props.itemsPerPageOptions' }, | ||
rowsPerPageText: { custom: 'footer-props.itemsPerPageText' }, | ||
prevIcon: { custom: 'footer-props.prevIcon' }, | ||
nextIcon: { custom: 'footer-props.nextIcon' } | ||
VChipGroup: { | ||
activeClass: 'selected-class', | ||
centerActive: false, | ||
mobileBreakPoint: false, | ||
nextIcon: false, | ||
prevIcon: false, | ||
showArrows: false, | ||
value: 'model-value' | ||
}, | ||
VDataTable: { | ||
sortIcon: { custom: 'header-props.sortIcon' }, | ||
hideHeaders: 'hideDefaultHeader', | ||
selectAll: 'showSelect' | ||
VColorPicker: { | ||
flat: false, | ||
hideModeSwitch: false, | ||
value: 'model-value' | ||
}, | ||
VExpansionPanels: { | ||
expand: 'multiple' | ||
activeClass: 'selected-class', | ||
flat: false, | ||
focusable: false, | ||
hover: false, | ||
tile: false, | ||
value: 'model-value', | ||
valueComparator: false | ||
}, | ||
VTextField: { | ||
box: 'filled', | ||
outline: 'outlined', | ||
mask: false | ||
...inputs | ||
}, | ||
VTextarea: { | ||
box: 'filled', | ||
outline: 'outlined', | ||
mask: false | ||
...inputs | ||
}, | ||
VFileInput: { | ||
type: false, | ||
...inputs | ||
}, | ||
VSelect: { | ||
box: 'filled', | ||
combobox: { custom: '<v-combobox />' }, | ||
outline: 'outlined' | ||
...select | ||
}, | ||
VAutocomplete: { | ||
box: 'filled', | ||
outline: 'outlined' | ||
...select | ||
}, | ||
VCombobox: { | ||
box: 'filled', | ||
outline: 'outlined' | ||
...select | ||
}, | ||
VInput: { | ||
...inputs | ||
}, | ||
VDialog: { | ||
...overlay | ||
}, | ||
VMenu: { | ||
allowOverflow: false, | ||
auto: false, | ||
bottom: { | ||
custom: 'location and origin' | ||
}, | ||
closeOnClick: { | ||
name: 'persistent', | ||
value: true | ||
}, | ||
left: { | ||
custom: 'location and origin' | ||
}, | ||
nudgeBottom: { | ||
custom: 'offset' | ||
}, | ||
nudgeLeft: { | ||
custom: 'offset' | ||
}, | ||
nudgeRight: { | ||
custom: 'offset' | ||
}, | ||
nudgeTop: { | ||
custom: 'offset' | ||
}, | ||
offsetOverflow: false, | ||
offsetX: false, | ||
offsetY: false, | ||
positionX: false, | ||
positionY: false, | ||
right: { | ||
custom: 'location and origin' | ||
}, | ||
rounded: false, | ||
tile: false, | ||
top: { | ||
custom: 'location and origin' | ||
}, | ||
value: 'model-value', | ||
...overlay | ||
}, | ||
VFooter: { | ||
fixed: false, | ||
outlined: false, | ||
padless: false, | ||
shaped: false, | ||
tile: false, | ||
width: false, | ||
...size | ||
}, | ||
VForm: { | ||
value: 'model-value' | ||
}, | ||
VHover: { | ||
value: 'model-value' | ||
}, | ||
VIcon: { | ||
dense: false, | ||
disabled: false, | ||
left: 'start', | ||
right: 'end' | ||
}, | ||
VImg: { | ||
contain: { | ||
custom: 'cover' | ||
}, | ||
contentClass: false, | ||
height: false, | ||
position: false, | ||
...theme, | ||
...size | ||
}, | ||
VItemGroup: { | ||
activeClass: 'selected-class', | ||
value: 'model-value', | ||
valueComparator: false | ||
}, | ||
VItem: { | ||
activeClass: 'selected-class' | ||
}, | ||
VLazy: { | ||
value: 'model-value' | ||
}, | ||
VList: { | ||
expand: false, | ||
flat: false, | ||
outlined: false, | ||
subheader: false, | ||
threeLine: { | ||
name: 'lines', | ||
value: 'three' | ||
}, | ||
twoLine: { | ||
name: 'lines', | ||
value: 'two' | ||
}, | ||
tile: false | ||
}, | ||
VListGroup: { | ||
activeClass: false, | ||
disabled: false, | ||
eager: false, | ||
group: false, | ||
noAction: false, | ||
ripple: false, | ||
subGroup: false | ||
}, | ||
VListItem: { | ||
avatar: false | ||
append: false, | ||
ripple: false, | ||
selectable: { | ||
custom: 'value' | ||
}, | ||
threeLine: { | ||
name: 'lines', | ||
value: 'three' | ||
}, | ||
twoLine: { | ||
name: 'lines', | ||
value: 'two' | ||
}, | ||
inputValue: { | ||
custom: 'active' | ||
}, | ||
...link | ||
}, | ||
VToolbar: { | ||
app: { custom: '<v-app-bar app />' }, | ||
manualScroll: { custom: '<v-app-bar :value="false" />' }, | ||
clippedLeft: { custom: '<v-app-bar clipped-left />' }, | ||
clippedRight: { custom: '<v-app-bar clipped-right />' }, | ||
invertedScroll: { custom: '<v-app-bar inverted-scroll />' }, | ||
scrollOffScreen: { custom: '<v-app-bar scroll-off-screen />' }, | ||
scrollTarget: { custom: '<v-app-bar scroll-target />' }, | ||
scrollThreshold: { custom: '<v-app-bar scroll-threshold />' }, | ||
card: 'flat' | ||
VNavigationDrawer: { | ||
app: false, | ||
bottom: { | ||
name: 'location', | ||
value: 'bottom' | ||
}, | ||
clipped: false, | ||
fixed: false, | ||
height: false, | ||
hideOverlay: { | ||
name: 'scrim', | ||
value: false | ||
}, | ||
miniVariant: 'rail', | ||
miniVariantWidth: 'rail-width', | ||
mobileBreakPoint: false, | ||
overlayColor: { | ||
name: 'scrim', | ||
value: value => value | ||
}, | ||
overlayOpacity: false, | ||
right: { | ||
name: 'location', | ||
value: 'right' | ||
}, | ||
src: 'image', | ||
stateless: false, | ||
value: 'model-value' | ||
}, | ||
VOverlay: { | ||
color: { | ||
name: 'scrim', | ||
value: value => value | ||
}, | ||
opacity: false, | ||
value: 'model-value' | ||
}, | ||
VPagination: { | ||
circle: 'rounded', | ||
value: 'model-value', | ||
wrapperAriaLabel: 'aria-label' | ||
}, | ||
VProgressCircular: { | ||
button: false, | ||
value: 'model-value' | ||
}, | ||
VProgressLinear: { | ||
absolute: false, | ||
backgroundColor: 'bg-color', | ||
backgroundOpacity: 'bg-opacity', | ||
bottom: false, | ||
fixed: false, | ||
query: false, | ||
top: false, | ||
value: 'model-value' | ||
}, | ||
VRadio: { | ||
activeClass: 'false', | ||
offIcon: 'false-icon', | ||
onIcon: 'true-icon', | ||
offValue: 'false-value', | ||
onValue: 'true-value' | ||
}, | ||
VRadioGroup: { | ||
activeClass: false, | ||
backgroundColor: false, | ||
column: false, | ||
multiple: false, | ||
...inputs | ||
}, | ||
VSlider: { | ||
backgroundColor: false, | ||
tickLabels: 'ticks', | ||
ticks: { | ||
custom: 'show-ticks' | ||
}, | ||
vertical: { | ||
name: 'direction', | ||
value: 'vertical' | ||
}, | ||
height: false, | ||
loading: false, | ||
inverseLabel: false, | ||
...inputs, | ||
...theme | ||
}, | ||
VRangeSlider: { | ||
backgroundColor: false, | ||
tickLabels: 'ticks', | ||
ticks: { | ||
custom: 'show-ticks' | ||
}, | ||
vertical: { | ||
name: 'direction', | ||
value: 'vertical' | ||
}, | ||
height: false, | ||
loading: false, | ||
inverseLabel: false, | ||
...inputs, | ||
...theme | ||
}, | ||
VRating: { | ||
backgroundColor: false, | ||
closeDelay: false, | ||
halfIcon: false, | ||
iconLabel: 'item-aria-label', | ||
large: false, | ||
openDelay: false, | ||
value: 'model-value', | ||
...sizes | ||
}, | ||
VSheet: { | ||
outlined: false, | ||
shaped: false, | ||
tile: false | ||
}, | ||
VSlideGroup: { | ||
activeClass: 'selected-class', | ||
mobileBreakPoint: false, | ||
value: 'model-value', | ||
valueComparator: false, | ||
...theme | ||
}, | ||
VSnackbar: { | ||
autoHeight: false | ||
} | ||
} | ||
if (getInstalledVuetifyVersion() >= '2.3.0') { | ||
mergeDeep(replacements, { | ||
VBanner: { | ||
mobileBreakPoint: 'mobileBreakpoint' | ||
app: false, | ||
bottom: { | ||
name: 'location', | ||
value: 'bottom' | ||
}, | ||
VDataIterator: { | ||
mobileBreakPoint: 'mobileBreakpoint' | ||
centered: { | ||
custom: 'location' | ||
}, | ||
VNavigationDrawer: { | ||
mobileBreakPoint: 'mobileBreakpoint' | ||
elevation: false, | ||
left: { | ||
name: 'location', | ||
value: 'left' | ||
}, | ||
VSlideGroup: { | ||
mobileBreakPoint: 'mobileBreakpoint' | ||
outlined: { | ||
name: 'variant', | ||
value: 'outlined' | ||
}, | ||
VTabs: { | ||
mobileBreakPoint: 'mobileBreakpoint' | ||
right: { | ||
name: 'location', | ||
value: 'right' | ||
}, | ||
shaped: false, | ||
text: false, | ||
tile: false, | ||
top: { | ||
name: 'location', | ||
value: 'top' | ||
}, | ||
value: 'model-value' | ||
}, | ||
VSwitch: { | ||
...inputs | ||
}, | ||
VSystemBar: { | ||
app: false, | ||
fixed: false, | ||
lightsOut: false | ||
}, | ||
VTabs: { | ||
activeClass: false, | ||
alignWithTitle: { | ||
name: 'align-tabs', | ||
value: 'title' | ||
}, | ||
backgroundColor: 'bg-color', | ||
value: 'model-value', | ||
...theme | ||
}, | ||
VTab: { | ||
activeClass: 'selected-class', | ||
link: false, | ||
...link | ||
}, | ||
VThemeProvider: { | ||
root: false | ||
}, | ||
VTimeline: { | ||
alignTop: { | ||
name: 'align', | ||
value: 'top' | ||
}, | ||
reverse: false | ||
}, | ||
VTimelineItem: { | ||
color: 'dot-color', | ||
left: false, | ||
right: false, | ||
...theme, | ||
...sizes | ||
}, | ||
VToolbar: { | ||
bottom: false, | ||
outlined: false, | ||
prominent: false, | ||
shaped: false, | ||
short: false, | ||
src: 'image', | ||
tile: false, | ||
width: false, | ||
...size | ||
}, | ||
VToolbarItems: { | ||
tag: false | ||
}, | ||
VTooltip: { | ||
allowOverflow: false, | ||
bottom: { | ||
custom: 'location and origin' | ||
}, | ||
closeOnClick: { | ||
name: 'persistent', | ||
value: true | ||
}, | ||
left: { | ||
custom: 'location and origin' | ||
}, | ||
nudgeBottom: { | ||
custom: 'offset' | ||
}, | ||
nudgeLeft: { | ||
custom: 'offset' | ||
}, | ||
nudgeRight: { | ||
custom: 'offset' | ||
}, | ||
nudgeTop: { | ||
custom: 'offset' | ||
}, | ||
positionX: false, | ||
positionY: false, | ||
right: { | ||
custom: 'location and origin' | ||
}, | ||
top: { | ||
custom: 'location and origin' | ||
}, | ||
value: 'model-value', | ||
...overlay | ||
}, | ||
VWindow: { | ||
activeClass: 'selected-class', | ||
showArrowsOnHover: false, | ||
touchless: false, | ||
value: 'model-value', | ||
valueComparator: false, | ||
vertical: { | ||
name: 'direction', | ||
value: 'vertical' | ||
} | ||
}) | ||
} | ||
}, | ||
VWindowItem: { | ||
activeClass: 'selected-class' | ||
} | ||
}; | ||
mergeDeep(replacements.VDataTable, replacements.VDataIterator) | ||
// ------------------------------------------------------------------------------ | ||
@@ -129,22 +822,10 @@ // Rule Definition | ||
}, | ||
create (context) { | ||
create(context) { | ||
return context.parserServices.defineTemplateBodyVisitor({ | ||
VAttribute (attr) { | ||
if ( | ||
attr.directive && | ||
(attr.key.name.name !== 'bind' || !attr.key.argument) | ||
) return | ||
const tag = classify(attr.parent.parent.rawName) | ||
if (!Object.keys(replacements).includes(tag)) return | ||
const propName = attr.directive | ||
? hyphenate(attr.key.argument.rawName) | ||
: hyphenate(attr.key.rawName) | ||
const propNameNode = attr.directive | ||
? attr.key.argument | ||
: attr | ||
VAttribute(attr) { | ||
if (attr.directive && (attr.key.name.name !== 'bind' || !attr.key.argument)) return; | ||
const tag = classify(attr.parent.parent.rawName); | ||
if (!Object.keys(replacements).includes(tag)) return; | ||
const propName = attr.directive ? hyphenate(attr.key.argument.rawName) : hyphenate(attr.key.rawName); | ||
const propNameNode = attr.directive ? attr.key.argument : attr; | ||
Object.entries(replacements[tag]).forEach(([test, replace]) => { | ||
@@ -155,5 +836,7 @@ if (hyphenate(test) === propName) { | ||
messageId: 'removed', | ||
data: { name: propName }, | ||
data: { | ||
name: propName | ||
}, | ||
node: propNameNode | ||
}) | ||
}); | ||
} else if (typeof replace === 'string') { | ||
@@ -167,7 +850,9 @@ context.report({ | ||
node: propNameNode, | ||
fix (fixer) { | ||
return fixer.replaceText(propNameNode, replace) | ||
fix(fixer) { | ||
return fixer.replaceText(propNameNode, replace); | ||
} | ||
}) | ||
} else if (typeof replace === 'object' && Object.hasOwnProperty.call(replace, 'custom')) { | ||
}); | ||
} else if (typeof replace === 'object' && 'name' in replace && 'value' in replace) { | ||
const value = typeof replace.value === 'function' ? replace.value(attr.value?.value) : replace.value; | ||
if (value == null) return; | ||
context.report({ | ||
@@ -177,12 +862,29 @@ messageId: 'replacedWith', | ||
a: propName, | ||
b: `${replace.name}="${value}"` | ||
}, | ||
node: propNameNode, | ||
fix(fixer) { | ||
if (attr.directive) { | ||
const expression = attr.value.expression.raw; | ||
return [fixer.replaceText(propNameNode, replace.name), fixer.replaceText(attr.value, `"${expression} && '${value}'"`)]; | ||
} else { | ||
return fixer.replaceText(attr, `${replace.name}="${value}"`); | ||
} | ||
} | ||
}); | ||
} else if (typeof replace === 'object' && 'custom' in replace) { | ||
context.report({ | ||
messageId: 'replacedWith', | ||
data: { | ||
a: propName, | ||
b: replace.custom | ||
}, | ||
node: propNameNode | ||
}) | ||
}); | ||
} | ||
} | ||
}) | ||
}); | ||
} | ||
}) | ||
}); | ||
} | ||
} | ||
}; |
@@ -1,30 +0,26 @@ | ||
function addClass (context, fixer, element, className) { | ||
const classNode = element.startTag.attributes.find(attr => attr.key.name === 'class') | ||
"use strict"; | ||
function addClass(context, fixer, element, className) { | ||
const classNode = element.startTag.attributes.find(attr => attr.key.name === 'class'); | ||
if (classNode && classNode.value) { | ||
// class="" | ||
return fixer.replaceText(classNode.value, `"${classNode.value.value} ${className}"`) | ||
return fixer.replaceText(classNode.value, `"${classNode.value.value} ${className}"`); | ||
} else if (classNode) { | ||
// class | ||
return fixer.insertTextAfter(classNode, `="${className}"`) | ||
return fixer.insertTextAfter(classNode, `="${className}"`); | ||
} else { | ||
// nothing | ||
return fixer.insertTextAfter( | ||
context.parserServices.getTemplateBodyTokenStore().getFirstToken(element.startTag), | ||
` class="${className}"` | ||
) | ||
return fixer.insertTextAfter(context.parserServices.getTemplateBodyTokenStore().getFirstToken(element.startTag), ` class="${className}"`); | ||
} | ||
} | ||
function removeAttr (context, fixer, node) { | ||
const source = context.getSourceCode().text | ||
let [start, end] = node.range | ||
function removeAttr(context, fixer, node) { | ||
const source = context.getSourceCode().text; | ||
let [start, end] = node.range; | ||
// Remove extra whitespace before attributes | ||
start -= /\s*$/g.exec(source.substring(0, start))[0].length | ||
return fixer.removeRange([start, end]) | ||
start -= /\s*$/g.exec(source.substring(0, start))[0].length; | ||
return fixer.removeRange([start, end]); | ||
} | ||
module.exports = { | ||
addClass, | ||
removeAttr | ||
} | ||
}; |
@@ -1,28 +0,15 @@ | ||
const Module = require('module') | ||
const path = require('path') | ||
"use strict"; | ||
// https://github.com/benmosher/eslint-plugin-import/pull/1591 | ||
// https://github.com/benmosher/eslint-plugin-import/pull/1602 | ||
// Polyfill Node's `Module.createRequireFromPath` if not present (added in Node v10.12.0) | ||
// Use `Module.createRequire` if available (added in Node v12.2.0) | ||
// eslint-disable-next-line node/no-deprecated-api | ||
const createRequire = Module.createRequire || Module.createRequireFromPath || function (filename) { | ||
const mod = new Module(filename, null) | ||
mod.filename = filename | ||
mod.paths = Module._nodeModulePaths(path.dirname(filename)) | ||
mod._compile(`module.exports = require;`, filename) | ||
return mod.exports | ||
} | ||
function getInstalledVuetifyVersion () { | ||
const { | ||
createRequire | ||
} = require('module'); | ||
const path = require('path'); | ||
function getInstalledVuetifyVersion() { | ||
try { | ||
const installedVuetify = createRequire(path.resolve(process.cwd(), 'package.json'))('vuetify/package.json') | ||
return installedVuetify.version | ||
const installedVuetify = createRequire(path.resolve(process.cwd(), 'package.json'))('vuetify/package.json'); | ||
return installedVuetify.version; | ||
} catch (e) {} | ||
} | ||
module.exports = { | ||
getInstalledVuetifyVersion | ||
} | ||
}; |
@@ -1,7 +0,6 @@ | ||
const alignmentClasses = [ | ||
/^align-(content-)?(start|baseline|center|end|space-around|space-between)$/, | ||
/^justify-(start|center|end|space-around|space-between)$/, | ||
/^justify-between$/ // No idea where this was from or if it's a typo, but it's in the docs | ||
] | ||
"use strict"; | ||
const alignmentClasses = [/^align-(content-)?(start|baseline|center|end|space-around|space-between)$/, /^justify-(start|center|end|space-around|space-between)$/, /^justify-between$/ // No idea where this was from or if it's a typo, but it's in the docs | ||
]; | ||
// These attributes have alternative props, so shouldn't be turned into classes by the fixer | ||
@@ -11,18 +10,11 @@ const noFix = { | ||
VRow: [...alignmentClasses, 'row', 'column', 'reverse', 'wrap'], | ||
VCol: [ | ||
/^align-self-(start|baseline|center|end)$/, | ||
/^offset-(xs|sm|md|lg|xl)\d{1,2}$/, | ||
/^order-(xs|sm|md|lg|xl)\d{1,2}$/, | ||
/^(xs|sm|md|lg|xl)\d{1,2}$/ | ||
] | ||
} | ||
function isGridAttribute (tag, name) { | ||
VCol: [/^align-self-(start|baseline|center|end)$/, /^offset-(xs|sm|md|lg|xl)\d{1,2}$/, /^order-(xs|sm|md|lg|xl)\d{1,2}$/, /^(xs|sm|md|lg|xl)\d{1,2}$/] | ||
}; | ||
function isGridAttribute(tag, name) { | ||
return noFix[tag] && noFix[tag].some(match => { | ||
return match instanceof RegExp ? match.test(name) : name === match | ||
}) | ||
return match instanceof RegExp ? match.test(name) : name === match; | ||
}); | ||
} | ||
module.exports = { | ||
isGridAttribute | ||
} | ||
}; |
@@ -1,67 +0,44 @@ | ||
'use strict' | ||
'use strict'; | ||
function hyphenate ( | ||
/* istanbul ignore next */ | ||
str = '' | ||
) { | ||
return str.replace(/\B([A-Z])/g, '-$1').toLowerCase() | ||
function hyphenate( /* istanbul ignore next */ | ||
str = '') { | ||
return str.replace(/\B([A-Z])/g, '-$1').toLowerCase(); | ||
} | ||
function classify (str) { | ||
return str | ||
.replace(/(?:^|[-_])(\w)/g, c => c.toUpperCase()) | ||
.replace(/[-_]/g, '') | ||
function classify(str) { | ||
return str.replace(/(?:^|[-_])(\w)/g, c => c.toUpperCase()).replace(/[-_]/g, ''); | ||
} | ||
const specialAttrs = [ | ||
'style', 'class', 'id', | ||
'contenteditable', 'draggable', 'spellcheck', | ||
'key', 'ref', 'slot', 'is', 'slot-scope' | ||
] | ||
function isBuiltinAttribute (name) { | ||
return specialAttrs.includes(name) || | ||
name.startsWith('data-') || | ||
name.startsWith('aria-') | ||
const specialAttrs = ['style', 'class', 'id', 'contenteditable', 'draggable', 'spellcheck', 'key', 'ref', 'slot', 'is', 'slot-scope']; | ||
function isBuiltinAttribute(name) { | ||
return specialAttrs.includes(name) || name.startsWith('data-') || name.startsWith('aria-'); | ||
} | ||
function getAttributes (element) { | ||
const attrs = [] | ||
function getAttributes(element) { | ||
const attrs = []; | ||
element.startTag.attributes.forEach(node => { | ||
if (node.directive && (node.key.name.name !== 'bind' || !node.key.argument)) return | ||
const name = hyphenate(node.directive ? node.key.argument.name : node.key.rawName) | ||
if (!isBuiltinAttribute(name)) attrs.push({ name, node }) | ||
}) | ||
return attrs | ||
if (node.directive && (node.key.name.name !== 'bind' || !node.key.argument)) return; | ||
const name = hyphenate(node.directive ? node.key.argument.name : node.key.rawName); | ||
if (!isBuiltinAttribute(name)) attrs.push({ | ||
name, | ||
node | ||
}); | ||
}); | ||
return attrs; | ||
} | ||
function isObject (obj) { | ||
return obj !== null && typeof obj === 'object' | ||
function isObject(obj) { | ||
return obj !== null && typeof obj === 'object'; | ||
} | ||
function mergeDeep (source, target) { | ||
function mergeDeep(source, target) { | ||
for (const key in target) { | ||
const sourceProperty = source[key] | ||
const targetProperty = target[key] | ||
const sourceProperty = source[key]; | ||
const targetProperty = target[key]; | ||
// Only continue deep merging if | ||
// both properties are objects | ||
if ( | ||
isObject(sourceProperty) && | ||
isObject(targetProperty) | ||
) { | ||
source[key] = mergeDeep(sourceProperty, targetProperty) | ||
continue | ||
if (isObject(sourceProperty) && isObject(targetProperty)) { | ||
source[key] = mergeDeep(sourceProperty, targetProperty); | ||
continue; | ||
} | ||
source[key] = targetProperty | ||
source[key] = targetProperty; | ||
} | ||
return source | ||
return source; | ||
} | ||
module.exports = { | ||
@@ -74,2 +51,2 @@ hyphenate, | ||
mergeDeep | ||
} | ||
}; |
{ | ||
"name": "eslint-plugin-vuetify", | ||
"version": "1.1.0", | ||
"version": "2.0.0-beta.0", | ||
"description": "An eslint plugin for Vuetify", | ||
@@ -10,6 +10,8 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"build": "rimraf lib && babel src --out-dir lib", | ||
"test": "mocha tests --recursive --reporter dot", | ||
"test:coverage": "nyc mocha tests --recursive --reporter dot", | ||
"test:ci": "nyc --reporter=lcov mocha tests --recursive --reporter dot", | ||
"lint": "eslint lib tests" | ||
"lint": "eslint src tests", | ||
"prepublishOnly": "npm run build" | ||
}, | ||
@@ -21,21 +23,25 @@ "files": [ | ||
"dependencies": { | ||
"eslint-plugin-vue": "^7.0.0", | ||
"eslint-plugin-vue": "^9.6.0", | ||
"requireindex": "^1.2.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^8.0.1", | ||
"eslint-config-standard": "^16.0.3", | ||
"eslint-plugin-import": "^2.25.2", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-promise": "^5.1.1", | ||
"husky": "^6.0.0", | ||
"mocha": "^9.1.3", | ||
"@babel/cli": "^7.19.3", | ||
"@babel/core": "^7.19.6", | ||
"@babel/preset-env": "^7.19.4", | ||
"eslint": "^8.26.0", | ||
"eslint-config-standard": "^17.0.0", | ||
"eslint-plugin-import": "^2.26.0", | ||
"eslint-plugin-n": "^15.3.0", | ||
"eslint-plugin-promise": "^6.1.1", | ||
"husky": "^8.0.1", | ||
"mocha": "^10.1.0", | ||
"nyc": "^15.1.0", | ||
"vue": "^2.6.14", | ||
"vuetify": "^2.5.10" | ||
"rimraf": "^3.0.2", | ||
"vue": "^3.2.41", | ||
"vuetify": "^3.0.0-beta.15" | ||
}, | ||
"peerDependencies": { | ||
"eslint": "^6.2.0 || ^7.0.0 || ^8.0.0", | ||
"vuetify": "^2.0.0" | ||
"eslint": "^8.0.0", | ||
"vuetify": "^3.0.0" | ||
} | ||
} |
# eslint-plugin-vuetify | ||
> An eslint plugin for Vuetify. | ||
> Built for https://github.com/vuetifyjs/vuetify/pull/7327, requires vuetify >=2.0.0 | ||
@@ -48,2 +46,3 @@ <br> | ||
- Prevent the use of classes that have been removed from Vuetify ([`no-deprecated-classes`]) | ||
- Prevent the use of the old theme class syntax ([`no-deprecated-colors`]) | ||
@@ -54,7 +53,5 @@ ### Grid system | ||
- Prevent the use of legacy grid components and props ([`no-legacy-grid`]) | ||
- Warn about unknown attributes not being converted to classes on new grid components ([`grid-unknown-attributes`]) | ||
[`no-legacy-grid`]: ./docs/rules/no-legacy-grid.md | ||
[`grid-unknown-attributes`]: ./docs/rules/grid-unknown-attributes.md | ||
@@ -64,2 +61,3 @@ [`no-deprecated-components`]: ./docs/rules/no-deprecated-components.md | ||
[`no-deprecated-classes`]: ./docs/rules/no-deprecated-classes.md | ||
[`no-deprecated-colors`]: ./docs/rules/no-deprecated-colors.md | ||
@@ -66,0 +64,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
39226
1342
2
14
15
1
89
1
+ Added@jridgewell/sourcemap-codec@1.5.0(transitive)
+ Added@vue/compiler-core@3.5.10(transitive)
+ Added@vue/compiler-dom@3.5.10(transitive)
+ Added@vue/compiler-sfc@3.5.10(transitive)
+ Added@vue/compiler-ssr@3.5.10(transitive)
+ Added@vue/reactivity@3.5.10(transitive)
+ Added@vue/runtime-core@3.5.10(transitive)
+ Added@vue/runtime-dom@3.5.10(transitive)
+ Added@vue/server-renderer@3.5.10(transitive)
+ Added@vue/shared@3.5.10(transitive)
+ Addedboolbase@1.0.0(transitive)
+ Addedcssesc@3.0.0(transitive)
+ Addedentities@4.5.0(transitive)
+ Addedeslint-plugin-vue@9.28.0(transitive)
+ Addedestree-walker@2.0.2(transitive)
+ Addedmagic-string@0.30.11(transitive)
+ Addednth-check@2.1.1(transitive)
+ Addedpostcss-selector-parser@6.1.2(transitive)
+ Addedsemver@7.6.3(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addedvue@3.5.10(transitive)
+ Addedvue-eslint-parser@9.4.3(transitive)
+ Addedvuetify@3.7.2(transitive)
+ Addedxml-name-validator@4.0.0(transitive)
- Removed@vue/compiler-sfc@2.7.16(transitive)
- Removedacorn@7.4.1(transitive)
- Removedeslint-plugin-vue@7.20.0(transitive)
- Removedeslint-scope@5.1.1(transitive)
- Removedeslint-utils@2.1.0(transitive)
- Removedeslint-visitor-keys@1.3.0(transitive)
- Removedespree@6.2.1(transitive)
- Removedestraverse@4.3.0(transitive)
- Removedprettier@2.8.8(transitive)
- Removedsemver@6.3.1(transitive)
- Removedsource-map@0.6.1(transitive)
- Removedvue@2.7.16(transitive)
- Removedvue-eslint-parser@7.11.0(transitive)
- Removedvuetify@2.7.2(transitive)
Updatedeslint-plugin-vue@^9.6.0