Skip to content

Commit a01ba99

Browse files
authored
Merge pull request #1165 from nextcloud-libraries/feat/1001/nc-vue-deprecations-pt3
feat(nextcloud-vue-plugin): deprecate NcPopover props
2 parents 0f948cb + 3accde1 commit a01ba99

File tree

2 files changed

+147
-1
lines changed

2 files changed

+147
-1
lines changed

lib/plugins/nextcloud-vue/rules/no-deprecated-props.test.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ describe('no-deprecated-props', () => {
2626
})
2727

2828
test('no-deprecated-props if library is not in use', () => {
29-
console.log('only ttests')
3029
vol.fromNestedJSON({
3130
'/a': {
3231
'package.json': '{"name": "my-app","version": "0.1.0"}',
@@ -283,6 +282,11 @@ describe('no-deprecated-props', () => {
283282
filename: '/a/src/component.vue',
284283
errors: [{ messageId: 'useNcSelectUsersInstead' }],
285284
},
285+
{
286+
code: '<template><NcPopover :close-on-click-outside="false" /></template>',
287+
filename: '/a/src/component.vue',
288+
errors: [{ messageId: 'useNoCloseOnClickOutsideInstead' }],
289+
},
286290
{
287291
code: '<template><NcTextField trailing-button-icon="arrowRight" /></template>',
288292
filename: '/a/src/component.vue',
@@ -305,6 +309,54 @@ describe('no-deprecated-props', () => {
305309
filename: '/a/src/component.vue',
306310
errors: [{ messageId: 'removeExact' }],
307311
},
312+
{
313+
code: '<template><NcCheckboxRadioSwitch checked /></template>',
314+
filename: '/a/src/component.vue',
315+
errors: [{ messageId: 'useModelValueInsteadChecked' }],
316+
output: '<template><NcCheckboxRadioSwitch model-value /></template>',
317+
},
318+
{
319+
code: '<template><NcCheckboxRadioSwitch :checked="isChecked" /></template>',
320+
filename: '/a/src/component.vue',
321+
errors: [{ messageId: 'useModelValueInsteadChecked' }],
322+
output: '<template><NcCheckboxRadioSwitch :model-value="isChecked" /></template>',
323+
},
324+
{
325+
code: '<template><NcCheckboxRadioSwitch :checked.sync="isChecked" /></template>',
326+
filename: '/a/src/component.vue',
327+
errors: [{ messageId: 'useModelValueInsteadChecked' }],
328+
output: '<template><NcCheckboxRadioSwitch v-model="isChecked" /></template>',
329+
},
330+
{
331+
code: '<template><NcCheckboxRadioSwitch v-model:checked="isChecked" /></template>',
332+
filename: '/a/src/component.vue',
333+
errors: [{ messageId: 'useModelValueInsteadChecked' }],
334+
output: '<template><NcCheckboxRadioSwitch v-model="isChecked" /></template>',
335+
},
336+
{
337+
code: '<template><NcTextField value="input" /></template>',
338+
filename: '/a/src/component.vue',
339+
errors: [{ messageId: 'useModelValueInsteadValue' }],
340+
output: '<template><NcTextField model-value="input" /></template>',
341+
},
342+
{
343+
code: '<template><NcTextField :value="input" /></template>',
344+
filename: '/a/src/component.vue',
345+
errors: [{ messageId: 'useModelValueInsteadValue' }],
346+
output: '<template><NcTextField :model-value="input" /></template>',
347+
},
348+
{
349+
code: '<template><NcTextField :value.sync="input" /></template>',
350+
filename: '/a/src/component.vue',
351+
errors: [{ messageId: 'useModelValueInsteadValue' }],
352+
output: '<template><NcTextField v-model="input" /></template>',
353+
},
354+
{
355+
code: '<template><NcTextField v-model:value="input" /></template>',
356+
filename: '/a/src/component.vue',
357+
errors: [{ messageId: 'useModelValueInsteadValue' }],
358+
output: '<template><NcTextField v-model="input" /></template>',
359+
},
308360
],
309361
})
310362
})

lib/plugins/nextcloud-vue/rules/no-deprecated-props.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default {
2626
useLocaleInstead: 'Using `lang` is deprecated - use `locale` instead',
2727
useTypeDateRangeInstead: 'Using `range` is deprecated - use `type` with `date-range` or `datetime-range` instead',
2828
useNoCloseInstead: 'Using `can-close` is deprecated - use `no-close` instead',
29+
useNoCloseOnClickOutsideInstead: 'Using `close-on-click-outside` is deprecated - use `no-close-on-click-outside` instead',
2930
useDisableSwipeForModalInstead: 'Using `enable-swipe` is deprecated - use `disable-swipe` instead',
3031
useNoFocusTrapInstead: 'Using `focus-trap` is deprecated - use `no-focus-trap` instead',
3132
useKeepOpenInstead: 'Using `close-on-select` is deprecated - use `keep-open` instead',
@@ -35,13 +36,16 @@ export default {
3536
removeLimitWidth: 'Using `limit-width` is deprecated - remove prop from components, otherwise root element will inherit incorrect attribute.',
3637
removeExact: 'Using `exact` is deprecated - consult Vue Router documentation for alternatives.',
3738
useCloseButtonOutsideInstead: 'Using `close-button-contained` is deprecated - use `close-button-outside` instead',
39+
useModelValueInsteadChecked: 'Using `checked` is deprecated - use `model-value` or `v-model` instead',
40+
useModelValueInsteadValue: 'Using `value` is deprecated - use `model-value` or `v-model` instead',
3841
},
3942
},
4043

4144
create(context) {
4245
const versionSatisfies = createLibVersionValidator(context)
4346
const isVue3Valid = versionSatisfies('9.0.0') // #6651
4447
const isAriaHiddenValid = versionSatisfies('8.2.0') // #4835
48+
const isModelValueValid = versionSatisfies('8.20.0') // #6172
4549
const isDisableSwipeValid = versionSatisfies('8.23.0') // #6452
4650
const isVariantTypeValid = versionSatisfies('8.24.0') // #6472
4751
const isDefaultBooleanFalseValid = versionSatisfies('8.24.0') // #6656
@@ -246,6 +250,18 @@ export default {
246250
})
247251
},
248252

253+
'VElement[name="ncpopover"] VAttribute:has(VIdentifier[name="close-on-click-outside"])': function(node) {
254+
if (!isVue3Valid) {
255+
// Do not throw for v8.X.X
256+
return
257+
}
258+
259+
context.report({
260+
node,
261+
messageId: 'useNoCloseOnClickOutsideInstead',
262+
})
263+
},
264+
249265
'VElement[name="ncmodal"] VAttribute:has(VIdentifier[name="enable-swipe"])': function(node) {
250266
if (!isDisableSwipeValid) {
251267
context.report({ node, messageId: 'outdatedVueLibrary' })
@@ -371,6 +387,84 @@ export default {
371387
messageId: 'removeExact',
372388
})
373389
},
390+
391+
'VElement VAttribute:has(VIdentifier[name="checked"])': function(node) {
392+
if (![
393+
'ncactioncheckbox',
394+
'ncactionradio',
395+
'nccheckboxradioswitch',
396+
].includes(node.parent.parent.name)) {
397+
return
398+
}
399+
400+
if (!isModelValueValid) {
401+
context.report({ node, messageId: 'outdatedVueLibrary' })
402+
return
403+
}
404+
405+
context.report({
406+
node,
407+
messageId: 'useModelValueInsteadChecked',
408+
fix: (fixer) => {
409+
if (node.key.type === 'VIdentifier') {
410+
return fixer.replaceTextRange(node.key.range, 'model-value')
411+
} else if (node.key.type === 'VDirectiveKey') {
412+
if (node.key.name.name === 'model') {
413+
return fixer.replaceTextRange(node.key.range, 'v-model')
414+
} else if (node.key.modifiers.some((m) => m.name === 'sync')) {
415+
return fixer.replaceTextRange(node.key.range, 'v-model')
416+
} else {
417+
return fixer.replaceTextRange(node.key.argument.range, 'model-value')
418+
}
419+
}
420+
},
421+
})
422+
},
423+
424+
'VElement VAttribute:has(VIdentifier[name="value"])': function(node) {
425+
if (![
426+
'ncactioninput',
427+
'ncactiontexteditable',
428+
'nccolorpicker',
429+
'ncdatetimepicker',
430+
'ncdatetimepickernative',
431+
'ncinputfield',
432+
'nctextfield',
433+
'ncpasswordfield',
434+
'ncrichcontenteditable',
435+
'ncselecttags',
436+
'ncselect',
437+
'ncsettingsinputtext',
438+
'ncsettingsselectgroup',
439+
'nctextarea',
440+
'nctimezonepicker',
441+
].includes(node.parent.parent.name)) {
442+
return
443+
}
444+
445+
if (!isModelValueValid) {
446+
context.report({ node, messageId: 'outdatedVueLibrary' })
447+
return
448+
}
449+
450+
context.report({
451+
node,
452+
messageId: 'useModelValueInsteadValue',
453+
fix: (fixer) => {
454+
if (node.key.type === 'VIdentifier') {
455+
return fixer.replaceTextRange(node.key.range, 'model-value')
456+
} else if (node.key.type === 'VDirectiveKey') {
457+
if (node.key.name.name === 'model') {
458+
return fixer.replaceTextRange(node.key.range, 'v-model')
459+
} else if (node.key.modifiers.some((m) => m.name === 'sync')) {
460+
return fixer.replaceTextRange(node.key.range, 'v-model')
461+
} else {
462+
return fixer.replaceTextRange(node.key.argument.range, 'model-value')
463+
}
464+
}
465+
},
466+
})
467+
},
374468
})
375469
},
376470
} satisfies Rule.RuleModule

0 commit comments

Comments
 (0)