@nextcloud/eslint-config
Version:
Eslint shared config for nextcloud apps and libraries
98 lines (97 loc) • 4.6 kB
JavaScript
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { createLibVersionValidator } from "../utils/lib-version-parser.js";
/*
Introduced in @nextcloud/vue v8.23.0
https://github.com/nextcloud-libraries/nextcloud-vue/pull/6385
*/
const rule = {
meta: {
docs: {
description: 'Deprecated @nextcloud/vue import syntax',
recommended: true,
},
fixable: 'code',
messages: {
outdatedVueLibrary: 'Installed @nextcloud/vue library is outdated and does not support all reported errors. Install latest compatible version',
deprecatedDist: 'Import from "@nextcloud/vue/dist" is deprecated',
deprecatedMixin: 'Mixins are no longer recommended by Vue. Consider using available alternatives',
deprecatedNcSettingsInputText: 'NcSettingsInputText is deprecated. Consider using available alternatives',
deprecatedTooltip: 'Tooltip directive is deprecated. use native title attribute or NcPopover instead',
},
},
create(context) {
const versionSatisfies = createLibVersionValidator(context);
const isVersionValidForDist = versionSatisfies('8.23.0');
const oldPattern = '@nextcloud/vue/dist/([^/]+)/([^/.]+)';
// Matches both the legacy `dist/Mixins/*` path and a bare `mixins/*` path.
// There is no clean `@nextcloud/vue/mixins/*` subpath export (only components,
// composables, directives and functions), so mixins must be migrated to
// composables rather than have their import path rewritten.
const mixinPattern = '@nextcloud/vue/(?:dist/)?mixins/([^/.]+)';
const isVersionValidForTooltip = versionSatisfies('8.25.0');
const tooltipPattern = '@nextcloud/vue/directives/Tooltip';
const isVersionValidForNcSettingsInputText = versionSatisfies('8.31.0');
const patternForNcSettingsInputText = '@nextcloud/vue/components/NcSettingsInputText';
return {
ImportDeclaration: function (node) {
const importPath = node.source.value;
const matchForNcSettingsInputText = importPath.match(new RegExp(patternForNcSettingsInputText));
if (matchForNcSettingsInputText) {
if (!isVersionValidForNcSettingsInputText) {
context.report({ node, messageId: 'outdatedVueLibrary' });
return;
}
context.report({
node,
messageId: 'deprecatedNcSettingsInputText',
});
}
const mixinMatch = importPath.match(new RegExp(mixinPattern, 'i'));
if (mixinMatch) {
if (!isVersionValidForDist) {
context.report({ node, messageId: 'outdatedVueLibrary' });
return;
}
context.report({
node,
messageId: 'deprecatedMixin',
});
}
const tooltipMatch = importPath.match(new RegExp(tooltipPattern));
if (tooltipMatch) {
if (!isVersionValidForTooltip) {
context.report({ node, messageId: 'outdatedVueLibrary' });
return;
}
context.report({
node,
messageId: 'deprecatedTooltip',
});
}
const match = importPath.match(new RegExp(oldPattern));
if (match) {
if (!isVersionValidForDist) {
context.report({ node, messageId: 'outdatedVueLibrary' });
return;
}
// Mixins removed in v9 and already reported as `deprecatedMixin`
if (match[1].toLowerCase() === 'mixins') {
return;
}
const newImportPath = `'@nextcloud/vue/${match[1].toLowerCase()}/${match[2]}'`;
context.report({
node,
messageId: 'deprecatedDist',
fix(fixer) {
return fixer.replaceText(node.source, newImportPath);
},
});
}
},
};
},
};
export default rule;