fix(editor): Prevent expression editor focus being lost when user is selecting (#9525)

This commit is contained in:
Elias Meire 2024-05-29 14:37:05 +02:00 committed by GitHub
parent 3be7bb898b
commit 6698179a69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 238 additions and 176 deletions

View file

@ -20,33 +20,33 @@ describe('Inline expression editor', () => {
it('should resolve primitive resolvables', () => {
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('1 + 2');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^3$/);
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('"ab"');
WorkflowPage.getters.inlineExpressionEditorInput().type('{rightArrow}+');
WorkflowPage.getters.inlineExpressionEditorInput().type('"cd"');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^abcd$/);
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('true && false');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^false$/);
});
it('should resolve object resolvables', () => {
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters
.inlineExpressionEditorInput()
.type('{ a: 1 }', { parseSpecialCharSequences: false });
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^\[Object: \{"a": 1\}\]$/);
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters
.inlineExpressionEditorInput()
.type('{ a: 1 }.a', { parseSpecialCharSequences: false });
@ -55,13 +55,13 @@ describe('Inline expression editor', () => {
it('should resolve array resolvables', () => {
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('[1, 2, 3]');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^\[Array: \[1,2,3\]\]$/);
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('[1, 2, 3]');
WorkflowPage.getters.inlineExpressionEditorInput().type('[0]');
WorkflowPage.getters.inlineExpressionEditorOutput().contains(/^1$/);
@ -81,7 +81,7 @@ describe('Inline expression editor', () => {
it('should resolve $parameter[]', () => {
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
// Resolving $parameter is slow, especially on CI runner
WorkflowPage.getters.inlineExpressionEditorInput().type('$parameter["operation"]');
WorkflowPage.getters.inlineExpressionEditorOutput().should('have.text', 'getAll');
@ -90,19 +90,19 @@ describe('Inline expression editor', () => {
it('should resolve input: $json,$input,$(nodeName)', () => {
// Previous nodes have not run, input is empty
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('$json.myStr');
WorkflowPage.getters
.inlineExpressionEditorOutput()
.should('have.text', '[Execute previous nodes for preview]');
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('$input.item.json.myStr');
WorkflowPage.getters
.inlineExpressionEditorOutput()
.should('have.text', '[Execute previous nodes for preview]');
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters
.inlineExpressionEditorInput()
.type("$('Schedule Trigger').item.json.myStr");
@ -118,15 +118,15 @@ describe('Inline expression editor', () => {
// Previous nodes have run, input can be resolved
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('$json.myStr');
WorkflowPage.getters.inlineExpressionEditorOutput().should('have.text', 'Monday');
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().type('$input.item.json.myStr');
WorkflowPage.getters.inlineExpressionEditorOutput().should('have.text', 'Monday');
WorkflowPage.getters.inlineExpressionEditorInput().clear();
WorkflowPage.getters.inlineExpressionEditorInput().type('{{');
WorkflowPage.getters.inlineExpressionEditorInput().click().type('{{');
WorkflowPage.getters
.inlineExpressionEditorInput()
.type("$('Schedule Trigger').item.json.myStr");

View file

@ -20,16 +20,16 @@ describe('Expression editor modal', () => {
it('should resolve primitive resolvables', () => {
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ 1 + 2');
WorkflowPage.getters.expressionModalInput().click().type('{{ 1 + 2');
WorkflowPage.getters.expressionModalOutput().contains(/^3$/);
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ "ab" + "cd"');
WorkflowPage.getters.expressionModalInput().click().type('{{ "ab" + "cd"');
WorkflowPage.getters.expressionModalOutput().contains(/^abcd$/);
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ true && false');
WorkflowPage.getters.expressionModalInput().click().type('{{ true && false');
WorkflowPage.getters.expressionModalOutput().contains(/^false$/);
});
@ -37,6 +37,7 @@ describe('Expression editor modal', () => {
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters
.expressionModalInput()
.click()
.type('{{ { a : 1 }', { parseSpecialCharSequences: false });
WorkflowPage.getters.expressionModalOutput().contains(/^\[Object: \{"a": 1\}\]$/);
@ -44,18 +45,19 @@ describe('Expression editor modal', () => {
WorkflowPage.getters
.expressionModalInput()
.click()
.type('{{ { a : 1 }.a', { parseSpecialCharSequences: false });
WorkflowPage.getters.expressionModalOutput().contains(/^1$/);
});
it('should resolve array resolvables', () => {
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ [1, 2, 3]');
WorkflowPage.getters.expressionModalInput().click().type('{{ [1, 2, 3]');
WorkflowPage.getters.expressionModalOutput().contains(/^\[Array: \[1,2,3\]\]$/);
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ [1, 2, 3][0]');
WorkflowPage.getters.expressionModalInput().click().type('{{ [1, 2, 3][0]');
WorkflowPage.getters.expressionModalOutput().contains(/^1$/);
});
});
@ -73,24 +75,27 @@ describe('Expression editor modal', () => {
it('should resolve $parameter[]', () => {
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ $parameter["operation"]');
WorkflowPage.getters.expressionModalInput().click().type('{{ $parameter["operation"]');
WorkflowPage.getters.expressionModalOutput().should('have.text', 'getAll');
});
it('should resolve input: $json,$input,$(nodeName)', () => {
// Previous nodes have not run, input is empty
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ $json.myStr');
WorkflowPage.getters.expressionModalInput().click().type('{{ $json.myStr');
WorkflowPage.getters
.expressionModalOutput()
.should('have.text', '[Execute previous nodes for preview]');
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ $input.item.json.myStr');
WorkflowPage.getters.expressionModalInput().click().type('{{ $input.item.json.myStr');
WorkflowPage.getters
.expressionModalOutput()
.should('have.text', '[Execute previous nodes for preview]');
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type("{{ $('Schedule Trigger').item.json.myStr");
WorkflowPage.getters
.expressionModalInput()
.click()
.type("{{ $('Schedule Trigger').item.json.myStr");
WorkflowPage.getters
.expressionModalOutput()
.should('have.text', '[Execute previous nodes for preview]');
@ -104,13 +109,16 @@ describe('Expression editor modal', () => {
// Previous nodes have run, input can be resolved
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ $json.myStr');
WorkflowPage.getters.expressionModalInput().click().type('{{ $json.myStr');
WorkflowPage.getters.expressionModalOutput().should('have.text', 'Monday');
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type('{{ $input.item.json.myStr');
WorkflowPage.getters.expressionModalInput().click().type('{{ $input.item.json.myStr');
WorkflowPage.getters.expressionModalOutput().should('have.text', 'Monday');
WorkflowPage.getters.expressionModalInput().clear();
WorkflowPage.getters.expressionModalInput().type("{{ $('Schedule Trigger').item.json.myStr");
WorkflowPage.getters
.expressionModalInput()
.click()
.type("{{ $('Schedule Trigger').item.json.myStr");
WorkflowPage.getters.expressionModalOutput().should('have.text', 'Monday');
});
});

View file

@ -26,15 +26,15 @@
"test:dev": "vitest"
},
"dependencies": {
"@codemirror/autocomplete": "^6.11.1",
"@codemirror/commands": "^6.3.2",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/autocomplete": "^6.16.0",
"@codemirror/commands": "^6.5.0",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-python": "^6.1.3",
"@codemirror/language": "^6.9.3",
"@codemirror/lint": "^6.4.2",
"@codemirror/state": "^6.3.3",
"@codemirror/view": "^6.22.3",
"@codemirror/lang-python": "^6.1.6",
"@codemirror/language": "^6.10.1",
"@codemirror/lint": "^6.8.0",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.26.3",
"@fontsource/open-sans": "^4.5.0",
"@jsplumb/browser-ui": "^5.13.2",
"@jsplumb/common": "^5.13.2",

View file

@ -1,14 +1,16 @@
import * as workflowHelpers from '@/composables/useWorkflowHelpers';
import { EditorView } from '@codemirror/view';
import { createTestingPinia } from '@pinia/testing';
import { waitFor } from '@testing-library/vue';
import { waitFor, fireEvent } from '@testing-library/vue';
import { setActivePinia } from 'pinia';
import { beforeEach, describe, vi } from 'vitest';
import { ref, toValue } from 'vue';
import { n8nLang } from '../../plugins/codemirror/n8nLang';
import { defineComponent, h, ref, toValue } from 'vue';
import { n8nLang } from '@/plugins/codemirror/n8nLang';
import { useExpressionEditor } from '../useExpressionEditor';
import { useRouter } from 'vue-router';
import { EditorSelection } from '@codemirror/state';
import userEvent from '@testing-library/user-event';
import { renderComponent } from '@/__tests__/render';
vi.mock('@/composables/useAutocompleteTelemetry', () => ({
useAutocompleteTelemetry: vi.fn(),
@ -31,6 +33,26 @@ describe('useExpressionEditor', () => {
return mock;
};
const renderExpressionEditor = async (
options: Omit<Parameters<typeof useExpressionEditor>[0], 'editorRef'> = {},
) => {
let expressionEditor!: ReturnType<typeof useExpressionEditor>;
const renderResult = renderComponent(
defineComponent({
setup() {
const root = ref<HTMLElement>();
expressionEditor = useExpressionEditor({ ...options, editorRef: root });
return () => h('div', { ref: root, 'data-test-id': 'editor-root' });
},
}),
{ props: { options } },
);
expect(renderResult.getByTestId('editor-root')).toBeInTheDocument();
await waitFor(() => toValue(expressionEditor.editor));
return { renderResult, expressionEditor };
};
beforeEach(() => {
setActivePinia(createTestingPinia());
});
@ -40,27 +62,21 @@ describe('useExpressionEditor', () => {
});
test('should create an editor', async () => {
const root = ref<HTMLElement>();
const { editor } = useExpressionEditor({
editorRef: root,
});
const { expressionEditor } = await renderExpressionEditor();
root.value = document.createElement('div');
await waitFor(() => expect(toValue(editor)).toBeInstanceOf(EditorView));
await waitFor(() => expect(toValue(expressionEditor.editor)).toBeInstanceOf(EditorView));
});
test('should calculate segments', async () => {
mockResolveExpression().mockReturnValueOnce(15);
const root = ref<HTMLElement>();
const { segments } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { segments },
} = await renderExpressionEditor({
editorValue: 'before {{ $json.test.length }} after',
extensions: [n8nLang()],
});
root.value = document.createElement('div');
await waitFor(() => {
expect(toValue(segments.all)).toEqual([
{
@ -118,134 +134,124 @@ describe('useExpressionEditor', () => {
describe('readEditorValue()', () => {
test('should return the full editor value (unresolved)', async () => {
mockResolveExpression().mockReturnValueOnce(15);
const root = ref<HTMLElement>();
const { readEditorValue } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { readEditorValue },
} = await renderExpressionEditor({
editorValue: 'before {{ $json.test.length }} after',
extensions: [n8nLang()],
});
root.value = document.createElement('div');
await waitFor(() =>
expect(readEditorValue()).toEqual('before {{ $json.test.length }} after'),
);
expect(readEditorValue()).toEqual('before {{ $json.test.length }} after');
});
});
describe('setCursorPosition()', () => {
test('should set cursor position to number correctly', async () => {
const root = ref<HTMLElement>();
const editorValue = 'text here';
const { editor, setCursorPosition } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { editor, setCursorPosition },
} = await renderExpressionEditor({
editorValue,
extensions: [],
});
root.value = document.createElement('div');
await waitFor(() => toValue(editor));
setCursorPosition(4);
await waitFor(() =>
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(4)),
);
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(4));
});
test('should set cursor position to end correctly', async () => {
const root = ref<HTMLElement>();
const editorValue = 'text here';
const correctPosition = editorValue.length;
const { editor, setCursorPosition } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { editor, setCursorPosition },
} = await renderExpressionEditor({
editorValue,
extensions: [],
});
root.value = document.createElement('div');
await waitFor(() => toValue(editor));
setCursorPosition('end');
await waitFor(() =>
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(correctPosition)),
);
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(correctPosition));
});
test('should set cursor position to last expression correctly', async () => {
const root = ref<HTMLElement>();
const editorValue = 'text {{ $json.foo }} {{ $json.bar }} here';
const correctPosition = editorValue.indexOf('bar') + 'bar'.length;
const { editor, setCursorPosition } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { editor, setCursorPosition },
} = await renderExpressionEditor({
editorValue,
extensions: [n8nLang()],
});
root.value = document.createElement('div');
await waitFor(() => toValue(editor));
setCursorPosition('lastExpression');
await waitFor(() =>
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(correctPosition)),
);
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(correctPosition));
});
});
describe('select()', () => {
test('should select number range', async () => {
const root = ref<HTMLElement>();
const editorValue = 'text here';
const { editor, select } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { editor, select },
} = await renderExpressionEditor({
editorValue,
extensions: [],
});
root.value = document.createElement('div');
await waitFor(() => toValue(editor));
select(4, 7);
await waitFor(() =>
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(4, 7)),
);
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(4, 7));
});
test('should select until end', async () => {
const root = ref<HTMLElement>();
const editorValue = 'text here';
const { editor, select } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { editor, select },
} = await renderExpressionEditor({
editorValue,
extensions: [],
});
root.value = document.createElement('div');
await waitFor(() => toValue(editor));
select(4, 'end');
await waitFor(() =>
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(4, 9)),
);
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(4, 9));
});
});
describe('selectAll()', () => {
test('should select all', async () => {
const root = ref<HTMLElement>();
const editorValue = 'text here';
const { editor, selectAll } = useExpressionEditor({
editorRef: root,
const {
expressionEditor: { editor, selectAll },
} = await renderExpressionEditor({
editorValue,
extensions: [],
});
root.value = document.createElement('div');
await waitFor(() => toValue(editor));
selectAll();
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(0, 9));
});
});
await waitFor(() =>
expect(toValue(editor)?.state.selection).toEqual(EditorSelection.single(0, 9)),
);
describe('blur on click outside', () => {
test('should blur when another element is clicked', async () => {
const { renderResult, expressionEditor } = await renderExpressionEditor();
const root = renderResult.getByTestId('editor-root');
const input = root.querySelector('.cm-line') as HTMLDivElement;
await userEvent.click(input);
expect(expressionEditor.editor.value?.hasFocus).toBe(true);
await fireEvent(document, new MouseEvent('click'));
expect(expressionEditor.editor.value?.hasFocus).toBe(false);
});
test('should NOT blur when another element is clicked while selecting', async () => {
const { renderResult, expressionEditor } = await renderExpressionEditor();
const root = renderResult.getByTestId('editor-root');
const input = root.querySelector('.cm-line') as HTMLDivElement;
await userEvent.click(input);
expect(expressionEditor.editor.value?.hasFocus).toBe(true);
await fireEvent(input, new MouseEvent('mousedown', { bubbles: true }));
await fireEvent(document, new MouseEvent('click'));
expect(expressionEditor.editor.value?.hasFocus).toBe(true);
});
});
});

View file

@ -72,6 +72,7 @@ export const useExpressionEditor = ({
const readOnlyExtensions = ref<Compartment>(new Compartment());
const telemetryExtensions = ref<Compartment>(new Compartment());
const autocompleteStatus = ref<'pending' | 'active' | null>(null);
const dragging = ref(false);
const updateSegments = (): void => {
const state = editor.value?.state;
@ -169,9 +170,10 @@ export const useExpressionEditor = ({
}
function blurOnClickOutside(event: MouseEvent) {
if (event.target && !editor.value?.dom.contains(event.target as Node)) {
if (event.target && !dragging.value && !editor.value?.dom.contains(event.target as Node)) {
blur();
}
dragging.value = false;
}
watch(editorRef, () => {
@ -199,6 +201,11 @@ export const useExpressionEditor = ({
return null;
}),
EditorView.contentAttributes.of({ 'data-gramm': 'false' }), // disable grammarly
EditorView.domEventHandlers({
mousedown: () => {
dragging.value = true;
},
}),
],
});

View file

@ -1069,32 +1069,32 @@ importers:
packages/editor-ui:
dependencies:
'@codemirror/autocomplete':
specifier: ^6.11.1
version: 6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
specifier: ^6.16.0
version: 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@codemirror/commands':
specifier: ^6.3.2
version: 6.3.2
specifier: ^6.5.0
version: 6.5.0
'@codemirror/lang-javascript':
specifier: ^6.2.1
version: 6.2.1
specifier: ^6.2.2
version: 6.2.2
'@codemirror/lang-json':
specifier: ^6.0.1
version: 6.0.1
'@codemirror/lang-python':
specifier: ^6.1.3
version: 6.1.3(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
specifier: ^6.1.6
version: 6.1.6(@codemirror/view@6.26.3)
'@codemirror/language':
specifier: ^6.9.3
version: 6.9.3
specifier: ^6.10.1
version: 6.10.1
'@codemirror/lint':
specifier: ^6.4.2
version: 6.4.2
specifier: ^6.8.0
version: 6.8.0
'@codemirror/state':
specifier: ^6.3.3
version: 6.3.3
specifier: ^6.4.1
version: 6.4.1
'@codemirror/view':
specifier: ^6.22.3
version: 6.22.3
specifier: ^6.26.3
version: 6.26.3
'@fontsource/open-sans':
specifier: ^4.5.0
version: 4.5.12
@ -1136,7 +1136,7 @@ importers:
version: link:../@n8n/codemirror-lang
'@n8n/codemirror-lang-sql':
specifier: ^1.0.2
version: 1.0.2(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
version: 1.0.2(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@n8n/permissions':
specifier: workspace:*
version: link:../@n8n/permissions
@ -4670,49 +4670,63 @@ packages:
- react
dev: true
/@codemirror/autocomplete@6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0):
resolution: {integrity: sha512-L5UInv8Ffd6BPw0P3EF7JLYAMeEbclY7+6Q11REt8vhih8RuLreKtPy/xk8wPxs4EQgYqzI7cdgpiYwWlbS/ow==}
/@codemirror/autocomplete@6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.1.0):
resolution: {integrity: sha512-P/LeCTtZHRTCU4xQsa89vSKWecYv1ZqwzOd5topheGRf+qtacFgBeIMQi3eL8Kt/BUNvxUWkx+5qP2jlGoARrg==}
peerDependencies:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies:
'@codemirror/language': 6.9.3
'@codemirror/state': 6.3.3
'@codemirror/view': 6.22.3
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.1.0
dev: false
/@codemirror/commands@6.3.2:
resolution: {integrity: sha512-tjoi4MCWDNxgIpoLZ7+tezdS9OEB6pkiDKhfKx9ReJ/XBcs2G2RXIu+/FxXBlWsPTsz6C9q/r4gjzrsxpcnqCQ==}
/@codemirror/autocomplete@6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1):
resolution: {integrity: sha512-P/LeCTtZHRTCU4xQsa89vSKWecYv1ZqwzOd5topheGRf+qtacFgBeIMQi3eL8Kt/BUNvxUWkx+5qP2jlGoARrg==}
peerDependencies:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies:
'@codemirror/language': 6.9.3
'@codemirror/state': 6.3.3
'@codemirror/view': 6.22.3
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.2.1
dev: false
/@codemirror/commands@6.5.0:
resolution: {integrity: sha512-rK+sj4fCAN/QfcY9BEzYMgp4wwL/q5aj/VfNSoH1RWPF9XS/dUwBkvlL3hpWgEjOqlpdN1uLC9UkjJ4tmyjJYg==}
dependencies:
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.1.0
dev: false
/@codemirror/lang-css@6.0.1(@codemirror/view@6.22.3)(@lezer/common@1.1.0):
/@codemirror/lang-css@6.0.1(@codemirror/view@6.26.3)(@lezer/common@1.1.0):
resolution: {integrity: sha512-rlLq1Dt0WJl+2epLQeAsfqIsx3lGu4HStHCJu95nGGuz2P2fNugbU3dQYafr2VRjM4eMC9HviI6jvS98CNtG5w==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.9.3
'@codemirror/state': 6.3.3
'@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@lezer/css': 1.1.1
transitivePeerDependencies:
- '@codemirror/view'
- '@lezer/common'
dev: false
/@codemirror/lang-javascript@6.2.1:
resolution: {integrity: sha512-jlFOXTejVyiQCW3EQwvKH0m99bUYIw40oPmFjSX2VS78yzfe0HELZ+NEo9Yfo1MkGRpGlj3Gnu4rdxV1EnAs5A==}
/@codemirror/lang-javascript@6.2.2:
resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.9.3
'@codemirror/lint': 6.4.2
'@codemirror/state': 6.3.3
'@codemirror/view': 6.22.3
'@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.10.1
'@codemirror/lint': 6.8.0
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.1.0
'@lezer/javascript': 1.0.2
dev: false
@ -4720,20 +4734,31 @@ packages:
/@codemirror/lang-json@6.0.1:
resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==}
dependencies:
'@codemirror/language': 6.9.3
'@codemirror/language': 6.10.1
'@lezer/json': 1.0.0
dev: false
/@codemirror/lang-python@6.1.3(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0):
resolution: {integrity: sha512-S9w2Jl74hFlD5nqtUMIaXAq9t5WlM0acCkyuQWUUSvZclk1sV+UfnpFiZzuZSG+hfEaOmxKR5UxY/Uxswn7EhQ==}
/@codemirror/lang-python@6.1.6(@codemirror/view@6.26.3):
resolution: {integrity: sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.9.3
'@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.2.1)
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@lezer/common': 1.2.1
'@lezer/python': 1.1.5
transitivePeerDependencies:
- '@codemirror/state'
- '@codemirror/view'
- '@lezer/common'
dev: false
/@codemirror/language@6.10.1:
resolution: {integrity: sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==}
dependencies:
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.1.0
'@lezer/highlight': 1.1.1
'@lezer/lr': 1.4.0
style-mod: 4.1.0
dev: false
/@codemirror/language@6.9.3:
@ -4747,11 +4772,11 @@ packages:
style-mod: 4.1.0
dev: false
/@codemirror/lint@6.4.2:
resolution: {integrity: sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==}
/@codemirror/lint@6.8.0:
resolution: {integrity: sha512-lsFofvaw0lnPRJlQylNsC4IRt/1lI4OD/yYslrSGVndOJfStc58v+8p9dgGiD90ktOfL7OhBWns1ZETYgz0EJA==}
dependencies:
'@codemirror/state': 6.3.3
'@codemirror/view': 6.22.3
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
crelt: 1.0.5
dev: false
@ -4759,10 +4784,22 @@ packages:
resolution: {integrity: sha512-0wufKcTw2dEwEaADajjHf6hBy1sh3M6V0e+q4JKIhLuiMSe5td5HOWpUdvKth1fT1M9VYOboajoBHpkCd7PG7A==}
dev: false
/@codemirror/state@6.4.1:
resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==}
dev: false
/@codemirror/view@6.22.3:
resolution: {integrity: sha512-rqnq+Zospwoi3x1vZ8BGV1MlRsaGljX+6qiGYmIpJ++M+LCC+wjfDaPklhwpWSgv7pr/qx29KiAKQBH5+DOn4w==}
dependencies:
'@codemirror/state': 6.3.3
'@codemirror/state': 6.4.1
style-mod: 4.1.0
w3c-keyname: 2.2.6
dev: false
/@codemirror/view@6.26.3:
resolution: {integrity: sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==}
dependencies:
'@codemirror/state': 6.4.1
style-mod: 4.1.0
w3c-keyname: 2.2.6
dev: false
@ -6666,6 +6703,10 @@ packages:
/@lezer/common@1.1.0:
resolution: {integrity: sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==}
/@lezer/common@1.2.1:
resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==}
dev: false
/@lezer/css@1.1.1:
resolution: {integrity: sha512-mSjx+unLLapEqdOYDejnGBokB5+AiJKZVclmud0MKQOKx3DLJ5b5VTCstgDDknR6iIV4gVrN6euzsCnj0A2gQA==}
dependencies:
@ -6835,12 +6876,12 @@ packages:
dev: false
optional: true
/@n8n/codemirror-lang-sql@1.0.2(@codemirror/view@6.22.3)(@lezer/common@1.1.0):
/@n8n/codemirror-lang-sql@1.0.2(@codemirror/view@6.26.3)(@lezer/common@1.1.0):
resolution: {integrity: sha512-sOf/KyewSu3Ikij0CkRtzJJDhRDZcwNCEYl8UdH4U/riL0/XZGcBD7MYofCCcKszanJZiEWRZ2KU1sRp234iMg==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.9.3
'@codemirror/state': 6.3.3
'@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@lezer/highlight': 1.1.1
'@lezer/lr': 1.4.0
transitivePeerDependencies:
@ -12662,12 +12703,12 @@ packages:
/codemirror-lang-html-n8n@1.0.0:
resolution: {integrity: sha512-ofNP6VTDGJ5rue+kTCZlDZdF1PnE0sl2cAkfrsCAd5MlBgDmqTwuFJIkTI6KXOJXs0ucdTYH6QLhy9BSW7EaOQ==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
'@codemirror/lang-css': 6.0.1(@codemirror/view@6.22.3)(@lezer/common@1.1.0)
'@codemirror/lang-javascript': 6.2.1
'@codemirror/language': 6.9.3
'@codemirror/state': 6.3.3
'@codemirror/view': 6.22.3
'@codemirror/autocomplete': 6.16.0(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@codemirror/lang-css': 6.0.1(@codemirror/view@6.26.3)(@lezer/common@1.1.0)
'@codemirror/lang-javascript': 6.2.2
'@codemirror/language': 6.10.1
'@codemirror/state': 6.4.1
'@codemirror/view': 6.26.3
'@lezer/common': 1.1.0
'@lezer/css': 1.1.1
'@lezer/highlight': 1.1.1