import { sf } from './helpers/Stringifier' import * as vscode from 'vscode' export namespace utils { /** 检查列表中是否包含指定元素 */ export function listContains(list: T[], item: T): boolean { return list.indexOf(item) !== -1 } /** 将类似 "SomeName" 的字符串转换成类似 "someName" 的形式 */ export function pascalToCamel(str: string) { return str[0].toLowerCase() + str.slice(1) } /** 将类似 "someName" 的字符串转换成类似 "SomeName" 的形式 */ export function camelToPascal(str: string) { return str[0].toUpperCase() + str.slice(1) } /** 将类似 "SomeName" 的字符串转换成 ["some","name"] */ export function recoverPascal(str: string) { const camelStr = pascalToCamel(str) const res = [] const regex = /^[A-Z]+$/ let tempStr = '' for (let el of camelStr) { if (regex.test(el)) { res.push(tempStr) el = el.toLocaleLowerCase() tempStr = '' } tempStr += el } if (tempStr.length > 0) { res.push(tempStr) } return res } /** 校验字符串是否符合 "SomeName" 或者 "Some" 的格式 */ export function validatePascal(str: string) { const regex1 = /^[A-Z]+$/ if (!regex1.test(str[0])) return false if (str === 'For' || str === 'Elif' || str === 'If' || str === 'Else' || str === 'Plugin' || str === 'Slot') { return false } const regex2 = /([A-Z][a-z]*)+/ if (!regex2.test(str)) return false return true } export function pick(object: T, keys: KS[]): { [K in KS]: T[K] } { const res: any = {} for (const key of keys) { res[key] = object[key] } return res } /** * convert a string into camelcase * any charactor followed a separator will be convert to uppercased letter, * otherwise convert to lowercased letter * @param str string to convert * @param separators list of separator, defauls to "-"/"_" */ export function camelizeString(str: string, separators: string[] = ['-', '_']): string { const out: any = [] let i: number = 0 while (i < str.length) { if (separators.indexOf(str[i]) > -1) { out.push(str[i + 1].toUpperCase()) i++ } else { out.push(str[i]) } i++ } return out.join('') } /** * convert a string into PascalCase * @param str string to convert * @param separators list of separators */ export function pascalizeString(str: string, separators: string[] = ['-', '_']): string { return utils.camelToPascal(utils.camelizeString(str, separators)) } /** * convert all keys in an object recursivly using utils.camelizeKey * @param obj */ export function camelize(obj: object): { [key: string]: any } { if (obj === null || obj === undefined) { return obj } else if (obj instanceof Array) { return obj.map((item) => { return utils.camelize(item) }) } else if (typeof obj === 'object') { const out: any = {} for (const key in obj as any) { const v = (obj as any)[key] out[utils.camelizeString(key)] = utils.camelize(v) } return out } else { return obj } } /** * convert a string into words split by middlescore * - "someName" will be convert to "some-name" * - "SomeName" will be convert to "some-name" if ignoreFirst is true, * otherwise it will be "-some-name" * @param str * @param ignoreFirst */ export function middlelizeString(str: string, ignoreFirst: boolean = true): string { const out: string[] = [] let i: number = 0 const lowerCasedStr = str.toString().toLowerCase() while (i < str.length) { if (str[i] !== lowerCasedStr[i]) { if (!ignoreFirst || i !== 0) { out.push('-') out.push(lowerCasedStr[i]) i++ continue } } out.push(str[i].toLocaleLowerCase()) i++ } return out.join('') } /** * convert all keys in object to middlescore-splitted key * - "someName" will be convert to "some-name" * - "SomeName" will be convert to "some-name" if ignoreFirst is true, * otherwise it will be "-some-name" * @param obj target object */ export function middlelize(obj: object): { [key: string]: any } { if (obj === null || obj === undefined) { return obj } else if (obj instanceof Array) { return obj.map((item) => { return utils.middlelize(item) }) } else if (typeof obj === 'object') { const out: any = {} for (const key in obj as any) { const v = (obj as any)[key] out[utils.middlelizeString(key)] = utils.middlelize(v) } return out } else { return obj } } /** * convert all keys in object to underline-splitted key * - "someName" will be convert to "some_name" * - "SomeName" will be convert to "some_name" if ignoreFirst is true, * otherwise it will be "_some_name" * @param obj target object */ export function underlize(obj: object): { [key: string]: any } { if (obj === null || obj === undefined) { return obj } else if (obj instanceof Array) { return obj.map((item) => { return utils.underlize(item) }) } else if (typeof obj === 'object') { const out: any = {} for (const key in obj as any) { const v = (obj as any)[key] out[utils.underlizeString(key)] = utils.underlize(v) } return out } else { return obj } } /** * convert key to be underline-splitted key * - "someName" will be convert to "some_name" * - "SomeName" will be convert to "some_name" if ignoreFirst is true, * otherwise it will be "_some_name" * @param str * @param ignoreFirst */ export function underlizeString(str: string, ignoreFirst: boolean = false): string { const out: string[] = [] let i: number = 0 const lowerCasedStr: string = str.toString().toLowerCase() while (i < str.length) { if (str[i] !== lowerCasedStr[i]) { if (!ignoreFirst || i !== 0) { out.push('_') out.push(lowerCasedStr[i]) i++ continue } } out.push(str[i].toLocaleLowerCase()) i++ } return out.join('') } export function isEmptyObject(object: {}): boolean { if (!utils.isRawObject(object)) { return false } // return Object.keys(object).length > 0 for (const _ in object) { return false } return true } /** * 检测一个对象是否是一个单纯对象(不包括其子类和其他原始类型的对象,比如 {a:1}) * @param target 检测对象 */ export function isRawObject(target: any): boolean { return !!target && target.constructor === Object } export function listToBoolMap(list: T[], hashKey?: keyof T) { const map: { [key: string]: true } = {} if (hashKey) { for (const item of list) { map['' + item[hashKey]] = true } } else { for (const item of list) { map['' + item] = true } } return map } export function listToMap(list: T[], hashKey: keyof T) { const map: { [key: string]: T } = {} for (const item of list) { map['' + item[hashKey]] = item } return map } /** returns a promise that resolves after specified time */ export function asyncDelay(time: number) { return new Promise((resolve) => { setTimeout(() => { resolve() }, time) }) } /** * 格式化对象 * @param value 待格式化对象,通常为 { name : "string" } * @param filed 字段名,如果传入 返回 type filed = { xxx } 否则 返回 { xxx } */ export function marshalIndent(value: any, field?: string) { if (typeof value === 'object') { return sf.formatDesp(value, field) } return value } /** * 将标签中可能存在的修饰符 '?' 去掉 * @param label 标签 */ export function initLabel(label: string) { if (label[label.length - 1] === '?') { return label.slice(0, label.length - 1) } return label } export function getLinePrefix(document: vscode.TextDocument, position: vscode.Position) { return document.lineAt(position).text.substr(0, position.character) } export function getWord(document: vscode.TextDocument, position: vscode.Position) { return document.getText(document.getWordRangeAtPosition(position)) } export const debounce = (fn: any, delay: number) => { let timer: any return () => { if (timer) { clearTimeout(timer) } timer = setTimeout(() => { fn() }, delay) } } export const dataPointContextValidator = (document: vscode.TextDocument, position: vscode.Position) => { let isValidate = false if (document.getWordRangeAtPosition(position, /{{.*?}}/)) { isValidate = true } else if (document.getWordRangeAtPosition(position, /(cond|list)=".*?"/)) { isValidate = true } return isValidate } }