UNPKG

alm

Version:

The best IDE for TypeScript

616 lines (615 loc) 18.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function log() { console.log('log'); } exports.log = log; /** * Create a quick lookup map from list */ function createMap(arr) { return arr.reduce(function (result, key) { result[key] = true; return result; }, {}); } exports.createMap = createMap; /** * Create a quick lookup map from list */ function createMapByKey(arr, getKey) { var result = {}; arr.forEach(function (item) { var key = getKey(item); result[key] = result[key] ? result[key].concat(item) : [item]; }); return result; } exports.createMapByKey = createMapByKey; /** * Turns keys into values and values into keys */ function reverseKeysAndValues(obj) { var toret = {}; Object.keys(obj).forEach(function (key) { toret[obj[key]] = key; }); return toret; } exports.reverseKeysAndValues = reverseKeysAndValues; /** Sloppy but effective code to find distinct */ function distinct(arr) { var map = createMap(arr); return Object.keys(map); } exports.distinct = distinct; exports.uniq = distinct; /** * Values for dictionary */ function values(dict) { return Object.keys(dict).map(function (key) { return dict[key]; }); } exports.values = values; /** * Debounce */ var now = function () { return new Date().getTime(); }; function debounce(func, milliseconds, immediate) { if (immediate === void 0) { immediate = false; } var timeout, args, context, timestamp, result; var wait = milliseconds; var later = function () { var last = now() - timestamp; if (last < wait && last > 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function () { context = this; args = arguments; timestamp = now(); var callNow = immediate && !timeout; if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; } exports.debounce = debounce; ; /** * Like debounce but will also call if a state change is significant enough to not ignore silently * Note: * - Significant changes : the function is called *immediately* without debouncing (but still marked for future debouncing). */ function triggeredDebounce(config) { var lastArg, lastCallTimeStamp; var hasALastArg = false; // true if we are `holding back` any previous arg var pendingTimeout = null; var later = function () { var timeSinceLast = now() - lastCallTimeStamp; if (timeSinceLast < config.milliseconds) { if (pendingTimeout) { clearTimeout(pendingTimeout); pendingTimeout = null; } pendingTimeout = setTimeout(later, config.milliseconds - timeSinceLast); } else { config.func(lastArg); hasALastArg = false; } }; return function (arg) { var stateChangeSignificant = hasALastArg && config.mustcall(arg, lastArg); if (stateChangeSignificant) { config.func(lastArg); } lastArg = arg; hasALastArg = true; lastCallTimeStamp = now(); later(); }; } exports.triggeredDebounce = triggeredDebounce; ; function throttle(func, milliseconds, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var gnow = now; var later = function () { previous = options.leading === false ? 0 : gnow(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function () { var now = gnow(); if (!previous && options.leading === false) previous = now; var remaining = milliseconds - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > milliseconds) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; } exports.throttle = throttle; ; function once(func) { var ran = false; var memo = undefined; return function () { if (ran) return memo; ran = true; memo = func.apply(this, arguments); func = null; return memo; }; } exports.once = once; function rangeLimited(args) { var num = args.num, min = args.min, max = args.max, loopAround = args.loopAround; var limited = Math.max(Math.min(num, max), min); if (loopAround && limited > num) { return max; } if (loopAround && limited < num) { return min; } return limited; } exports.rangeLimited = rangeLimited; /** * Is TypeSript or is JavaScript file checks */ exports.isTs = function (filePath, ext) { if (ext === void 0) { ext = getExt(filePath); } return ext == 'ts' || ext == 'tsx'; }; exports.isTsx = function (filePath, ext) { if (ext === void 0) { ext = getExt(filePath); } return ext == 'tsx'; }; exports.isJs = function (filePath, ext) { if (ext === void 0) { ext = getExt(filePath); } return ext == 'js' || ext == 'jsx'; }; exports.isJsOrTs = function (filePath) { var ext = getExt(filePath); return exports.isJs(filePath, ext) || exports.isTs(filePath, ext); }; /** `/asdf/bar/j.ts` => `ts` */ function getExt(filePath) { var parts = filePath.split('.'); return parts[parts.length - 1].toLowerCase(); } exports.getExt = getExt; /** * `/asdf/bar/j.ts` => `/asdf/bar/j` * `/asdf/bar/j.d.ts` => `/asdf/bar/j.d` */ function removeExt(filePath) { var dot = filePath.lastIndexOf('.'); if (dot === -1) { return filePath; } return filePath.substring(0, dot); } exports.removeExt = removeExt; /** * asdf/asdf:123 => asdf/asdf + 122 * Note: returned line is 0 based */ function getFilePathLine(query) { var _a = query.split(':'), filePath = _a[0], lineNum = _a[1]; var line = lineNum ? parseInt(lineNum) - 1 : 0; line = line > 0 ? line : 0; return { filePath: filePath, line: line }; } exports.getFilePathLine = getFilePathLine; /** `/asdf/bar/j.ts` => `j.ts` */ function getFileName(fullFilePath) { var parts = fullFilePath.split('/'); return parts[parts.length - 1]; } exports.getFileName = getFileName; /** `/asdf/bar/j.ts` => `/asdf/bar` */ function getDirectory(filePath) { var directory = filePath.substring(0, filePath.lastIndexOf("/")); return directory; } exports.getDirectory = getDirectory; /** Folder + filename only e.g. `/asdf/something/tsconfig.json` => `something/tsconfig.json` */ function getDirectoryAndFileName(filePath) { var directoryPath = getDirectory(filePath); var directoryName = getFileName(directoryPath); var fileName = getFileName(filePath); return directoryName + "/" + fileName; } exports.getDirectoryAndFileName = getDirectoryAndFileName; /** * shallow equality of sorted arrays */ function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; } exports.arraysEqual = arraysEqual; /** Creates a Guid (UUID v4) */ function createId() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } exports.createId = createId; /** Creates a Guid (UUID v4) */ exports.createGuid = createId; // Not optimized function selectMany(arr) { var result = []; for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr[i].length; j++) { result.push(arr[i][j]); } } return result; } exports.selectMany = selectMany; /** From `file://filePath` to `filePath` */ function getFilePathFromUrl(url) { var filePath = getFilePathAndProtocolFromUrl(url).filePath; return filePath; } exports.getFilePathFromUrl = getFilePathFromUrl; /** We consistently have tabs with protocol + filePath */ function getFilePathAndProtocolFromUrl(url) { // TODO: error handling var protocol = url.substr(0, url.indexOf('://')); var filePath = url.substr((protocol + '://').length); return { protocol: protocol, filePath: filePath }; } exports.getFilePathAndProtocolFromUrl = getFilePathAndProtocolFromUrl; function getUrlFromFilePathAndProtocol(config) { return config.protocol + '://' + config.filePath; } exports.getUrlFromFilePathAndProtocol = getUrlFromFilePathAndProtocol; /** * Promise.resolve is something I call the time (allows you to take x|promise and return promise ... aka make sync prog async if needed) */ exports.resolve = Promise.resolve.bind(Promise); /** Useful for various editor related stuff e.g. completions */ var punctuations = createMap([';', '{', '}', '(', ')', '.', ':', '<', '>', "'", '"']); /** Does the prefix end in punctuation */ exports.prefixEndsInPunctuation = function (prefix) { return prefix.length && prefix.trim().length && punctuations[prefix.trim()[prefix.trim().length - 1]]; }; /** String based enum pattern */ function stringEnum(x) { // make values same as keys Object.keys(x).map(function (key) { return x[key] = key; }); } exports.stringEnum = stringEnum; /** * Just adds your intercept function to be called whenever the original function is called * Calls your function *before* the original is called */ function intercepted(config) { return function () { config.intercept.apply(null, arguments); return config.orig.apply(config.context, arguments); }; } exports.intercepted = intercepted; /** * path.relative for browser * from : https://github.com/substack/path-browserify/blob/master/index.js * but modified to not depened on `path.resolve` as from and to are already resolved in our case */ exports.relative = function (from, to) { function trim(arr) { var start = 0; for (; start < arr.length; start++) { if (arr[start] !== '') break; } var end = arr.length - 1; for (; end >= 0; end--) { if (arr[end] !== '') break; } if (start > end) return []; return arr.slice(start, end - start + 1); } var fromParts = trim(from.split('/')); var toParts = trim(to.split('/')); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; for (var i = 0; i < length; i++) { if (fromParts[i] !== toParts[i]) { samePartsLength = i; break; } } var outputParts = []; for (var i = samePartsLength; i < fromParts.length; i++) { outputParts.push('..'); } outputParts = outputParts.concat(toParts.slice(samePartsLength)); return outputParts.join('/'); }; exports.imageUrl = '/images'; var supportedImages = { 'svg': 'image/svg+xml', 'gif': 'image/gif', 'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'bmp': 'image/bmp' }; var imageExtensions = Object.keys(supportedImages); /** * Provides info on the image files we support */ function isImage(url) { return imageExtensions.some(function (ext) { return url.endsWith("." + ext); }); } exports.isImage = isImage; function getImageMimeType(filePath) { var ext = getExt(filePath); return supportedImages[ext]; } exports.getImageMimeType = getImageMimeType; /** * Great for find and replace */ function findOptionsToQueryRegex(options) { // Note that Code mirror only takes `query` string *tries* to detect case senstivity, regex on its own // So simpler if we just convert options into regex, and then code mirror will happy use the regex as is var str = options.query; var query; /** This came from search.js in code mirror */ var defaultQuery = /x^/; if (!options.isRegex) { // from CMs search.js str = str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); } if (options.isFullWord) { str = "\\b" + str + "\\b"; } try { query = new RegExp(str, options.isCaseSensitive ? "g" : "gi"); } catch (e) { query = defaultQuery; } if (query.test("")) { query = defaultQuery; } return query; } exports.findOptionsToQueryRegex = findOptionsToQueryRegex; /** * Quick and dirty pad left */ function padLeft(str, paddingValue) { var pad = ' '; return pad.substring(0, paddingValue - str.length) + str; } exports.padLeft = padLeft; function extend() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var newObj = {}; for (var _a = 0, args_1 = args; _a < args_1.length; _a++) { var obj = args_1[_a]; for (var key in obj) { //copy all the fields newObj[key] = obj[key]; } } return newObj; } exports.extend = extend; ; /** * Simple timer */ function timer() { var timeStart = new Date().getTime(); return { /** <integer>s e.g 2s etc. */ get seconds() { var seconds = Math.ceil((new Date().getTime() - timeStart) / 1000) + 's'; return seconds; }, /** Milliseconds e.g. 2000ms etc. */ get ms() { var ms = (new Date().getTime() - timeStart) + 'ms'; return ms; } }; } exports.timer = timer; /** * Returns a nice conversion of milliseconds into seconds / mintues as needed */ function formatMilliseconds(ms) { if (ms < 1000) return ms + "ms"; var s = ms / 1000; if (s < 60) { return s.toFixed(2) + "s"; } var m = s / 60; return m.toFixed(2) + "min"; } exports.formatMilliseconds = formatMilliseconds; /** * If you add a new schema make sure you download its schema as well */ exports.supportedAutocompleteConfigFileNames = { 'tsconfig.json': true, 'package.json': true, 'tslint.json': true, 'alm.json': true, }; /** * Files for which we have autocomplete intelligence */ function isSupportedConfigFileForAutocomplete(filePath) { var fileName = getFileName(filePath); return !!exports.supportedAutocompleteConfigFileNames[fileName]; } exports.isSupportedConfigFileForAutocomplete = isSupportedConfigFileForAutocomplete; exports.supportedHoverConfigFileNames = { 'package.json': true, }; /** * Files for which we have hover intelligence */ function isSupportedConfigFileForHover(filePath) { var fileName = getFileName(filePath); return !!exports.supportedHoverConfigFileNames[fileName]; } exports.isSupportedConfigFileForHover = isSupportedConfigFileForHover; exports.cancellationToken = function () { var cancelled = false; return { get isCancelled() { return cancelled; }, cancel: function () { return cancelled = true; } }; }; exports.cancelled = "cancelled"; /** * Cancellable For Each */ function cancellableForEach(config) { return new Promise(function (resolve, reject) { var index = 0; var lookAtNext = function () { // Completed? if (index === config.items.length) { resolve({}); } else if (config.cancellationToken.isCancelled) { reject(exports.cancelled); } else { var nextItem = config.items[index++]; config.cb(nextItem); // Yield the thread for a bit setTimeout(lookAtNext); } }; lookAtNext(); }); } exports.cancellableForEach = cancellableForEach; /** * https://github.com/facebook/react/issues/5465#issuecomment-157888325 */ var makeCancelable = function (promise) { var hasCanceled_ = false; var wrappedPromise = new Promise(function (resolve, reject) { promise.then(function (val) { return hasCanceled_ ? reject({ isCanceled: true }) : resolve(val); }); promise.catch(function (error) { return hasCanceled_ ? reject({ isCanceled: true }) : reject(error); }); }); return { promise: wrappedPromise, cancel: function () { hasCanceled_ = true; }, }; }; /** * For promise chains that might become invalid fast */ function onlyLastCall(call) { /** * Kept the delay to 0 as I am using this in select list view * and that really benifits from immediate feedback. */ var delay = 0; var timeout; var _resolve; var _reject; var _cancel = function () { return null; }; var later = function () { timeout = null; var _a = makeCancelable(call()), promise = _a.promise, cancel = _a.cancel; _cancel = cancel; promise .then(function (res) { _resolve(res); }) .catch(function (rej) { _reject(rej); }); }; var trueCall = function () { return new Promise(function (resolve, reject) { if (timeout) { clearTimeout(timeout); } // Cancel any pending _cancel(); _resolve = resolve; _reject = reject; timeout = setTimeout(later, delay); }); }; return trueCall; } exports.onlyLastCall = onlyLastCall; /** * Delay given ms */ function delay(ms) { return new Promise(function (res) { return setTimeout(res, ms); }); } exports.delay = delay;