Skip to content

Commit f49784d

Browse files
committed
fix(executor): strip dots from normalized block names so dotted names resolve
References split on '.', so a block named "Hunter.io 1" could never be resolved (the first path segment cut the name at the dot). normalizeName now strips dots on both the tag-generation and lookup sides, which cannot break any previously working reference. Aligns the inline normalizers in connection drag-drop, deploy modal, output select, and tag dropdown, and renames Cal Com to Cal.com now that dotted display names work.
1 parent b3de6b2 commit f49784d

10 files changed

Lines changed: 39 additions & 15 deletions

File tree

apps/docs/content/docs/en/integrations/calcom.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Cal Com
2+
title: Cal.com
33
description: Manage Cal.com bookings, event types, schedules, and availability
44
---
55

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/output-select/output-select.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
flattenWorkflowOutputs,
1212
} from '@/lib/workflows/blocks/flatten-outputs'
1313
import { getBlock } from '@/blocks'
14+
import { normalizeName } from '@/executor/constants'
1415
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
1516
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
1617
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
@@ -147,7 +148,7 @@ export function OutputSelect({
147148
return flat.map((f) => {
148149
const displayBlockName =
149150
f.blockName && typeof f.blockName === 'string'
150-
? f.blockName.replace(/\s+/g, '').toLowerCase()
151+
? normalizeName(f.blockName)
151152
: `block-${f.blockId}`
152153
return {
153154
id: `${f.blockId}_${f.path}`,

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
import { syncLocalDraftFromServer } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/sync-local-draft'
3333
import type { DeployReadiness } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-deploy-readiness'
3434
import { runPreDeployChecks } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-predeploy-checks'
35-
import { startsWithUuid } from '@/executor/constants'
35+
import { normalizeName, startsWithUuid } from '@/executor/constants'
3636
import { useA2AAgentByWorkflow } from '@/hooks/queries/a2a/agents'
3737
import { useApiKeys } from '@/hooks/queries/api-keys'
3838
import {
@@ -273,9 +273,7 @@ export function DeployModal({
273273
const parts = outputId.split('.')
274274
if (parts.length >= 2) {
275275
const blockName = parts[0]
276-
return blocks.some(
277-
(b) => b.name?.toLowerCase().replace(/\s+/g, '') === blockName.toLowerCase()
278-
)
276+
return blocks.some((b) => b.name && normalizeName(b.name) === blockName.toLowerCase())
279277
}
280278
return true
281279
})

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/components/field-item/field-item.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ChevronDown } from 'lucide-react'
77
import { Badge } from '@/components/emcn'
88
import { handleKeyboardActivation } from '@/lib/core/utils/keyboard'
99
import type { ConnectedBlock } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-block-connections'
10+
import { normalizeName } from '@/executor/constants'
1011

1112
const logger = createLogger('FieldItem')
1213

@@ -44,7 +45,7 @@ export function FieldItem({
4445
}: FieldItemProps) {
4546
const handleDragStart = useCallback(
4647
(e: React.DragEvent) => {
47-
const normalizedBlockName = connection.name.replace(/\s+/g, '').toLowerCase()
48+
const normalizedBlockName = normalizeName(connection.name)
4849
const fullTag = `${normalizedBlockName}.${path}`
4950

5051
e.dataTransfer.setData(

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/connection-blocks.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import type { ConnectedBlock } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-block-connections'
1515
import { useBlockOutputFields } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-output-fields'
1616
import { getBlock } from '@/blocks/registry'
17+
import { normalizeName } from '@/executor/constants'
1718
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
1819
import { EMPTY_SUBBLOCK_VALUES, useSubBlockStore } from '@/stores/workflows/subblock/store'
1920
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
@@ -279,7 +280,7 @@ export function ConnectionBlocks({ connections, currentBlockId }: ConnectionBloc
279280

280281
const handleConnectionDragStart = useCallback(
281282
(e: React.DragEvent, connection: ConnectedBlock) => {
282-
const normalizedBlockName = connection.name.replace(/\s+/g, '').toLowerCase()
283+
const normalizedBlockName = normalizeName(connection.name)
283284

284285
e.dataTransfer.setData(
285286
'application/json',

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1518,7 +1518,7 @@ export const TagDropdown: React.FC<TagDropdownProps> = ({
15181518
if (tag.startsWith(TAG_PREFIXES.VARIABLE)) {
15191519
const variableName = tag.substring(TAG_PREFIXES.VARIABLE.length)
15201520
const variableObj = workflowVariables.find(
1521-
(v: Variable) => v.name.replace(/\s+/g, '') === variableName
1521+
(v: Variable) => normalizeName(v.name) === variableName
15221522
)
15231523

15241524
if (variableObj) {

apps/sim/blocks/blocks/calcom.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getTrigger } from '@/triggers'
66

77
export const CalComBlock: BlockConfig<ToolResponse> = {
88
type: 'calcom',
9-
name: 'Cal Com',
9+
name: 'Cal.com',
1010
description: 'Manage Cal.com bookings, event types, schedules, and availability',
1111
authMode: AuthMode.OAuth,
1212
triggerAllowed: true,

apps/sim/executor/constants.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,9 +485,16 @@ export function escapeRegExp(value: string): string {
485485
}
486486

487487
/**
488-
* Normalizes a name for comparison by converting to lowercase and removing spaces.
489-
* Used for both block names and variable names to ensure consistent matching.
488+
* Normalizes a name for comparison by converting to lowercase and removing
489+
* spaces and dots. Used for both block names and variable names to ensure
490+
* consistent matching.
491+
*
492+
* Dots are stripped because `.` is the reference path delimiter — a name like
493+
* "Trigger.dev 1" must normalize to "triggerdev1" so the reference
494+
* `<triggerdev1.output>` parses unambiguously. Dotted names could never be
495+
* referenced before (the first path segment cut the name at the dot), so
496+
* stripping dots cannot break any previously working reference.
490497
*/
491498
export function normalizeName(name: string): string {
492-
return name.toLowerCase().replace(/\s+/g, '')
499+
return name.toLowerCase().replace(/\s+/g, '').replace(/\./g, '')
493500
}

apps/sim/executor/variables/resolvers/block.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ describe('BlockResolver', () => {
243243
expect(resolver.resolve('<My Source Block>', ctx)).toEqual({ message: 'hello' })
244244
})
245245

246+
it.concurrent('should resolve blocks whose names contain dots via dot-stripped names', () => {
247+
const workflow = createTestWorkflow([{ id: 'block-dot', name: 'Hunter.io 1' }])
248+
const resolver = new BlockResolver(workflow)
249+
const ctx = createTestContext('current', {
250+
'block-dot': { email: 'jane@acme.com', score: 92 },
251+
})
252+
253+
expect(resolver.resolve('<hunterio1.email>', ctx)).toBe('jane@acme.com')
254+
expect(resolver.resolve('<hunterio1.score>', ctx)).toBe(92)
255+
})
256+
246257
it.concurrent('should resolve nested property path', () => {
247258
const workflow = createTestWorkflow([{ id: 'source' }])
248259
const resolver = new BlockResolver(workflow)

apps/sim/stores/workflows/utils.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@ describe('normalizeName', () => {
3535
expect(normalizeName('already_normalized')).toBe('already_normalized')
3636
})
3737

38-
it.concurrent('should preserve non-space special characters', () => {
38+
it.concurrent('should preserve non-space special characters except dots', () => {
3939
expect(normalizeName('my-variable')).toBe('my-variable')
4040
expect(normalizeName('my_variable')).toBe('my_variable')
41-
expect(normalizeName('my.variable')).toBe('my.variable')
41+
})
42+
43+
it.concurrent('should strip dots since they conflict with the reference path delimiter', () => {
44+
expect(normalizeName('my.variable')).toBe('myvariable')
45+
expect(normalizeName('Trigger.dev 1')).toBe('triggerdev1')
46+
expect(normalizeName('Hunter.io 2')).toBe('hunterio2')
4247
})
4348

4449
it.concurrent('should handle tabs and newlines as whitespace', () => {

0 commit comments

Comments
 (0)