Skip to content

Commit

Permalink
feat(editor): Add lint for $('Node').item in runOnceForAllItems mode (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
elsmr authored and riascho committed Sep 23, 2024
1 parent a9bd39b commit 0705d7e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 7 deletions.
45 changes: 45 additions & 0 deletions cypress/e2e/6-code-node.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
21 changes: 14 additions & 7 deletions packages/editor-ui/src/components/CodeNodeEditor/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions packages/editor-ui/src/styles/plugins/_codemirror.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@
padding: var(--spacing-xs);
}

&:has(.cm-tooltip-lint) {
padding: 0;
overflow: hidden;
}

.autocomplete-info-container {
display: flex;
flex-direction: column;
Expand Down

0 comments on commit 0705d7e

Please sign in to comment.