mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-06 06:48:21 +00:00
165 lines
4.3 KiB
JavaScript
165 lines
4.3 KiB
JavaScript
import _ from 'lodash';
|
|
import Fuse from 'fuse.js';
|
|
|
|
export function getSuggestionKeys(currentState) {
|
|
const suggestionList = [];
|
|
|
|
const map = new Map();
|
|
|
|
const buildMap = (data, path = '') => {
|
|
const keys = Object.keys(data);
|
|
keys.forEach((key, index) => {
|
|
const value = data[key];
|
|
const _type = Object.prototype.toString.call(value).slice(8, -1);
|
|
const prevType = map.get(path)?.type;
|
|
|
|
let newPath = '';
|
|
if (path === '') {
|
|
newPath = key;
|
|
} else if (prevType === 'Array') {
|
|
newPath = `${path}[${index}]`;
|
|
} else {
|
|
newPath = `${path}.${key}`;
|
|
}
|
|
|
|
if (_type === 'Object') {
|
|
map.set(newPath, { type: _type });
|
|
buildMap(value, newPath);
|
|
}
|
|
if (_type === 'Array') {
|
|
map.set(newPath, { type: _type });
|
|
buildMap(value, newPath);
|
|
} else {
|
|
map.set(newPath, { type: _type });
|
|
}
|
|
});
|
|
};
|
|
|
|
buildMap(currentState, '');
|
|
map.forEach((__, key) => suggestionList.push(key));
|
|
|
|
return suggestionList;
|
|
}
|
|
|
|
export function generateHints(word, suggestions) {
|
|
if (word === '') {
|
|
return suggestions;
|
|
}
|
|
|
|
const fuse = new Fuse(suggestions);
|
|
return fuse.search(word).map((result) => result.item);
|
|
}
|
|
|
|
export function computeCurrentWord(editor, _cursorPosition, ignoreBraces = false) {
|
|
const cursor = editor.getCursor();
|
|
const line = cursor.line;
|
|
const value = editor.getLine(line);
|
|
const sliced = value.slice(0, _cursorPosition);
|
|
|
|
const splitter = ignoreBraces ? ' ' : '{{';
|
|
|
|
const split = sliced.split(splitter);
|
|
const splittedWord = split.slice(-1).pop();
|
|
|
|
// Check if the word still has spaces, to avoid replacing entire code
|
|
const lastWord = splittedWord.split(' ').slice(-1).pop();
|
|
|
|
return lastWord;
|
|
}
|
|
|
|
export function makeOverlay(style) {
|
|
return {
|
|
// eslint-disable-next-line no-unused-vars
|
|
token: function (stream, state) {
|
|
var ch;
|
|
if (stream.match('{{')) {
|
|
while ((ch = stream.next()) != null)
|
|
if (ch === '}' && stream.next() === '}') {
|
|
stream.eat('}');
|
|
return style;
|
|
}
|
|
}
|
|
// eslint-disable-next-line no-empty
|
|
while (stream.next() != null && !stream.match('{{', false)) {}
|
|
return null;
|
|
},
|
|
};
|
|
}
|
|
|
|
export function onBeforeChange(editor, change, ignoreBraces = false) {
|
|
if (!ignoreBraces) {
|
|
const cursor = editor.getCursor();
|
|
const line = cursor.line;
|
|
const ch = cursor.ch;
|
|
const value = editor.getLine(line);
|
|
const isLastCharacterBrace = value.slice(ch - 1, value.length) === '{';
|
|
|
|
if (isLastCharacterBrace && change.origin === '+input' && change.text[0] === '{') {
|
|
change.text[0] = '{}}';
|
|
// editor.setCursor({ line: 0, ch: ch })
|
|
}
|
|
}
|
|
|
|
return change;
|
|
}
|
|
|
|
function keystrokeChecker(editor) {
|
|
const keyPromise = new Promise((resolve, reject) => {
|
|
editor.on('keyup', function (editor, event) {
|
|
if (event.key == 'Enter' || event.key == 'Backspace') {
|
|
resolve(true);
|
|
}
|
|
reject(false);
|
|
});
|
|
});
|
|
return keyPromise;
|
|
}
|
|
|
|
export function canShowHint(editor, ignoreBraces = false) {
|
|
if (!editor.hasFocus()) return false;
|
|
|
|
const cursor = editor.getCursor();
|
|
const line = cursor.line;
|
|
const ch = cursor.ch;
|
|
const value = editor.getLine(line);
|
|
|
|
if (ignoreBraces && value.length > 0) return true;
|
|
|
|
return value.slice(ch, ch + 2) === '}}';
|
|
}
|
|
|
|
export function handleChange(editor, onChange, suggestions, ignoreBraces = false) {
|
|
let state = editor.state.matchHighlighter;
|
|
editor.addOverlay((state.overlay = makeOverlay(state.options.style)));
|
|
|
|
const cursor = editor.getCursor();
|
|
const currentWord = computeCurrentWord(editor, cursor.ch, ignoreBraces);
|
|
const hints = generateHints(currentWord, suggestions);
|
|
|
|
const options = {
|
|
alignWithWord: false,
|
|
completeSingle: false,
|
|
hint: function () {
|
|
return {
|
|
from: { line: cursor.line, ch: cursor.ch - currentWord.length },
|
|
to: cursor,
|
|
list: hints,
|
|
};
|
|
},
|
|
};
|
|
if (canShowHint(editor, ignoreBraces)) {
|
|
const keystrokeValue = keystrokeChecker(editor)
|
|
.then((res) => {
|
|
return res;
|
|
})
|
|
.catch((err) => {
|
|
return err;
|
|
});
|
|
|
|
const keystrokeCaller = async () => {
|
|
const returnValue = await keystrokeValue;
|
|
if (!returnValue) editor.showHint(options);
|
|
};
|
|
keystrokeCaller();
|
|
}
|
|
}
|