UNPKG

javascript-typescript-langserver

Version:

Implementation of the Language Server Protocol for JavaScript and TypeScript

207 lines 7.33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fast_json_patch_1 = require("fast-json-patch"); const rxjs_1 = require("rxjs"); const string_similarity_1 = require("string-similarity"); const ts = require("typescript"); const url = require("url"); /** * Converts an Iterable to an Observable. * Workaround for https://github.com/ReactiveX/rxjs/issues/2306 */ function observableFromIterable(iterable) { return rxjs_1.Observable.from(iterable); } exports.observableFromIterable = observableFromIterable; /** * Template string tag to escape JSON Pointer components as per https://tools.ietf.org/html/rfc6901#section-3 */ function JSONPTR(strings, ...toEscape) { return strings.reduce((left, right, i) => left + fast_json_patch_1.escapePathComponent(toEscape[i - 1]) + right); } exports.JSONPTR = JSONPTR; /** * Makes documentation string from symbol display part array returned by TS */ function docstring(parts) { return ts.displayPartsToString(parts); } exports.docstring = docstring; /** * Normalizes path to match POSIX standard (slashes) * This conversion should only be necessary to convert windows paths when calling TS APIs. */ function toUnixPath(filePath) { return filePath.replace(/\\/g, '/'); } exports.toUnixPath = toUnixPath; /** * Normalizes URI encoding by encoding _all_ special characters in the pathname */ function normalizeUri(uri) { const parts = url.parse(uri); if (!parts.pathname) { return uri; } const pathParts = parts.pathname.split('/').map(segment => encodeURIComponent(decodeURIComponent(segment))); // Decode Windows drive letter colon if (/^[a-z]%3A$/i.test(pathParts[1])) { pathParts[1] = decodeURIComponent(pathParts[1]); } parts.pathname = pathParts.join('/'); return url.format(parts); } exports.normalizeUri = normalizeUri; /** * Converts an abolute path to a file:// uri * * @param path an absolute path */ function path2uri(path) { // Require a leading slash, on windows prefixed with drive letter if (!/^(?:[a-z]:)?[\\\/]/i.test(path)) { throw new Error(`${path} is not an absolute path`); } const parts = path.split(/[\\\/]/); // If the first segment is a Windows drive letter, prefix with a slash and skip encoding let head = parts.shift(); if (head !== '') { head = '/' + head; } else { head = encodeURIComponent(head); } return `file://${head}/${parts.map(encodeURIComponent).join('/')}`; } exports.path2uri = path2uri; /** * Converts a uri to an absolute path. * The OS style is determined by the URI. E.g. `file:///c:/foo` always results in `c:\foo` * * @param uri a file:// uri */ function uri2path(uri) { const parts = url.parse(uri); if (parts.protocol !== 'file:') { throw new Error('Cannot resolve non-file uri to path: ' + uri); } let filePath = parts.pathname || ''; // If the path starts with a drive letter, return a Windows path if (/^\/[a-z]:\//i.test(filePath)) { filePath = filePath.substr(1).replace(/\//g, '\\'); } return decodeURIComponent(filePath); } exports.uri2path = uri2path; const jstsPattern = /\.[tj]sx?$/; function isJSTSFile(filename) { return jstsPattern.test(filename); } exports.isJSTSFile = isJSTSFile; const jstsConfigPattern = /(^|\/)[tj]sconfig\.json$/; function isConfigFile(filename) { return jstsConfigPattern.test(filename); } exports.isConfigFile = isConfigFile; const packageJsonPattern = /(^|\/)package\.json$/; function isPackageJsonFile(filename) { return packageJsonPattern.test(filename); } exports.isPackageJsonFile = isPackageJsonFile; const globalTSPatterns = [ /(^|\/)globals?\.d\.ts$/, /node_modules\/(?:\@|%40)types\/(node|jasmine|jest|mocha)\/.*\.d\.ts$/, /(^|\/)typings\/.*\.d\.ts$/, /(^|\/)tsd\.d\.ts($|\/)/, /(^|\/)tslib\.d\.ts$/, ]; // isGlobalTSFile returns whether or not the filename contains global // variables based on a best practices heuristic // (https://basarat.gitbooks.io/typescript/content/docs/project/modules.html). In // reality, a file has global scope if it does not begin with an // import statement, but to check this, we'd have to read each // TypeScript file. function isGlobalTSFile(filename) { for (const globalTSPattern of globalTSPatterns) { if (globalTSPattern.test(filename)) { return true; } } return false; } exports.isGlobalTSFile = isGlobalTSFile; function isDependencyFile(filename) { return filename.startsWith('node_modules/') || filename.indexOf('/node_modules/') !== -1; } exports.isDependencyFile = isDependencyFile; function isDeclarationFile(filename) { return filename.endsWith('.d.ts'); } exports.isDeclarationFile = isDeclarationFile; /** * Compares two values and returns a numeric score between 0 and 1 defining of how well they match. * E.g. if 2 of 4 properties in the query match, will return 2 */ function getMatchingPropertyCount(query, value) { // Compare strings by similarity // This allows to match a path like "lib/foo/bar.d.ts" with "src/foo/bar.ts" // Last check is a workaround for https://github.com/aceakash/string-similarity/issues/6 if (typeof query === 'string' && typeof value === 'string' && !(query.length <= 1 && value.length <= 1)) { return string_similarity_1.compareTwoStrings(query, value); } // If query is a scalar value, compare by identity and return 0 or 1 if (typeof query !== 'object' || query === null) { return +(query === value); } // If value is scalar, return no match if (typeof value !== 'object' && value !== null) { return 0; } // Both values are objects, compare each property and sum the scores return Object.keys(query).reduce((score, key) => score + getMatchingPropertyCount(query[key], value[key]), 0); } exports.getMatchingPropertyCount = getMatchingPropertyCount; /** * Returns the maximum score that could be achieved with the given query (the amount of "leaf" properties) * E.g. for `{ name, kind, package: { name }}` will return 3 */ function getPropertyCount(query) { if (typeof query === 'object' && query !== null) { return Object.keys(query).reduce((score, key) => score + getPropertyCount(query[key]), 0); } return 1; } exports.getPropertyCount = getPropertyCount; /** * Returns true if the passed SymbolDescriptor has at least the same properties as the passed partial SymbolDescriptor */ function isSymbolDescriptorMatch(query, symbol) { for (const key of Object.keys(query)) { if (!query[key]) { continue; } if (key === 'package') { if (!symbol.package || !isPackageDescriptorMatch(query.package, symbol.package)) { return false; } continue; } if (query[key] !== symbol[key]) { return false; } } return true; } exports.isSymbolDescriptorMatch = isSymbolDescriptorMatch; function isPackageDescriptorMatch(query, pkg) { for (const key of Object.keys(query)) { if (query[key] === undefined) { continue; } if (query[key] !== pkg[key]) { return false; } } return true; } //# sourceMappingURL=util.js.map