This commit is contained in:
Elias Meire 2024-10-30 09:21:38 +01:00
parent 42966628d3
commit 406aeb005a
No known key found for this signature in database
8 changed files with 1516 additions and 41 deletions

View file

@ -4,11 +4,10 @@ import type { CodeExecutionMode, CodeNodeEditorLanguage } from 'n8n-workflow';
import { format } from 'prettier';
import jsParser from 'prettier/plugins/babel';
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 { codeNodeEditorEventBus } from '@/event-bus';
import { usePostHog } from '@/stores/posthog.store';
import { useRootStore } from '@/stores/root.store';
import { useCodeEditor } from '@/composables/useCodeEditor';
@ -18,6 +17,8 @@ import { useTelemetry } from '@/composables/useTelemetry';
import AskAI from './AskAI/AskAI.vue';
import { CODE_PLACEHOLDERS } from './constants';
import { useLinter } from './linter';
import { useSettingsStore } from '@/stores/settings.store';
import { dropInCodeEditor } from '@/plugins/codemirror/dragAndDrop';
type Props = {
mode: CodeExecutionMode;
@ -59,8 +60,11 @@ const linter = useLinter(
);
const extensions = computed(() => [linter.value]);
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,
language: () => props.language,
editorValue: () => props.modelValue,

View file

@ -19,6 +19,7 @@ import { editorKeymap } from '@/plugins/codemirror/keymap';
import { n8nAutocompletion } from '@/plugins/codemirror/n8nLang';
import { computed, onMounted, ref, watch } from 'vue';
import { codeEditorTheme } from '../CodeNodeEditor/theme';
import { mappingDropCursor } from '@/plugins/codemirror/dragAndDrop';
type Props = {
modelValue: string;

View file

@ -2,7 +2,7 @@ import { codeEditorTheme } from '@/components/CodeNodeEditor/theme';
import { editorKeymap } from '@/plugins/codemirror/keymap';
import { typescript } from '@/plugins/codemirror/lsp/typescript';
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 { javascript } from '@codemirror/lang-javascript';
import { json } from '@codemirror/lang-json';
@ -40,6 +40,7 @@ import {
type MaybeRefOrGetter,
type Ref,
} from 'vue';
import { mappingDropCursor } from '../plugins/codemirror/dragAndDrop';
export type CodeEditorLanguage = 'json' | 'html' | 'javaScript' | 'python';
@ -232,7 +233,9 @@ export const useCodeEditor = ({
dropCursor(),
indentOnInput(),
bracketMatching(),
closeBrackets(),
highlightActiveLineGutter(),
mappingDropCursor(),
indentationMarkers({
highlightActiveBlock: true,
markerType: 'fullScope',

View file

@ -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 { linter, type LintSource } from '@codemirror/lint';
import { combineConfig, Facet, type Extension } from '@codemirror/state';
@ -17,13 +17,23 @@ export const tsFacet = Facet.define<
const tsCompletions: CompletionSource = async (context) => {
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);
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) => {

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,9 @@ import {
cmPosToTs,
} from './utils';
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 => {
let env: tsvfs.VirtualTypeScriptEnvironment;
@ -21,12 +24,11 @@ const worker = (): LanguageServiceWorker => {
allowJs: true,
checkJs: true,
target: ts.ScriptTarget.ESNext,
lib: ['ESNext'],
noLib: true,
module: ts.ModuleKind.ESNext,
strict: true,
typeRoots: [],
types: [],
importHelpers: false,
skipDefaultLibCheck: true,
noEmit: true,
};
@ -40,15 +42,8 @@ const worker = (): LanguageServiceWorker => {
await indexedDbCache('typescript-cache', 'fs-map'),
);
fsMap.set('types.d.ts', types);
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);
env = tsvfs.createVirtualTypeScriptEnvironment(
@ -76,13 +71,19 @@ declare global {
if (!completionInfo) return null;
const options = completionInfo.entries.map((entry): Completion => {
const boost = -Number(entry.sortText) || 0;
return {
label: entry.name,
boost,
};
});
const options = completionInfo.entries
.filter(
(entry) =>
!TS_COMPLETE_BLOCKLIST.includes(entry.kind) &&
(entry.sortText < '15' || completionInfo.optionalReplacementSpan?.length),
)
.map((entry): Completion => {
const boost = -Number(entry.sortText) || 0;
return {
label: entry.name,
boost,
};
});
return {
from: pos,

View file

@ -1,7 +1,7 @@
import type { Diagnostic } from '@codemirror/lint';
import ts from 'typescript';
export const FILE_NAME = 'index.ts';
export const FILE_NAME = 'index.js';
const FN_PREFIX = '(() => {\n';
export function wrapInFunction(script: string): string {
@ -9,7 +9,7 @@ export function wrapInFunction(script: string): string {
}
export function cmPosToTs(pos: number) {
return pos + FN_PREFIX.length - 1;
return pos + FN_PREFIX.length;
}
export function tsPosToCm(pos: number) {

View file

@ -26,5 +26,6 @@
// TODO: remove all options below this line
"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"]
}