mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-14 00:24:07 -08:00
WIP
This commit is contained in:
parent
42966628d3
commit
406aeb005a
|
@ -4,11 +4,10 @@ import type { CodeExecutionMode, CodeNodeEditorLanguage } from 'n8n-workflow';
|
||||||
import { format } from 'prettier';
|
import { format } from 'prettier';
|
||||||
import jsParser from 'prettier/plugins/babel';
|
import jsParser from 'prettier/plugins/babel';
|
||||||
import * as estree from 'prettier/plugins/estree';
|
import * as estree from 'prettier/plugins/estree';
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
import { computed, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue';
|
||||||
|
|
||||||
import { CODE_NODE_TYPE } from '@/constants';
|
import { CODE_NODE_TYPE } from '@/constants';
|
||||||
import { codeNodeEditorEventBus } from '@/event-bus';
|
import { codeNodeEditorEventBus } from '@/event-bus';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
|
||||||
import { useRootStore } from '@/stores/root.store';
|
import { useRootStore } from '@/stores/root.store';
|
||||||
|
|
||||||
import { useCodeEditor } from '@/composables/useCodeEditor';
|
import { useCodeEditor } from '@/composables/useCodeEditor';
|
||||||
|
@ -18,6 +17,8 @@ import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import AskAI from './AskAI/AskAI.vue';
|
import AskAI from './AskAI/AskAI.vue';
|
||||||
import { CODE_PLACEHOLDERS } from './constants';
|
import { CODE_PLACEHOLDERS } from './constants';
|
||||||
import { useLinter } from './linter';
|
import { useLinter } from './linter';
|
||||||
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
|
import { dropInCodeEditor } from '@/plugins/codemirror/dragAndDrop';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
mode: CodeExecutionMode;
|
mode: CodeExecutionMode;
|
||||||
|
@ -59,8 +60,11 @@ const linter = useLinter(
|
||||||
);
|
);
|
||||||
const extensions = computed(() => [linter.value]);
|
const extensions = computed(() => [linter.value]);
|
||||||
const placeholder = computed(() => CODE_PLACEHOLDERS[props.language]?.[props.mode] ?? '');
|
const placeholder = computed(() => CODE_PLACEHOLDERS[props.language]?.[props.mode] ?? '');
|
||||||
|
const dragAndDropEnabled = computed(() => {
|
||||||
|
return !props.isReadOnly && props.mode === 'runOnceForEachItem';
|
||||||
|
});
|
||||||
|
|
||||||
const { highlightLine, readEditorValue } = useCodeEditor({
|
const { highlightLine, readEditorValue, editor } = useCodeEditor({
|
||||||
editorRef: codeNodeEditorRef,
|
editorRef: codeNodeEditorRef,
|
||||||
language: () => props.language,
|
language: () => props.language,
|
||||||
editorValue: () => props.modelValue,
|
editorValue: () => props.modelValue,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { editorKeymap } from '@/plugins/codemirror/keymap';
|
||||||
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
|
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { codeEditorTheme } from '../CodeNodeEditor/theme';
|
import { codeEditorTheme } from '../CodeNodeEditor/theme';
|
||||||
|
import { mappingDropCursor } from '@/plugins/codemirror/dragAndDrop';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
modelValue: string;
|
modelValue: string;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { codeEditorTheme } from '@/components/CodeNodeEditor/theme';
|
||||||
import { editorKeymap } from '@/plugins/codemirror/keymap';
|
import { editorKeymap } from '@/plugins/codemirror/keymap';
|
||||||
import { typescript } from '@/plugins/codemirror/lsp/typescript';
|
import { typescript } from '@/plugins/codemirror/lsp/typescript';
|
||||||
import { closeCursorInfoBox } from '@/plugins/codemirror/tooltips/InfoBoxTooltip';
|
import { closeCursorInfoBox } from '@/plugins/codemirror/tooltips/InfoBoxTooltip';
|
||||||
import { closeCompletion, completionStatus } from '@codemirror/autocomplete';
|
import { closeBrackets, closeCompletion, completionStatus } from '@codemirror/autocomplete';
|
||||||
import { history } from '@codemirror/commands';
|
import { history } from '@codemirror/commands';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { json } from '@codemirror/lang-json';
|
import { json } from '@codemirror/lang-json';
|
||||||
|
@ -40,6 +40,7 @@ import {
|
||||||
type MaybeRefOrGetter,
|
type MaybeRefOrGetter,
|
||||||
type Ref,
|
type Ref,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
import { mappingDropCursor } from '../plugins/codemirror/dragAndDrop';
|
||||||
|
|
||||||
export type CodeEditorLanguage = 'json' | 'html' | 'javaScript' | 'python';
|
export type CodeEditorLanguage = 'json' | 'html' | 'javaScript' | 'python';
|
||||||
|
|
||||||
|
@ -232,7 +233,9 @@ export const useCodeEditor = ({
|
||||||
dropCursor(),
|
dropCursor(),
|
||||||
indentOnInput(),
|
indentOnInput(),
|
||||||
bracketMatching(),
|
bracketMatching(),
|
||||||
|
closeBrackets(),
|
||||||
highlightActiveLineGutter(),
|
highlightActiveLineGutter(),
|
||||||
|
mappingDropCursor(),
|
||||||
indentationMarkers({
|
indentationMarkers({
|
||||||
highlightActiveBlock: true,
|
highlightActiveBlock: true,
|
||||||
markerType: 'fullScope',
|
markerType: 'fullScope',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { autocompletion, completeFromList, type CompletionSource } from '@codemirror/autocomplete';
|
import { autocompletion, type CompletionSource } from '@codemirror/autocomplete';
|
||||||
import { javascriptLanguage } from '@codemirror/lang-javascript';
|
import { javascriptLanguage } from '@codemirror/lang-javascript';
|
||||||
import { linter, type LintSource } from '@codemirror/lint';
|
import { linter, type LintSource } from '@codemirror/lint';
|
||||||
import { combineConfig, Facet, type Extension } from '@codemirror/state';
|
import { combineConfig, Facet, type Extension } from '@codemirror/state';
|
||||||
|
@ -17,13 +17,23 @@ export const tsFacet = Facet.define<
|
||||||
|
|
||||||
const tsCompletions: CompletionSource = async (context) => {
|
const tsCompletions: CompletionSource = async (context) => {
|
||||||
const { worker } = context.state.facet(tsFacet);
|
const { worker } = context.state.facet(tsFacet);
|
||||||
console.log('complete', context);
|
const { pos, explicit } = context;
|
||||||
|
|
||||||
|
let word = context.matchBefore(/\w*/);
|
||||||
|
if (!word?.text) {
|
||||||
|
word = context.matchBefore(/\./);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!word?.text && !explicit) return null;
|
||||||
|
|
||||||
const result = await worker.getCompletionsAtPos(context.pos);
|
const result = await worker.getCompletionsAtPos(context.pos);
|
||||||
|
|
||||||
if (!result) return result;
|
if (!result) return result;
|
||||||
|
|
||||||
return await completeFromList(result.options)(context);
|
return {
|
||||||
|
from: word ? (word.text === '.' ? word.to : word.from) : pos,
|
||||||
|
options: result.options,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const tsLint: LintSource = async (view) => {
|
const tsLint: LintSource = async (view) => {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,9 @@ import {
|
||||||
cmPosToTs,
|
cmPosToTs,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import type { Completion } from '@codemirror/autocomplete';
|
import type { Completion } from '@codemirror/autocomplete';
|
||||||
|
import types from './types.d.ts?raw';
|
||||||
|
|
||||||
|
const TS_COMPLETE_BLOCKLIST: ts.ScriptElementKind[] = [ts.ScriptElementKind.warning];
|
||||||
|
|
||||||
const worker = (): LanguageServiceWorker => {
|
const worker = (): LanguageServiceWorker => {
|
||||||
let env: tsvfs.VirtualTypeScriptEnvironment;
|
let env: tsvfs.VirtualTypeScriptEnvironment;
|
||||||
|
@ -21,12 +24,11 @@ const worker = (): LanguageServiceWorker => {
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
checkJs: true,
|
checkJs: true,
|
||||||
target: ts.ScriptTarget.ESNext,
|
target: ts.ScriptTarget.ESNext,
|
||||||
lib: ['ESNext'],
|
noLib: true,
|
||||||
module: ts.ModuleKind.ESNext,
|
module: ts.ModuleKind.ESNext,
|
||||||
strict: true,
|
strict: true,
|
||||||
typeRoots: [],
|
|
||||||
types: [],
|
|
||||||
importHelpers: false,
|
importHelpers: false,
|
||||||
|
skipDefaultLibCheck: true,
|
||||||
noEmit: true,
|
noEmit: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,15 +42,8 @@ const worker = (): LanguageServiceWorker => {
|
||||||
await indexedDbCache('typescript-cache', 'fs-map'),
|
await indexedDbCache('typescript-cache', 'fs-map'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
fsMap.set('types.d.ts', types);
|
||||||
fsMap.set(FILE_NAME, wrapInFunction(content));
|
fsMap.set(FILE_NAME, wrapInFunction(content));
|
||||||
fsMap.set(
|
|
||||||
'types.d.ts',
|
|
||||||
`export {};
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
const $input: { json: Record<string,any>, all: () => [] }
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const system = tsvfs.createSystem(fsMap);
|
const system = tsvfs.createSystem(fsMap);
|
||||||
env = tsvfs.createVirtualTypeScriptEnvironment(
|
env = tsvfs.createVirtualTypeScriptEnvironment(
|
||||||
|
@ -76,13 +71,19 @@ declare global {
|
||||||
|
|
||||||
if (!completionInfo) return null;
|
if (!completionInfo) return null;
|
||||||
|
|
||||||
const options = completionInfo.entries.map((entry): Completion => {
|
const options = completionInfo.entries
|
||||||
const boost = -Number(entry.sortText) || 0;
|
.filter(
|
||||||
return {
|
(entry) =>
|
||||||
label: entry.name,
|
!TS_COMPLETE_BLOCKLIST.includes(entry.kind) &&
|
||||||
boost,
|
(entry.sortText < '15' || completionInfo.optionalReplacementSpan?.length),
|
||||||
};
|
)
|
||||||
});
|
.map((entry): Completion => {
|
||||||
|
const boost = -Number(entry.sortText) || 0;
|
||||||
|
return {
|
||||||
|
label: entry.name,
|
||||||
|
boost,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
from: pos,
|
from: pos,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Diagnostic } from '@codemirror/lint';
|
import type { Diagnostic } from '@codemirror/lint';
|
||||||
import ts from 'typescript';
|
import ts from 'typescript';
|
||||||
|
|
||||||
export const FILE_NAME = 'index.ts';
|
export const FILE_NAME = 'index.js';
|
||||||
const FN_PREFIX = '(() => {\n';
|
const FN_PREFIX = '(() => {\n';
|
||||||
|
|
||||||
export function wrapInFunction(script: string): string {
|
export function wrapInFunction(script: string): string {
|
||||||
|
@ -9,7 +9,7 @@ export function wrapInFunction(script: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cmPosToTs(pos: number) {
|
export function cmPosToTs(pos: number) {
|
||||||
return pos + FN_PREFIX.length - 1;
|
return pos + FN_PREFIX.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tsPosToCm(pos: number) {
|
export function tsPosToCm(pos: number) {
|
||||||
|
|
|
@ -26,5 +26,6 @@
|
||||||
// TODO: remove all options below this line
|
// TODO: remove all options below this line
|
||||||
"useUnknownInCatchVariables": false
|
"useUnknownInCatchVariables": false
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"]
|
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"],
|
||||||
|
"exclude": ["src/plugins/codemirror/lsp/worker/**/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue