88 lines
3.6 KiB
JavaScript
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
|