From f150343141d53449f5a41bedc85ca9bd52cf1b1e Mon Sep 17 00:00:00 2001 From: Jon Date: Fri, 1 Aug 2025 09:16:19 +0100 Subject: [PATCH] fix: Fix issue with some community nodes not displaying correctly (#17866) --- .../community-packages.service.ts | 2 +- .../editor-ui/src/utils/nodeTypeUtils.test.ts | 56 ++++++++++++++++++- .../editor-ui/src/utils/nodeTypesUtils.ts | 2 +- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/community-packages/community-packages.service.ts b/packages/cli/src/community-packages/community-packages.service.ts index f34726f55b..fd55a8dad5 100644 --- a/packages/cli/src/community-packages/community-packages.service.ts +++ b/packages/cli/src/community-packages/community-packages.service.ts @@ -57,7 +57,7 @@ const { const asyncExec = promisify(exec); -const INVALID_OR_SUSPICIOUS_PACKAGE_NAME = /[^0-9a-z@\-./]/; +const INVALID_OR_SUSPICIOUS_PACKAGE_NAME = /[^0-9a-z@\-._/]/; type PackageJson = { name: 'installed-nodes'; diff --git a/packages/frontend/editor-ui/src/utils/nodeTypeUtils.test.ts b/packages/frontend/editor-ui/src/utils/nodeTypeUtils.test.ts index 8eb9c47118..fd190ff82f 100644 --- a/packages/frontend/editor-ui/src/utils/nodeTypeUtils.test.ts +++ b/packages/frontend/editor-ui/src/utils/nodeTypeUtils.test.ts @@ -1,5 +1,5 @@ import type { ResourceMapperField } from 'n8n-workflow'; -import { isResourceMapperFieldListStale } from './nodeTypesUtils'; +import { isCommunityPackageName, isResourceMapperFieldListStale } from './nodeTypesUtils'; describe('isResourceMapperFieldListStale', () => { const baseField: ResourceMapperField = { @@ -73,3 +73,57 @@ describe('isResourceMapperFieldListStale', () => { expect(isResourceMapperFieldListStale(oldFields, newFields)).toBe(true); }); }); + +describe('isCommunityPackageName', () => { + // Standard community package names + it('should identify standard community node package names', () => { + expect(isCommunityPackageName('n8n-nodes-example')).toBe(true); + expect(isCommunityPackageName('n8n-nodes-custom')).toBe(true); + expect(isCommunityPackageName('n8n-nodes-test')).toBe(true); + }); + + // Scoped package names + it('should identify scoped community node package names', () => { + expect(isCommunityPackageName('@username/n8n-nodes-example')).toBe(true); + expect(isCommunityPackageName('@org/n8n-nodes-custom')).toBe(true); + expect(isCommunityPackageName('@test-scope/n8n-nodes-test-name')).toBe(true); + }); + + it('should identify scoped packages with other characters', () => { + expect(isCommunityPackageName('n8n-nodes-my_package')).toBe(true); + expect(isCommunityPackageName('@user/n8n-nodes-with_underscore')).toBe(true); + expect(isCommunityPackageName('@user_name/n8n-nodes-example')).toBe(true); + expect(isCommunityPackageName('@n8n-io/n8n-nodes-test')).toBe(true); + expect(isCommunityPackageName('@n8n.io/n8n-nodes-test')).toBe(true); + }); + + it('should handle mixed cases', () => { + expect(isCommunityPackageName('@user-name_org/n8n-nodes-mixed-case_example')).toBe(true); + expect(isCommunityPackageName('@mixed_style-org/n8n-nodes-complex_name-format')).toBe(true); + expect(isCommunityPackageName('@my.mixed_style-org/n8n-nodes-complex_name-format')).toBe(true); + }); + + // Official n8n packages that should not be identified as community packages + it('should not identify official n8n packages as community nodes', () => { + expect(isCommunityPackageName('@n8n/n8n-nodes-example')).toBe(false); + expect(isCommunityPackageName('n8n-nodes-base')).toBe(false); + }); + + // Additional edge cases + it('should handle edge cases correctly', () => { + // Non-matching patterns + expect(isCommunityPackageName('not-n8n-nodes')).toBe(false); + expect(isCommunityPackageName('n8n-core')).toBe(false); + + // With node name after package + expect(isCommunityPackageName('n8n-nodes-example.NodeName')).toBe(true); + expect(isCommunityPackageName('@user/n8n-nodes-example.NodeName')).toBe(true); + }); + + // Multiple executions to test regex state + it('should work correctly with multiple consecutive calls', () => { + expect(isCommunityPackageName('@user/n8n-nodes-example')).toBe(true); + expect(isCommunityPackageName('n8n-nodes-base')).toBe(false); + expect(isCommunityPackageName('@test-scope/n8n-nodes-test')).toBe(true); + }); +}); diff --git a/packages/frontend/editor-ui/src/utils/nodeTypesUtils.ts b/packages/frontend/editor-ui/src/utils/nodeTypesUtils.ts index 11bf67c86e..57c0ca6d8e 100644 --- a/packages/frontend/editor-ui/src/utils/nodeTypesUtils.ts +++ b/packages/frontend/editor-ui/src/utils/nodeTypesUtils.ts @@ -31,7 +31,7 @@ import { const CRED_KEYWORDS_TO_FILTER = ['API', 'OAuth1', 'OAuth2']; const NODE_KEYWORDS_TO_FILTER = ['Trigger']; -const COMMUNITY_PACKAGE_NAME_REGEX = /^(?!@n8n\/)(@\w+\/)?n8n-nodes-(?!base\b)\b\w+/g; +const COMMUNITY_PACKAGE_NAME_REGEX = /^(?!@n8n\/)(@[\w.-]+\/)?n8n-nodes-(?!base\b)\b\w+/g; const RESOURCE_MAPPER_FIELD_NAME_REGEX = /value\[\"(.+)\"\]/; export function getAppNameFromCredType(name: string) {