Files
n8n-nodes-gwezz-changdunovel/node_modules/@n8n/eslint-plugin-community-nodes/dist/rules/package-name-convention.js
2025-10-26 23:10:15 +08:00

88 lines
3.6 KiB
JavaScript

import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../utils/index.js';
export const PackageNameConventionRule = createRule({
name: 'package-name-convention',
meta: {
type: 'problem',
docs: {
description: 'Enforce correct package naming convention for n8n community nodes',
},
messages: {
renameTo: "Rename to '{{suggestedName}}'",
invalidPackageName: 'Package name "{{ packageName }}" must follow the convention "n8n-nodes-[PACKAGE-NAME]" or "@[AUTHOR]/n8n-nodes-[PACKAGE-NAME]"',
},
schema: [],
hasSuggestions: true,
},
defaultOptions: [],
create(context) {
if (!context.filename.endsWith('package.json')) {
return {};
}
return {
ObjectExpression(node) {
if (node.parent?.type === AST_NODE_TYPES.Property) {
return;
}
const nameProperty = node.properties.find((property) => property.type === AST_NODE_TYPES.Property &&
property.key.type === AST_NODE_TYPES.Literal &&
property.key.value === 'name');
if (!nameProperty || nameProperty.type !== AST_NODE_TYPES.Property) {
return;
}
if (nameProperty.value.type !== AST_NODE_TYPES.Literal) {
return;
}
const packageName = nameProperty.value.value;
const packageNameStr = typeof packageName === 'string' ? packageName : null;
if (!packageNameStr || !isValidPackageName(packageNameStr)) {
const suggestions = [];
// Generate package name suggestions if we have a valid string
if (packageNameStr) {
const suggestedNames = generatePackageNameSuggestions(packageNameStr);
for (const suggestedName of suggestedNames) {
suggestions.push({
messageId: 'renameTo',
data: { suggestedName },
fix(fixer) {
return fixer.replaceText(nameProperty.value, `"${suggestedName}"`);
},
});
}
}
context.report({
node: nameProperty,
messageId: 'invalidPackageName',
data: {
packageName: packageNameStr ?? 'undefined',
},
suggest: suggestions,
});
}
},
};
},
});
function isValidPackageName(name) {
const unscoped = /^n8n-nodes-.+$/;
const scoped = /^@.+\/n8n-nodes-.+$/;
return unscoped.test(name) || scoped.test(name);
}
function generatePackageNameSuggestions(invalidName) {
const cleanName = (name) => {
return name
.replace(/^nodes?-?n8n-?/, '')
.replace(/^n8n-/, '')
.replace(/^nodes?-?/, '')
.replace(/^node-/, '')
.replace(/-nodes$/, '');
};
if (invalidName.startsWith('@')) {
const [scope, packagePart] = invalidName.split('/');
const clean = cleanName(packagePart ?? '');
return clean ? [`${scope}/n8n-nodes-${clean}`] : [];
}
const clean = cleanName(invalidName);
return clean ? [`n8n-nodes-${clean}`] : [];
}
//# sourceMappingURL=package-name-convention.js.map