mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
feat(editor): Add lint for $('Node').item in runOnceForAllItems mode (#10743)
This commit is contained in:
parent
6ecf84ffe8
commit
1b04be1240
|
@ -38,6 +38,51 @@ describe('Code node', () => {
|
|||
|
||||
successToast().contains('Node executed successfully');
|
||||
});
|
||||
|
||||
it('should show lint errors in `runOnceForAllItems` mode', () => {
|
||||
const getParameter = () => ndv.getters.parameterInput('jsCode').should('be.visible');
|
||||
const getEditor = () => getParameter().find('.cm-content').should('exist');
|
||||
|
||||
getEditor().type('{selectall}').paste(`$input.itemMatching()
|
||||
$input.item
|
||||
$('When clicking ‘Test workflow’').item
|
||||
$input.first(1)
|
||||
|
||||
for (const item of $input.all()) {
|
||||
item.foo
|
||||
}
|
||||
|
||||
return
|
||||
`);
|
||||
getParameter().get('.cm-lint-marker-error').should('have.length', 6);
|
||||
getParameter().contains('itemMatching').realHover();
|
||||
cy.get('.cm-tooltip-lint').should(
|
||||
'have.text',
|
||||
'`.itemMatching()` expects an item index to be passed in as its argument.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should show lint errors in `runOnceForEachItem` mode', () => {
|
||||
const getParameter = () => ndv.getters.parameterInput('jsCode').should('be.visible');
|
||||
const getEditor = () => getParameter().find('.cm-content').should('exist');
|
||||
|
||||
ndv.getters.parameterInput('mode').click();
|
||||
ndv.actions.selectOptionInParameterDropdown('mode', 'Run Once for Each Item');
|
||||
getEditor().type('{selectall}').paste(`$input.itemMatching()
|
||||
$input.all()
|
||||
$input.first()
|
||||
$input.item()
|
||||
|
||||
return []
|
||||
`);
|
||||
|
||||
getParameter().get('.cm-lint-marker-error').should('have.length', 5);
|
||||
getParameter().contains('all').realHover();
|
||||
cy.get('.cm-tooltip-lint').should(
|
||||
'have.text',
|
||||
"Method `$input.all()` is only available in the 'Run Once for All Items' mode.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ask AI', () => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Diagnostic } from '@codemirror/lint';
|
|||
import { linter } from '@codemirror/lint';
|
||||
import type { EditorView } from '@codemirror/view';
|
||||
import * as esprima from 'esprima-next';
|
||||
import type { Node } from 'estree';
|
||||
import type { Node, MemberExpression } from 'estree';
|
||||
import type { CodeExecutionMode, CodeNodeEditorLanguage } from 'n8n-workflow';
|
||||
import { toValue, type MaybeRefOrGetter } from 'vue';
|
||||
|
||||
|
@ -153,13 +153,20 @@ export const useLinter = (
|
|||
if (toValue(mode) === 'runOnceForAllItems') {
|
||||
type TargetNode = RangeNode & { property: RangeNode };
|
||||
|
||||
const isInputIdentifier = (node: Node) =>
|
||||
node.type === 'Identifier' && node.name === '$input';
|
||||
const isPreviousNodeCall = (node: Node) =>
|
||||
node.type === 'CallExpression' &&
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name === '$';
|
||||
const isDirectMemberExpression = (node: Node): node is MemberExpression =>
|
||||
node.type === 'MemberExpression' && !node.computed;
|
||||
const isItemIdentifier = (node: Node) => node.type === 'Identifier' && node.name === 'item';
|
||||
|
||||
const isUnavailableInputItemAccess = (node: Node) =>
|
||||
node.type === 'MemberExpression' &&
|
||||
!node.computed &&
|
||||
node.object.type === 'Identifier' &&
|
||||
node.object.name === '$input' &&
|
||||
node.property.type === 'Identifier' &&
|
||||
node.property.name === 'item';
|
||||
isDirectMemberExpression(node) &&
|
||||
(isInputIdentifier(node.object) || isPreviousNodeCall(node.object)) &&
|
||||
isItemIdentifier(node.property);
|
||||
|
||||
walk<TargetNode>(ast, isUnavailableInputItemAccess).forEach((node) => {
|
||||
const [start, end] = getRange(node.property);
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
padding: var(--spacing-xs);
|
||||
}
|
||||
|
||||
&:has(.cm-tooltip-lint) {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.autocomplete-info-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
Loading…
Reference in a new issue