fix(editor): Amend missing nodeName passthroughs for codemirror completions (no-changelog) (#17292)

This commit is contained in:
Charlie Kolb
2025-07-14 16:33:19 +02:00
committed by GitHub
parent f1e03ab6b1
commit 987e0ecf09
3 changed files with 26 additions and 6 deletions

View File

@@ -40,6 +40,7 @@ import { useI18n } from '@n8n/i18n';
import { useWorkflowsStore } from '../stores/workflows.store';
import { useAutocompleteTelemetry } from './useAutocompleteTelemetry';
import { ignoreUpdateAnnotation } from '../utils/forceParse';
import { TARGET_NODE_PARAMETER_FACET } from '@/plugins/codemirror/completions/constants';
export const useExpressionEditor = ({
editorRef,
@@ -205,6 +206,7 @@ export const useExpressionEditor = ({
const state = EditorState.create({
doc: toValue(editorValue),
extensions: [
TARGET_NODE_PARAMETER_FACET.of(toValue(targetNodeParameterContext)),
customExtensions.value.of(toValue(extensions)),
readOnlyExtensions.value.of([EditorState.readOnly.of(toValue(isReadOnly))]),
telemetryExtensions.value.of([]),

View File

@@ -2,6 +2,7 @@ import { prefixMatch, longestCommonPrefix, resolveAutocompleteExpression } from
import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import type { Resolved } from './types';
import { escapeMappingString } from '@/utils/mappingUtils';
import { TARGET_NODE_PARAMETER_FACET } from './constants';
/**
* Resolution-based completions offered at the start of bracket access notation.
@@ -14,6 +15,7 @@ import { escapeMappingString } from '@/utils/mappingUtils';
* - `$input.first().json.myStr[|`
*/
export function bracketAccessCompletions(context: CompletionContext): CompletionResult | null {
const targetNodeParameterContext = context.state.facet(TARGET_NODE_PARAMETER_FACET);
const word = context.matchBefore(/\$[\S\s]*\[.*/);
if (!word) return null;
@@ -30,7 +32,10 @@ export function bracketAccessCompletions(context: CompletionContext): Completion
let resolved: Resolved;
try {
resolved = resolveAutocompleteExpression(`={{ ${base} }}`);
resolved = resolveAutocompleteExpression(
`={{ ${base} }}`,
targetNodeParameterContext?.nodeName,
);
} catch {
return null;
}

View File

@@ -28,6 +28,7 @@ import {
RECOMMENDED_SECTION,
STRING_RECOMMENDED_OPTIONS,
STRING_SECTIONS,
TARGET_NODE_PARAMETER_FACET,
} from './constants';
import { createInfoBoxRenderer } from './infoBoxRenderer';
import { luxonInstanceDocs } from './nativesAutocompleteDocs/luxon.instance.docs';
@@ -56,11 +57,13 @@ import {
} from './utils';
import { javascriptLanguage } from '@codemirror/lang-javascript';
import { isPairedItemIntermediateNodesError } from '@/utils/expressions';
import type { TargetNodeParameterContext } from '@/Interface';
/**
* Resolution-based completions offered according to datatype.
*/
export function datatypeCompletions(context: CompletionContext): CompletionResult | null {
const targetNodeParameterContext = context.state.facet(TARGET_NODE_PARAMETER_FACET);
const word = context.matchBefore(DATATYPE_REGEX);
if (!word) return null;
@@ -86,7 +89,8 @@ export function datatypeCompletions(context: CompletionContext): CompletionResul
options = secretProvidersOptions();
} else {
const resolved = attempt(
(): Resolved => resolveAutocompleteExpression(`={{ ${base} }}`),
(): Resolved =>
resolveAutocompleteExpression(`={{ ${base} }}`, targetNodeParameterContext?.nodeName),
(error) => {
if (!isPairedItemIntermediateNodesError(error)) {
return null;
@@ -94,7 +98,10 @@ export function datatypeCompletions(context: CompletionContext): CompletionResul
// Fallback on first item to provide autocomplete when intermediate nodes have not run
return attempt(() =>
resolveAutocompleteExpression(`={{ ${expressionWithFirstItem(syntaxTree, base)} }}`),
resolveAutocompleteExpression(
`={{ ${expressionWithFirstItem(syntaxTree, base)} }}`,
targetNodeParameterContext?.nodeName,
),
);
},
);
@@ -116,7 +123,7 @@ export function datatypeCompletions(context: CompletionContext): CompletionResul
// When autocomplete is explicitely opened (by Ctrl+Space or programatically), add completions for the current word with '.' prefix
// example: {{ $json.str| }} -> ['length', 'includes()'...] (would usually need a '.' suffix)
if (context.explicit && !word.text.endsWith('.') && options.length === 0) {
options = explicitDataTypeOptions(word.text);
options = explicitDataTypeOptions(word.text, targetNodeParameterContext);
from = word.to;
}
@@ -134,10 +141,16 @@ export function datatypeCompletions(context: CompletionContext): CompletionResul
};
}
function explicitDataTypeOptions(expression: string): Completion[] {
function explicitDataTypeOptions(
expression: string,
targetNodeParameterContext?: TargetNodeParameterContext,
): Completion[] {
return attempt(
() => {
const resolved = resolveAutocompleteExpression(`={{ ${expression} }}`);
const resolved = resolveAutocompleteExpression(
`={{ ${expression} }}`,
targetNodeParameterContext?.nodeName,
);
return datatypeOptions({
resolved,
base: expression,