/// /// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// import { Ace } from 'ace-builds'; export type tbMetaType = 'object' | 'function' | 'service' | 'property' | 'argument'; export type TbEditorCompletions = {[name: string]: TbEditorCompletion}; export interface FunctionArgType { type?: string; description?: string; } export interface FunctionArg extends FunctionArgType { name: string; type?: string; description?: string; optional?: boolean; } export interface TbEditorCompletion { meta: tbMetaType; description?: string; type?: string; args?: FunctionArg[]; return?: FunctionArgType; children?: TbEditorCompletions; } interface TbEditorAceCompletion extends Ace.Completion { isTbEditorAceCompletion: true; snippet: string; description?: string; type?: string; args?: FunctionArg[]; return?: FunctionArgType; } export class TbEditorCompleter implements Ace.Completer { identifierRegexps: RegExp[] = [ /[a-zA-Z_0-9\$\-\u00A2-\u2000\u2070-\uFFFF.]/ ]; constructor(private editorCompletions: TbEditorCompletions) { } getCompletions(editor: Ace.Editor, session: Ace.EditSession, position: Ace.Point, prefix: string, callback: Ace.CompleterCallback): void { const result = this.prepareCompletions(prefix); if (result) { callback(null, result); } } private resolvePath(prefix: string): string[] { if (!prefix || !prefix.length) { return []; } let parts = prefix.split('.'); if (parts.length) { parts.pop(); } else { parts = []; } let currentCompletions = this.editorCompletions; for (const part of parts) { if (currentCompletions[part]) { currentCompletions = currentCompletions[part].children; if (!currentCompletions) { return null; } } else { return null; } } return parts; } private prepareCompletions(prefix: string): Ace.Completion[] { const path = this.resolvePath(prefix); if (path !== null) { return this.toAceCompletionsList(this.editorCompletions, path); } else { return []; } } private toAceCompletionsList(completions: TbEditorCompletions, parentPath: string[]): Ace.Completion[] { const result: Ace.Completion[] = []; let targetCompletions = completions; let parentPrefix = ''; if (parentPath.length) { parentPrefix = parentPath.join('.') + '.'; for (const path of parentPath) { targetCompletions = targetCompletions[path].children; } } for (const key of Object.keys(targetCompletions)) { result.push(this.toAceCompletion(key, targetCompletions[key], parentPrefix)); } return result; } private toAceCompletion(name: string, completion: TbEditorCompletion, parentPrefix: string): Ace.Completion { const aceCompletion: TbEditorAceCompletion = { isTbEditorAceCompletion: true, snippet: parentPrefix + name, name, caption: parentPrefix + name, score: 100000, value: parentPrefix + name, meta: completion.meta, type: completion.type, description: completion.description, args: completion.args, return: completion.return }; return aceCompletion; } getDocTooltip(completion: TbEditorAceCompletion) { if (completion && completion.isTbEditorAceCompletion) { return { docHTML: this.createDocHTML(completion) }; } } private createDocHTML(completion: TbEditorAceCompletion): string { let title = `${completion.name}`; if (completion.meta === 'function') { title += '('; if (completion.args) { const strArgs: string[] = []; for (const arg of completion.args) { let strArg = `${arg.name}`; if (arg.optional) { strArg += '?'; } if (arg.type) { strArg += `: ${arg.type}`; } strArgs.push(strArg); } title += strArgs.join(', '); } title += '): '; if (completion.return) { title += completion.return.type; } else { title += 'void'; } } else { title += `: ${completion.type ? completion.type : completion.meta}`; } let html = `
${title}`;
if (completion.description) {
html += `${arg.name}`;
if (arg.optional) {
strArg += ' (optional)';
}
strArg += ' | ';
if (arg.type) {
strArg += `${arg.type}`;
}
strArg += ' | '; if (arg.description) { strArg += `${arg.description}`; } strArg += ' |
${completion.return.type}`;
if (completion.return.description) {
returnStr += `: ${completion.return.description}`;
}
returnStr += '