UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

259 lines (228 loc) 9.72 kB
Object.defineProperty(exports, '__esModule', { value: true }); /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.linterMessageToDiagnosticMessage = linterMessageToDiagnosticMessage; exports.linterMessagesToDiagnosticUpdate = linterMessagesToDiagnosticUpdate; function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _atom2; function _atom() { return _atom2 = require('atom'); } var _nuclideDiagnosticsProviderBase2; function _nuclideDiagnosticsProviderBase() { return _nuclideDiagnosticsProviderBase2 = require('../../nuclide-diagnostics-provider-base'); } var _commonsNodePromise2; function _commonsNodePromise() { return _commonsNodePromise2 = require('../../commons-node/promise'); } // Exported for testing. function linterMessageToDiagnosticMessage(msg, providerName) { // The types are slightly different, so we need to copy to make Flow happy. Basically, a Trace // does not need a filePath property, but a LinterTrace does. Trace is a subtype of LinterTrace, // so copying works but aliasing does not. For a detailed explanation see // https://github.com/facebook/flow/issues/908 var trace = msg.trace ? msg.trace.map(function (component) { return _extends({}, component); }) : undefined; if (msg.filePath) { return { scope: 'file', providerName: msg.name != null ? msg.name : providerName, type: msg.type, filePath: msg.filePath, text: msg.text, html: msg.html, range: msg.range && (_atom2 || _atom()).Range.fromObject(msg.range), trace: trace, fix: msg.fix == null ? undefined : { oldRange: msg.fix.range, oldText: msg.fix.oldText, newText: msg.fix.newText } }; } else { return { scope: 'project', providerName: msg.name != null ? msg.name : providerName, type: msg.type, text: msg.text, html: msg.html, range: msg.range && (_atom2 || _atom()).Range.fromObject(msg.range), trace: trace }; } } // Exported for testing. function linterMessagesToDiagnosticUpdate(currentPath, msgs) { var providerName = arguments.length <= 2 || arguments[2] === undefined ? 'Unnamed Linter' : arguments[2]; var filePathToMessages = new Map(); if (currentPath) { // Make sure we invalidate the messages for the current path. We may want to // figure out which other paths we want to invalidate if it turns out that // linters regularly return messages for other files. filePathToMessages.set(currentPath, []); } var projectMessages = []; for (var msg of msgs) { var diagnosticMessage = linterMessageToDiagnosticMessage(msg, providerName); if (diagnosticMessage.scope === 'file') { var path = diagnosticMessage.filePath; var messages = filePathToMessages.get(path); if (messages == null) { messages = []; filePathToMessages.set(path, messages); } messages.push(diagnosticMessage); } else { // Project scope. projectMessages.push(diagnosticMessage); } } return { filePathToMessages: filePathToMessages, projectMessages: projectMessages }; } /** * Provides an adapter between legacy linters (defined by the LinterProvider * type), and Nuclide Diagnostic Providers. * * The constructor takes a LinterProvider as an argument, and the resulting * LinterAdapter is a valid DiagnosticProvider. * * Note that this allows an extension to ordinary LinterProviders. We allow an * optional additional field, providerName, to indicate the display name of the * linter. */ var LinterAdapter = (function () { function LinterAdapter(provider) { var _this = this; var ProviderBase = arguments.length <= 1 || arguments[1] === undefined ? (_nuclideDiagnosticsProviderBase2 || _nuclideDiagnosticsProviderBase()).DiagnosticsProviderBase : arguments[1]; _classCallCheck(this, LinterAdapter); var utilsOptions = { grammarScopes: new Set(provider.grammarScopes), enableForAllGrammars: provider.allGrammarScopes, shouldRunOnTheFly: provider.lintOnFly, onTextEditorEvent: function onTextEditorEvent(editor) { return _this._runLint(editor); }, onNewUpdateSubscriber: function onNewUpdateSubscriber(callback) { return _this._newUpdateSubscriber(callback); } }; this._providerUtils = new ProviderBase(utilsOptions); this._provider = provider; this._enabled = true; this._requestSerializer = new (_commonsNodePromise2 || _commonsNodePromise()).RequestSerializer(); this._filesForBuffer = new WeakMap(); this._onDestroyDisposables = new Map(); } _createClass(LinterAdapter, [{ key: '_runLint', value: _asyncToGenerator(function* (editor) { var _this2 = this; if (this._enabled) { var result = yield this._requestSerializer.run(this._provider.lint(editor)); if (result.status === 'success') { var _ret = (function () { var buffer = editor.getBuffer(); if (buffer.isDestroyed()) { return { v: undefined }; } if (_this2._provider.invalidateOnClose && !_this2._onDestroyDisposables.has(buffer)) { (function () { var disposable = buffer.onDidDestroy(function () { _this2._invalidateBuffer(buffer); _this2._onDestroyDisposables.delete(buffer); disposable.dispose(); }); _this2._onDestroyDisposables.set(buffer, disposable); })(); } var linterMessages = result.result; var diagnosticUpdate = linterMessagesToDiagnosticUpdate(editor.getPath(), linterMessages, _this2._provider.providerName || _this2._provider.name); _this2._invalidateBuffer(buffer); _this2._providerUtils.publishMessageUpdate(diagnosticUpdate); var filePathToMessages = diagnosticUpdate.filePathToMessages; if (filePathToMessages != null) { _this2._filesForBuffer.set(buffer, Array.from(filePathToMessages.keys())); } })(); if (typeof _ret === 'object') return _ret.v; } } }) }, { key: '_newUpdateSubscriber', value: function _newUpdateSubscriber(callback) { var activeTextEditor = atom.workspace.getActiveTextEditor(); if (activeTextEditor) { var matchesGrammar = this._provider.grammarScopes.indexOf(activeTextEditor.getGrammar().scopeName) !== -1; if (!this._lintInProgress() && matchesGrammar) { this._runLint(activeTextEditor); } } } }, { key: 'setEnabled', value: function setEnabled(enabled) { this._enabled = enabled; } }, { key: 'setLintOnFly', value: function setLintOnFly(lintOnFly) { this._providerUtils.setRunOnTheFly(lintOnFly && this._provider.lintOnFly); } }, { key: 'dispose', value: function dispose() { this._providerUtils.dispose(); this._onDestroyDisposables.forEach(function (disposable) { return disposable.dispose(); }); this._onDestroyDisposables.clear(); } }, { key: '_lintInProgress', value: function _lintInProgress() { return this._requestSerializer.isRunInProgress(); } }, { key: 'onMessageUpdate', value: function onMessageUpdate(callback) { return this._providerUtils.onMessageUpdate(callback); } }, { key: 'onMessageInvalidation', value: function onMessageInvalidation(callback) { return this._providerUtils.onMessageInvalidation(callback); } }, { key: '_invalidateBuffer', value: function _invalidateBuffer(buffer) { var filePaths = this._filesForBuffer.get(buffer); if (filePaths != null) { this._providerUtils.publishMessageInvalidation({ scope: 'file', filePaths: filePaths }); } } }]); return LinterAdapter; })(); exports.LinterAdapter = LinterAdapter; /** * Keep track of the files with diagnostics for each text buffer. * This way we can accurately invalidate diagnostics when files are renamed. */